Contact Form by Supsystic - Version 1.7.12

Version Description

/ 23.02.2021 = * Security Fixes

Download this release

Release Info

Developer supsystic.com
Plugin Icon 128x128 Contact Form by Supsystic
Version 1.7.12
Comparing to
See all releases

Code changes from version 1.7.8 to 1.7.12

Files changed (205) hide show
  1. assets/forms/img/bg/2016_ht_1_bg.jpg +0 -0
  2. assets/forms/img/bg/bg_support_form.jpg +0 -0
  3. assets/forms/img/bg/scf-red-background.png +0 -0
  4. assets/forms/img/bg/tea-time.jpg +0 -0
  5. assets/forms/img/bg/tea-time.png +0 -0
  6. assets/forms/img/images/2016_ht_1_crist_wrench.png +0 -0
  7. assets/forms/img/images/2016_ht_1_santa.png +0 -0
  8. assets/forms/img/images/2016_ht_1_snow1.png +0 -0
  9. assets/forms/img/images/2016_ht_1_snow2.png +0 -0
  10. assets/forms/img/images/2016_ht_1_snow3.png +0 -0
  11. assets/forms/img/images/facebook-icon.png +0 -0
  12. assets/forms/img/images/google-plus-icon.png +0 -0
  13. assets/forms/img/images/paper-plane.png +0 -0
  14. assets/forms/img/images/scf-top-img-snow-1.png +0 -0
  15. assets/forms/img/images/scf-top-img-snow-2.png +0 -0
  16. assets/forms/img/images/support_image.png +0 -0
  17. assets/forms/img/images/twitter-icon.png +0 -0
  18. assets/forms/img/preview/141-merry-cristmas-prev.png +0 -0
  19. assets/forms/img/preview/Ho-ho-ho-template-prev.png +0 -0
  20. assets/forms/img/preview/base-contact.jpg +0 -0
  21. assets/forms/img/preview/intransigent.jpg +0 -0
  22. assets/forms/img/preview/kiwifruit.png +0 -0
  23. assets/forms/img/preview/light-grey.png +0 -0
  24. assets/forms/img/preview/neon.jpg +0 -0
  25. assets/forms/img/preview/opacity-grey.png +0 -0
  26. assets/forms/img/preview/simple-white.png +0 -0
  27. assets/forms/img/preview/tea-time.png +0 -0
  28. assets/forms/promo/img/AB-testing-pro.jpg +0 -0
  29. assets/forms/promo/img/fb-subscribe.jpg +0 -0
  30. assets/forms/promo/img/logic.png +0 -0
  31. assets/forms/promo/img/subscribe.png +0 -0
  32. assets/forms/promo/rating-stats.png +0 -0
  33. cfs.php +61 -60
  34. classes/Twig/Autoloader.php +48 -48
  35. classes/Twig/Compiler.php +270 -270
  36. classes/Twig/CompilerInterface.php +36 -36
  37. classes/Twig/Environment.php +1254 -1254
  38. classes/Twig/Error.php +248 -248
  39. classes/Twig/Error/Loader.php +31 -31
  40. classes/Twig/Error/Runtime.php +20 -20
  41. classes/Twig/Error/Syntax.php +20 -20
  42. classes/Twig/ExistsLoaderInterface.php +29 -29
  43. classes/Twig/ExpressionParser.php +598 -598
  44. classes/Twig/Extension.php +93 -93
  45. classes/Twig/Extension/Core.php +1462 -1462
  46. classes/Twig/Extension/Debug.php +71 -71
  47. classes/Twig/Extension/Escaper.php +107 -107
  48. classes/Twig/Extension/Optimizer.php +35 -35
  49. classes/Twig/Extension/Sandbox.php +112 -112
  50. classes/Twig/Extension/Staging.php +113 -113
  51. classes/Twig/Extension/StringLoader.php +64 -64
  52. classes/Twig/ExtensionInterface.php +83 -83
  53. classes/Twig/Filter.php +81 -81
  54. classes/Twig/Filter/Function.php +37 -37
  55. classes/Twig/Filter/Method.php +39 -39
  56. classes/Twig/Filter/Node.php +39 -39
  57. classes/Twig/FilterCallableInterface.php +23 -23
  58. classes/Twig/FilterInterface.php +42 -42
  59. classes/Twig/Function.php +71 -71
  60. classes/Twig/Function/Function.php +38 -38
  61. classes/Twig/Function/Method.php +40 -40
  62. classes/Twig/Function/Node.php +39 -39
  63. classes/Twig/FunctionCallableInterface.php +23 -23
  64. classes/Twig/FunctionInterface.php +39 -39
  65. classes/Twig/Lexer.php +409 -409
  66. classes/Twig/LexerInterface.php +32 -32
  67. classes/Twig/Loader/Array.php +95 -95
  68. classes/Twig/Loader/Chain.php +138 -138
  69. classes/Twig/Loader/Filesystem.php +236 -236
  70. classes/Twig/Loader/String.php +59 -59
  71. classes/Twig/LoaderInterface.php +52 -52
  72. classes/Twig/Markup.php +37 -37
  73. classes/Twig/Node.php +226 -226
  74. classes/Twig/Node/AutoEscape.php +39 -39
  75. classes/Twig/Node/Block.php +44 -44
  76. classes/Twig/Node/BlockReference.php +37 -37
  77. classes/Twig/Node/Body.php +19 -19
  78. classes/Twig/Node/Do.php +38 -38
  79. classes/Twig/Node/Embed.php +38 -38
  80. classes/Twig/Node/Expression.php +20 -20
  81. classes/Twig/Node/Expression/Array.php +86 -86
  82. classes/Twig/Node/Expression/AssignName.php +28 -28
  83. classes/Twig/Node/Expression/Binary.php +40 -40
  84. classes/Twig/Node/Expression/Binary/Add.php +18 -18
  85. classes/Twig/Node/Expression/Binary/And.php +18 -18
  86. classes/Twig/Node/Expression/Binary/BitwiseAnd.php +18 -18
  87. classes/Twig/Node/Expression/Binary/BitwiseOr.php +18 -18
  88. classes/Twig/Node/Expression/Binary/BitwiseXor.php +18 -18
  89. classes/Twig/Node/Expression/Binary/Concat.php +18 -18
  90. classes/Twig/Node/Expression/Binary/Div.php +18 -18
  91. classes/Twig/Node/Expression/Binary/EndsWith.php +30 -30
  92. classes/Twig/Node/Expression/Binary/Equal.php +17 -17
  93. classes/Twig/Node/Expression/Binary/FloorDiv.php +29 -29
  94. classes/Twig/Node/Expression/Binary/Greater.php +17 -17
  95. classes/Twig/Node/Expression/Binary/GreaterEqual.php +17 -17
  96. classes/Twig/Node/Expression/Binary/In.php +33 -33
  97. classes/Twig/Node/Expression/Binary/Less.php +17 -17
  98. classes/Twig/Node/Expression/Binary/LessEqual.php +17 -17
  99. classes/Twig/Node/Expression/Binary/Matches.php +28 -28
  100. classes/Twig/Node/Expression/Binary/Mod.php +18 -18
  101. classes/Twig/Node/Expression/Binary/Mul.php +18 -18
  102. classes/Twig/Node/Expression/Binary/NotEqual.php +17 -17
  103. classes/Twig/Node/Expression/Binary/NotIn.php +33 -33
  104. classes/Twig/Node/Expression/Binary/Or.php +18 -18
  105. classes/Twig/Node/Expression/Binary/Power.php +33 -33
  106. classes/Twig/Node/Expression/Binary/Range.php +33 -33
  107. classes/Twig/Node/Expression/Binary/StartsWith.php +28 -28
  108. classes/Twig/Node/Expression/Binary/Sub.php +18 -18
  109. classes/Twig/Node/Expression/BlockReference.php +51 -51
  110. classes/Twig/Node/Expression/Call.php +176 -176
  111. classes/Twig/Node/Expression/Conditional.php +31 -31
  112. classes/Twig/Node/Expression/Constant.php +23 -23
  113. classes/Twig/Node/Expression/ExtensionReference.php +33 -33
  114. classes/Twig/Node/Expression/Filter.php +36 -36
  115. classes/Twig/Node/Expression/Filter/Default.php +43 -43
  116. classes/Twig/Node/Expression/Function.php +35 -35
  117. classes/Twig/Node/Expression/GetAttr.php +53 -53
  118. classes/Twig/Node/Expression/MethodCall.php +41 -41
  119. classes/Twig/Node/Expression/Name.php +88 -88
  120. classes/Twig/Node/Expression/Parent.php +47 -47
  121. classes/Twig/Node/Expression/TempName.php +26 -26
  122. classes/Twig/Node/Expression/Test.php +32 -32
  123. classes/Twig/Node/Expression/Test/Constant.php +46 -46
  124. classes/Twig/Node/Expression/Test/Defined.php +54 -54
  125. classes/Twig/Node/Expression/Test/Divisibleby.php +33 -33
  126. classes/Twig/Node/Expression/Test/Even.php +32 -32
  127. classes/Twig/Node/Expression/Test/Null.php +31 -31
  128. classes/Twig/Node/Expression/Test/Odd.php +32 -32
  129. classes/Twig/Node/Expression/Test/Sameas.php +29 -29
  130. classes/Twig/Node/Expression/Unary.php +30 -30
  131. classes/Twig/Node/Expression/Unary/Neg.php +18 -18
  132. classes/Twig/Node/Expression/Unary/Not.php +18 -18
  133. classes/Twig/Node/Expression/Unary/Pos.php +18 -18
  134. classes/Twig/Node/Flush.php +36 -36
  135. classes/Twig/Node/For.php +112 -112
  136. classes/Twig/Node/ForLoop.php +55 -55
  137. classes/Twig/Node/If.php +66 -66
  138. classes/Twig/Node/Import.php +50 -50
  139. classes/Twig/Node/Include.php +99 -99
  140. classes/Twig/Node/Macro.php +96 -96
  141. classes/Twig/Node/Module.php +383 -383
  142. classes/Twig/Node/Print.php +39 -39
  143. classes/Twig/Node/Sandbox.php +47 -47
  144. classes/Twig/Node/SandboxedModule.php +60 -60
  145. classes/Twig/Node/SandboxedPrint.php +59 -59
  146. classes/Twig/Node/Set.php +101 -101
  147. classes/Twig/Node/SetTemp.php +35 -35
  148. classes/Twig/Node/Spaceless.php +40 -40
  149. classes/Twig/Node/Text.php +39 -39
  150. classes/Twig/NodeInterface.php +31 -31
  151. classes/Twig/NodeOutputInterface.php +19 -19
  152. classes/Twig/NodeTraverser.php +88 -88
  153. classes/Twig/NodeVisitor/Escaper.php +167 -167
  154. classes/Twig/NodeVisitor/Optimizer.php +246 -246
  155. classes/Twig/NodeVisitor/SafeAnalysis.php +139 -139
  156. classes/Twig/NodeVisitor/Sandbox.php +92 -92
  157. classes/Twig/NodeVisitorInterface.php +47 -47
  158. classes/Twig/Parser.php +390 -390
  159. classes/Twig/ParserInterface.php +31 -31
  160. classes/Twig/Sandbox/SecurityError.php +19 -19
  161. classes/Twig/Sandbox/SecurityPolicy.php +119 -119
  162. classes/Twig/Sandbox/SecurityPolicyInterface.php +24 -24
  163. classes/Twig/SimpleFilter.php +94 -94
  164. classes/Twig/SimpleFunction.php +84 -84
  165. classes/Twig/SimpleTest.php +46 -46
  166. classes/Twig/Template.php +485 -485
  167. classes/Twig/TemplateInterface.php +48 -48
  168. classes/Twig/Test.php +34 -34
  169. classes/Twig/TestCallableInterface.php +21 -21
  170. classes/Twig/TestInterface.php +26 -26
  171. classes/Twig/Token.php +216 -216
  172. classes/Twig/TokenParser.php +33 -33
  173. classes/Twig/TokenParser/AutoEscape.php +89 -89
  174. classes/Twig/TokenParser/Block.php +81 -81
  175. classes/Twig/TokenParser/Do.php +42 -42
  176. classes/Twig/TokenParser/Embed.php +66 -66
  177. classes/Twig/TokenParser/Extends.php +52 -52
  178. classes/Twig/TokenParser/Filter.php +61 -61
  179. classes/Twig/TokenParser/Flush.php +42 -42
  180. classes/Twig/TokenParser/For.php +135 -135
  181. classes/Twig/TokenParser/From.php +70 -70
  182. classes/Twig/TokenParser/If.php +94 -94
  183. classes/Twig/TokenParser/Import.php +49 -49
  184. classes/Twig/TokenParser/Include.php +75 -75
  185. classes/Twig/TokenParser/Macro.php +68 -68
  186. classes/Twig/TokenParser/Sandbox.php +68 -68
  187. classes/Twig/TokenParser/Set.php +83 -83
  188. classes/Twig/TokenParser/Spaceless.php +59 -59
  189. classes/Twig/TokenParser/Use.php +76 -76
  190. classes/Twig/TokenParserBroker.php +136 -136
  191. classes/Twig/TokenParserBrokerInterface.php +45 -45
  192. classes/Twig/TokenParserInterface.php +43 -43
  193. classes/Twig/TokenStream.php +156 -156
  194. classes/baseObject.php +22 -22
  195. classes/controller.php +232 -234
  196. classes/csvgenerator.php +38 -38
  197. classes/date.php +8 -8
  198. classes/db.php +154 -141
  199. classes/dispatcher.php +41 -41
  200. classes/errors.php +93 -93
  201. classes/field.php +518 -518
  202. classes/fieldAdapter.php +315 -310
  203. classes/filegenerator.php +52 -52
  204. classes/fileuploader.php +147 -142
  205. classes/frame.php +258 -500
assets/forms/img/bg/2016_ht_1_bg.jpg ADDED
Binary file
assets/forms/img/bg/bg_support_form.jpg ADDED
Binary file
assets/forms/img/bg/scf-red-background.png ADDED
Binary file
assets/forms/img/bg/tea-time.jpg ADDED
Binary file
assets/forms/img/bg/tea-time.png ADDED
Binary file
assets/forms/img/images/2016_ht_1_crist_wrench.png ADDED
Binary file
assets/forms/img/images/2016_ht_1_santa.png ADDED
Binary file
assets/forms/img/images/2016_ht_1_snow1.png ADDED
Binary file
assets/forms/img/images/2016_ht_1_snow2.png ADDED
Binary file
assets/forms/img/images/2016_ht_1_snow3.png ADDED
Binary file
assets/forms/img/images/facebook-icon.png ADDED
Binary file
assets/forms/img/images/google-plus-icon.png ADDED
Binary file
assets/forms/img/images/paper-plane.png ADDED
Binary file
assets/forms/img/images/scf-top-img-snow-1.png ADDED
Binary file
assets/forms/img/images/scf-top-img-snow-2.png ADDED
Binary file
assets/forms/img/images/support_image.png ADDED
Binary file
assets/forms/img/images/twitter-icon.png ADDED
Binary file
assets/forms/img/preview/141-merry-cristmas-prev.png ADDED
Binary file
assets/forms/img/preview/Ho-ho-ho-template-prev.png ADDED
Binary file
assets/forms/img/preview/base-contact.jpg ADDED
Binary file
assets/forms/img/preview/intransigent.jpg ADDED
Binary file
assets/forms/img/preview/kiwifruit.png ADDED
Binary file
assets/forms/img/preview/light-grey.png ADDED
Binary file
assets/forms/img/preview/neon.jpg ADDED
Binary file
assets/forms/img/preview/opacity-grey.png ADDED
Binary file
assets/forms/img/preview/simple-white.png ADDED
Binary file
assets/forms/img/preview/tea-time.png ADDED
Binary file
assets/forms/promo/img/AB-testing-pro.jpg ADDED
Binary file
assets/forms/promo/img/fb-subscribe.jpg ADDED
Binary file
assets/forms/promo/img/logic.png ADDED
Binary file
assets/forms/promo/img/subscribe.png ADDED
Binary file
assets/forms/promo/rating-stats.png ADDED
Binary file
cfs.php CHANGED
@@ -1,60 +1,61 @@
1
- <?php
2
- /**
3
- * Plugin Name: Contact Form by Supsystic
4
- * Description: Contact Form Builder with drag-and-drop editor to create responsive, mobile ready contact forms in a second. Custom fields and contact form templates
5
- * Version: 1.7.9
6
- * Author: supsystic.com
7
- * Author URI: https://supsystic.com
8
- * Text Domain: contact-form-by-supsystic
9
- * Domain Path: /languages
10
- **/
11
- /**
12
- * Base config constants and functions
13
- */
14
- require_once(dirname(__FILE__). DIRECTORY_SEPARATOR. 'config.php');
15
- require_once(dirname(__FILE__). DIRECTORY_SEPARATOR. 'functions.php');
16
- /**
17
- * Connect all required core classes
18
- */
19
- importClassCfs('dbCfs');
20
- importClassCfs('installerCfs');
21
- importClassCfs('baseObjectCfs');
22
- importClassCfs('moduleCfs');
23
- importClassCfs('moduleWidgetCfs');
24
- importClassCfs('modelCfs');
25
- importClassCfs('modelSubscribeCfs');
26
- importClassCfs('viewCfs');
27
- importClassCfs('controllerCfs');
28
- importClassCfs('helperCfs');
29
- importClassCfs('dispatcherCfs');
30
- importClassCfs('fieldCfs');
31
- importClassCfs('tableCfs');
32
- importClassCfs('frameCfs');
33
- /**
34
- * @deprecated since version 1.0.1
35
- */
36
- importClassCfs('langCfs');
37
- importClassCfs('reqCfs');
38
- importClassCfs('uriCfs');
39
- importClassCfs('htmlCfs');
40
- importClassCfs('responseCfs');
41
- importClassCfs('fieldAdapterCfs');
42
- importClassCfs('validatorCfs');
43
- importClassCfs('errorsCfs');
44
- importClassCfs('utilsCfs');
45
- importClassCfs('modInstallerCfs');
46
- importClassCfs('installerDbUpdaterCfs');
47
- importClassCfs('dateCfs');
48
- /**
49
- * Check plugin version - maybe we need to update database, and check global errors in request
50
- */
51
- installerCfs::update();
52
- errorsCfs::init();
53
- /**
54
- * Start application
55
- */
56
- frameCfs::_()->parseRoute();
57
- frameCfs::_()->init();
58
- frameCfs::_()->exec();
59
-
60
- //var_dump(frameCfs::_()->getActivationErrors()); exit();
 
1
+ <?php
2
+ /**
3
+ * Plugin Name: Contact Form by Supsystic
4
+ * Description: Contact Form Builder with drag-and-drop editor to create responsive, mobile ready contact forms in a second. Custom fields and contact form templates
5
+ * Version: 1.7.12
6
+ * Author: supsystic.com
7
+ * Author URI: https://supsystic.com
8
+ * Text Domain: contact-form-by-supsystic
9
+ * Domain Path: /languages
10
+ **/
11
+ /**
12
+ * Base config constants and functions
13
+ */
14
+ require_once(dirname(__FILE__). DIRECTORY_SEPARATOR. 'config.php');
15
+ require_once(dirname(__FILE__). DIRECTORY_SEPARATOR. 'functions.php');
16
+ /**
17
+ * Connect all required core classes
18
+ */
19
+ importSqlParser();
20
+ importClassCfs('dbCfs');
21
+ importClassCfs('installerCfs');
22
+ importClassCfs('baseObjectCfs');
23
+ importClassCfs('moduleCfs');
24
+ importClassCfs('moduleWidgetCfs');
25
+ importClassCfs('modelCfs');
26
+ importClassCfs('modelSubscribeCfs');
27
+ importClassCfs('viewCfs');
28
+ importClassCfs('controllerCfs');
29
+ importClassCfs('helperCfs');
30
+ importClassCfs('dispatcherCfs');
31
+ importClassCfs('fieldCfs');
32
+ importClassCfs('tableCfs');
33
+ importClassCfs('frameCfs');
34
+ /**
35
+ * @deprecated since version 1.0.1
36
+ */
37
+ importClassCfs('langCfs');
38
+ importClassCfs('reqCfs');
39
+ importClassCfs('uriCfs');
40
+ importClassCfs('htmlCfs');
41
+ importClassCfs('responseCfs');
42
+ importClassCfs('fieldAdapterCfs');
43
+ importClassCfs('validatorCfs');
44
+ importClassCfs('errorsCfs');
45
+ importClassCfs('utilsCfs');
46
+ importClassCfs('modInstallerCfs');
47
+ importClassCfs('installerDbUpdaterCfs');
48
+ importClassCfs('dateCfs');
49
+ /**
50
+ * Check plugin version - maybe we need to update database, and check global errors in request
51
+ */
52
+ installerCfs::update();
53
+ errorsCfs::init();
54
+ /**
55
+ * Start application
56
+ */
57
+ frameCfs::_()->parseRoute();
58
+ frameCfs::_()->init();
59
+ frameCfs::_()->exec();
60
+
61
+ //var_dump(frameCfs::_()->getActivationErrors()); exit();
classes/Twig/Autoloader.php CHANGED
@@ -1,48 +1,48 @@
1
- <?php
2
-
3
- /*
4
- * This file is part of Twig.
5
- *
6
- * (c) 2009 Fabien Potencier
7
- *
8
- * For the full copyright and license information, please view the LICENSE
9
- * file that was distributed with this source code.
10
- */
11
-
12
- /**
13
- * Autoloads Twig classes.
14
- *
15
- * @author Fabien Potencier <fabien@symfony.com>
16
- */
17
- class Twig_Autoloader
18
- {
19
- /**
20
- * Registers Twig_Autoloader as an SPL autoloader.
21
- *
22
- * @param bool $prepend Whether to prepend the autoloader or not.
23
- */
24
- public static function register($prepend = false)
25
- {
26
- if (version_compare(phpversion(), '5.3.0', '>=')) {
27
- spl_autoload_register(array(__CLASS__, 'autoload'), true, $prepend);
28
- } else {
29
- spl_autoload_register(array(__CLASS__, 'autoload'));
30
- }
31
- }
32
-
33
- /**
34
- * Handles autoloading of classes.
35
- *
36
- * @param string $class A class name.
37
- */
38
- public static function autoload($class)
39
- {
40
- if (0 !== strpos($class, 'Twig')) {
41
- return;
42
- }
43
-
44
- if (is_file($file = dirname(__FILE__).'/../'.str_replace(array('_', "\0"), array('/', ''), $class).'.php')) {
45
- require $file;
46
- }
47
- }
48
- }
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2009 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ /**
13
+ * Autoloads Twig classes.
14
+ *
15
+ * @author Fabien Potencier <fabien@symfony.com>
16
+ */
17
+ class Twig_Autoloader
18
+ {
19
+ /**
20
+ * Registers Twig_Autoloader as an SPL autoloader.
21
+ *
22
+ * @param bool $prepend Whether to prepend the autoloader or not.
23
+ */
24
+ public static function register($prepend = false)
25
+ {
26
+ if (version_compare(phpversion(), '5.3.0', '>=')) {
27
+ spl_autoload_register(array(__CLASS__, 'autoload'), true, $prepend);
28
+ } else {
29
+ spl_autoload_register(array(__CLASS__, 'autoload'));
30
+ }
31
+ }
32
+
33
+ /**
34
+ * Handles autoloading of classes.
35
+ *
36
+ * @param string $class A class name.
37
+ */
38
+ public static function autoload($class)
39
+ {
40
+ if (0 !== strpos($class, 'Twig')) {
41
+ return;
42
+ }
43
+
44
+ if (is_file($file = dirname(__FILE__).'/../'.str_replace(array('_', "\0"), array('/', ''), $class).'.php')) {
45
+ require $file;
46
+ }
47
+ }
48
+ }
classes/Twig/Compiler.php CHANGED
@@ -1,270 +1,270 @@
1
- <?php
2
-
3
- /*
4
- * This file is part of Twig.
5
- *
6
- * (c) 2009 Fabien Potencier
7
- * (c) 2009 Armin Ronacher
8
- *
9
- * For the full copyright and license information, please view the LICENSE
10
- * file that was distributed with this source code.
11
- */
12
-
13
- /**
14
- * Compiles a node to PHP code.
15
- *
16
- * @author Fabien Potencier <fabien@symfony.com>
17
- */
18
- class Twig_Compiler implements Twig_CompilerInterface
19
- {
20
- protected $lastLine;
21
- protected $source;
22
- protected $indentation;
23
- protected $env;
24
- protected $debugInfo;
25
- protected $sourceOffset;
26
- protected $sourceLine;
27
- protected $filename;
28
-
29
- /**
30
- * Constructor.
31
- *
32
- * @param Twig_Environment $env The twig environment instance
33
- */
34
- public function __construct(Twig_Environment $env)
35
- {
36
- $this->env = $env;
37
- $this->debugInfo = array();
38
- }
39
-
40
- public function getFilename()
41
- {
42
- return $this->filename;
43
- }
44
-
45
- /**
46
- * Returns the environment instance related to this compiler.
47
- *
48
- * @return Twig_Environment The environment instance
49
- */
50
- public function getEnvironment()
51
- {
52
- return $this->env;
53
- }
54
-
55
- /**
56
- * Gets the current PHP code after compilation.
57
- *
58
- * @return string The PHP code
59
- */
60
- public function getSource()
61
- {
62
- return $this->source;
63
- }
64
-
65
- /**
66
- * Compiles a node.
67
- *
68
- * @param Twig_NodeInterface $node The node to compile
69
- * @param int $indentation The current indentation
70
- *
71
- * @return Twig_Compiler The current compiler instance
72
- */
73
- public function compile(Twig_NodeInterface $node, $indentation = 0)
74
- {
75
- $this->lastLine = null;
76
- $this->source = '';
77
- $this->sourceOffset = 0;
78
- // source code starts at 1 (as we then increment it when we encounter new lines)
79
- $this->sourceLine = 1;
80
- $this->indentation = $indentation;
81
-
82
- if ($node instanceof Twig_Node_Module) {
83
- $this->filename = $node->getAttribute('filename');
84
- }
85
-
86
- $node->compile($this);
87
-
88
- return $this;
89
- }
90
-
91
- public function subcompile(Twig_NodeInterface $node, $raw = true)
92
- {
93
- if (false === $raw) {
94
- $this->addIndentation();
95
- }
96
-
97
- $node->compile($this);
98
-
99
- return $this;
100
- }
101
-
102
- /**
103
- * Adds a raw string to the compiled code.
104
- *
105
- * @param string $string The string
106
- *
107
- * @return Twig_Compiler The current compiler instance
108
- */
109
- public function raw($string)
110
- {
111
- $this->source .= $string;
112
-
113
- return $this;
114
- }
115
-
116
- /**
117
- * Writes a string to the compiled code by adding indentation.
118
- *
119
- * @return Twig_Compiler The current compiler instance
120
- */
121
- public function write()
122
- {
123
- $strings = func_get_args();
124
- foreach ($strings as $string) {
125
- $this->addIndentation();
126
- $this->source .= $string;
127
- }
128
-
129
- return $this;
130
- }
131
-
132
- /**
133
- * Appends an indentation to the current PHP code after compilation.
134
- *
135
- * @return Twig_Compiler The current compiler instance
136
- */
137
- public function addIndentation()
138
- {
139
- $this->source .= str_repeat(' ', $this->indentation * 4);
140
-
141
- return $this;
142
- }
143
-
144
- /**
145
- * Adds a quoted string to the compiled code.
146
- *
147
- * @param string $value The string
148
- *
149
- * @return Twig_Compiler The current compiler instance
150
- */
151
- public function string($value)
152
- {
153
- $this->source .= sprintf('"%s"', addcslashes($value, "\0\t\"\$\\"));
154
-
155
- return $this;
156
- }
157
-
158
- /**
159
- * Returns a PHP representation of a given value.
160
- *
161
- * @param mixed $value The value to convert
162
- *
163
- * @return Twig_Compiler The current compiler instance
164
- */
165
- public function repr($value)
166
- {
167
- if (is_int($value) || is_float($value)) {
168
- if (false !== $locale = setlocale(LC_NUMERIC, 0)) {
169
- setlocale(LC_NUMERIC, 'C');
170
- }
171
-
172
- $this->raw($value);
173
-
174
- if (false !== $locale) {
175
- setlocale(LC_NUMERIC, $locale);
176
- }
177
- } elseif (null === $value) {
178
- $this->raw('null');
179
- } elseif (is_bool($value)) {
180
- $this->raw($value ? 'true' : 'false');
181
- } elseif (is_array($value)) {
182
- $this->raw('array(');
183
- $first = true;
184
- foreach ($value as $key => $value) {
185
- if (!$first) {
186
- $this->raw(', ');
187
- }
188
- $first = false;
189
- $this->repr($key);
190
- $this->raw(' => ');
191
- $this->repr($value);
192
- }
193
- $this->raw(')');
194
- } else {
195
- $this->string($value);
196
- }
197
-
198
- return $this;
199
- }
200
-
201
- /**
202
- * Adds debugging information.
203
- *
204
- * @param Twig_NodeInterface $node The related twig node
205
- *
206
- * @return Twig_Compiler The current compiler instance
207
- */
208
- public function addDebugInfo(Twig_NodeInterface $node)
209
- {
210
- if ($node->getLine() != $this->lastLine) {
211
- $this->write(sprintf("// line %d\n", $node->getLine()));
212
-
213
- // when mbstring.func_overload is set to 2
214
- // mb_substr_count() replaces substr_count()
215
- // but they have different signatures!
216
- if (((int) ini_get('mbstring.func_overload')) & 2) {
217
- // this is much slower than the "right" version
218
- $this->sourceLine += mb_substr_count(mb_substr($this->source, $this->sourceOffset), "\n");
219
- } else {
220
- $this->sourceLine += substr_count($this->source, "\n", $this->sourceOffset);
221
- }
222
- $this->sourceOffset = strlen($this->source);
223
- $this->debugInfo[$this->sourceLine] = $node->getLine();
224
-
225
- $this->lastLine = $node->getLine();
226
- }
227
-
228
- return $this;
229
- }
230
-
231
- public function getDebugInfo()
232
- {
233
- return $this->debugInfo;
234
- }
235
-
236
- /**
237
- * Indents the generated code.
238
- *
239
- * @param int $step The number of indentation to add
240
- *
241
- * @return Twig_Compiler The current compiler instance
242
- */
243
- public function indent($step = 1)
244
- {
245
- $this->indentation += $step;
246
-
247
- return $this;
248
- }
249
-
250
- /**
251
- * Outdents the generated code.
252
- *
253
- * @param int $step The number of indentation to remove
254
- *
255
- * @return Twig_Compiler The current compiler instance
256
- *
257
- * @throws LogicException When trying to outdent too much so the indentation would become negative
258
- */
259
- public function outdent($step = 1)
260
- {
261
- // can't outdent by more steps than the current indentation level
262
- if ($this->indentation < $step) {
263
- throw new LogicException('Unable to call outdent() as the indentation would become negative');
264
- }
265
-
266
- $this->indentation -= $step;
267
-
268
- return $this;
269
- }
270
- }
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2009 Fabien Potencier
7
+ * (c) 2009 Armin Ronacher
8
+ *
9
+ * For the full copyright and license information, please view the LICENSE
10
+ * file that was distributed with this source code.
11
+ */
12
+
13
+ /**
14
+ * Compiles a node to PHP code.
15
+ *
16
+ * @author Fabien Potencier <fabien@symfony.com>
17
+ */
18
+ class Twig_Compiler implements Twig_CompilerInterface
19
+ {
20
+ protected $lastLine;
21
+ protected $source;
22
+ protected $indentation;
23
+ protected $env;
24
+ protected $debugInfo;
25
+ protected $sourceOffset;
26
+ protected $sourceLine;
27
+ protected $filename;
28
+
29
+ /**
30
+ * Constructor.
31
+ *
32
+ * @param Twig_Environment $env The twig environment instance
33
+ */
34
+ public function __construct(Twig_Environment $env)
35
+ {
36
+ $this->env = $env;
37
+ $this->debugInfo = array();
38
+ }
39
+
40
+ public function getFilename()
41
+ {
42
+ return $this->filename;
43
+ }
44
+
45
+ /**
46
+ * Returns the environment instance related to this compiler.
47
+ *
48
+ * @return Twig_Environment The environment instance
49
+ */
50
+ public function getEnvironment()
51
+ {
52
+ return $this->env;
53
+ }
54
+
55
+ /**
56
+ * Gets the current PHP code after compilation.
57
+ *
58
+ * @return string The PHP code
59
+ */
60
+ public function getSource()
61
+ {
62
+ return $this->source;
63
+ }
64
+
65
+ /**
66
+ * Compiles a node.
67
+ *
68
+ * @param Twig_NodeInterface $node The node to compile
69
+ * @param int $indentation The current indentation
70
+ *
71
+ * @return Twig_Compiler The current compiler instance
72
+ */
73
+ public function compile(Twig_NodeInterface $node, $indentation = 0)
74
+ {
75
+ $this->lastLine = null;
76
+ $this->source = '';
77
+ $this->sourceOffset = 0;
78
+ // source code starts at 1 (as we then increment it when we encounter new lines)
79
+ $this->sourceLine = 1;
80
+ $this->indentation = $indentation;
81
+
82
+ if ($node instanceof Twig_Node_Module) {
83
+ $this->filename = $node->getAttribute('filename');
84
+ }
85
+
86
+ $node->compile($this);
87
+
88
+ return $this;
89
+ }
90
+
91
+ public function subcompile(Twig_NodeInterface $node, $raw = true)
92
+ {
93
+ if (false === $raw) {
94
+ $this->addIndentation();
95
+ }
96
+
97
+ $node->compile($this);
98
+
99
+ return $this;
100
+ }
101
+
102
+ /**
103
+ * Adds a raw string to the compiled code.
104
+ *
105
+ * @param string $string The string
106
+ *
107
+ * @return Twig_Compiler The current compiler instance
108
+ */
109
+ public function raw($string)
110
+ {
111
+ $this->source .= $string;
112
+
113
+ return $this;
114
+ }
115
+
116
+ /**
117
+ * Writes a string to the compiled code by adding indentation.
118
+ *
119
+ * @return Twig_Compiler The current compiler instance
120
+ */
121
+ public function write()
122
+ {
123
+ $strings = func_get_args();
124
+ foreach ($strings as $string) {
125
+ $this->addIndentation();
126
+ $this->source .= $string;
127
+ }
128
+
129
+ return $this;
130
+ }
131
+
132
+ /**
133
+ * Appends an indentation to the current PHP code after compilation.
134
+ *
135
+ * @return Twig_Compiler The current compiler instance
136
+ */
137
+ public function addIndentation()
138
+ {
139
+ $this->source .= str_repeat(' ', $this->indentation * 4);
140
+
141
+ return $this;
142
+ }
143
+
144
+ /**
145
+ * Adds a quoted string to the compiled code.
146
+ *
147
+ * @param string $value The string
148
+ *
149
+ * @return Twig_Compiler The current compiler instance
150
+ */
151
+ public function string($value)
152
+ {
153
+ $this->source .= sprintf('"%s"', addcslashes($value, "\0\t\"\$\\"));
154
+
155
+ return $this;
156
+ }
157
+
158
+ /**
159
+ * Returns a PHP representation of a given value.
160
+ *
161
+ * @param mixed $value The value to convert
162
+ *
163
+ * @return Twig_Compiler The current compiler instance
164
+ */
165
+ public function repr($value)
166
+ {
167
+ if (is_int($value) || is_float($value)) {
168
+ if (false !== $locale = setlocale(LC_NUMERIC, 0)) {
169
+ setlocale(LC_NUMERIC, 'C');
170
+ }
171
+
172
+ $this->raw($value);
173
+
174
+ if (false !== $locale) {
175
+ setlocale(LC_NUMERIC, $locale);
176
+ }
177
+ } elseif (null === $value) {
178
+ $this->raw('null');
179
+ } elseif (is_bool($value)) {
180
+ $this->raw($value ? 'true' : 'false');
181
+ } elseif (is_array($value)) {
182
+ $this->raw('array(');
183
+ $first = true;
184
+ foreach ($value as $key => $value) {
185
+ if (!$first) {
186
+ $this->raw(', ');
187
+ }
188
+ $first = false;
189
+ $this->repr($key);
190
+ $this->raw(' => ');
191
+ $this->repr($value);
192
+ }
193
+ $this->raw(')');
194
+ } else {
195
+ $this->string($value);
196
+ }
197
+
198
+ return $this;
199
+ }
200
+
201
+ /**
202
+ * Adds debugging information.
203
+ *
204
+ * @param Twig_NodeInterface $node The related twig node
205
+ *
206
+ * @return Twig_Compiler The current compiler instance
207
+ */
208
+ public function addDebugInfo(Twig_NodeInterface $node)
209
+ {
210
+ if ($node->getLine() != $this->lastLine) {
211
+ $this->write(sprintf("// line %d\n", $node->getLine()));
212
+
213
+ // when mbstring.func_overload is set to 2
214
+ // mb_substr_count() replaces substr_count()
215
+ // but they have different signatures!
216
+ if (((int) ini_get('mbstring.func_overload')) & 2) {
217
+ // this is much slower than the "right" version
218
+ $this->sourceLine += mb_substr_count(mb_substr($this->source, $this->sourceOffset), "\n");
219
+ } else {
220
+ $this->sourceLine += substr_count($this->source, "\n", $this->sourceOffset);
221
+ }
222
+ $this->sourceOffset = strlen($this->source);
223
+ $this->debugInfo[$this->sourceLine] = $node->getLine();
224
+
225
+ $this->lastLine = $node->getLine();
226
+ }
227
+
228
+ return $this;
229
+ }
230
+
231
+ public function getDebugInfo()
232
+ {
233
+ return $this->debugInfo;
234
+ }
235
+
236
+ /**
237
+ * Indents the generated code.
238
+ *
239
+ * @param int $step The number of indentation to add
240
+ *
241
+ * @return Twig_Compiler The current compiler instance
242
+ */
243
+ public function indent($step = 1)
244
+ {
245
+ $this->indentation += $step;
246
+
247
+ return $this;
248
+ }
249
+
250
+ /**
251
+ * Outdents the generated code.
252
+ *
253
+ * @param int $step The number of indentation to remove
254
+ *
255
+ * @return Twig_Compiler The current compiler instance
256
+ *
257
+ * @throws LogicException When trying to outdent too much so the indentation would become negative
258
+ */
259
+ public function outdent($step = 1)
260
+ {
261
+ // can't outdent by more steps than the current indentation level
262
+ if ($this->indentation < $step) {
263
+ throw new LogicException('Unable to call outdent() as the indentation would become negative');
264
+ }
265
+
266
+ $this->indentation -= $step;
267
+
268
+ return $this;
269
+ }
270
+ }
classes/Twig/CompilerInterface.php CHANGED
@@ -1,36 +1,36 @@
1
- <?php
2
-
3
- /*
4
- * This file is part of Twig.
5
- *
6
- * (c) 2009 Fabien Potencier
7
- *
8
- * For the full copyright and license information, please view the LICENSE
9
- * file that was distributed with this source code.
10
- */
11
-
12
- /**
13
- * Interface implemented by compiler classes.
14
- *
15
- * @author Fabien Potencier <fabien@symfony.com>
16
- *
17
- * @deprecated since 1.12 (to be removed in 3.0)
18
- */
19
- interface Twig_CompilerInterface
20
- {
21
- /**
22
- * Compiles a node.
23
- *
24
- * @param Twig_NodeInterface $node The node to compile
25
- *
26
- * @return Twig_CompilerInterface The current compiler instance
27
- */
28
- public function compile(Twig_NodeInterface $node);
29
-
30
- /**
31
- * Gets the current PHP code after compilation.
32
- *
33
- * @return string The PHP code
34
- */
35
- public function getSource();
36
- }
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2009 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ /**
13
+ * Interface implemented by compiler classes.
14
+ *
15
+ * @author Fabien Potencier <fabien@symfony.com>
16
+ *
17
+ * @deprecated since 1.12 (to be removed in 3.0)
18
+ */
19
+ interface Twig_CompilerInterface
20
+ {
21
+ /**
22
+ * Compiles a node.
23
+ *
24
+ * @param Twig_NodeInterface $node The node to compile
25
+ *
26
+ * @return Twig_CompilerInterface The current compiler instance
27
+ */
28
+ public function compile(Twig_NodeInterface $node);
29
+
30
+ /**
31
+ * Gets the current PHP code after compilation.
32
+ *
33
+ * @return string The PHP code
34
+ */
35
+ public function getSource();
36
+ }
classes/Twig/Environment.php CHANGED
@@ -1,1254 +1,1254 @@
1
- <?php
2
-
3
- /*
4
- * This file is part of Twig.
5
- *
6
- * (c) 2009 Fabien Potencier
7
- *
8
- * For the full copyright and license information, please view the LICENSE
9
- * file that was distributed with this source code.
10
- */
11
-
12
- /**
13
- * Stores the Twig configuration.
14
- *
15
- * @author Fabien Potencier <fabien@symfony.com>
16
- */
17
- class Twig_Environment
18
- {
19
- const VERSION = '1.16.0';
20
-
21
- protected $charset;
22
- protected $loader;
23
- protected $debug;
24
- protected $autoReload;
25
- protected $cache;
26
- protected $lexer;
27
- protected $parser;
28
- protected $compiler;
29
- protected $baseTemplateClass;
30
- protected $extensions;
31
- protected $parsers;
32
- protected $visitors;
33
- protected $filters;
34
- protected $tests;
35
- protected $functions;
36
- protected $globals;
37
- protected $runtimeInitialized;
38
- protected $extensionInitialized;
39
- protected $loadedTemplates;
40
- protected $strictVariables;
41
- protected $unaryOperators;
42
- protected $binaryOperators;
43
- protected $templateClassPrefix = '__TwigTemplate_';
44
- protected $functionCallbacks;
45
- protected $filterCallbacks;
46
- protected $staging;
47
-
48
- /**
49
- * Constructor.
50
- *
51
- * Available options:
52
- *
53
- * * debug: When set to true, it automatically set "auto_reload" to true as
54
- * well (default to false).
55
- *
56
- * * charset: The charset used by the templates (default to UTF-8).
57
- *
58
- * * base_template_class: The base template class to use for generated
59
- * templates (default to Twig_Template).
60
- *
61
- * * cache: An absolute path where to store the compiled templates, or
62
- * false to disable compilation cache (default).
63
- *
64
- * * auto_reload: Whether to reload the template if the original source changed.
65
- * If you don't provide the auto_reload option, it will be
66
- * determined automatically based on the debug value.
67
- *
68
- * * strict_variables: Whether to ignore invalid variables in templates
69
- * (default to false).
70
- *
71
- * * autoescape: Whether to enable auto-escaping (default to html):
72
- * * false: disable auto-escaping
73
- * * true: equivalent to html
74
- * * html, js: set the autoescaping to one of the supported strategies
75
- * * PHP callback: a PHP callback that returns an escaping strategy based on the template "filename"
76
- *
77
- * * optimizations: A flag that indicates which optimizations to apply
78
- * (default to -1 which means that all optimizations are enabled;
79
- * set it to 0 to disable).
80
- *
81
- * @param Twig_LoaderInterface $loader A Twig_LoaderInterface instance
82
- * @param array $options An array of options
83
- */
84
- public function __construct(Twig_LoaderInterface $loader = null, $options = array())
85
- {
86
- if (null !== $loader) {
87
- $this->setLoader($loader);
88
- }
89
-
90
- $options = array_merge(array(
91
- 'debug' => false,
92
- 'charset' => 'UTF-8',
93
- 'base_template_class' => 'Twig_Template',
94
- 'strict_variables' => false,
95
- 'autoescape' => 'html',
96
- 'cache' => false,
97
- 'auto_reload' => null,
98
- 'optimizations' => -1,
99
- ), $options);
100
-
101
- $this->debug = (bool) $options['debug'];
102
- $this->charset = strtoupper($options['charset']);
103
- $this->baseTemplateClass = $options['base_template_class'];
104
- $this->autoReload = null === $options['auto_reload'] ? $this->debug : (bool) $options['auto_reload'];
105
- $this->strictVariables = (bool) $options['strict_variables'];
106
- $this->runtimeInitialized = false;
107
- $this->setCache($options['cache']);
108
- $this->functionCallbacks = array();
109
- $this->filterCallbacks = array();
110
-
111
- $this->addExtension(new Twig_Extension_Core());
112
- $this->addExtension(new Twig_Extension_Escaper($options['autoescape']));
113
- $this->addExtension(new Twig_Extension_Optimizer($options['optimizations']));
114
- $this->extensionInitialized = false;
115
- $this->staging = new Twig_Extension_Staging();
116
- }
117
-
118
- /**
119
- * Gets the base template class for compiled templates.
120
- *
121
- * @return string The base template class name
122
- */
123
- public function getBaseTemplateClass()
124
- {
125
- return $this->baseTemplateClass;
126
- }
127
-
128
- /**
129
- * Sets the base template class for compiled templates.
130
- *
131
- * @param string $class The base template class name
132
- */
133
- public function setBaseTemplateClass($class)
134
- {
135
- $this->baseTemplateClass = $class;
136
- }
137
-
138
- /**
139
- * Enables debugging mode.
140
- */
141
- public function enableDebug()
142
- {
143
- $this->debug = true;
144
- }
145
-
146
- /**
147
- * Disables debugging mode.
148
- */
149
- public function disableDebug()
150
- {
151
- $this->debug = false;
152
- }
153
-
154
- /**
155
- * Checks if debug mode is enabled.
156
- *
157
- * @return bool true if debug mode is enabled, false otherwise
158
- */
159
- public function isDebug()
160
- {
161
- return $this->debug;
162
- }
163
-
164
- /**
165
- * Enables the auto_reload option.
166
- */
167
- public function enableAutoReload()
168
- {
169
- $this->autoReload = true;
170
- }
171
-
172
- /**
173
- * Disables the auto_reload option.
174
- */
175
- public function disableAutoReload()
176
- {
177
- $this->autoReload = false;
178
- }
179
-
180
- /**
181
- * Checks if the auto_reload option is enabled.
182
- *
183
- * @return bool true if auto_reload is enabled, false otherwise
184
- */
185
- public function isAutoReload()
186
- {
187
- return $this->autoReload;
188
- }
189
-
190
- /**
191
- * Enables the strict_variables option.
192
- */
193
- public function enableStrictVariables()
194
- {
195
- $this->strictVariables = true;
196
- }
197
-
198
- /**
199
- * Disables the strict_variables option.
200
- */
201
- public function disableStrictVariables()
202
- {
203
- $this->strictVariables = false;
204
- }
205
-
206
- /**
207
- * Checks if the strict_variables option is enabled.
208
- *
209
- * @return bool true if strict_variables is enabled, false otherwise
210
- */
211
- public function isStrictVariables()
212
- {
213
- return $this->strictVariables;
214
- }
215
-
216
- /**
217
- * Gets the cache directory or false if cache is disabled.
218
- *
219
- * @return string|false
220
- */
221
- public function getCache()
222
- {
223
- return $this->cache;
224
- }
225
-
226
- /**
227
- * Sets the cache directory or false if cache is disabled.
228
- *
229
- * @param string|false $cache The absolute path to the compiled templates,
230
- * or false to disable cache
231
- */
232
- public function setCache($cache)
233
- {
234
- $this->cache = $cache ? $cache : false;
235
- }
236
-
237
- /**
238
- * Gets the cache filename for a given template.
239
- *
240
- * @param string $name The template name
241
- *
242
- * @return string|false The cache file name or false when caching is disabled
243
- */
244
- public function getCacheFilename($name)
245
- {
246
- if (false === $this->cache) {
247
- return false;
248
- }
249
-
250
- $class = substr($this->getTemplateClass($name), strlen($this->templateClassPrefix));
251
-
252
- return $this->getCache().'/'.substr($class, 0, 2).'/'.substr($class, 2, 2).'/'.substr($class, 4).'.php';
253
- }
254
-
255
- /**
256
- * Gets the template class associated with the given string.
257
- *
258
- * @param string $name The name for which to calculate the template class name
259
- * @param int $index The index if it is an embedded template
260
- *
261
- * @return string The template class name
262
- */
263
- public function getTemplateClass($name, $index = null)
264
- {
265
- return $this->templateClassPrefix.hash('sha256', $this->getLoader()->getCacheKey($name)).(null === $index ? '' : '_'.$index);
266
- }
267
-
268
- /**
269
- * Gets the template class prefix.
270
- *
271
- * @return string The template class prefix
272
- */
273
- public function getTemplateClassPrefix()
274
- {
275
- return $this->templateClassPrefix;
276
- }
277
-
278
- /**
279
- * Renders a template.
280
- *
281
- * @param string $name The template name
282
- * @param array $context An array of parameters to pass to the template
283
- *
284
- * @return string The rendered template
285
- *
286
- * @throws Twig_Error_Loader When the template cannot be found
287
- * @throws Twig_Error_Syntax When an error occurred during compilation
288
- * @throws Twig_Error_Runtime When an error occurred during rendering
289
- */
290
- public function render($name, array $context = array())
291
- {
292
- return $this->loadTemplate($name)->render($context);
293
- }
294
-
295
- /**
296
- * Displays a template.
297
- *
298
- * @param string $name The template name
299
- * @param array $context An array of parameters to pass to the template
300
- *
301
- * @throws Twig_Error_Loader When the template cannot be found
302
- * @throws Twig_Error_Syntax When an error occurred during compilation
303
- * @throws Twig_Error_Runtime When an error occurred during rendering
304
- */
305
- public function display($name, array $context = array())
306
- {
307
- $this->loadTemplate($name)->display($context);
308
- }
309
-
310
- /**
311
- * Loads a template by name.
312
- *
313
- * @param string $name The template name
314
- * @param int $index The index if it is an embedded template
315
- *
316
- * @return Twig_TemplateInterface A template instance representing the given template name
317
- *
318
- * @throws Twig_Error_Loader When the template cannot be found
319
- * @throws Twig_Error_Syntax When an error occurred during compilation
320
- */
321
- public function loadTemplate($name, $index = null)
322
- {
323
- $cls = $this->getTemplateClass($name, $index);
324
-
325
- if (isset($this->loadedTemplates[$cls])) {
326
- return $this->loadedTemplates[$cls];
327
- }
328
-
329
- if (!class_exists($cls, false)) {
330
- if (false === $cache = $this->getCacheFilename($name)) {
331
- eval('?>'.$this->compileSource($this->getLoader()->getSource($name), $name));
332
- } else {
333
- if (!is_file($cache) || ($this->isAutoReload() && !$this->isTemplateFresh($name, filemtime($cache)))) {
334
- $this->writeCacheFile($cache, $this->compileSource($this->getLoader()->getSource($name), $name));
335
- }
336
-
337
- require_once $cache;
338
- }
339
- }
340
-
341
- if (!$this->runtimeInitialized) {
342
- $this->initRuntime();
343
- }
344
-
345
- return $this->loadedTemplates[$cls] = new $cls($this);
346
- }
347
-
348
- /**
349
- * Returns true if the template is still fresh.
350
- *
351
- * Besides checking the loader for freshness information,
352
- * this method also checks if the enabled extensions have
353
- * not changed.
354
- *
355
- * @param string $name The template name
356
- * @param timestamp $time The last modification time of the cached template
357
- *
358
- * @return bool true if the template is fresh, false otherwise
359
- */
360
- public function isTemplateFresh($name, $time)
361
- {
362
- foreach ($this->extensions as $extension) {
363
- $r = new ReflectionObject($extension);
364
- if (filemtime($r->getFileName()) > $time) {
365
- return false;
366
- }
367
- }
368
-
369
- return $this->getLoader()->isFresh($name, $time);
370
- }
371
-
372
- /**
373
- * Tries to load a template consecutively from an array.
374
- *
375
- * Similar to loadTemplate() but it also accepts Twig_TemplateInterface instances and an array
376
- * of templates where each is tried to be loaded.
377
- *
378
- * @param string|Twig_Template|array $names A template or an array of templates to try consecutively
379
- *
380
- * @return Twig_Template
381
- *
382
- * @throws Twig_Error_Loader When none of the templates can be found
383
- * @throws Twig_Error_Syntax When an error occurred during compilation
384
- */
385
- public function resolveTemplate($names)
386
- {
387
- if (!is_array($names)) {
388
- $names = array($names);
389
- }
390
-
391
- foreach ($names as $name) {
392
- if ($name instanceof Twig_Template) {
393
- return $name;
394
- }
395
-
396
- try {
397
- return $this->loadTemplate($name);
398
- } catch (Twig_Error_Loader $e) {
399
- }
400
- }
401
-
402
- if (1 === count($names)) {
403
- throw $e;
404
- }
405
-
406
- throw new Twig_Error_Loader(sprintf('Unable to find one of the following templates: "%s".', implode('", "', $names)));
407
- }
408
-
409
- /**
410
- * Clears the internal template cache.
411
- */
412
- public function clearTemplateCache()
413
- {
414
- $this->loadedTemplates = array();
415
- }
416
-
417
- /**
418
- * Clears the template cache files on the filesystem.
419
- */
420
- public function clearCacheFiles()
421
- {
422
- if (false === $this->cache) {
423
- return;
424
- }
425
-
426
- foreach (new RecursiveIteratorIterator(new RecursiveDirectoryIterator($this->cache), RecursiveIteratorIterator::LEAVES_ONLY) as $file) {
427
- if ($file->isFile()) {
428
- @unlink($file->getPathname());
429
- }
430
- }
431
- }
432
-
433
- /**
434
- * Gets the Lexer instance.
435
- *
436
- * @return Twig_LexerInterface A Twig_LexerInterface instance
437
- */
438
- public function getLexer()
439
- {
440
- if (null === $this->lexer) {
441
- $this->lexer = new Twig_Lexer($this);
442
- }
443
-
444
- return $this->lexer;
445
- }
446
-
447
- /**
448
- * Sets the Lexer instance.
449
- *
450
- * @param Twig_LexerInterface A Twig_LexerInterface instance
451
- */
452
- public function setLexer(Twig_LexerInterface $lexer)
453
- {
454
- $this->lexer = $lexer;
455
- }
456
-
457
- /**
458
- * Tokenizes a source code.
459
- *
460
- * @param string $source The template source code
461
- * @param string $name The template name
462
- *
463
- * @return Twig_TokenStream A Twig_TokenStream instance
464
- *
465
- * @throws Twig_Error_Syntax When the code is syntactically wrong
466
- */
467
- public function tokenize($source, $name = null)
468
- {
469
- return $this->getLexer()->tokenize($source, $name);
470
- }
471
-
472
- /**
473
- * Gets the Parser instance.
474
- *
475
- * @return Twig_ParserInterface A Twig_ParserInterface instance
476
- */
477
- public function getParser()
478
- {
479
- if (null === $this->parser) {
480
- $this->parser = new Twig_Parser($this);
481
- }
482
-
483
- return $this->parser;
484
- }
485
-
486
- /**
487
- * Sets the Parser instance.
488
- *
489
- * @param Twig_ParserInterface A Twig_ParserInterface instance
490
- */
491
- public function setParser(Twig_ParserInterface $parser)
492
- {
493
- $this->parser = $parser;
494
- }
495
-
496
- /**
497
- * Converts a token stream to a node tree.
498
- *
499
- * @param Twig_TokenStream $stream A token stream instance
500
- *
501
- * @return Twig_Node_Module A node tree
502
- *
503
- * @throws Twig_Error_Syntax When the token stream is syntactically or semantically wrong
504
- */
505
- public function parse(Twig_TokenStream $stream)
506
- {
507
- return $this->getParser()->parse($stream);
508
- }
509
-
510
- /**
511
- * Gets the Compiler instance.
512
- *
513
- * @return Twig_CompilerInterface A Twig_CompilerInterface instance
514
- */
515
- public function getCompiler()
516
- {
517
- if (null === $this->compiler) {
518
- $this->compiler = new Twig_Compiler($this);
519
- }
520
-
521
- return $this->compiler;
522
- }
523
-
524
- /**
525
- * Sets the Compiler instance.
526
- *
527
- * @param Twig_CompilerInterface $compiler A Twig_CompilerInterface instance
528
- */
529
- public function setCompiler(Twig_CompilerInterface $compiler)
530
- {
531
- $this->compiler = $compiler;
532
- }
533
-
534
- /**
535
- * Compiles a node and returns the PHP code.
536
- *
537
- * @param Twig_NodeInterface $node A Twig_NodeInterface instance
538
- *
539
- * @return string The compiled PHP source code
540
- */
541
- public function compile(Twig_NodeInterface $node)
542
- {
543
- return $this->getCompiler()->compile($node)->getSource();
544
- }
545
-
546
- /**
547
- * Compiles a template source code.
548
- *
549
- * @param string $source The template source code
550
- * @param string $name The template name
551
- *
552
- * @return string The compiled PHP source code
553
- *
554
- * @throws Twig_Error_Syntax When there was an error during tokenizing, parsing or compiling
555
- */
556
- public function compileSource($source, $name = null)
557
- {
558
- try {
559
- return $this->compile($this->parse($this->tokenize($source, $name)));
560
- } catch (Twig_Error $e) {
561
- $e->setTemplateFile($name);
562
- throw $e;
563
- } catch (Exception $e) {
564
- throw new Twig_Error_Syntax(sprintf('An exception has been thrown during the compilation of a template ("%s").', $e->getMessage()), -1, $name, $e);
565
- }
566
- }
567
-
568
- /**
569
- * Sets the Loader instance.
570
- *
571
- * @param Twig_LoaderInterface $loader A Twig_LoaderInterface instance
572
- */
573
- public function setLoader(Twig_LoaderInterface $loader)
574
- {
575
- $this->loader = $loader;
576
- }
577
-
578
- /**
579
- * Gets the Loader instance.
580
- *
581
- * @return Twig_LoaderInterface A Twig_LoaderInterface instance
582
- */
583
- public function getLoader()
584
- {
585
- if (null === $this->loader) {
586
- throw new LogicException('You must set a loader first.');
587
- }
588
-
589
- return $this->loader;
590
- }
591
-
592
- /**
593
- * Sets the default template charset.
594
- *
595
- * @param string $charset The default charset
596
- */
597
- public function setCharset($charset)
598
- {
599
- $this->charset = strtoupper($charset);
600
- }
601
-
602
- /**
603
- * Gets the default template charset.
604
- *
605
- * @return string The default charset
606
- */
607
- public function getCharset()
608
- {
609
- return $this->charset;
610
- }
611
-
612
- /**
613
- * Initializes the runtime environment.
614
- */
615
- public function initRuntime()
616
- {
617
- $this->runtimeInitialized = true;
618
-
619
- foreach ($this->getExtensions() as $extension) {
620
- $extension->initRuntime($this);
621
- }
622
- }
623
-
624
- /**
625
- * Returns true if the given extension is registered.
626
- *
627
- * @param string $name The extension name
628
- *
629
- * @return bool Whether the extension is registered or not
630
- */
631
- public function hasExtension($name)
632
- {
633
- return isset($this->extensions[$name]);
634
- }
635
-
636
- /**
637
- * Gets an extension by name.
638
- *
639
- * @param string $name The extension name
640
- *
641
- * @return Twig_ExtensionInterface A Twig_ExtensionInterface instance
642
- */
643
- public function getExtension($name)
644
- {
645
- if (!isset($this->extensions[$name])) {
646
- throw new Twig_Error_Runtime(sprintf('The "%s" extension is not enabled.', $name));
647
- }
648
-
649
- return $this->extensions[$name];
650
- }
651
-
652
- /**
653
- * Registers an extension.
654
- *
655
- * @param Twig_ExtensionInterface $extension A Twig_ExtensionInterface instance
656
- */
657
- public function addExtension(Twig_ExtensionInterface $extension)
658
- {
659
- if ($this->extensionInitialized) {
660
- throw new LogicException(sprintf('Unable to register extension "%s" as extensions have already been initialized.', $extension->getName()));
661
- }
662
-
663
- $this->extensions[$extension->getName()] = $extension;
664
- }
665
-
666
- /**
667
- * Removes an extension by name.
668
- *
669
- * This method is deprecated and you should not use it.
670
- *
671
- * @param string $name The extension name
672
- *
673
- * @deprecated since 1.12 (to be removed in 2.0)
674
- */
675
- public function removeExtension($name)
676
- {
677
- if ($this->extensionInitialized) {
678
- throw new LogicException(sprintf('Unable to remove extension "%s" as extensions have already been initialized.', $name));
679
- }
680
-
681
- unset($this->extensions[$name]);
682
- }
683
-
684
- /**
685
- * Registers an array of extensions.
686
- *
687
- * @param array $extensions An array of extensions
688
- */
689
- public function setExtensions(array $extensions)
690
- {
691
- foreach ($extensions as $extension) {
692
- $this->addExtension($extension);
693
- }
694
- }
695
-
696
- /**
697
- * Returns all registered extensions.
698
- *
699
- * @return array An array of extensions
700
- */
701
- public function getExtensions()
702
- {
703
- return $this->extensions;
704
- }
705
-
706
- /**
707
- * Registers a Token Parser.
708
- *
709
- * @param Twig_TokenParserInterface $parser A Twig_TokenParserInterface instance
710
- */
711
- public function addTokenParser(Twig_TokenParserInterface $parser)
712
- {
713
- if ($this->extensionInitialized) {
714
- throw new LogicException('Unable to add a token parser as extensions have already been initialized.');
715
- }
716
-
717
- $this->staging->addTokenParser($parser);
718
- }
719
-
720
- /**
721
- * Gets the registered Token Parsers.
722
- *
723
- * @return Twig_TokenParserBrokerInterface A broker containing token parsers
724
- */
725
- public function getTokenParsers()
726
- {
727
- if (!$this->extensionInitialized) {
728
- $this->initExtensions();
729
- }
730
-
731
- return $this->parsers;
732
- }
733
-
734
- /**
735
- * Gets registered tags.
736
- *
737
- * Be warned that this method cannot return tags defined by Twig_TokenParserBrokerInterface classes.
738
- *
739
- * @return Twig_TokenParserInterface[] An array of Twig_TokenParserInterface instances
740
- */
741
- public function getTags()
742
- {
743
- $tags = array();
744
- foreach ($this->getTokenParsers()->getParsers() as $parser) {
745
- if ($parser instanceof Twig_TokenParserInterface) {
746
- $tags[$parser->getTag()] = $parser;
747
- }
748
- }
749
-
750
- return $tags;
751
- }
752
-
753
- /**
754
- * Registers a Node Visitor.
755
- *
756
- * @param Twig_NodeVisitorInterface $visitor A Twig_NodeVisitorInterface instance
757
- */
758
- public function addNodeVisitor(Twig_NodeVisitorInterface $visitor)
759
- {
760
- if ($this->extensionInitialized) {
761
- throw new LogicException('Unable to add a node visitor as extensions have already been initialized.');
762
- }
763
-
764
- $this->staging->addNodeVisitor($visitor);
765
- }
766
-
767
- /**
768
- * Gets the registered Node Visitors.
769
- *
770
- * @return Twig_NodeVisitorInterface[] An array of Twig_NodeVisitorInterface instances
771
- */
772
- public function getNodeVisitors()
773
- {
774
- if (!$this->extensionInitialized) {
775
- $this->initExtensions();
776
- }
777
-
778
- return $this->visitors;
779
- }
780
-
781
- /**
782
- * Registers a Filter.
783
- *
784
- * @param string|Twig_SimpleFilter $name The filter name or a Twig_SimpleFilter instance
785
- * @param Twig_FilterInterface|Twig_SimpleFilter $filter A Twig_FilterInterface instance or a Twig_SimpleFilter instance
786
- */
787
- public function addFilter($name, $filter = null)
788
- {
789
- if (!$name instanceof Twig_SimpleFilter && !($filter instanceof Twig_SimpleFilter || $filter instanceof Twig_FilterInterface)) {
790
- throw new LogicException('A filter must be an instance of Twig_FilterInterface or Twig_SimpleFilter');
791
- }
792
-
793
- if ($name instanceof Twig_SimpleFilter) {
794
- $filter = $name;
795
- $name = $filter->getName();
796
- }
797
-
798
- if ($this->extensionInitialized) {
799
- throw new LogicException(sprintf('Unable to add filter "%s" as extensions have already been initialized.', $name));
800
- }
801
-
802
- $this->staging->addFilter($name, $filter);
803
- }
804
-
805
- /**
806
- * Get a filter by name.
807
- *
808
- * Subclasses may override this method and load filters differently;
809
- * so no list of filters is available.
810
- *
811
- * @param string $name The filter name
812
- *
813
- * @return Twig_Filter|false A Twig_Filter instance or false if the filter does not exist
814
- */
815
- public function getFilter($name)
816
- {
817
- if (!$this->extensionInitialized) {
818
- $this->initExtensions();
819
- }
820
-
821
- if (isset($this->filters[$name])) {
822
- return $this->filters[$name];
823
- }
824
-
825
- foreach ($this->filters as $pattern => $filter) {
826
- $pattern = str_replace('\\*', '(.*?)', preg_quote($pattern, '#'), $count);
827
-
828
- if ($count) {
829
- if (preg_match('#^'.$pattern.'$#', $name, $matches)) {
830
- array_shift($matches);
831
- $filter->setArguments($matches);
832
-
833
- return $filter;
834
- }
835
- }
836
- }
837
-
838
- foreach ($this->filterCallbacks as $callback) {
839
- if (false !== $filter = call_user_func($callback, $name)) {
840
- return $filter;
841
- }
842
- }
843
-
844
- return false;
845
- }
846
-
847
- public function registerUndefinedFilterCallback($callable)
848
- {
849
- $this->filterCallbacks[] = $callable;
850
- }
851
-
852
- /**
853
- * Gets the registered Filters.
854
- *
855
- * Be warned that this method cannot return filters defined with registerUndefinedFunctionCallback.
856
- *
857
- * @return Twig_FilterInterface[] An array of Twig_FilterInterface instances
858
- *
859
- * @see registerUndefinedFilterCallback
860
- */
861
- public function getFilters()
862
- {
863
- if (!$this->extensionInitialized) {
864
- $this->initExtensions();
865
- }
866
-
867
- return $this->filters;
868
- }
869
-
870
- /**
871
- * Registers a Test.
872
- *
873
- * @param string|Twig_SimpleTest $name The test name or a Twig_SimpleTest instance
874
- * @param Twig_TestInterface|Twig_SimpleTest $test A Twig_TestInterface instance or a Twig_SimpleTest instance
875
- */
876
- public function addTest($name, $test = null)
877
- {
878
- if (!$name instanceof Twig_SimpleTest && !($test instanceof Twig_SimpleTest || $test instanceof Twig_TestInterface)) {
879
- throw new LogicException('A test must be an instance of Twig_TestInterface or Twig_SimpleTest');
880
- }
881
-
882
- if ($name instanceof Twig_SimpleTest) {
883
- $test = $name;
884
- $name = $test->getName();
885
- }
886
-
887
- if ($this->extensionInitialized) {
888
- throw new LogicException(sprintf('Unable to add test "%s" as extensions have already been initialized.', $name));
889
- }
890
-
891
- $this->staging->addTest($name, $test);
892
- }
893
-
894
- /**
895
- * Gets the registered Tests.
896
- *
897
- * @return Twig_TestInterface[] An array of Twig_TestInterface instances
898
- */
899
- public function getTests()
900
- {
901
- if (!$this->extensionInitialized) {
902
- $this->initExtensions();
903
- }
904
-
905
- return $this->tests;
906
- }
907
-
908
- /**
909
- * Gets a test by name.
910
- *
911
- * @param string $name The test name
912
- *
913
- * @return Twig_Test|false A Twig_Test instance or false if the test does not exist
914
- */
915
- public function getTest($name)
916
- {
917
- if (!$this->extensionInitialized) {
918
- $this->initExtensions();
919
- }
920
-
921
- if (isset($this->tests[$name])) {
922
- return $this->tests[$name];
923
- }
924
-
925
- return false;
926
- }
927
-
928
- /**
929
- * Registers a Function.
930
- *
931
- * @param string|Twig_SimpleFunction $name The function name or a Twig_SimpleFunction instance
932
- * @param Twig_FunctionInterface|Twig_SimpleFunction $function A Twig_FunctionInterface instance or a Twig_SimpleFunction instance
933
- */
934
- public function addFunction($name, $function = null)
935
- {
936
- if (!$name instanceof Twig_SimpleFunction && !($function instanceof Twig_SimpleFunction || $function instanceof Twig_FunctionInterface)) {
937
- throw new LogicException('A function must be an instance of Twig_FunctionInterface or Twig_SimpleFunction');
938
- }
939
-
940
- if ($name instanceof Twig_SimpleFunction) {
941
- $function = $name;
942
- $name = $function->getName();
943
- }
944
-
945
- if ($this->extensionInitialized) {
946
- throw new LogicException(sprintf('Unable to add function "%s" as extensions have already been initialized.', $name));
947
- }
948
-
949
- $this->staging->addFunction($name, $function);
950
- }
951
-
952
- /**
953
- * Get a function by name.
954
- *
955
- * Subclasses may override this method and load functions differently;
956
- * so no list of functions is available.
957
- *
958
- * @param string $name function name
959
- *
960
- * @return Twig_Function|false A Twig_Function instance or false if the function does not exist
961
- */
962
- public function getFunction($name)
963
- {
964
- if (!$this->extensionInitialized) {
965
- $this->initExtensions();
966
- }
967
-
968
- if (isset($this->functions[$name])) {
969
- return $this->functions[$name];
970
- }
971
-
972
- foreach ($this->functions as $pattern => $function) {
973
- $pattern = str_replace('\\*', '(.*?)', preg_quote($pattern, '#'), $count);
974
-
975
- if ($count) {
976
- if (preg_match('#^'.$pattern.'$#', $name, $matches)) {
977
- array_shift($matches);
978
- $function->setArguments($matches);
979
-
980
- return $function;
981
- }
982
- }
983
- }
984
-
985
- foreach ($this->functionCallbacks as $callback) {
986
- if (false !== $function = call_user_func($callback, $name)) {
987
- return $function;
988
- }
989
- }
990
-
991
- return false;
992
- }
993
-
994
- public function registerUndefinedFunctionCallback($callable)
995
- {
996
- $this->functionCallbacks[] = $callable;
997
- }
998
-
999
- /**
1000
- * Gets registered functions.
1001
- *
1002
- * Be warned that this method cannot return functions defined with registerUndefinedFunctionCallback.
1003
- *
1004
- * @return Twig_FunctionInterface[] An array of Twig_FunctionInterface instances
1005
- *
1006
- * @see registerUndefinedFunctionCallback
1007
- */
1008
- public function getFunctions()
1009
- {
1010
- if (!$this->extensionInitialized) {
1011
- $this->initExtensions();
1012
- }
1013
-
1014
- return $this->functions;
1015
- }
1016
-
1017
- /**
1018
- * Registers a Global.
1019
- *
1020
- * New globals can be added before compiling or rendering a template;
1021
- * but after, you can only update existing globals.
1022
- *
1023
- * @param string $name The global name
1024
- * @param mixed $value The global value
1025
- */
1026
- public function addGlobal($name, $value)
1027
- {
1028
- if ($this->extensionInitialized || $this->runtimeInitialized) {
1029
- if (null === $this->globals) {
1030
- $this->globals = $this->initGlobals();
1031
- }
1032
-
1033
- /* This condition must be uncommented in Twig 2.0
1034
- if (!array_key_exists($name, $this->globals)) {
1035
- throw new LogicException(sprintf('Unable to add global "%s" as the runtime or the extensions have already been initialized.', $name));
1036
- }
1037
- */
1038
- }
1039
-
1040
- if ($this->extensionInitialized || $this->runtimeInitialized) {
1041
- // update the value
1042
- $this->globals[$name] = $value;
1043
- } else {
1044
- $this->staging->addGlobal($name, $value);
1045
- }
1046
- }
1047
-
1048
- /**
1049
- * Gets the registered Globals.
1050
- *
1051
- * @return array An array of globals
1052
- */
1053
- public function getGlobals()
1054
- {
1055
- if (!$this->runtimeInitialized && !$this->extensionInitialized) {
1056
- return $this->initGlobals();
1057
- }
1058
-
1059
- if (null === $this->globals) {
1060
- $this->globals = $this->initGlobals();
1061
- }
1062
-
1063
- return $this->globals;
1064
- }
1065
-
1066
- /**
1067
- * Merges a context with the defined globals.
1068
- *
1069
- * @param array $context An array representing the context
1070
- *
1071
- * @return array The context merged with the globals
1072
- */
1073
- public function mergeGlobals(array $context)
1074
- {
1075
- // we don't use array_merge as the context being generally
1076
- // bigger than globals, this code is faster.
1077
- foreach ($this->getGlobals() as $key => $value) {
1078
- if (!array_key_exists($key, $context)) {
1079
- $context[$key] = $value;
1080
- }
1081
- }
1082
-
1083
- return $context;
1084
- }
1085
-
1086
- /**
1087
- * Gets the registered unary Operators.
1088
- *
1089
- * @return array An array of unary operators
1090
- */
1091
- public function getUnaryOperators()
1092
- {
1093
- if (!$this->extensionInitialized) {
1094
- $this->initExtensions();
1095
- }
1096
-
1097
- return $this->unaryOperators;
1098
- }
1099
-
1100
- /**
1101
- * Gets the registered binary Operators.
1102
- *
1103
- * @return array An array of binary operators
1104
- */
1105
- public function getBinaryOperators()
1106
- {
1107
- if (!$this->extensionInitialized) {
1108
- $this->initExtensions();
1109
- }
1110
-
1111
- return $this->binaryOperators;
1112
- }
1113
-
1114
- public function computeAlternatives($name, $items)
1115
- {
1116
- $alternatives = array();
1117
- foreach ($items as $item) {
1118
- $lev = levenshtein($name, $item);
1119
- if ($lev <= strlen($name) / 3 || false !== strpos($item, $name)) {
1120
- $alternatives[$item] = $lev;
1121
- }
1122
- }
1123
- asort($alternatives);
1124
-
1125
- return array_keys($alternatives);
1126
- }
1127
-
1128
- protected function initGlobals()
1129
- {
1130
- $globals = array();
1131
- foreach ($this->extensions as $extension) {
1132
- $extGlob = $extension->getGlobals();
1133
- if (!is_array($extGlob)) {
1134
- throw new UnexpectedValueException(sprintf('"%s::getGlobals()" must return an array of globals.', get_class($extension)));
1135
- }
1136
-
1137
- $globals[] = $extGlob;
1138
- }
1139
-
1140
- $globals[] = $this->staging->getGlobals();
1141
-
1142
- return call_user_func_array('array_merge', $globals);
1143
- }
1144
-
1145
- protected function initExtensions()
1146
- {
1147
- if ($this->extensionInitialized) {
1148
- return;
1149
- }
1150
-
1151
- $this->extensionInitialized = true;
1152
- $this->parsers = new Twig_TokenParserBroker();
1153
- $this->filters = array();
1154
- $this->functions = array();
1155
- $this->tests = array();
1156
- $this->visitors = array();
1157
- $this->unaryOperators = array();
1158
- $this->binaryOperators = array();
1159
-
1160
- foreach ($this->extensions as $extension) {
1161
- $this->initExtension($extension);
1162
- }
1163
- $this->initExtension($this->staging);
1164
- }
1165
-
1166
- protected function initExtension(Twig_ExtensionInterface $extension)
1167
- {
1168
- // filters
1169
- foreach ($extension->getFilters() as $name => $filter) {
1170
- if ($name instanceof Twig_SimpleFilter) {
1171
- $filter = $name;
1172
- $name = $filter->getName();
1173
- } elseif ($filter instanceof Twig_SimpleFilter) {
1174
- $name = $filter->getName();
1175
- }
1176
-
1177
- $this->filters[$name] = $filter;
1178
- }
1179
-
1180
- // functions
1181
- foreach ($extension->getFunctions() as $name => $function) {
1182
- if ($name instanceof Twig_SimpleFunction) {
1183
- $function = $name;
1184
- $name = $function->getName();
1185
- } elseif ($function instanceof Twig_SimpleFunction) {
1186
- $name = $function->getName();
1187
- }
1188
-
1189
- $this->functions[$name] = $function;
1190
- }
1191
-
1192
- // tests
1193
- foreach ($extension->getTests() as $name => $test) {
1194
- if ($name instanceof Twig_SimpleTest) {
1195
- $test = $name;
1196
- $name = $test->getName();
1197
- } elseif ($test instanceof Twig_SimpleTest) {
1198
- $name = $test->getName();
1199
- }
1200
-
1201
- $this->tests[$name] = $test;
1202
- }
1203
-
1204
- // token parsers
1205
- foreach ($extension->getTokenParsers() as $parser) {
1206
- if ($parser instanceof Twig_TokenParserInterface) {
1207
- $this->parsers->addTokenParser($parser);
1208
- } elseif ($parser instanceof Twig_TokenParserBrokerInterface) {
1209
- $this->parsers->addTokenParserBroker($parser);
1210
- } else {
1211
- throw new LogicException('getTokenParsers() must return an array of Twig_TokenParserInterface or Twig_TokenParserBrokerInterface instances');
1212
- }
1213
- }
1214
-
1215
- // node visitors
1216
- foreach ($extension->getNodeVisitors() as $visitor) {
1217
- $this->visitors[] = $visitor;
1218
- }
1219
-
1220
- // operators
1221
- if ($operators = $extension->getOperators()) {
1222
- if (2 !== count($operators)) {
1223
- throw new InvalidArgumentException(sprintf('"%s::getOperators()" does not return a valid operators array.', get_class($extension)));
1224
- }
1225
-
1226
- $this->unaryOperators = array_merge($this->unaryOperators, $operators[0]);
1227
- $this->binaryOperators = array_merge($this->binaryOperators, $operators[1]);
1228
- }
1229
- }
1230
-
1231
- protected function writeCacheFile($file, $content)
1232
- {
1233
- $dir = dirname($file);
1234
- if (!is_dir($dir)) {
1235
- if (false === @mkdir($dir, 0777, true) && !is_dir($dir)) {
1236
- throw new RuntimeException(sprintf("Unable to create the cache directory (%s).", $dir));
1237
- }
1238
- } elseif (!is_writable($dir)) {
1239
- throw new RuntimeException(sprintf("Unable to write in the cache directory (%s).", $dir));
1240
- }
1241
-
1242
- $tmpFile = tempnam($dir, basename($file));
1243
- if (false !== @file_put_contents($tmpFile, $content)) {
1244
- // rename does not work on Win32 before 5.2.6
1245
- if (@rename($tmpFile, $file) || (@copy($tmpFile, $file) && unlink($tmpFile))) {
1246
- @chmod($file, 0666 & ~umask());
1247
-
1248
- return;
1249
- }
1250
- }
1251
-
1252
- throw new RuntimeException(sprintf('Failed to write cache file "%s".', $file));
1253
- }
1254
- }
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2009 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ /**
13
+ * Stores the Twig configuration.
14
+ *
15
+ * @author Fabien Potencier <fabien@symfony.com>
16
+ */
17
+ class Twig_Environment
18
+ {
19
+ const VERSION = '1.16.0';
20
+
21
+ protected $charset;
22
+ protected $loader;
23
+ protected $debug;
24
+ protected $autoReload;
25
+ protected $cache;
26
+ protected $lexer;
27
+ protected $parser;
28
+ protected $compiler;
29
+ protected $baseTemplateClass;
30
+ protected $extensions;
31
+ protected $parsers;
32
+ protected $visitors;
33
+ protected $filters;
34
+ protected $tests;
35
+ protected $functions;
36
+ protected $globals;
37
+ protected $runtimeInitialized;
38
+ protected $extensionInitialized;
39
+ protected $loadedTemplates;
40
+ protected $strictVariables;
41
+ protected $unaryOperators;
42
+ protected $binaryOperators;
43
+ protected $templateClassPrefix = '__TwigTemplate_';
44
+ protected $functionCallbacks;
45
+ protected $filterCallbacks;
46
+ protected $staging;
47
+
48
+ /**
49
+ * Constructor.
50
+ *
51
+ * Available options:
52
+ *
53
+ * * debug: When set to true, it automatically set "auto_reload" to true as
54
+ * well (default to false).
55
+ *
56
+ * * charset: The charset used by the templates (default to UTF-8).
57
+ *
58
+ * * base_template_class: The base template class to use for generated
59
+ * templates (default to Twig_Template).
60
+ *
61
+ * * cache: An absolute path where to store the compiled templates, or
62
+ * false to disable compilation cache (default).
63
+ *
64
+ * * auto_reload: Whether to reload the template if the original source changed.
65
+ * If you don't provide the auto_reload option, it will be
66
+ * determined automatically based on the debug value.
67
+ *
68
+ * * strict_variables: Whether to ignore invalid variables in templates
69
+ * (default to false).
70
+ *
71
+ * * autoescape: Whether to enable auto-escaping (default to html):
72
+ * * false: disable auto-escaping
73
+ * * true: equivalent to html
74
+ * * html, js: set the autoescaping to one of the supported strategies
75
+ * * PHP callback: a PHP callback that returns an escaping strategy based on the template "filename"
76
+ *
77
+ * * optimizations: A flag that indicates which optimizations to apply
78
+ * (default to -1 which means that all optimizations are enabled;
79
+ * set it to 0 to disable).
80
+ *
81
+ * @param Twig_LoaderInterface $loader A Twig_LoaderInterface instance
82
+ * @param array $options An array of options
83
+ */
84
+ public function __construct(Twig_LoaderInterface $loader = null, $options = array())
85
+ {
86
+ if (null !== $loader) {
87
+ $this->setLoader($loader);
88
+ }
89
+
90
+ $options = array_merge(array(
91
+ 'debug' => false,
92
+ 'charset' => 'UTF-8',
93
+ 'base_template_class' => 'Twig_Template',
94
+ 'strict_variables' => false,
95
+ 'autoescape' => 'html',
96
+ 'cache' => false,
97
+ 'auto_reload' => null,
98
+ 'optimizations' => -1,
99
+ ), $options);
100
+
101
+ $this->debug = (bool) $options['debug'];
102
+ $this->charset = strtoupper($options['charset']);
103
+ $this->baseTemplateClass = $options['base_template_class'];
104
+ $this->autoReload = null === $options['auto_reload'] ? $this->debug : (bool) $options['auto_reload'];
105
+ $this->strictVariables = (bool) $options['strict_variables'];
106
+ $this->runtimeInitialized = false;
107
+ $this->setCache($options['cache']);
108
+ $this->functionCallbacks = array();
109
+ $this->filterCallbacks = array();
110
+
111
+ $this->addExtension(new Twig_Extension_Core());
112
+ $this->addExtension(new Twig_Extension_Escaper($options['autoescape']));
113
+ $this->addExtension(new Twig_Extension_Optimizer($options['optimizations']));
114
+ $this->extensionInitialized = false;
115
+ $this->staging = new Twig_Extension_Staging();
116
+ }
117
+
118
+ /**
119
+ * Gets the base template class for compiled templates.
120
+ *
121
+ * @return string The base template class name
122
+ */
123
+ public function getBaseTemplateClass()
124
+ {
125
+ return $this->baseTemplateClass;
126
+ }
127
+
128
+ /**
129
+ * Sets the base template class for compiled templates.
130
+ *
131
+ * @param string $class The base template class name
132
+ */
133
+ public function setBaseTemplateClass($class)
134
+ {
135
+ $this->baseTemplateClass = $class;
136
+ }
137
+
138
+ /**
139
+ * Enables debugging mode.
140
+ */
141
+ public function enableDebug()
142
+ {
143
+ $this->debug = true;
144
+ }
145
+
146
+ /**
147
+ * Disables debugging mode.
148
+ */
149
+ public function disableDebug()
150
+ {
151
+ $this->debug = false;
152
+ }
153
+
154
+ /**
155
+ * Checks if debug mode is enabled.
156
+ *
157
+ * @return bool true if debug mode is enabled, false otherwise
158
+ */
159
+ public function isDebug()
160
+ {
161
+ return $this->debug;
162
+ }
163
+
164
+ /**
165
+ * Enables the auto_reload option.
166
+ */
167
+ public function enableAutoReload()
168
+ {
169
+ $this->autoReload = true;
170
+ }
171
+
172
+ /**
173
+ * Disables the auto_reload option.
174
+ */
175
+ public function disableAutoReload()
176
+ {
177
+ $this->autoReload = false;
178
+ }
179
+
180
+ /**
181
+ * Checks if the auto_reload option is enabled.
182
+ *
183
+ * @return bool true if auto_reload is enabled, false otherwise
184
+ */
185
+ public function isAutoReload()
186
+ {
187
+ return $this->autoReload;
188
+ }
189
+
190
+ /**
191
+ * Enables the strict_variables option.
192
+ */
193
+ public function enableStrictVariables()
194
+ {
195
+ $this->strictVariables = true;
196
+ }
197
+
198
+ /**
199
+ * Disables the strict_variables option.
200
+ */
201
+ public function disableStrictVariables()
202
+ {
203
+ $this->strictVariables = false;
204
+ }
205
+
206
+ /**
207
+ * Checks if the strict_variables option is enabled.
208
+ *
209
+ * @return bool true if strict_variables is enabled, false otherwise
210
+ */
211
+ public function isStrictVariables()
212
+ {
213
+ return $this->strictVariables;
214
+ }
215
+
216
+ /**
217
+ * Gets the cache directory or false if cache is disabled.
218
+ *
219
+ * @return string|false
220
+ */
221
+ public function getCache()
222
+ {
223
+ return $this->cache;
224
+ }
225
+
226
+ /**
227
+ * Sets the cache directory or false if cache is disabled.
228
+ *
229
+ * @param string|false $cache The absolute path to the compiled templates,
230
+ * or false to disable cache
231
+ */
232
+ public function setCache($cache)
233
+ {
234
+ $this->cache = $cache ? $cache : false;
235
+ }
236
+
237
+ /**
238
+ * Gets the cache filename for a given template.
239
+ *
240
+ * @param string $name The template name
241
+ *
242
+ * @return string|false The cache file name or false when caching is disabled
243
+ */
244
+ public function getCacheFilename($name)
245
+ {
246
+ if (false === $this->cache) {
247
+ return false;
248
+ }
249
+
250
+ $class = substr($this->getTemplateClass($name), strlen($this->templateClassPrefix));
251
+
252
+ return $this->getCache().'/'.substr($class, 0, 2).'/'.substr($class, 2, 2).'/'.substr($class, 4).'.php';
253
+ }
254
+
255
+ /**
256
+ * Gets the template class associated with the given string.
257
+ *
258
+ * @param string $name The name for which to calculate the template class name
259
+ * @param int $index The index if it is an embedded template
260
+ *
261
+ * @return string The template class name
262
+ */
263
+ public function getTemplateClass($name, $index = null)
264
+ {
265
+ return $this->templateClassPrefix.hash('sha256', $this->getLoader()->getCacheKey($name)).(null === $index ? '' : '_'.$index);
266
+ }
267
+
268
+ /**
269
+ * Gets the template class prefix.
270
+ *
271
+ * @return string The template class prefix
272
+ */
273
+ public function getTemplateClassPrefix()
274
+ {
275
+ return $this->templateClassPrefix;
276
+ }
277
+
278
+ /**
279
+ * Renders a template.
280
+ *
281
+ * @param string $name The template name
282
+ * @param array $context An array of parameters to pass to the template
283
+ *
284
+ * @return string The rendered template
285
+ *
286
+ * @throws Twig_Error_Loader When the template cannot be found
287
+ * @throws Twig_Error_Syntax When an error occurred during compilation
288
+ * @throws Twig_Error_Runtime When an error occurred during rendering
289
+ */
290
+ public function render($name, array $context = array())
291
+ {
292
+ return $this->loadTemplate($name)->render($context);
293
+ }
294
+
295
+ /**
296
+ * Displays a template.
297
+ *
298
+ * @param string $name The template name
299
+ * @param array $context An array of parameters to pass to the template
300
+ *
301
+ * @throws Twig_Error_Loader When the template cannot be found
302
+ * @throws Twig_Error_Syntax When an error occurred during compilation
303
+ * @throws Twig_Error_Runtime When an error occurred during rendering
304
+ */
305
+ public function display($name, array $context = array())
306
+ {
307
+ $this->loadTemplate($name)->display($context);
308
+ }
309
+
310
+ /**
311
+ * Loads a template by name.
312
+ *
313
+ * @param string $name The template name
314
+ * @param int $index The index if it is an embedded template
315
+ *
316
+ * @return Twig_TemplateInterface A template instance representing the given template name
317
+ *
318
+ * @throws Twig_Error_Loader When the template cannot be found
319
+ * @throws Twig_Error_Syntax When an error occurred during compilation
320
+ */
321
+ public function loadTemplate($name, $index = null)
322
+ {
323
+ $cls = $this->getTemplateClass($name, $index);
324
+
325
+ if (isset($this->loadedTemplates[$cls])) {
326
+ return $this->loadedTemplates[$cls];
327
+ }
328
+
329
+ if (!class_exists($cls, false)) {
330
+ if (false === $cache = $this->getCacheFilename($name)) {
331
+ eval('?>'.$this->compileSource($this->getLoader()->getSource($name), $name));
332
+ } else {
333
+ if (!is_file($cache) || ($this->isAutoReload() && !$this->isTemplateFresh($name, filemtime($cache)))) {
334
+ $this->writeCacheFile($cache, $this->compileSource($this->getLoader()->getSource($name), $name));
335
+ }
336
+
337
+ require_once $cache;
338
+ }
339
+ }
340
+
341
+ if (!$this->runtimeInitialized) {
342
+ $this->initRuntime();
343
+ }
344
+
345
+ return $this->loadedTemplates[$cls] = new $cls($this);
346
+ }
347
+
348
+ /**
349
+ * Returns true if the template is still fresh.
350
+ *
351
+ * Besides checking the loader for freshness information,
352
+ * this method also checks if the enabled extensions have
353
+ * not changed.
354
+ *
355
+ * @param string $name The template name
356
+ * @param timestamp $time The last modification time of the cached template
357
+ *
358
+ * @return bool true if the template is fresh, false otherwise
359
+ */
360
+ public function isTemplateFresh($name, $time)
361
+ {
362
+ foreach ($this->extensions as $extension) {
363
+ $r = new ReflectionObject($extension);
364
+ if (filemtime($r->getFileName()) > $time) {
365
+ return false;
366
+ }
367
+ }
368
+
369
+ return $this->getLoader()->isFresh($name, $time);
370
+ }
371
+
372
+ /**
373
+ * Tries to load a template consecutively from an array.
374
+ *
375
+ * Similar to loadTemplate() but it also accepts Twig_TemplateInterface instances and an array
376
+ * of templates where each is tried to be loaded.
377
+ *
378
+ * @param string|Twig_Template|array $names A template or an array of templates to try consecutively
379
+ *
380
+ * @return Twig_Template
381
+ *
382
+ * @throws Twig_Error_Loader When none of the templates can be found
383
+ * @throws Twig_Error_Syntax When an error occurred during compilation
384
+ */
385
+ public function resolveTemplate($names)
386
+ {
387
+ if (!is_array($names)) {
388
+ $names = array($names);
389
+ }
390
+
391
+ foreach ($names as $name) {
392
+ if ($name instanceof Twig_Template) {
393
+ return $name;
394
+ }
395
+
396
+ try {
397
+ return $this->loadTemplate($name);
398
+ } catch (Twig_Error_Loader $e) {
399
+ }
400
+ }
401
+
402
+ if (1 === count($names)) {
403
+ throw $e;
404
+ }
405
+
406
+ throw new Twig_Error_Loader(sprintf('Unable to find one of the following templates: "%s".', implode('", "', $names)));
407
+ }
408
+
409
+ /**
410
+ * Clears the internal template cache.
411
+ */
412
+ public function clearTemplateCache()
413
+ {
414
+ $this->loadedTemplates = array();
415
+ }
416
+
417
+ /**
418
+ * Clears the template cache files on the filesystem.
419
+ */
420
+ public function clearCacheFiles()
421
+ {
422
+ if (false === $this->cache) {
423
+ return;
424
+ }
425
+
426
+ foreach (new RecursiveIteratorIterator(new RecursiveDirectoryIterator($this->cache), RecursiveIteratorIterator::LEAVES_ONLY) as $file) {
427
+ if ($file->isFile()) {
428
+ @unlink($file->getPathname());
429
+ }
430
+ }
431
+ }
432
+
433
+ /**
434
+ * Gets the Lexer instance.
435
+ *
436
+ * @return Twig_LexerInterface A Twig_LexerInterface instance
437
+ */
438
+ public function getLexer()
439
+ {
440
+ if (null === $this->lexer) {
441
+ $this->lexer = new Twig_Lexer($this);
442
+ }
443
+
444
+ return $this->lexer;
445
+ }
446
+
447
+ /**
448
+ * Sets the Lexer instance.
449
+ *
450
+ * @param Twig_LexerInterface A Twig_LexerInterface instance
451
+ */
452
+ public function setLexer(Twig_LexerInterface $lexer)
453
+ {
454
+ $this->lexer = $lexer;
455
+ }
456
+
457
+ /**
458
+ * Tokenizes a source code.
459
+ *
460
+ * @param string $source The template source code
461
+ * @param string $name The template name
462
+ *
463
+ * @return Twig_TokenStream A Twig_TokenStream instance
464
+ *
465
+ * @throws Twig_Error_Syntax When the code is syntactically wrong
466
+ */
467
+ public function tokenize($source, $name = null)
468
+ {
469
+ return $this->getLexer()->tokenize($source, $name);
470
+ }
471
+
472
+ /**
473
+ * Gets the Parser instance.
474
+ *
475
+ * @return Twig_ParserInterface A Twig_ParserInterface instance
476
+ */
477
+ public function getParser()
478
+ {
479
+ if (null === $this->parser) {
480
+ $this->parser = new Twig_Parser($this);
481
+ }
482
+
483
+ return $this->parser;
484
+ }
485
+
486
+ /**
487
+ * Sets the Parser instance.
488
+ *
489
+ * @param Twig_ParserInterface A Twig_ParserInterface instance
490
+ */
491
+ public function setParser(Twig_ParserInterface $parser)
492
+ {
493
+ $this->parser = $parser;
494
+ }
495
+
496
+ /**
497
+ * Converts a token stream to a node tree.
498
+ *
499
+ * @param Twig_TokenStream $stream A token stream instance
500
+ *
501
+ * @return Twig_Node_Module A node tree
502
+ *
503
+ * @throws Twig_Error_Syntax When the token stream is syntactically or semantically wrong
504
+ */
505
+ public function parse(Twig_TokenStream $stream)
506
+ {
507
+ return $this->getParser()->parse($stream);
508
+ }
509
+
510
+ /**
511
+ * Gets the Compiler instance.
512
+ *
513
+ * @return Twig_CompilerInterface A Twig_CompilerInterface instance
514
+ */
515
+ public function getCompiler()
516
+ {
517
+ if (null === $this->compiler) {
518
+ $this->compiler = new Twig_Compiler($this);
519
+ }
520
+
521
+ return $this->compiler;
522
+ }
523
+
524
+ /**
525
+ * Sets the Compiler instance.
526
+ *
527
+ * @param Twig_CompilerInterface $compiler A Twig_CompilerInterface instance
528
+ */
529
+ public function setCompiler(Twig_CompilerInterface $compiler)
530
+ {
531
+ $this->compiler = $compiler;
532
+ }
533
+
534
+ /**
535
+ * Compiles a node and returns the PHP code.
536
+ *
537
+ * @param Twig_NodeInterface $node A Twig_NodeInterface instance
538
+ *
539
+ * @return string The compiled PHP source code
540
+ */
541
+ public function compile(Twig_NodeInterface $node)
542
+ {
543
+ return $this->getCompiler()->compile($node)->getSource();
544
+ }
545
+
546
+ /**
547
+ * Compiles a template source code.
548
+ *
549
+ * @param string $source The template source code
550
+ * @param string $name The template name
551
+ *
552
+ * @return string The compiled PHP source code
553
+ *
554
+ * @throws Twig_Error_Syntax When there was an error during tokenizing, parsing or compiling
555
+ */
556
+ public function compileSource($source, $name = null)
557
+ {
558
+ try {
559
+ return $this->compile($this->parse($this->tokenize($source, $name)));
560
+ } catch (Twig_Error $e) {
561
+ $e->setTemplateFile($name);
562
+ throw $e;
563
+ } catch (Exception $e) {
564
+ throw new Twig_Error_Syntax(sprintf('An exception has been thrown during the compilation of a template ("%s").', $e->getMessage()), -1, $name, $e);
565
+ }
566
+ }
567
+
568
+ /**
569
+ * Sets the Loader instance.
570
+ *
571
+ * @param Twig_LoaderInterface $loader A Twig_LoaderInterface instance
572
+ */
573
+ public function setLoader(Twig_LoaderInterface $loader)
574
+ {
575
+ $this->loader = $loader;
576
+ }
577
+
578
+ /**
579
+ * Gets the Loader instance.
580
+ *
581
+ * @return Twig_LoaderInterface A Twig_LoaderInterface instance
582
+ */
583
+ public function getLoader()
584
+ {
585
+ if (null === $this->loader) {
586
+ throw new LogicException('You must set a loader first.');
587
+ }
588
+
589
+ return $this->loader;
590
+ }
591
+
592
+ /**
593
+ * Sets the default template charset.
594
+ *
595
+ * @param string $charset The default charset
596
+ */
597
+ public function setCharset($charset)
598
+ {
599
+ $this->charset = strtoupper($charset);
600
+ }
601
+
602
+ /**
603
+ * Gets the default template charset.
604
+ *
605
+ * @return string The default charset
606
+ */
607
+ public function getCharset()
608
+ {
609
+ return $this->charset;
610
+ }
611
+
612
+ /**
613
+ * Initializes the runtime environment.
614
+ */
615
+ public function initRuntime()
616
+ {
617
+ $this->runtimeInitialized = true;
618
+
619
+ foreach ($this->getExtensions() as $extension) {
620
+ $extension->initRuntime($this);
621
+ }
622
+ }
623
+
624
+ /**
625
+ * Returns true if the given extension is registered.
626
+ *
627
+ * @param string $name The extension name
628
+ *
629
+ * @return bool Whether the extension is registered or not
630
+ */
631
+ public function hasExtension($name)
632
+ {
633
+ return isset($this->extensions[$name]);
634
+ }
635
+
636
+ /**
637
+ * Gets an extension by name.
638
+ *
639
+ * @param string $name The extension name
640
+ *
641
+ * @return Twig_ExtensionInterface A Twig_ExtensionInterface instance
642
+ */
643
+ public function getExtension($name)
644
+ {
645
+ if (!isset($this->extensions[$name])) {
646
+ throw new Twig_Error_Runtime(sprintf('The "%s" extension is not enabled.', $name));
647
+ }
648
+
649
+ return $this->extensions[$name];
650
+ }
651
+
652
+ /**
653
+ * Registers an extension.
654
+ *
655
+ * @param Twig_ExtensionInterface $extension A Twig_ExtensionInterface instance
656
+ */
657
+ public function addExtension(Twig_ExtensionInterface $extension)
658
+ {
659
+ if ($this->extensionInitialized) {
660
+ throw new LogicException(sprintf('Unable to register extension "%s" as extensions have already been initialized.', $extension->getName()));
661
+ }
662
+
663
+ $this->extensions[$extension->getName()] = $extension;
664
+ }
665
+
666
+ /**
667
+ * Removes an extension by name.
668
+ *
669
+ * This method is deprecated and you should not use it.
670
+ *
671
+ * @param string $name The extension name
672
+ *
673
+ * @deprecated since 1.12 (to be removed in 2.0)
674
+ */
675
+ public function removeExtension($name)
676
+ {
677
+ if ($this->extensionInitialized) {
678
+ throw new LogicException(sprintf('Unable to remove extension "%s" as extensions have already been initialized.', $name));
679
+ }
680
+
681
+ unset($this->extensions[$name]);
682
+ }
683
+
684
+ /**
685
+ * Registers an array of extensions.
686
+ *
687
+ * @param array $extensions An array of extensions
688
+ */
689
+ public function setExtensions(array $extensions)
690
+ {
691
+ foreach ($extensions as $extension) {
692
+ $this->addExtension($extension);
693
+ }
694
+ }
695
+
696
+ /**
697
+ * Returns all registered extensions.
698
+ *
699
+ * @return array An array of extensions
700
+ */
701
+ public function getExtensions()
702
+ {
703
+ return $this->extensions;
704
+ }
705
+
706
+ /**
707
+ * Registers a Token Parser.
708
+ *
709
+ * @param Twig_TokenParserInterface $parser A Twig_TokenParserInterface instance
710
+ */
711
+ public function addTokenParser(Twig_TokenParserInterface $parser)
712
+ {
713
+ if ($this->extensionInitialized) {
714
+ throw new LogicException('Unable to add a token parser as extensions have already been initialized.');
715
+ }
716
+
717
+ $this->staging->addTokenParser($parser);
718
+ }
719
+
720
+ /**
721
+ * Gets the registered Token Parsers.
722
+ *
723
+ * @return Twig_TokenParserBrokerInterface A broker containing token parsers
724
+ */
725
+ public function getTokenParsers()
726
+ {
727
+ if (!$this->extensionInitialized) {
728
+ $this->initExtensions();
729
+ }
730
+
731
+ return $this->parsers;
732
+ }
733
+
734
+ /**
735
+ * Gets registered tags.
736
+ *
737
+ * Be warned that this method cannot return tags defined by Twig_TokenParserBrokerInterface classes.
738
+ *
739
+ * @return Twig_TokenParserInterface[] An array of Twig_TokenParserInterface instances
740
+ */
741
+ public function getTags()
742
+ {
743
+ $tags = array();
744
+ foreach ($this->getTokenParsers()->getParsers() as $parser) {
745
+ if ($parser instanceof Twig_TokenParserInterface) {
746
+ $tags[$parser->getTag()] = $parser;
747
+ }
748
+ }
749
+
750
+ return $tags;
751
+ }
752
+
753
+ /**
754
+ * Registers a Node Visitor.
755
+ *
756
+ * @param Twig_NodeVisitorInterface $visitor A Twig_NodeVisitorInterface instance
757
+ */
758
+ public function addNodeVisitor(Twig_NodeVisitorInterface $visitor)
759
+ {
760
+ if ($this->extensionInitialized) {
761
+ throw new LogicException('Unable to add a node visitor as extensions have already been initialized.');
762
+ }
763
+
764
+ $this->staging->addNodeVisitor($visitor);
765
+ }
766
+
767
+ /**
768
+ * Gets the registered Node Visitors.
769
+ *
770
+ * @return Twig_NodeVisitorInterface[] An array of Twig_NodeVisitorInterface instances
771
+ */
772
+ public function getNodeVisitors()
773
+ {
774
+ if (!$this->extensionInitialized) {
775
+ $this->initExtensions();
776
+ }
777
+
778
+ return $this->visitors;
779
+ }
780
+
781
+ /**
782
+ * Registers a Filter.
783
+ *
784
+ * @param string|Twig_SimpleFilter $name The filter name or a Twig_SimpleFilter instance
785
+ * @param Twig_FilterInterface|Twig_SimpleFilter $filter A Twig_FilterInterface instance or a Twig_SimpleFilter instance
786
+ */
787
+ public function addFilter($name, $filter = null)
788
+ {
789
+ if (!$name instanceof Twig_SimpleFilter && !($filter instanceof Twig_SimpleFilter || $filter instanceof Twig_FilterInterface)) {
790
+ throw new LogicException('A filter must be an instance of Twig_FilterInterface or Twig_SimpleFilter');
791
+ }
792
+
793
+ if ($name instanceof Twig_SimpleFilter) {
794
+ $filter = $name;
795
+ $name = $filter->getName();
796
+ }
797
+
798
+ if ($this->extensionInitialized) {
799
+ throw new LogicException(sprintf('Unable to add filter "%s" as extensions have already been initialized.', $name));
800
+ }
801
+
802
+ $this->staging->addFilter($name, $filter);
803
+ }
804
+
805
+ /**
806
+ * Get a filter by name.
807
+ *
808
+ * Subclasses may override this method and load filters differently;
809
+ * so no list of filters is available.
810
+ *
811
+ * @param string $name The filter name
812
+ *
813
+ * @return Twig_Filter|false A Twig_Filter instance or false if the filter does not exist
814
+ */
815
+ public function getFilter($name)
816
+ {
817
+ if (!$this->extensionInitialized) {
818
+ $this->initExtensions();
819
+ }
820
+
821
+ if (isset($this->filters[$name])) {
822
+ return $this->filters[$name];
823
+ }
824
+
825
+ foreach ($this->filters as $pattern => $filter) {
826
+ $pattern = str_replace('\\*', '(.*?)', preg_quote($pattern, '#'), $count);
827
+
828
+ if ($count) {
829
+ if (preg_match('#^'.$pattern.'$#', $name, $matches)) {
830
+ array_shift($matches);
831
+ $filter->setArguments($matches);
832
+
833
+ return $filter;
834
+ }
835
+ }
836
+ }
837
+
838
+ foreach ($this->filterCallbacks as $callback) {
839
+ if (false !== $filter = call_user_func($callback, $name)) {
840
+ return $filter;
841
+ }
842
+ }
843
+
844
+ return false;
845
+ }
846
+
847
+ public function registerUndefinedFilterCallback($callable)
848
+ {
849
+ $this->filterCallbacks[] = $callable;
850
+ }
851
+
852
+ /**
853
+ * Gets the registered Filters.
854
+ *
855
+ * Be warned that this method cannot return filters defined with registerUndefinedFunctionCallback.
856
+ *
857
+ * @return Twig_FilterInterface[] An array of Twig_FilterInterface instances
858
+ *
859
+ * @see registerUndefinedFilterCallback
860
+ */
861
+ public function getFilters()
862
+ {
863
+ if (!$this->extensionInitialized) {
864
+ $this->initExtensions();
865
+ }
866
+
867
+ return $this->filters;
868
+ }
869
+
870
+ /**
871
+ * Registers a Test.
872
+ *
873
+ * @param string|Twig_SimpleTest $name The test name or a Twig_SimpleTest instance
874
+ * @param Twig_TestInterface|Twig_SimpleTest $test A Twig_TestInterface instance or a Twig_SimpleTest instance
875
+ */
876
+ public function addTest($name, $test = null)
877
+ {
878
+ if (!$name instanceof Twig_SimpleTest && !($test instanceof Twig_SimpleTest || $test instanceof Twig_TestInterface)) {
879
+ throw new LogicException('A test must be an instance of Twig_TestInterface or Twig_SimpleTest');
880
+ }
881
+
882
+ if ($name instanceof Twig_SimpleTest) {
883
+ $test = $name;
884
+ $name = $test->getName();
885
+ }
886
+
887
+ if ($this->extensionInitialized) {
888
+ throw new LogicException(sprintf('Unable to add test "%s" as extensions have already been initialized.', $name));
889
+ }
890
+
891
+ $this->staging->addTest($name, $test);
892
+ }
893
+
894
+ /**
895
+ * Gets the registered Tests.
896
+ *
897
+ * @return Twig_TestInterface[] An array of Twig_TestInterface instances
898
+ */
899
+ public function getTests()
900
+ {
901
+ if (!$this->extensionInitialized) {
902
+ $this->initExtensions();
903
+ }
904
+
905
+ return $this->tests;
906
+ }
907
+
908
+ /**
909
+ * Gets a test by name.
910
+ *
911
+ * @param string $name The test name
912
+ *
913
+ * @return Twig_Test|false A Twig_Test instance or false if the test does not exist
914
+ */
915
+ public function getTest($name)
916
+ {
917
+ if (!$this->extensionInitialized) {
918
+ $this->initExtensions();
919
+ }
920
+
921
+ if (isset($this->tests[$name])) {
922
+ return $this->tests[$name];
923
+ }
924
+
925
+ return false;
926
+ }
927
+
928
+ /**
929
+ * Registers a Function.
930
+ *
931
+ * @param string|Twig_SimpleFunction $name The function name or a Twig_SimpleFunction instance
932
+ * @param Twig_FunctionInterface|Twig_SimpleFunction $function A Twig_FunctionInterface instance or a Twig_SimpleFunction instance
933
+ */
934
+ public function addFunction($name, $function = null)
935
+ {
936
+ if (!$name instanceof Twig_SimpleFunction && !($function instanceof Twig_SimpleFunction || $function instanceof Twig_FunctionInterface)) {
937
+ throw new LogicException('A function must be an instance of Twig_FunctionInterface or Twig_SimpleFunction');
938
+ }
939
+
940
+ if ($name instanceof Twig_SimpleFunction) {
941
+ $function = $name;
942
+ $name = $function->getName();
943
+ }
944
+
945
+ if ($this->extensionInitialized) {
946
+ throw new LogicException(sprintf('Unable to add function "%s" as extensions have already been initialized.', $name));
947
+ }
948
+
949
+ $this->staging->addFunction($name, $function);
950
+ }
951
+
952
+ /**
953
+ * Get a function by name.
954
+ *
955
+ * Subclasses may override this method and load functions differently;
956
+ * so no list of functions is available.
957
+ *
958
+ * @param string $name function name
959
+ *
960
+ * @return Twig_Function|false A Twig_Function instance or false if the function does not exist
961
+ */
962
+ public function getFunction($name)
963
+ {
964
+ if (!$this->extensionInitialized) {
965
+ $this->initExtensions();
966
+ }
967
+
968
+ if (isset($this->functions[$name])) {
969
+ return $this->functions[$name];
970
+ }
971
+
972
+ foreach ($this->functions as $pattern => $function) {
973
+ $pattern = str_replace('\\*', '(.*?)', preg_quote($pattern, '#'), $count);
974
+
975
+ if ($count) {
976
+ if (preg_match('#^'.$pattern.'$#', $name, $matches)) {
977
+ array_shift($matches);
978
+ $function->setArguments($matches);
979
+
980
+ return $function;
981
+ }
982
+ }
983
+ }
984
+
985
+ foreach ($this->functionCallbacks as $callback) {
986
+ if (false !== $function = call_user_func($callback, $name)) {
987
+ return $function;
988
+ }
989
+ }
990
+
991
+ return false;
992
+ }
993
+
994
+ public function registerUndefinedFunctionCallback($callable)
995
+ {
996
+ $this->functionCallbacks[] = $callable;
997
+ }
998
+
999
+ /**
1000
+ * Gets registered functions.
1001
+ *
1002
+ * Be warned that this method cannot return functions defined with registerUndefinedFunctionCallback.
1003
+ *
1004
+ * @return Twig_FunctionInterface[] An array of Twig_FunctionInterface instances
1005
+ *
1006
+ * @see registerUndefinedFunctionCallback
1007
+ */
1008
+ public function getFunctions()
1009
+ {
1010
+ if (!$this->extensionInitialized) {
1011
+ $this->initExtensions();
1012
+ }
1013
+
1014
+ return $this->functions;
1015
+ }
1016
+
1017
+ /**
1018
+ * Registers a Global.
1019
+ *
1020
+ * New globals can be added before compiling or rendering a template;
1021
+ * but after, you can only update existing globals.
1022
+ *
1023
+ * @param string $name The global name
1024
+ * @param mixed $value The global value
1025
+ */
1026
+ public function addGlobal($name, $value)
1027
+ {
1028
+ if ($this->extensionInitialized || $this->runtimeInitialized) {
1029
+ if (null === $this->globals) {
1030
+ $this->globals = $this->initGlobals();
1031
+ }
1032
+
1033
+ /* This condition must be uncommented in Twig 2.0
1034
+ if (!array_key_exists($name, $this->globals)) {
1035
+ throw new LogicException(sprintf('Unable to add global "%s" as the runtime or the extensions have already been initialized.', $name));
1036
+ }
1037
+ */
1038
+ }
1039
+
1040
+ if ($this->extensionInitialized || $this->runtimeInitialized) {
1041
+ // update the value
1042
+ $this->globals[$name] = $value;
1043
+ } else {
1044
+ $this->staging->addGlobal($name, $value);
1045
+ }
1046
+ }
1047
+
1048
+ /**
1049
+ * Gets the registered Globals.
1050
+ *
1051
+ * @return array An array of globals
1052
+ */
1053
+ public function getGlobals()
1054
+ {
1055
+ if (!$this->runtimeInitialized && !$this->extensionInitialized) {
1056
+ return $this->initGlobals();
1057
+ }
1058
+
1059
+ if (null === $this->globals) {
1060
+ $this->globals = $this->initGlobals();
1061
+ }
1062
+
1063
+ return $this->globals;
1064
+ }
1065
+
1066
+ /**
1067
+ * Merges a context with the defined globals.
1068
+ *
1069
+ * @param array $context An array representing the context
1070
+ *
1071
+ * @return array The context merged with the globals
1072
+ */
1073
+ public function mergeGlobals(array $context)
1074
+ {
1075
+ // we don't use array_merge as the context being generally
1076
+ // bigger than globals, this code is faster.
1077
+ foreach ($this->getGlobals() as $key => $value) {
1078
+ if (!array_key_exists($key, $context)) {
1079
+ $context[$key] = $value;
1080
+ }
1081
+ }
1082
+
1083
+ return $context;
1084
+ }
1085
+
1086
+ /**
1087
+ * Gets the registered unary Operators.
1088
+ *
1089
+ * @return array An array of unary operators
1090
+ */
1091
+ public function getUnaryOperators()
1092
+ {
1093
+ if (!$this->extensionInitialized) {
1094
+ $this->initExtensions();
1095
+ }
1096
+
1097
+ return $this->unaryOperators;
1098
+ }
1099
+
1100
+ /**
1101
+ * Gets the registered binary Operators.
1102
+ *
1103
+ * @return array An array of binary operators
1104
+ */
1105
+ public function getBinaryOperators()
1106
+ {
1107
+ if (!$this->extensionInitialized) {
1108
+ $this->initExtensions();
1109
+ }
1110
+
1111
+ return $this->binaryOperators;
1112
+ }
1113
+
1114
+ public function computeAlternatives($name, $items)
1115
+ {
1116
+ $alternatives = array();
1117
+ foreach ($items as $item) {
1118
+ $lev = levenshtein($name, $item);
1119
+ if ($lev <= strlen($name) / 3 || false !== strpos($item, $name)) {
1120
+ $alternatives[$item] = $lev;
1121
+ }
1122
+ }
1123
+ asort($alternatives);
1124
+
1125
+ return array_keys($alternatives);
1126
+ }
1127
+
1128
+ protected function initGlobals()
1129
+ {
1130
+ $globals = array();
1131
+ foreach ($this->extensions as $extension) {
1132
+ $extGlob = $extension->getGlobals();
1133
+ if (!is_array($extGlob)) {
1134
+ throw new UnexpectedValueException(sprintf('"%s::getGlobals()" must return an array of globals.', get_class($extension)));
1135
+ }
1136
+
1137
+ $globals[] = $extGlob;
1138
+ }
1139
+
1140
+ $globals[] = $this->staging->getGlobals();
1141
+
1142
+ return call_user_func_array('array_merge', $globals);
1143
+ }
1144
+
1145
+ protected function initExtensions()
1146
+ {
1147
+ if ($this->extensionInitialized) {
1148
+ return;
1149
+ }
1150
+
1151
+ $this->extensionInitialized = true;
1152
+ $this->parsers = new Twig_TokenParserBroker();
1153
+ $this->filters = array();
1154
+ $this->functions = array();
1155
+ $this->tests = array();
1156
+ $this->visitors = array();
1157
+ $this->unaryOperators = array();
1158
+ $this->binaryOperators = array();
1159
+
1160
+ foreach ($this->extensions as $extension) {
1161
+ $this->initExtension($extension);
1162
+ }
1163
+ $this->initExtension($this->staging);
1164
+ }
1165
+
1166
+ protected function initExtension(Twig_ExtensionInterface $extension)
1167
+ {
1168
+ // filters
1169
+ foreach ($extension->getFilters() as $name => $filter) {
1170
+ if ($name instanceof Twig_SimpleFilter) {
1171
+ $filter = $name;
1172
+ $name = $filter->getName();
1173
+ } elseif ($filter instanceof Twig_SimpleFilter) {
1174
+ $name = $filter->getName();
1175
+ }
1176
+
1177
+ $this->filters[$name] = $filter;
1178
+ }
1179
+
1180
+ // functions
1181
+ foreach ($extension->getFunctions() as $name => $function) {
1182
+ if ($name instanceof Twig_SimpleFunction) {
1183
+ $function = $name;
1184
+ $name = $function->getName();
1185
+ } elseif ($function instanceof Twig_SimpleFunction) {
1186
+ $name = $function->getName();
1187
+ }
1188
+
1189
+ $this->functions[$name] = $function;
1190
+ }
1191
+
1192
+ // tests
1193
+ foreach ($extension->getTests() as $name => $test) {
1194
+ if ($name instanceof Twig_SimpleTest) {
1195
+ $test = $name;
1196
+ $name = $test->getName();
1197
+ } elseif ($test instanceof Twig_SimpleTest) {
1198
+ $name = $test->getName();
1199
+ }
1200
+
1201
+ $this->tests[$name] = $test;
1202
+ }
1203
+
1204
+ // token parsers
1205
+ foreach ($extension->getTokenParsers() as $parser) {
1206
+ if ($parser instanceof Twig_TokenParserInterface) {
1207
+ $this->parsers->addTokenParser($parser);
1208
+ } elseif ($parser instanceof Twig_TokenParserBrokerInterface) {
1209
+ $this->parsers->addTokenParserBroker($parser);
1210
+ } else {
1211
+ throw new LogicException('getTokenParsers() must return an array of Twig_TokenParserInterface or Twig_TokenParserBrokerInterface instances');
1212
+ }
1213
+ }
1214
+
1215
+ // node visitors
1216
+ foreach ($extension->getNodeVisitors() as $visitor) {
1217
+ $this->visitors[] = $visitor;
1218
+ }
1219
+
1220
+ // operators
1221
+ if ($operators = $extension->getOperators()) {
1222
+ if (2 !== count($operators)) {
1223
+ throw new InvalidArgumentException(sprintf('"%s::getOperators()" does not return a valid operators array.', get_class($extension)));
1224
+ }
1225
+
1226
+ $this->unaryOperators = array_merge($this->unaryOperators, $operators[0]);
1227
+ $this->binaryOperators = array_merge($this->binaryOperators, $operators[1]);
1228
+ }
1229
+ }
1230
+
1231
+ protected function writeCacheFile($file, $content)
1232
+ {
1233
+ $dir = dirname($file);
1234
+ if (!is_dir($dir)) {
1235
+ if (false === @mkdir($dir, 0777, true) && !is_dir($dir)) {
1236
+ throw new RuntimeException(sprintf("Unable to create the cache directory (%s).", $dir));
1237
+ }
1238
+ } elseif (!is_writable($dir)) {
1239
+ throw new RuntimeException(sprintf("Unable to write in the cache directory (%s).", $dir));
1240
+ }
1241
+
1242
+ $tmpFile = tempnam($dir, basename($file));
1243
+ if (false !== @file_put_contents($tmpFile, $content)) {
1244
+ // rename does not work on Win32 before 5.2.6
1245
+ if (@rename($tmpFile, $file) || (@copy($tmpFile, $file) && unlink($tmpFile))) {
1246
+ @chmod($file, 0666 & ~umask());
1247
+
1248
+ return;
1249
+ }
1250
+ }
1251
+
1252
+ throw new RuntimeException(sprintf('Failed to write cache file "%s".', $file));
1253
+ }
1254
+ }
classes/Twig/Error.php CHANGED
@@ -1,248 +1,248 @@
1
- <?php
2
-
3
- /*
4
- * This file is part of Twig.
5
- *
6
- * (c) 2009 Fabien Potencier
7
- *
8
- * For the full copyright and license information, please view the LICENSE
9
- * file that was distributed with this source code.
10
- */
11
-
12
- /**
13
- * Twig base exception.
14
- *
15
- * This exception class and its children must only be used when
16
- * an error occurs during the loading of a template, when a syntax error
17
- * is detected in a template, or when rendering a template. Other
18
- * errors must use regular PHP exception classes (like when the template
19
- * cache directory is not writable for instance).
20
- *
21
- * To help debugging template issues, this class tracks the original template
22
- * name and line where the error occurred.
23
- *
24
- * Whenever possible, you must set these information (original template name
25
- * and line number) yourself by passing them to the constructor. If some or all
26
- * these information are not available from where you throw the exception, then
27
- * this class will guess them automatically (when the line number is set to -1
28
- * and/or the filename is set to null). As this is a costly operation, this
29
- * can be disabled by passing false for both the filename and the line number
30
- * when creating a new instance of this class.
31
- *
32
- * @author Fabien Potencier <fabien@symfony.com>
33
- */
34
- class Twig_Error extends Exception
35
- {
36
- protected $lineno;
37
- protected $filename;
38
- protected $rawMessage;
39
- protected $previous;
40
-
41
- /**
42
- * Constructor.
43
- *
44
- * Set both the line number and the filename to false to
45
- * disable automatic guessing of the original template name
46
- * and line number.
47
- *
48
- * Set the line number to -1 to enable its automatic guessing.
49
- * Set the filename to null to enable its automatic guessing.
50
- *
51
- * By default, automatic guessing is enabled.
52
- *
53
- * @param string $message The error message
54
- * @param int $lineno The template line where the error occurred
55
- * @param string $filename The template file name where the error occurred
56
- * @param Exception $previous The previous exception
57
- */
58
- public function __construct($message, $lineno = -1, $filename = null, Exception $previous = null)
59
- {
60
- if (version_compare(PHP_VERSION, '5.3.0', '<')) {
61
- $this->previous = $previous;
62
- parent::__construct('');
63
- } else {
64
- parent::__construct('', 0, $previous);
65
- }
66
-
67
- $this->lineno = $lineno;
68
- $this->filename = $filename;
69
-
70
- if (-1 === $this->lineno || null === $this->filename) {
71
- $this->guessTemplateInfo();
72
- }
73
-
74
- $this->rawMessage = $message;
75
-
76
- $this->updateRepr();
77
- }
78
-
79
- /**
80
- * Gets the raw message.
81
- *
82
- * @return string The raw message
83
- */
84
- public function getRawMessage()
85
- {
86
- return $this->rawMessage;
87
- }
88
-
89
- /**
90
- * Gets the filename where the error occurred.
91
- *
92
- * @return string The filename
93
- */
94
- public function getTemplateFile()
95
- {
96
- return $this->filename;
97
- }
98
-
99
- /**
100
- * Sets the filename where the error occurred.
101
- *
102
- * @param string $filename The filename
103
- */
104
- public function setTemplateFile($filename)
105
- {
106
- $this->filename = $filename;
107
-
108
- $this->updateRepr();
109
- }
110
-
111
- /**
112
- * Gets the template line where the error occurred.
113
- *
114
- * @return int The template line
115
- */
116
- public function getTemplateLine()
117
- {
118
- return $this->lineno;
119
- }
120
-
121
- /**
122
- * Sets the template line where the error occurred.
123
- *
124
- * @param int $lineno The template line
125
- */
126
- public function setTemplateLine($lineno)
127
- {
128
- $this->lineno = $lineno;
129
-
130
- $this->updateRepr();
131
- }
132
-
133
- public function guess()
134
- {
135
- $this->guessTemplateInfo();
136
- $this->updateRepr();
137
- }
138
-
139
- /**
140
- * For PHP < 5.3.0, provides access to the getPrevious() method.
141
- *
142
- * @param string $method The method name
143
- * @param array $arguments The parameters to be passed to the method
144
- *
145
- * @return Exception The previous exception or null
146
- *
147
- * @throws BadMethodCallException
148
- */
149
- public function __call($method, $arguments)
150
- {
151
- if ('getprevious' == strtolower($method)) {
152
- return $this->previous;
153
- }
154
-
155
- throw new BadMethodCallException(sprintf('Method "Twig_Error::%s()" does not exist.', $method));
156
- }
157
-
158
- protected function updateRepr()
159
- {
160
- $this->message = $this->rawMessage;
161
-
162
- $dot = false;
163
- if ('.' === substr($this->message, -1)) {
164
- $this->message = substr($this->message, 0, -1);
165
- $dot = true;
166
- }
167
-
168
- if ($this->filename) {
169
- if (is_string($this->filename) || (is_object($this->filename) && method_exists($this->filename, '__toString'))) {
170
- $filename = sprintf('"%s"', $this->filename);
171
- } else {
172
- $filename = json_encode($this->filename);
173
- }
174
- $this->message .= sprintf(' in %s', $filename);
175
- }
176
-
177
- if ($this->lineno && $this->lineno >= 0) {
178
- $this->message .= sprintf(' at line %d', $this->lineno);
179
- }
180
-
181
- if ($dot) {
182
- $this->message .= '.';
183
- }
184
- }
185
-
186
- protected function guessTemplateInfo()
187
- {
188
- $template = null;
189
- $templateClass = null;
190
-
191
- if (version_compare(phpversion(), '5.3.6', '>=')) {
192
- $backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS | DEBUG_BACKTRACE_PROVIDE_OBJECT);
193
- } else {
194
- $backtrace = debug_backtrace();
195
- }
196
-
197
- foreach ($backtrace as $trace) {
198
- if (isset($trace['object']) && $trace['object'] instanceof Twig_Template && 'Twig_Template' !== get_class($trace['object'])) {
199
- $currentClass = get_class($trace['object']);
200
- $isEmbedContainer = 0 === strpos($templateClass, $currentClass);
201
- if (null === $this->filename || ($this->filename == $trace['object']->getTemplateName() && !$isEmbedContainer)) {
202
- $template = $trace['object'];
203
- $templateClass = get_class($trace['object']);
204
- }
205
- }
206
- }
207
-
208
- // update template filename
209
- if (null !== $template && null === $this->filename) {
210
- $this->filename = $template->getTemplateName();
211
- }
212
-
213
- if (null === $template || $this->lineno > -1) {
214
- return;
215
- }
216
-
217
- $r = new ReflectionObject($template);
218
- $file = $r->getFileName();
219
-
220
- // hhvm has a bug where eval'ed files comes out as the current directory
221
- if (is_dir($file)) {
222
- $file = '';
223
- }
224
-
225
- $exceptions = array($e = $this);
226
- while (($e instanceof self || method_exists($e, 'getPrevious')) && $e = $e->getPrevious()) {
227
- $exceptions[] = $e;
228
- }
229
-
230
- while ($e = array_pop($exceptions)) {
231
- $traces = $e->getTrace();
232
- while ($trace = array_shift($traces)) {
233
- if (!isset($trace['file']) || !isset($trace['line']) || $file != $trace['file']) {
234
- continue;
235
- }
236
-
237
- foreach ($template->getDebugInfo() as $codeLine => $templateLine) {
238
- if ($codeLine <= $trace['line']) {
239
- // update template line
240
- $this->lineno = $templateLine;
241
-
242
- return;
243
- }
244
- }
245
- }
246
- }
247
- }
248
- }
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2009 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ /**
13
+ * Twig base exception.
14
+ *
15
+ * This exception class and its children must only be used when
16
+ * an error occurs during the loading of a template, when a syntax error
17
+ * is detected in a template, or when rendering a template. Other
18
+ * errors must use regular PHP exception classes (like when the template
19
+ * cache directory is not writable for instance).
20
+ *
21
+ * To help debugging template issues, this class tracks the original template
22
+ * name and line where the error occurred.
23
+ *
24
+ * Whenever possible, you must set these information (original template name
25
+ * and line number) yourself by passing them to the constructor. If some or all
26
+ * these information are not available from where you throw the exception, then
27
+ * this class will guess them automatically (when the line number is set to -1
28
+ * and/or the filename is set to null). As this is a costly operation, this
29
+ * can be disabled by passing false for both the filename and the line number
30
+ * when creating a new instance of this class.
31
+ *
32
+ * @author Fabien Potencier <fabien@symfony.com>
33
+ */
34
+ class Twig_Error extends Exception
35
+ {
36
+ protected $lineno;
37
+ protected $filename;
38
+ protected $rawMessage;
39
+ protected $previous;
40
+
41
+ /**
42
+ * Constructor.
43
+ *
44
+ * Set both the line number and the filename to false to
45
+ * disable automatic guessing of the original template name
46
+ * and line number.
47
+ *
48
+ * Set the line number to -1 to enable its automatic guessing.
49
+ * Set the filename to null to enable its automatic guessing.
50
+ *
51
+ * By default, automatic guessing is enabled.
52
+ *
53
+ * @param string $message The error message
54
+ * @param int $lineno The template line where the error occurred
55
+ * @param string $filename The template file name where the error occurred
56
+ * @param Exception $previous The previous exception
57
+ */
58
+ public function __construct($message, $lineno = -1, $filename = null, Exception $previous = null)
59
+ {
60
+ if (version_compare(PHP_VERSION, '5.3.0', '<')) {
61
+ $this->previous = $previous;
62
+ parent::__construct('');
63
+ } else {
64
+ parent::__construct('', 0, $previous);
65
+ }
66
+
67
+ $this->lineno = $lineno;
68
+ $this->filename = $filename;
69
+
70
+ if (-1 === $this->lineno || null === $this->filename) {
71
+ $this->guessTemplateInfo();
72
+ }
73
+
74
+ $this->rawMessage = $message;
75
+
76
+ $this->updateRepr();
77
+ }
78
+
79
+ /**
80
+ * Gets the raw message.
81
+ *
82
+ * @return string The raw message
83
+ */
84
+ public function getRawMessage()
85
+ {
86
+ return $this->rawMessage;
87
+ }
88
+
89
+ /**
90
+ * Gets the filename where the error occurred.
91
+ *
92
+ * @return string The filename
93
+ */
94
+ public function getTemplateFile()
95
+ {
96
+ return $this->filename;
97
+ }
98
+
99
+ /**
100
+ * Sets the filename where the error occurred.
101
+ *
102
+ * @param string $filename The filename
103
+ */
104
+ public function setTemplateFile($filename)
105
+ {
106
+ $this->filename = $filename;
107
+
108
+ $this->updateRepr();
109
+ }
110
+
111
+ /**
112
+ * Gets the template line where the error occurred.
113
+ *
114
+ * @return int The template line
115
+ */
116
+ public function getTemplateLine()
117
+ {
118
+ return $this->lineno;
119
+ }
120
+
121
+ /**
122
+ * Sets the template line where the error occurred.
123
+ *
124
+ * @param int $lineno The template line
125
+ */
126
+ public function setTemplateLine($lineno)
127
+ {
128
+ $this->lineno = $lineno;
129
+
130
+ $this->updateRepr();
131
+ }
132
+
133
+ public function guess()
134
+ {
135
+ $this->guessTemplateInfo();
136
+ $this->updateRepr();
137
+ }
138
+
139
+ /**
140
+ * For PHP < 5.3.0, provides access to the getPrevious() method.
141
+ *
142
+ * @param string $method The method name
143
+ * @param array $arguments The parameters to be passed to the method
144
+ *
145
+ * @return Exception The previous exception or null
146
+ *
147
+ * @throws BadMethodCallException
148
+ */
149
+ public function __call($method, $arguments)
150
+ {
151
+ if ('getprevious' == strtolower($method)) {
152
+ return $this->previous;
153
+ }
154
+
155
+ throw new BadMethodCallException(sprintf('Method "Twig_Error::%s()" does not exist.', $method));
156
+ }
157
+
158
+ protected function updateRepr()
159
+ {
160
+ $this->message = $this->rawMessage;
161
+
162
+ $dot = false;
163
+ if ('.' === substr($this->message, -1)) {
164
+ $this->message = substr($this->message, 0, -1);
165
+ $dot = true;
166
+ }
167
+
168
+ if ($this->filename) {
169
+ if (is_string($this->filename) || (is_object($this->filename) && method_exists($this->filename, '__toString'))) {
170
+ $filename = sprintf('"%s"', $this->filename);
171
+ } else {
172
+ $filename = json_encode($this->filename);
173
+ }
174
+ $this->message .= sprintf(' in %s', $filename);
175
+ }
176
+
177
+ if ($this->lineno && $this->lineno >= 0) {
178
+ $this->message .= sprintf(' at line %d', $this->lineno);
179
+ }
180
+
181
+ if ($dot) {
182
+ $this->message .= '.';
183
+ }
184
+ }
185
+
186
+ protected function guessTemplateInfo()
187
+ {
188
+ $template = null;
189
+ $templateClass = null;
190
+
191
+ if (version_compare(phpversion(), '5.3.6', '>=')) {
192
+ $backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS | DEBUG_BACKTRACE_PROVIDE_OBJECT);
193
+ } else {
194
+ $backtrace = debug_backtrace();
195
+ }
196
+
197
+ foreach ($backtrace as $trace) {
198
+ if (isset($trace['object']) && $trace['object'] instanceof Twig_Template && 'Twig_Template' !== get_class($trace['object'])) {
199
+ $currentClass = get_class($trace['object']);
200
+ $isEmbedContainer = 0 === strpos($templateClass, $currentClass);
201
+ if (null === $this->filename || ($this->filename == $trace['object']->getTemplateName() && !$isEmbedContainer)) {
202
+ $template = $trace['object'];
203
+ $templateClass = get_class($trace['object']);
204
+ }
205
+ }
206
+ }
207
+
208
+ // update template filename
209
+ if (null !== $template && null === $this->filename) {
210
+ $this->filename = $template->getTemplateName();
211
+ }
212
+
213
+ if (null === $template || $this->lineno > -1) {
214
+ return;
215
+ }
216
+
217
+ $r = new ReflectionObject($template);
218
+ $file = $r->getFileName();
219
+
220
+ // hhvm has a bug where eval'ed files comes out as the current directory
221
+ if (is_dir($file)) {
222
+ $file = '';
223
+ }
224
+
225
+ $exceptions = array($e = $this);
226
+ while (($e instanceof self || method_exists($e, 'getPrevious')) && $e = $e->getPrevious()) {
227
+ $exceptions[] = $e;
228
+ }
229
+
230
+ while ($e = array_pop($exceptions)) {
231
+ $traces = $e->getTrace();
232
+ while ($trace = array_shift($traces)) {
233
+ if (!isset($trace['file']) || !isset($trace['line']) || $file != $trace['file']) {
234
+ continue;
235
+ }
236
+
237
+ foreach ($template->getDebugInfo() as $codeLine => $templateLine) {
238
+ if ($codeLine <= $trace['line']) {
239
+ // update template line
240
+ $this->lineno = $templateLine;
241
+
242
+ return;
243
+ }
244
+ }
245
+ }
246
+ }
247
+ }
248
+ }
classes/Twig/Error/Loader.php CHANGED
@@ -1,31 +1,31 @@
1
- <?php
2
-
3
- /*
4
- * This file is part of Twig.
5
- *
6
- * (c) 2010 Fabien Potencier
7
- *
8
- * For the full copyright and license information, please view the LICENSE
9
- * file that was distributed with this source code.
10
- */
11
-
12
- /**
13
- * Exception thrown when an error occurs during template loading.
14
- *
15
- * Automatic template information guessing is always turned off as
16
- * if a template cannot be loaded, there is nothing to guess.
17
- * However, when a template is loaded from another one, then, we need
18
- * to find the current context and this is automatically done by
19
- * Twig_Template::displayWithErrorHandling().
20
- *
21
- * This strategy makes Twig_Environment::resolveTemplate() much faster.
22
- *
23
- * @author Fabien Potencier <fabien@symfony.com>
24
- */
25
- class Twig_Error_Loader extends Twig_Error
26
- {
27
- public function __construct($message, $lineno = -1, $filename = null, Exception $previous = null)
28
- {
29
- parent::__construct($message, false, false, $previous);
30
- }
31
- }
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2010 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ /**
13
+ * Exception thrown when an error occurs during template loading.
14
+ *
15
+ * Automatic template information guessing is always turned off as
16
+ * if a template cannot be loaded, there is nothing to guess.
17
+ * However, when a template is loaded from another one, then, we need
18
+ * to find the current context and this is automatically done by
19
+ * Twig_Template::displayWithErrorHandling().
20
+ *
21
+ * This strategy makes Twig_Environment::resolveTemplate() much faster.
22
+ *
23
+ * @author Fabien Potencier <fabien@symfony.com>
24
+ */
25
+ class Twig_Error_Loader extends Twig_Error
26
+ {
27
+ public function __construct($message, $lineno = -1, $filename = null, Exception $previous = null)
28
+ {
29
+ parent::__construct($message, false, false, $previous);
30
+ }
31
+ }
classes/Twig/Error/Runtime.php CHANGED
@@ -1,20 +1,20 @@
1
- <?php
2
-
3
- /*
4
- * This file is part of Twig.
5
- *
6
- * (c) 2009 Fabien Potencier
7
- * (c) 2009 Armin Ronacher
8
- *
9
- * For the full copyright and license information, please view the LICENSE
10
- * file that was distributed with this source code.
11
- */
12
-
13
- /**
14
- * Exception thrown when an error occurs at runtime.
15
- *
16
- * @author Fabien Potencier <fabien@symfony.com>
17
- */
18
- class Twig_Error_Runtime extends Twig_Error
19
- {
20
- }
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2009 Fabien Potencier
7
+ * (c) 2009 Armin Ronacher
8
+ *
9
+ * For the full copyright and license information, please view the LICENSE
10
+ * file that was distributed with this source code.
11
+ */
12
+
13
+ /**
14
+ * Exception thrown when an error occurs at runtime.
15
+ *
16
+ * @author Fabien Potencier <fabien@symfony.com>
17
+ */
18
+ class Twig_Error_Runtime extends Twig_Error
19
+ {
20
+ }
classes/Twig/Error/Syntax.php CHANGED
@@ -1,20 +1,20 @@
1
- <?php
2
-
3
- /*
4
- * This file is part of Twig.
5
- *
6
- * (c) 2009 Fabien Potencier
7
- * (c) 2009 Armin Ronacher
8
- *
9
- * For the full copyright and license information, please view the LICENSE
10
- * file that was distributed with this source code.
11
- */
12
-
13
- /**
14
- * Exception thrown when a syntax error occurs during lexing or parsing of a template.
15
- *
16
- * @author Fabien Potencier <fabien@symfony.com>
17
- */
18
- class Twig_Error_Syntax extends Twig_Error
19
- {
20
- }
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2009 Fabien Potencier
7
+ * (c) 2009 Armin Ronacher
8
+ *
9
+ * For the full copyright and license information, please view the LICENSE
10
+ * file that was distributed with this source code.
11
+ */
12
+
13
+ /**
14
+ * Exception thrown when a syntax error occurs during lexing or parsing of a template.
15
+ *
16
+ * @author Fabien Potencier <fabien@symfony.com>
17
+ */
18
+ class Twig_Error_Syntax extends Twig_Error
19
+ {
20
+ }
classes/Twig/ExistsLoaderInterface.php CHANGED
@@ -1,29 +1,29 @@
1
- <?php
2
-
3
- /*
4
- * This file is part of Twig.
5
- *
6
- * (c) 2009 Fabien Potencier
7
- *
8
- * For the full copyright and license information, please view the LICENSE
9
- * file that was distributed with this source code.
10
- */
11
-
12
- /**
13
- * Adds an exists() method for loaders.
14
- *
15
- * @author Florin Patan <florinpatan@gmail.com>
16
- *
17
- * @deprecated since 1.12 (to be removed in 3.0)
18
- */
19
- interface Twig_ExistsLoaderInterface
20
- {
21
- /**
22
- * Check if we have the source code of a template, given its name.
23
- *
24
- * @param string $name The name of the template to check if we can load
25
- *
26
- * @return bool If the template source code is handled by this loader or not
27
- */
28
- public function exists($name);
29
- }
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2009 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ /**
13
+ * Adds an exists() method for loaders.
14
+ *
15
+ * @author Florin Patan <florinpatan@gmail.com>
16
+ *
17
+ * @deprecated since 1.12 (to be removed in 3.0)
18
+ */
19
+ interface Twig_ExistsLoaderInterface
20
+ {
21
+ /**
22
+ * Check if we have the source code of a template, given its name.
23
+ *
24
+ * @param string $name The name of the template to check if we can load
25
+ *
26
+ * @return bool If the template source code is handled by this loader or not
27
+ */
28
+ public function exists($name);
29
+ }
classes/Twig/ExpressionParser.php CHANGED
@@ -1,598 +1,598 @@
1
- <?php
2
-
3
- /*
4
- * This file is part of Twig.
5
- *
6
- * (c) 2009 Fabien Potencier
7
- * (c) 2009 Armin Ronacher
8
- *
9
- * For the full copyright and license information, please view the LICENSE
10
- * file that was distributed with this source code.
11
- */
12
-
13
- /**
14
- * Parses expressions.
15
- *
16
- * This parser implements a "Precedence climbing" algorithm.
17
- *
18
- * @see http://www.engr.mun.ca/~theo/Misc/exp_parsing.htm
19
- * @see http://en.wikipedia.org/wiki/Operator-precedence_parser
20
- *
21
- * @author Fabien Potencier <fabien@symfony.com>
22
- */
23
- class Twig_ExpressionParser
24
- {
25
- const OPERATOR_LEFT = 1;
26
- const OPERATOR_RIGHT = 2;
27
-
28
- protected $parser;
29
- protected $unaryOperators;
30
- protected $binaryOperators;
31
-
32
- public function __construct(Twig_Parser $parser, array $unaryOperators, array $binaryOperators)
33
- {
34
- $this->parser = $parser;
35
- $this->unaryOperators = $unaryOperators;
36
- $this->binaryOperators = $binaryOperators;
37
- }
38
-
39
- public function parseExpression($precedence = 0)
40
- {
41
- $expr = $this->getPrimary();
42
- $token = $this->parser->getCurrentToken();
43
- while ($this->isBinary($token) && $this->binaryOperators[$token->getValue()]['precedence'] >= $precedence) {
44
- $op = $this->binaryOperators[$token->getValue()];
45
- $this->parser->getStream()->next();
46
-
47
- if (isset($op['callable'])) {
48
- $expr = call_user_func($op['callable'], $this->parser, $expr);
49
- } else {
50
- $expr1 = $this->parseExpression(self::OPERATOR_LEFT === $op['associativity'] ? $op['precedence'] + 1 : $op['precedence']);
51
- $class = $op['class'];
52
- $expr = new $class($expr, $expr1, $token->getLine());
53
- }
54
-
55
- $token = $this->parser->getCurrentToken();
56
- }
57
-
58
- if (0 === $precedence) {
59
- return $this->parseConditionalExpression($expr);
60
- }
61
-
62
- return $expr;
63
- }
64
-
65
- protected function getPrimary()
66
- {
67
- $token = $this->parser->getCurrentToken();
68
-
69
- if ($this->isUnary($token)) {
70
- $operator = $this->unaryOperators[$token->getValue()];
71
- $this->parser->getStream()->next();
72
- $expr = $this->parseExpression($operator['precedence']);
73
- $class = $operator['class'];
74
-
75
- return $this->parsePostfixExpression(new $class($expr, $token->getLine()));
76
- } elseif ($token->test(Twig_Token::PUNCTUATION_TYPE, '(')) {
77
- $this->parser->getStream()->next();
78
- $expr = $this->parseExpression();
79
- $this->parser->getStream()->expect(Twig_Token::PUNCTUATION_TYPE, ')', 'An opened parenthesis is not properly closed');
80
-
81
- return $this->parsePostfixExpression($expr);
82
- }
83
-
84
- return $this->parsePrimaryExpression();
85
- }
86
-
87
- protected function parseConditionalExpression($expr)
88
- {
89
- while ($this->parser->getStream()->nextIf(Twig_Token::PUNCTUATION_TYPE, '?')) {
90
- if (!$this->parser->getStream()->nextIf(Twig_Token::PUNCTUATION_TYPE, ':')) {
91
- $expr2 = $this->parseExpression();
92
- if ($this->parser->getStream()->nextIf(Twig_Token::PUNCTUATION_TYPE, ':')) {
93
- $expr3 = $this->parseExpression();
94
- } else {
95
- $expr3 = new Twig_Node_Expression_Constant('', $this->parser->getCurrentToken()->getLine());
96
- }
97
- } else {
98
- $expr2 = $expr;
99
- $expr3 = $this->parseExpression();
100
- }
101
-
102
- $expr = new Twig_Node_Expression_Conditional($expr, $expr2, $expr3, $this->parser->getCurrentToken()->getLine());
103
- }
104
-
105
- return $expr;
106
- }
107
-
108
- protected function isUnary(Twig_Token $token)
109
- {
110
- return $token->test(Twig_Token::OPERATOR_TYPE) && isset($this->unaryOperators[$token->getValue()]);
111
- }
112
-
113
- protected function isBinary(Twig_Token $token)
114
- {
115
- return $token->test(Twig_Token::OPERATOR_TYPE) && isset($this->binaryOperators[$token->getValue()]);
116
- }
117
-
118
- public function parsePrimaryExpression()
119
- {
120
- $token = $this->parser->getCurrentToken();
121
- switch ($token->getType()) {
122
- case Twig_Token::NAME_TYPE:
123
- $this->parser->getStream()->next();
124
- switch ($token->getValue()) {
125
- case 'true':
126
- case 'TRUE':
127
- $node = new Twig_Node_Expression_Constant(true, $token->getLine());
128
- break;
129
-
130
- case 'false':
131
- case 'FALSE':
132
- $node = new Twig_Node_Expression_Constant(false, $token->getLine());
133
- break;
134
-
135
- case 'none':
136
- case 'NONE':
137
- case 'null':
138
- case 'NULL':
139
- $node = new Twig_Node_Expression_Constant(null, $token->getLine());
140
- break;
141
-
142
- default:
143
- if ('(' === $this->parser->getCurrentToken()->getValue()) {
144
- $node = $this->getFunctionNode($token->getValue(), $token->getLine());
145
- } else {
146
- $node = new Twig_Node_Expression_Name($token->getValue(), $token->getLine());
147
- }
148
- }
149
- break;
150
-
151
- case Twig_Token::NUMBER_TYPE:
152
- $this->parser->getStream()->next();
153
- $node = new Twig_Node_Expression_Constant($token->getValue(), $token->getLine());
154
- break;
155
-
156
- case Twig_Token::STRING_TYPE:
157
- case Twig_Token::INTERPOLATION_START_TYPE:
158
- $node = $this->parseStringExpression();
159
- break;
160
-
161
- case Twig_Token::OPERATOR_TYPE:
162
- if (preg_match(Twig_Lexer::REGEX_NAME, $token->getValue(), $matches) && $matches[0] == $token->getValue()) {
163
- // in this context, string operators are variable names
164
- $this->parser->getStream()->next();
165
- $node = new Twig_Node_Expression_Name($token->getValue(), $token->getLine());
166
- break;
167
- }
168
-
169
- default:
170
- if ($token->test(Twig_Token::PUNCTUATION_TYPE, '[')) {
171
- $node = $this->parseArrayExpression();
172
- } elseif ($token->test(Twig_Token::PUNCTUATION_TYPE, '{')) {
173
- $node = $this->parseHashExpression();
174
- } else {
175
- throw new Twig_Error_Syntax(sprintf('Unexpected token "%s" of value "%s"', Twig_Token::typeToEnglish($token->getType()), $token->getValue()), $token->getLine(), $this->parser->getFilename());
176
- }
177
- }
178
-
179
- return $this->parsePostfixExpression($node);
180
- }
181
-
182
- public function parseStringExpression()
183
- {
184
- $stream = $this->parser->getStream();
185
-
186
- $nodes = array();
187
- // a string cannot be followed by another string in a single expression
188
- $nextCanBeString = true;
189
- while (true) {
190
- if ($nextCanBeString && $token = $stream->nextIf(Twig_Token::STRING_TYPE)) {
191
- $nodes[] = new Twig_Node_Expression_Constant($token->getValue(), $token->getLine());
192
- $nextCanBeString = false;
193
- } elseif ($stream->nextIf(Twig_Token::INTERPOLATION_START_TYPE)) {
194
- $nodes[] = $this->parseExpression();
195
- $stream->expect(Twig_Token::INTERPOLATION_END_TYPE);
196
- $nextCanBeString = true;
197
- } else {
198
- break;
199
- }
200
- }
201
-
202
- $expr = array_shift($nodes);
203
- foreach ($nodes as $node) {
204
- $expr = new Twig_Node_Expression_Binary_Concat($expr, $node, $node->getLine());
205
- }
206
-
207
- return $expr;
208
- }
209
-
210
- public function parseArrayExpression()
211
- {
212
- $stream = $this->parser->getStream();
213
- $stream->expect(Twig_Token::PUNCTUATION_TYPE, '[', 'An array element was expected');
214
-
215
- $node = new Twig_Node_Expression_Array(array(), $stream->getCurrent()->getLine());
216
- $first = true;
217
- while (!$stream->test(Twig_Token::PUNCTUATION_TYPE, ']')) {
218
- if (!$first) {
219
- $stream->expect(Twig_Token::PUNCTUATION_TYPE, ',', 'An array element must be followed by a comma');
220
-
221
- // trailing ,?
222
- if ($stream->test(Twig_Token::PUNCTUATION_TYPE, ']')) {
223
- break;
224
- }
225
- }
226
- $first = false;
227
-
228
- $node->addElement($this->parseExpression());
229
- }
230
- $stream->expect(Twig_Token::PUNCTUATION_TYPE, ']', 'An opened array is not properly closed');
231
-
232
- return $node;
233
- }
234
-
235
- public function parseHashExpression()
236
- {
237
- $stream = $this->parser->getStream();
238
- $stream->expect(Twig_Token::PUNCTUATION_TYPE, '{', 'A hash element was expected');
239
-
240
- $node = new Twig_Node_Expression_Array(array(), $stream->getCurrent()->getLine());
241
- $first = true;
242
- while (!$stream->test(Twig_Token::PUNCTUATION_TYPE, '}')) {
243
- if (!$first) {
244
- $stream->expect(Twig_Token::PUNCTUATION_TYPE, ',', 'A hash value must be followed by a comma');
245
-
246
- // trailing ,?
247
- if ($stream->test(Twig_Token::PUNCTUATION_TYPE, '}')) {
248
- break;
249
- }
250
- }
251
- $first = false;
252
-
253
- // a hash key can be:
254
- //
255
- // * a number -- 12
256
- // * a string -- 'a'
257
- // * a name, which is equivalent to a string -- a
258
- // * an expression, which must be enclosed in parentheses -- (1 + 2)
259
- if (($token = $stream->nextIf(Twig_Token::STRING_TYPE)) || ($token = $stream->nextIf(Twig_Token::NAME_TYPE)) || $token = $stream->nextIf(Twig_Token::NUMBER_TYPE)) {
260
- $key = new Twig_Node_Expression_Constant($token->getValue(), $token->getLine());
261
- } elseif ($stream->test(Twig_Token::PUNCTUATION_TYPE, '(')) {
262
- $key = $this->parseExpression();
263
- } else {
264
- $current = $stream->getCurrent();
265
-
266
- throw new Twig_Error_Syntax(sprintf('A hash key must be a quoted string, a number, a name, or an expression enclosed in parentheses (unexpected token "%s" of value "%s"', Twig_Token::typeToEnglish($current->getType()), $current->getValue()), $current->getLine(), $this->parser->getFilename());
267
- }
268
-
269
- $stream->expect(Twig_Token::PUNCTUATION_TYPE, ':', 'A hash key must be followed by a colon (:)');
270
- $value = $this->parseExpression();
271
-
272
- $node->addElement($value, $key);
273
- }
274
- $stream->expect(Twig_Token::PUNCTUATION_TYPE, '}', 'An opened hash is not properly closed');
275
-
276
- return $node;
277
- }
278
-
279
- public function parsePostfixExpression($node)
280
- {
281
- while (true) {
282
- $token = $this->parser->getCurrentToken();
283
- if ($token->getType() == Twig_Token::PUNCTUATION_TYPE) {
284
- if ('.' == $token->getValue() || '[' == $token->getValue()) {
285
- $node = $this->parseSubscriptExpression($node);
286
- } elseif ('|' == $token->getValue()) {
287
- $node = $this->parseFilterExpression($node);
288
- } else {
289
- break;
290
- }
291
- } else {
292
- break;
293
- }
294
- }
295
-
296
- return $node;
297
- }
298
-
299
- public function getFunctionNode($name, $line)
300
- {
301
- switch ($name) {
302
- case 'parent':
303
- $args = $this->parseArguments();
304
- if (!count($this->parser->getBlockStack())) {
305
- throw new Twig_Error_Syntax('Calling "parent" outside a block is forbidden', $line, $this->parser->getFilename());
306
- }
307
-
308
- if (!$this->parser->getParent() && !$this->parser->hasTraits()) {
309
- throw new Twig_Error_Syntax('Calling "parent" on a template that does not extend nor "use" another template is forbidden', $line, $this->parser->getFilename());
310
- }
311
-
312
- return new Twig_Node_Expression_Parent($this->parser->peekBlockStack(), $line);
313
- case 'block':
314
- return new Twig_Node_Expression_BlockReference($this->parseArguments()->getNode(0), false, $line);
315
- case 'attribute':
316
- $args = $this->parseArguments();
317
- if (count($args) < 2) {
318
- throw new Twig_Error_Syntax('The "attribute" function takes at least two arguments (the variable and the attributes)', $line, $this->parser->getFilename());
319
- }
320
-
321
- return new Twig_Node_Expression_GetAttr($args->getNode(0), $args->getNode(1), count($args) > 2 ? $args->getNode(2) : new Twig_Node_Expression_Array(array(), $line), Twig_Template::ANY_CALL, $line);
322
- default:
323
- if (null !== $alias = $this->parser->getImportedSymbol('function', $name)) {
324
- $arguments = new Twig_Node_Expression_Array(array(), $line);
325
- foreach ($this->parseArguments() as $n) {
326
- $arguments->addElement($n);
327
- }
328
-
329
- $node = new Twig_Node_Expression_MethodCall($alias['node'], $alias['name'], $arguments, $line);
330
- $node->setAttribute('safe', true);
331
-
332
- return $node;
333
- }
334
-
335
- $args = $this->parseArguments(true);
336
- $class = $this->getFunctionNodeClass($name, $line);
337
-
338
- return new $class($name, $args, $line);
339
- }
340
- }
341
-
342
- public function parseSubscriptExpression($node)
343
- {
344
- $stream = $this->parser->getStream();
345
- $token = $stream->next();
346
- $lineno = $token->getLine();
347
- $arguments = new Twig_Node_Expression_Array(array(), $lineno);
348
- $type = Twig_Template::ANY_CALL;
349
- if ($token->getValue() == '.') {
350
- $token = $stream->next();
351
- if (
352
- $token->getType() == Twig_Token::NAME_TYPE
353
- ||
354
- $token->getType() == Twig_Token::NUMBER_TYPE
355
- ||
356
- ($token->getType() == Twig_Token::OPERATOR_TYPE && preg_match(Twig_Lexer::REGEX_NAME, $token->getValue()))
357
- ) {
358
- $arg = new Twig_Node_Expression_Constant($token->getValue(), $lineno);
359
-
360
- if ($stream->test(Twig_Token::PUNCTUATION_TYPE, '(')) {
361
- $type = Twig_TemplateInterface::METHOD_CALL;
362
- foreach ($this->parseArguments() as $n) {
363
- $arguments->addElement($n);
364
- }
365
- }
366
- } else {
367
- throw new Twig_Error_Syntax('Expected name or number', $lineno, $this->parser->getFilename());
368
- }
369
-
370
- if ($node instanceof Twig_Node_Expression_Name && null !== $this->parser->getImportedSymbol('template', $node->getAttribute('name'))) {
371
- if (!$arg instanceof Twig_Node_Expression_Constant) {
372
- throw new Twig_Error_Syntax(sprintf('Dynamic macro names are not supported (called on "%s")', $node->getAttribute('name')), $token->getLine(), $this->parser->getFilename());
373
- }
374
-
375
- $node = new Twig_Node_Expression_MethodCall($node, 'get'.$arg->getAttribute('value'), $arguments, $lineno);
376
- $node->setAttribute('safe', true);
377
-
378
- return $node;
379
- }
380
- } else {
381
- $type = Twig_Template::ARRAY_CALL;
382
-
383
- // slice?
384
- $slice = false;
385
- if ($stream->test(Twig_Token::PUNCTUATION_TYPE, ':')) {
386
- $slice = true;
387
- $arg = new Twig_Node_Expression_Constant(0, $token->getLine());
388
- } else {
389
- $arg = $this->parseExpression();
390
- }
391
-
392
- if ($stream->nextIf(Twig_Token::PUNCTUATION_TYPE, ':')) {
393
- $slice = true;
394
- }
395
-
396
- if ($slice) {
397
- if ($stream->test(Twig_Token::PUNCTUATION_TYPE, ']')) {
398
- $length = new Twig_Node_Expression_Constant(null, $token->getLine());
399
- } else {
400
- $length = $this->parseExpression();
401
- }
402
-
403
- $class = $this->getFilterNodeClass('slice', $token->getLine());
404
- $arguments = new Twig_Node(array($arg, $length));
405
- $filter = new $class($node, new Twig_Node_Expression_Constant('slice', $token->getLine()), $arguments, $token->getLine());
406
-
407
- $stream->expect(Twig_Token::PUNCTUATION_TYPE, ']');
408
-
409
- return $filter;
410
- }
411
-
412
- $stream->expect(Twig_Token::PUNCTUATION_TYPE, ']');
413
- }
414
-
415
- return new Twig_Node_Expression_GetAttr($node, $arg, $arguments, $type, $lineno);
416
- }
417
-
418
- public function parseFilterExpression($node)
419
- {
420
- $this->parser->getStream()->next();
421
-
422
- return $this->parseFilterExpressionRaw($node);
423
- }
424
-
425
- public function parseFilterExpressionRaw($node, $tag = null)
426
- {
427
- while (true) {
428
- $token = $this->parser->getStream()->expect(Twig_Token::NAME_TYPE);
429
-
430
- $name = new Twig_Node_Expression_Constant($token->getValue(), $token->getLine());
431
- if (!$this->parser->getStream()->test(Twig_Token::PUNCTUATION_TYPE, '(')) {
432
- $arguments = new Twig_Node();
433
- } else {
434
- $arguments = $this->parseArguments(true);
435
- }
436
-
437
- $class = $this->getFilterNodeClass($name->getAttribute('value'), $token->getLine());
438
-
439
- $node = new $class($node, $name, $arguments, $token->getLine(), $tag);
440
-
441
- if (!$this->parser->getStream()->test(Twig_Token::PUNCTUATION_TYPE, '|')) {
442
- break;
443
- }
444
-
445
- $this->parser->getStream()->next();
446
- }
447
-
448
- return $node;
449
- }
450
-
451
- /**
452
- * Parses arguments.
453
- *
454
- * @param bool $namedArguments Whether to allow named arguments or not
455
- * @param bool $definition Whether we are parsing arguments for a function definition
456
- */
457
- public function parseArguments($namedArguments = false, $definition = false)
458
- {
459
- $args = array();
460
- $stream = $this->parser->getStream();
461
-
462
- $stream->expect(Twig_Token::PUNCTUATION_TYPE, '(', 'A list of arguments must begin with an opening parenthesis');
463
- while (!$stream->test(Twig_Token::PUNCTUATION_TYPE, ')')) {
464
- if (!empty($args)) {
465
- $stream->expect(Twig_Token::PUNCTUATION_TYPE, ',', 'Arguments must be separated by a comma');
466
- }
467
-
468
- if ($definition) {
469
- $token = $stream->expect(Twig_Token::NAME_TYPE, null, 'An argument must be a name');
470
- $value = new Twig_Node_Expression_Name($token->getValue(), $this->parser->getCurrentToken()->getLine());
471
- } else {
472
- $value = $this->parseExpression();
473
- }
474
-
475
- $name = null;
476
- if ($namedArguments && $token = $stream->nextIf(Twig_Token::OPERATOR_TYPE, '=')) {
477
- if (!$value instanceof Twig_Node_Expression_Name) {
478
- throw new Twig_Error_Syntax(sprintf('A parameter name must be a string, "%s" given', get_class($value)), $token->getLine(), $this->parser->getFilename());
479
- }
480
- $name = $value->getAttribute('name');
481
-
482
- if ($definition) {
483
- $value = $this->parsePrimaryExpression();
484
-
485
- if (!$this->checkConstantExpression($value)) {
486
- throw new Twig_Error_Syntax(sprintf('A default value for an argument must be a constant (a boolean, a string, a number, or an array).'), $token->getLine(), $this->parser->getFilename());
487
- }
488
- } else {
489
- $value = $this->parseExpression();
490
- }
491
- }
492
-
493
- if ($definition) {
494
- if (null === $name) {
495
- $name = $value->getAttribute('name');
496
- $value = new Twig_Node_Expression_Constant(null, $this->parser->getCurrentToken()->getLine());
497
- }
498
- $args[$name] = $value;
499
- } else {
500
- if (null === $name) {
501
- $args[] = $value;
502
- } else {
503
- $args[$name] = $value;
504
- }
505
- }
506
- }
507
- $stream->expect(Twig_Token::PUNCTUATION_TYPE, ')', 'A list of arguments must be closed by a parenthesis');
508
-
509
- return new Twig_Node($args);
510
- }
511
-
512
- public function parseAssignmentExpression()
513
- {
514
- $targets = array();
515
- while (true) {
516
- $token = $this->parser->getStream()->expect(Twig_Token::NAME_TYPE, null, 'Only variables can be assigned to');
517
- if (in_array($token->getValue(), array('true', 'false', 'none'))) {
518
- throw new Twig_Error_Syntax(sprintf('You cannot assign a value to "%s"', $token->getValue()), $token->getLine(), $this->parser->getFilename());
519
- }
520
- $targets[] = new Twig_Node_Expression_AssignName($token->getValue(), $token->getLine());
521
-
522
- if (!$this->parser->getStream()->nextIf(Twig_Token::PUNCTUATION_TYPE, ',')) {
523
- break;
524
- }
525
- }
526
-
527
- return new Twig_Node($targets);
528
- }
529
-
530
- public function parseMultitargetExpression()
531
- {
532
- $targets = array();
533
- while (true) {
534
- $targets[] = $this->parseExpression();
535
- if (!$this->parser->getStream()->nextIf(Twig_Token::PUNCTUATION_TYPE, ',')) {
536
- break;
537
- }
538
- }
539
-
540
- return new Twig_Node($targets);
541
- }
542
-
543
- protected function getFunctionNodeClass($name, $line)
544
- {
545
- $env = $this->parser->getEnvironment();
546
-
547
- if (false === $function = $env->getFunction($name)) {
548
- $message = sprintf('The function "%s" does not exist', $name);
549
- if ($alternatives = $env->computeAlternatives($name, array_keys($env->getFunctions()))) {
550
- $message = sprintf('%s. Did you mean "%s"', $message, implode('", "', $alternatives));
551
- }
552
-
553
- throw new Twig_Error_Syntax($message, $line, $this->parser->getFilename());
554
- }
555
-
556
- if ($function instanceof Twig_SimpleFunction) {
557
- return $function->getNodeClass();
558
- }
559
-
560
- return $function instanceof Twig_Function_Node ? $function->getClass() : 'Twig_Node_Expression_Function';
561
- }
562
-
563
- protected function getFilterNodeClass($name, $line)
564
- {
565
- $env = $this->parser->getEnvironment();
566
-
567
- if (false === $filter = $env->getFilter($name)) {
568
- $message = sprintf('The filter "%s" does not exist', $name);
569
- if ($alternatives = $env->computeAlternatives($name, array_keys($env->getFilters()))) {
570
- $message = sprintf('%s. Did you mean "%s"', $message, implode('", "', $alternatives));
571
- }
572
-
573
- throw new Twig_Error_Syntax($message, $line, $this->parser->getFilename());
574
- }
575
-
576
- if ($filter instanceof Twig_SimpleFilter) {
577
- return $filter->getNodeClass();
578
- }
579
-
580
- return $filter instanceof Twig_Filter_Node ? $filter->getClass() : 'Twig_Node_Expression_Filter';
581
- }
582
-
583
- // checks that the node only contains "constant" elements
584
- protected function checkConstantExpression(Twig_NodeInterface $node)
585
- {
586
- if (!($node instanceof Twig_Node_Expression_Constant || $node instanceof Twig_Node_Expression_Array)) {
587
- return false;
588
- }
589
-
590
- foreach ($node as $n) {
591
- if (!$this->checkConstantExpression($n)) {
592
- return false;
593
- }
594
- }
595
-
596
- return true;
597
- }
598
- }
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2009 Fabien Potencier
7
+ * (c) 2009 Armin Ronacher
8
+ *
9
+ * For the full copyright and license information, please view the LICENSE
10
+ * file that was distributed with this source code.
11
+ */
12
+
13
+ /**
14
+ * Parses expressions.
15
+ *
16
+ * This parser implements a "Precedence climbing" algorithm.
17
+ *
18
+ * @see http://www.engr.mun.ca/~theo/Misc/exp_parsing.htm
19
+ * @see http://en.wikipedia.org/wiki/Operator-precedence_parser
20
+ *
21
+ * @author Fabien Potencier <fabien@symfony.com>
22
+ */
23
+ class Twig_ExpressionParser
24
+ {
25
+ const OPERATOR_LEFT = 1;
26
+ const OPERATOR_RIGHT = 2;
27
+
28
+ protected $parser;
29
+ protected $unaryOperators;
30
+ protected $binaryOperators;
31
+
32
+ public function __construct(Twig_Parser $parser, array $unaryOperators, array $binaryOperators)
33
+ {
34
+ $this->parser = $parser;
35
+ $this->unaryOperators = $unaryOperators;
36
+ $this->binaryOperators = $binaryOperators;
37
+ }
38
+
39
+ public function parseExpression($precedence = 0)
40
+ {
41
+ $expr = $this->getPrimary();
42
+ $token = $this->parser->getCurrentToken();
43
+ while ($this->isBinary($token) && $this->binaryOperators[$token->getValue()]['precedence'] >= $precedence) {
44
+ $op = $this->binaryOperators[$token->getValue()];
45
+ $this->parser->getStream()->next();
46
+
47
+ if (isset($op['callable'])) {
48
+ $expr = call_user_func($op['callable'], $this->parser, $expr);
49
+ } else {
50
+ $expr1 = $this->parseExpression(self::OPERATOR_LEFT === $op['associativity'] ? $op['precedence'] + 1 : $op['precedence']);
51
+ $class = $op['class'];
52
+ $expr = new $class($expr, $expr1, $token->getLine());
53
+ }
54
+
55
+ $token = $this->parser->getCurrentToken();
56
+ }
57
+
58
+ if (0 === $precedence) {
59
+ return $this->parseConditionalExpression($expr);
60
+ }
61
+
62
+ return $expr;
63
+ }
64
+
65
+ protected function getPrimary()
66
+ {
67
+ $token = $this->parser->getCurrentToken();
68
+
69
+ if ($this->isUnary($token)) {
70
+ $operator = $this->unaryOperators[$token->getValue()];
71
+ $this->parser->getStream()->next();
72
+ $expr = $this->parseExpression($operator['precedence']);
73
+ $class = $operator['class'];
74
+
75
+ return $this->parsePostfixExpression(new $class($expr, $token->getLine()));
76
+ } elseif ($token->test(Twig_Token::PUNCTUATION_TYPE, '(')) {
77
+ $this->parser->getStream()->next();
78
+ $expr = $this->parseExpression();
79
+ $this->parser->getStream()->expect(Twig_Token::PUNCTUATION_TYPE, ')', 'An opened parenthesis is not properly closed');
80
+
81
+ return $this->parsePostfixExpression($expr);
82
+ }
83
+
84
+ return $this->parsePrimaryExpression();
85
+ }
86
+
87
+ protected function parseConditionalExpression($expr)
88
+ {
89
+ while ($this->parser->getStream()->nextIf(Twig_Token::PUNCTUATION_TYPE, '?')) {
90
+ if (!$this->parser->getStream()->nextIf(Twig_Token::PUNCTUATION_TYPE, ':')) {
91
+ $expr2 = $this->parseExpression();
92
+ if ($this->parser->getStream()->nextIf(Twig_Token::PUNCTUATION_TYPE, ':')) {
93
+ $expr3 = $this->parseExpression();
94
+ } else {
95
+ $expr3 = new Twig_Node_Expression_Constant('', $this->parser->getCurrentToken()->getLine());
96
+ }
97
+ } else {
98
+ $expr2 = $expr;
99
+ $expr3 = $this->parseExpression();
100
+ }
101
+
102
+ $expr = new Twig_Node_Expression_Conditional($expr, $expr2, $expr3, $this->parser->getCurrentToken()->getLine());
103
+ }
104
+
105
+ return $expr;
106
+ }
107
+
108
+ protected function isUnary(Twig_Token $token)
109
+ {
110
+ return $token->test(Twig_Token::OPERATOR_TYPE) && isset($this->unaryOperators[$token->getValue()]);
111
+ }
112
+
113
+ protected function isBinary(Twig_Token $token)
114
+ {
115
+ return $token->test(Twig_Token::OPERATOR_TYPE) && isset($this->binaryOperators[$token->getValue()]);
116
+ }
117
+
118
+ public function parsePrimaryExpression()
119
+ {
120
+ $token = $this->parser->getCurrentToken();
121
+ switch ($token->getType()) {
122
+ case Twig_Token::NAME_TYPE:
123
+ $this->parser->getStream()->next();
124
+ switch ($token->getValue()) {
125
+ case 'true':
126
+ case 'TRUE':
127
+ $node = new Twig_Node_Expression_Constant(true, $token->getLine());
128
+ break;
129
+
130
+ case 'false':
131
+ case 'FALSE':
132
+ $node = new Twig_Node_Expression_Constant(false, $token->getLine());
133
+ break;
134
+
135
+ case 'none':
136
+ case 'NONE':
137
+ case 'null':
138
+ case 'NULL':
139
+ $node = new Twig_Node_Expression_Constant(null, $token->getLine());
140
+ break;
141
+
142
+ default:
143
+ if ('(' === $this->parser->getCurrentToken()->getValue()) {
144
+ $node = $this->getFunctionNode($token->getValue(), $token->getLine());
145
+ } else {
146
+ $node = new Twig_Node_Expression_Name($token->getValue(), $token->getLine());
147
+ }
148
+ }
149
+ break;
150
+
151
+ case Twig_Token::NUMBER_TYPE:
152
+ $this->parser->getStream()->next();
153
+ $node = new Twig_Node_Expression_Constant($token->getValue(), $token->getLine());
154
+ break;
155
+
156
+ case Twig_Token::STRING_TYPE:
157
+ case Twig_Token::INTERPOLATION_START_TYPE:
158
+ $node = $this->parseStringExpression();
159
+ break;
160
+
161
+ case Twig_Token::OPERATOR_TYPE:
162
+ if (preg_match(Twig_Lexer::REGEX_NAME, $token->getValue(), $matches) && $matches[0] == $token->getValue()) {
163
+ // in this context, string operators are variable names
164
+ $this->parser->getStream()->next();
165
+ $node = new Twig_Node_Expression_Name($token->getValue(), $token->getLine());
166
+ break;
167
+ }
168
+
169
+ default:
170
+ if ($token->test(Twig_Token::PUNCTUATION_TYPE, '[')) {
171
+ $node = $this->parseArrayExpression();
172
+ } elseif ($token->test(Twig_Token::PUNCTUATION_TYPE, '{')) {
173
+ $node = $this->parseHashExpression();
174
+ } else {
175
+ throw new Twig_Error_Syntax(sprintf('Unexpected token "%s" of value "%s"', Twig_Token::typeToEnglish($token->getType()), $token->getValue()), $token->getLine(), $this->parser->getFilename());
176
+ }
177
+ }
178
+
179
+ return $this->parsePostfixExpression($node);
180
+ }
181
+
182
+ public function parseStringExpression()
183
+ {
184
+ $stream = $this->parser->getStream();
185
+
186
+ $nodes = array();
187
+ // a string cannot be followed by another string in a single expression
188
+ $nextCanBeString = true;
189
+ while (true) {
190
+ if ($nextCanBeString && $token = $stream->nextIf(Twig_Token::STRING_TYPE)) {
191
+ $nodes[] = new Twig_Node_Expression_Constant($token->getValue(), $token->getLine());
192
+ $nextCanBeString = false;
193
+ } elseif ($stream->nextIf(Twig_Token::INTERPOLATION_START_TYPE)) {
194
+ $nodes[] = $this->parseExpression();
195
+ $stream->expect(Twig_Token::INTERPOLATION_END_TYPE);
196
+ $nextCanBeString = true;
197
+ } else {
198
+ break;
199
+ }
200
+ }
201
+
202
+ $expr = array_shift($nodes);
203
+ foreach ($nodes as $node) {
204
+ $expr = new Twig_Node_Expression_Binary_Concat($expr, $node, $node->getLine());
205
+ }
206
+
207
+ return $expr;
208
+ }
209
+
210
+ public function parseArrayExpression()
211
+ {
212
+ $stream = $this->parser->getStream();
213
+ $stream->expect(Twig_Token::PUNCTUATION_TYPE, '[', 'An array element was expected');
214
+
215
+ $node = new Twig_Node_Expression_Array(array(), $stream->getCurrent()->getLine());
216
+ $first = true;
217
+ while (!$stream->test(Twig_Token::PUNCTUATION_TYPE, ']')) {
218
+ if (!$first) {
219
+ $stream->expect(Twig_Token::PUNCTUATION_TYPE, ',', 'An array element must be followed by a comma');
220
+
221
+ // trailing ,?
222
+ if ($stream->test(Twig_Token::PUNCTUATION_TYPE, ']')) {
223
+ break;
224
+ }
225
+ }
226
+ $first = false;
227
+
228
+ $node->addElement($this->parseExpression());
229
+ }
230
+ $stream->expect(Twig_Token::PUNCTUATION_TYPE, ']', 'An opened array is not properly closed');
231
+
232
+ return $node;
233
+ }
234
+
235
+ public function parseHashExpression()
236
+ {
237
+ $stream = $this->parser->getStream();
238
+ $stream->expect(Twig_Token::PUNCTUATION_TYPE, '{', 'A hash element was expected');
239
+
240
+ $node = new Twig_Node_Expression_Array(array(), $stream->getCurrent()->getLine());
241
+ $first = true;
242
+ while (!$stream->test(Twig_Token::PUNCTUATION_TYPE, '}')) {
243
+ if (!$first) {
244
+ $stream->expect(Twig_Token::PUNCTUATION_TYPE, ',', 'A hash value must be followed by a comma');
245
+
246
+ // trailing ,?
247
+ if ($stream->test(Twig_Token::PUNCTUATION_TYPE, '}')) {
248
+ break;
249
+ }
250
+ }
251
+ $first = false;
252
+
253
+ // a hash key can be:
254
+ //
255
+ // * a number -- 12
256
+ // * a string -- 'a'
257
+ // * a name, which is equivalent to a string -- a
258
+ // * an expression, which must be enclosed in parentheses -- (1 + 2)
259
+ if (($token = $stream->nextIf(Twig_Token::STRING_TYPE)) || ($token = $stream->nextIf(Twig_Token::NAME_TYPE)) || $token = $stream->nextIf(Twig_Token::NUMBER_TYPE)) {
260
+ $key = new Twig_Node_Expression_Constant($token->getValue(), $token->getLine());
261
+ } elseif ($stream->test(Twig_Token::PUNCTUATION_TYPE, '(')) {
262
+ $key = $this->parseExpression();
263
+ } else {
264
+ $current = $stream->getCurrent();
265
+
266
+ throw new Twig_Error_Syntax(sprintf('A hash key must be a quoted string, a number, a name, or an expression enclosed in parentheses (unexpected token "%s" of value "%s"', Twig_Token::typeToEnglish($current->getType()), $current->getValue()), $current->getLine(), $this->parser->getFilename());
267
+ }
268
+
269
+ $stream->expect(Twig_Token::PUNCTUATION_TYPE, ':', 'A hash key must be followed by a colon (:)');
270
+ $value = $this->parseExpression();
271
+
272
+ $node->addElement($value, $key);
273
+ }
274
+ $stream->expect(Twig_Token::PUNCTUATION_TYPE, '}', 'An opened hash is not properly closed');
275
+
276
+ return $node;
277
+ }
278
+
279
+ public function parsePostfixExpression($node)
280
+ {
281
+ while (true) {
282
+ $token = $this->parser->getCurrentToken();
283
+ if ($token->getType() == Twig_Token::PUNCTUATION_TYPE) {
284
+ if ('.' == $token->getValue() || '[' == $token->getValue()) {
285
+ $node = $this->parseSubscriptExpression($node);
286
+ } elseif ('|' == $token->getValue()) {
287
+ $node = $this->parseFilterExpression($node);
288
+ } else {
289
+ break;
290
+ }
291
+ } else {
292
+ break;
293
+ }
294
+ }
295
+
296
+ return $node;
297
+ }
298
+
299
+ public function getFunctionNode($name, $line)
300
+ {
301
+ switch ($name) {
302
+ case 'parent':
303
+ $args = $this->parseArguments();
304
+ if (!count($this->parser->getBlockStack())) {
305
+ throw new Twig_Error_Syntax('Calling "parent" outside a block is forbidden', $line, $this->parser->getFilename());
306
+ }
307
+
308
+ if (!$this->parser->getParent() && !$this->parser->hasTraits()) {
309
+ throw new Twig_Error_Syntax('Calling "parent" on a template that does not extend nor "use" another template is forbidden', $line, $this->parser->getFilename());
310
+ }
311
+
312
+ return new Twig_Node_Expression_Parent($this->parser->peekBlockStack(), $line);
313
+ case 'block':
314
+ return new Twig_Node_Expression_BlockReference($this->parseArguments()->getNode(0), false, $line);
315
+ case 'attribute':
316
+ $args = $this->parseArguments();
317
+ if (count($args) < 2) {
318
+ throw new Twig_Error_Syntax('The "attribute" function takes at least two arguments (the variable and the attributes)', $line, $this->parser->getFilename());
319
+ }
320
+
321
+ return new Twig_Node_Expression_GetAttr($args->getNode(0), $args->getNode(1), count($args) > 2 ? $args->getNode(2) : new Twig_Node_Expression_Array(array(), $line), Twig_Template::ANY_CALL, $line);
322
+ default:
323
+ if (null !== $alias = $this->parser->getImportedSymbol('function', $name)) {
324
+ $arguments = new Twig_Node_Expression_Array(array(), $line);
325
+ foreach ($this->parseArguments() as $n) {
326
+ $arguments->addElement($n);
327
+ }
328
+
329
+ $node = new Twig_Node_Expression_MethodCall($alias['node'], $alias['name'], $arguments, $line);
330
+ $node->setAttribute('safe', true);
331
+
332
+ return $node;
333
+ }
334
+
335
+ $args = $this->parseArguments(true);
336
+ $class = $this->getFunctionNodeClass($name, $line);
337
+
338
+ return new $class($name, $args, $line);
339
+ }
340
+ }
341
+
342
+ public function parseSubscriptExpression($node)
343
+ {
344
+ $stream = $this->parser->getStream();
345
+ $token = $stream->next();
346
+ $lineno = $token->getLine();
347
+ $arguments = new Twig_Node_Expression_Array(array(), $lineno);
348
+ $type = Twig_Template::ANY_CALL;
349
+ if ($token->getValue() == '.') {
350
+ $token = $stream->next();
351
+ if (
352
+ $token->getType() == Twig_Token::NAME_TYPE
353
+ ||
354
+ $token->getType() == Twig_Token::NUMBER_TYPE
355
+ ||
356
+ ($token->getType() == Twig_Token::OPERATOR_TYPE && preg_match(Twig_Lexer::REGEX_NAME, $token->getValue()))
357
+ ) {
358
+ $arg = new Twig_Node_Expression_Constant($token->getValue(), $lineno);
359
+
360
+ if ($stream->test(Twig_Token::PUNCTUATION_TYPE, '(')) {
361
+ $type = Twig_TemplateInterface::METHOD_CALL;
362
+ foreach ($this->parseArguments() as $n) {
363
+ $arguments->addElement($n);
364
+ }
365
+ }
366
+ } else {
367
+ throw new Twig_Error_Syntax('Expected name or number', $lineno, $this->parser->getFilename());
368
+ }
369
+
370
+ if ($node instanceof Twig_Node_Expression_Name && null !== $this->parser->getImportedSymbol('template', $node->getAttribute('name'))) {
371
+ if (!$arg instanceof Twig_Node_Expression_Constant) {
372
+ throw new Twig_Error_Syntax(sprintf('Dynamic macro names are not supported (called on "%s")', $node->getAttribute('name')), $token->getLine(), $this->parser->getFilename());
373
+ }
374
+
375
+ $node = new Twig_Node_Expression_MethodCall($node, 'get'.$arg->getAttribute('value'), $arguments, $lineno);
376
+ $node->setAttribute('safe', true);
377
+
378
+ return $node;
379
+ }
380
+ } else {
381
+ $type = Twig_Template::ARRAY_CALL;
382
+
383
+ // slice?
384
+ $slice = false;
385
+ if ($stream->test(Twig_Token::PUNCTUATION_TYPE, ':')) {
386
+ $slice = true;
387
+ $arg = new Twig_Node_Expression_Constant(0, $token->getLine());
388
+ } else {
389
+ $arg = $this->parseExpression();
390
+ }
391
+
392
+ if ($stream->nextIf(Twig_Token::PUNCTUATION_TYPE, ':')) {
393
+ $slice = true;
394
+ }
395
+
396
+ if ($slice) {
397
+ if ($stream->test(Twig_Token::PUNCTUATION_TYPE, ']')) {
398
+ $length = new Twig_Node_Expression_Constant(null, $token->getLine());
399
+ } else {
400
+ $length = $this->parseExpression();
401
+ }
402
+
403
+ $class = $this->getFilterNodeClass('slice', $token->getLine());
404
+ $arguments = new Twig_Node(array($arg, $length));
405
+ $filter = new $class($node, new Twig_Node_Expression_Constant('slice', $token->getLine()), $arguments, $token->getLine());
406
+
407
+ $stream->expect(Twig_Token::PUNCTUATION_TYPE, ']');
408
+
409
+ return $filter;
410
+ }
411
+
412
+ $stream->expect(Twig_Token::PUNCTUATION_TYPE, ']');
413
+ }
414
+
415
+ return new Twig_Node_Expression_GetAttr($node, $arg, $arguments, $type, $lineno);
416
+ }
417
+
418
+ public function parseFilterExpression($node)
419
+ {
420
+ $this->parser->getStream()->next();
421
+
422
+ return $this->parseFilterExpressionRaw($node);
423
+ }
424
+
425
+ public function parseFilterExpressionRaw($node, $tag = null)
426
+ {
427
+ while (true) {
428
+ $token = $this->parser->getStream()->expect(Twig_Token::NAME_TYPE);
429
+
430
+ $name = new Twig_Node_Expression_Constant($token->getValue(), $token->getLine());
431
+ if (!$this->parser->getStream()->test(Twig_Token::PUNCTUATION_TYPE, '(')) {
432
+ $arguments = new Twig_Node();
433
+ } else {
434
+ $arguments = $this->parseArguments(true);
435
+ }
436
+
437
+ $class = $this->getFilterNodeClass($name->getAttribute('value'), $token->getLine());
438
+
439
+ $node = new $class($node, $name, $arguments, $token->getLine(), $tag);
440
+
441
+ if (!$this->parser->getStream()->test(Twig_Token::PUNCTUATION_TYPE, '|')) {
442
+ break;
443
+ }
444
+
445
+ $this->parser->getStream()->next();
446
+ }
447
+
448
+ return $node;
449
+ }
450
+
451
+ /**
452
+ * Parses arguments.
453
+ *
454
+ * @param bool $namedArguments Whether to allow named arguments or not
455
+ * @param bool $definition Whether we are parsing arguments for a function definition
456
+ */
457
+ public function parseArguments($namedArguments = false, $definition = false)
458
+ {
459
+ $args = array();
460
+ $stream = $this->parser->getStream();
461
+
462
+ $stream->expect(Twig_Token::PUNCTUATION_TYPE, '(', 'A list of arguments must begin with an opening parenthesis');
463
+ while (!$stream->test(Twig_Token::PUNCTUATION_TYPE, ')')) {
464
+ if (!empty($args)) {
465
+ $stream->expect(Twig_Token::PUNCTUATION_TYPE, ',', 'Arguments must be separated by a comma');
466
+ }
467
+
468
+ if ($definition) {
469
+ $token = $stream->expect(Twig_Token::NAME_TYPE, null, 'An argument must be a name');
470
+ $value = new Twig_Node_Expression_Name($token->getValue(), $this->parser->getCurrentToken()->getLine());
471
+ } else {
472
+ $value = $this->parseExpression();
473
+ }
474
+
475
+ $name = null;
476
+ if ($namedArguments && $token = $stream->nextIf(Twig_Token::OPERATOR_TYPE, '=')) {
477
+ if (!$value instanceof Twig_Node_Expression_Name) {
478
+ throw new Twig_Error_Syntax(sprintf('A parameter name must be a string, "%s" given', get_class($value)), $token->getLine(), $this->parser->getFilename());
479
+ }
480
+ $name = $value->getAttribute('name');
481
+
482
+ if ($definition) {
483
+ $value = $this->parsePrimaryExpression();
484
+
485
+ if (!$this->checkConstantExpression($value)) {
486
+ throw new Twig_Error_Syntax(sprintf('A default value for an argument must be a constant (a boolean, a string, a number, or an array).'), $token->getLine(), $this->parser->getFilename());
487
+ }
488
+ } else {
489
+ $value = $this->parseExpression();
490
+ }
491
+ }
492
+
493
+ if ($definition) {
494
+ if (null === $name) {
495
+ $name = $value->getAttribute('name');
496
+ $value = new Twig_Node_Expression_Constant(null, $this->parser->getCurrentToken()->getLine());
497
+ }
498
+ $args[$name] = $value;
499
+ } else {
500
+ if (null === $name) {
501
+ $args[] = $value;
502
+ } else {
503
+ $args[$name] = $value;
504
+ }
505
+ }
506
+ }
507
+ $stream->expect(Twig_Token::PUNCTUATION_TYPE, ')', 'A list of arguments must be closed by a parenthesis');
508
+
509
+ return new Twig_Node($args);
510
+ }
511
+
512
+ public function parseAssignmentExpression()
513
+ {
514
+ $targets = array();
515
+ while (true) {
516
+ $token = $this->parser->getStream()->expect(Twig_Token::NAME_TYPE, null, 'Only variables can be assigned to');
517
+ if (in_array($token->getValue(), array('true', 'false', 'none'))) {
518
+ throw new Twig_Error_Syntax(sprintf('You cannot assign a value to "%s"', $token->getValue()), $token->getLine(), $this->parser->getFilename());
519
+ }
520
+ $targets[] = new Twig_Node_Expression_AssignName($token->getValue(), $token->getLine());
521
+
522
+ if (!$this->parser->getStream()->nextIf(Twig_Token::PUNCTUATION_TYPE, ',')) {
523
+ break;
524
+ }
525
+ }
526
+
527
+ return new Twig_Node($targets);
528
+ }
529
+
530
+ public function parseMultitargetExpression()
531
+ {
532
+ $targets = array();
533
+ while (true) {
534
+ $targets[] = $this->parseExpression();
535
+ if (!$this->parser->getStream()->nextIf(Twig_Token::PUNCTUATION_TYPE, ',')) {
536
+ break;
537
+ }
538
+ }
539
+
540
+ return new Twig_Node($targets);
541
+ }
542
+
543
+ protected function getFunctionNodeClass($name, $line)
544
+ {
545
+ $env = $this->parser->getEnvironment();
546
+
547
+ if (false === $function = $env->getFunction($name)) {
548
+ $message = sprintf('The function "%s" does not exist', $name);
549
+ if ($alternatives = $env->computeAlternatives($name, array_keys($env->getFunctions()))) {
550
+ $message = sprintf('%s. Did you mean "%s"', $message, implode('", "', $alternatives));
551
+ }
552
+
553
+ throw new Twig_Error_Syntax($message, $line, $this->parser->getFilename());
554
+ }
555
+
556
+ if ($function instanceof Twig_SimpleFunction) {
557
+ return $function->getNodeClass();
558
+ }
559
+
560
+ return $function instanceof Twig_Function_Node ? $function->getClass() : 'Twig_Node_Expression_Function';
561
+ }
562
+
563
+ protected function getFilterNodeClass($name, $line)
564
+ {
565
+ $env = $this->parser->getEnvironment();
566
+
567
+ if (false === $filter = $env->getFilter($name)) {
568
+ $message = sprintf('The filter "%s" does not exist', $name);
569
+ if ($alternatives = $env->computeAlternatives($name, array_keys($env->getFilters()))) {
570
+ $message = sprintf('%s. Did you mean "%s"', $message, implode('", "', $alternatives));
571
+ }
572
+
573
+ throw new Twig_Error_Syntax($message, $line, $this->parser->getFilename());
574
+ }
575
+
576
+ if ($filter instanceof Twig_SimpleFilter) {
577
+ return $filter->getNodeClass();
578
+ }
579
+
580
+ return $filter instanceof Twig_Filter_Node ? $filter->getClass() : 'Twig_Node_Expression_Filter';
581
+ }
582
+
583
+ // checks that the node only contains "constant" elements
584
+ protected function checkConstantExpression(Twig_NodeInterface $node)
585
+ {
586
+ if (!($node instanceof Twig_Node_Expression_Constant || $node instanceof Twig_Node_Expression_Array)) {
587
+ return false;
588
+ }
589
+
590
+ foreach ($node as $n) {
591
+ if (!$this->checkConstantExpression($n)) {
592
+ return false;
593
+ }
594
+ }
595
+
596
+ return true;
597
+ }
598
+ }
classes/Twig/Extension.php CHANGED
@@ -1,93 +1,93 @@
1
- <?php
2
-
3
- /*
4
- * This file is part of Twig.
5
- *
6
- * (c) 2009 Fabien Potencier
7
- *
8
- * For the full copyright and license information, please view the LICENSE
9
- * file that was distributed with this source code.
10
- */
11
- abstract class Twig_Extension implements Twig_ExtensionInterface
12
- {
13
- /**
14
- * Initializes the runtime environment.
15
- *
16
- * This is where you can load some file that contains filter functions for instance.
17
- *
18
- * @param Twig_Environment $environment The current Twig_Environment instance
19
- */
20
- public function initRuntime(Twig_Environment $environment)
21
- {
22
- }
23
-
24
- /**
25
- * Returns the token parser instances to add to the existing list.
26
- *
27
- * @return array An array of Twig_TokenParserInterface or Twig_TokenParserBrokerInterface instances
28
- */
29
- public function getTokenParsers()
30
- {
31
- return array();
32
- }
33
-
34
- /**
35
- * Returns the node visitor instances to add to the existing list.
36
- *
37
- * @return Twig_NodeVisitorInterface[] An array of Twig_NodeVisitorInterface instances
38
- */
39
- public function getNodeVisitors()
40
- {
41
- return array();
42
- }
43
-
44
- /**
45
- * Returns a list of filters to add to the existing list.
46
- *
47
- * @return array An array of filters
48
- */
49
- public function getFilters()
50
- {
51
- return array();
52
- }
53
-
54
- /**
55
- * Returns a list of tests to add to the existing list.
56
- *
57
- * @return array An array of tests
58
- */
59
- public function getTests()
60
- {
61
- return array();
62
- }
63
-
64
- /**
65
- * Returns a list of functions to add to the existing list.
66
- *
67
- * @return array An array of functions
68
- */
69
- public function getFunctions()
70
- {
71
- return array();
72
- }
73
-
74
- /**
75
- * Returns a list of operators to add to the existing list.
76
- *
77
- * @return array An array of operators
78
- */
79
- public function getOperators()
80
- {
81
- return array();
82
- }
83
-
84
- /**
85
- * Returns a list of global variables to add to the existing list.
86
- *
87
- * @return array An array of global variables
88
- */
89
- public function getGlobals()
90
- {
91
- return array();
92
- }
93
- }
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2009 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+ abstract class Twig_Extension implements Twig_ExtensionInterface
12
+ {
13
+ /**
14
+ * Initializes the runtime environment.
15
+ *
16
+ * This is where you can load some file that contains filter functions for instance.
17
+ *
18
+ * @param Twig_Environment $environment The current Twig_Environment instance
19
+ */
20
+ public function initRuntime(Twig_Environment $environment)
21
+ {
22
+ }
23
+
24
+ /**
25
+ * Returns the token parser instances to add to the existing list.
26
+ *
27
+ * @return array An array of Twig_TokenParserInterface or Twig_TokenParserBrokerInterface instances
28
+ */
29
+ public function getTokenParsers()
30
+ {
31
+ return array();
32
+ }
33
+
34
+ /**
35
+ * Returns the node visitor instances to add to the existing list.
36
+ *
37
+ * @return Twig_NodeVisitorInterface[] An array of Twig_NodeVisitorInterface instances
38
+ */
39
+ public function getNodeVisitors()
40
+ {
41
+ return array();
42
+ }
43
+
44
+ /**
45
+ * Returns a list of filters to add to the existing list.
46
+ *
47
+ * @return array An array of filters
48
+ */
49
+ public function getFilters()
50
+ {
51
+ return array();
52
+ }
53
+
54
+ /**
55
+ * Returns a list of tests to add to the existing list.
56
+ *
57
+ * @return array An array of tests
58
+ */
59
+ public function getTests()
60
+ {
61
+ return array();
62
+ }
63
+
64
+ /**
65
+ * Returns a list of functions to add to the existing list.
66
+ *
67
+ * @return array An array of functions
68
+ */
69
+ public function getFunctions()
70
+ {
71
+ return array();
72
+ }
73
+
74
+ /**
75
+ * Returns a list of operators to add to the existing list.
76
+ *
77
+ * @return array An array of operators
78
+ */
79
+ public function getOperators()
80
+ {
81
+ return array();
82
+ }
83
+
84
+ /**
85
+ * Returns a list of global variables to add to the existing list.
86
+ *
87
+ * @return array An array of global variables
88
+ */
89
+ public function getGlobals()
90
+ {
91
+ return array();
92
+ }
93
+ }
classes/Twig/Extension/Core.php CHANGED
@@ -1,1462 +1,1462 @@
1
- <?php
2
-
3
- if (!defined('ENT_SUBSTITUTE')) {
4
- // use 0 as hhvm does not support several flags yet
5
- define('ENT_SUBSTITUTE', 0);
6
- }
7
-
8
- /*
9
- * This file is part of Twig.
10
- *
11
- * (c) 2009 Fabien Potencier
12
- *
13
- * For the full copyright and license information, please view the LICENSE
14
- * file that was distributed with this source code.
15
- */
16
- class Twig_Extension_Core extends Twig_Extension
17
- {
18
- protected $dateFormats = array('F j, Y H:i', '%d days');
19
- protected $numberFormat = array(0, '.', ',');
20
- protected $timezone = null;
21
- protected $escapers = array();
22
-
23
- /**
24
- * Defines a new escaper to be used via the escape filter.
25
- *
26
- * @param string $strategy The strategy name that should be used as a strategy in the escape call
27
- * @param callable $callable A valid PHP callable
28
- */
29
- public function setEscaper($strategy, $callable)
30
- {
31
- $this->escapers[$strategy] = $callable;
32
- }
33
-
34
- /**
35
- * Gets all defined escapers.
36
- *
37
- * @return array An array of escapers
38
- */
39
- public function getEscapers()
40
- {
41
- return $this->escapers;
42
- }
43
-
44
- /**
45
- * Sets the default format to be used by the date filter.
46
- *
47
- * @param string $format The default date format string
48
- * @param string $dateIntervalFormat The default date interval format string
49
- */
50
- public function setDateFormat($format = null, $dateIntervalFormat = null)
51
- {
52
- if (null !== $format) {
53
- $this->dateFormats[0] = $format;
54
- }
55
-
56
- if (null !== $dateIntervalFormat) {
57
- $this->dateFormats[1] = $dateIntervalFormat;
58
- }
59
- }
60
-
61
- /**
62
- * Gets the default format to be used by the date filter.
63
- *
64
- * @return array The default date format string and the default date interval format string
65
- */
66
- public function getDateFormat()
67
- {
68
- return $this->dateFormats;
69
- }
70
-
71
- /**
72
- * Sets the default timezone to be used by the date filter.
73
- *
74
- * @param DateTimeZone|string $timezone The default timezone string or a DateTimeZone object
75
- */
76
- public function setTimezone($timezone)
77
- {
78
- $this->timezone = $timezone instanceof DateTimeZone ? $timezone : new DateTimeZone($timezone);
79
- }
80
-
81
- /**
82
- * Gets the default timezone to be used by the date filter.
83
- *
84
- * @return DateTimeZone The default timezone currently in use
85
- */
86
- public function getTimezone()
87
- {
88
- if (null === $this->timezone) {
89
- $this->timezone = new DateTimeZone(date_default_timezone_get());
90
- }
91
-
92
- return $this->timezone;
93
- }
94
-
95
- /**
96
- * Sets the default format to be used by the number_format filter.
97
- *
98
- * @param int $decimal The number of decimal places to use.
99
- * @param string $decimalPoint The character(s) to use for the decimal point.
100
- * @param string $thousandSep The character(s) to use for the thousands separator.
101
- */
102
- public function setNumberFormat($decimal, $decimalPoint, $thousandSep)
103
- {
104
- $this->numberFormat = array($decimal, $decimalPoint, $thousandSep);
105
- }
106
-
107
- /**
108
- * Get the default format used by the number_format filter.
109
- *
110
- * @return array The arguments for number_format()
111
- */
112
- public function getNumberFormat()
113
- {
114
- return $this->numberFormat;
115
- }
116
-
117
- /**
118
- * Returns the token parser instance to add to the existing list.
119
- *
120
- * @return Twig_TokenParser[] An array of Twig_TokenParser instances
121
- */
122
- public function getTokenParsers()
123
- {
124
- return array(
125
- new Twig_TokenParser_For(),
126
- new Twig_TokenParser_If(),
127
- new Twig_TokenParser_Extends(),
128
- new Twig_TokenParser_Include(),
129
- new Twig_TokenParser_Block(),
130
- new Twig_TokenParser_Use(),
131
- new Twig_TokenParser_Filter(),
132
- new Twig_TokenParser_Macro(),
133
- new Twig_TokenParser_Import(),
134
- new Twig_TokenParser_From(),
135
- new Twig_TokenParser_Set(),
136
- new Twig_TokenParser_Spaceless(),
137
- new Twig_TokenParser_Flush(),
138
- new Twig_TokenParser_Do(),
139
- new Twig_TokenParser_Embed(),
140
- );
141
- }
142
-
143
- /**
144
- * Returns a list of filters to add to the existing list.
145
- *
146
- * @return array An array of filters
147
- */
148
- public function getFilters()
149
- {
150
- $filters = array(
151
- // formatting filters
152
- new Twig_SimpleFilter('date', 'twig_date_format_filter', array('needs_environment' => true)),
153
- new Twig_SimpleFilter('date_modify', 'twig_date_modify_filter', array('needs_environment' => true)),
154
- new Twig_SimpleFilter('format', 'sprintf'),
155
- new Twig_SimpleFilter('replace', 'strtr'),
156
- new Twig_SimpleFilter('number_format', 'twig_number_format_filter', array('needs_environment' => true)),
157
- new Twig_SimpleFilter('abs', 'abs'),
158
- new Twig_SimpleFilter('round', 'twig_round'),
159
-
160
- // encoding
161
- new Twig_SimpleFilter('url_encode', 'twig_urlencode_filter'),
162
- new Twig_SimpleFilter('json_encode', 'twig_jsonencode_filter'),
163
- new Twig_SimpleFilter('convert_encoding', 'twig_convert_encoding'),
164
-
165
- // string filters
166
- new Twig_SimpleFilter('title', 'twig_title_string_filter', array('needs_environment' => true)),
167
- new Twig_SimpleFilter('capitalize', 'twig_capitalize_string_filter', array('needs_environment' => true)),
168
- new Twig_SimpleFilter('upper', 'strtoupper'),
169
- new Twig_SimpleFilter('lower', 'strtolower'),
170
- new Twig_SimpleFilter('striptags', 'strip_tags'),
171
- new Twig_SimpleFilter('trim', 'trim'),
172
- new Twig_SimpleFilter('nl2br', 'nl2br', array('pre_escape' => 'html', 'is_safe' => array('html'))),
173
-
174
- // array helpers
175
- new Twig_SimpleFilter('join', 'twig_join_filter'),
176
- new Twig_SimpleFilter('split', 'twig_split_filter'),
177
- new Twig_SimpleFilter('sort', 'twig_sort_filter'),
178
- new Twig_SimpleFilter('merge', 'twig_array_merge'),
179
- new Twig_SimpleFilter('batch', 'twig_array_batch'),
180
-
181
- // string/array filters
182
- new Twig_SimpleFilter('reverse', 'twig_reverse_filter', array('needs_environment' => true)),
183
- new Twig_SimpleFilter('length', 'twig_length_filter', array('needs_environment' => true)),
184
- new Twig_SimpleFilter('slice', 'twig_slice', array('needs_environment' => true)),
185
- new Twig_SimpleFilter('first', 'twig_first', array('needs_environment' => true)),
186
- new Twig_SimpleFilter('last', 'twig_last', array('needs_environment' => true)),
187
-
188
- // iteration and runtime
189
- new Twig_SimpleFilter('default', '_twig_default_filter', array('node_class' => 'Twig_Node_Expression_Filter_Default')),
190
- new Twig_SimpleFilter('keys', 'twig_get_array_keys_filter'),
191
-
192
- // escaping
193
- new Twig_SimpleFilter('escape', 'twig_escape_filter', array('needs_environment' => true, 'is_safe_callback' => 'twig_escape_filter_is_safe')),
194
- new Twig_SimpleFilter('e', 'twig_escape_filter', array('needs_environment' => true, 'is_safe_callback' => 'twig_escape_filter_is_safe')),
195
- );
196
-
197
- if (function_exists('mb_get_info')) {
198
- $filters[] = new Twig_SimpleFilter('upper', 'twig_upper_filter', array('needs_environment' => true));
199
- $filters[] = new Twig_SimpleFilter('lower', 'twig_lower_filter', array('needs_environment' => true));
200
- }
201
-
202
- return $filters;
203
- }
204
-
205
- /**
206
- * Returns a list of global functions to add to the existing list.
207
- *
208
- * @return array An array of global functions
209
- */
210
- public function getFunctions()
211
- {
212
- return array(
213
- new Twig_SimpleFunction('max', 'max'),
214
- new Twig_SimpleFunction('min', 'min'),
215
- new Twig_SimpleFunction('range', 'range'),
216
- new Twig_SimpleFunction('constant', 'twig_constant'),
217
- new Twig_SimpleFunction('cycle', 'twig_cycle'),
218
- new Twig_SimpleFunction('random', 'twig_random', array('needs_environment' => true)),
219
- new Twig_SimpleFunction('date', 'twig_date_converter', array('needs_environment' => true)),
220
- new Twig_SimpleFunction('include', 'twig_include', array('needs_environment' => true, 'needs_context' => true, 'is_safe' => array('all'))),
221
- new Twig_SimpleFunction('source', 'twig_source', array('needs_environment' => true, 'is_safe' => array('all'))),
222
- );
223
- }
224
-
225
- /**
226
- * Returns a list of tests to add to the existing list.
227
- *
228
- * @return array An array of tests
229
- */
230
- public function getTests()
231
- {
232
- return array(
233
- new Twig_SimpleTest('even', null, array('node_class' => 'Twig_Node_Expression_Test_Even')),
234
- new Twig_SimpleTest('odd', null, array('node_class' => 'Twig_Node_Expression_Test_Odd')),
235
- new Twig_SimpleTest('defined', null, array('node_class' => 'Twig_Node_Expression_Test_Defined')),
236
- new Twig_SimpleTest('sameas', null, array('node_class' => 'Twig_Node_Expression_Test_Sameas')),
237
- new Twig_SimpleTest('same as', null, array('node_class' => 'Twig_Node_Expression_Test_Sameas')),
238
- new Twig_SimpleTest('none', null, array('node_class' => 'Twig_Node_Expression_Test_Null')),
239
- new Twig_SimpleTest('null', null, array('node_class' => 'Twig_Node_Expression_Test_Null')),
240
- new Twig_SimpleTest('divisibleby', null, array('node_class' => 'Twig_Node_Expression_Test_Divisibleby')),
241
- new Twig_SimpleTest('divisible by', null, array('node_class' => 'Twig_Node_Expression_Test_Divisibleby')),
242
- new Twig_SimpleTest('constant', null, array('node_class' => 'Twig_Node_Expression_Test_Constant')),
243
- new Twig_SimpleTest('empty', 'twig_test_empty'),
244
- new Twig_SimpleTest('iterable', 'twig_test_iterable'),
245
- );
246
- }
247
-
248
- /**
249
- * Returns a list of operators to add to the existing list.
250
- *
251
- * @return array An array of operators
252
- */
253
- public function getOperators()
254
- {
255
- return array(
256
- array(
257
- 'not' => array('precedence' => 50, 'class' => 'Twig_Node_Expression_Unary_Not'),
258
- '-' => array('precedence' => 500, 'class' => 'Twig_Node_Expression_Unary_Neg'),
259
- '+' => array('precedence' => 500, 'class' => 'Twig_Node_Expression_Unary_Pos'),
260
- ),
261
- array(
262
- 'or' => array('precedence' => 10, 'class' => 'Twig_Node_Expression_Binary_Or', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
263
- 'and' => array('precedence' => 15, 'class' => 'Twig_Node_Expression_Binary_And', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
264
- 'b-or' => array('precedence' => 16, 'class' => 'Twig_Node_Expression_Binary_BitwiseOr', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
265
- 'b-xor' => array('precedence' => 17, 'class' => 'Twig_Node_Expression_Binary_BitwiseXor', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
266
- 'b-and' => array('precedence' => 18, 'class' => 'Twig_Node_Expression_Binary_BitwiseAnd', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
267
- '==' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_Equal', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
268
- '!=' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_NotEqual', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
269
- '<' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_Less', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
270
- '>' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_Greater', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
271
- '>=' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_GreaterEqual', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
272
- '<=' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_LessEqual', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
273
- 'not in' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_NotIn', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
274
- 'in' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_In', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
275
- 'matches' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_Matches', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
276
- 'starts with' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_StartsWith', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
277
- 'ends with' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_EndsWith', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
278
- '..' => array('precedence' => 25, 'class' => 'Twig_Node_Expression_Binary_Range', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
279
- '+' => array('precedence' => 30, 'class' => 'Twig_Node_Expression_Binary_Add', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
280
- '-' => array('precedence' => 30, 'class' => 'Twig_Node_Expression_Binary_Sub', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
281
- '~' => array('precedence' => 40, 'class' => 'Twig_Node_Expression_Binary_Concat', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
282
- '*' => array('precedence' => 60, 'class' => 'Twig_Node_Expression_Binary_Mul', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
283
- '/' => array('precedence' => 60, 'class' => 'Twig_Node_Expression_Binary_Div', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
284
- '//' => array('precedence' => 60, 'class' => 'Twig_Node_Expression_Binary_FloorDiv', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
285
- '%' => array('precedence' => 60, 'class' => 'Twig_Node_Expression_Binary_Mod', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
286
- 'is' => array('precedence' => 100, 'callable' => array($this, 'parseTestExpression'), 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
287
- 'is not' => array('precedence' => 100, 'callable' => array($this, 'parseNotTestExpression'), 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
288
- '**' => array('precedence' => 200, 'class' => 'Twig_Node_Expression_Binary_Power', 'associativity' => Twig_ExpressionParser::OPERATOR_RIGHT),
289
- ),
290
- );
291
- }
292
-
293
- public function parseNotTestExpression(Twig_Parser $parser, Twig_NodeInterface $node)
294
- {
295
- return new Twig_Node_Expression_Unary_Not($this->parseTestExpression($parser, $node), $parser->getCurrentToken()->getLine());
296
- }
297
-
298
- public function parseTestExpression(Twig_Parser $parser, Twig_NodeInterface $node)
299
- {
300
- $stream = $parser->getStream();
301
- $name = $stream->expect(Twig_Token::NAME_TYPE)->getValue();
302
- $class = $this->getTestNodeClass($parser, $name, $node->getLine());
303
- $arguments = null;
304
- if ($stream->test(Twig_Token::PUNCTUATION_TYPE, '(')) {
305
- $arguments = $parser->getExpressionParser()->parseArguments(true);
306
- }
307
-
308
- return new $class($node, $name, $arguments, $parser->getCurrentToken()->getLine());
309
- }
310
-
311
- protected function getTestNodeClass(Twig_Parser $parser, $name, $line)
312
- {
313
- $env = $parser->getEnvironment();
314
- $testMap = $env->getTests();
315
- $testName = null;
316
- if (isset($testMap[$name])) {
317
- $testName = $name;
318
- } elseif ($parser->getStream()->test(Twig_Token::NAME_TYPE)) {
319
- // try 2-words tests
320
- $name = $name.' '.$parser->getCurrentToken()->getValue();
321
-
322
- if (isset($testMap[$name])) {
323
- $parser->getStream()->next();
324
-
325
- $testName = $name;
326
- }
327
- }
328
-
329
- if (null === $testName) {
330
- $message = sprintf('The test "%s" does not exist', $name);
331
- if ($alternatives = $env->computeAlternatives($name, array_keys($env->getTests()))) {
332
- $message = sprintf('%s. Did you mean "%s"', $message, implode('", "', $alternatives));
333
- }
334
-
335
- throw new Twig_Error_Syntax($message, $line, $parser->getFilename());
336
- }
337
-
338
- if ($testMap[$name] instanceof Twig_SimpleTest) {
339
- return $testMap[$name]->getNodeClass();
340
- }
341
-
342
- return $testMap[$name] instanceof Twig_Test_Node ? $testMap[$name]->getClass() : 'Twig_Node_Expression_Test';
343
- }
344
-
345
- /**
346
- * Returns the name of the extension.
347
- *
348
- * @return string The extension name
349
- */
350
- public function getName()
351
- {
352
- return 'core';
353
- }
354
- }
355
-
356
- /**
357
- * Cycles over a value.
358
- *
359
- * @param ArrayAccess|array $values An array or an ArrayAccess instance
360
- * @param int $position The cycle position
361
- *
362
- * @return string The next value in the cycle
363
- */
364
- function twig_cycle($values, $position)
365
- {
366
- if (!is_array($values) && !$values instanceof ArrayAccess) {
367
- return $values;
368
- }
369
-
370
- return $values[$position % count($values)];
371
- }
372
-
373
- /**
374
- * Returns a random value depending on the supplied parameter type:
375
- * - a random item from a Traversable or array
376
- * - a random character from a string
377
- * - a random integer between 0 and the integer parameter
378
- *
379
- * @param Twig_Environment $env A Twig_Environment instance
380
- * @param Traversable|array|int|string $values The values to pick a random item from
381
- *
382
- * @throws Twig_Error_Runtime When $values is an empty array (does not apply to an empty string which is returned as is).
383
- *
384
- * @return mixed A random value from the given sequence
385
- */
386
- function twig_random(Twig_Environment $env, $values = null)
387
- {
388
- if (null === $values) {
389
- return mt_rand();
390
- }
391
-
392
- if (is_int($values) || is_float($values)) {
393
- return $values < 0 ? mt_rand($values, 0) : mt_rand(0, $values);
394
- }
395
-
396
- if ($values instanceof Traversable) {
397
- $values = iterator_to_array($values);
398
- } elseif (is_string($values)) {
399
- if ('' === $values) {
400
- return '';
401
- }
402
- if (null !== $charset = $env->getCharset()) {
403
- if ('UTF-8' != $charset) {
404
- $values = twig_convert_encoding($values, 'UTF-8', $charset);
405
- }
406
-
407
- // unicode version of str_split()
408
- // split at all positions, but not after the start and not before the end
409
- $values = preg_split('/(?<!^)(?!$)/u', $values);
410
-
411
- if ('UTF-8' != $charset) {
412
- foreach ($values as $i => $value) {
413
- $values[$i] = twig_convert_encoding($value, $charset, 'UTF-8');
414
- }
415
- }
416
- } else {
417
- return $values[mt_rand(0, strlen($values) - 1)];
418
- }
419
- }
420
-
421
- if (!is_array($values)) {
422
- return $values;
423
- }
424
-
425
- if (0 === count($values)) {
426
- throw new Twig_Error_Runtime('The random function cannot pick from an empty array.');
427
- }
428
-
429
- return $values[array_rand($values, 1)];
430
- }
431
-
432
- /**
433
- * Converts a date to the given format.
434
- *
435
- * <pre>
436
- * {{ post.published_at|date("m/d/Y") }}
437
- * </pre>
438
- *
439
- * @param Twig_Environment $env A Twig_Environment instance
440
- * @param DateTime|DateInterval|string $date A date
441
- * @param string $format A format
442
- * @param DateTimeZone|string $timezone A timezone
443
- *
444
- * @return string The formatted date
445
- */
446
- function twig_date_format_filter(Twig_Environment $env, $date, $format = null, $timezone = null)
447
- {
448
- if (null === $format) {
449
- $formats = $env->getExtension('core')->getDateFormat();
450
- $format = $date instanceof DateInterval ? $formats[1] : $formats[0];
451
- }
452
-
453
- if ($date instanceof DateInterval) {
454
- return $date->format($format);
455
- }
456
-
457
- return twig_date_converter($env, $date, $timezone)->format($format);
458
- }
459
-
460
- /**
461
- * Returns a new date object modified
462
- *
463
- * <pre>
464
- * {{ post.published_at|date_modify("-1day")|date("m/d/Y") }}
465
- * </pre>
466
- *
467
- * @param Twig_Environment $env A Twig_Environment instance
468
- * @param DateTime|string $date A date
469
- * @param string $modifier A modifier string
470
- *
471
- * @return DateTime A new date object
472
- */
473
- function twig_date_modify_filter(Twig_Environment $env, $date, $modifier)
474
- {
475
- $date = twig_date_converter($env, $date, false);
476
- $date->modify($modifier);
477
-
478
- return $date;
479
- }
480
-
481
- /**
482
- * Converts an input to a DateTime instance.
483
- *
484
- * <pre>
485
- * {% if date(user.created_at) < date('+2days') %}
486
- * {# do something #}
487
- * {% endif %}
488
- * </pre>
489
- *
490
- * @param Twig_Environment $env A Twig_Environment instance
491
- * @param DateTime|string $date A date
492
- * @param DateTimeZone|string $timezone A timezone
493
- *
494
- * @return DateTime A DateTime instance
495
- */
496
- function twig_date_converter(Twig_Environment $env, $date = null, $timezone = null)
497
- {
498
- // determine the timezone
499
- if (!$timezone) {
500
- $defaultTimezone = $env->getExtension('core')->getTimezone();
501
- } elseif (!$timezone instanceof DateTimeZone) {
502
- $defaultTimezone = new DateTimeZone($timezone);
503
- } else {
504
- $defaultTimezone = $timezone;
505
- }
506
-
507
- // immutable dates
508
- if ($date instanceof DateTimeImmutable) {
509
- return false !== $timezone ? $date->setTimezone($defaultTimezone) : $date;
510
- }
511
-
512
- if ($date instanceof DateTime || $date instanceof DateTimeInterface) {
513
- $date = clone $date;
514
- if (false !== $timezone) {
515
- $date->setTimezone($defaultTimezone);
516
- }
517
-
518
- return $date;
519
- }
520
-
521
- $asString = (string) $date;
522
- if (ctype_digit($asString) || (!empty($asString) && '-' === $asString[0] && ctype_digit(substr($asString, 1)))) {
523
- $date = '@'.$date;
524
- }
525
-
526
- $date = new DateTime($date, $defaultTimezone);
527
- if (false !== $timezone) {
528
- $date->setTimezone($defaultTimezone);
529
- }
530
-
531
- return $date;
532
- }
533
-
534
- /**
535
- * Rounds a number.
536
- *
537
- * @param int|float $value The value to round
538
- * @param int|float $precision The rounding precision
539
- * @param string $method The method to use for rounding
540
- *
541
- * @return int|float The rounded number
542
- */
543
- function twig_round($value, $precision = 0, $method = 'common')
544
- {
545
- if ('common' == $method) {
546
- return round($value, $precision);
547
- }
548
-
549
- if ('ceil' != $method && 'floor' != $method) {
550
- throw new Twig_Error_Runtime('The round filter only supports the "common", "ceil", and "floor" methods.');
551
- }
552
-
553
- return $method($value * pow(10, $precision)) / pow(10, $precision);
554
- }
555
-
556
- /**
557
- * Number format filter.
558
- *
559
- * All of the formatting options can be left null, in that case the defaults will
560
- * be used. Supplying any of the parameters will override the defaults set in the
561
- * environment object.
562
- *
563
- * @param Twig_Environment $env A Twig_Environment instance
564
- * @param mixed $number A float/int/string of the number to format
565
- * @param int $decimal The number of decimal points to display.
566
- * @param string $decimalPoint The character(s) to use for the decimal point.
567
- * @param string $thousandSep The character(s) to use for the thousands separator.
568
- *
569
- * @return string The formatted number
570
- */
571
- function twig_number_format_filter(Twig_Environment $env, $number, $decimal = null, $decimalPoint = null, $thousandSep = null)
572
- {
573
- $defaults = $env->getExtension('core')->getNumberFormat();
574
- if (null === $decimal) {
575
- $decimal = $defaults[0];
576
- }
577
-
578
- if (null === $decimalPoint) {
579
- $decimalPoint = $defaults[1];
580
- }
581
-
582
- if (null === $thousandSep) {
583
- $thousandSep = $defaults[2];
584
- }
585
-
586
- return number_format((float) $number, $decimal, $decimalPoint, $thousandSep);
587
- }
588
-
589
- /**
590
- * URL encodes (RFC 3986) a string as a path segment or an array as a query string.
591
- *
592
- * @param string|array $url A URL or an array of query parameters
593
- *
594
- * @return string The URL encoded value
595
- */
596
- function twig_urlencode_filter($url)
597
- {
598
- if (is_array($url)) {
599
- if (defined('PHP_QUERY_RFC3986')) {
600
- return http_build_query($url, '', '&', PHP_QUERY_RFC3986);
601
- }
602
-
603
- return http_build_query($url, '', '&');
604
- }
605
-
606
- return rawurlencode($url);
607
- }
608
-
609
- if (version_compare(PHP_VERSION, '5.3.0', '<')) {
610
- /**
611
- * JSON encodes a variable.
612
- *
613
- * @param mixed $value The value to encode.
614
- * @param int $options Not used on PHP 5.2.x
615
- *
616
- * @return mixed The JSON encoded value
617
- */
618
- function twig_jsonencode_filter($value, $options = 0)
619
- {
620
- if ($value instanceof Twig_Markup) {
621
- $value = (string) $value;
622
- } elseif (is_array($value)) {
623
- array_walk_recursive($value, '_twig_markup2string');
624
- }
625
-
626
- return json_encode($value);
627
- }
628
- } else {
629
- /**
630
- * JSON encodes a variable.
631
- *
632
- * @param mixed $value The value to encode.
633
- * @param int $options Bitmask consisting of JSON_HEX_QUOT, JSON_HEX_TAG, JSON_HEX_AMP, JSON_HEX_APOS, JSON_NUMERIC_CHECK, JSON_PRETTY_PRINT, JSON_UNESCAPED_SLASHES, JSON_FORCE_OBJECT
634
- *
635
- * @return mixed The JSON encoded value
636
- */
637
- function twig_jsonencode_filter($value, $options = 0)
638
- {
639
- if ($value instanceof Twig_Markup) {
640
- $value = (string) $value;
641
- } elseif (is_array($value)) {
642
- array_walk_recursive($value, '_twig_markup2string');
643
- }
644
-
645
- return json_encode($value, $options);
646
- }
647
- }
648
-
649
- function _twig_markup2string(&$value)
650
- {
651
- if ($value instanceof Twig_Markup) {
652
- $value = (string) $value;
653
- }
654
- }
655
-
656
- /**
657
- * Merges an array with another one.
658
- *
659
- * <pre>
660
- * {% set items = { 'apple': 'fruit', 'orange': 'fruit' } %}
661
- *
662
- * {% set items = items|merge({ 'peugeot': 'car' }) %}
663
- *
664
- * {# items now contains { 'apple': 'fruit', 'orange': 'fruit', 'peugeot': 'car' } #}
665
- * </pre>
666
- *
667
- * @param array $arr1 An array
668
- * @param array $arr2 An array
669
- *
670
- * @return array The merged array
671
- */
672
- function twig_array_merge($arr1, $arr2)
673
- {
674
- if (!is_array($arr1) || !is_array($arr2)) {
675
- throw new Twig_Error_Runtime('The merge filter only works with arrays or hashes.');
676
- }
677
-
678
- return array_merge($arr1, $arr2);
679
- }
680
-
681
- /**
682
- * Slices a variable.
683
- *
684
- * @param Twig_Environment $env A Twig_Environment instance
685
- * @param mixed $item A variable
686
- * @param int $start Start of the slice
687
- * @param int $length Size of the slice
688
- * @param bool $preserveKeys Whether to preserve key or not (when the input is an array)
689
- *
690
- * @return mixed The sliced variable
691
- */
692
- function twig_slice(Twig_Environment $env, $item, $start, $length = null, $preserveKeys = false)
693
- {
694
- if ($item instanceof Traversable) {
695
- $item = iterator_to_array($item, false);
696
- }
697
-
698
- if (is_array($item)) {
699
- return array_slice($item, $start, $length, $preserveKeys);
700
- }
701
-
702
- $item = (string) $item;
703
-
704
- if (function_exists('mb_get_info') && null !== $charset = $env->getCharset()) {
705
- return mb_substr($item, $start, null === $length ? mb_strlen($item, $charset) - $start : $length, $charset);
706
- }
707
-
708
- return null === $length ? substr($item, $start) : substr($item, $start, $length);
709
- }
710
-
711
- /**
712
- * Returns the first element of the item.
713
- *
714
- * @param Twig_Environment $env A Twig_Environment instance
715
- * @param mixed $item A variable
716
- *
717
- * @return mixed The first element of the item
718
- */
719
- function twig_first(Twig_Environment $env, $item)
720
- {
721
- $elements = twig_slice($env, $item, 0, 1, false);
722
-
723
- return is_string($elements) ? $elements : current($elements);
724
- }
725
-
726
- /**
727
- * Returns the last element of the item.
728
- *
729
- * @param Twig_Environment $env A Twig_Environment instance
730
- * @param mixed $item A variable
731
- *
732
- * @return mixed The last element of the item
733
- */
734
- function twig_last(Twig_Environment $env, $item)
735
- {
736
- $elements = twig_slice($env, $item, -1, 1, false);
737
-
738
- return is_string($elements) ? $elements : current($elements);
739
- }
740
-
741
- /**
742
- * Joins the values to a string.
743
- *
744
- * The separator between elements is an empty string per default, you can define it with the optional parameter.
745
- *
746
- * <pre>
747
- * {{ [1, 2, 3]|join('|') }}
748
- * {# returns 1|2|3 #}
749
- *
750
- * {{ [1, 2, 3]|join }}
751
- * {# returns 123 #}
752
- * </pre>
753
- *
754
- * @param array $value An array
755
- * @param string $glue The separator
756
- *
757
- * @return string The concatenated string
758
- */
759
- function twig_join_filter($value, $glue = '')
760
- {
761
- if ($value instanceof Traversable) {
762
- $value = iterator_to_array($value, false);
763
- }
764
-
765
- return implode($glue, (array) $value);
766
- }
767
-
768
- /**
769
- * Splits the string into an array.
770
- *
771
- * <pre>
772
- * {{ "one,two,three"|split(',') }}
773
- * {# returns [one, two, three] #}
774
- *
775
- * {{ "one,two,three,four,five"|split(',', 3) }}
776
- * {# returns [one, two, "three,four,five"] #}
777
- *
778
- * {{ "123"|split('') }}
779
- * {# returns [1, 2, 3] #}
780
- *
781
- * {{ "aabbcc"|split('', 2) }}
782
- * {# returns [aa, bb, cc] #}
783
- * </pre>
784
- *
785
- * @param string $value A string
786
- * @param string $delimiter The delimiter
787
- * @param int $limit The limit
788
- *
789
- * @return array The split string as an array
790
- */
791
- function twig_split_filter($value, $delimiter, $limit = null)
792
- {
793
- if (empty($delimiter)) {
794
- return str_split($value, null === $limit ? 1 : $limit);
795
- }
796
-
797
- return null === $limit ? explode($delimiter, $value) : explode($delimiter, $value, $limit);
798
- }
799
-
800
- // The '_default' filter is used internally to avoid using the ternary operator
801
- // which costs a lot for big contexts (before PHP 5.4). So, on average,
802
- // a function call is cheaper.
803
- function _twig_default_filter($value, $default = '')
804
- {
805
- if (twig_test_empty($value)) {
806
- return $default;
807
- }
808
-
809
- return $value;
810
- }
811
-
812
- /**
813
- * Returns the keys for the given array.
814
- *
815
- * It is useful when you want to iterate over the keys of an array:
816
- *
817
- * <pre>
818
- * {% for key in array|keys %}
819
- * {# ... #}
820
- * {% endfor %}
821
- * </pre>
822
- *
823
- * @param array $array An array
824
- *
825
- * @return array The keys
826
- */
827
- function twig_get_array_keys_filter($array)
828
- {
829
- if (is_object($array) && $array instanceof Traversable) {
830
- return array_keys(iterator_to_array($array));
831
- }
832
-
833
- if (!is_array($array)) {
834
- return array();
835
- }
836
-
837
- return array_keys($array);
838
- }
839
-
840
- /**
841
- * Reverses a variable.
842
- *
843
- * @param Twig_Environment $env A Twig_Environment instance
844
- * @param array|Traversable|string $item An array, a Traversable instance, or a string
845
- * @param bool $preserveKeys Whether to preserve key or not
846
- *
847
- * @return mixed The reversed input
848
- */
849
- function twig_reverse_filter(Twig_Environment $env, $item, $preserveKeys = false)
850
- {
851
- if (is_object($item) && $item instanceof Traversable) {
852
- return array_reverse(iterator_to_array($item), $preserveKeys);
853
- }
854
-
855
- if (is_array($item)) {
856
- return array_reverse($item, $preserveKeys);
857
- }
858
-
859
- if (null !== $charset = $env->getCharset()) {
860
- $string = (string) $item;
861
-
862
- if ('UTF-8' != $charset) {
863
- $item = twig_convert_encoding($string, 'UTF-8', $charset);
864
- }
865
-
866
- preg_match_all('/./us', $item, $matches);
867
-
868
- $string = implode('', array_reverse($matches[0]));
869
-
870
- if ('UTF-8' != $charset) {
871
- $string = twig_convert_encoding($string, $charset, 'UTF-8');
872
- }
873
-
874
- return $string;
875
- }
876
-
877
- return strrev((string) $item);
878
- }
879
-
880
- /**
881
- * Sorts an array.
882
- *
883
- * @param array $array An array
884
- */
885
- function twig_sort_filter($array)
886
- {
887
- asort($array);
888
-
889
- return $array;
890
- }
891
-
892
- /* used internally */
893
- function twig_in_filter($value, $compare)
894
- {
895
- if (is_array($compare)) {
896
- return in_array($value, $compare, is_object($value));
897
- } elseif (is_string($compare)) {
898
- if (!strlen($value)) {
899
- return empty($compare);
900
- }
901
-
902
- return false !== strpos($compare, (string) $value);
903
- } elseif ($compare instanceof Traversable) {
904
- return in_array($value, iterator_to_array($compare, false), is_object($value));
905
- }
906
-
907
- return false;
908
- }
909
-
910
- /**
911
- * Escapes a string.
912
- *
913
- * @param Twig_Environment $env A Twig_Environment instance
914
- * @param string $string The value to be escaped
915
- * @param string $strategy The escaping strategy
916
- * @param string $charset The charset
917
- * @param bool $autoescape Whether the function is called by the auto-escaping feature (true) or by the developer (false)
918
- */
919
- function twig_escape_filter(Twig_Environment $env, $string, $strategy = 'html', $charset = null, $autoescape = false)
920
- {
921
- if ($autoescape && $string instanceof Twig_Markup) {
922
- return $string;
923
- }
924
-
925
- if (!is_string($string)) {
926
- if (is_object($string) && method_exists($string, '__toString')) {
927
- $string = (string) $string;
928
- } else {
929
- return $string;
930
- }
931
- }
932
-
933
- if (null === $charset) {
934
- $charset = $env->getCharset();
935
- }
936
-
937
- switch ($strategy) {
938
- case 'html':
939
- // see http://php.net/htmlspecialchars
940
-
941
- // Using a static variable to avoid initializing the array
942
- // each time the function is called. Moving the declaration on the
943
- // top of the function slow downs other escaping strategies.
944
- static $htmlspecialcharsCharsets;
945
-
946
- if (null === $htmlspecialcharsCharsets) {
947
- if ('hiphop' === substr(PHP_VERSION, -6)) {
948
- $htmlspecialcharsCharsets = array('utf-8' => true, 'UTF-8' => true);
949
- } else {
950
- $htmlspecialcharsCharsets = array(
951
- 'ISO-8859-1' => true, 'ISO8859-1' => true,
952
- 'ISO-8859-15' => true, 'ISO8859-15' => true,
953
- 'utf-8' => true, 'UTF-8' => true,
954
- 'CP866' => true, 'IBM866' => true, '866' => true,
955
- 'CP1251' => true, 'WINDOWS-1251' => true, 'WIN-1251' => true,
956
- '1251' => true,
957
- 'CP1252' => true, 'WINDOWS-1252' => true, '1252' => true,
958
- 'KOI8-R' => true, 'KOI8-RU' => true, 'KOI8R' => true,
959
- 'BIG5' => true, '950' => true,
960
- 'GB2312' => true, '936' => true,
961
- 'BIG5-HKSCS' => true,
962
- 'SHIFT_JIS' => true, 'SJIS' => true, '932' => true,
963
- 'EUC-JP' => true, 'EUCJP' => true,
964
- 'ISO8859-5' => true, 'ISO-8859-5' => true, 'MACROMAN' => true,
965
- );
966
- }
967
- }
968
-
969
- if (isset($htmlspecialcharsCharsets[$charset])) {
970
- return htmlspecialchars($string, ENT_QUOTES | ENT_SUBSTITUTE, $charset);
971
- }
972
-
973
- if (isset($htmlspecialcharsCharsets[strtoupper($charset)])) {
974
- // cache the lowercase variant for future iterations
975
- $htmlspecialcharsCharsets[$charset] = true;
976
-
977
- return htmlspecialchars($string, ENT_QUOTES | ENT_SUBSTITUTE, $charset);
978
- }
979
-
980
- $string = twig_convert_encoding($string, 'UTF-8', $charset);
981
- $string = htmlspecialchars($string, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8');
982
-
983
- return twig_convert_encoding($string, $charset, 'UTF-8');
984
-
985
- case 'js':
986
- // escape all non-alphanumeric characters
987
- // into their \xHH or \uHHHH representations
988
- if ('UTF-8' != $charset) {
989
- $string = twig_convert_encoding($string, 'UTF-8', $charset);
990
- }
991
-
992
- if (0 == strlen($string) ? false : (1 == preg_match('/^./su', $string) ? false : true)) {
993
- throw new Twig_Error_Runtime('The string to escape is not a valid UTF-8 string.');
994
- }
995
-
996
- $string = preg_replace_callback('#[^a-zA-Z0-9,\._]#Su', '_twig_escape_js_callback', $string);
997
-
998
- if ('UTF-8' != $charset) {
999
- $string = twig_convert_encoding($string, $charset, 'UTF-8');
1000
- }
1001
-
1002
- return $string;
1003
-
1004
- case 'css':
1005
- if ('UTF-8' != $charset) {
1006
- $string = twig_convert_encoding($string, 'UTF-8', $charset);
1007
- }
1008
-
1009
- if (0 == strlen($string) ? false : (1 == preg_match('/^./su', $string) ? false : true)) {
1010
- throw new Twig_Error_Runtime('The string to escape is not a valid UTF-8 string.');
1011
- }
1012
-
1013
- $string = preg_replace_callback('#[^a-zA-Z0-9]#Su', '_twig_escape_css_callback', $string);
1014
-
1015
- if ('UTF-8' != $charset) {
1016
- $string = twig_convert_encoding($string, $charset, 'UTF-8');
1017
- }
1018
-
1019
- return $string;
1020
-
1021
- case 'html_attr':
1022
- if ('UTF-8' != $charset) {
1023
- $string = twig_convert_encoding($string, 'UTF-8', $charset);
1024
- }
1025
-
1026
- if (0 == strlen($string) ? false : (1 == preg_match('/^./su', $string) ? false : true)) {
1027
- throw new Twig_Error_Runtime('The string to escape is not a valid UTF-8 string.');
1028
- }
1029
-
1030
- $string = preg_replace_callback('#[^a-zA-Z0-9,\.\-_]#Su', '_twig_escape_html_attr_callback', $string);
1031
-
1032
- if ('UTF-8' != $charset) {
1033
- $string = twig_convert_encoding($string, $charset, 'UTF-8');
1034
- }
1035
-
1036
- return $string;
1037
-
1038
- case 'url':
1039
- // hackish test to avoid version_compare that is much slower, this works unless PHP releases a 5.10.*
1040
- // at that point however PHP 5.2.* support can be removed
1041
- if (PHP_VERSION < '5.3.0') {
1042
- return str_replace('%7E', '~', rawurlencode($string));
1043
- }
1044
-
1045
- return rawurlencode($string);
1046
-
1047
- default:
1048
- static $escapers;
1049
-
1050
- if (null === $escapers) {
1051
- $escapers = $env->getExtension('core')->getEscapers();
1052
- }
1053
-
1054
- if (isset($escapers[$strategy])) {
1055
- return call_user_func($escapers[$strategy], $env, $string, $charset);
1056
- }
1057
-
1058
- $validStrategies = implode(', ', array_merge(array('html', 'js', 'url', 'css', 'html_attr'), array_keys($escapers)));
1059
-
1060
- throw new Twig_Error_Runtime(sprintf('Invalid escaping strategy "%s" (valid ones: %s).', $strategy, $validStrategies));
1061
- }
1062
- }
1063
-
1064
- /* used internally */
1065
- function twig_escape_filter_is_safe(Twig_Node $filterArgs)
1066
- {
1067
- foreach ($filterArgs as $arg) {
1068
- if ($arg instanceof Twig_Node_Expression_Constant) {
1069
- return array($arg->getAttribute('value'));
1070
- }
1071
-
1072
- return array();
1073
- }
1074
-
1075
- return array('html');
1076
- }
1077
-
1078
- if (function_exists('mb_convert_encoding')) {
1079
- function twig_convert_encoding($string, $to, $from)
1080
- {
1081
- return mb_convert_encoding($string, $to, $from);
1082
- }
1083
- } elseif (function_exists('iconv')) {
1084
- function twig_convert_encoding($string, $to, $from)
1085
- {
1086
- return iconv($from, $to, $string);
1087
- }
1088
- } else {
1089
- function twig_convert_encoding($string, $to, $from)
1090
- {
1091
- throw new Twig_Error_Runtime('No suitable convert encoding function (use UTF-8 as your encoding or install the iconv or mbstring extension).');
1092
- }
1093
- }
1094
-
1095
- function _twig_escape_js_callback($matches)
1096
- {
1097
- $char = $matches[0];
1098
-
1099
- // \xHH
1100
- if (!isset($char[1])) {
1101
- return '\\x'.strtoupper(substr('00'.bin2hex($char), -2));
1102
- }
1103
-
1104
- // \uHHHH
1105
- $char = twig_convert_encoding($char, 'UTF-16BE', 'UTF-8');
1106
-
1107
- return '\\u'.strtoupper(substr('0000'.bin2hex($char), -4));
1108
- }
1109
-
1110
- function _twig_escape_css_callback($matches)
1111
- {
1112
- $char = $matches[0];
1113
-
1114
- // \xHH
1115
- if (!isset($char[1])) {
1116
- $hex = ltrim(strtoupper(bin2hex($char)), '0');
1117
- if (0 === strlen($hex)) {
1118
- $hex = '0';
1119
- }
1120
-
1121
- return '\\'.$hex.' ';
1122
- }
1123
-
1124
- // \uHHHH
1125
- $char = twig_convert_encoding($char, 'UTF-16BE', 'UTF-8');
1126
-
1127
- return '\\'.ltrim(strtoupper(bin2hex($char)), '0').' ';
1128
- }
1129
-
1130
- /**
1131
- * This function is adapted from code coming from Zend Framework.
1132
- *
1133
- * @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
1134
- * @license http://framework.zend.com/license/new-bsd New BSD License
1135
- */
1136
- function _twig_escape_html_attr_callback($matches)
1137
- {
1138
- /*
1139
- * While HTML supports far more named entities, the lowest common denominator
1140
- * has become HTML5's XML Serialisation which is restricted to the those named
1141
- * entities that XML supports. Using HTML entities would result in this error:
1142
- * XML Parsing Error: undefined entity
1143
- */
1144
- static $entityMap = array(
1145
- 34 => 'quot', /* quotation mark */
1146
- 38 => 'amp', /* ampersand */
1147
- 60 => 'lt', /* less-than sign */
1148
- 62 => 'gt', /* greater-than sign */
1149
- );
1150
-
1151
- $chr = $matches[0];
1152
- $ord = ord($chr);
1153
-
1154
- /**
1155
- * The following replaces characters undefined in HTML with the
1156
- * hex entity for the Unicode replacement character.
1157
- */
1158
- if (($ord <= 0x1f && $chr != "\t" && $chr != "\n" && $chr != "\r") || ($ord >= 0x7f && $ord <= 0x9f)) {
1159
- return '&#xFFFD;';
1160
- }
1161
-
1162
- /**
1163
- * Check if the current character to escape has a name entity we should
1164
- * replace it with while grabbing the hex value of the character.
1165
- */
1166
- if (strlen($chr) == 1) {
1167
- $hex = strtoupper(substr('00'.bin2hex($chr), -2));
1168
- } else {
1169
- $chr = twig_convert_encoding($chr, 'UTF-16BE', 'UTF-8');
1170
- $hex = strtoupper(substr('0000'.bin2hex($chr), -4));
1171
- }
1172
-
1173
- $int = hexdec($hex);
1174
- if (array_key_exists($int, $entityMap)) {
1175
- return sprintf('&%s;', $entityMap[$int]);
1176
- }
1177
-
1178
- /**
1179
- * Per OWASP recommendations, we'll use hex entities for any other
1180
- * characters where a named entity does not exist.
1181
- */
1182
-
1183
- return sprintf('&#x%s;', $hex);
1184
- }
1185
-
1186
- // add multibyte extensions if possible
1187
- if (function_exists('mb_get_info')) {
1188
- /**
1189
- * Returns the length of a variable.
1190
- *
1191
- * @param Twig_Environment $env A Twig_Environment instance
1192
- * @param mixed $thing A variable
1193
- *
1194
- * @return int The length of the value
1195
- */
1196
- function twig_length_filter(Twig_Environment $env, $thing)
1197
- {
1198
- return is_scalar($thing) ? mb_strlen($thing, $env->getCharset()) : count($thing);
1199
- }
1200
-
1201
- /**
1202
- * Converts a string to uppercase.
1203
- *
1204
- * @param Twig_Environment $env A Twig_Environment instance
1205
- * @param string $string A string
1206
- *
1207
- * @return string The uppercased string
1208
- */
1209
- function twig_upper_filter(Twig_Environment $env, $string)
1210
- {
1211
- if (null !== ($charset = $env->getCharset())) {
1212
- return mb_strtoupper($string, $charset);
1213
- }
1214
-
1215
- return strtoupper($string);
1216
- }
1217
-
1218
- /**
1219
- * Converts a string to lowercase.
1220
- *
1221
- * @param Twig_Environment $env A Twig_Environment instance
1222
- * @param string $string A string
1223
- *
1224
- * @return string The lowercased string
1225
- */
1226
- function twig_lower_filter(Twig_Environment $env, $string)
1227
- {
1228
- if (null !== ($charset = $env->getCharset())) {
1229
- return mb_strtolower($string, $charset);
1230
- }
1231
-
1232
- return strtolower($string);
1233
- }
1234
-
1235
- /**
1236
- * Returns a titlecased string.
1237
- *
1238
- * @param Twig_Environment $env A Twig_Environment instance
1239
- * @param string $string A string
1240
- *
1241
- * @return string The titlecased string
1242
- */
1243
- function twig_title_string_filter(Twig_Environment $env, $string)
1244
- {
1245
- if (null !== ($charset = $env->getCharset())) {
1246
- return mb_convert_case($string, MB_CASE_TITLE, $charset);
1247
- }
1248
-
1249
- return ucwords(strtolower($string));
1250
- }
1251
-
1252
- /**
1253
- * Returns a capitalized string.
1254
- *
1255
- * @param Twig_Environment $env A Twig_Environment instance
1256
- * @param string $string A string
1257
- *
1258
- * @return string The capitalized string
1259
- */
1260
- function twig_capitalize_string_filter(Twig_Environment $env, $string)
1261
- {
1262
- if (null !== ($charset = $env->getCharset())) {
1263
- return mb_strtoupper(mb_substr($string, 0, 1, $charset), $charset).
1264
- mb_strtolower(mb_substr($string, 1, mb_strlen($string, $charset), $charset), $charset);
1265
- }
1266
-
1267
- return ucfirst(strtolower($string));
1268
- }
1269
- }
1270
- // and byte fallback
1271
- else {
1272
- /**
1273
- * Returns the length of a variable.
1274
- *
1275
- * @param Twig_Environment $env A Twig_Environment instance
1276
- * @param mixed $thing A variable
1277
- *
1278
- * @return int The length of the value
1279
- */
1280
- function twig_length_filter(Twig_Environment $env, $thing)
1281
- {
1282
- return is_scalar($thing) ? strlen($thing) : count($thing);
1283
- }
1284
-
1285
- /**
1286
- * Returns a titlecased string.
1287
- *
1288
- * @param Twig_Environment $env A Twig_Environment instance
1289
- * @param string $string A string
1290
- *
1291
- * @return string The titlecased string
1292
- */
1293
- function twig_title_string_filter(Twig_Environment $env, $string)
1294
- {
1295
- return ucwords(strtolower($string));
1296
- }
1297
-
1298
- /**
1299
- * Returns a capitalized string.
1300
- *
1301
- * @param Twig_Environment $env A Twig_Environment instance
1302
- * @param string $string A string
1303
- *
1304
- * @return string The capitalized string
1305
- */
1306
- function twig_capitalize_string_filter(Twig_Environment $env, $string)
1307
- {
1308
- return ucfirst(strtolower($string));
1309
- }
1310
- }
1311
-
1312
- /* used internally */
1313
- function twig_ensure_traversable($seq)
1314
- {
1315
- if ($seq instanceof Traversable || is_array($seq)) {
1316
- return $seq;
1317
- }
1318
-
1319
- return array();
1320
- }
1321
-
1322
- /**
1323
- * Checks if a variable is empty.
1324
- *
1325
- * <pre>
1326
- * {# evaluates to true if the foo variable is null, false, or the empty string #}
1327
- * {% if foo is empty %}
1328
- * {# ... #}
1329
- * {% endif %}
1330
- * </pre>
1331
- *
1332
- * @param mixed $value A variable
1333
- *
1334
- * @return bool true if the value is empty, false otherwise
1335
- */
1336
- function twig_test_empty($value)
1337
- {
1338
- if ($value instanceof Countable) {
1339
- return 0 == count($value);
1340
- }
1341
-
1342
- return '' === $value || false === $value || null === $value || array() === $value;
1343
- }
1344
-
1345
- /**
1346
- * Checks if a variable is traversable.
1347
- *
1348
- * <pre>
1349
- * {# evaluates to true if the foo variable is an array or a traversable object #}
1350
- * {% if foo is traversable %}
1351
- * {# ... #}
1352
- * {% endif %}
1353
- * </pre>
1354
- *
1355
- * @param mixed $value A variable
1356
- *
1357
- * @return bool true if the value is traversable
1358
- */
1359
- function twig_test_iterable($value)
1360
- {
1361
- return $value instanceof Traversable || is_array($value);
1362
- }
1363
-
1364
- /**
1365
- * Renders a template.
1366
- *
1367
- * @param string|array $template The template to render or an array of templates to try consecutively
1368
- * @param array $variables The variables to pass to the template
1369
- * @param bool $with_context Whether to pass the current context variables or not
1370
- * @param bool $ignore_missing Whether to ignore missing templates or not
1371
- * @param bool $sandboxed Whether to sandbox the template or not
1372
- *
1373
- * @return string The rendered template
1374
- */
1375
- function twig_include(Twig_Environment $env, $context, $template, $variables = array(), $withContext = true, $ignoreMissing = false, $sandboxed = false)
1376
- {
1377
- $alreadySandboxed = false;
1378
- $sandbox = null;
1379
- if ($withContext) {
1380
- $variables = array_merge($context, $variables);
1381
- }
1382
-
1383
- if ($isSandboxed = $sandboxed && $env->hasExtension('sandbox')) {
1384
- $sandbox = $env->getExtension('sandbox');
1385
- if (!$alreadySandboxed = $sandbox->isSandboxed()) {
1386
- $sandbox->enableSandbox();
1387
- }
1388
- }
1389
-
1390
- try {
1391
- return $env->resolveTemplate($template)->render($variables);
1392
- } catch (Twig_Error_Loader $e) {
1393
- if (!$ignoreMissing) {
1394
- throw $e;
1395
- }
1396
- }
1397
-
1398
- if ($isSandboxed && !$alreadySandboxed) {
1399
- $sandbox->disableSandbox();
1400
- }
1401
- }
1402
-
1403
- /**
1404
- * Returns a template content without rendering it.
1405
- *
1406
- * @param string $name The template name
1407
- *
1408
- * @return string The template source
1409
- */
1410
- function twig_source(Twig_Environment $env, $name)
1411
- {
1412
- return $env->getLoader()->getSource($name);
1413
- }
1414
-
1415
- /**
1416
- * Provides the ability to get constants from instances as well as class/global constants.
1417
- *
1418
- * @param string $constant The name of the constant
1419
- * @param null|object $object The object to get the constant from
1420
- *
1421
- * @return string
1422
- */
1423
- function twig_constant($constant, $object = null)
1424
- {
1425
- if (null !== $object) {
1426
- $constant = get_class($object).'::'.$constant;
1427
- }
1428
-
1429
- return constant($constant);
1430
- }
1431
-
1432
- /**
1433
- * Batches item.
1434
- *
1435
- * @param array $items An array of items
1436
- * @param int $size The size of the batch
1437
- * @param mixed $fill A value used to fill missing items
1438
- *
1439
- * @return array
1440
- */
1441
- function twig_array_batch($items, $size, $fill = null)
1442
- {
1443
- if ($items instanceof Traversable) {
1444
- $items = iterator_to_array($items, false);
1445
- }
1446
-
1447
- $size = ceil($size);
1448
-
1449
- $result = array_chunk($items, $size, true);
1450
-
1451
- if (null !== $fill) {
1452
- $last = count($result) - 1;
1453
- if ($fillCount = $size - count($result[$last])) {
1454
- $result[$last] = array_merge(
1455
- $result[$last],
1456
- array_fill(0, $fillCount, $fill)
1457
- );
1458
- }
1459
- }
1460
-
1461
- return $result;
1462
- }
1
+ <?php
2
+
3
+ if (!defined('ENT_SUBSTITUTE')) {
4
+ // use 0 as hhvm does not support several flags yet
5
+ define('ENT_SUBSTITUTE', 0);
6
+ }
7
+
8
+ /*
9
+ * This file is part of Twig.
10
+ *
11
+ * (c) 2009 Fabien Potencier
12
+ *
13
+ * For the full copyright and license information, please view the LICENSE
14
+ * file that was distributed with this source code.
15
+ */
16
+ class Twig_Extension_Core extends Twig_Extension
17
+ {
18
+ protected $dateFormats = array('F j, Y H:i', '%d days');
19
+ protected $numberFormat = array(0, '.', ',');
20
+ protected $timezone = null;
21
+ protected $escapers = array();
22
+
23
+ /**
24
+ * Defines a new escaper to be used via the escape filter.
25
+ *
26
+ * @param string $strategy The strategy name that should be used as a strategy in the escape call
27
+ * @param callable $callable A valid PHP callable
28
+ */
29
+ public function setEscaper($strategy, $callable)
30
+ {
31
+ $this->escapers[$strategy] = $callable;
32
+ }
33
+
34
+ /**
35
+ * Gets all defined escapers.
36
+ *
37
+ * @return array An array of escapers
38
+ */
39
+ public function getEscapers()
40
+ {
41
+ return $this->escapers;
42
+ }
43
+
44
+ /**
45
+ * Sets the default format to be used by the date filter.
46
+ *
47
+ * @param string $format The default date format string
48
+ * @param string $dateIntervalFormat The default date interval format string
49
+ */
50
+ public function setDateFormat($format = null, $dateIntervalFormat = null)
51
+ {
52
+ if (null !== $format) {
53
+ $this->dateFormats[0] = $format;
54
+ }
55
+
56
+ if (null !== $dateIntervalFormat) {
57
+ $this->dateFormats[1] = $dateIntervalFormat;
58
+ }
59
+ }
60
+
61
+ /**
62
+ * Gets the default format to be used by the date filter.
63
+ *
64
+ * @return array The default date format string and the default date interval format string
65
+ */
66
+ public function getDateFormat()
67
+ {
68
+ return $this->dateFormats;
69
+ }
70
+
71
+ /**
72
+ * Sets the default timezone to be used by the date filter.
73
+ *
74
+ * @param DateTimeZone|string $timezone The default timezone string or a DateTimeZone object
75
+ */
76
+ public function setTimezone($timezone)
77
+ {
78
+ $this->timezone = $timezone instanceof DateTimeZone ? $timezone : new DateTimeZone($timezone);
79
+ }
80
+
81
+ /**
82
+ * Gets the default timezone to be used by the date filter.
83
+ *
84
+ * @return DateTimeZone The default timezone currently in use
85
+ */
86
+ public function getTimezone()
87
+ {
88
+ if (null === $this->timezone) {
89
+ $this->timezone = new DateTimeZone(date_default_timezone_get());
90
+ }
91
+
92
+ return $this->timezone;
93
+ }
94
+
95
+ /**
96
+ * Sets the default format to be used by the number_format filter.
97
+ *
98
+ * @param int $decimal The number of decimal places to use.
99
+ * @param string $decimalPoint The character(s) to use for the decimal point.
100
+ * @param string $thousandSep The character(s) to use for the thousands separator.
101
+ */
102
+ public function setNumberFormat($decimal, $decimalPoint, $thousandSep)
103
+ {
104
+ $this->numberFormat = array($decimal, $decimalPoint, $thousandSep);
105
+ }
106
+
107
+ /**
108
+ * Get the default format used by the number_format filter.
109
+ *
110
+ * @return array The arguments for number_format()
111
+ */
112
+ public function getNumberFormat()
113
+ {
114
+ return $this->numberFormat;
115
+ }
116
+
117
+ /**
118
+ * Returns the token parser instance to add to the existing list.
119
+ *
120
+ * @return Twig_TokenParser[] An array of Twig_TokenParser instances
121
+ */
122
+ public function getTokenParsers()
123
+ {
124
+ return array(
125
+ new Twig_TokenParser_For(),
126
+ new Twig_TokenParser_If(),
127
+ new Twig_TokenParser_Extends(),
128
+ new Twig_TokenParser_Include(),
129
+ new Twig_TokenParser_Block(),
130
+ new Twig_TokenParser_Use(),
131
+ new Twig_TokenParser_Filter(),
132
+ new Twig_TokenParser_Macro(),
133
+ new Twig_TokenParser_Import(),
134
+ new Twig_TokenParser_From(),
135
+ new Twig_TokenParser_Set(),
136
+ new Twig_TokenParser_Spaceless(),
137
+ new Twig_TokenParser_Flush(),
138
+ new Twig_TokenParser_Do(),
139
+ new Twig_TokenParser_Embed(),
140
+ );
141
+ }
142
+
143
+ /**
144
+ * Returns a list of filters to add to the existing list.
145
+ *
146
+ * @return array An array of filters
147
+ */
148
+ public function getFilters()
149
+ {
150
+ $filters = array(
151
+ // formatting filters
152
+ new Twig_SimpleFilter('date', 'twig_date_format_filter', array('needs_environment' => true)),
153
+ new Twig_SimpleFilter('date_modify', 'twig_date_modify_filter', array('needs_environment' => true)),
154
+ new Twig_SimpleFilter('format', 'sprintf'),
155
+ new Twig_SimpleFilter('replace', 'strtr'),
156
+ new Twig_SimpleFilter('number_format', 'twig_number_format_filter', array('needs_environment' => true)),
157
+ new Twig_SimpleFilter('abs', 'abs'),
158
+ new Twig_SimpleFilter('round', 'twig_round'),
159
+
160
+ // encoding
161
+ new Twig_SimpleFilter('url_encode', 'twig_urlencode_filter'),
162
+ new Twig_SimpleFilter('json_encode', 'twig_jsonencode_filter'),
163
+ new Twig_SimpleFilter('convert_encoding', 'twig_convert_encoding'),
164
+
165
+ // string filters
166
+ new Twig_SimpleFilter('title', 'twig_title_string_filter', array('needs_environment' => true)),
167
+ new Twig_SimpleFilter('capitalize', 'twig_capitalize_string_filter', array('needs_environment' => true)),
168
+ new Twig_SimpleFilter('upper', 'strtoupper'),
169
+ new Twig_SimpleFilter('lower', 'strtolower'),
170
+ new Twig_SimpleFilter('striptags', 'strip_tags'),
171
+ new Twig_SimpleFilter('trim', 'trim'),
172
+ new Twig_SimpleFilter('nl2br', 'nl2br', array('pre_escape' => 'html', 'is_safe' => array('html'))),
173
+
174
+ // array helpers
175
+ new Twig_SimpleFilter('join', 'twig_join_filter'),
176
+ new Twig_SimpleFilter('split', 'twig_split_filter'),
177
+ new Twig_SimpleFilter('sort', 'twig_sort_filter'),
178
+ new Twig_SimpleFilter('merge', 'twig_array_merge'),
179
+ new Twig_SimpleFilter('batch', 'twig_array_batch'),
180
+
181
+ // string/array filters
182
+ new Twig_SimpleFilter('reverse', 'twig_reverse_filter', array('needs_environment' => true)),
183
+ new Twig_SimpleFilter('length', 'twig_length_filter', array('needs_environment' => true)),
184
+ new Twig_SimpleFilter('slice', 'twig_slice', array('needs_environment' => true)),
185
+ new Twig_SimpleFilter('first', 'twig_first', array('needs_environment' => true)),
186
+ new Twig_SimpleFilter('last', 'twig_last', array('needs_environment' => true)),
187
+
188
+ // iteration and runtime
189
+ new Twig_SimpleFilter('default', '_twig_default_filter', array('node_class' => 'Twig_Node_Expression_Filter_Default')),
190
+ new Twig_SimpleFilter('keys', 'twig_get_array_keys_filter'),
191
+
192
+ // escaping
193
+ new Twig_SimpleFilter('escape', 'twig_escape_filter', array('needs_environment' => true, 'is_safe_callback' => 'twig_escape_filter_is_safe')),
194
+ new Twig_SimpleFilter('e', 'twig_escape_filter', array('needs_environment' => true, 'is_safe_callback' => 'twig_escape_filter_is_safe')),
195
+ );
196
+
197
+ if (function_exists('mb_get_info')) {
198
+ $filters[] = new Twig_SimpleFilter('upper', 'twig_upper_filter', array('needs_environment' => true));
199
+ $filters[] = new Twig_SimpleFilter('lower', 'twig_lower_filter', array('needs_environment' => true));
200
+ }
201
+
202
+ return $filters;
203
+ }
204
+
205
+ /**
206
+ * Returns a list of global functions to add to the existing list.
207
+ *
208
+ * @return array An array of global functions
209
+ */
210
+ public function getFunctions()
211
+ {
212
+ return array(
213
+ new Twig_SimpleFunction('max', 'max'),
214
+ new Twig_SimpleFunction('min', 'min'),
215
+ new Twig_SimpleFunction('range', 'range'),
216
+ new Twig_SimpleFunction('constant', 'twig_constant'),
217
+ new Twig_SimpleFunction('cycle', 'twig_cycle'),
218
+ new Twig_SimpleFunction('random', 'twig_random', array('needs_environment' => true)),
219
+ new Twig_SimpleFunction('date', 'twig_date_converter', array('needs_environment' => true)),
220
+ new Twig_SimpleFunction('include', 'twig_include', array('needs_environment' => true, 'needs_context' => true, 'is_safe' => array('all'))),
221
+ new Twig_SimpleFunction('source', 'twig_source', array('needs_environment' => true, 'is_safe' => array('all'))),
222
+ );
223
+ }
224
+
225
+ /**
226
+ * Returns a list of tests to add to the existing list.
227
+ *
228
+ * @return array An array of tests
229
+ */
230
+ public function getTests()
231
+ {
232
+ return array(
233
+ new Twig_SimpleTest('even', null, array('node_class' => 'Twig_Node_Expression_Test_Even')),
234
+ new Twig_SimpleTest('odd', null, array('node_class' => 'Twig_Node_Expression_Test_Odd')),
235
+ new Twig_SimpleTest('defined', null, array('node_class' => 'Twig_Node_Expression_Test_Defined')),
236
+ new Twig_SimpleTest('sameas', null, array('node_class' => 'Twig_Node_Expression_Test_Sameas')),
237
+ new Twig_SimpleTest('same as', null, array('node_class' => 'Twig_Node_Expression_Test_Sameas')),
238
+ new Twig_SimpleTest('none', null, array('node_class' => 'Twig_Node_Expression_Test_Null')),
239
+ new Twig_SimpleTest('null', null, array('node_class' => 'Twig_Node_Expression_Test_Null')),
240
+ new Twig_SimpleTest('divisibleby', null, array('node_class' => 'Twig_Node_Expression_Test_Divisibleby')),
241
+ new Twig_SimpleTest('divisible by', null, array('node_class' => 'Twig_Node_Expression_Test_Divisibleby')),
242
+ new Twig_SimpleTest('constant', null, array('node_class' => 'Twig_Node_Expression_Test_Constant')),
243
+ new Twig_SimpleTest('empty', 'twig_test_empty'),
244
+ new Twig_SimpleTest('iterable', 'twig_test_iterable'),
245
+ );
246
+ }
247
+
248
+ /**
249
+ * Returns a list of operators to add to the existing list.
250
+ *
251
+ * @return array An array of operators
252
+ */
253
+ public function getOperators()
254
+ {
255
+ return array(
256
+ array(
257
+ 'not' => array('precedence' => 50, 'class' => 'Twig_Node_Expression_Unary_Not'),
258
+ '-' => array('precedence' => 500, 'class' => 'Twig_Node_Expression_Unary_Neg'),
259
+ '+' => array('precedence' => 500, 'class' => 'Twig_Node_Expression_Unary_Pos'),
260
+ ),
261
+ array(
262
+ 'or' => array('precedence' => 10, 'class' => 'Twig_Node_Expression_Binary_Or', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
263
+ 'and' => array('precedence' => 15, 'class' => 'Twig_Node_Expression_Binary_And', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
264
+ 'b-or' => array('precedence' => 16, 'class' => 'Twig_Node_Expression_Binary_BitwiseOr', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
265
+ 'b-xor' => array('precedence' => 17, 'class' => 'Twig_Node_Expression_Binary_BitwiseXor', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
266
+ 'b-and' => array('precedence' => 18, 'class' => 'Twig_Node_Expression_Binary_BitwiseAnd', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
267
+ '==' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_Equal', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
268
+ '!=' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_NotEqual', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
269
+ '<' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_Less', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
270
+ '>' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_Greater', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
271
+ '>=' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_GreaterEqual', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
272
+ '<=' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_LessEqual', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
273
+ 'not in' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_NotIn', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
274
+ 'in' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_In', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
275
+ 'matches' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_Matches', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
276
+ 'starts with' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_StartsWith', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
277
+ 'ends with' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_EndsWith', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
278
+ '..' => array('precedence' => 25, 'class' => 'Twig_Node_Expression_Binary_Range', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
279
+ '+' => array('precedence' => 30, 'class' => 'Twig_Node_Expression_Binary_Add', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
280
+ '-' => array('precedence' => 30, 'class' => 'Twig_Node_Expression_Binary_Sub', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
281
+ '~' => array('precedence' => 40, 'class' => 'Twig_Node_Expression_Binary_Concat', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
282
+ '*' => array('precedence' => 60, 'class' => 'Twig_Node_Expression_Binary_Mul', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
283
+ '/' => array('precedence' => 60, 'class' => 'Twig_Node_Expression_Binary_Div', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
284
+ '//' => array('precedence' => 60, 'class' => 'Twig_Node_Expression_Binary_FloorDiv', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
285
+ '%' => array('precedence' => 60, 'class' => 'Twig_Node_Expression_Binary_Mod', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
286
+ 'is' => array('precedence' => 100, 'callable' => array($this, 'parseTestExpression'), 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
287
+ 'is not' => array('precedence' => 100, 'callable' => array($this, 'parseNotTestExpression'), 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
288
+ '**' => array('precedence' => 200, 'class' => 'Twig_Node_Expression_Binary_Power', 'associativity' => Twig_ExpressionParser::OPERATOR_RIGHT),
289
+ ),
290
+ );
291
+ }
292
+
293
+ public function parseNotTestExpression(Twig_Parser $parser, Twig_NodeInterface $node)
294
+ {
295
+ return new Twig_Node_Expression_Unary_Not($this->parseTestExpression($parser, $node), $parser->getCurrentToken()->getLine());
296
+ }
297
+
298
+ public function parseTestExpression(Twig_Parser $parser, Twig_NodeInterface $node)
299
+ {
300
+ $stream = $parser->getStream();
301
+ $name = $stream->expect(Twig_Token::NAME_TYPE)->getValue();
302
+ $class = $this->getTestNodeClass($parser, $name, $node->getLine());
303
+ $arguments = null;
304
+ if ($stream->test(Twig_Token::PUNCTUATION_TYPE, '(')) {
305
+ $arguments = $parser->getExpressionParser()->parseArguments(true);
306
+ }
307
+
308
+ return new $class($node, $name, $arguments, $parser->getCurrentToken()->getLine());
309
+ }
310
+
311
+ protected function getTestNodeClass(Twig_Parser $parser, $name, $line)
312
+ {
313
+ $env = $parser->getEnvironment();
314
+ $testMap = $env->getTests();
315
+ $testName = null;
316
+ if (isset($testMap[$name])) {
317
+ $testName = $name;
318
+ } elseif ($parser->getStream()->test(Twig_Token::NAME_TYPE)) {
319
+ // try 2-words tests
320
+ $name = $name.' '.$parser->getCurrentToken()->getValue();
321
+
322
+ if (isset($testMap[$name])) {
323
+ $parser->getStream()->next();
324
+
325
+ $testName = $name;
326
+ }
327
+ }
328
+
329
+ if (null === $testName) {
330
+ $message = sprintf('The test "%s" does not exist', $name);
331
+ if ($alternatives = $env->computeAlternatives($name, array_keys($env->getTests()))) {
332
+ $message = sprintf('%s. Did you mean "%s"', $message, implode('", "', $alternatives));
333
+ }
334
+
335
+ throw new Twig_Error_Syntax($message, $line, $parser->getFilename());
336
+ }
337
+
338
+ if ($testMap[$name] instanceof Twig_SimpleTest) {
339
+ return $testMap[$name]->getNodeClass();
340
+ }
341
+
342
+ return $testMap[$name] instanceof Twig_Test_Node ? $testMap[$name]->getClass() : 'Twig_Node_Expression_Test';
343
+ }
344
+
345
+ /**
346
+ * Returns the name of the extension.
347
+ *
348
+ * @return string The extension name
349
+ */
350
+ public function getName()
351
+ {
352
+ return 'core';
353
+ }
354
+ }
355
+
356
+ /**
357
+ * Cycles over a value.
358
+ *
359
+ * @param ArrayAccess|array $values An array or an ArrayAccess instance
360
+ * @param int $position The cycle position
361
+ *
362
+ * @return string The next value in the cycle
363
+ */
364
+ function twig_cycle($values, $position)
365
+ {
366
+ if (!is_array($values) && !$values instanceof ArrayAccess) {
367
+ return $values;
368
+ }
369
+
370
+ return $values[$position % count($values)];
371
+ }
372
+
373
+ /**
374
+ * Returns a random value depending on the supplied parameter type:
375
+ * - a random item from a Traversable or array
376
+ * - a random character from a string
377
+ * - a random integer between 0 and the integer parameter
378
+ *
379
+ * @param Twig_Environment $env A Twig_Environment instance
380
+ * @param Traversable|array|int|string $values The values to pick a random item from
381
+ *
382
+ * @throws Twig_Error_Runtime When $values is an empty array (does not apply to an empty string which is returned as is).
383
+ *
384
+ * @return mixed A random value from the given sequence
385
+ */
386
+ function twig_random(Twig_Environment $env, $values = null)
387
+ {
388
+ if (null === $values) {
389
+ return mt_rand();
390
+ }
391
+
392
+ if (is_int($values) || is_float($values)) {
393
+ return $values < 0 ? mt_rand($values, 0) : mt_rand(0, $values);
394
+ }
395
+
396
+ if ($values instanceof Traversable) {
397
+ $values = iterator_to_array($values);
398
+ } elseif (is_string($values)) {
399
+ if ('' === $values) {
400
+ return '';
401
+ }
402
+ if (null !== $charset = $env->getCharset()) {
403
+ if ('UTF-8' != $charset) {
404
+ $values = twig_convert_encoding($values, 'UTF-8', $charset);
405
+ }
406
+
407
+ // unicode version of str_split()
408
+ // split at all positions, but not after the start and not before the end
409
+ $values = preg_split('/(?<!^)(?!$)/u', $values);
410
+
411
+ if ('UTF-8' != $charset) {
412
+ foreach ($values as $i => $value) {
413
+ $values[$i] = twig_convert_encoding($value, $charset, 'UTF-8');
414
+ }
415
+ }
416
+ } else {
417
+ return $values[mt_rand(0, strlen($values) - 1)];
418
+ }
419
+ }
420
+
421
+ if (!is_array($values)) {
422
+ return $values;
423
+ }
424
+
425
+ if (0 === count($values)) {
426
+ throw new Twig_Error_Runtime('The random function cannot pick from an empty array.');
427
+ }
428
+
429
+ return $values[array_rand($values, 1)];
430
+ }
431
+
432
+ /**
433
+ * Converts a date to the given format.
434
+ *
435
+ * <pre>
436
+ * {{ post.published_at|date("m/d/Y") }}
437
+ * </pre>
438
+ *
439
+ * @param Twig_Environment $env A Twig_Environment instance
440
+ * @param DateTime|DateInterval|string $date A date
441
+ * @param string $format A format
442
+ * @param DateTimeZone|string $timezone A timezone
443
+ *
444
+ * @return string The formatted date
445
+ */
446
+ function twig_date_format_filter(Twig_Environment $env, $date, $format = null, $timezone = null)
447
+ {
448
+ if (null === $format) {
449
+ $formats = $env->getExtension('core')->getDateFormat();
450
+ $format = $date instanceof DateInterval ? $formats[1] : $formats[0];
451
+ }
452
+
453
+ if ($date instanceof DateInterval) {
454
+ return $date->format($format);
455
+ }
456
+
457
+ return twig_date_converter($env, $date, $timezone)->format($format);
458
+ }
459
+
460
+ /**
461
+ * Returns a new date object modified
462
+ *
463
+ * <pre>
464
+ * {{ post.published_at|date_modify("-1day")|date("m/d/Y") }}
465
+ * </pre>
466
+ *
467
+ * @param Twig_Environment $env A Twig_Environment instance
468
+ * @param DateTime|string $date A date
469
+ * @param string $modifier A modifier string
470
+ *
471
+ * @return DateTime A new date object
472
+ */
473
+ function twig_date_modify_filter(Twig_Environment $env, $date, $modifier)
474
+ {
475
+ $date = twig_date_converter($env, $date, false);
476
+ $date->modify($modifier);
477
+
478
+ return $date;
479
+ }
480
+
481
+ /**
482
+ * Converts an input to a DateTime instance.
483
+ *
484
+ * <pre>
485
+ * {% if date(user.created_at) < date('+2days') %}
486
+ * {# do something #}
487
+ * {% endif %}
488
+ * </pre>
489
+ *
490
+ * @param Twig_Environment $env A Twig_Environment instance
491
+ * @param DateTime|string $date A date
492
+ * @param DateTimeZone|string $timezone A timezone
493
+ *
494
+ * @return DateTime A DateTime instance
495
+ */
496
+ function twig_date_converter(Twig_Environment $env, $date = null, $timezone = null)
497
+ {
498
+ // determine the timezone
499
+ if (!$timezone) {
500
+ $defaultTimezone = $env->getExtension('core')->getTimezone();
501
+ } elseif (!$timezone instanceof DateTimeZone) {
502
+ $defaultTimezone = new DateTimeZone($timezone);
503
+ } else {
504
+ $defaultTimezone = $timezone;
505
+ }
506
+
507
+ // immutable dates
508
+ if ($date instanceof DateTimeImmutable) {
509
+ return false !== $timezone ? $date->setTimezone($defaultTimezone) : $date;
510
+ }
511
+
512
+ if ($date instanceof DateTime || $date instanceof DateTimeInterface) {
513
+ $date = clone $date;
514
+ if (false !== $timezone) {
515
+ $date->setTimezone($defaultTimezone);
516
+ }
517
+
518
+ return $date;
519
+ }
520
+
521
+ $asString = (string) $date;
522
+ if (ctype_digit($asString) || (!empty($asString) && '-' === $asString[0] && ctype_digit(substr($asString, 1)))) {
523
+ $date = '@'.$date;
524
+ }
525
+
526
+ $date = new DateTime($date, $defaultTimezone);
527
+ if (false !== $timezone) {
528
+ $date->setTimezone($defaultTimezone);
529
+ }
530
+
531
+ return $date;
532
+ }
533
+
534
+ /**
535
+ * Rounds a number.
536
+ *
537
+ * @param int|float $value The value to round
538
+ * @param int|float $precision The rounding precision
539
+ * @param string $method The method to use for rounding
540
+ *
541
+ * @return int|float The rounded number
542
+ */
543
+ function twig_round($value, $precision = 0, $method = 'common')
544
+ {
545
+ if ('common' == $method) {
546
+ return round($value, $precision);
547
+ }
548
+
549
+ if ('ceil' != $method && 'floor' != $method) {
550
+ throw new Twig_Error_Runtime('The round filter only supports the "common", "ceil", and "floor" methods.');
551
+ }
552
+
553
+ return $method($value * pow(10, $precision)) / pow(10, $precision);
554
+ }
555
+
556
+ /**
557
+ * Number format filter.
558
+ *
559
+ * All of the formatting options can be left null, in that case the defaults will
560
+ * be used. Supplying any of the parameters will override the defaults set in the
561
+ * environment object.
562
+ *
563
+ * @param Twig_Environment $env A Twig_Environment instance
564
+ * @param mixed $number A float/int/string of the number to format
565
+ * @param int $decimal The number of decimal points to display.
566
+ * @param string $decimalPoint The character(s) to use for the decimal point.
567
+ * @param string $thousandSep The character(s) to use for the thousands separator.
568
+ *
569
+ * @return string The formatted number
570
+ */
571
+ function twig_number_format_filter(Twig_Environment $env, $number, $decimal = null, $decimalPoint = null, $thousandSep = null)
572
+ {
573
+ $defaults = $env->getExtension('core')->getNumberFormat();
574
+ if (null === $decimal) {
575
+ $decimal = $defaults[0];
576
+ }
577
+
578
+ if (null === $decimalPoint) {
579
+ $decimalPoint = $defaults[1];
580
+ }
581
+
582
+ if (null === $thousandSep) {
583
+ $thousandSep = $defaults[2];
584
+ }
585
+
586
+ return number_format((float) $number, $decimal, $decimalPoint, $thousandSep);
587
+ }
588
+
589
+ /**
590
+ * URL encodes (RFC 3986) a string as a path segment or an array as a query string.
591
+ *
592
+ * @param string|array $url A URL or an array of query parameters
593
+ *
594
+ * @return string The URL encoded value
595
+ */
596
+ function twig_urlencode_filter($url)
597
+ {
598
+ if (is_array($url)) {
599
+ if (defined('PHP_QUERY_RFC3986')) {
600
+ return http_build_query($url, '', '&', PHP_QUERY_RFC3986);
601
+ }
602
+
603
+ return http_build_query($url, '', '&');
604
+ }
605
+
606
+ return rawurlencode($url);
607
+ }
608
+
609
+ if (version_compare(PHP_VERSION, '5.3.0', '<')) {
610
+ /**
611
+ * JSON encodes a variable.
612
+ *
613
+ * @param mixed $value The value to encode.
614
+ * @param int $options Not used on PHP 5.2.x
615
+ *
616
+ * @return mixed The JSON encoded value
617
+ */
618
+ function twig_jsonencode_filter($value, $options = 0)
619
+ {
620
+ if ($value instanceof Twig_Markup) {
621
+ $value = (string) $value;
622
+ } elseif (is_array($value)) {
623
+ array_walk_recursive($value, '_twig_markup2string');
624
+ }
625
+
626
+ return json_encode($value);
627
+ }
628
+ } else {
629
+ /**
630
+ * JSON encodes a variable.
631
+ *
632
+ * @param mixed $value The value to encode.
633
+ * @param int $options Bitmask consisting of JSON_HEX_QUOT, JSON_HEX_TAG, JSON_HEX_AMP, JSON_HEX_APOS, JSON_NUMERIC_CHECK, JSON_PRETTY_PRINT, JSON_UNESCAPED_SLASHES, JSON_FORCE_OBJECT
634
+ *
635
+ * @return mixed The JSON encoded value
636
+ */
637
+ function twig_jsonencode_filter($value, $options = 0)
638
+ {
639
+ if ($value instanceof Twig_Markup) {
640
+ $value = (string) $value;
641
+ } elseif (is_array($value)) {
642
+ array_walk_recursive($value, '_twig_markup2string');
643
+ }
644
+
645
+ return json_encode($value, $options);
646
+ }
647
+ }
648
+
649
+ function _twig_markup2string(&$value)
650
+ {
651
+ if ($value instanceof Twig_Markup) {
652
+ $value = (string) $value;
653
+ }
654
+ }
655
+
656
+ /**
657
+ * Merges an array with another one.
658
+ *
659
+ * <pre>
660
+ * {% set items = { 'apple': 'fruit', 'orange': 'fruit' } %}
661
+ *
662
+ * {% set items = items|merge({ 'peugeot': 'car' }) %}
663
+ *
664
+ * {# items now contains { 'apple': 'fruit', 'orange': 'fruit', 'peugeot': 'car' } #}
665
+ * </pre>
666
+ *
667
+ * @param array $arr1 An array
668
+ * @param array $arr2 An array
669
+ *
670
+ * @return array The merged array
671
+ */
672
+ function twig_array_merge($arr1, $arr2)
673
+ {
674
+ if (!is_array($arr1) || !is_array($arr2)) {
675
+ throw new Twig_Error_Runtime('The merge filter only works with arrays or hashes.');
676
+ }
677
+
678
+ return array_merge($arr1, $arr2);
679
+ }
680
+
681
+ /**
682
+ * Slices a variable.
683
+ *
684
+ * @param Twig_Environment $env A Twig_Environment instance
685
+ * @param mixed $item A variable
686
+ * @param int $start Start of the slice
687
+ * @param int $length Size of the slice
688
+ * @param bool $preserveKeys Whether to preserve key or not (when the input is an array)
689
+ *
690
+ * @return mixed The sliced variable
691
+ */
692
+ function twig_slice(Twig_Environment $env, $item, $start, $length = null, $preserveKeys = false)
693
+ {
694
+ if ($item instanceof Traversable) {
695
+ $item = iterator_to_array($item, false);
696
+ }
697
+
698
+ if (is_array($item)) {
699
+ return array_slice($item, $start, $length, $preserveKeys);
700
+ }
701
+
702
+ $item = (string) $item;
703
+
704
+ if (function_exists('mb_get_info') && null !== $charset = $env->getCharset()) {
705
+ return mb_substr($item, $start, null === $length ? mb_strlen($item, $charset) - $start : $length, $charset);
706
+ }
707
+
708
+ return null === $length ? substr($item, $start) : substr($item, $start, $length);
709
+ }
710
+
711
+ /**
712
+ * Returns the first element of the item.
713
+ *
714
+ * @param Twig_Environment $env A Twig_Environment instance
715
+ * @param mixed $item A variable
716
+ *
717
+ * @return mixed The first element of the item
718
+ */
719
+ function twig_first(Twig_Environment $env, $item)
720
+ {
721
+ $elements = twig_slice($env, $item, 0, 1, false);
722
+
723
+ return is_string($elements) ? $elements : current($elements);
724
+ }
725
+
726
+ /**
727
+ * Returns the last element of the item.
728
+ *
729
+ * @param Twig_Environment $env A Twig_Environment instance
730
+ * @param mixed $item A variable
731
+ *
732
+ * @return mixed The last element of the item
733
+ */
734
+ function twig_last(Twig_Environment $env, $item)
735
+ {
736
+ $elements = twig_slice($env, $item, -1, 1, false);
737
+
738
+ return is_string($elements) ? $elements : current($elements);
739
+ }
740
+
741
+ /**
742
+ * Joins the values to a string.
743
+ *
744
+ * The separator between elements is an empty string per default, you can define it with the optional parameter.
745
+ *
746
+ * <pre>
747
+ * {{ [1, 2, 3]|join('|') }}
748
+ * {# returns 1|2|3 #}
749
+ *
750
+ * {{ [1, 2, 3]|join }}
751
+ * {# returns 123 #}
752
+ * </pre>
753
+ *
754
+ * @param array $value An array
755
+ * @param string $glue The separator
756
+ *
757
+ * @return string The concatenated string
758
+ */
759
+ function twig_join_filter($value, $glue = '')
760
+ {
761
+ if ($value instanceof Traversable) {
762
+ $value = iterator_to_array($value, false);
763
+ }
764
+
765
+ return implode($glue, (array) $value);
766
+ }
767
+
768
+ /**
769
+ * Splits the string into an array.
770
+ *
771
+ * <pre>
772
+ * {{ "one,two,three"|split(',') }}
773
+ * {# returns [one, two, three] #}
774
+ *
775
+ * {{ "one,two,three,four,five"|split(',', 3) }}
776
+ * {# returns [one, two, "three,four,five"] #}
777
+ *
778
+ * {{ "123"|split('') }}
779
+ * {# returns [1, 2, 3] #}
780
+ *
781
+ * {{ "aabbcc"|split('', 2) }}
782
+ * {# returns [aa, bb, cc] #}
783
+ * </pre>
784
+ *
785
+ * @param string $value A string
786
+ * @param string $delimiter The delimiter
787
+ * @param int $limit The limit
788
+ *
789
+ * @return array The split string as an array
790
+ */
791
+ function twig_split_filter($value, $delimiter, $limit = null)
792
+ {
793
+ if (empty($delimiter)) {
794
+ return str_split($value, null === $limit ? 1 : $limit);
795
+ }
796
+
797
+ return null === $limit ? explode($delimiter, $value) : explode($delimiter, $value, $limit);
798
+ }
799
+
800
+ // The '_default' filter is used internally to avoid using the ternary operator
801
+ // which costs a lot for big contexts (before PHP 5.4). So, on average,
802
+ // a function call is cheaper.
803
+ function _twig_default_filter($value, $default = '')
804
+ {
805
+ if (twig_test_empty($value)) {
806
+ return $default;
807
+ }
808
+
809
+ return $value;
810
+ }
811
+
812
+ /**
813
+ * Returns the keys for the given array.
814
+ *
815
+ * It is useful when you want to iterate over the keys of an array:
816
+ *
817
+ * <pre>
818
+ * {% for key in array|keys %}
819
+ * {# ... #}
820
+ * {% endfor %}
821
+ * </pre>
822
+ *
823
+ * @param array $array An array
824
+ *
825
+ * @return array The keys
826
+ */
827
+ function twig_get_array_keys_filter($array)
828
+ {
829
+ if (is_object($array) && $array instanceof Traversable) {
830
+ return array_keys(iterator_to_array($array));
831
+ }
832
+
833
+ if (!is_array($array)) {
834
+ return array();
835
+ }
836
+
837
+ return array_keys($array);
838
+ }
839
+
840
+ /**
841
+ * Reverses a variable.
842
+ *
843
+ * @param Twig_Environment $env A Twig_Environment instance
844
+ * @param array|Traversable|string $item An array, a Traversable instance, or a string
845
+ * @param bool $preserveKeys Whether to preserve key or not
846
+ *
847
+ * @return mixed The reversed input
848
+ */
849
+ function twig_reverse_filter(Twig_Environment $env, $item, $preserveKeys = false)
850
+ {
851
+ if (is_object($item) && $item instanceof Traversable) {
852
+ return array_reverse(iterator_to_array($item), $preserveKeys);
853
+ }
854
+
855
+ if (is_array($item)) {
856
+ return array_reverse($item, $preserveKeys);
857
+ }
858
+
859
+ if (null !== $charset = $env->getCharset()) {
860
+ $string = (string) $item;
861
+
862
+ if ('UTF-8' != $charset) {
863
+ $item = twig_convert_encoding($string, 'UTF-8', $charset);
864
+ }
865
+
866
+ preg_match_all('/./us', $item, $matches);
867
+
868
+ $string = implode('', array_reverse($matches[0]));
869
+
870
+ if ('UTF-8' != $charset) {
871
+ $string = twig_convert_encoding($string, $charset, 'UTF-8');
872
+ }
873
+
874
+ return $string;
875
+ }
876
+
877
+ return strrev((string) $item);
878
+ }
879
+
880
+ /**
881
+ * Sorts an array.
882
+ *
883
+ * @param array $array An array
884
+ */
885
+ function twig_sort_filter($array)
886
+ {
887
+ asort($array);
888
+
889
+ return $array;
890
+ }
891
+
892
+ /* used internally */
893
+ function twig_in_filter($value, $compare)
894
+ {
895
+ if (is_array($compare)) {
896
+ return in_array($value, $compare, is_object($value));
897
+ } elseif (is_string($compare)) {
898
+ if (!strlen($value)) {
899
+ return empty($compare);
900
+ }
901
+
902
+ return false !== strpos($compare, (string) $value);
903
+ } elseif ($compare instanceof Traversable) {
904
+ return in_array($value, iterator_to_array($compare, false), is_object($value));
905
+ }
906
+
907
+ return false;
908
+ }
909
+
910
+ /**
911
+ * Escapes a string.
912
+ *
913
+ * @param Twig_Environment $env A Twig_Environment instance
914
+ * @param string $string The value to be escaped
915
+ * @param string $strategy The escaping strategy
916
+ * @param string $charset The charset
917
+ * @param bool $autoescape Whether the function is called by the auto-escaping feature (true) or by the developer (false)
918
+ */
919
+ function twig_escape_filter(Twig_Environment $env, $string, $strategy = 'html', $charset = null, $autoescape = false)
920
+ {
921
+ if ($autoescape && $string instanceof Twig_Markup) {
922
+ return $string;
923
+ }
924
+
925
+ if (!is_string($string)) {
926
+ if (is_object($string) && method_exists($string, '__toString')) {
927
+ $string = (string) $string;
928
+ } else {
929
+ return $string;
930
+ }
931
+ }
932
+
933
+ if (null === $charset) {
934
+ $charset = $env->getCharset();
935
+ }
936
+
937
+ switch ($strategy) {
938
+ case 'html':
939
+ // see http://php.net/htmlspecialchars
940
+
941
+ // Using a static variable to avoid initializing the array
942
+ // each time the function is called. Moving the declaration on the
943
+ // top of the function slow downs other escaping strategies.
944
+ static $htmlspecialcharsCharsets;
945
+
946
+ if (null === $htmlspecialcharsCharsets) {
947
+ if ('hiphop' === substr(PHP_VERSION, -6)) {
948
+ $htmlspecialcharsCharsets = array('utf-8' => true, 'UTF-8' => true);
949
+ } else {
950
+ $htmlspecialcharsCharsets = array(
951
+ 'ISO-8859-1' => true, 'ISO8859-1' => true,
952
+ 'ISO-8859-15' => true, 'ISO8859-15' => true,
953
+ 'utf-8' => true, 'UTF-8' => true,
954
+ 'CP866' => true, 'IBM866' => true, '866' => true,
955
+ 'CP1251' => true, 'WINDOWS-1251' => true, 'WIN-1251' => true,
956
+ '1251' => true,
957
+ 'CP1252' => true, 'WINDOWS-1252' => true, '1252' => true,
958
+ 'KOI8-R' => true, 'KOI8-RU' => true, 'KOI8R' => true,
959
+ 'BIG5' => true, '950' => true,
960
+ 'GB2312' => true, '936' => true,
961
+ 'BIG5-HKSCS' => true,
962
+ 'SHIFT_JIS' => true, 'SJIS' => true, '932' => true,
963
+ 'EUC-JP' => true, 'EUCJP' => true,
964
+ 'ISO8859-5' => true, 'ISO-8859-5' => true, 'MACROMAN' => true,
965
+ );
966
+ }
967
+ }
968
+
969
+ if (isset($htmlspecialcharsCharsets[$charset])) {
970
+ return htmlspecialchars($string, ENT_QUOTES | ENT_SUBSTITUTE, $charset);
971
+ }
972
+
973
+ if (isset($htmlspecialcharsCharsets[strtoupper($charset)])) {
974
+ // cache the lowercase variant for future iterations
975
+ $htmlspecialcharsCharsets[$charset] = true;
976
+
977
+ return htmlspecialchars($string, ENT_QUOTES | ENT_SUBSTITUTE, $charset);
978
+ }
979
+
980
+ $string = twig_convert_encoding($string, 'UTF-8', $charset);
981
+ $string = htmlspecialchars($string, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8');
982
+
983
+ return twig_convert_encoding($string, $charset, 'UTF-8');
984
+
985
+ case 'js':
986
+ // escape all non-alphanumeric characters
987
+ // into their \xHH or \uHHHH representations
988
+ if ('UTF-8' != $charset) {
989
+ $string = twig_convert_encoding($string, 'UTF-8', $charset);
990
+ }
991
+
992
+ if (0 == strlen($string) ? false : (1 == preg_match('/^./su', $string) ? false : true)) {
993
+ throw new Twig_Error_Runtime('The string to escape is not a valid UTF-8 string.');
994
+ }
995
+
996
+ $string = preg_replace_callback('#[^a-zA-Z0-9,\._]#Su', '_twig_escape_js_callback', $string);
997
+
998
+ if ('UTF-8' != $charset) {
999
+ $string = twig_convert_encoding($string, $charset, 'UTF-8');
1000
+ }
1001
+
1002
+ return $string;
1003
+
1004
+ case 'css':
1005
+ if ('UTF-8' != $charset) {
1006
+ $string = twig_convert_encoding($string, 'UTF-8', $charset);
1007
+ }
1008
+
1009
+ if (0 == strlen($string) ? false : (1 == preg_match('/^./su', $string) ? false : true)) {
1010
+ throw new Twig_Error_Runtime('The string to escape is not a valid UTF-8 string.');
1011
+ }
1012
+
1013
+ $string = preg_replace_callback('#[^a-zA-Z0-9]#Su', '_twig_escape_css_callback', $string);
1014
+
1015
+ if ('UTF-8' != $charset) {
1016
+ $string = twig_convert_encoding($string, $charset, 'UTF-8');
1017
+ }
1018
+
1019
+ return $string;
1020
+
1021
+ case 'html_attr':
1022
+ if ('UTF-8' != $charset) {
1023
+ $string = twig_convert_encoding($string, 'UTF-8', $charset);
1024
+ }
1025
+
1026
+ if (0 == strlen($string) ? false : (1 == preg_match('/^./su', $string) ? false : true)) {
1027
+ throw new Twig_Error_Runtime('The string to escape is not a valid UTF-8 string.');
1028
+ }
1029
+
1030
+ $string = preg_replace_callback('#[^a-zA-Z0-9,\.\-_]#Su', '_twig_escape_html_attr_callback', $string);
1031
+
1032
+ if ('UTF-8' != $charset) {
1033
+ $string = twig_convert_encoding($string, $charset, 'UTF-8');
1034
+ }
1035
+
1036
+ return $string;
1037
+
1038
+ case 'url':
1039
+ // hackish test to avoid version_compare that is much slower, this works unless PHP releases a 5.10.*
1040
+ // at that point however PHP 5.2.* support can be removed
1041
+ if (PHP_VERSION < '5.3.0') {
1042
+ return str_replace('%7E', '~', rawurlencode($string));
1043
+ }
1044
+
1045
+ return rawurlencode($string);
1046
+
1047
+ default:
1048
+ static $escapers;
1049
+
1050
+ if (null === $escapers) {
1051
+ $escapers = $env->getExtension('core')->getEscapers();
1052
+ }
1053
+
1054
+ if (isset($escapers[$strategy])) {
1055
+ return call_user_func($escapers[$strategy], $env, $string, $charset);
1056
+ }
1057
+
1058
+ $validStrategies = implode(', ', array_merge(array('html', 'js', 'url', 'css', 'html_attr'), array_keys($escapers)));
1059
+
1060
+ throw new Twig_Error_Runtime(sprintf('Invalid escaping strategy "%s" (valid ones: %s).', $strategy, $validStrategies));
1061
+ }
1062
+ }
1063
+
1064
+ /* used internally */
1065
+ function twig_escape_filter_is_safe(Twig_Node $filterArgs)
1066
+ {
1067
+ foreach ($filterArgs as $arg) {
1068
+ if ($arg instanceof Twig_Node_Expression_Constant) {
1069
+ return array($arg->getAttribute('value'));
1070
+ }
1071
+
1072
+ return array();
1073
+ }
1074
+
1075
+ return array('html');
1076
+ }
1077
+
1078
+ if (function_exists('mb_convert_encoding')) {
1079
+ function twig_convert_encoding($string, $to, $from)
1080
+ {
1081
+ return mb_convert_encoding($string, $to, $from);
1082
+ }
1083
+ } elseif (function_exists('iconv')) {
1084
+ function twig_convert_encoding($string, $to, $from)
1085
+ {
1086
+ return iconv($from, $to, $string);
1087
+ }
1088
+ } else {
1089
+ function twig_convert_encoding($string, $to, $from)
1090
+ {
1091
+ throw new Twig_Error_Runtime('No suitable convert encoding function (use UTF-8 as your encoding or install the iconv or mbstring extension).');
1092
+ }
1093
+ }
1094
+
1095
+ function _twig_escape_js_callback($matches)
1096
+ {
1097
+ $char = $matches[0];
1098
+
1099
+ // \xHH
1100
+ if (!isset($char[1])) {
1101
+ return '\\x'.strtoupper(substr('00'.bin2hex($char), -2));
1102
+ }
1103
+
1104
+ // \uHHHH
1105
+ $char = twig_convert_encoding($char, 'UTF-16BE', 'UTF-8');
1106
+
1107
+ return '\\u'.strtoupper(substr('0000'.bin2hex($char), -4));
1108
+ }
1109
+
1110
+ function _twig_escape_css_callback($matches)
1111
+ {
1112
+ $char = $matches[0];
1113
+
1114
+ // \xHH
1115
+ if (!isset($char[1])) {
1116
+ $hex = ltrim(strtoupper(bin2hex($char)), '0');
1117
+ if (0 === strlen($hex)) {
1118
+ $hex = '0';
1119
+ }
1120
+
1121
+ return '\\'.$hex.' ';
1122
+ }
1123
+
1124
+ // \uHHHH
1125
+ $char = twig_convert_encoding($char, 'UTF-16BE', 'UTF-8');
1126
+
1127
+ return '\\'.ltrim(strtoupper(bin2hex($char)), '0').' ';
1128
+ }
1129
+
1130
+ /**
1131
+ * This function is adapted from code coming from Zend Framework.
1132
+ *
1133
+ * @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
1134
+ * @license http://framework.zend.com/license/new-bsd New BSD License
1135
+ */
1136
+ function _twig_escape_html_attr_callback($matches)
1137
+ {
1138
+ /*
1139
+ * While HTML supports far more named entities, the lowest common denominator
1140
+ * has become HTML5's XML Serialisation which is restricted to the those named
1141
+ * entities that XML supports. Using HTML entities would result in this error:
1142
+ * XML Parsing Error: undefined entity
1143
+ */
1144
+ static $entityMap = array(
1145
+ 34 => 'quot', /* quotation mark */
1146
+ 38 => 'amp', /* ampersand */
1147
+ 60 => 'lt', /* less-than sign */
1148
+ 62 => 'gt', /* greater-than sign */
1149
+ );
1150
+
1151
+ $chr = $matches[0];
1152
+ $ord = ord($chr);
1153
+
1154
+ /**
1155
+ * The following replaces characters undefined in HTML with the
1156
+ * hex entity for the Unicode replacement character.
1157
+ */
1158
+ if (($ord <= 0x1f && $chr != "\t" && $chr != "\n" && $chr != "\r") || ($ord >= 0x7f && $ord <= 0x9f)) {
1159
+ return '&#xFFFD;';
1160
+ }
1161
+
1162
+ /**
1163
+ * Check if the current character to escape has a name entity we should
1164
+ * replace it with while grabbing the hex value of the character.
1165
+ */
1166
+ if (strlen($chr) == 1) {
1167
+ $hex = strtoupper(substr('00'.bin2hex($chr), -2));
1168
+ } else {
1169
+ $chr = twig_convert_encoding($chr, 'UTF-16BE', 'UTF-8');
1170
+ $hex = strtoupper(substr('0000'.bin2hex($chr), -4));
1171
+ }
1172
+
1173
+ $int = hexdec($hex);
1174
+ if (array_key_exists($int, $entityMap)) {
1175
+ return sprintf('&%s;', $entityMap[$int]);
1176
+ }
1177
+
1178
+ /**
1179
+ * Per OWASP recommendations, we'll use hex entities for any other
1180
+ * characters where a named entity does not exist.
1181
+ */
1182
+
1183
+ return sprintf('&#x%s;', $hex);
1184
+ }
1185
+
1186
+ // add multibyte extensions if possible
1187
+ if (function_exists('mb_get_info')) {
1188
+ /**
1189
+ * Returns the length of a variable.
1190
+ *
1191
+ * @param Twig_Environment $env A Twig_Environment instance
1192
+ * @param mixed $thing A variable
1193
+ *
1194
+ * @return int The length of the value
1195
+ */
1196
+ function twig_length_filter(Twig_Environment $env, $thing)
1197
+ {
1198
+ return is_scalar($thing) ? mb_strlen($thing, $env->getCharset()) : count($thing);
1199
+ }
1200
+
1201
+ /**
1202
+ * Converts a string to uppercase.
1203
+ *
1204
+ * @param Twig_Environment $env A Twig_Environment instance
1205
+ * @param string $string A string
1206
+ *
1207
+ * @return string The uppercased string
1208
+ */
1209
+ function twig_upper_filter(Twig_Environment $env, $string)
1210
+ {
1211
+ if (null !== ($charset = $env->getCharset())) {
1212
+ return mb_strtoupper($string, $charset);
1213
+ }
1214
+
1215
+ return strtoupper($string);
1216
+ }
1217
+
1218
+ /**
1219
+ * Converts a string to lowercase.
1220
+ *
1221
+ * @param Twig_Environment $env A Twig_Environment instance
1222
+ * @param string $string A string
1223
+ *
1224
+ * @return string The lowercased string
1225
+ */
1226
+ function twig_lower_filter(Twig_Environment $env, $string)
1227
+ {
1228
+ if (null !== ($charset = $env->getCharset())) {
1229
+ return mb_strtolower($string, $charset);
1230
+ }
1231
+
1232
+ return strtolower($string);
1233
+ }
1234
+
1235
+ /**
1236
+ * Returns a titlecased string.
1237
+ *
1238
+ * @param Twig_Environment $env A Twig_Environment instance
1239
+ * @param string $string A string
1240
+ *
1241
+ * @return string The titlecased string
1242
+ */
1243
+ function twig_title_string_filter(Twig_Environment $env, $string)
1244
+ {
1245
+ if (null !== ($charset = $env->getCharset())) {
1246
+ return mb_convert_case($string, MB_CASE_TITLE, $charset);
1247
+ }
1248
+
1249
+ return ucwords(strtolower($string));
1250
+ }
1251
+
1252
+ /**
1253
+ * Returns a capitalized string.
1254
+ *
1255
+ * @param Twig_Environment $env A Twig_Environment instance
1256
+ * @param string $string A string
1257
+ *
1258
+ * @return string The capitalized string
1259
+ */
1260
+ function twig_capitalize_string_filter(Twig_Environment $env, $string)
1261
+ {
1262
+ if (null !== ($charset = $env->getCharset())) {
1263
+ return mb_strtoupper(mb_substr($string, 0, 1, $charset), $charset).
1264
+ mb_strtolower(mb_substr($string, 1, mb_strlen($string, $charset), $charset), $charset);
1265
+ }
1266
+
1267
+ return ucfirst(strtolower($string));
1268
+ }
1269
+ }
1270
+ // and byte fallback
1271
+ else {
1272
+ /**
1273
+ * Returns the length of a variable.
1274
+ *
1275
+ * @param Twig_Environment $env A Twig_Environment instance
1276
+ * @param mixed $thing A variable
1277
+ *
1278
+ * @return int The length of the value
1279
+ */
1280
+ function twig_length_filter(Twig_Environment $env, $thing)
1281
+ {
1282
+ return is_scalar($thing) ? strlen($thing) : count($thing);
1283
+ }
1284
+
1285
+ /**
1286
+ * Returns a titlecased string.
1287
+ *
1288
+ * @param Twig_Environment $env A Twig_Environment instance
1289
+ * @param string $string A string
1290
+ *
1291
+ * @return string The titlecased string
1292
+ */
1293
+ function twig_title_string_filter(Twig_Environment $env, $string)
1294
+ {
1295
+ return ucwords(strtolower($string));
1296
+ }
1297
+
1298
+ /**
1299
+ * Returns a capitalized string.
1300
+ *
1301
+ * @param Twig_Environment $env A Twig_Environment instance
1302
+ * @param string $string A string
1303
+ *
1304
+ * @return string The capitalized string
1305
+ */
1306
+ function twig_capitalize_string_filter(Twig_Environment $env, $string)
1307
+ {
1308
+ return ucfirst(strtolower($string));
1309
+ }
1310
+ }
1311
+
1312
+ /* used internally */
1313
+ function twig_ensure_traversable($seq)
1314
+ {
1315
+ if ($seq instanceof Traversable || is_array($seq)) {
1316
+ return $seq;
1317
+ }
1318
+
1319
+ return array();
1320
+ }
1321
+
1322
+ /**
1323
+ * Checks if a variable is empty.
1324
+ *
1325
+ * <pre>
1326
+ * {# evaluates to true if the foo variable is null, false, or the empty string #}
1327
+ * {% if foo is empty %}
1328
+ * {# ... #}
1329
+ * {% endif %}
1330
+ * </pre>
1331
+ *
1332
+ * @param mixed $value A variable
1333
+ *
1334
+ * @return bool true if the value is empty, false otherwise
1335
+ */
1336
+ function twig_test_empty($value)
1337
+ {
1338
+ if ($value instanceof Countable) {
1339
+ return 0 == count($value);
1340
+ }
1341
+
1342
+ return '' === $value || false === $value || null === $value || array() === $value;
1343
+ }
1344
+
1345
+ /**
1346
+ * Checks if a variable is traversable.
1347
+ *
1348
+ * <pre>
1349
+ * {# evaluates to true if the foo variable is an array or a traversable object #}
1350
+ * {% if foo is traversable %}
1351
+ * {# ... #}
1352
+ * {% endif %}
1353
+ * </pre>
1354
+ *
1355
+ * @param mixed $value A variable
1356
+ *
1357
+ * @return bool true if the value is traversable
1358
+ */
1359
+ function twig_test_iterable($value)
1360
+ {
1361
+ return $value instanceof Traversable || is_array($value);
1362
+ }
1363
+
1364
+ /**
1365
+ * Renders a template.
1366
+ *
1367
+ * @param string|array $template The template to render or an array of templates to try consecutively
1368
+ * @param array $variables The variables to pass to the template
1369
+ * @param bool $with_context Whether to pass the current context variables or not
1370
+ * @param bool $ignore_missing Whether to ignore missing templates or not
1371
+ * @param bool $sandboxed Whether to sandbox the template or not
1372
+ *
1373
+ * @return string The rendered template
1374
+ */
1375
+ function twig_include(Twig_Environment $env, $context, $template, $variables = array(), $withContext = true, $ignoreMissing = false, $sandboxed = false)
1376
+ {
1377
+ $alreadySandboxed = false;
1378
+ $sandbox = null;
1379
+ if ($withContext) {
1380
+ $variables = array_merge($context, $variables);
1381
+ }
1382
+
1383
+ if ($isSandboxed = $sandboxed && $env->hasExtension('sandbox')) {
1384
+ $sandbox = $env->getExtension('sandbox');
1385
+ if (!$alreadySandboxed = $sandbox->isSandboxed()) {
1386
+ $sandbox->enableSandbox();
1387
+ }
1388
+ }
1389
+
1390
+ try {
1391
+ return $env->resolveTemplate($template)->render($variables);
1392
+ } catch (Twig_Error_Loader $e) {
1393
+ if (!$ignoreMissing) {
1394
+ throw $e;
1395
+ }
1396
+ }
1397
+
1398
+ if ($isSandboxed && !$alreadySandboxed) {
1399
+ $sandbox->disableSandbox();
1400
+ }
1401
+ }
1402
+
1403
+ /**
1404
+ * Returns a template content without rendering it.
1405
+ *
1406
+ * @param string $name The template name
1407
+ *
1408
+ * @return string The template source
1409
+ */
1410
+ function twig_source(Twig_Environment $env, $name)
1411
+ {
1412
+ return $env->getLoader()->getSource($name);
1413
+ }
1414
+
1415
+ /**
1416
+ * Provides the ability to get constants from instances as well as class/global constants.
1417
+ *
1418
+ * @param string $constant The name of the constant
1419
+ * @param null|object $object The object to get the constant from
1420
+ *
1421
+ * @return string
1422
+ */
1423
+ function twig_constant($constant, $object = null)
1424
+ {
1425
+ if (null !== $object) {
1426
+ $constant = get_class($object).'::'.$constant;
1427
+ }
1428
+
1429
+ return constant($constant);
1430
+ }
1431
+
1432
+ /**
1433
+ * Batches item.
1434
+ *
1435
+ * @param array $items An array of items
1436
+ * @param int $size The size of the batch
1437
+ * @param mixed $fill A value used to fill missing items
1438
+ *
1439
+ * @return array
1440
+ */
1441
+ function twig_array_batch($items, $size, $fill = null)
1442
+ {
1443
+ if ($items instanceof Traversable) {
1444
+ $items = iterator_to_array($items, false);
1445
+ }
1446
+
1447
+ $size = ceil($size);
1448
+
1449
+ $result = array_chunk($items, $size, true);
1450
+
1451
+ if (null !== $fill) {
1452
+ $last = count($result) - 1;
1453
+ if ($fillCount = $size - count($result[$last])) {
1454
+ $result[$last] = array_merge(
1455
+ $result[$last],
1456
+ array_fill(0, $fillCount, $fill)
1457
+ );
1458
+ }
1459
+ }
1460
+
1461
+ return $result;
1462
+ }
classes/Twig/Extension/Debug.php CHANGED
@@ -1,71 +1,71 @@
1
- <?php
2
-
3
- /*
4
- * This file is part of Twig.
5
- *
6
- * (c) 2011 Fabien Potencier
7
- *
8
- * For the full copyright and license information, please view the LICENSE
9
- * file that was distributed with this source code.
10
- */
11
- class Twig_Extension_Debug extends Twig_Extension
12
- {
13
- /**
14
- * Returns a list of global functions to add to the existing list.
15
- *
16
- * @return array An array of global functions
17
- */
18
- public function getFunctions()
19
- {
20
- // dump is safe if var_dump is overridden by xdebug
21
- $isDumpOutputHtmlSafe = extension_loaded('xdebug')
22
- // false means that it was not set (and the default is on) or it explicitly enabled
23
- && (false === ini_get('xdebug.overload_var_dump') || ini_get('xdebug.overload_var_dump'))
24
- // false means that it was not set (and the default is on) or it explicitly enabled
25
- // xdebug.overload_var_dump produces HTML only when html_errors is also enabled
26
- && (false === ini_get('html_errors') || ini_get('html_errors'))
27
- || 'cli' === php_sapi_name()
28
- ;
29
-
30
- return array(
31
- new Twig_SimpleFunction('dump', 'twig_var_dump', array('is_safe' => $isDumpOutputHtmlSafe ? array('html') : array(), 'needs_context' => true, 'needs_environment' => true)),
32
- );
33
- }
34
-
35
- /**
36
- * Returns the name of the extension.
37
- *
38
- * @return string The extension name
39
- */
40
- public function getName()
41
- {
42
- return 'debug';
43
- }
44
- }
45
-
46
- function twig_var_dump(Twig_Environment $env, $context)
47
- {
48
- if (!$env->isDebug()) {
49
- return;
50
- }
51
-
52
- ob_start();
53
-
54
- $count = func_num_args();
55
- if (2 === $count) {
56
- $vars = array();
57
- foreach ($context as $key => $value) {
58
- if (!$value instanceof Twig_Template) {
59
- $vars[$key] = $value;
60
- }
61
- }
62
-
63
- var_dump($vars);
64
- } else {
65
- for ($i = 2; $i < $count; $i++) {
66
- var_dump(func_get_arg($i));
67
- }
68
- }
69
-
70
- return ob_get_clean();
71
- }
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2011 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+ class Twig_Extension_Debug extends Twig_Extension
12
+ {
13
+ /**
14
+ * Returns a list of global functions to add to the existing list.
15
+ *
16
+ * @return array An array of global functions
17
+ */
18
+ public function getFunctions()
19
+ {
20
+ // dump is safe if var_dump is overridden by xdebug
21
+ $isDumpOutputHtmlSafe = extension_loaded('xdebug')
22
+ // false means that it was not set (and the default is on) or it explicitly enabled
23
+ && (false === ini_get('xdebug.overload_var_dump') || ini_get('xdebug.overload_var_dump'))
24
+ // false means that it was not set (and the default is on) or it explicitly enabled
25
+ // xdebug.overload_var_dump produces HTML only when html_errors is also enabled
26
+ && (false === ini_get('html_errors') || ini_get('html_errors'))
27
+ || 'cli' === php_sapi_name()
28
+ ;
29
+
30
+ return array(
31
+ new Twig_SimpleFunction('dump', 'twig_var_dump', array('is_safe' => $isDumpOutputHtmlSafe ? array('html') : array(), 'needs_context' => true, 'needs_environment' => true)),
32
+ );
33
+ }
34
+
35
+ /**
36
+ * Returns the name of the extension.
37
+ *
38
+ * @return string The extension name
39
+ */
40
+ public function getName()
41
+ {
42
+ return 'debug';
43
+ }
44
+ }
45
+
46
+ function twig_var_dump(Twig_Environment $env, $context)
47
+ {
48
+ if (!$env->isDebug()) {
49
+ return;
50
+ }
51
+
52
+ ob_start();
53
+
54
+ $count = func_num_args();
55
+ if (2 === $count) {
56
+ $vars = array();
57
+ foreach ($context as $key => $value) {
58
+ if (!$value instanceof Twig_Template) {
59
+ $vars[$key] = $value;
60
+ }
61
+ }
62
+
63
+ var_dump($vars);
64
+ } else {
65
+ for ($i = 2; $i < $count; $i++) {
66
+ var_dump(func_get_arg($i));
67
+ }
68
+ }
69
+
70
+ return ob_get_clean();
71
+ }
classes/Twig/Extension/Escaper.php CHANGED
@@ -1,107 +1,107 @@
1
- <?php
2
-
3
- /*
4
- * This file is part of Twig.
5
- *
6
- * (c) 2009 Fabien Potencier
7
- *
8
- * For the full copyright and license information, please view the LICENSE
9
- * file that was distributed with this source code.
10
- */
11
- class Twig_Extension_Escaper extends Twig_Extension
12
- {
13
- protected $defaultStrategy;
14
-
15
- public function __construct($defaultStrategy = 'html')
16
- {
17
- $this->setDefaultStrategy($defaultStrategy);
18
- }
19
-
20
- /**
21
- * Returns the token parser instances to add to the existing list.
22
- *
23
- * @return array An array of Twig_TokenParserInterface or Twig_TokenParserBrokerInterface instances
24
- */
25
- public function getTokenParsers()
26
- {
27
- return array(new Twig_TokenParser_AutoEscape());
28
- }
29
-
30
- /**
31
- * Returns the node visitor instances to add to the existing list.
32
- *
33
- * @return Twig_NodeVisitorInterface[] An array of Twig_NodeVisitorInterface instances
34
- */
35
- public function getNodeVisitors()
36
- {
37
- return array(new Twig_NodeVisitor_Escaper());
38
- }
39
-
40
- /**
41
- * Returns a list of filters to add to the existing list.
42
- *
43
- * @return array An array of filters
44
- */
45
- public function getFilters()
46
- {
47
- return array(
48
- new Twig_SimpleFilter('raw', 'twig_raw_filter', array('is_safe' => array('all'))),
49
- );
50
- }
51
-
52
- /**
53
- * Sets the default strategy to use when not defined by the user.
54
- *
55
- * The strategy can be a valid PHP callback that takes the template
56
- * "filename" as an argument and returns the strategy to use.
57
- *
58
- * @param mixed $defaultStrategy An escaping strategy
59
- */
60
- public function setDefaultStrategy($defaultStrategy)
61
- {
62
- // for BC
63
- if (true === $defaultStrategy) {
64
- $defaultStrategy = 'html';
65
- }
66
-
67
- $this->defaultStrategy = $defaultStrategy;
68
- }
69
-
70
- /**
71
- * Gets the default strategy to use when not defined by the user.
72
- *
73
- * @param string $filename The template "filename"
74
- *
75
- * @return string The default strategy to use for the template
76
- */
77
- public function getDefaultStrategy($filename)
78
- {
79
- // disable string callables to avoid calling a function named html or js,
80
- // or any other upcoming escaping strategy
81
- if (!is_string($this->defaultStrategy) && is_callable($this->defaultStrategy)) {
82
- return call_user_func($this->defaultStrategy, $filename);
83
- }
84
-
85
- return $this->defaultStrategy;
86
- }
87
-
88
- /**
89
- * Returns the name of the extension.
90
- *
91
- * @return string The extension name
92
- */
93
- public function getName()
94
- {
95
- return 'escaper';
96
- }
97
- }
98
-
99
- /**
100
- * Marks a variable as being safe.
101
- *
102
- * @param string $string A PHP variable
103
- */
104
- function twig_raw_filter($string)
105
- {
106
- return $string;
107
- }
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2009 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+ class Twig_Extension_Escaper extends Twig_Extension
12
+ {
13
+ protected $defaultStrategy;
14
+
15
+ public function __construct($defaultStrategy = 'html')
16
+ {
17
+ $this->setDefaultStrategy($defaultStrategy);
18
+ }
19
+
20
+ /**
21
+ * Returns the token parser instances to add to the existing list.
22
+ *
23
+ * @return array An array of Twig_TokenParserInterface or Twig_TokenParserBrokerInterface instances
24
+ */
25
+ public function getTokenParsers()
26
+ {
27
+ return array(new Twig_TokenParser_AutoEscape());
28
+ }
29
+
30
+ /**
31
+ * Returns the node visitor instances to add to the existing list.
32
+ *
33
+ * @return Twig_NodeVisitorInterface[] An array of Twig_NodeVisitorInterface instances
34
+ */
35
+ public function getNodeVisitors()
36
+ {
37
+ return array(new Twig_NodeVisitor_Escaper());
38
+ }
39
+
40
+ /**
41
+ * Returns a list of filters to add to the existing list.
42
+ *
43
+ * @return array An array of filters
44
+ */
45
+ public function getFilters()
46
+ {
47
+ return array(
48
+ new Twig_SimpleFilter('raw', 'twig_raw_filter', array('is_safe' => array('all'))),
49
+ );
50
+ }
51
+
52
+ /**
53
+ * Sets the default strategy to use when not defined by the user.
54
+ *
55
+ * The strategy can be a valid PHP callback that takes the template
56
+ * "filename" as an argument and returns the strategy to use.
57
+ *
58
+ * @param mixed $defaultStrategy An escaping strategy
59
+ */
60
+ public function setDefaultStrategy($defaultStrategy)
61
+ {
62
+ // for BC
63
+ if (true === $defaultStrategy) {
64
+ $defaultStrategy = 'html';
65
+ }
66
+
67
+ $this->defaultStrategy = $defaultStrategy;
68
+ }
69
+
70
+ /**
71
+ * Gets the default strategy to use when not defined by the user.
72
+ *
73
+ * @param string $filename The template "filename"
74
+ *
75
+ * @return string The default strategy to use for the template
76
+ */
77
+ public function getDefaultStrategy($filename)
78
+ {
79
+ // disable string callables to avoid calling a function named html or js,
80
+ // or any other upcoming escaping strategy
81
+ if (!is_string($this->defaultStrategy) && is_callable($this->defaultStrategy)) {
82
+ return call_user_func($this->defaultStrategy, $filename);
83
+ }
84
+
85
+ return $this->defaultStrategy;
86
+ }
87
+
88
+ /**
89
+ * Returns the name of the extension.
90
+ *
91
+ * @return string The extension name
92
+ */
93
+ public function getName()
94
+ {
95
+ return 'escaper';
96
+ }
97
+ }
98
+
99
+ /**
100
+ * Marks a variable as being safe.
101
+ *
102
+ * @param string $string A PHP variable
103
+ */
104
+ function twig_raw_filter($string)
105
+ {
106
+ return $string;
107
+ }
classes/Twig/Extension/Optimizer.php CHANGED
@@ -1,35 +1,35 @@
1
- <?php
2
-
3
- /*
4
- * This file is part of Twig.
5
- *
6
- * (c) 2010 Fabien Potencier
7
- *
8
- * For the full copyright and license information, please view the LICENSE
9
- * file that was distributed with this source code.
10
- */
11
- class Twig_Extension_Optimizer extends Twig_Extension
12
- {
13
- protected $optimizers;
14
-
15
- public function __construct($optimizers = -1)
16
- {
17
- $this->optimizers = $optimizers;
18
- }
19
-
20
- /**
21
- * {@inheritdoc}
22
- */
23
- public function getNodeVisitors()
24
- {
25
- return array(new Twig_NodeVisitor_Optimizer($this->optimizers));
26
- }
27
-
28
- /**
29
- * {@inheritdoc}
30
- */
31
- public function getName()
32
- {
33
- return 'optimizer';
34
- }
35
- }
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2010 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+ class Twig_Extension_Optimizer extends Twig_Extension
12
+ {
13
+ protected $optimizers;
14
+
15
+ public function __construct($optimizers = -1)
16
+ {
17
+ $this->optimizers = $optimizers;
18
+ }
19
+
20
+ /**
21
+ * {@inheritdoc}
22
+ */
23
+ public function getNodeVisitors()
24
+ {
25
+ return array(new Twig_NodeVisitor_Optimizer($this->optimizers));
26
+ }
27
+
28
+ /**
29
+ * {@inheritdoc}
30
+ */
31
+ public function getName()
32
+ {
33
+ return 'optimizer';
34
+ }
35
+ }
classes/Twig/Extension/Sandbox.php CHANGED
@@ -1,112 +1,112 @@
1
- <?php
2
-
3
- /*
4
- * This file is part of Twig.
5
- *
6
- * (c) 2009 Fabien Potencier
7
- *
8
- * For the full copyright and license information, please view the LICENSE
9
- * file that was distributed with this source code.
10
- */
11
- class Twig_Extension_Sandbox extends Twig_Extension
12
- {
13
- protected $sandboxedGlobally;
14
- protected $sandboxed;
15
- protected $policy;
16
-
17
- public function __construct(Twig_Sandbox_SecurityPolicyInterface $policy, $sandboxed = false)
18
- {
19
- $this->policy = $policy;
20
- $this->sandboxedGlobally = $sandboxed;
21
- }
22
-
23
- /**
24
- * Returns the token parser instances to add to the existing list.
25
- *
26
- * @return array An array of Twig_TokenParserInterface or Twig_TokenParserBrokerInterface instances
27
- */
28
- public function getTokenParsers()
29
- {
30
- return array(new Twig_TokenParser_Sandbox());
31
- }
32
-
33
- /**
34
- * Returns the node visitor instances to add to the existing list.
35
- *
36
- * @return Twig_NodeVisitorInterface[] An array of Twig_NodeVisitorInterface instances
37
- */
38
- public function getNodeVisitors()
39
- {
40
- return array(new Twig_NodeVisitor_Sandbox());
41
- }
42
-
43
- public function enableSandbox()
44
- {
45
- $this->sandboxed = true;
46
- }
47
-
48
- public function disableSandbox()
49
- {
50
- $this->sandboxed = false;
51
- }
52
-
53
- public function isSandboxed()
54
- {
55
- return $this->sandboxedGlobally || $this->sandboxed;
56
- }
57
-
58
- public function isSandboxedGlobally()
59
- {
60
- return $this->sandboxedGlobally;
61
- }
62
-
63
- public function setSecurityPolicy(Twig_Sandbox_SecurityPolicyInterface $policy)
64
- {
65
- $this->policy = $policy;
66
- }
67
-
68
- public function getSecurityPolicy()
69
- {
70
- return $this->policy;
71
- }
72
-
73
- public function checkSecurity($tags, $filters, $functions)
74
- {
75
- if ($this->isSandboxed()) {
76
- $this->policy->checkSecurity($tags, $filters, $functions);
77
- }
78
- }
79
-
80
- public function checkMethodAllowed($obj, $method)
81
- {
82
- if ($this->isSandboxed()) {
83
- $this->policy->checkMethodAllowed($obj, $method);
84
- }
85
- }
86
-
87
- public function checkPropertyAllowed($obj, $method)
88
- {
89
- if ($this->isSandboxed()) {
90
- $this->policy->checkPropertyAllowed($obj, $method);
91
- }
92
- }
93
-
94
- public function ensureToStringAllowed($obj)
95
- {
96
- if ($this->isSandboxed() && is_object($obj)) {
97
- $this->policy->checkMethodAllowed($obj, '__toString');
98
- }
99
-
100
- return $obj;
101
- }
102
-
103
- /**
104
- * Returns the name of the extension.
105
- *
106
- * @return string The extension name
107
- */
108
- public function getName()
109
- {
110
- return 'sandbox';
111
- }
112
- }
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2009 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+ class Twig_Extension_Sandbox extends Twig_Extension
12
+ {
13
+ protected $sandboxedGlobally;
14
+ protected $sandboxed;
15
+ protected $policy;
16
+
17
+ public function __construct(Twig_Sandbox_SecurityPolicyInterface $policy, $sandboxed = false)
18
+ {
19
+ $this->policy = $policy;
20
+ $this->sandboxedGlobally = $sandboxed;
21
+ }
22
+
23
+ /**
24
+ * Returns the token parser instances to add to the existing list.
25
+ *
26
+ * @return array An array of Twig_TokenParserInterface or Twig_TokenParserBrokerInterface instances
27
+ */
28
+ public function getTokenParsers()
29
+ {
30
+ return array(new Twig_TokenParser_Sandbox());
31
+ }
32
+
33
+ /**
34
+ * Returns the node visitor instances to add to the existing list.
35
+ *
36
+ * @return Twig_NodeVisitorInterface[] An array of Twig_NodeVisitorInterface instances
37
+ */
38
+ public function getNodeVisitors()
39
+ {
40
+ return array(new Twig_NodeVisitor_Sandbox());
41
+ }
42
+
43
+ public function enableSandbox()
44
+ {
45
+ $this->sandboxed = true;
46
+ }
47
+
48
+ public function disableSandbox()
49
+ {
50
+ $this->sandboxed = false;
51
+ }
52
+
53
+ public function isSandboxed()
54
+ {
55
+ return $this->sandboxedGlobally || $this->sandboxed;
56
+ }
57
+
58
+ public function isSandboxedGlobally()
59
+ {
60
+ return $this->sandboxedGlobally;
61
+ }
62
+
63
+ public function setSecurityPolicy(Twig_Sandbox_SecurityPolicyInterface $policy)
64
+ {
65
+ $this->policy = $policy;
66
+ }
67
+
68
+ public function getSecurityPolicy()
69
+ {
70
+ return $this->policy;
71
+ }
72
+
73
+ public function checkSecurity($tags, $filters, $functions)
74
+ {
75
+ if ($this->isSandboxed()) {
76
+ $this->policy->checkSecurity($tags, $filters, $functions);
77
+ }
78
+ }
79
+
80
+ public function checkMethodAllowed($obj, $method)
81
+ {
82
+ if ($this->isSandboxed()) {
83
+ $this->policy->checkMethodAllowed($obj, $method);
84
+ }
85
+ }
86
+
87
+ public function checkPropertyAllowed($obj, $method)
88
+ {
89
+ if ($this->isSandboxed()) {
90
+ $this->policy->checkPropertyAllowed($obj, $method);
91
+ }
92
+ }
93
+
94
+ public function ensureToStringAllowed($obj)
95
+ {
96
+ if ($this->isSandboxed() && is_object($obj)) {
97
+ $this->policy->checkMethodAllowed($obj, '__toString');
98
+ }
99
+
100
+ return $obj;
101
+ }
102
+
103
+ /**
104
+ * Returns the name of the extension.
105
+ *
106
+ * @return string The extension name
107
+ */
108
+ public function getName()
109
+ {
110
+ return 'sandbox';
111
+ }
112
+ }
classes/Twig/Extension/Staging.php CHANGED
@@ -1,113 +1,113 @@
1
- <?php
2
-
3
- /*
4
- * This file is part of Twig.
5
- *
6
- * (c) 2012 Fabien Potencier
7
- *
8
- * For the full copyright and license information, please view the LICENSE
9
- * file that was distributed with this source code.
10
- */
11
-
12
- /**
13
- * Internal class.
14
- *
15
- * This class is used by Twig_Environment as a staging area and must not be used directly.
16
- *
17
- * @author Fabien Potencier <fabien@symfony.com>
18
- */
19
- class Twig_Extension_Staging extends Twig_Extension
20
- {
21
- protected $functions = array();
22
- protected $filters = array();
23
- protected $visitors = array();
24
- protected $tokenParsers = array();
25
- protected $globals = array();
26
- protected $tests = array();
27
-
28
- public function addFunction($name, $function)
29
- {
30
- $this->functions[$name] = $function;
31
- }
32
-
33
- /**
34
- * {@inheritdoc}
35
- */
36
- public function getFunctions()
37
- {
38
- return $this->functions;
39
- }
40
-
41
- public function addFilter($name, $filter)
42
- {
43
- $this->filters[$name] = $filter;
44
- }
45
-
46
- /**
47
- * {@inheritdoc}
48
- */
49
- public function getFilters()
50
- {
51
- return $this->filters;
52
- }
53
-
54
- public function addNodeVisitor(Twig_NodeVisitorInterface $visitor)
55
- {
56
- $this->visitors[] = $visitor;
57
- }
58
-
59
- /**
60
- * {@inheritdoc}
61
- */
62
- public function getNodeVisitors()
63
- {
64
- return $this->visitors;
65
- }
66
-
67
- public function addTokenParser(Twig_TokenParserInterface $parser)
68
- {
69
- $this->tokenParsers[] = $parser;
70
- }
71
-
72
- /**
73
- * {@inheritdoc}
74
- */
75
- public function getTokenParsers()
76
- {
77
- return $this->tokenParsers;
78
- }
79
-
80
- public function addGlobal($name, $value)
81
- {
82
- $this->globals[$name] = $value;
83
- }
84
-
85
- /**
86
- * {@inheritdoc}
87
- */
88
- public function getGlobals()
89
- {
90
- return $this->globals;
91
- }
92
-
93
- public function addTest($name, $test)
94
- {
95
- $this->tests[$name] = $test;
96
- }
97
-
98
- /**
99
- * {@inheritdoc}
100
- */
101
- public function getTests()
102
- {
103
- return $this->tests;
104
- }
105
-
106
- /**
107
- * {@inheritdoc}
108
- */
109
- public function getName()
110
- {
111
- return 'staging';
112
- }
113
- }
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2012 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ /**
13
+ * Internal class.
14
+ *
15
+ * This class is used by Twig_Environment as a staging area and must not be used directly.
16
+ *
17
+ * @author Fabien Potencier <fabien@symfony.com>
18
+ */
19
+ class Twig_Extension_Staging extends Twig_Extension
20
+ {
21
+ protected $functions = array();
22
+ protected $filters = array();
23
+ protected $visitors = array();
24
+ protected $tokenParsers = array();
25
+ protected $globals = array();
26
+ protected $tests = array();
27
+
28
+ public function addFunction($name, $function)
29
+ {
30
+ $this->functions[$name] = $function;
31
+ }
32
+
33
+ /**
34
+ * {@inheritdoc}
35
+ */
36
+ public function getFunctions()
37
+ {
38
+ return $this->functions;
39
+ }
40
+
41
+ public function addFilter($name, $filter)
42
+ {
43
+ $this->filters[$name] = $filter;
44
+ }
45
+
46
+ /**
47
+ * {@inheritdoc}
48
+ */
49
+ public function getFilters()
50
+ {
51
+ return $this->filters;
52
+ }
53
+
54
+ public function addNodeVisitor(Twig_NodeVisitorInterface $visitor)
55
+ {
56
+ $this->visitors[] = $visitor;
57
+ }
58
+
59
+ /**
60
+ * {@inheritdoc}
61
+ */
62
+ public function getNodeVisitors()
63
+ {
64
+ return $this->visitors;
65
+ }
66
+
67
+ public function addTokenParser(Twig_TokenParserInterface $parser)
68
+ {
69
+ $this->tokenParsers[] = $parser;
70
+ }
71
+
72
+ /**
73
+ * {@inheritdoc}
74
+ */
75
+ public function getTokenParsers()
76
+ {
77
+ return $this->tokenParsers;
78
+ }
79
+
80
+ public function addGlobal($name, $value)
81
+ {
82
+ $this->globals[$name] = $value;
83
+ }
84
+
85
+ /**
86
+ * {@inheritdoc}
87
+ */
88
+ public function getGlobals()
89
+ {
90
+ return $this->globals;
91
+ }
92
+
93
+ public function addTest($name, $test)
94
+ {
95
+ $this->tests[$name] = $test;
96
+ }
97
+
98
+ /**
99
+ * {@inheritdoc}
100
+ */
101
+ public function getTests()
102
+ {
103
+ return $this->tests;
104
+ }
105
+
106
+ /**
107
+ * {@inheritdoc}
108
+ */
109
+ public function getName()
110
+ {
111
+ return 'staging';
112
+ }
113
+ }
classes/Twig/Extension/StringLoader.php CHANGED
@@ -1,64 +1,64 @@
1
- <?php
2
-
3
- /*
4
- * This file is part of Twig.
5
- *
6
- * (c) 2012 Fabien Potencier
7
- *
8
- * For the full copyright and license information, please view the LICENSE
9
- * file that was distributed with this source code.
10
- */
11
- class Twig_Extension_StringLoader extends Twig_Extension
12
- {
13
- /**
14
- * {@inheritdoc}
15
- */
16
- public function getFunctions()
17
- {
18
- return array(
19
- new Twig_SimpleFunction('template_from_string', 'twig_template_from_string', array('needs_environment' => true)),
20
- );
21
- }
22
-
23
- /**
24
- * {@inheritdoc}
25
- */
26
- public function getName()
27
- {
28
- return 'string_loader';
29
- }
30
- }
31
-
32
- /**
33
- * Loads a template from a string.
34
- *
35
- * <pre>
36
- * {{ include(template_from_string("Hello {{ name }}")) }}
37
- * </pre>
38
- *
39
- * @param Twig_Environment $env A Twig_Environment instance
40
- * @param string $template A template as a string
41
- *
42
- * @return Twig_Template A Twig_Template instance
43
- */
44
- function twig_template_from_string(Twig_Environment $env, $template)
45
- {
46
- $name = sprintf('__string_template__%s', hash('sha256', uniqid(mt_rand(), true), false));
47
-
48
- $loader = new Twig_Loader_Chain(array(
49
- new Twig_Loader_Array(array($name => $template)),
50
- $current = $env->getLoader(),
51
- ));
52
-
53
- $env->setLoader($loader);
54
- try {
55
- $template = $env->loadTemplate($name);
56
- } catch (Exception $e) {
57
- $env->setLoader($current);
58
-
59
- throw $e;
60
- }
61
- $env->setLoader($current);
62
-
63
- return $template;
64
- }
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2012 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+ class Twig_Extension_StringLoader extends Twig_Extension
12
+ {
13
+ /**
14
+ * {@inheritdoc}
15
+ */
16
+ public function getFunctions()
17
+ {
18
+ return array(
19
+ new Twig_SimpleFunction('template_from_string', 'twig_template_from_string', array('needs_environment' => true)),
20
+ );
21
+ }
22
+
23
+ /**
24
+ * {@inheritdoc}
25
+ */
26
+ public function getName()
27
+ {
28
+ return 'string_loader';
29
+ }
30
+ }
31
+
32
+ /**
33
+ * Loads a template from a string.
34
+ *
35
+ * <pre>
36
+ * {{ include(template_from_string("Hello {{ name }}")) }}
37
+ * </pre>
38
+ *
39
+ * @param Twig_Environment $env A Twig_Environment instance
40
+ * @param string $template A template as a string
41
+ *
42
+ * @return Twig_Template A Twig_Template instance
43
+ */
44
+ function twig_template_from_string(Twig_Environment $env, $template)
45
+ {
46
+ $name = sprintf('__string_template__%s', hash('sha256', uniqid(mt_rand(), true), false));
47
+
48
+ $loader = new Twig_Loader_Chain(array(
49
+ new Twig_Loader_Array(array($name => $template)),
50
+ $current = $env->getLoader(),
51
+ ));
52
+
53
+ $env->setLoader($loader);
54
+ try {
55
+ $template = $env->loadTemplate($name);
56
+ } catch (Exception $e) {
57
+ $env->setLoader($current);
58
+
59
+ throw $e;
60
+ }
61
+ $env->setLoader($current);
62
+
63
+ return $template;
64
+ }
classes/Twig/ExtensionInterface.php CHANGED
@@ -1,83 +1,83 @@
1
- <?php
2
-
3
- /*
4
- * This file is part of Twig.
5
- *
6
- * (c) 2009 Fabien Potencier
7
- *
8
- * For the full copyright and license information, please view the LICENSE
9
- * file that was distributed with this source code.
10
- */
11
-
12
- /**
13
- * Interface implemented by extension classes.
14
- *
15
- * @author Fabien Potencier <fabien@symfony.com>
16
- */
17
- interface Twig_ExtensionInterface
18
- {
19
- /**
20
- * Initializes the runtime environment.
21
- *
22
- * This is where you can load some file that contains filter functions for instance.
23
- *
24
- * @param Twig_Environment $environment The current Twig_Environment instance
25
- */
26
- public function initRuntime(Twig_Environment $environment);
27
-
28
- /**
29
- * Returns the token parser instances to add to the existing list.
30
- *
31
- * @return array An array of Twig_TokenParserInterface or Twig_TokenParserBrokerInterface instances
32
- */
33
- public function getTokenParsers();
34
-
35
- /**
36
- * Returns the node visitor instances to add to the existing list.
37
- *
38
- * @return Twig_NodeVisitorInterface[] An array of Twig_NodeVisitorInterface instances
39
- */
40
- public function getNodeVisitors();
41
-
42
- /**
43
- * Returns a list of filters to add to the existing list.
44
- *
45
- * @return array An array of filters
46
- */
47
- public function getFilters();
48
-
49
- /**
50
- * Returns a list of tests to add to the existing list.
51
- *
52
- * @return array An array of tests
53
- */
54
- public function getTests();
55
-
56
- /**
57
- * Returns a list of functions to add to the existing list.
58
- *
59
- * @return array An array of functions
60
- */
61
- public function getFunctions();
62
-
63
- /**
64
- * Returns a list of operators to add to the existing list.
65
- *
66
- * @return array An array of operators
67
- */
68
- public function getOperators();
69
-
70
- /**
71
- * Returns a list of global variables to add to the existing list.
72
- *
73
- * @return array An array of global variables
74
- */
75
- public function getGlobals();
76
-
77
- /**
78
- * Returns the name of the extension.
79
- *
80
- * @return string The extension name
81
- */
82
- public function getName();
83
- }
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2009 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ /**
13
+ * Interface implemented by extension classes.
14
+ *
15
+ * @author Fabien Potencier <fabien@symfony.com>
16
+ */
17
+ interface Twig_ExtensionInterface
18
+ {
19
+ /**
20
+ * Initializes the runtime environment.
21
+ *
22
+ * This is where you can load some file that contains filter functions for instance.
23
+ *
24
+ * @param Twig_Environment $environment The current Twig_Environment instance
25
+ */
26
+ public function initRuntime(Twig_Environment $environment);
27
+
28
+ /**
29
+ * Returns the token parser instances to add to the existing list.
30
+ *
31
+ * @return array An array of Twig_TokenParserInterface or Twig_TokenParserBrokerInterface instances
32
+ */
33
+ public function getTokenParsers();
34
+
35
+ /**
36
+ * Returns the node visitor instances to add to the existing list.
37
+ *
38
+ * @return Twig_NodeVisitorInterface[] An array of Twig_NodeVisitorInterface instances
39
+ */
40
+ public function getNodeVisitors();
41
+
42
+ /**
43
+ * Returns a list of filters to add to the existing list.
44
+ *
45
+ * @return array An array of filters
46
+ */
47
+ public function getFilters();
48
+
49
+ /**
50
+ * Returns a list of tests to add to the existing list.
51
+ *
52
+ * @return array An array of tests
53
+ */
54
+ public function getTests();
55
+
56
+ /**
57
+ * Returns a list of functions to add to the existing list.
58
+ *
59
+ * @return array An array of functions
60
+ */
61
+ public function getFunctions();
62
+
63
+ /**
64
+ * Returns a list of operators to add to the existing list.
65
+ *
66
+ * @return array An array of operators
67
+ */
68
+ public function getOperators();
69
+
70
+ /**
71
+ * Returns a list of global variables to add to the existing list.
72
+ *
73
+ * @return array An array of global variables
74
+ */
75
+ public function getGlobals();
76
+
77
+ /**
78
+ * Returns the name of the extension.
79
+ *
80
+ * @return string The extension name
81
+ */
82
+ public function getName();
83
+ }
classes/Twig/Filter.php CHANGED
@@ -1,81 +1,81 @@
1
- <?php
2
-
3
- /*
4
- * This file is part of Twig.
5
- *
6
- * (c) 2009 Fabien Potencier
7
- *
8
- * For the full copyright and license information, please view the LICENSE
9
- * file that was distributed with this source code.
10
- */
11
-
12
- /**
13
- * Represents a template filter.
14
- *
15
- * Use Twig_SimpleFilter instead.
16
- *
17
- * @author Fabien Potencier <fabien@symfony.com>
18
- * @deprecated since 1.12 (to be removed in 2.0)
19
- */
20
- abstract class Twig_Filter implements Twig_FilterInterface, Twig_FilterCallableInterface
21
- {
22
- protected $options;
23
- protected $arguments = array();
24
-
25
- public function __construct(array $options = array())
26
- {
27
- $this->options = array_merge(array(
28
- 'needs_environment' => false,
29
- 'needs_context' => false,
30
- 'pre_escape' => null,
31
- 'preserves_safety' => null,
32
- 'callable' => null,
33
- ), $options);
34
- }
35
-
36
- public function setArguments($arguments)
37
- {
38
- $this->arguments = $arguments;
39
- }
40
-
41
- public function getArguments()
42
- {
43
- return $this->arguments;
44
- }
45
-
46
- public function needsEnvironment()
47
- {
48
- return $this->options['needs_environment'];
49
- }
50
-
51
- public function needsContext()
52
- {
53
- return $this->options['needs_context'];
54
- }
55
-
56
- public function getSafe(Twig_Node $filterArgs)
57
- {
58
- if (isset($this->options['is_safe'])) {
59
- return $this->options['is_safe'];
60
- }
61
-
62
- if (isset($this->options['is_safe_callback'])) {
63
- return call_user_func($this->options['is_safe_callback'], $filterArgs);
64
- }
65
- }
66
-
67
- public function getPreservesSafety()
68
- {
69
- return $this->options['preserves_safety'];
70
- }
71
-
72
- public function getPreEscape()
73
- {
74
- return $this->options['pre_escape'];
75
- }
76
-
77
- public function getCallable()
78
- {
79
- return $this->options['callable'];
80
- }
81
- }
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2009 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ /**
13
+ * Represents a template filter.
14
+ *
15
+ * Use Twig_SimpleFilter instead.
16
+ *
17
+ * @author Fabien Potencier <fabien@symfony.com>
18
+ * @deprecated since 1.12 (to be removed in 2.0)
19
+ */
20
+ abstract class Twig_Filter implements Twig_FilterInterface, Twig_FilterCallableInterface
21
+ {
22
+ protected $options;
23
+ protected $arguments = array();
24
+
25
+ public function __construct(array $options = array())
26
+ {
27
+ $this->options = array_merge(array(
28
+ 'needs_environment' => false,
29
+ 'needs_context' => false,
30
+ 'pre_escape' => null,
31
+ 'preserves_safety' => null,
32
+ 'callable' => null,
33
+ ), $options);
34
+ }
35
+
36
+ public function setArguments($arguments)
37
+ {
38
+ $this->arguments = $arguments;
39
+ }
40
+
41
+ public function getArguments()
42
+ {
43
+ return $this->arguments;
44
+ }
45
+
46
+ public function needsEnvironment()
47
+ {
48
+ return $this->options['needs_environment'];
49
+ }
50
+
51
+ public function needsContext()
52
+ {
53
+ return $this->options['needs_context'];
54
+ }
55
+
56
+ public function getSafe(Twig_Node $filterArgs)
57
+ {
58
+ if (isset($this->options['is_safe'])) {
59
+ return $this->options['is_safe'];
60
+ }
61
+
62
+ if (isset($this->options['is_safe_callback'])) {
63
+ return call_user_func($this->options['is_safe_callback'], $filterArgs);
64
+ }
65
+ }
66
+
67
+ public function getPreservesSafety()
68
+ {
69
+ return $this->options['preserves_safety'];
70
+ }
71
+
72
+ public function getPreEscape()
73
+ {
74
+ return $this->options['pre_escape'];
75
+ }
76
+
77
+ public function getCallable()
78
+ {
79
+ return $this->options['callable'];
80
+ }
81
+ }
classes/Twig/Filter/Function.php CHANGED
@@ -1,37 +1,37 @@
1
- <?php
2
-
3
- /*
4
- * This file is part of Twig.
5
- *
6
- * (c) 2009 Fabien Potencier
7
- *
8
- * For the full copyright and license information, please view the LICENSE
9
- * file that was distributed with this source code.
10
- */
11
-
12
- /**
13
- * Represents a function template filter.
14
- *
15
- * Use Twig_SimpleFilter instead.
16
- *
17
- * @author Fabien Potencier <fabien@symfony.com>
18
- * @deprecated since 1.12 (to be removed in 2.0)
19
- */
20
- class Twig_Filter_Function extends Twig_Filter
21
- {
22
- protected $function;
23
-
24
- public function __construct($function, array $options = array())
25
- {
26
- $options['callable'] = $function;
27
-
28
- parent::__construct($options);
29
-
30
- $this->function = $function;
31
- }
32
-
33
- public function compile()
34
- {
35
- return $this->function;
36
- }
37
- }
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2009 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ /**
13
+ * Represents a function template filter.
14
+ *
15
+ * Use Twig_SimpleFilter instead.
16
+ *
17
+ * @author Fabien Potencier <fabien@symfony.com>
18
+ * @deprecated since 1.12 (to be removed in 2.0)
19
+ */
20
+ class Twig_Filter_Function extends Twig_Filter
21
+ {
22
+ protected $function;
23
+
24
+ public function __construct($function, array $options = array())
25
+ {
26
+ $options['callable'] = $function;
27
+
28
+ parent::__construct($options);
29
+
30
+ $this->function = $function;
31
+ }
32
+
33
+ public function compile()
34
+ {
35
+ return $this->function;
36
+ }
37
+ }
classes/Twig/Filter/Method.php CHANGED
@@ -1,39 +1,39 @@
1
- <?php
2
-
3
- /*
4
- * This file is part of Twig.
5
- *
6
- * (c) 2009 Fabien Potencier
7
- *
8
- * For the full copyright and license information, please view the LICENSE
9
- * file that was distributed with this source code.
10
- */
11
-
12
- /**
13
- * Represents a method template filter.
14
- *
15
- * Use Twig_SimpleFilter instead.
16
- *
17
- * @author Fabien Potencier <fabien@symfony.com>
18
- * @deprecated since 1.12 (to be removed in 2.0)
19
- */
20
- class Twig_Filter_Method extends Twig_Filter
21
- {
22
- protected $extension;
23
- protected $method;
24
-
25
- public function __construct(Twig_ExtensionInterface $extension, $method, array $options = array())
26
- {
27
- $options['callable'] = array($extension, $method);
28
-
29
- parent::__construct($options);
30
-
31
- $this->extension = $extension;
32
- $this->method = $method;
33
- }
34
-
35
- public function compile()
36
- {
37
- return sprintf('$this->env->getExtension(\'%s\')->%s', $this->extension->getName(), $this->method);
38
- }
39
- }
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2009 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ /**
13
+ * Represents a method template filter.
14
+ *
15
+ * Use Twig_SimpleFilter instead.
16
+ *
17
+ * @author Fabien Potencier <fabien@symfony.com>
18
+ * @deprecated since 1.12 (to be removed in 2.0)
19
+ */
20
+ class Twig_Filter_Method extends Twig_Filter
21
+ {
22
+ protected $extension;
23
+ protected $method;
24
+
25
+ public function __construct(Twig_ExtensionInterface $extension, $method, array $options = array())
26
+ {
27
+ $options['callable'] = array($extension, $method);
28
+
29
+ parent::__construct($options);
30
+
31
+ $this->extension = $extension;
32
+ $this->method = $method;
33
+ }
34
+
35
+ public function compile()
36
+ {
37
+ return sprintf('$this->env->getExtension(\'%s\')->%s', $this->extension->getName(), $this->method);
38
+ }
39
+ }
classes/Twig/Filter/Node.php CHANGED
@@ -1,39 +1,39 @@
1
- <?php
2
-
3
- /*
4
- * This file is part of Twig.
5
- *
6
- * (c) 2011 Fabien Potencier
7
- *
8
- * For the full copyright and license information, please view the LICENSE
9
- * file that was distributed with this source code.
10
- */
11
-
12
- /**
13
- * Represents a template filter as a node.
14
- *
15
- * Use Twig_SimpleFilter instead.
16
- *
17
- * @author Fabien Potencier <fabien@symfony.com>
18
- * @deprecated since 1.12 (to be removed in 2.0)
19
- */
20
- class Twig_Filter_Node extends Twig_Filter
21
- {
22
- protected $class;
23
-
24
- public function __construct($class, array $options = array())
25
- {
26
- parent::__construct($options);
27
-
28
- $this->class = $class;
29
- }
30
-
31
- public function getClass()
32
- {
33
- return $this->class;
34
- }
35
-
36
- public function compile()
37
- {
38
- }
39
- }
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2011 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ /**
13
+ * Represents a template filter as a node.
14
+ *
15
+ * Use Twig_SimpleFilter instead.
16
+ *
17
+ * @author Fabien Potencier <fabien@symfony.com>
18
+ * @deprecated since 1.12 (to be removed in 2.0)
19
+ */
20
+ class Twig_Filter_Node extends Twig_Filter
21
+ {
22
+ protected $class;
23
+
24
+ public function __construct($class, array $options = array())
25
+ {
26
+ parent::__construct($options);
27
+
28
+ $this->class = $class;
29
+ }
30
+
31
+ public function getClass()
32
+ {
33
+ return $this->class;
34
+ }
35
+
36
+ public function compile()
37
+ {
38
+ }
39
+ }
classes/Twig/FilterCallableInterface.php CHANGED
@@ -1,23 +1,23 @@
1
- <?php
2
-
3
- /*
4
- * This file is part of Twig.
5
- *
6
- * (c) 2012 Fabien Potencier
7
- *
8
- * For the full copyright and license information, please view the LICENSE
9
- * file that was distributed with this source code.
10
- */
11
-
12
- /**
13
- * Represents a callable template filter.
14
- *
15
- * Use Twig_SimpleFilter instead.
16
- *
17
- * @author Fabien Potencier <fabien@symfony.com>
18
- * @deprecated since 1.12 (to be removed in 2.0)
19
- */
20
- interface Twig_FilterCallableInterface
21
- {
22
- public function getCallable();
23
- }
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2012 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ /**
13
+ * Represents a callable template filter.
14
+ *
15
+ * Use Twig_SimpleFilter instead.
16
+ *
17
+ * @author Fabien Potencier <fabien@symfony.com>
18
+ * @deprecated since 1.12 (to be removed in 2.0)
19
+ */
20
+ interface Twig_FilterCallableInterface
21
+ {
22
+ public function getCallable();
23
+ }
classes/Twig/FilterInterface.php CHANGED
@@ -1,42 +1,42 @@
1
- <?php
2
-
3
- /*
4
- * This file is part of Twig.
5
- *
6
- * (c) 2010 Fabien Potencier
7
- *
8
- * For the full copyright and license information, please view the LICENSE
9
- * file that was distributed with this source code.
10
- */
11
-
12
- /**
13
- * Represents a template filter.
14
- *
15
- * Use Twig_SimpleFilter instead.
16
- *
17
- * @author Fabien Potencier <fabien@symfony.com>
18
- * @deprecated since 1.12 (to be removed in 2.0)
19
- */
20
- interface Twig_FilterInterface
21
- {
22
- /**
23
- * Compiles a filter.
24
- *
25
- * @return string The PHP code for the filter
26
- */
27
- public function compile();
28
-
29
- public function needsEnvironment();
30
-
31
- public function needsContext();
32
-
33
- public function getSafe(Twig_Node $filterArgs);
34
-
35
- public function getPreservesSafety();
36
-
37
- public function getPreEscape();
38
-
39
- public function setArguments($arguments);
40
-
41
- public function getArguments();
42
- }
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2010 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ /**
13
+ * Represents a template filter.
14
+ *
15
+ * Use Twig_SimpleFilter instead.
16
+ *
17
+ * @author Fabien Potencier <fabien@symfony.com>
18
+ * @deprecated since 1.12 (to be removed in 2.0)
19
+ */
20
+ interface Twig_FilterInterface
21
+ {
22
+ /**
23
+ * Compiles a filter.
24
+ *
25
+ * @return string The PHP code for the filter
26
+ */
27
+ public function compile();
28
+
29
+ public function needsEnvironment();
30
+
31
+ public function needsContext();
32
+
33
+ public function getSafe(Twig_Node $filterArgs);
34
+
35
+ public function getPreservesSafety();
36
+
37
+ public function getPreEscape();
38
+
39
+ public function setArguments($arguments);
40
+
41
+ public function getArguments();
42
+ }
classes/Twig/Function.php CHANGED
@@ -1,71 +1,71 @@
1
- <?php
2
-
3
- /*
4
- * This file is part of Twig.
5
- *
6
- * (c) 2010 Fabien Potencier
7
- *
8
- * For the full copyright and license information, please view the LICENSE
9
- * file that was distributed with this source code.
10
- */
11
-
12
- /**
13
- * Represents a template function.
14
- *
15
- * Use Twig_SimpleFunction instead.
16
- *
17
- * @author Fabien Potencier <fabien@symfony.com>
18
- * @deprecated since 1.12 (to be removed in 2.0)
19
- */
20
- abstract class Twig_Function implements Twig_FunctionInterface, Twig_FunctionCallableInterface
21
- {
22
- protected $options;
23
- protected $arguments = array();
24
-
25
- public function __construct(array $options = array())
26
- {
27
- $this->options = array_merge(array(
28
- 'needs_environment' => false,
29
- 'needs_context' => false,
30
- 'callable' => null,
31
- ), $options);
32
- }
33
-
34
- public function setArguments($arguments)
35
- {
36
- $this->arguments = $arguments;
37
- }
38
-
39
- public function getArguments()
40
- {
41
- return $this->arguments;
42
- }
43
-
44
- public function needsEnvironment()
45
- {
46
- return $this->options['needs_environment'];
47
- }
48
-
49
- public function needsContext()
50
- {
51
- return $this->options['needs_context'];
52
- }
53
-
54
- public function getSafe(Twig_Node $functionArgs)
55
- {
56
- if (isset($this->options['is_safe'])) {
57
- return $this->options['is_safe'];
58
- }
59
-
60
- if (isset($this->options['is_safe_callback'])) {
61
- return call_user_func($this->options['is_safe_callback'], $functionArgs);
62
- }
63
-
64
- return array();
65
- }
66
-
67
- public function getCallable()
68
- {
69
- return $this->options['callable'];
70
- }
71
- }
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2010 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ /**
13
+ * Represents a template function.
14
+ *
15
+ * Use Twig_SimpleFunction instead.
16
+ *
17
+ * @author Fabien Potencier <fabien@symfony.com>
18
+ * @deprecated since 1.12 (to be removed in 2.0)
19
+ */
20
+ abstract class Twig_Function implements Twig_FunctionInterface, Twig_FunctionCallableInterface
21
+ {
22
+ protected $options;
23
+ protected $arguments = array();
24
+
25
+ public function __construct(array $options = array())
26
+ {
27
+ $this->options = array_merge(array(
28
+ 'needs_environment' => false,
29
+ 'needs_context' => false,
30
+ 'callable' => null,
31
+ ), $options);
32
+ }
33
+
34
+ public function setArguments($arguments)
35
+ {
36
+ $this->arguments = $arguments;
37
+ }
38
+
39
+ public function getArguments()
40
+ {
41
+ return $this->arguments;
42
+ }
43
+
44
+ public function needsEnvironment()
45
+ {
46
+ return $this->options['needs_environment'];
47
+ }
48
+
49
+ public function needsContext()
50
+ {
51
+ return $this->options['needs_context'];
52
+ }
53
+
54
+ public function getSafe(Twig_Node $functionArgs)
55
+ {
56
+ if (isset($this->options['is_safe'])) {
57
+ return $this->options['is_safe'];
58
+ }
59
+
60
+ if (isset($this->options['is_safe_callback'])) {
61
+ return call_user_func($this->options['is_safe_callback'], $functionArgs);
62
+ }
63
+
64
+ return array();
65
+ }
66
+
67
+ public function getCallable()
68
+ {
69
+ return $this->options['callable'];
70
+ }
71
+ }
classes/Twig/Function/Function.php CHANGED
@@ -1,38 +1,38 @@
1
- <?php
2
-
3
- /*
4
- * This file is part of Twig.
5
- *
6
- * (c) 2009 Fabien Potencier
7
- * (c) 2010 Arnaud Le Blanc
8
- *
9
- * For the full copyright and license information, please view the LICENSE
10
- * file that was distributed with this source code.
11
- */
12
-
13
- /**
14
- * Represents a function template function.
15
- *
16
- * Use Twig_SimpleFunction instead.
17
- *
18
- * @author Arnaud Le Blanc <arnaud.lb@gmail.com>
19
- * @deprecated since 1.12 (to be removed in 2.0)
20
- */
21
- class Twig_Function_Function extends Twig_Function
22
- {
23
- protected $function;
24
-
25
- public function __construct($function, array $options = array())
26
- {
27
- $options['callable'] = $function;
28
-
29
- parent::__construct($options);
30
-
31
- $this->function = $function;
32
- }
33
-
34
- public function compile()
35
- {
36
- return $this->function;
37
- }
38
- }
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2009 Fabien Potencier
7
+ * (c) 2010 Arnaud Le Blanc
8
+ *
9
+ * For the full copyright and license information, please view the LICENSE
10
+ * file that was distributed with this source code.
11
+ */
12
+
13
+ /**
14
+ * Represents a function template function.
15
+ *
16
+ * Use Twig_SimpleFunction instead.
17
+ *
18
+ * @author Arnaud Le Blanc <arnaud.lb@gmail.com>
19
+ * @deprecated since 1.12 (to be removed in 2.0)
20
+ */
21
+ class Twig_Function_Function extends Twig_Function
22
+ {
23
+ protected $function;
24
+
25
+ public function __construct($function, array $options = array())
26
+ {
27
+ $options['callable'] = $function;
28
+
29
+ parent::__construct($options);
30
+
31
+ $this->function = $function;
32
+ }
33
+
34
+ public function compile()
35
+ {
36
+ return $this->function;
37
+ }
38
+ }
classes/Twig/Function/Method.php CHANGED
@@ -1,40 +1,40 @@
1
- <?php
2
-
3
- /*
4
- * This file is part of Twig.
5
- *
6
- * (c) 2009 Fabien Potencier
7
- * (c) 2010 Arnaud Le Blanc
8
- *
9
- * For the full copyright and license information, please view the LICENSE
10
- * file that was distributed with this source code.
11
- */
12
-
13
- /**
14
- * Represents a method template function.
15
- *
16
- * Use Twig_SimpleFunction instead.
17
- *
18
- * @author Arnaud Le Blanc <arnaud.lb@gmail.com>
19
- * @deprecated since 1.12 (to be removed in 2.0)
20
- */
21
- class Twig_Function_Method extends Twig_Function
22
- {
23
- protected $extension;
24
- protected $method;
25
-
26
- public function __construct(Twig_ExtensionInterface $extension, $method, array $options = array())
27
- {
28
- $options['callable'] = array($extension, $method);
29
-
30
- parent::__construct($options);
31
-
32
- $this->extension = $extension;
33
- $this->method = $method;
34
- }
35
-
36
- public function compile()
37
- {
38
- return sprintf('$this->env->getExtension(\'%s\')->%s', $this->extension->getName(), $this->method);
39
- }
40
- }
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2009 Fabien Potencier
7
+ * (c) 2010 Arnaud Le Blanc
8
+ *
9
+ * For the full copyright and license information, please view the LICENSE
10
+ * file that was distributed with this source code.
11
+ */
12
+
13
+ /**
14
+ * Represents a method template function.
15
+ *
16
+ * Use Twig_SimpleFunction instead.
17
+ *
18
+ * @author Arnaud Le Blanc <arnaud.lb@gmail.com>
19
+ * @deprecated since 1.12 (to be removed in 2.0)
20
+ */
21
+ class Twig_Function_Method extends Twig_Function
22
+ {
23
+ protected $extension;
24
+ protected $method;
25
+
26
+ public function __construct(Twig_ExtensionInterface $extension, $method, array $options = array())
27
+ {
28
+ $options['callable'] = array($extension, $method);
29
+
30
+ parent::__construct($options);
31
+
32
+ $this->extension = $extension;
33
+ $this->method = $method;
34
+ }
35
+
36
+ public function compile()
37
+ {
38
+ return sprintf('$this->env->getExtension(\'%s\')->%s', $this->extension->getName(), $this->method);
39
+ }
40
+ }
classes/Twig/Function/Node.php CHANGED
@@ -1,39 +1,39 @@
1
- <?php
2
-
3
- /*
4
- * This file is part of Twig.
5
- *
6
- * (c) 2011 Fabien Potencier
7
- *
8
- * For the full copyright and license information, please view the LICENSE
9
- * file that was distributed with this source code.
10
- */
11
-
12
- /**
13
- * Represents a template function as a node.
14
- *
15
- * Use Twig_SimpleFunction instead.
16
- *
17
- * @author Fabien Potencier <fabien@symfony.com>
18
- * @deprecated since 1.12 (to be removed in 2.0)
19
- */
20
- class Twig_Function_Node extends Twig_Function
21
- {
22
- protected $class;
23
-
24
- public function __construct($class, array $options = array())
25
- {
26
- parent::__construct($options);
27
-
28
- $this->class = $class;
29
- }
30
-
31
- public function getClass()
32
- {
33
- return $this->class;
34
- }
35
-
36
- public function compile()
37
- {
38
- }
39
- }
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2011 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ /**
13
+ * Represents a template function as a node.
14
+ *
15
+ * Use Twig_SimpleFunction instead.
16
+ *
17
+ * @author Fabien Potencier <fabien@symfony.com>
18
+ * @deprecated since 1.12 (to be removed in 2.0)
19
+ */
20
+ class Twig_Function_Node extends Twig_Function
21
+ {
22
+ protected $class;
23
+
24
+ public function __construct($class, array $options = array())
25
+ {
26
+ parent::__construct($options);
27
+
28
+ $this->class = $class;
29
+ }
30
+
31
+ public function getClass()
32
+ {
33
+ return $this->class;
34
+ }
35
+
36
+ public function compile()
37
+ {
38
+ }
39
+ }
classes/Twig/FunctionCallableInterface.php CHANGED
@@ -1,23 +1,23 @@
1
- <?php
2
-
3
- /*
4
- * This file is part of Twig.
5
- *
6
- * (c) 2012 Fabien Potencier
7
- *
8
- * For the full copyright and license information, please view the LICENSE
9
- * file that was distributed with this source code.
10
- */
11
-
12
- /**
13
- * Represents a callable template function.
14
- *
15
- * Use Twig_SimpleFunction instead.
16
- *
17
- * @author Fabien Potencier <fabien@symfony.com>
18
- * @deprecated since 1.12 (to be removed in 2.0)
19
- */
20
- interface Twig_FunctionCallableInterface
21
- {
22
- public function getCallable();
23
- }
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2012 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ /**
13
+ * Represents a callable template function.
14
+ *
15
+ * Use Twig_SimpleFunction instead.
16
+ *
17
+ * @author Fabien Potencier <fabien@symfony.com>
18
+ * @deprecated since 1.12 (to be removed in 2.0)
19
+ */
20
+ interface Twig_FunctionCallableInterface
21
+ {
22
+ public function getCallable();
23
+ }
classes/Twig/FunctionInterface.php CHANGED
@@ -1,39 +1,39 @@
1
- <?php
2
-
3
- /*
4
- * This file is part of Twig.
5
- *
6
- * (c) 2010 Fabien Potencier
7
- * (c) 2010 Arnaud Le Blanc
8
- *
9
- * For the full copyright and license information, please view the LICENSE
10
- * file that was distributed with this source code.
11
- */
12
-
13
- /**
14
- * Represents a template function.
15
- *
16
- * Use Twig_SimpleFunction instead.
17
- *
18
- * @author Arnaud Le Blanc <arnaud.lb@gmail.com>
19
- * @deprecated since 1.12 (to be removed in 2.0)
20
- */
21
- interface Twig_FunctionInterface
22
- {
23
- /**
24
- * Compiles a function.
25
- *
26
- * @return string The PHP code for the function
27
- */
28
- public function compile();
29
-
30
- public function needsEnvironment();
31
-
32
- public function needsContext();
33
-
34
- public function getSafe(Twig_Node $filterArgs);
35
-
36
- public function setArguments($arguments);
37
-
38
- public function getArguments();
39
- }
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2010 Fabien Potencier
7
+ * (c) 2010 Arnaud Le Blanc
8
+ *
9
+ * For the full copyright and license information, please view the LICENSE
10
+ * file that was distributed with this source code.
11
+ */
12
+
13
+ /**
14
+ * Represents a template function.
15
+ *
16
+ * Use Twig_SimpleFunction instead.
17
+ *
18
+ * @author Arnaud Le Blanc <arnaud.lb@gmail.com>
19
+ * @deprecated since 1.12 (to be removed in 2.0)
20
+ */
21
+ interface Twig_FunctionInterface
22
+ {
23
+ /**
24
+ * Compiles a function.
25
+ *
26
+ * @return string The PHP code for the function
27
+ */
28
+ public function compile();
29
+
30
+ public function needsEnvironment();
31
+
32
+ public function needsContext();
33
+
34
+ public function getSafe(Twig_Node $filterArgs);
35
+
36
+ public function setArguments($arguments);
37
+
38
+ public function getArguments();
39
+ }
classes/Twig/Lexer.php CHANGED
@@ -1,409 +1,409 @@
1
- <?php
2
-
3
- /*
4
- * This file is part of Twig.
5
- *
6
- * (c) 2009 Fabien Potencier
7
- * (c) 2009 Armin Ronacher
8
- *
9
- * For the full copyright and license information, please view the LICENSE
10
- * file that was distributed with this source code.
11
- */
12
-
13
- /**
14
- * Lexes a template string.
15
- *
16
- * @author Fabien Potencier <fabien@symfony.com>
17
- */
18
- class Twig_Lexer implements Twig_LexerInterface
19
- {
20
- protected $tokens;
21
- protected $code;
22
- protected $cursor;
23
- protected $lineno;
24
- protected $end;
25
- protected $state;
26
- protected $states;
27
- protected $brackets;
28
- protected $env;
29
- protected $filename;
30
- protected $options;
31
- protected $regexes;
32
- protected $position;
33
- protected $positions;
34
- protected $currentVarBlockLine;
35
-
36
- const STATE_DATA = 0;
37
- const STATE_BLOCK = 1;
38
- const STATE_VAR = 2;
39
- const STATE_STRING = 3;
40
- const STATE_INTERPOLATION = 4;
41
-
42
- const REGEX_NAME = '/[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*/A';
43
- const REGEX_NUMBER = '/[0-9]+(?:\.[0-9]+)?/A';
44
- const REGEX_STRING = '/"([^#"\\\\]*(?:\\\\.[^#"\\\\]*)*)"|\'([^\'\\\\]*(?:\\\\.[^\'\\\\]*)*)\'/As';
45
- const REGEX_DQ_STRING_DELIM = '/"/A';
46
- const REGEX_DQ_STRING_PART = '/[^#"\\\\]*(?:(?:\\\\.|#(?!\{))[^#"\\\\]*)*/As';
47
- const PUNCTUATION = '()[]{}?:.,|';
48
-
49
- public function __construct(Twig_Environment $env, array $options = array())
50
- {
51
- $this->env = $env;
52
-
53
- $this->options = array_merge(array(
54
- 'tag_comment' => array('{#', '#}'),
55
- 'tag_block' => array('{%', '%}'),
56
- 'tag_variable' => array('{{', '}}'),
57
- 'whitespace_trim' => '-',
58
- 'interpolation' => array('#{', '}'),
59
- ), $options);
60
-
61
- $this->regexes = array(
62
- 'lex_var' => '/\s*'.preg_quote($this->options['whitespace_trim'].$this->options['tag_variable'][1], '/').'\s*|\s*'.preg_quote($this->options['tag_variable'][1], '/').'/A',
63
- 'lex_block' => '/\s*(?:'.preg_quote($this->options['whitespace_trim'].$this->options['tag_block'][1], '/').'\s*|\s*'.preg_quote($this->options['tag_block'][1], '/').')\n?/A',
64
- 'lex_raw_data' => '/('.preg_quote($this->options['tag_block'][0].$this->options['whitespace_trim'], '/').'|'.preg_quote($this->options['tag_block'][0], '/').')\s*(?:end%s)\s*(?:'.preg_quote($this->options['whitespace_trim'].$this->options['tag_block'][1], '/').'\s*|\s*'.preg_quote($this->options['tag_block'][1], '/').')/s',
65
- 'operator' => $this->getOperatorRegex(),
66
- 'lex_comment' => '/(?:'.preg_quote($this->options['whitespace_trim'], '/').preg_quote($this->options['tag_comment'][1], '/').'\s*|'.preg_quote($this->options['tag_comment'][1], '/').')\n?/s',
67
- 'lex_block_raw' => '/\s*(raw|verbatim)\s*(?:'.preg_quote($this->options['whitespace_trim'].$this->options['tag_block'][1], '/').'\s*|\s*'.preg_quote($this->options['tag_block'][1], '/').')/As',
68
- 'lex_block_line' => '/\s*line\s+(\d+)\s*'.preg_quote($this->options['tag_block'][1], '/').'/As',
69
- 'lex_tokens_start' => '/('.preg_quote($this->options['tag_variable'][0], '/').'|'.preg_quote($this->options['tag_block'][0], '/').'|'.preg_quote($this->options['tag_comment'][0], '/').')('.preg_quote($this->options['whitespace_trim'], '/').')?/s',
70
- 'interpolation_start' => '/'.preg_quote($this->options['interpolation'][0], '/').'\s*/A',
71
- 'interpolation_end' => '/\s*'.preg_quote($this->options['interpolation'][1], '/').'/A',
72
- );
73
- }
74
-
75
- /**
76
- * {@inheritdoc}
77
- */
78
- public function tokenize($code, $filename = null)
79
- {
80
- if (function_exists('mb_internal_encoding') && ((int) ini_get('mbstring.func_overload')) & 2) {
81
- $mbEncoding = mb_internal_encoding();
82
- mb_internal_encoding('ASCII');
83
- } else {
84
- $mbEncoding = null;
85
- }
86
-
87
- $this->code = str_replace(array("\r\n", "\r"), "\n", $code);
88
- $this->filename = $filename;
89
- $this->cursor = 0;
90
- $this->lineno = 1;
91
- $this->end = strlen($this->code);
92
- $this->tokens = array();
93
- $this->state = self::STATE_DATA;
94
- $this->states = array();
95
- $this->brackets = array();
96
- $this->position = -1;
97
-
98
- // find all token starts in one go
99
- preg_match_all($this->regexes['lex_tokens_start'], $this->code, $matches, PREG_OFFSET_CAPTURE);
100
- $this->positions = $matches;
101
-
102
- while ($this->cursor < $this->end) {
103
- // dispatch to the lexing functions depending
104
- // on the current state
105
- switch ($this->state) {
106
- case self::STATE_DATA:
107
- $this->lexData();
108
- break;
109
-
110
- case self::STATE_BLOCK:
111
- $this->lexBlock();
112
- break;
113
-
114
- case self::STATE_VAR:
115
- $this->lexVar();
116
- break;
117
-
118
- case self::STATE_STRING:
119
- $this->lexString();
120
- break;
121
-
122
- case self::STATE_INTERPOLATION:
123
- $this->lexInterpolation();
124
- break;
125
- }
126
- }
127
-
128
- $this->pushToken(Twig_Token::EOF_TYPE);
129
-
130
- if (!empty($this->brackets)) {
131
- list($expect, $lineno) = array_pop($this->brackets);
132
- throw new Twig_Error_Syntax(sprintf('Unclosed "%s"', $expect), $lineno, $this->filename);
133
- }
134
-
135
- if ($mbEncoding) {
136
- mb_internal_encoding($mbEncoding);
137
- }
138
-
139
- return new Twig_TokenStream($this->tokens, $this->filename);
140
- }
141
-
142
- protected function lexData()
143
- {
144
- // if no matches are left we return the rest of the template as simple text token
145
- if ($this->position == count($this->positions[0]) - 1) {
146
- $this->pushToken(Twig_Token::TEXT_TYPE, substr($this->code, $this->cursor));
147
- $this->cursor = $this->end;
148
-
149
- return;
150
- }
151
-
152
- // Find the first token after the current cursor
153
- $position = $this->positions[0][++$this->position];
154
- while ($position[1] < $this->cursor) {
155
- if ($this->position == count($this->positions[0]) - 1) {
156
- return;
157
- }
158
- $position = $this->positions[0][++$this->position];
159
- }
160
-
161
- // push the template text first
162
- $text = $textContent = substr($this->code, $this->cursor, $position[1] - $this->cursor);
163
- if (isset($this->positions[2][$this->position][0])) {
164
- $text = rtrim($text);
165
- }
166
- $this->pushToken(Twig_Token::TEXT_TYPE, $text);
167
- $this->moveCursor($textContent.$position[0]);
168
-
169
- switch ($this->positions[1][$this->position][0]) {
170
- case $this->options['tag_comment'][0]:
171
- $this->lexComment();
172
- break;
173
-
174
- case $this->options['tag_block'][0]:
175
- // raw data?
176
- if (preg_match($this->regexes['lex_block_raw'], $this->code, $match, null, $this->cursor)) {
177
- $this->moveCursor($match[0]);
178
- $this->lexRawData($match[1]);
179
- // {% line \d+ %}
180
- } elseif (preg_match($this->regexes['lex_block_line'], $this->code, $match, null, $this->cursor)) {
181
- $this->moveCursor($match[0]);
182
- $this->lineno = (int) $match[1];
183
- } else {
184
- $this->pushToken(Twig_Token::BLOCK_START_TYPE);
185
- $this->pushState(self::STATE_BLOCK);
186
- $this->currentVarBlockLine = $this->lineno;
187
- }
188
- break;
189
-
190
- case $this->options['tag_variable'][0]:
191
- $this->pushToken(Twig_Token::VAR_START_TYPE);
192
- $this->pushState(self::STATE_VAR);
193
- $this->currentVarBlockLine = $this->lineno;
194
- break;
195
- }
196
- }
197
-
198
- protected function lexBlock()
199
- {
200
- if (empty($this->brackets) && preg_match($this->regexes['lex_block'], $this->code, $match, null, $this->cursor)) {
201
- $this->pushToken(Twig_Token::BLOCK_END_TYPE);
202
- $this->moveCursor($match[0]);
203
- $this->popState();
204
- } else {
205
- $this->lexExpression();
206
- }
207
- }
208
-
209
- protected function lexVar()
210
- {
211
- if (empty($this->brackets) && preg_match($this->regexes['lex_var'], $this->code, $match, null, $this->cursor)) {
212
- $this->pushToken(Twig_Token::VAR_END_TYPE);
213
- $this->moveCursor($match[0]);
214
- $this->popState();
215
- } else {
216
- $this->lexExpression();
217
- }
218
- }
219
-
220
- protected function lexExpression()
221
- {
222
- // whitespace
223
- if (preg_match('/\s+/A', $this->code, $match, null, $this->cursor)) {
224
- $this->moveCursor($match[0]);
225
-
226
- if ($this->cursor >= $this->end) {
227
- throw new Twig_Error_Syntax(sprintf('Unclosed "%s"', $this->state === self::STATE_BLOCK ? 'block' : 'variable'), $this->currentVarBlockLine, $this->filename);
228
- }
229
- }
230
-
231
- // operators
232
- if (preg_match($this->regexes['operator'], $this->code, $match, null, $this->cursor)) {
233
- $this->pushToken(Twig_Token::OPERATOR_TYPE, preg_replace('/\s+/', ' ', $match[0]));
234
- $this->moveCursor($match[0]);
235
- }
236
- // names
237
- elseif (preg_match(self::REGEX_NAME, $this->code, $match, null, $this->cursor)) {
238
- $this->pushToken(Twig_Token::NAME_TYPE, $match[0]);
239
- $this->moveCursor($match[0]);
240
- }
241
- // numbers
242
- elseif (preg_match(self::REGEX_NUMBER, $this->code, $match, null, $this->cursor)) {
243
- $number = (float) $match[0]; // floats
244
- if (ctype_digit($match[0]) && $number <= PHP_INT_MAX) {
245
- $number = (int) $match[0]; // integers lower than the maximum
246
- }
247
- $this->pushToken(Twig_Token::NUMBER_TYPE, $number);
248
- $this->moveCursor($match[0]);
249
- }
250
- // punctuation
251
- elseif (false !== strpos(self::PUNCTUATION, $this->code[$this->cursor])) {
252
- // opening bracket
253
- if (false !== strpos('([{', $this->code[$this->cursor])) {
254
- $this->brackets[] = array($this->code[$this->cursor], $this->lineno);
255
- }
256
- // closing bracket
257
- elseif (false !== strpos(')]}', $this->code[$this->cursor])) {
258
- if (empty($this->brackets)) {
259
- throw new Twig_Error_Syntax(sprintf('Unexpected "%s"', $this->code[$this->cursor]), $this->lineno, $this->filename);
260
- }
261
-
262
- list($expect, $lineno) = array_pop($this->brackets);
263
- if ($this->code[$this->cursor] != strtr($expect, '([{', ')]}')) {
264
- throw new Twig_Error_Syntax(sprintf('Unclosed "%s"', $expect), $lineno, $this->filename);
265
- }
266
- }
267
-
268
- $this->pushToken(Twig_Token::PUNCTUATION_TYPE, $this->code[$this->cursor]);
269
- ++$this->cursor;
270
- }
271
- // strings
272
- elseif (preg_match(self::REGEX_STRING, $this->code, $match, null, $this->cursor)) {
273
- $this->pushToken(Twig_Token::STRING_TYPE, stripcslashes(substr($match[0], 1, -1)));
274
- $this->moveCursor($match[0]);
275
- }
276
- // opening double quoted string
277
- elseif (preg_match(self::REGEX_DQ_STRING_DELIM, $this->code, $match, null, $this->cursor)) {
278
- $this->brackets[] = array('"', $this->lineno);
279
- $this->pushState(self::STATE_STRING);
280
- $this->moveCursor($match[0]);
281
- }
282
- // unlexable
283
- else {
284
- throw new Twig_Error_Syntax(sprintf('Unexpected character "%s"', $this->code[$this->cursor]), $this->lineno, $this->filename);
285
- }
286
- }
287
-
288
- protected function lexRawData($tag)
289
- {
290
- if (!preg_match(str_replace('%s', $tag, $this->regexes['lex_raw_data']), $this->code, $match, PREG_OFFSET_CAPTURE, $this->cursor)) {
291
- throw new Twig_Error_Syntax(sprintf('Unexpected end of file: Unclosed "%s" block', $tag), $this->lineno, $this->filename);
292
- }
293
-
294
- $text = substr($this->code, $this->cursor, $match[0][1] - $this->cursor);
295
- $this->moveCursor($text.$match[0][0]);
296
-
297
- if (false !== strpos($match[1][0], $this->options['whitespace_trim'])) {
298
- $text = rtrim($text);
299
- }
300
-
301
- $this->pushToken(Twig_Token::TEXT_TYPE, $text);
302
- }
303
-
304
- protected function lexComment()
305
- {
306
- if (!preg_match($this->regexes['lex_comment'], $this->code, $match, PREG_OFFSET_CAPTURE, $this->cursor)) {
307
- throw new Twig_Error_Syntax('Unclosed comment', $this->lineno, $this->filename);
308
- }
309
-
310
- $this->moveCursor(substr($this->code, $this->cursor, $match[0][1] - $this->cursor).$match[0][0]);
311
- }
312
-
313
- protected function lexString()
314
- {
315
- if (preg_match($this->regexes['interpolation_start'], $this->code, $match, null, $this->cursor)) {
316
- $this->brackets[] = array($this->options['interpolation'][0], $this->lineno);
317
- $this->pushToken(Twig_Token::INTERPOLATION_START_TYPE);
318
- $this->moveCursor($match[0]);
319
- $this->pushState(self::STATE_INTERPOLATION);
320
-
321
- } elseif (preg_match(self::REGEX_DQ_STRING_PART, $this->code, $match, null, $this->cursor) && strlen($match[0]) > 0) {
322
- $this->pushToken(Twig_Token::STRING_TYPE, stripcslashes($match[0]));
323
- $this->moveCursor($match[0]);
324
-
325
- } elseif (preg_match(self::REGEX_DQ_STRING_DELIM, $this->code, $match, null, $this->cursor)) {
326
- list($expect, $lineno) = array_pop($this->brackets);
327
- if ($this->code[$this->cursor] != '"') {
328
- throw new Twig_Error_Syntax(sprintf('Unclosed "%s"', $expect), $lineno, $this->filename);
329
- }
330
-
331
- $this->popState();
332
- ++$this->cursor;
333
- }
334
- }
335
-
336
- protected function lexInterpolation()
337
- {
338
- $bracket = end($this->brackets);
339
- if ($this->options['interpolation'][0] === $bracket[0] && preg_match($this->regexes['interpolation_end'], $this->code, $match, null, $this->cursor)) {
340
- array_pop($this->brackets);
341
- $this->pushToken(Twig_Token::INTERPOLATION_END_TYPE);
342
- $this->moveCursor($match[0]);
343
- $this->popState();
344
- } else {
345
- $this->lexExpression();
346
- }
347
- }
348
-
349
- protected function pushToken($type, $value = '')
350
- {
351
- // do not push empty text tokens
352
- if (Twig_Token::TEXT_TYPE === $type && '' === $value) {
353
- return;
354
- }
355
-
356
- $this->tokens[] = new Twig_Token($type, $value, $this->lineno);
357
- }
358
-
359
- protected function moveCursor($text)
360
- {
361
- $this->cursor += strlen($text);
362
- $this->lineno += substr_count($text, "\n");
363
- }
364
-
365
- protected function getOperatorRegex()
366
- {
367
- $operators = array_merge(
368
- array('='),
369
- array_keys($this->env->getUnaryOperators()),
370
- array_keys($this->env->getBinaryOperators())
371
- );
372
-
373
- $operators = array_combine($operators, array_map('strlen', $operators));
374
- arsort($operators);
375
-
376
- $regex = array();
377
- foreach ($operators as $operator => $length) {
378
- // an operator that ends with a character must be followed by
379
- // a whitespace or a parenthesis
380
- if (ctype_alpha($operator[$length - 1])) {
381
- $r = preg_quote($operator, '/').'(?=[\s()])';
382
- } else {
383
- $r = preg_quote($operator, '/');
384
- }
385
-
386
- // an operator with a space can be any amount of whitespaces
387
- $r = preg_replace('/\s+/', '\s+', $r);
388
-
389
- $regex[] = $r;
390
- }
391
-
392
- return '/'.implode('|', $regex).'/A';
393
- }
394
-
395
- protected function pushState($state)
396
- {
397
- $this->states[] = $this->state;
398
- $this->state = $state;
399
- }
400
-
401
- protected function popState()
402
- {
403
- if (0 === count($this->states)) {
404
- throw new Exception('Cannot pop state without a previous state');
405
- }
406
-
407
- $this->state = array_pop($this->states);
408
- }
409
- }
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2009 Fabien Potencier
7
+ * (c) 2009 Armin Ronacher
8
+ *
9
+ * For the full copyright and license information, please view the LICENSE
10
+ * file that was distributed with this source code.
11
+ */
12
+
13
+ /**
14
+ * Lexes a template string.
15
+ *
16
+ * @author Fabien Potencier <fabien@symfony.com>
17
+ */
18
+ class Twig_Lexer implements Twig_LexerInterface
19
+ {
20
+ protected $tokens;
21
+ protected $code;
22
+ protected $cursor;
23
+ protected $lineno;
24
+ protected $end;
25
+ protected $state;
26
+ protected $states;
27
+ protected $brackets;
28
+ protected $env;
29
+ protected $filename;
30
+ protected $options;
31
+ protected $regexes;
32
+ protected $position;
33
+ protected $positions;
34
+ protected $currentVarBlockLine;
35
+
36
+ const STATE_DATA = 0;
37
+ const STATE_BLOCK = 1;
38
+ const STATE_VAR = 2;
39
+ const STATE_STRING = 3;
40
+ const STATE_INTERPOLATION = 4;
41
+
42
+ const REGEX_NAME = '/[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*/A';
43
+ const REGEX_NUMBER = '/[0-9]+(?:\.[0-9]+)?/A';
44
+ const REGEX_STRING = '/"([^#"\\\\]*(?:\\\\.[^#"\\\\]*)*)"|\'([^\'\\\\]*(?:\\\\.[^\'\\\\]*)*)\'/As';
45
+ const REGEX_DQ_STRING_DELIM = '/"/A';
46
+ const REGEX_DQ_STRING_PART = '/[^#"\\\\]*(?:(?:\\\\.|#(?!\{))[^#"\\\\]*)*/As';
47
+ const PUNCTUATION = '()[]{}?:.,|';
48
+
49
+ public function __construct(Twig_Environment $env, array $options = array())
50
+ {
51
+ $this->env = $env;
52
+
53
+ $this->options = array_merge(array(
54
+ 'tag_comment' => array('{#', '#}'),
55
+ 'tag_block' => array('{%', '%}'),
56
+ 'tag_variable' => array('{{', '}}'),
57
+ 'whitespace_trim' => '-',
58
+ 'interpolation' => array('#{', '}'),
59
+ ), $options);
60
+
61
+ $this->regexes = array(
62
+ 'lex_var' => '/\s*'.preg_quote($this->options['whitespace_trim'].$this->options['tag_variable'][1], '/').'\s*|\s*'.preg_quote($this->options['tag_variable'][1], '/').'/A',
63
+ 'lex_block' => '/\s*(?:'.preg_quote($this->options['whitespace_trim'].$this->options['tag_block'][1], '/').'\s*|\s*'.preg_quote($this->options['tag_block'][1], '/').')\n?/A',
64
+ 'lex_raw_data' => '/('.preg_quote($this->options['tag_block'][0].$this->options['whitespace_trim'], '/').'|'.preg_quote($this->options['tag_block'][0], '/').')\s*(?:end%s)\s*(?:'.preg_quote($this->options['whitespace_trim'].$this->options['tag_block'][1], '/').'\s*|\s*'.preg_quote($this->options['tag_block'][1], '/').')/s',
65
+ 'operator' => $this->getOperatorRegex(),
66
+ 'lex_comment' => '/(?:'.preg_quote($this->options['whitespace_trim'], '/').preg_quote($this->options['tag_comment'][1], '/').'\s*|'.preg_quote($this->options['tag_comment'][1], '/').')\n?/s',
67
+ 'lex_block_raw' => '/\s*(raw|verbatim)\s*(?:'.preg_quote($this->options['whitespace_trim'].$this->options['tag_block'][1], '/').'\s*|\s*'.preg_quote($this->options['tag_block'][1], '/').')/As',
68
+ 'lex_block_line' => '/\s*line\s+(\d+)\s*'.preg_quote($this->options['tag_block'][1], '/').'/As',
69
+ 'lex_tokens_start' => '/('.preg_quote($this->options['tag_variable'][0], '/').'|'.preg_quote($this->options['tag_block'][0], '/').'|'.preg_quote($this->options['tag_comment'][0], '/').')('.preg_quote($this->options['whitespace_trim'], '/').')?/s',
70
+ 'interpolation_start' => '/'.preg_quote($this->options['interpolation'][0], '/').'\s*/A',
71
+ 'interpolation_end' => '/\s*'.preg_quote($this->options['interpolation'][1], '/').'/A',
72
+ );
73
+ }
74
+
75
+ /**
76
+ * {@inheritdoc}
77
+ */
78
+ public function tokenize($code, $filename = null)
79
+ {
80
+ if (function_exists('mb_internal_encoding') && ((int) ini_get('mbstring.func_overload')) & 2) {
81
+ $mbEncoding = mb_internal_encoding();
82
+ mb_internal_encoding('ASCII');
83
+ } else {
84
+ $mbEncoding = null;
85
+ }
86
+
87
+ $this->code = str_replace(array("\r\n", "\r"), "\n", $code);
88
+ $this->filename = $filename;
89
+ $this->cursor = 0;
90
+ $this->lineno = 1;
91
+ $this->end = strlen($this->code);
92
+ $this->tokens = array();
93
+ $this->state = self::STATE_DATA;
94
+ $this->states = array();
95
+ $this->brackets = array();
96
+ $this->position = -1;
97
+
98
+ // find all token starts in one go
99
+ preg_match_all($this->regexes['lex_tokens_start'], $this->code, $matches, PREG_OFFSET_CAPTURE);
100
+ $this->positions = $matches;
101
+
102
+ while ($this->cursor < $this->end) {
103
+ // dispatch to the lexing functions depending
104
+ // on the current state
105
+ switch ($this->state) {
106
+ case self::STATE_DATA:
107
+ $this->lexData();
108
+ break;
109
+
110
+ case self::STATE_BLOCK:
111
+ $this->lexBlock();
112
+ break;
113
+
114
+ case self::STATE_VAR:
115
+ $this->lexVar();
116
+ break;
117
+
118
+ case self::STATE_STRING:
119
+ $this->lexString();
120
+ break;
121
+
122
+ case self::STATE_INTERPOLATION:
123
+ $this->lexInterpolation();
124
+ break;
125
+ }
126
+ }
127
+
128
+ $this->pushToken(Twig_Token::EOF_TYPE);
129
+
130
+ if (!empty($this->brackets)) {
131
+ list($expect, $lineno) = array_pop($this->brackets);
132
+ throw new Twig_Error_Syntax(sprintf('Unclosed "%s"', $expect), $lineno, $this->filename);
133
+ }
134
+
135
+ if ($mbEncoding) {
136
+ mb_internal_encoding($mbEncoding);
137
+ }
138
+
139
+ return new Twig_TokenStream($this->tokens, $this->filename);
140
+ }
141
+
142
+ protected function lexData()
143
+ {
144
+ // if no matches are left we return the rest of the template as simple text token
145
+ if ($this->position == count($this->positions[0]) - 1) {
146
+ $this->pushToken(Twig_Token::TEXT_TYPE, substr($this->code, $this->cursor));
147
+ $this->cursor = $this->end;
148
+
149
+ return;
150
+ }
151
+
152
+ // Find the first token after the current cursor
153
+ $position = $this->positions[0][++$this->position];
154
+ while ($position[1] < $this->cursor) {
155
+ if ($this->position == count($this->positions[0]) - 1) {
156
+ return;
157
+ }
158
+ $position = $this->positions[0][++$this->position];
159
+ }
160
+
161
+ // push the template text first
162
+ $text = $textContent = substr($this->code, $this->cursor, $position[1] - $this->cursor);
163
+ if (isset($this->positions[2][$this->position][0])) {
164
+ $text = rtrim($text);
165
+ }
166
+ $this->pushToken(Twig_Token::TEXT_TYPE, $text);
167
+ $this->moveCursor($textContent.$position[0]);
168
+
169
+ switch ($this->positions[1][$this->position][0]) {
170
+ case $this->options['tag_comment'][0]:
171
+ $this->lexComment();
172
+ break;
173
+
174
+ case $this->options['tag_block'][0]:
175
+ // raw data?
176
+ if (preg_match($this->regexes['lex_block_raw'], $this->code, $match, null, $this->cursor)) {
177
+ $this->moveCursor($match[0]);
178
+ $this->lexRawData($match[1]);
179
+ // {% line \d+ %}
180
+ } elseif (preg_match($this->regexes['lex_block_line'], $this->code, $match, null, $this->cursor)) {
181
+ $this->moveCursor($match[0]);
182
+ $this->lineno = (int) $match[1];
183
+ } else {
184
+ $this->pushToken(Twig_Token::BLOCK_START_TYPE);
185
+ $this->pushState(self::STATE_BLOCK);
186
+ $this->currentVarBlockLine = $this->lineno;
187
+ }
188
+ break;
189
+
190
+ case $this->options['tag_variable'][0]:
191
+ $this->pushToken(Twig_Token::VAR_START_TYPE);
192
+ $this->pushState(self::STATE_VAR);
193
+ $this->currentVarBlockLine = $this->lineno;
194
+ break;
195
+ }
196
+ }
197
+
198
+ protected function lexBlock()
199
+ {
200
+ if (empty($this->brackets) && preg_match($this->regexes['lex_block'], $this->code, $match, null, $this->cursor)) {
201
+ $this->pushToken(Twig_Token::BLOCK_END_TYPE);
202
+ $this->moveCursor($match[0]);
203
+ $this->popState();
204
+ } else {
205
+ $this->lexExpression();
206
+ }
207
+ }
208
+
209
+ protected function lexVar()
210
+ {
211
+ if (empty($this->brackets) && preg_match($this->regexes['lex_var'], $this->code, $match, null, $this->cursor)) {
212
+ $this->pushToken(Twig_Token::VAR_END_TYPE);
213
+ $this->moveCursor($match[0]);
214
+ $this->popState();
215
+ } else {
216
+ $this->lexExpression();
217
+ }
218
+ }
219
+
220
+ protected function lexExpression()
221
+ {
222
+ // whitespace
223
+ if (preg_match('/\s+/A', $this->code, $match, null, $this->cursor)) {
224
+ $this->moveCursor($match[0]);
225
+
226
+ if ($this->cursor >= $this->end) {
227
+ throw new Twig_Error_Syntax(sprintf('Unclosed "%s"', $this->state === self::STATE_BLOCK ? 'block' : 'variable'), $this->currentVarBlockLine, $this->filename);
228
+ }
229
+ }
230
+
231
+ // operators
232
+ if (preg_match($this->regexes['operator'], $this->code, $match, null, $this->cursor)) {
233
+ $this->pushToken(Twig_Token::OPERATOR_TYPE, preg_replace('/\s+/', ' ', $match[0]));
234
+ $this->moveCursor($match[0]);
235
+ }
236
+ // names
237
+ elseif (preg_match(self::REGEX_NAME, $this->code, $match, null, $this->cursor)) {
238
+ $this->pushToken(Twig_Token::NAME_TYPE, $match[0]);
239
+ $this->moveCursor($match[0]);
240
+ }
241
+ // numbers
242
+ elseif (preg_match(self::REGEX_NUMBER, $this->code, $match, null, $this->cursor)) {
243
+ $number = (float) $match[0]; // floats
244
+ if (ctype_digit($match[0]) && $number <= PHP_INT_MAX) {
245
+ $number = (int) $match[0]; // integers lower than the maximum
246
+ }
247
+ $this->pushToken(Twig_Token::NUMBER_TYPE, $number);
248
+ $this->moveCursor($match[0]);
249
+ }
250
+ // punctuation
251
+ elseif (false !== strpos(self::PUNCTUATION, $this->code[$this->cursor])) {
252
+ // opening bracket
253
+ if (false !== strpos('([{', $this->code[$this->cursor])) {
254
+ $this->brackets[] = array($this->code[$this->cursor], $this->lineno);
255
+ }
256
+ // closing bracket
257
+ elseif (false !== strpos(')]}', $this->code[$this->cursor])) {
258
+ if (empty($this->brackets)) {
259
+ throw new Twig_Error_Syntax(sprintf('Unexpected "%s"', $this->code[$this->cursor]), $this->lineno, $this->filename);
260
+ }
261
+
262
+ list($expect, $lineno) = array_pop($this->brackets);
263
+ if ($this->code[$this->cursor] != strtr($expect, '([{', ')]}')) {
264
+ throw new Twig_Error_Syntax(sprintf('Unclosed "%s"', $expect), $lineno, $this->filename);
265
+ }
266
+ }
267
+
268
+ $this->pushToken(Twig_Token::PUNCTUATION_TYPE, $this->code[$this->cursor]);
269
+ ++$this->cursor;
270
+ }
271
+ // strings
272
+ elseif (preg_match(self::REGEX_STRING, $this->code, $match, null, $this->cursor)) {
273
+ $this->pushToken(Twig_Token::STRING_TYPE, stripcslashes(substr($match[0], 1, -1)));
274
+ $this->moveCursor($match[0]);
275
+ }
276
+ // opening double quoted string
277
+ elseif (preg_match(self::REGEX_DQ_STRING_DELIM, $this->code, $match, null, $this->cursor)) {
278
+ $this->brackets[] = array('"', $this->lineno);
279
+ $this->pushState(self::STATE_STRING);
280
+ $this->moveCursor($match[0]);
281
+ }
282
+ // unlexable
283
+ else {
284
+ throw new Twig_Error_Syntax(sprintf('Unexpected character "%s"', $this->code[$this->cursor]), $this->lineno, $this->filename);
285
+ }
286
+ }
287
+
288
+ protected function lexRawData($tag)
289
+ {
290
+ if (!preg_match(str_replace('%s', $tag, $this->regexes['lex_raw_data']), $this->code, $match, PREG_OFFSET_CAPTURE, $this->cursor)) {
291
+ throw new Twig_Error_Syntax(sprintf('Unexpected end of file: Unclosed "%s" block', $tag), $this->lineno, $this->filename);
292
+ }
293
+
294
+ $text = substr($this->code, $this->cursor, $match[0][1] - $this->cursor);
295
+ $this->moveCursor($text.$match[0][0]);
296
+
297
+ if (false !== strpos($match[1][0], $this->options['whitespace_trim'])) {
298
+ $text = rtrim($text);
299
+ }
300
+
301
+ $this->pushToken(Twig_Token::TEXT_TYPE, $text);
302
+ }
303
+
304
+ protected function lexComment()
305
+ {
306
+ if (!preg_match($this->regexes['lex_comment'], $this->code, $match, PREG_OFFSET_CAPTURE, $this->cursor)) {
307
+ throw new Twig_Error_Syntax('Unclosed comment', $this->lineno, $this->filename);
308
+ }
309
+
310
+ $this->moveCursor(substr($this->code, $this->cursor, $match[0][1] - $this->cursor).$match[0][0]);
311
+ }
312
+
313
+ protected function lexString()
314
+ {
315
+ if (preg_match($this->regexes['interpolation_start'], $this->code, $match, null, $this->cursor)) {
316
+ $this->brackets[] = array($this->options['interpolation'][0], $this->lineno);
317
+ $this->pushToken(Twig_Token::INTERPOLATION_START_TYPE);
318
+ $this->moveCursor($match[0]);
319
+ $this->pushState(self::STATE_INTERPOLATION);
320
+
321
+ } elseif (preg_match(self::REGEX_DQ_STRING_PART, $this->code, $match, null, $this->cursor) && strlen($match[0]) > 0) {
322
+ $this->pushToken(Twig_Token::STRING_TYPE, stripcslashes($match[0]));
323
+ $this->moveCursor($match[0]);
324
+
325
+ } elseif (preg_match(self::REGEX_DQ_STRING_DELIM, $this->code, $match, null, $this->cursor)) {
326
+ list($expect, $lineno) = array_pop($this->brackets);
327
+ if ($this->code[$this->cursor] != '"') {
328
+ throw new Twig_Error_Syntax(sprintf('Unclosed "%s"', $expect), $lineno, $this->filename);
329
+ }
330
+
331
+ $this->popState();
332
+ ++$this->cursor;
333
+ }
334
+ }
335
+
336
+ protected function lexInterpolation()
337
+ {
338
+ $bracket = end($this->brackets);
339
+ if ($this->options['interpolation'][0] === $bracket[0] && preg_match($this->regexes['interpolation_end'], $this->code, $match, null, $this->cursor)) {
340
+ array_pop($this->brackets);
341
+ $this->pushToken(Twig_Token::INTERPOLATION_END_TYPE);
342
+ $this->moveCursor($match[0]);
343
+ $this->popState();
344
+ } else {
345
+ $this->lexExpression();
346
+ }
347
+ }
348
+
349
+ protected function pushToken($type, $value = '')
350
+ {
351
+ // do not push empty text tokens
352
+ if (Twig_Token::TEXT_TYPE === $type && '' === $value) {
353
+ return;
354
+ }
355
+
356
+ $this->tokens[] = new Twig_Token($type, $value, $this->lineno);
357
+ }
358
+
359
+ protected function moveCursor($text)
360
+ {
361
+ $this->cursor += strlen($text);
362
+ $this->lineno += substr_count($text, "\n");
363
+ }
364
+
365
+ protected function getOperatorRegex()
366
+ {
367
+ $operators = array_merge(
368
+ array('='),
369
+ array_keys($this->env->getUnaryOperators()),
370
+ array_keys($this->env->getBinaryOperators())
371
+ );
372
+
373
+ $operators = array_combine($operators, array_map('strlen', $operators));
374
+ arsort($operators);
375
+
376
+ $regex = array();
377
+ foreach ($operators as $operator => $length) {
378
+ // an operator that ends with a character must be followed by
379
+ // a whitespace or a parenthesis
380
+ if (ctype_alpha($operator[$length - 1])) {
381
+ $r = preg_quote($operator, '/').'(?=[\s()])';
382
+ } else {
383
+ $r = preg_quote($operator, '/');
384
+ }
385
+
386
+ // an operator with a space can be any amount of whitespaces
387
+ $r = preg_replace('/\s+/', '\s+', $r);
388
+
389
+ $regex[] = $r;
390
+ }
391
+
392
+ return '/'.implode('|', $regex).'/A';
393
+ }
394
+
395
+ protected function pushState($state)
396
+ {
397
+ $this->states[] = $this->state;
398
+ $this->state = $state;
399
+ }
400
+
401
+ protected function popState()
402
+ {
403
+ if (0 === count($this->states)) {
404
+ throw new Exception('Cannot pop state without a previous state');
405
+ }
406
+
407
+ $this->state = array_pop($this->states);
408
+ }
409
+ }
classes/Twig/LexerInterface.php CHANGED
@@ -1,32 +1,32 @@
1
- <?php
2
-
3
- /*
4
- * This file is part of Twig.
5
- *
6
- * (c) 2009 Fabien Potencier
7
- *
8
- * For the full copyright and license information, please view the LICENSE
9
- * file that was distributed with this source code.
10
- */
11
-
12
- /**
13
- * Interface implemented by lexer classes.
14
- *
15
- * @author Fabien Potencier <fabien@symfony.com>
16
- *
17
- * @deprecated since 1.12 (to be removed in 3.0)
18
- */
19
- interface Twig_LexerInterface
20
- {
21
- /**
22
- * Tokenizes a source code.
23
- *
24
- * @param string $code The source code
25
- * @param string $filename A unique identifier for the source code
26
- *
27
- * @return Twig_TokenStream A token stream instance
28
- *
29
- * @throws Twig_Error_Syntax When the code is syntactically wrong
30
- */
31
- public function tokenize($code, $filename = null);
32
- }
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2009 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ /**
13
+ * Interface implemented by lexer classes.
14
+ *
15
+ * @author Fabien Potencier <fabien@symfony.com>
16
+ *
17
+ * @deprecated since 1.12 (to be removed in 3.0)
18
+ */
19
+ interface Twig_LexerInterface
20
+ {
21
+ /**
22
+ * Tokenizes a source code.
23
+ *
24
+ * @param string $code The source code
25
+ * @param string $filename A unique identifier for the source code
26
+ *
27
+ * @return Twig_TokenStream A token stream instance
28
+ *
29
+ * @throws Twig_Error_Syntax When the code is syntactically wrong
30
+ */
31
+ public function tokenize($code, $filename = null);
32
+ }
classes/Twig/Loader/Array.php CHANGED
@@ -1,95 +1,95 @@
1
- <?php
2
-
3
- /*
4
- * This file is part of Twig.
5
- *
6
- * (c) 2009 Fabien Potencier
7
- *
8
- * For the full copyright and license information, please view the LICENSE
9
- * file that was distributed with this source code.
10
- */
11
-
12
- /**
13
- * Loads a template from an array.
14
- *
15
- * When using this loader with a cache mechanism, you should know that a new cache
16
- * key is generated each time a template content "changes" (the cache key being the
17
- * source code of the template). If you don't want to see your cache grows out of
18
- * control, you need to take care of clearing the old cache file by yourself.
19
- *
20
- * @author Fabien Potencier <fabien@symfony.com>
21
- */
22
- class Twig_Loader_Array implements Twig_LoaderInterface, Twig_ExistsLoaderInterface
23
- {
24
- protected $templates = array();
25
-
26
- /**
27
- * Constructor.
28
- *
29
- * @param array $templates An array of templates (keys are the names, and values are the source code)
30
- *
31
- * @see Twig_Loader
32
- */
33
- public function __construct(array $templates)
34
- {
35
- $this->templates = $templates;
36
- }
37
-
38
- /**
39
- * Adds or overrides a template.
40
- *
41
- * @param string $name The template name
42
- * @param string $template The template source
43
- */
44
- public function setTemplate($name, $template)
45
- {
46
- $this->templates[(string) $name] = $template;
47
- }
48
-
49
- /**
50
- * {@inheritdoc}
51
- */
52
- public function getSource($name)
53
- {
54
- $name = (string) $name;
55
- if (!isset($this->templates[$name])) {
56
- throw new Twig_Error_Loader(sprintf('Template "%s" is not defined.', $name));
57
- }
58
-
59
- return $this->templates[$name];
60
- }
61
-
62
- /**
63
- * {@inheritdoc}
64
- */
65
- public function exists($name)
66
- {
67
- return isset($this->templates[(string) $name]);
68
- }
69
-
70
- /**
71
- * {@inheritdoc}
72
- */
73
- public function getCacheKey($name)
74
- {
75
- $name = (string) $name;
76
- if (!isset($this->templates[$name])) {
77
- throw new Twig_Error_Loader(sprintf('Template "%s" is not defined.', $name));
78
- }
79
-
80
- return $this->templates[$name];
81
- }
82
-
83
- /**
84
- * {@inheritdoc}
85
- */
86
- public function isFresh($name, $time)
87
- {
88
- $name = (string) $name;
89
- if (!isset($this->templates[$name])) {
90
- throw new Twig_Error_Loader(sprintf('Template "%s" is not defined.', $name));
91
- }
92
-
93
- return true;
94
- }
95
- }
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2009 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ /**
13
+ * Loads a template from an array.
14
+ *
15
+ * When using this loader with a cache mechanism, you should know that a new cache
16
+ * key is generated each time a template content "changes" (the cache key being the
17
+ * source code of the template). If you don't want to see your cache grows out of
18
+ * control, you need to take care of clearing the old cache file by yourself.
19
+ *
20
+ * @author Fabien Potencier <fabien@symfony.com>
21
+ */
22
+ class Twig_Loader_Array implements Twig_LoaderInterface, Twig_ExistsLoaderInterface
23
+ {
24
+ protected $templates = array();
25
+
26
+ /**
27
+ * Constructor.
28
+ *
29
+ * @param array $templates An array of templates (keys are the names, and values are the source code)
30
+ *
31
+ * @see Twig_Loader
32
+ */
33
+ public function __construct(array $templates)
34
+ {
35
+ $this->templates = $templates;
36
+ }
37
+
38
+ /**
39
+ * Adds or overrides a template.
40
+ *
41
+ * @param string $name The template name
42
+ * @param string $template The template source
43
+ */
44
+ public function setTemplate($name, $template)
45
+ {
46
+ $this->templates[(string) $name] = $template;
47
+ }
48
+
49
+ /**
50
+ * {@inheritdoc}
51
+ */
52
+ public function getSource($name)
53
+ {
54
+ $name = (string) $name;
55
+ if (!isset($this->templates[$name])) {
56
+ throw new Twig_Error_Loader(sprintf('Template "%s" is not defined.', $name));
57
+ }
58
+
59
+ return $this->templates[$name];
60
+ }
61
+
62
+ /**
63
+ * {@inheritdoc}
64
+ */
65
+ public function exists($name)
66
+ {
67
+ return isset($this->templates[(string) $name]);
68
+ }
69
+
70
+ /**
71
+ * {@inheritdoc}
72
+ */
73
+ public function getCacheKey($name)
74
+ {
75
+ $name = (string) $name;
76
+ if (!isset($this->templates[$name])) {
77
+ throw new Twig_Error_Loader(sprintf('Template "%s" is not defined.', $name));
78
+ }
79
+
80
+ return $this->templates[$name];
81
+ }
82
+
83
+ /**
84
+ * {@inheritdoc}
85
+ */
86
+ public function isFresh($name, $time)
87
+ {
88
+ $name = (string) $name;
89
+ if (!isset($this->templates[$name])) {
90
+ throw new Twig_Error_Loader(sprintf('Template "%s" is not defined.', $name));
91
+ }
92
+
93
+ return true;
94
+ }
95
+ }
classes/Twig/Loader/Chain.php CHANGED
@@ -1,138 +1,138 @@
1
- <?php
2
-
3
- /*
4
- * This file is part of Twig.
5
- *
6
- * (c) 2011 Fabien Potencier
7
- *
8
- * For the full copyright and license information, please view the LICENSE
9
- * file that was distributed with this source code.
10
- */
11
-
12
- /**
13
- * Loads templates from other loaders.
14
- *
15
- * @author Fabien Potencier <fabien@symfony.com>
16
- */
17
- class Twig_Loader_Chain implements Twig_LoaderInterface, Twig_ExistsLoaderInterface
18
- {
19
- private $hasSourceCache = array();
20
- protected $loaders = array();
21
-
22
- /**
23
- * Constructor.
24
- *
25
- * @param Twig_LoaderInterface[] $loaders An array of loader instances
26
- */
27
- public function __construct(array $loaders = array())
28
- {
29
- foreach ($loaders as $loader) {
30
- $this->addLoader($loader);
31
- }
32
- }
33
-
34
- /**
35
- * Adds a loader instance.
36
- *
37
- * @param Twig_LoaderInterface $loader A Loader instance
38
- */
39
- public function addLoader(Twig_LoaderInterface $loader)
40
- {
41
- $this->loaders[] = $loader;
42
- $this->hasSourceCache = array();
43
- }
44
-
45
- /**
46
- * {@inheritdoc}
47
- */
48
- public function getSource($name)
49
- {
50
- $exceptions = array();
51
- foreach ($this->loaders as $loader) {
52
- if ($loader instanceof Twig_ExistsLoaderInterface && !$loader->exists($name)) {
53
- continue;
54
- }
55
-
56
- try {
57
- return $loader->getSource($name);
58
- } catch (Twig_Error_Loader $e) {
59
- $exceptions[] = $e->getMessage();
60
- }
61
- }
62
-
63
- throw new Twig_Error_Loader(sprintf('Template "%s" is not defined (%s).', $name, implode(', ', $exceptions)));
64
- }
65
-
66
- /**
67
- * {@inheritdoc}
68
- */
69
- public function exists($name)
70
- {
71
- $name = (string) $name;
72
-
73
- if (isset($this->hasSourceCache[$name])) {
74
- return $this->hasSourceCache[$name];
75
- }
76
-
77
- foreach ($this->loaders as $loader) {
78
- if ($loader instanceof Twig_ExistsLoaderInterface) {
79
- if ($loader->exists($name)) {
80
- return $this->hasSourceCache[$name] = true;
81
- }
82
-
83
- continue;
84
- }
85
-
86
- try {
87
- $loader->getSource($name);
88
-
89
- return $this->hasSourceCache[$name] = true;
90
- } catch (Twig_Error_Loader $e) {
91
- }
92
- }
93
-
94
- return $this->hasSourceCache[$name] = false;
95
- }
96
-
97
- /**
98
- * {@inheritdoc}
99
- */
100
- public function getCacheKey($name)
101
- {
102
- $exceptions = array();
103
- foreach ($this->loaders as $loader) {
104
- if ($loader instanceof Twig_ExistsLoaderInterface && !$loader->exists($name)) {
105
- continue;
106
- }
107
-
108
- try {
109
- return $loader->getCacheKey($name);
110
- } catch (Twig_Error_Loader $e) {
111
- $exceptions[] = get_class($loader).': '.$e->getMessage();
112
- }
113
- }
114
-
115
- throw new Twig_Error_Loader(sprintf('Template "%s" is not defined (%s).', $name, implode(' ', $exceptions)));
116
- }
117
-
118
- /**
119
- * {@inheritdoc}
120
- */
121
- public function isFresh($name, $time)
122
- {
123
- $exceptions = array();
124
- foreach ($this->loaders as $loader) {
125
- if ($loader instanceof Twig_ExistsLoaderInterface && !$loader->exists($name)) {
126
- continue;
127
- }
128
-
129
- try {
130
- return $loader->isFresh($name, $time);
131
- } catch (Twig_Error_Loader $e) {
132
- $exceptions[] = get_class($loader).': '.$e->getMessage();
133
- }
134
- }
135
-
136
- throw new Twig_Error_Loader(sprintf('Template "%s" is not defined (%s).', $name, implode(' ', $exceptions)));
137
- }
138
- }
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2011 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ /**
13
+ * Loads templates from other loaders.
14
+ *
15
+ * @author Fabien Potencier <fabien@symfony.com>
16
+ */
17
+ class Twig_Loader_Chain implements Twig_LoaderInterface, Twig_ExistsLoaderInterface
18
+ {
19
+ private $hasSourceCache = array();
20
+ protected $loaders = array();
21
+
22
+ /**
23
+ * Constructor.
24
+ *
25
+ * @param Twig_LoaderInterface[] $loaders An array of loader instances
26
+ */
27
+ public function __construct(array $loaders = array())
28
+ {
29
+ foreach ($loaders as $loader) {
30
+ $this->addLoader($loader);
31
+ }
32
+ }
33
+
34
+ /**
35
+ * Adds a loader instance.
36
+ *
37
+ * @param Twig_LoaderInterface $loader A Loader instance
38
+ */
39
+ public function addLoader(Twig_LoaderInterface $loader)
40
+ {
41
+ $this->loaders[] = $loader;
42
+ $this->hasSourceCache = array();
43
+ }
44
+
45
+ /**
46
+ * {@inheritdoc}
47
+ */
48
+ public function getSource($name)
49
+ {
50
+ $exceptions = array();
51
+ foreach ($this->loaders as $loader) {
52
+ if ($loader instanceof Twig_ExistsLoaderInterface && !$loader->exists($name)) {
53
+ continue;
54
+ }
55
+
56
+ try {
57
+ return $loader->getSource($name);
58
+ } catch (Twig_Error_Loader $e) {
59
+ $exceptions[] = $e->getMessage();
60
+ }
61
+ }
62
+
63
+ throw new Twig_Error_Loader(sprintf('Template "%s" is not defined (%s).', $name, implode(', ', $exceptions)));
64
+ }
65
+
66
+ /**
67
+ * {@inheritdoc}
68
+ */
69
+ public function exists($name)
70
+ {
71
+ $name = (string) $name;
72
+
73
+ if (isset($this->hasSourceCache[$name])) {
74
+ return $this->hasSourceCache[$name];
75
+ }
76
+
77
+ foreach ($this->loaders as $loader) {
78
+ if ($loader instanceof Twig_ExistsLoaderInterface) {
79
+ if ($loader->exists($name)) {
80
+ return $this->hasSourceCache[$name] = true;
81
+ }
82
+
83
+ continue;
84
+ }
85
+
86
+ try {
87
+ $loader->getSource($name);
88
+
89
+ return $this->hasSourceCache[$name] = true;
90
+ } catch (Twig_Error_Loader $e) {
91
+ }
92
+ }
93
+
94
+ return $this->hasSourceCache[$name] = false;
95
+ }
96
+
97
+ /**
98
+ * {@inheritdoc}
99
+ */
100
+ public function getCacheKey($name)
101
+ {
102
+ $exceptions = array();
103
+ foreach ($this->loaders as $loader) {
104
+ if ($loader instanceof Twig_ExistsLoaderInterface && !$loader->exists($name)) {
105
+ continue;
106
+ }
107
+
108
+ try {
109
+ return $loader->getCacheKey($name);
110
+ } catch (Twig_Error_Loader $e) {
111
+ $exceptions[] = get_class($loader).': '.$e->getMessage();
112
+ }
113
+ }
114
+
115
+ throw new Twig_Error_Loader(sprintf('Template "%s" is not defined (%s).', $name, implode(' ', $exceptions)));
116
+ }
117
+
118
+ /**
119
+ * {@inheritdoc}
120
+ */
121
+ public function isFresh($name, $time)
122
+ {
123
+ $exceptions = array();
124
+ foreach ($this->loaders as $loader) {
125
+ if ($loader instanceof Twig_ExistsLoaderInterface && !$loader->exists($name)) {
126
+ continue;
127
+ }
128
+
129
+ try {
130
+ return $loader->isFresh($name, $time);
131
+ } catch (Twig_Error_Loader $e) {
132
+ $exceptions[] = get_class($loader).': '.$e->getMessage();
133
+ }
134
+ }
135
+
136
+ throw new Twig_Error_Loader(sprintf('Template "%s" is not defined (%s).', $name, implode(' ', $exceptions)));
137
+ }
138
+ }
classes/Twig/Loader/Filesystem.php CHANGED
@@ -1,236 +1,236 @@
1
- <?php
2
-
3
- /*
4
- * This file is part of Twig.
5
- *
6
- * (c) 2009 Fabien Potencier
7
- *
8
- * For the full copyright and license information, please view the LICENSE
9
- * file that was distributed with this source code.
10
- */
11
-
12
- /**
13
- * Loads template from the filesystem.
14
- *
15
- * @author Fabien Potencier <fabien@symfony.com>
16
- */
17
- class Twig_Loader_Filesystem implements Twig_LoaderInterface, Twig_ExistsLoaderInterface
18
- {
19
- /** Identifier of the main namespace. */
20
- const MAIN_NAMESPACE = '__main__';
21
-
22
- protected $paths = array();
23
- protected $cache = array();
24
-
25
- /**
26
- * Constructor.
27
- *
28
- * @param string|array $paths A path or an array of paths where to look for templates
29
- */
30
- public function __construct($paths = array())
31
- {
32
- if ($paths) {
33
- $this->setPaths($paths);
34
- }
35
- }
36
-
37
- /**
38
- * Returns the paths to the templates.
39
- *
40
- * @param string $namespace A path namespace
41
- *
42
- * @return array The array of paths where to look for templates
43
- */
44
- public function getPaths($namespace = self::MAIN_NAMESPACE)
45
- {
46
- return isset($this->paths[$namespace]) ? $this->paths[$namespace] : array();
47
- }
48
-
49
- /**
50
- * Returns the path namespaces.
51
- *
52
- * The main namespace is always defined.
53
- *
54
- * @return array The array of defined namespaces
55
- */
56
- public function getNamespaces()
57
- {
58
- return array_keys($this->paths);
59
- }
60
-
61
- /**
62
- * Sets the paths where templates are stored.
63
- *
64
- * @param string|array $paths A path or an array of paths where to look for templates
65
- * @param string $namespace A path namespace
66
- */
67
- public function setPaths($paths, $namespace = self::MAIN_NAMESPACE)
68
- {
69
- if (!is_array($paths)) {
70
- $paths = array($paths);
71
- }
72
-
73
- $this->paths[$namespace] = array();
74
- foreach ($paths as $path) {
75
- $this->addPath($path, $namespace);
76
- }
77
- }
78
-
79
- /**
80
- * Adds a path where templates are stored.
81
- *
82
- * @param string $path A path where to look for templates
83
- * @param string $namespace A path name
84
- *
85
- * @throws Twig_Error_Loader
86
- */
87
- public function addPath($path, $namespace = self::MAIN_NAMESPACE)
88
- {
89
- // invalidate the cache
90
- $this->cache = array();
91
-
92
- if (!is_dir($path)) {
93
- throw new Twig_Error_Loader(sprintf('The "%s" directory does not exist.', $path));
94
- }
95
-
96
- $this->paths[$namespace][] = rtrim($path, '/\\');
97
- }
98
-
99
- /**
100
- * Prepends a path where templates are stored.
101
- *
102
- * @param string $path A path where to look for templates
103
- * @param string $namespace A path name
104
- *
105
- * @throws Twig_Error_Loader
106
- */
107
- public function prependPath($path, $namespace = self::MAIN_NAMESPACE)
108
- {
109
- // invalidate the cache
110
- $this->cache = array();
111
-
112
- if (!is_dir($path)) {
113
- throw new Twig_Error_Loader(sprintf('The "%s" directory does not exist.', $path));
114
- }
115
-
116
- $path = rtrim($path, '/\\');
117
-
118
- if (!isset($this->paths[$namespace])) {
119
- $this->paths[$namespace][] = $path;
120
- } else {
121
- array_unshift($this->paths[$namespace], $path);
122
- }
123
- }
124
-
125
- /**
126
- * {@inheritdoc}
127
- */
128
- public function getSource($name)
129
- {
130
- return file_get_contents($this->findTemplate($name));
131
- }
132
-
133
- /**
134
- * {@inheritdoc}
135
- */
136
- public function getCacheKey($name)
137
- {
138
- return $this->findTemplate($name);
139
- }
140
-
141
- /**
142
- * {@inheritdoc}
143
- */
144
- public function exists($name)
145
- {
146
- $name = $this->normalizeName($name);
147
-
148
- if (isset($this->cache[$name])) {
149
- return true;
150
- }
151
-
152
- try {
153
- $this->findTemplate($name);
154
-
155
- return true;
156
- } catch (Twig_Error_Loader $exception) {
157
- return false;
158
- }
159
- }
160
-
161
- /**
162
- * {@inheritdoc}
163
- */
164
- public function isFresh($name, $time)
165
- {
166
- return filemtime($this->findTemplate($name)) <= $time;
167
- }
168
-
169
- protected function findTemplate($name)
170
- {
171
- $name = $this->normalizeName($name);
172
-
173
- if (isset($this->cache[$name])) {
174
- return $this->cache[$name];
175
- }
176
-
177
- $this->validateName($name);
178
-
179
- list($namespace, $shortname) = $this->parseName($name);
180
-
181
- if (!isset($this->paths[$namespace])) {
182
- throw new Twig_Error_Loader(sprintf('There are no registered paths for namespace "%s".', $namespace));
183
- }
184
-
185
- foreach ($this->paths[$namespace] as $path) {
186
- if (is_file($path.'/'.$shortname)) {
187
- return $this->cache[$name] = $path.'/'.$shortname;
188
- }
189
- }
190
-
191
- throw new Twig_Error_Loader(sprintf('Unable to find template "%s" (looked into: %s).', $name, implode(', ', $this->paths[$namespace])));
192
- }
193
-
194
- protected function parseName($name, $default = self::MAIN_NAMESPACE)
195
- {
196
- if (isset($name[0]) && '@' == $name[0]) {
197
- if (false === $pos = strpos($name, '/')) {
198
- throw new Twig_Error_Loader(sprintf('Malformed namespaced template name "%s" (expecting "@namespace/template_name").', $name));
199
- }
200
-
201
- $namespace = substr($name, 1, $pos - 1);
202
- $shortname = substr($name, $pos + 1);
203
-
204
- return array($namespace, $shortname);
205
- }
206
-
207
- return array($default, $name);
208
- }
209
-
210
- protected function normalizeName($name)
211
- {
212
- return preg_replace('#/{2,}#', '/', strtr((string) $name, '\\', '/'));
213
- }
214
-
215
- protected function validateName($name)
216
- {
217
- if (false !== strpos($name, "\0")) {
218
- throw new Twig_Error_Loader('A template name cannot contain NUL bytes.');
219
- }
220
-
221
- $name = ltrim($name, '/');
222
- $parts = explode('/', $name);
223
- $level = 0;
224
- foreach ($parts as $part) {
225
- if ('..' === $part) {
226
- --$level;
227
- } elseif ('.' !== $part) {
228
- ++$level;
229
- }
230
-
231
- if ($level < 0) {
232
- throw new Twig_Error_Loader(sprintf('Looks like you try to load a template outside configured directories (%s).', $name));
233
- }
234
- }
235
- }
236
- }
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2009 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ /**
13
+ * Loads template from the filesystem.
14
+ *
15
+ * @author Fabien Potencier <fabien@symfony.com>
16
+ */
17
+ class Twig_Loader_Filesystem implements Twig_LoaderInterface, Twig_ExistsLoaderInterface
18
+ {
19
+ /** Identifier of the main namespace. */
20
+ const MAIN_NAMESPACE = '__main__';
21
+
22
+ protected $paths = array();
23
+ protected $cache = array();
24
+
25
+ /**
26
+ * Constructor.
27
+ *
28
+ * @param string|array $paths A path or an array of paths where to look for templates
29
+ */
30
+ public function __construct($paths = array())
31
+ {
32
+ if ($paths) {
33
+ $this->setPaths($paths);
34
+ }
35
+ }
36
+
37
+ /**
38
+ * Returns the paths to the templates.
39
+ *
40
+ * @param string $namespace A path namespace
41
+ *
42
+ * @return array The array of paths where to look for templates
43
+ */
44
+ public function getPaths($namespace = self::MAIN_NAMESPACE)
45
+ {
46
+ return isset($this->paths[$namespace]) ? $this->paths[$namespace] : array();
47
+ }
48
+
49
+ /**
50
+ * Returns the path namespaces.
51
+ *
52
+ * The main namespace is always defined.
53
+ *
54
+ * @return array The array of defined namespaces
55
+ */
56
+ public function getNamespaces()
57
+ {
58
+ return array_keys($this->paths);
59
+ }
60
+
61
+ /**
62
+ * Sets the paths where templates are stored.
63
+ *
64
+ * @param string|array $paths A path or an array of paths where to look for templates
65
+ * @param string $namespace A path namespace
66
+ */
67
+ public function setPaths($paths, $namespace = self::MAIN_NAMESPACE)
68
+ {
69
+ if (!is_array($paths)) {
70
+ $paths = array($paths);
71
+ }
72
+
73
+ $this->paths[$namespace] = array();
74
+ foreach ($paths as $path) {
75
+ $this->addPath($path, $namespace);
76
+ }
77
+ }
78
+
79
+ /**
80
+ * Adds a path where templates are stored.
81
+ *
82
+ * @param string $path A path where to look for templates
83
+ * @param string $namespace A path name
84
+ *
85
+ * @throws Twig_Error_Loader
86
+ */
87
+ public function addPath($path, $namespace = self::MAIN_NAMESPACE)
88
+ {
89
+ // invalidate the cache
90
+ $this->cache = array();
91
+
92
+ if (!is_dir($path)) {
93
+ throw new Twig_Error_Loader(sprintf('The "%s" directory does not exist.', $path));
94
+ }
95
+
96
+ $this->paths[$namespace][] = rtrim($path, '/\\');
97
+ }
98
+
99
+ /**
100
+ * Prepends a path where templates are stored.
101
+ *
102
+ * @param string $path A path where to look for templates
103
+ * @param string $namespace A path name
104
+ *
105
+ * @throws Twig_Error_Loader
106
+ */
107
+ public function prependPath($path, $namespace = self::MAIN_NAMESPACE)
108
+ {
109
+ // invalidate the cache
110
+ $this->cache = array();
111
+
112
+ if (!is_dir($path)) {
113
+ throw new Twig_Error_Loader(sprintf('The "%s" directory does not exist.', $path));
114
+ }
115
+
116
+ $path = rtrim($path, '/\\');
117
+
118
+ if (!isset($this->paths[$namespace])) {
119
+ $this->paths[$namespace][] = $path;
120
+ } else {
121
+ array_unshift($this->paths[$namespace], $path);
122
+ }
123
+ }
124
+
125
+ /**
126
+ * {@inheritdoc}
127
+ */
128
+ public function getSource($name)
129
+ {
130
+ return file_get_contents($this->findTemplate($name));
131
+ }
132
+
133
+ /**
134
+ * {@inheritdoc}
135
+ */
136
+ public function getCacheKey($name)
137
+ {
138
+ return $this->findTemplate($name);
139
+ }
140
+
141
+ /**
142
+ * {@inheritdoc}
143
+ */
144
+ public function exists($name)
145
+ {
146
+ $name = $this->normalizeName($name);
147
+
148
+ if (isset($this->cache[$name])) {
149
+ return true;
150
+ }
151
+
152
+ try {
153
+ $this->findTemplate($name);
154
+
155
+ return true;
156
+ } catch (Twig_Error_Loader $exception) {
157
+ return false;
158
+ }
159
+ }
160
+
161
+ /**
162
+ * {@inheritdoc}
163
+ */
164
+ public function isFresh($name, $time)
165
+ {
166
+ return filemtime($this->findTemplate($name)) <= $time;
167
+ }
168
+
169
+ protected function findTemplate($name)
170
+ {
171
+ $name = $this->normalizeName($name);
172
+
173
+ if (isset($this->cache[$name])) {
174
+ return $this->cache[$name];
175
+ }
176
+
177
+ $this->validateName($name);
178
+
179
+ list($namespace, $shortname) = $this->parseName($name);
180
+
181
+ if (!isset($this->paths[$namespace])) {
182
+ throw new Twig_Error_Loader(sprintf('There are no registered paths for namespace "%s".', $namespace));
183
+ }
184
+
185
+ foreach ($this->paths[$namespace] as $path) {
186
+ if (is_file($path.'/'.$shortname)) {
187
+ return $this->cache[$name] = $path.'/'.$shortname;
188
+ }
189
+ }
190
+
191
+ throw new Twig_Error_Loader(sprintf('Unable to find template "%s" (looked into: %s).', $name, implode(', ', $this->paths[$namespace])));
192
+ }
193
+
194
+ protected function parseName($name, $default = self::MAIN_NAMESPACE)
195
+ {
196
+ if (isset($name[0]) && '@' == $name[0]) {
197
+ if (false === $pos = strpos($name, '/')) {
198
+ throw new Twig_Error_Loader(sprintf('Malformed namespaced template name "%s" (expecting "@namespace/template_name").', $name));
199
+ }
200
+
201
+ $namespace = substr($name, 1, $pos - 1);
202
+ $shortname = substr($name, $pos + 1);
203
+
204
+ return array($namespace, $shortname);
205
+ }
206
+
207
+ return array($default, $name);
208
+ }
209
+
210
+ protected function normalizeName($name)
211
+ {
212
+ return preg_replace('#/{2,}#', '/', strtr((string) $name, '\\', '/'));
213
+ }
214
+
215
+ protected function validateName($name)
216
+ {
217
+ if (false !== strpos($name, "\0")) {
218
+ throw new Twig_Error_Loader('A template name cannot contain NUL bytes.');
219
+ }
220
+
221
+ $name = ltrim($name, '/');
222
+ $parts = explode('/', $name);
223
+ $level = 0;
224
+ foreach ($parts as $part) {
225
+ if ('..' === $part) {
226
+ --$level;
227
+ } elseif ('.' !== $part) {
228
+ ++$level;
229
+ }
230
+
231
+ if ($level < 0) {
232
+ throw new Twig_Error_Loader(sprintf('Looks like you try to load a template outside configured directories (%s).', $name));
233
+ }
234
+ }
235
+ }
236
+ }
classes/Twig/Loader/String.php CHANGED
@@ -1,59 +1,59 @@
1
- <?php
2
-
3
- /*
4
- * This file is part of Twig.
5
- *
6
- * (c) 2009 Fabien Potencier
7
- *
8
- * For the full copyright and license information, please view the LICENSE
9
- * file that was distributed with this source code.
10
- */
11
-
12
- /**
13
- * Loads a template from a string.
14
- *
15
- * This loader should only be used for unit testing as it has many limitations
16
- * (for instance, the include or extends tag does not make any sense for a string
17
- * loader).
18
- *
19
- * When using this loader with a cache mechanism, you should know that a new cache
20
- * key is generated each time a template content "changes" (the cache key being the
21
- * source code of the template). If you don't want to see your cache grows out of
22
- * control, you need to take care of clearing the old cache file by yourself.
23
- *
24
- * @author Fabien Potencier <fabien@symfony.com>
25
- */
26
- class Twig_Loader_String implements Twig_LoaderInterface, Twig_ExistsLoaderInterface
27
- {
28
- /**
29
- * {@inheritdoc}
30
- */
31
- public function getSource($name)
32
- {
33
- return $name;
34
- }
35
-
36
- /**
37
- * {@inheritdoc}
38
- */
39
- public function exists($name)
40
- {
41
- return true;
42
- }
43
-
44
- /**
45
- * {@inheritdoc}
46
- */
47
- public function getCacheKey($name)
48
- {
49
- return $name;
50
- }
51
-
52
- /**
53
- * {@inheritdoc}
54
- */
55
- public function isFresh($name, $time)
56
- {
57
- return true;
58
- }
59
- }
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2009 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ /**
13
+ * Loads a template from a string.
14
+ *
15
+ * This loader should only be used for unit testing as it has many limitations
16
+ * (for instance, the include or extends tag does not make any sense for a string
17
+ * loader).
18
+ *
19
+ * When using this loader with a cache mechanism, you should know that a new cache
20
+ * key is generated each time a template content "changes" (the cache key being the
21
+ * source code of the template). If you don't want to see your cache grows out of
22
+ * control, you need to take care of clearing the old cache file by yourself.
23
+ *
24
+ * @author Fabien Potencier <fabien@symfony.com>
25
+ */
26
+ class Twig_Loader_String implements Twig_LoaderInterface, Twig_ExistsLoaderInterface
27
+ {
28
+ /**
29
+ * {@inheritdoc}
30
+ */
31
+ public function getSource($name)
32
+ {
33
+ return $name;
34
+ }
35
+
36
+ /**
37
+ * {@inheritdoc}
38
+ */
39
+ public function exists($name)
40
+ {
41
+ return true;
42
+ }
43
+
44
+ /**
45
+ * {@inheritdoc}
46
+ */
47
+ public function getCacheKey($name)
48
+ {
49
+ return $name;
50
+ }
51
+
52
+ /**
53
+ * {@inheritdoc}
54
+ */
55
+ public function isFresh($name, $time)
56
+ {
57
+ return true;
58
+ }
59
+ }
classes/Twig/LoaderInterface.php CHANGED
@@ -1,52 +1,52 @@
1
- <?php
2
-
3
- /*
4
- * This file is part of Twig.
5
- *
6
- * (c) 2009 Fabien Potencier
7
- *
8
- * For the full copyright and license information, please view the LICENSE
9
- * file that was distributed with this source code.
10
- */
11
-
12
- /**
13
- * Interface all loaders must implement.
14
- *
15
- * @author Fabien Potencier <fabien@symfony.com>
16
- */
17
- interface Twig_LoaderInterface
18
- {
19
- /**
20
- * Gets the source code of a template, given its name.
21
- *
22
- * @param string $name The name of the template to load
23
- *
24
- * @return string The template source code
25
- *
26
- * @throws Twig_Error_Loader When $name is not found
27
- */
28
- public function getSource($name);
29
-
30
- /**
31
- * Gets the cache key to use for the cache for a given template name.
32
- *
33
- * @param string $name The name of the template to load
34
- *
35
- * @return string The cache key
36
- *
37
- * @throws Twig_Error_Loader When $name is not found
38
- */
39
- public function getCacheKey($name);
40
-
41
- /**
42
- * Returns true if the template is still fresh.
43
- *
44
- * @param string $name The template name
45
- * @param timestamp $time The last modification time of the cached template
46
- *
47
- * @return bool true if the template is fresh, false otherwise
48
- *
49
- * @throws Twig_Error_Loader When $name is not found
50
- */
51
- public function isFresh($name, $time);
52
- }
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2009 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ /**
13
+ * Interface all loaders must implement.
14
+ *
15
+ * @author Fabien Potencier <fabien@symfony.com>
16
+ */
17
+ interface Twig_LoaderInterface
18
+ {
19
+ /**
20
+ * Gets the source code of a template, given its name.
21
+ *
22
+ * @param string $name The name of the template to load
23
+ *
24
+ * @return string The template source code
25
+ *
26
+ * @throws Twig_Error_Loader When $name is not found
27
+ */
28
+ public function getSource($name);
29
+
30
+ /**
31
+ * Gets the cache key to use for the cache for a given template name.
32
+ *
33
+ * @param string $name The name of the template to load
34
+ *
35
+ * @return string The cache key
36
+ *
37
+ * @throws Twig_Error_Loader When $name is not found
38
+ */
39
+ public function getCacheKey($name);
40
+
41
+ /**
42
+ * Returns true if the template is still fresh.
43
+ *
44
+ * @param string $name The template name
45
+ * @param timestamp $time The last modification time of the cached template
46
+ *
47
+ * @return bool true if the template is fresh, false otherwise
48
+ *
49
+ * @throws Twig_Error_Loader When $name is not found
50
+ */
51
+ public function isFresh($name, $time);
52
+ }
classes/Twig/Markup.php CHANGED
@@ -1,37 +1,37 @@
1
- <?php
2
-
3
- /*
4
- * This file is part of Twig.
5
- *
6
- * (c) 2010 Fabien Potencier
7
- *
8
- * For the full copyright and license information, please view the LICENSE
9
- * file that was distributed with this source code.
10
- */
11
-
12
- /**
13
- * Marks a content as safe.
14
- *
15
- * @author Fabien Potencier <fabien@symfony.com>
16
- */
17
- class Twig_Markup implements Countable
18
- {
19
- protected $content;
20
- protected $charset;
21
-
22
- public function __construct($content, $charset)
23
- {
24
- $this->content = (string) $content;
25
- $this->charset = $charset;
26
- }
27
-
28
- public function __toString()
29
- {
30
- return $this->content;
31
- }
32
-
33
- public function count()
34
- {
35
- return function_exists('mb_get_info') ? mb_strlen($this->content, $this->charset) : strlen($this->content);
36
- }
37
- }
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2010 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ /**
13
+ * Marks a content as safe.
14
+ *
15
+ * @author Fabien Potencier <fabien@symfony.com>
16
+ */
17
+ class Twig_Markup implements Countable
18
+ {
19
+ protected $content;
20
+ protected $charset;
21
+
22
+ public function __construct($content, $charset)
23
+ {
24
+ $this->content = (string) $content;
25
+ $this->charset = $charset;
26
+ }
27
+
28
+ public function __toString()
29
+ {
30
+ return $this->content;
31
+ }
32
+
33
+ public function count()
34
+ {
35
+ return function_exists('mb_get_info') ? mb_strlen($this->content, $this->charset) : strlen($this->content);
36
+ }
37
+ }
classes/Twig/Node.php CHANGED
@@ -1,226 +1,226 @@
1
- <?php
2
-
3
- /*
4
- * This file is part of Twig.
5
- *
6
- * (c) 2009 Fabien Potencier
7
- * (c) 2009 Armin Ronacher
8
- *
9
- * For the full copyright and license information, please view the LICENSE
10
- * file that was distributed with this source code.
11
- */
12
-
13
- /**
14
- * Represents a node in the AST.
15
- *
16
- * @author Fabien Potencier <fabien@symfony.com>
17
- */
18
- class Twig_Node implements Twig_NodeInterface
19
- {
20
- protected $nodes;
21
- protected $attributes;
22
- protected $lineno;
23
- protected $tag;
24
-
25
- /**
26
- * Constructor.
27
- *
28
- * The nodes are automatically made available as properties ($this->node).
29
- * The attributes are automatically made available as array items ($this['name']).
30
- *
31
- * @param array $nodes An array of named nodes
32
- * @param array $attributes An array of attributes (should not be nodes)
33
- * @param int $lineno The line number
34
- * @param string $tag The tag name associated with the Node
35
- */
36
- public function __construct(array $nodes = array(), array $attributes = array(), $lineno = 0, $tag = null)
37
- {
38
- $this->nodes = $nodes;
39
- $this->attributes = $attributes;
40
- $this->lineno = $lineno;
41
- $this->tag = $tag;
42
- }
43
-
44
- public function __toString()
45
- {
46
- $attributes = array();
47
- foreach ($this->attributes as $name => $value) {
48
- $attributes[] = sprintf('%s: %s', $name, str_replace("\n", '', var_export($value, true)));
49
- }
50
-
51
- $repr = array(get_class($this).'('.implode(', ', $attributes));
52
-
53
- if (count($this->nodes)) {
54
- foreach ($this->nodes as $name => $node) {
55
- $len = strlen($name) + 4;
56
- $noderepr = array();
57
- foreach (explode("\n", (string) $node) as $line) {
58
- $noderepr[] = str_repeat(' ', $len).$line;
59
- }
60
-
61
- $repr[] = sprintf(' %s: %s', $name, ltrim(implode("\n", $noderepr)));
62
- }
63
-
64
- $repr[] = ')';
65
- } else {
66
- $repr[0] .= ')';
67
- }
68
-
69
- return implode("\n", $repr);
70
- }
71
-
72
- public function toXml($asDom = false)
73
- {
74
- $dom = new DOMDocument('1.0', 'UTF-8');
75
- $dom->formatOutput = true;
76
- $dom->appendChild($xml = $dom->createElement('twig'));
77
-
78
- $xml->appendChild($node = $dom->createElement('node'));
79
- $node->setAttribute('class', get_class($this));
80
-
81
- foreach ($this->attributes as $name => $value) {
82
- $node->appendChild($attribute = $dom->createElement('attribute'));
83
- $attribute->setAttribute('name', $name);
84
- $attribute->appendChild($dom->createTextNode($value));
85
- }
86
-
87
- foreach ($this->nodes as $name => $n) {
88
- if (null === $n) {
89
- continue;
90
- }
91
-
92
- $child = $n->toXml(true)->getElementsByTagName('node')->item(0);
93
- $child = $dom->importNode($child, true);
94
- $child->setAttribute('name', $name);
95
-
96
- $node->appendChild($child);
97
- }
98
-
99
- return $asDom ? $dom : $dom->saveXml();
100
- }
101
-
102
- public function compile(Twig_Compiler $compiler)
103
- {
104
- foreach ($this->nodes as $node) {
105
- $node->compile($compiler);
106
- }
107
- }
108
-
109
- public function getLine()
110
- {
111
- return $this->lineno;
112
- }
113
-
114
- public function getNodeTag()
115
- {
116
- return $this->tag;
117
- }
118
-
119
- /**
120
- * Returns true if the attribute is defined.
121
- *
122
- * @param string The attribute name
123
- *
124
- * @return bool true if the attribute is defined, false otherwise
125
- */
126
- public function hasAttribute($name)
127
- {
128
- return array_key_exists($name, $this->attributes);
129
- }
130
-
131
- /**
132
- * Gets an attribute.
133
- *
134
- * @param string The attribute name
135
- *
136
- * @return mixed The attribute value
137
- */
138
- public function getAttribute($name)
139
- {
140
- if (!array_key_exists($name, $this->attributes)) {
141
- throw new LogicException(sprintf('Attribute "%s" does not exist for Node "%s".', $name, get_class($this)));
142
- }
143
-
144
- return $this->attributes[$name];
145
- }
146
-
147
- /**
148
- * Sets an attribute.
149
- *
150
- * @param string The attribute name
151
- * @param mixed The attribute value
152
- */
153
- public function setAttribute($name, $value)
154
- {
155
- $this->attributes[$name] = $value;
156
- }
157
-
158
- /**
159
- * Removes an attribute.
160
- *
161
- * @param string The attribute name
162
- */
163
- public function removeAttribute($name)
164
- {
165
- unset($this->attributes[$name]);
166
- }
167
-
168
- /**
169
- * Returns true if the node with the given identifier exists.
170
- *
171
- * @param string The node name
172
- *
173
- * @return bool true if the node with the given name exists, false otherwise
174
- */
175
- public function hasNode($name)
176
- {
177
- return array_key_exists($name, $this->nodes);
178
- }
179
-
180
- /**
181
- * Gets a node by name.
182
- *
183
- * @param string The node name
184
- *
185
- * @return Twig_Node A Twig_Node instance
186
- */
187
- public function getNode($name)
188
- {
189
- if (!array_key_exists($name, $this->nodes)) {
190
- throw new LogicException(sprintf('Node "%s" does not exist for Node "%s".', $name, get_class($this)));
191
- }
192
-
193
- return $this->nodes[$name];
194
- }
195
-
196
- /**
197
- * Sets a node.
198
- *
199
- * @param string The node name
200
- * @param Twig_Node A Twig_Node instance
201
- */
202
- public function setNode($name, $node = null)
203
- {
204
- $this->nodes[$name] = $node;
205
- }
206
-
207
- /**
208
- * Removes a node by name.
209
- *
210
- * @param string The node name
211
- */
212
- public function removeNode($name)
213
- {
214
- unset($this->nodes[$name]);
215
- }
216
-
217
- public function count()
218
- {
219
- return count($this->nodes);
220
- }
221
-
222
- public function getIterator()
223
- {
224
- return new ArrayIterator($this->nodes);
225
- }
226
- }
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2009 Fabien Potencier
7
+ * (c) 2009 Armin Ronacher
8
+ *
9
+ * For the full copyright and license information, please view the LICENSE
10
+ * file that was distributed with this source code.
11
+ */
12
+
13
+ /**
14
+ * Represents a node in the AST.
15
+ *
16
+ * @author Fabien Potencier <fabien@symfony.com>
17
+ */
18
+ class Twig_Node implements Twig_NodeInterface
19
+ {
20
+ protected $nodes;
21
+ protected $attributes;
22
+ protected $lineno;
23
+ protected $tag;
24
+
25
+ /**
26
+ * Constructor.
27
+ *
28
+ * The nodes are automatically made available as properties ($this->node).
29
+ * The attributes are automatically made available as array items ($this['name']).
30
+ *
31
+ * @param array $nodes An array of named nodes
32
+ * @param array $attributes An array of attributes (should not be nodes)
33
+ * @param int $lineno The line number
34
+ * @param string $tag The tag name associated with the Node
35
+ */
36
+ public function __construct(array $nodes = array(), array $attributes = array(), $lineno = 0, $tag = null)
37
+ {
38
+ $this->nodes = $nodes;
39
+ $this->attributes = $attributes;
40
+ $this->lineno = $lineno;
41
+ $this->tag = $tag;
42
+ }
43
+
44
+ public function __toString()
45
+ {
46
+ $attributes = array();
47
+ foreach ($this->attributes as $name => $value) {
48
+ $attributes[] = sprintf('%s: %s', $name, str_replace("\n", '', var_export($value, true)));
49
+ }
50
+
51
+ $repr = array(get_class($this).'('.implode(', ', $attributes));
52
+
53
+ if (count($this->nodes)) {
54
+ foreach ($this->nodes as $name => $node) {
55
+ $len = strlen($name) + 4;
56
+ $noderepr = array();
57
+ foreach (explode("\n", (string) $node) as $line) {
58
+ $noderepr[] = str_repeat(' ', $len).$line;
59
+ }
60
+
61
+ $repr[] = sprintf(' %s: %s', $name, ltrim(implode("\n", $noderepr)));
62
+ }
63
+
64
+ $repr[] = ')';
65
+ } else {
66
+ $repr[0] .= ')';
67
+ }
68
+
69
+ return implode("\n", $repr);
70
+ }
71
+
72
+ public function toXml($asDom = false)
73
+ {
74
+ $dom = new DOMDocument('1.0', 'UTF-8');
75
+ $dom->formatOutput = true;
76
+ $dom->appendChild($xml = $dom->createElement('twig'));
77
+
78
+ $xml->appendChild($node = $dom->createElement('node'));
79
+ $node->setAttribute('class', get_class($this));
80
+
81
+ foreach ($this->attributes as $name => $value) {
82
+ $node->appendChild($attribute = $dom->createElement('attribute'));
83
+ $attribute->setAttribute('name', $name);
84
+ $attribute->appendChild($dom->createTextNode($value));
85
+ }
86
+
87
+ foreach ($this->nodes as $name => $n) {
88
+ if (null === $n) {
89
+ continue;
90
+ }
91
+
92
+ $child = $n->toXml(true)->getElementsByTagName('node')->item(0);
93
+ $child = $dom->importNode($child, true);
94
+ $child->setAttribute('name', $name);
95
+
96
+ $node->appendChild($child);
97
+ }
98
+
99
+ return $asDom ? $dom : $dom->saveXml();
100
+ }
101
+
102
+ public function compile(Twig_Compiler $compiler)
103
+ {
104
+ foreach ($this->nodes as $node) {
105
+ $node->compile($compiler);
106
+ }
107
+ }
108
+
109
+ public function getLine()
110
+ {
111
+ return $this->lineno;
112
+ }
113
+
114
+ public function getNodeTag()
115
+ {
116
+ return $this->tag;
117
+ }
118
+
119
+ /**
120
+ * Returns true if the attribute is defined.
121
+ *
122
+ * @param string The attribute name
123
+ *
124
+ * @return bool true if the attribute is defined, false otherwise
125
+ */
126
+ public function hasAttribute($name)
127
+ {
128
+ return array_key_exists($name, $this->attributes);
129
+ }
130
+
131
+ /**
132
+ * Gets an attribute.
133
+ *
134
+ * @param string The attribute name
135
+ *
136
+ * @return mixed The attribute value
137
+ */
138
+ public function getAttribute($name)
139
+ {
140
+ if (!array_key_exists($name, $this->attributes)) {
141
+ throw new LogicException(sprintf('Attribute "%s" does not exist for Node "%s".', $name, get_class($this)));
142
+ }
143
+
144
+ return $this->attributes[$name];
145
+ }
146
+
147
+ /**
148
+ * Sets an attribute.
149
+ *
150
+ * @param string The attribute name
151
+ * @param mixed The attribute value
152
+ */
153
+ public function setAttribute($name, $value)
154
+ {
155
+ $this->attributes[$name] = $value;
156
+ }
157
+
158
+ /**
159
+ * Removes an attribute.
160
+ *
161
+ * @param string The attribute name
162
+ */
163
+ public function removeAttribute($name)
164
+ {
165
+ unset($this->attributes[$name]);
166
+ }
167
+
168
+ /**
169
+ * Returns true if the node with the given identifier exists.
170
+ *
171
+ * @param string The node name
172
+ *
173
+ * @return bool true if the node with the given name exists, false otherwise
174
+ */
175
+ public function hasNode($name)
176
+ {
177
+ return array_key_exists($name, $this->nodes);
178
+ }
179
+
180
+ /**
181
+ * Gets a node by name.
182
+ *
183
+ * @param string The node name
184
+ *
185
+ * @return Twig_Node A Twig_Node instance
186
+ */
187
+ public function getNode($name)
188
+ {
189
+ if (!array_key_exists($name, $this->nodes)) {
190
+ throw new LogicException(sprintf('Node "%s" does not exist for Node "%s".', $name, get_class($this)));
191
+ }
192
+
193
+ return $this->nodes[$name];
194
+ }
195
+
196
+ /**
197
+ * Sets a node.
198
+ *
199
+ * @param string The node name
200
+ * @param Twig_Node A Twig_Node instance
201
+ */
202
+ public function setNode($name, $node = null)
203
+ {
204
+ $this->nodes[$name] = $node;
205
+ }
206
+
207
+ /**
208
+ * Removes a node by name.
209
+ *
210
+ * @param string The node name
211
+ */
212
+ public function removeNode($name)
213
+ {
214
+ unset($this->nodes[$name]);
215
+ }
216
+
217
+ public function count()
218
+ {
219
+ return count($this->nodes);
220
+ }
221
+
222
+ public function getIterator()
223
+ {
224
+ return new ArrayIterator($this->nodes);
225
+ }
226
+ }
classes/Twig/Node/AutoEscape.php CHANGED
@@ -1,39 +1,39 @@
1
- <?php
2
-
3
- /*
4
- * This file is part of Twig.
5
- *
6
- * (c) 2009 Fabien Potencier
7
- *
8
- * For the full copyright and license information, please view the LICENSE
9
- * file that was distributed with this source code.
10
- */
11
-
12
- /**
13
- * Represents an autoescape node.
14
- *
15
- * The value is the escaping strategy (can be html, js, ...)
16
- *
17
- * The true value is equivalent to html.
18
- *
19
- * If autoescaping is disabled, then the value is false.
20
- *
21
- * @author Fabien Potencier <fabien@symfony.com>
22
- */
23
- class Twig_Node_AutoEscape extends Twig_Node
24
- {
25
- public function __construct($value, Twig_NodeInterface $body, $lineno, $tag = 'autoescape')
26
- {
27
- parent::__construct(array('body' => $body), array('value' => $value), $lineno, $tag);
28
- }
29
-
30
- /**
31
- * Compiles the node to PHP.
32
- *
33
- * @param Twig_Compiler A Twig_Compiler instance
34
- */
35
- public function compile(Twig_Compiler $compiler)
36
- {
37
- $compiler->subcompile($this->getNode('body'));
38
- }
39
- }
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2009 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ /**
13
+ * Represents an autoescape node.
14
+ *
15
+ * The value is the escaping strategy (can be html, js, ...)
16
+ *
17
+ * The true value is equivalent to html.
18
+ *
19
+ * If autoescaping is disabled, then the value is false.
20
+ *
21
+ * @author Fabien Potencier <fabien@symfony.com>
22
+ */
23
+ class Twig_Node_AutoEscape extends Twig_Node
24
+ {
25
+ public function __construct($value, Twig_NodeInterface $body, $lineno, $tag = 'autoescape')
26
+ {
27
+ parent::__construct(array('body' => $body), array('value' => $value), $lineno, $tag);
28
+ }
29
+
30
+ /**
31
+ * Compiles the node to PHP.
32
+ *
33
+ * @param Twig_Compiler A Twig_Compiler instance
34
+ */
35
+ public function compile(Twig_Compiler $compiler)
36
+ {
37
+ $compiler->subcompile($this->getNode('body'));
38
+ }
39
+ }
classes/Twig/Node/Block.php CHANGED
@@ -1,44 +1,44 @@
1
- <?php
2
-
3
- /*
4
- * This file is part of Twig.
5
- *
6
- * (c) 2009 Fabien Potencier
7
- * (c) 2009 Armin Ronacher
8
- *
9
- * For the full copyright and license information, please view the LICENSE
10
- * file that was distributed with this source code.
11
- */
12
-
13
- /**
14
- * Represents a block node.
15
- *
16
- * @author Fabien Potencier <fabien@symfony.com>
17
- */
18
- class Twig_Node_Block extends Twig_Node
19
- {
20
- public function __construct($name, Twig_NodeInterface $body, $lineno, $tag = null)
21
- {
22
- parent::__construct(array('body' => $body), array('name' => $name), $lineno, $tag);
23
- }
24
-
25
- /**
26
- * Compiles the node to PHP.
27
- *
28
- * @param Twig_Compiler A Twig_Compiler instance
29
- */
30
- public function compile(Twig_Compiler $compiler)
31
- {
32
- $compiler
33
- ->addDebugInfo($this)
34
- ->write(sprintf("public function block_%s(\$context, array \$blocks = array())\n", $this->getAttribute('name')), "{\n")
35
- ->indent()
36
- ;
37
-
38
- $compiler
39
- ->subcompile($this->getNode('body'))
40
- ->outdent()
41
- ->write("}\n\n")
42
- ;
43
- }
44
- }
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2009 Fabien Potencier
7
+ * (c) 2009 Armin Ronacher
8
+ *
9
+ * For the full copyright and license information, please view the LICENSE
10
+ * file that was distributed with this source code.
11
+ */
12
+
13
+ /**
14
+ * Represents a block node.
15
+ *
16
+ * @author Fabien Potencier <fabien@symfony.com>
17
+ */
18
+ class Twig_Node_Block extends Twig_Node
19
+ {
20
+ public function __construct($name, Twig_NodeInterface $body, $lineno, $tag = null)
21
+ {
22
+ parent::__construct(array('body' => $body), array('name' => $name), $lineno, $tag);
23
+ }
24
+
25
+ /**
26
+ * Compiles the node to PHP.
27
+ *
28
+ * @param Twig_Compiler A Twig_Compiler instance
29
+ */
30
+ public function compile(Twig_Compiler $compiler)
31
+ {
32
+ $compiler
33
+ ->addDebugInfo($this)
34
+ ->write(sprintf("public function block_%s(\$context, array \$blocks = array())\n", $this->getAttribute('name')), "{\n")
35
+ ->indent()
36
+ ;
37
+
38
+ $compiler
39
+ ->subcompile($this->getNode('body'))
40
+ ->outdent()
41
+ ->write("}\n\n")
42
+ ;
43
+ }
44
+ }
classes/Twig/Node/BlockReference.php CHANGED
@@ -1,37 +1,37 @@
1
- <?php
2
-
3
- /*
4
- * This file is part of Twig.
5
- *
6
- * (c) 2009 Fabien Potencier
7
- * (c) 2009 Armin Ronacher
8
- *
9
- * For the full copyright and license information, please view the LICENSE
10
- * file that was distributed with this source code.
11
- */
12
-
13
- /**
14
- * Represents a block call node.
15
- *
16
- * @author Fabien Potencier <fabien@symfony.com>
17
- */
18
- class Twig_Node_BlockReference extends Twig_Node implements Twig_NodeOutputInterface
19
- {
20
- public function __construct($name, $lineno, $tag = null)
21
- {
22
- parent::__construct(array(), array('name' => $name), $lineno, $tag);
23
- }
24
-
25
- /**
26
- * Compiles the node to PHP.
27
- *
28
- * @param Twig_Compiler A Twig_Compiler instance
29
- */
30
- public function compile(Twig_Compiler $compiler)
31
- {
32
- $compiler
33
- ->addDebugInfo($this)
34
- ->write(sprintf("\$this->displayBlock('%s', \$context, \$blocks);\n", $this->getAttribute('name')))
35
- ;
36
- }
37
- }
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2009 Fabien Potencier
7
+ * (c) 2009 Armin Ronacher
8
+ *
9
+ * For the full copyright and license information, please view the LICENSE
10
+ * file that was distributed with this source code.
11
+ */
12
+
13
+ /**
14
+ * Represents a block call node.
15
+ *
16
+ * @author Fabien Potencier <fabien@symfony.com>
17
+ */
18
+ class Twig_Node_BlockReference extends Twig_Node implements Twig_NodeOutputInterface
19
+ {
20
+ public function __construct($name, $lineno, $tag = null)
21
+ {
22
+ parent::__construct(array(), array('name' => $name), $lineno, $tag);
23
+ }
24
+
25
+ /**
26
+ * Compiles the node to PHP.
27
+ *
28
+ * @param Twig_Compiler A Twig_Compiler instance
29
+ */
30
+ public function compile(Twig_Compiler $compiler)
31
+ {
32
+ $compiler
33
+ ->addDebugInfo($this)
34
+ ->write(sprintf("\$this->displayBlock('%s', \$context, \$blocks);\n", $this->getAttribute('name')))
35
+ ;
36
+ }
37
+ }
classes/Twig/Node/Body.php CHANGED
@@ -1,19 +1,19 @@
1
- <?php
2
-
3
- /*
4
- * This file is part of Twig.
5
- *
6
- * (c) 2011 Fabien Potencier
7
- *
8
- * For the full copyright and license information, please view the LICENSE
9
- * file that was distributed with this source code.
10
- */
11
-
12
- /**
13
- * Represents a body node.
14
- *
15
- * @author Fabien Potencier <fabien@symfony.com>
16
- */
17
- class Twig_Node_Body extends Twig_Node
18
- {
19
- }
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2011 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ /**
13
+ * Represents a body node.
14
+ *
15
+ * @author Fabien Potencier <fabien@symfony.com>
16
+ */
17
+ class Twig_Node_Body extends Twig_Node
18
+ {
19
+ }
classes/Twig/Node/Do.php CHANGED
@@ -1,38 +1,38 @@
1
- <?php
2
-
3
- /*
4
- * This file is part of Twig.
5
- *
6
- * (c) 2011 Fabien Potencier
7
- *
8
- * For the full copyright and license information, please view the LICENSE
9
- * file that was distributed with this source code.
10
- */
11
-
12
- /**
13
- * Represents a do node.
14
- *
15
- * @author Fabien Potencier <fabien@symfony.com>
16
- */
17
- class Twig_Node_Do extends Twig_Node
18
- {
19
- public function __construct(Twig_Node_Expression $expr, $lineno, $tag = null)
20
- {
21
- parent::__construct(array('expr' => $expr), array(), $lineno, $tag);
22
- }
23
-
24
- /**
25
- * Compiles the node to PHP.
26
- *
27
- * @param Twig_Compiler A Twig_Compiler instance
28
- */
29
- public function compile(Twig_Compiler $compiler)
30
- {
31
- $compiler
32
- ->addDebugInfo($this)
33
- ->write('')
34
- ->subcompile($this->getNode('expr'))
35
- ->raw(";\n")
36
- ;
37
- }
38
- }
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2011 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ /**
13
+ * Represents a do node.
14
+ *
15
+ * @author Fabien Potencier <fabien@symfony.com>
16
+ */
17
+ class Twig_Node_Do extends Twig_Node
18
+ {
19
+ public function __construct(Twig_Node_Expression $expr, $lineno, $tag = null)
20
+ {
21
+ parent::__construct(array('expr' => $expr), array(), $lineno, $tag);
22
+ }
23
+
24
+ /**
25
+ * Compiles the node to PHP.
26
+ *
27
+ * @param Twig_Compiler A Twig_Compiler instance
28
+ */
29
+ public function compile(Twig_Compiler $compiler)
30
+ {
31
+ $compiler
32
+ ->addDebugInfo($this)
33
+ ->write('')
34
+ ->subcompile($this->getNode('expr'))
35
+ ->raw(";\n")
36
+ ;
37
+ }
38
+ }
classes/Twig/Node/Embed.php CHANGED
@@ -1,38 +1,38 @@
1
- <?php
2
-
3
- /*
4
- * This file is part of Twig.
5
- *
6
- * (c) 2012 Fabien Potencier
7
- *
8
- * For the full copyright and license information, please view the LICENSE
9
- * file that was distributed with this source code.
10
- */
11
-
12
- /**
13
- * Represents an embed node.
14
- *
15
- * @author Fabien Potencier <fabien@symfony.com>
16
- */
17
- class Twig_Node_Embed extends Twig_Node_Include
18
- {
19
- // we don't inject the module to avoid node visitors to traverse it twice (as it will be already visited in the main module)
20
- public function __construct($filename, $index, Twig_Node_Expression $variables = null, $only = false, $ignoreMissing = false, $lineno, $tag = null)
21
- {
22
- parent::__construct(new Twig_Node_Expression_Constant('not_used', $lineno), $variables, $only, $ignoreMissing, $lineno, $tag);
23
-
24
- $this->setAttribute('filename', $filename);
25
- $this->setAttribute('index', $index);
26
- }
27
-
28
- protected function addGetTemplate(Twig_Compiler $compiler)
29
- {
30
- $compiler
31
- ->write("\$this->env->loadTemplate(")
32
- ->string($this->getAttribute('filename'))
33
- ->raw(', ')
34
- ->string($this->getAttribute('index'))
35
- ->raw(")")
36
- ;
37
- }
38
- }
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2012 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ /**
13
+ * Represents an embed node.
14
+ *
15
+ * @author Fabien Potencier <fabien@symfony.com>
16
+ */
17
+ class Twig_Node_Embed extends Twig_Node_Include
18
+ {
19
+ // we don't inject the module to avoid node visitors to traverse it twice (as it will be already visited in the main module)
20
+ public function __construct($filename, $index, Twig_Node_Expression $variables = null, $only = false, $ignoreMissing = false, $lineno, $tag = null)
21
+ {
22
+ parent::__construct(new Twig_Node_Expression_Constant('not_used', $lineno), $variables, $only, $ignoreMissing, $lineno, $tag);
23
+
24
+ $this->setAttribute('filename', $filename);
25
+ $this->setAttribute('index', $index);
26
+ }
27
+
28
+ protected function addGetTemplate(Twig_Compiler $compiler)
29
+ {
30
+ $compiler
31
+ ->write("\$this->env->loadTemplate(")
32
+ ->string($this->getAttribute('filename'))
33
+ ->raw(', ')
34
+ ->string($this->getAttribute('index'))
35
+ ->raw(")")
36
+ ;
37
+ }
38
+ }
classes/Twig/Node/Expression.php CHANGED
@@ -1,20 +1,20 @@
1
- <?php
2
-
3
- /*
4
- * This file is part of Twig.
5
- *
6
- * (c) 2009 Fabien Potencier
7
- * (c) 2009 Armin Ronacher
8
- *
9
- * For the full copyright and license information, please view the LICENSE
10
- * file that was distributed with this source code.
11
- */
12
-
13
- /**
14
- * Abstract class for all nodes that represents an expression.
15
- *
16
- * @author Fabien Potencier <fabien@symfony.com>
17
- */
18
- abstract class Twig_Node_Expression extends Twig_Node
19
- {
20
- }
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2009 Fabien Potencier
7
+ * (c) 2009 Armin Ronacher
8
+ *
9
+ * For the full copyright and license information, please view the LICENSE
10
+ * file that was distributed with this source code.
11
+ */
12
+
13
+ /**
14
+ * Abstract class for all nodes that represents an expression.
15
+ *
16
+ * @author Fabien Potencier <fabien@symfony.com>
17
+ */
18
+ abstract class Twig_Node_Expression extends Twig_Node
19
+ {
20
+ }
classes/Twig/Node/Expression/Array.php CHANGED
@@ -1,86 +1,86 @@
1
- <?php
2
-
3
- /*
4
- * This file is part of Twig.
5
- *
6
- * (c) 2009 Fabien Potencier
7
- *
8
- * For the full copyright and license information, please view the LICENSE
9
- * file that was distributed with this source code.
10
- */
11
- class Twig_Node_Expression_Array extends Twig_Node_Expression
12
- {
13
- protected $index;
14
-
15
- public function __construct(array $elements, $lineno)
16
- {
17
- parent::__construct($elements, array(), $lineno);
18
-
19
- $this->index = -1;
20
- foreach ($this->getKeyValuePairs() as $pair) {
21
- if ($pair['key'] instanceof Twig_Node_Expression_Constant && ctype_digit((string) $pair['key']->getAttribute('value')) && $pair['key']->getAttribute('value') > $this->index) {
22
- $this->index = $pair['key']->getAttribute('value');
23
- }
24
- }
25
- }
26
-
27
- public function getKeyValuePairs()
28
- {
29
- $pairs = array();
30
-
31
- foreach (array_chunk($this->nodes, 2) as $pair) {
32
- $pairs[] = array(
33
- 'key' => $pair[0],
34
- 'value' => $pair[1],
35
- );
36
- }
37
-
38
- return $pairs;
39
- }
40
-
41
- public function hasElement(Twig_Node_Expression $key)
42
- {
43
- foreach ($this->getKeyValuePairs() as $pair) {
44
- // we compare the string representation of the keys
45
- // to avoid comparing the line numbers which are not relevant here.
46
- if ((string) $key == (string) $pair['key']) {
47
- return true;
48
- }
49
- }
50
-
51
- return false;
52
- }
53
-
54
- public function addElement(Twig_Node_Expression $value, Twig_Node_Expression $key = null)
55
- {
56
- if (null === $key) {
57
- $key = new Twig_Node_Expression_Constant(++$this->index, $value->getLine());
58
- }
59
-
60
- array_push($this->nodes, $key, $value);
61
- }
62
-
63
- /**
64
- * Compiles the node to PHP.
65
- *
66
- * @param Twig_Compiler A Twig_Compiler instance
67
- */
68
- public function compile(Twig_Compiler $compiler)
69
- {
70
- $compiler->raw('array(');
71
- $first = true;
72
- foreach ($this->getKeyValuePairs() as $pair) {
73
- if (!$first) {
74
- $compiler->raw(', ');
75
- }
76
- $first = false;
77
-
78
- $compiler
79
- ->subcompile($pair['key'])
80
- ->raw(' => ')
81
- ->subcompile($pair['value'])
82
- ;
83
- }
84
- $compiler->raw(')');
85
- }
86
- }
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2009 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+ class Twig_Node_Expression_Array extends Twig_Node_Expression
12
+ {
13
+ protected $index;
14
+
15
+ public function __construct(array $elements, $lineno)
16
+ {
17
+ parent::__construct($elements, array(), $lineno);
18
+
19
+ $this->index = -1;
20
+ foreach ($this->getKeyValuePairs() as $pair) {
21
+ if ($pair['key'] instanceof Twig_Node_Expression_Constant && ctype_digit((string) $pair['key']->getAttribute('value')) && $pair['key']->getAttribute('value') > $this->index) {
22
+ $this->index = $pair['key']->getAttribute('value');
23
+ }
24
+ }
25
+ }
26
+
27
+ public function getKeyValuePairs()
28
+ {
29
+ $pairs = array();
30
+
31
+ foreach (array_chunk($this->nodes, 2) as $pair) {
32
+ $pairs[] = array(
33
+ 'key' => $pair[0],
34
+ 'value' => $pair[1],
35
+ );
36
+ }
37
+
38
+ return $pairs;
39
+ }
40
+
41
+ public function hasElement(Twig_Node_Expression $key)
42
+ {
43
+ foreach ($this->getKeyValuePairs() as $pair) {
44
+ // we compare the string representation of the keys
45
+ // to avoid comparing the line numbers which are not relevant here.
46
+ if ((string) $key == (string) $pair['key']) {
47
+ return true;
48
+ }
49
+ }
50
+
51
+ return false;
52
+ }
53
+
54
+ public function addElement(Twig_Node_Expression $value, Twig_Node_Expression $key = null)
55
+ {
56
+ if (null === $key) {
57
+ $key = new Twig_Node_Expression_Constant(++$this->index, $value->getLine());
58
+ }
59
+
60
+ array_push($this->nodes, $key, $value);
61
+ }
62
+
63
+ /**
64
+ * Compiles the node to PHP.
65
+ *
66
+ * @param Twig_Compiler A Twig_Compiler instance
67
+ */
68
+ public function compile(Twig_Compiler $compiler)
69
+ {
70
+ $compiler->raw('array(');
71
+ $first = true;
72
+ foreach ($this->getKeyValuePairs() as $pair) {
73
+ if (!$first) {
74
+ $compiler->raw(', ');
75
+ }
76
+ $first = false;
77
+
78
+ $compiler
79
+ ->subcompile($pair['key'])
80
+ ->raw(' => ')
81
+ ->subcompile($pair['value'])
82
+ ;
83
+ }
84
+ $compiler->raw(')');
85
+ }
86
+ }
classes/Twig/Node/Expression/AssignName.php CHANGED
@@ -1,28 +1,28 @@
1
- <?php
2
-
3
- /*
4
- * This file is part of Twig.
5
- *
6
- * (c) 2009 Fabien Potencier
7
- * (c) 2009 Armin Ronacher
8
- *
9
- * For the full copyright and license information, please view the LICENSE
10
- * file that was distributed with this source code.
11
- */
12
-
13
- class Twig_Node_Expression_AssignName extends Twig_Node_Expression_Name
14
- {
15
- /**
16
- * Compiles the node to PHP.
17
- *
18
- * @param Twig_Compiler A Twig_Compiler instance
19
- */
20
- public function compile(Twig_Compiler $compiler)
21
- {
22
- $compiler
23
- ->raw('$context[')
24
- ->string($this->getAttribute('name'))
25
- ->raw(']')
26
- ;
27
- }
28
- }
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2009 Fabien Potencier
7
+ * (c) 2009 Armin Ronacher
8
+ *
9
+ * For the full copyright and license information, please view the LICENSE
10
+ * file that was distributed with this source code.
11
+ */
12
+
13
+ class Twig_Node_Expression_AssignName extends Twig_Node_Expression_Name
14
+ {
15
+ /**
16
+ * Compiles the node to PHP.
17
+ *
18
+ * @param Twig_Compiler A Twig_Compiler instance
19
+ */
20
+ public function compile(Twig_Compiler $compiler)
21
+ {
22
+ $compiler
23
+ ->raw('$context[')
24
+ ->string($this->getAttribute('name'))
25
+ ->raw(']')
26
+ ;
27
+ }
28
+ }
classes/Twig/Node/Expression/Binary.php CHANGED
@@ -1,40 +1,40 @@
1
- <?php
2
-
3
- /*
4
- * This file is part of Twig.
5
- *
6
- * (c) 2009 Fabien Potencier
7
- * (c) 2009 Armin Ronacher
8
- *
9
- * For the full copyright and license information, please view the LICENSE
10
- * file that was distributed with this source code.
11
- */
12
- abstract class Twig_Node_Expression_Binary extends Twig_Node_Expression
13
- {
14
- public function __construct(Twig_NodeInterface $left, Twig_NodeInterface $right, $lineno)
15
- {
16
- parent::__construct(array('left' => $left, 'right' => $right), array(), $lineno);
17
- }
18
-
19
- /**
20
- * Compiles the node to PHP.
21
- *
22
- * @param Twig_Compiler A Twig_Compiler instance
23
- */
24
- public function compile(Twig_Compiler $compiler)
25
- {
26
- $compiler
27
- ->raw('(')
28
- ->subcompile($this->getNode('left'))
29
- ->raw(' ')
30
- ;
31
- $this->operator($compiler);
32
- $compiler
33
- ->raw(' ')
34
- ->subcompile($this->getNode('right'))
35
- ->raw(')')
36
- ;
37
- }
38
-
39
- abstract public function operator(Twig_Compiler $compiler);
40
- }
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2009 Fabien Potencier
7
+ * (c) 2009 Armin Ronacher
8
+ *
9
+ * For the full copyright and license information, please view the LICENSE
10
+ * file that was distributed with this source code.
11
+ */
12
+ abstract class Twig_Node_Expression_Binary extends Twig_Node_Expression
13
+ {
14
+ public function __construct(Twig_NodeInterface $left, Twig_NodeInterface $right, $lineno)
15
+ {
16
+ parent::__construct(array('left' => $left, 'right' => $right), array(), $lineno);
17
+ }
18
+
19
+ /**
20
+ * Compiles the node to PHP.
21
+ *
22
+ * @param Twig_Compiler A Twig_Compiler instance
23
+ */
24
+ public function compile(Twig_Compiler $compiler)
25
+ {
26
+ $compiler
27
+ ->raw('(')
28
+ ->subcompile($this->getNode('left'))
29
+ ->raw(' ')
30
+ ;
31
+ $this->operator($compiler);
32
+ $compiler
33
+ ->raw(' ')
34
+ ->subcompile($this->getNode('right'))
35
+ ->raw(')')
36
+ ;
37
+ }
38
+
39
+ abstract public function operator(Twig_Compiler $compiler);
40
+ }
classes/Twig/Node/Expression/Binary/Add.php CHANGED
@@ -1,18 +1,18 @@
1
- <?php
2
-
3
- /*
4
- * This file is part of Twig.
5
- *
6
- * (c) 2009 Fabien Potencier
7
- * (c) 2009 Armin Ronacher
8
- *
9
- * For the full copyright and license information, please view the LICENSE
10
- * file that was distributed with this source code.
11
- */
12
- class Twig_Node_Expression_Binary_Add extends Twig_Node_Expression_Binary
13
- {
14
- public function operator(Twig_Compiler $compiler)
15
- {
16
- return $compiler->raw('+');
17
- }
18
- }
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2009 Fabien Potencier
7
+ * (c) 2009 Armin Ronacher
8
+ *
9
+ * For the full copyright and license information, please view the LICENSE
10
+ * file that was distributed with this source code.
11
+ */
12
+ class Twig_Node_Expression_Binary_Add extends Twig_Node_Expression_Binary
13
+ {
14
+ public function operator(Twig_Compiler $compiler)
15
+ {
16
+ return $compiler->raw('+');
17
+ }
18
+ }
classes/Twig/Node/Expression/Binary/And.php CHANGED
@@ -1,18 +1,18 @@
1
- <?php
2
-
3
- /*
4
- * This file is part of Twig.
5
- *
6
- * (c) 2009 Fabien Potencier
7
- * (c) 2009 Armin Ronacher
8
- *
9
- * For the full copyright and license information, please view the LICENSE
10
- * file that was distributed with this source code.
11
- */
12
- class Twig_Node_Expression_Binary_And extends Twig_Node_Expression_Binary
13
- {
14
- public function operator(Twig_Compiler $compiler)
15
- {
16
- return $compiler->raw('&&');
17
- }
18
- }
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2009 Fabien Potencier
7
+ * (c) 2009 Armin Ronacher
8
+ *
9
+ * For the full copyright and license information, please view the LICENSE
10
+ * file that was distributed with this source code.
11
+ */
12
+ class Twig_Node_Expression_Binary_And extends Twig_Node_Expression_Binary
13
+ {
14
+ public function operator(Twig_Compiler $compiler)
15
+ {
16
+ return $compiler->raw('&&');
17
+ }
18
+ }
classes/Twig/Node/Expression/Binary/BitwiseAnd.php CHANGED
@@ -1,18 +1,18 @@
1
- <?php
2
-
3
- /*
4
- * This file is part of Twig.
5
- *
6
- * (c) 2009 Fabien Potencier
7
- * (c) 2009 Armin Ronacher
8
- *
9
- * For the full copyright and license information, please view the LICENSE
10
- * file that was distributed with this source code.
11
- */
12
- class Twig_Node_Expression_Binary_BitwiseAnd extends Twig_Node_Expression_Binary
13
- {
14
- public function operator(Twig_Compiler $compiler)
15
- {
16
- return $compiler->raw('&');
17
- }
18
- }
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2009 Fabien Potencier
7
+ * (c) 2009 Armin Ronacher
8
+ *
9
+ * For the full copyright and license information, please view the LICENSE
10
+ * file that was distributed with this source code.
11
+ */
12
+ class Twig_Node_Expression_Binary_BitwiseAnd extends Twig_Node_Expression_Binary
13
+ {
14
+ public function operator(Twig_Compiler $compiler)
15
+ {
16
+ return $compiler->raw('&');
17
+ }
18
+ }
classes/Twig/Node/Expression/Binary/BitwiseOr.php CHANGED
@@ -1,18 +1,18 @@
1
- <?php
2
-
3
- /*
4
- * This file is part of Twig.
5
- *
6
- * (c) 2009 Fabien Potencier
7
- * (c) 2009 Armin Ronacher
8
- *
9
- * For the full copyright and license information, please view the LICENSE
10
- * file that was distributed with this source code.
11
- */
12
- class Twig_Node_Expression_Binary_BitwiseOr extends Twig_Node_Expression_Binary
13
- {
14
- public function operator(Twig_Compiler $compiler)
15
- {
16
- return $compiler->raw('|');
17
- }
18
- }
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2009 Fabien Potencier
7
+ * (c) 2009 Armin Ronacher
8
+ *
9
+ * For the full copyright and license information, please view the LICENSE
10
+ * file that was distributed with this source code.
11
+ */
12
+ class Twig_Node_Expression_Binary_BitwiseOr extends Twig_Node_Expression_Binary
13
+ {
14
+ public function operator(Twig_Compiler $compiler)
15
+ {
16
+ return $compiler->raw('|');
17
+ }
18
+ }
classes/Twig/Node/Expression/Binary/BitwiseXor.php CHANGED
@@ -1,18 +1,18 @@
1
- <?php
2
-
3
- /*
4
- * This file is part of Twig.
5
- *
6
- * (c) 2009 Fabien Potencier
7
- * (c) 2009 Armin Ronacher
8
- *
9
- * For the full copyright and license information, please view the LICENSE
10
- * file that was distributed with this source code.
11
- */
12
- class Twig_Node_Expression_Binary_BitwiseXor extends Twig_Node_Expression_Binary
13
- {
14
- public function operator(Twig_Compiler $compiler)
15
- {
16
- return $compiler->raw('^');
17
- }
18
- }
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2009 Fabien Potencier
7
+ * (c) 2009 Armin Ronacher
8
+ *
9
+ * For the full copyright and license information, please view the LICENSE
10
+ * file that was distributed with this source code.
11
+ */
12
+ class Twig_Node_Expression_Binary_BitwiseXor extends Twig_Node_Expression_Binary
13
+ {
14
+ public function operator(Twig_Compiler $compiler)
15
+ {
16
+ return $compiler->raw('^');
17
+ }
18
+ }
classes/Twig/Node/Expression/Binary/Concat.php CHANGED
@@ -1,18 +1,18 @@
1
- <?php
2
-
3
- /*
4
- * This file is part of Twig.
5
- *
6
- * (c) 2009 Fabien Potencier
7
- * (c) 2009 Armin Ronacher
8
- *
9
- * For the full copyright and license information, please view the LICENSE
10
- * file that was distributed with this source code.
11
- */
12
- class Twig_Node_Expression_Binary_Concat extends Twig_Node_Expression_Binary
13
- {
14
- public function operator(Twig_Compiler $compiler)
15
- {
16
- return $compiler->raw('.');
17
- }
18
- }
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2009 Fabien Potencier
7
+ * (c) 2009 Armin Ronacher
8
+ *
9
+ * For the full copyright and license information, please view the LICENSE
10
+ * file that was distributed with this source code.
11
+ */
12
+ class Twig_Node_Expression_Binary_Concat extends Twig_Node_Expression_Binary
13
+ {
14
+ public function operator(Twig_Compiler $compiler)
15
+ {
16
+ return $compiler->raw('.');
17
+ }
18
+ }
classes/Twig/Node/Expression/Binary/Div.php CHANGED
@@ -1,18 +1,18 @@
1
- <?php
2
-
3
- /*
4
- * This file is part of Twig.
5
- *
6
- * (c) 2009 Fabien Potencier
7
- * (c) 2009 Armin Ronacher
8
- *
9
- * For the full copyright and license information, please view the LICENSE
10
- * file that was distributed with this source code.
11
- */
12
- class Twig_Node_Expression_Binary_Div extends Twig_Node_Expression_Binary
13
- {
14
- public function operator(Twig_Compiler $compiler)
15
- {
16
- return $compiler->raw('/');
17
- }
18
- }
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2009 Fabien Potencier
7
+ * (c) 2009 Armin Ronacher
8
+ *
9
+ * For the full copyright and license information, please view the LICENSE
10
+ * file that was distributed with this source code.
11
+ */
12
+ class Twig_Node_Expression_Binary_Div extends Twig_Node_Expression_Binary
13
+ {
14
+ public function operator(Twig_Compiler $compiler)
15
+ {
16
+ return $compiler->raw('/');
17
+ }
18
+ }
classes/Twig/Node/Expression/Binary/EndsWith.php CHANGED
@@ -1,30 +1,30 @@
1
- <?php
2
-
3
- /*
4
- * This file is part of Twig.
5
- *
6
- * (c) 2013 Fabien Potencier
7
- *
8
- * For the full copyright and license information, please view the LICENSE
9
- * file that was distributed with this source code.
10
- */
11
- class Twig_Node_Expression_Binary_EndsWith extends Twig_Node_Expression_Binary
12
- {
13
- public function compile(Twig_Compiler $compiler)
14
- {
15
- $compiler
16
- ->raw('(0 === substr_compare(')
17
- ->subcompile($this->getNode('left'))
18
- ->raw(', ')
19
- ->subcompile($this->getNode('right'))
20
- ->raw(', -strlen(')
21
- ->subcompile($this->getNode('right'))
22
- ->raw(')))')
23
- ;
24
- }
25
-
26
- public function operator(Twig_Compiler $compiler)
27
- {
28
- return $compiler->raw('');
29
- }
30
- }
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2013 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+ class Twig_Node_Expression_Binary_EndsWith extends Twig_Node_Expression_Binary
12
+ {
13
+ public function compile(Twig_Compiler $compiler)
14
+ {
15
+ $compiler
16
+ ->raw('(0 === substr_compare(')
17
+ ->subcompile($this->getNode('left'))
18
+ ->raw(', ')
19
+ ->subcompile($this->getNode('right'))
20
+ ->raw(', -strlen(')
21
+ ->subcompile($this->getNode('right'))
22
+ ->raw(')))')
23
+ ;
24
+ }
25
+
26
+ public function operator(Twig_Compiler $compiler)
27
+ {
28
+ return $compiler->raw('');
29
+ }
30
+ }
classes/Twig/Node/Expression/Binary/Equal.php CHANGED
@@ -1,17 +1,17 @@
1
- <?php
2
-
3
- /*
4
- * This file is part of Twig.
5
- *
6
- * (c) 2010 Fabien Potencier
7
- *
8
- * For the full copyright and license information, please view the LICENSE
9
- * file that was distributed with this source code.
10
- */
11
- class Twig_Node_Expression_Binary_Equal extends Twig_Node_Expression_Binary
12
- {
13
- public function operator(Twig_Compiler $compiler)
14
- {
15
- return $compiler->raw('==');
16
- }
17
- }
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2010 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+ class Twig_Node_Expression_Binary_Equal extends Twig_Node_Expression_Binary
12
+ {
13
+ public function operator(Twig_Compiler $compiler)
14
+ {
15
+ return $compiler->raw('==');
16
+ }
17
+ }
classes/Twig/Node/Expression/Binary/FloorDiv.php CHANGED
@@ -1,29 +1,29 @@
1
- <?php
2
-
3
- /*
4
- * This file is part of Twig.
5
- *
6
- * (c) 2009 Fabien Potencier
7
- *
8
- * For the full copyright and license information, please view the LICENSE
9
- * file that was distributed with this source code.
10
- */
11
- class Twig_Node_Expression_Binary_FloorDiv extends Twig_Node_Expression_Binary
12
- {
13
- /**
14
- * Compiles the node to PHP.
15
- *
16
- * @param Twig_Compiler A Twig_Compiler instance
17
- */
18
- public function compile(Twig_Compiler $compiler)
19
- {
20
- $compiler->raw('intval(floor(');
21
- parent::compile($compiler);
22
- $compiler->raw('))');
23
- }
24
-
25
- public function operator(Twig_Compiler $compiler)
26
- {
27
- return $compiler->raw('/');
28
- }
29
- }
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2009 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+ class Twig_Node_Expression_Binary_FloorDiv extends Twig_Node_Expression_Binary
12
+ {
13
+ /**
14
+ * Compiles the node to PHP.
15
+ *
16
+ * @param Twig_Compiler A Twig_Compiler instance
17
+ */
18
+ public function compile(Twig_Compiler $compiler)
19
+ {
20
+ $compiler->raw('intval(floor(');
21
+ parent::compile($compiler);
22
+ $compiler->raw('))');
23
+ }
24
+
25
+ public function operator(Twig_Compiler $compiler)
26
+ {
27
+ return $compiler->raw('/');
28
+ }
29
+ }
classes/Twig/Node/Expression/Binary/Greater.php CHANGED
@@ -1,17 +1,17 @@
1
- <?php
2
-
3
- /*
4
- * This file is part of Twig.
5
- *
6
- * (c) 2010 Fabien Potencier
7
- *
8
- * For the full copyright and license information, please view the LICENSE
9
- * file that was distributed with this source code.
10
- */
11
- class Twig_Node_Expression_Binary_Greater extends Twig_Node_Expression_Binary
12
- {
13
- public function operator(Twig_Compiler $compiler)
14
- {
15
- return $compiler->raw('>');
16
- }
17
- }
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2010 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+ class Twig_Node_Expression_Binary_Greater extends Twig_Node_Expression_Binary
12
+ {
13
+ public function operator(Twig_Compiler $compiler)
14
+ {
15
+ return $compiler->raw('>');
16
+ }
17
+ }
classes/Twig/Node/Expression/Binary/GreaterEqual.php CHANGED
@@ -1,17 +1,17 @@
1
- <?php
2
-
3
- /*
4
- * This file is part of Twig.
5
- *
6
- * (c) 2010 Fabien Potencier
7
- *
8
- * For the full copyright and license information, please view the LICENSE
9
- * file that was distributed with this source code.
10
- */
11
- class Twig_Node_Expression_Binary_GreaterEqual extends Twig_Node_Expression_Binary
12
- {
13
- public function operator(Twig_Compiler $compiler)
14
- {
15
- return $compiler->raw('>=');
16
- }
17
- }
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2010 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+ class Twig_Node_Expression_Binary_GreaterEqual extends Twig_Node_Expression_Binary
12
+ {
13
+ public function operator(Twig_Compiler $compiler)
14
+ {
15
+ return $compiler->raw('>=');
16
+ }
17
+ }
classes/Twig/Node/Expression/Binary/In.php CHANGED
@@ -1,33 +1,33 @@
1
- <?php
2
-
3
- /*
4
- * This file is part of Twig.
5
- *
6
- * (c) 2010 Fabien Potencier
7
- *
8
- * For the full copyright and license information, please view the LICENSE
9
- * file that was distributed with this source code.
10
- */
11
- class Twig_Node_Expression_Binary_In extends Twig_Node_Expression_Binary
12
- {
13
- /**
14
- * Compiles the node to PHP.
15
- *
16
- * @param Twig_Compiler A Twig_Compiler instance
17
- */
18
- public function compile(Twig_Compiler $compiler)
19
- {
20
- $compiler
21
- ->raw('twig_in_filter(')
22
- ->subcompile($this->getNode('left'))
23
- ->raw(', ')
24
- ->subcompile($this->getNode('right'))
25
- ->raw(')')
26
- ;
27
- }
28
-
29
- public function operator(Twig_Compiler $compiler)
30
- {
31
- return $compiler->raw('in');
32
- }
33
- }
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2010 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+ class Twig_Node_Expression_Binary_In extends Twig_Node_Expression_Binary
12
+ {
13
+ /**
14
+ * Compiles the node to PHP.
15
+ *
16
+ * @param Twig_Compiler A Twig_Compiler instance
17
+ */
18
+ public function compile(Twig_Compiler $compiler)
19
+ {
20
+ $compiler
21
+ ->raw('twig_in_filter(')
22
+ ->subcompile($this->getNode('left'))
23
+ ->raw(', ')
24
+ ->subcompile($this->getNode('right'))
25
+ ->raw(')')
26
+ ;
27
+ }
28
+
29
+ public function operator(Twig_Compiler $compiler)
30
+ {
31
+ return $compiler->raw('in');
32
+ }
33
+ }
classes/Twig/Node/Expression/Binary/Less.php CHANGED
@@ -1,17 +1,17 @@
1
- <?php
2
-
3
- /*
4
- * This file is part of Twig.
5
- *
6
- * (c) 2010 Fabien Potencier
7
- *
8
- * For the full copyright and license information, please view the LICENSE
9
- * file that was distributed with this source code.
10
- */
11
- class Twig_Node_Expression_Binary_Less extends Twig_Node_Expression_Binary
12
- {
13
- public function operator(Twig_Compiler $compiler)
14
- {
15
- return $compiler->raw('<');
16
- }
17
- }
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2010 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+ class Twig_Node_Expression_Binary_Less extends Twig_Node_Expression_Binary
12
+ {
13
+ public function operator(Twig_Compiler $compiler)
14
+ {
15
+ return $compiler->raw('<');
16
+ }
17
+ }
classes/Twig/Node/Expression/Binary/LessEqual.php CHANGED
@@ -1,17 +1,17 @@
1
- <?php
2
-
3
- /*
4
- * This file is part of Twig.
5
- *
6
- * (c) 2010 Fabien Potencier
7
- *
8
- * For the full copyright and license information, please view the LICENSE
9
- * file that was distributed with this source code.
10
- */
11
- class Twig_Node_Expression_Binary_LessEqual extends Twig_Node_Expression_Binary
12
- {
13
- public function operator(Twig_Compiler $compiler)
14
- {
15
- return $compiler->raw('<=');
16
- }
17
- }
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2010 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+ class Twig_Node_Expression_Binary_LessEqual extends Twig_Node_Expression_Binary
12
+ {
13
+ public function operator(Twig_Compiler $compiler)
14
+ {
15
+ return $compiler->raw('<=');
16
+ }
17
+ }
classes/Twig/Node/Expression/Binary/Matches.php CHANGED
@@ -1,28 +1,28 @@
1
- <?php
2
-
3
- /*
4
- * This file is part of Twig.
5
- *
6
- * (c) 2013 Fabien Potencier
7
- *
8
- * For the full copyright and license information, please view the LICENSE
9
- * file that was distributed with this source code.
10
- */
11
- class Twig_Node_Expression_Binary_Matches extends Twig_Node_Expression_Binary
12
- {
13
- public function compile(Twig_Compiler $compiler)
14
- {
15
- $compiler
16
- ->raw('preg_match(')
17
- ->subcompile($this->getNode('right'))
18
- ->raw(', ')
19
- ->subcompile($this->getNode('left'))
20
- ->raw(')')
21
- ;
22
- }
23
-
24
- public function operator(Twig_Compiler $compiler)
25
- {
26
- return $compiler->raw('');
27
- }
28
- }
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2013 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+ class Twig_Node_Expression_Binary_Matches extends Twig_Node_Expression_Binary
12
+ {
13
+ public function compile(Twig_Compiler $compiler)
14
+ {
15
+ $compiler
16
+ ->raw('preg_match(')
17
+ ->subcompile($this->getNode('right'))
18
+ ->raw(', ')
19
+ ->subcompile($this->getNode('left'))
20
+ ->raw(')')
21
+ ;
22
+ }
23
+
24
+ public function operator(Twig_Compiler $compiler)
25
+ {
26
+ return $compiler->raw('');
27
+ }
28
+ }
classes/Twig/Node/Expression/Binary/Mod.php CHANGED
@@ -1,18 +1,18 @@
1
- <?php
2
-
3
- /*
4
- * This file is part of Twig.
5
- *
6
- * (c) 2009 Fabien Potencier
7
- * (c) 2009 Armin Ronacher
8
- *
9
- * For the full copyright and license information, please view the LICENSE
10
- * file that was distributed with this source code.
11
- */
12
- class Twig_Node_Expression_Binary_Mod extends Twig_Node_Expression_Binary
13
- {
14
- public function operator(Twig_Compiler $compiler)
15
- {
16
- return $compiler->raw('%');
17
- }
18
- }
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2009 Fabien Potencier
7
+ * (c) 2009 Armin Ronacher
8
+ *
9
+ * For the full copyright and license information, please view the LICENSE
10
+ * file that was distributed with this source code.
11
+ */
12
+ class Twig_Node_Expression_Binary_Mod extends Twig_Node_Expression_Binary
13
+ {
14
+ public function operator(Twig_Compiler $compiler)
15
+ {
16
+ return $compiler->raw('%');
17
+ }
18
+ }
classes/Twig/Node/Expression/Binary/Mul.php CHANGED
@@ -1,18 +1,18 @@
1
- <?php
2
-
3
- /*
4
- * This file is part of Twig.
5
- *
6
- * (c) 2009 Fabien Potencier
7
- * (c) 2009 Armin Ronacher
8
- *
9
- * For the full copyright and license information, please view the LICENSE
10
- * file that was distributed with this source code.
11
- */
12
- class Twig_Node_Expression_Binary_Mul extends Twig_Node_Expression_Binary
13
- {
14
- public function operator(Twig_Compiler $compiler)
15
- {
16
- return $compiler->raw('*');
17
- }
18
- }
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2009 Fabien Potencier
7
+ * (c) 2009 Armin Ronacher
8
+ *
9
+ * For the full copyright and license information, please view the LICENSE
10
+ * file that was distributed with this source code.
11
+ */
12
+ class Twig_Node_Expression_Binary_Mul extends Twig_Node_Expression_Binary
13
+ {
14
+ public function operator(Twig_Compiler $compiler)
15
+ {
16
+ return $compiler->raw('*');
17
+ }
18
+ }
classes/Twig/Node/Expression/Binary/NotEqual.php CHANGED
@@ -1,17 +1,17 @@
1
- <?php
2
-
3
- /*
4
- * This file is part of Twig.
5
- *
6
- * (c) 2010 Fabien Potencier
7
- *
8
- * For the full copyright and license information, please view the LICENSE
9
- * file that was distributed with this source code.
10
- */
11
- class Twig_Node_Expression_Binary_NotEqual extends Twig_Node_Expression_Binary
12
- {
13
- public function operator(Twig_Compiler $compiler)
14
- {
15
- return $compiler->raw('!=');
16
- }
17
- }
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2010 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+ class Twig_Node_Expression_Binary_NotEqual extends Twig_Node_Expression_Binary
12
+ {
13
+ public function operator(Twig_Compiler $compiler)
14
+ {
15
+ return $compiler->raw('!=');
16
+ }
17
+ }
classes/Twig/Node/Expression/Binary/NotIn.php CHANGED
@@ -1,33 +1,33 @@
1
- <?php
2
-
3
- /*
4
- * This file is part of Twig.
5
- *
6
- * (c) 2010 Fabien Potencier
7
- *
8
- * For the full copyright and license information, please view the LICENSE
9
- * file that was distributed with this source code.
10
- */
11
- class Twig_Node_Expression_Binary_NotIn extends Twig_Node_Expression_Binary
12
- {
13
- /**
14
- * Compiles the node to PHP.
15
- *
16
- * @param Twig_Compiler A Twig_Compiler instance
17
- */
18
- public function compile(Twig_Compiler $compiler)
19
- {
20
- $compiler
21
- ->raw('!twig_in_filter(')
22
- ->subcompile($this->getNode('left'))
23
- ->raw(', ')
24
- ->subcompile($this->getNode('right'))
25
- ->raw(')')
26
- ;
27
- }
28
-
29
- public function operator(Twig_Compiler $compiler)
30
- {
31
- return $compiler->raw('not in');
32
- }
33
- }
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2010 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+ class Twig_Node_Expression_Binary_NotIn extends Twig_Node_Expression_Binary
12
+ {
13
+ /**
14
+ * Compiles the node to PHP.
15
+ *
16
+ * @param Twig_Compiler A Twig_Compiler instance
17
+ */
18
+ public function compile(Twig_Compiler $compiler)
19
+ {
20
+ $compiler
21
+ ->raw('!twig_in_filter(')
22
+ ->subcompile($this->getNode('left'))
23
+ ->raw(', ')
24
+ ->subcompile($this->getNode('right'))
25
+ ->raw(')')
26
+ ;
27
+ }
28
+
29
+ public function operator(Twig_Compiler $compiler)
30
+ {
31
+ return $compiler->raw('not in');
32
+ }
33
+ }
classes/Twig/Node/Expression/Binary/Or.php CHANGED
@@ -1,18 +1,18 @@
1
- <?php
2
-
3
- /*
4
- * This file is part of Twig.
5
- *
6
- * (c) 2009 Fabien Potencier
7
- * (c) 2009 Armin Ronacher
8
- *
9
- * For the full copyright and license information, please view the LICENSE
10
- * file that was distributed with this source code.
11
- */
12
- class Twig_Node_Expression_Binary_Or extends Twig_Node_Expression_Binary
13
- {
14
- public function operator(Twig_Compiler $compiler)
15
- {
16
- return $compiler->raw('||');
17
- }
18
- }
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2009 Fabien Potencier
7
+ * (c) 2009 Armin Ronacher
8
+ *
9
+ * For the full copyright and license information, please view the LICENSE
10
+ * file that was distributed with this source code.
11
+ */
12
+ class Twig_Node_Expression_Binary_Or extends Twig_Node_Expression_Binary
13
+ {
14
+ public function operator(Twig_Compiler $compiler)
15
+ {
16
+ return $compiler->raw('||');
17
+ }
18
+ }
classes/Twig/Node/Expression/Binary/Power.php CHANGED
@@ -1,33 +1,33 @@
1
- <?php
2
-
3
- /*
4
- * This file is part of Twig.
5
- *
6
- * (c) 2010 Fabien Potencier
7
- *
8
- * For the full copyright and license information, please view the LICENSE
9
- * file that was distributed with this source code.
10
- */
11
- class Twig_Node_Expression_Binary_Power extends Twig_Node_Expression_Binary
12
- {
13
- /**
14
- * Compiles the node to PHP.
15
- *
16
- * @param Twig_Compiler A Twig_Compiler instance
17
- */
18
- public function compile(Twig_Compiler $compiler)
19
- {
20
- $compiler
21
- ->raw('pow(')
22
- ->subcompile($this->getNode('left'))
23
- ->raw(', ')
24
- ->subcompile($this->getNode('right'))
25
- ->raw(')')
26
- ;
27
- }
28
-
29
- public function operator(Twig_Compiler $compiler)
30
- {
31
- return $compiler->raw('**');
32
- }
33
- }
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2010 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+ class Twig_Node_Expression_Binary_Power extends Twig_Node_Expression_Binary
12
+ {
13
+ /**
14
+ * Compiles the node to PHP.
15
+ *
16
+ * @param Twig_Compiler A Twig_Compiler instance
17
+ */
18
+ public function compile(Twig_Compiler $compiler)
19
+ {
20
+ $compiler
21
+ ->raw('pow(')
22
+ ->subcompile($this->getNode('left'))
23
+ ->raw(', ')
24
+ ->subcompile($this->getNode('right'))
25
+ ->raw(')')
26
+ ;
27
+ }
28
+
29
+ public function operator(Twig_Compiler $compiler)
30
+ {
31
+ return $compiler->raw('**');
32
+ }
33
+ }
classes/Twig/Node/Expression/Binary/Range.php CHANGED
@@ -1,33 +1,33 @@
1
- <?php
2
-
3
- /*
4
- * This file is part of Twig.
5
- *
6
- * (c) 2010 Fabien Potencier
7
- *
8
- * For the full copyright and license information, please view the LICENSE
9
- * file that was distributed with this source code.
10
- */
11
- class Twig_Node_Expression_Binary_Range extends Twig_Node_Expression_Binary
12
- {
13
- /**
14
- * Compiles the node to PHP.
15
- *
16
- * @param Twig_Compiler A Twig_Compiler instance
17
- */
18
- public function compile(Twig_Compiler $compiler)
19
- {
20
- $compiler
21
- ->raw('range(')
22
- ->subcompile($this->getNode('left'))
23
- ->raw(', ')
24
- ->subcompile($this->getNode('right'))
25
- ->raw(')')
26
- ;
27
- }
28
-
29
- public function operator(Twig_Compiler $compiler)
30
- {
31
- return $compiler->raw('..');
32
- }
33
- }
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2010 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+ class Twig_Node_Expression_Binary_Range extends Twig_Node_Expression_Binary
12
+ {
13
+ /**
14
+ * Compiles the node to PHP.
15
+ *
16
+ * @param Twig_Compiler A Twig_Compiler instance
17
+ */
18
+ public function compile(Twig_Compiler $compiler)
19
+ {
20
+ $compiler
21
+ ->raw('range(')
22
+ ->subcompile($this->getNode('left'))
23
+ ->raw(', ')
24
+ ->subcompile($this->getNode('right'))
25
+ ->raw(')')
26
+ ;
27
+ }
28
+
29
+ public function operator(Twig_Compiler $compiler)
30
+ {
31
+ return $compiler->raw('..');
32
+ }
33
+ }
classes/Twig/Node/Expression/Binary/StartsWith.php CHANGED
@@ -1,28 +1,28 @@
1
- <?php
2
-
3
- /*
4
- * This file is part of Twig.
5
- *
6
- * (c) 2013 Fabien Potencier
7
- *
8
- * For the full copyright and license information, please view the LICENSE
9
- * file that was distributed with this source code.
10
- */
11
- class Twig_Node_Expression_Binary_StartsWith extends Twig_Node_Expression_Binary
12
- {
13
- public function compile(Twig_Compiler $compiler)
14
- {
15
- $compiler
16
- ->raw('(0 === strpos(')
17
- ->subcompile($this->getNode('left'))
18
- ->raw(', ')
19
- ->subcompile($this->getNode('right'))
20
- ->raw('))')
21
- ;
22
- }
23
-
24
- public function operator(Twig_Compiler $compiler)
25
- {
26
- return $compiler->raw('');
27
- }
28
- }
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2013 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+ class Twig_Node_Expression_Binary_StartsWith extends Twig_Node_Expression_Binary
12
+ {
13
+ public function compile(Twig_Compiler $compiler)
14
+ {
15
+ $compiler
16
+ ->raw('(0 === strpos(')
17
+ ->subcompile($this->getNode('left'))
18
+ ->raw(', ')
19
+ ->subcompile($this->getNode('right'))
20
+ ->raw('))')
21
+ ;
22
+ }
23
+
24
+ public function operator(Twig_Compiler $compiler)
25
+ {
26
+ return $compiler->raw('');
27
+ }
28
+ }
classes/Twig/Node/Expression/Binary/Sub.php CHANGED
@@ -1,18 +1,18 @@
1
- <?php
2
-
3
- /*
4
- * This file is part of Twig.
5
- *
6
- * (c) 2009 Fabien Potencier
7
- * (c) 2009 Armin Ronacher
8
- *
9
- * For the full copyright and license information, please view the LICENSE
10
- * file that was distributed with this source code.
11
- */
12
- class Twig_Node_Expression_Binary_Sub extends Twig_Node_Expression_Binary
13
- {
14
- public function operator(Twig_Compiler $compiler)
15
- {
16
- return $compiler->raw('-');
17
- }
18
- }
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2009 Fabien Potencier
7
+ * (c) 2009 Armin Ronacher
8
+ *
9
+ * For the full copyright and license information, please view the LICENSE
10
+ * file that was distributed with this source code.
11
+ */
12
+ class Twig_Node_Expression_Binary_Sub extends Twig_Node_Expression_Binary
13
+ {
14
+ public function operator(Twig_Compiler $compiler)
15
+ {
16
+ return $compiler->raw('-');
17
+ }
18
+ }
classes/Twig/Node/Expression/BlockReference.php CHANGED
@@ -1,51 +1,51 @@
1
- <?php
2
-
3
- /*
4
- * This file is part of Twig.
5
- *
6
- * (c) 2009 Fabien Potencier
7
- * (c) 2009 Armin Ronacher
8
- *
9
- * For the full copyright and license information, please view the LICENSE
10
- * file that was distributed with this source code.
11
- */
12
-
13
- /**
14
- * Represents a block call node.
15
- *
16
- * @author Fabien Potencier <fabien@symfony.com>
17
- */
18
- class Twig_Node_Expression_BlockReference extends Twig_Node_Expression
19
- {
20
- public function __construct(Twig_NodeInterface $name, $asString = false, $lineno, $tag = null)
21
- {
22
- parent::__construct(array('name' => $name), array('as_string' => $asString, 'output' => false), $lineno, $tag);
23
- }
24
-
25
- /**
26
- * Compiles the node to PHP.
27
- *
28
- * @param Twig_Compiler A Twig_Compiler instance
29
- */
30
- public function compile(Twig_Compiler $compiler)
31
- {
32
- if ($this->getAttribute('as_string')) {
33
- $compiler->raw('(string) ');
34
- }
35
-
36
- if ($this->getAttribute('output')) {
37
- $compiler
38
- ->addDebugInfo($this)
39
- ->write("\$this->displayBlock(")
40
- ->subcompile($this->getNode('name'))
41
- ->raw(", \$context, \$blocks);\n")
42
- ;
43
- } else {
44
- $compiler
45
- ->raw("\$this->renderBlock(")
46
- ->subcompile($this->getNode('name'))
47
- ->raw(", \$context, \$blocks)")
48
- ;
49
- }
50
- }
51
- }
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2009 Fabien Potencier
7
+ * (c) 2009 Armin Ronacher
8
+ *
9
+ * For the full copyright and license information, please view the LICENSE
10
+ * file that was distributed with this source code.
11
+ */
12
+
13
+ /**
14
+ * Represents a block call node.
15
+ *
16
+ * @author Fabien Potencier <fabien@symfony.com>
17
+ */
18
+ class Twig_Node_Expression_BlockReference extends Twig_Node_Expression
19
+ {
20
+ public function __construct(Twig_NodeInterface $name, $asString = false, $lineno, $tag = null)
21
+ {
22
+ parent::__construct(array('name' => $name), array('as_string' => $asString, 'output' => false), $lineno, $tag);
23
+ }
24
+
25
+ /**
26
+ * Compiles the node to PHP.
27
+ *
28
+ * @param Twig_Compiler A Twig_Compiler instance
29
+ */
30
+ public function compile(Twig_Compiler $compiler)
31
+ {
32
+ if ($this->getAttribute('as_string')) {
33
+ $compiler->raw('(string) ');
34
+ }
35
+
36
+ if ($this->getAttribute('output')) {
37
+ $compiler
38
+ ->addDebugInfo($this)
39
+ ->write("\$this->displayBlock(")
40
+ ->subcompile($this->getNode('name'))
41
+ ->raw(", \$context, \$blocks);\n")
42
+ ;
43
+ } else {
44
+ $compiler
45
+ ->raw("\$this->renderBlock(")
46
+ ->subcompile($this->getNode('name'))
47
+ ->raw(", \$context, \$blocks)")
48
+ ;
49
+ }
50
+ }
51
+ }
classes/Twig/Node/Expression/Call.php CHANGED
@@ -1,176 +1,176 @@
1
- <?php
2
-
3
- /*
4
- * This file is part of Twig.
5
- *
6
- * (c) 2012 Fabien Potencier
7
- *
8
- * For the full copyright and license information, please view the LICENSE
9
- * file that was distributed with this source code.
10
- */
11
- abstract class Twig_Node_Expression_Call extends Twig_Node_Expression
12
- {
13
- protected function compileCallable(Twig_Compiler $compiler)
14
- {
15
- $closingParenthesis = false;
16
- if ($this->hasAttribute('callable') && $callable = $this->getAttribute('callable')) {
17
- if (is_string($callable)) {
18
- $compiler->raw($callable);
19
- } elseif (is_array($callable) && $callable[0] instanceof Twig_ExtensionInterface) {
20
- $compiler->raw(sprintf('$this->env->getExtension(\'%s\')->%s', $callable[0]->getName(), $callable[1]));
21
- } else {
22
- $type = ucfirst($this->getAttribute('type'));
23
- $compiler->raw(sprintf('call_user_func_array($this->env->get%s(\'%s\')->getCallable(), array', $type, $this->getAttribute('name')));
24
- $closingParenthesis = true;
25
- }
26
- } else {
27
- $compiler->raw($this->getAttribute('thing')->compile());
28
- }
29
-
30
- $this->compileArguments($compiler);
31
-
32
- if ($closingParenthesis) {
33
- $compiler->raw(')');
34
- }
35
- }
36
-
37
- protected function compileArguments(Twig_Compiler $compiler)
38
- {
39
- $compiler->raw('(');
40
-
41
- $first = true;
42
-
43
- if ($this->hasAttribute('needs_environment') && $this->getAttribute('needs_environment')) {
44
- $compiler->raw('$this->env');
45
- $first = false;
46
- }
47
-
48
- if ($this->hasAttribute('needs_context') && $this->getAttribute('needs_context')) {
49
- if (!$first) {
50
- $compiler->raw(', ');
51
- }
52
- $compiler->raw('$context');
53
- $first = false;
54
- }
55
-
56
- if ($this->hasAttribute('arguments')) {
57
- foreach ($this->getAttribute('arguments') as $argument) {
58
- if (!$first) {
59
- $compiler->raw(', ');
60
- }
61
- $compiler->string($argument);
62
- $first = false;
63
- }
64
- }
65
-
66
- if ($this->hasNode('node')) {
67
- if (!$first) {
68
- $compiler->raw(', ');
69
- }
70
- $compiler->subcompile($this->getNode('node'));
71
- $first = false;
72
- }
73
-
74
- if ($this->hasNode('arguments') && null !== $this->getNode('arguments')) {
75
- $callable = $this->hasAttribute('callable') ? $this->getAttribute('callable') : null;
76
-
77
- $arguments = $this->getArguments($callable, $this->getNode('arguments'));
78
-
79
- foreach ($arguments as $node) {
80
- if (!$first) {
81
- $compiler->raw(', ');
82
- }
83
- $compiler->subcompile($node);
84
- $first = false;
85
- }
86
- }
87
-
88
- $compiler->raw(')');
89
- }
90
-
91
- protected function getArguments($callable, $arguments)
92
- {
93
- $parameters = array();
94
- $named = false;
95
- foreach ($arguments as $name => $node) {
96
- if (!is_int($name)) {
97
- $named = true;
98
- $name = $this->normalizeName($name);
99
- } elseif ($named) {
100
- throw new Twig_Error_Syntax(sprintf('Positional arguments cannot be used after named arguments for %s "%s".', $this->getAttribute('type'), $this->getAttribute('name')));
101
- }
102
-
103
- $parameters[$name] = $node;
104
- }
105
-
106
- if (!$named) {
107
- return $parameters;
108
- }
109
-
110
- if (!$callable) {
111
- throw new LogicException(sprintf('Named arguments are not supported for %s "%s".', $this->getAttribute('type'), $this->getAttribute('name')));
112
- }
113
-
114
- // manage named arguments
115
- if (is_array($callable)) {
116
- $r = new ReflectionMethod($callable[0], $callable[1]);
117
- } elseif (is_object($callable) && !$callable instanceof Closure) {
118
- $r = new ReflectionObject($callable);
119
- $r = $r->getMethod('__invoke');
120
- } else {
121
- $r = new ReflectionFunction($callable);
122
- }
123
-
124
- $definition = $r->getParameters();
125
- if ($this->hasNode('node')) {
126
- array_shift($definition);
127
- }
128
- if ($this->hasAttribute('needs_environment') && $this->getAttribute('needs_environment')) {
129
- array_shift($definition);
130
- }
131
- if ($this->hasAttribute('needs_context') && $this->getAttribute('needs_context')) {
132
- array_shift($definition);
133
- }
134
- if ($this->hasAttribute('arguments') && null !== $this->getAttribute('arguments')) {
135
- foreach ($this->getAttribute('arguments') as $argument) {
136
- array_shift($definition);
137
- }
138
- }
139
-
140
- $arguments = array();
141
- $pos = 0;
142
- foreach ($definition as $param) {
143
- $name = $this->normalizeName($param->name);
144
-
145
- if (array_key_exists($name, $parameters)) {
146
- if (array_key_exists($pos, $parameters)) {
147
- throw new Twig_Error_Syntax(sprintf('Argument "%s" is defined twice for %s "%s".', $name, $this->getAttribute('type'), $this->getAttribute('name')));
148
- }
149
-
150
- $arguments[] = $parameters[$name];
151
- unset($parameters[$name]);
152
- } elseif (array_key_exists($pos, $parameters)) {
153
- $arguments[] = $parameters[$pos];
154
- unset($parameters[$pos]);
155
- ++$pos;
156
- } elseif ($param->isDefaultValueAvailable()) {
157
- $arguments[] = new Twig_Node_Expression_Constant($param->getDefaultValue(), -1);
158
- } elseif ($param->isOptional()) {
159
- break;
160
- } else {
161
- throw new Twig_Error_Syntax(sprintf('Value for argument "%s" is required for %s "%s".', $name, $this->getAttribute('type'), $this->getAttribute('name')));
162
- }
163
- }
164
-
165
- if (!empty($parameters)) {
166
- throw new Twig_Error_Syntax(sprintf('Unknown argument%s "%s" for %s "%s".', count($parameters) > 1 ? 's' : '', implode('", "', array_keys($parameters)), $this->getAttribute('type'), $this->getAttribute('name')));
167
- }
168
-
169
- return $arguments;
170
- }
171
-
172
- protected function normalizeName($name)
173
- {
174
- return strtolower(preg_replace(array('/([A-Z]+)([A-Z][a-z])/', '/([a-z\d])([A-Z])/'), array('\\1_\\2', '\\1_\\2'), $name));
175
- }
176
- }
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2012 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+ abstract class Twig_Node_Expression_Call extends Twig_Node_Expression
12
+ {
13
+ protected function compileCallable(Twig_Compiler $compiler)
14
+ {
15
+ $closingParenthesis = false;
16
+ if ($this->hasAttribute('callable') && $callable = $this->getAttribute('callable')) {
17
+ if (is_string($callable)) {
18
+ $compiler->raw($callable);
19
+ } elseif (is_array($callable) && $callable[0] instanceof Twig_ExtensionInterface) {
20
+ $compiler->raw(sprintf('$this->env->getExtension(\'%s\')->%s', $callable[0]->getName(), $callable[1]));
21
+ } else {
22
+ $type = ucfirst($this->getAttribute('type'));
23
+ $compiler->raw(sprintf('call_user_func_array($this->env->get%s(\'%s\')->getCallable(), array', $type, $this->getAttribute('name')));
24
+ $closingParenthesis = true;
25
+ }
26
+ } else {
27
+ $compiler->raw($this->getAttribute('thing')->compile());
28
+ }
29
+
30
+ $this->compileArguments($compiler);
31
+
32
+ if ($closingParenthesis) {
33
+ $compiler->raw(')');
34
+ }
35
+ }
36
+
37
+ protected function compileArguments(Twig_Compiler $compiler)
38
+ {
39
+ $compiler->raw('(');
40
+
41
+ $first = true;
42
+
43
+ if ($this->hasAttribute('needs_environment') && $this->getAttribute('needs_environment')) {
44
+ $compiler->raw('$this->env');
45
+ $first = false;
46
+ }
47
+
48
+ if ($this->hasAttribute('needs_context') && $this->getAttribute('needs_context')) {
49
+ if (!$first) {
50
+ $compiler->raw(', ');
51
+ }
52
+ $compiler->raw('$context');
53
+ $first = false;
54
+ }
55
+
56
+ if ($this->hasAttribute('arguments')) {
57
+ foreach ($this->getAttribute('arguments') as $argument) {
58
+ if (!$first) {
59
+ $compiler->raw(', ');
60
+ }
61
+ $compiler->string($argument);
62
+ $first = false;
63
+ }
64
+ }
65
+
66
+ if ($this->hasNode('node')) {
67
+ if (!$first) {
68
+ $compiler->raw(', ');
69
+ }
70
+ $compiler->subcompile($this->getNode('node'));
71
+ $first = false;
72
+ }
73
+
74
+ if ($this->hasNode('arguments') && null !== $this->getNode('arguments')) {
75
+ $callable = $this->hasAttribute('callable') ? $this->getAttribute('callable') : null;
76
+
77
+ $arguments = $this->getArguments($callable, $this->getNode('arguments'));
78
+
79
+ foreach ($arguments as $node) {
80
+ if (!$first) {
81
+ $compiler->raw(', ');
82
+ }
83
+ $compiler->subcompile($node);
84
+ $first = false;
85
+ }
86
+ }
87
+
88
+ $compiler->raw(')');
89
+ }
90
+
91
+ protected function getArguments($callable, $arguments)
92
+ {
93
+ $parameters = array();
94
+ $named = false;
95
+ foreach ($arguments as $name => $node) {
96
+ if (!is_int($name)) {
97
+ $named = true;
98
+ $name = $this->normalizeName($name);
99
+ } elseif ($named) {
100
+ throw new Twig_Error_Syntax(sprintf('Positional arguments cannot be used after named arguments for %s "%s".', $this->getAttribute('type'), $this->getAttribute('name')));
101
+ }
102
+
103
+ $parameters[$name] = $node;
104
+ }
105
+
106
+ if (!$named) {
107
+ return $parameters;
108
+ }
109
+
110
+ if (!$callable) {
111
+ throw new LogicException(sprintf('Named arguments are not supported for %s "%s".', $this->getAttribute('type'), $this->getAttribute('name')));
112
+ }
113
+
114
+ // manage named arguments
115
+ if (is_array($callable)) {
116
+ $r = new ReflectionMethod($callable[0], $callable[1]);
117
+ } elseif (is_object($callable) && !$callable instanceof Closure) {
118
+ $r = new ReflectionObject($callable);
119
+ $r = $r->getMethod('__invoke');
120
+ } else {
121
+ $r = new ReflectionFunction($callable);
122
+ }
123
+
124
+ $definition = $r->getParameters();
125
+ if ($this->hasNode('node')) {
126
+ array_shift($definition);
127
+ }
128
+ if ($this->hasAttribute('needs_environment') && $this->getAttribute('needs_environment')) {
129
+ array_shift($definition);
130
+ }
131
+ if ($this->hasAttribute('needs_context') && $this->getAttribute('needs_context')) {
132
+ array_shift($definition);
133
+ }
134
+ if ($this->hasAttribute('arguments') && null !== $this->getAttribute('arguments')) {
135
+ foreach ($this->getAttribute('arguments') as $argument) {
136
+ array_shift($definition);
137
+ }
138
+ }
139
+
140
+ $arguments = array();
141
+ $pos = 0;
142
+ foreach ($definition as $param) {
143
+ $name = $this->normalizeName($param->name);
144
+
145
+ if (array_key_exists($name, $parameters)) {
146
+ if (array_key_exists($pos, $parameters)) {
147
+ throw new Twig_Error_Syntax(sprintf('Argument "%s" is defined twice for %s "%s".', $name, $this->getAttribute('type'), $this->getAttribute('name')));
148
+ }
149
+
150
+ $arguments[] = $parameters[$name];
151
+ unset($parameters[$name]);
152
+ } elseif (array_key_exists($pos, $parameters)) {
153
+ $arguments[] = $parameters[$pos];
154
+ unset($parameters[$pos]);
155
+ ++$pos;
156
+ } elseif ($param->isDefaultValueAvailable()) {
157
+ $arguments[] = new Twig_Node_Expression_Constant($param->getDefaultValue(), -1);
158
+ } elseif ($param->isOptional()) {
159
+ break;
160
+ } else {
161
+ throw new Twig_Error_Syntax(sprintf('Value for argument "%s" is required for %s "%s".', $name, $this->getAttribute('type'), $this->getAttribute('name')));
162
+ }
163
+ }
164
+
165
+ if (!empty($parameters)) {
166
+ throw new Twig_Error_Syntax(sprintf('Unknown argument%s "%s" for %s "%s".', count($parameters) > 1 ? 's' : '', implode('", "', array_keys($parameters)), $this->getAttribute('type'), $this->getAttribute('name')));
167
+ }
168
+
169
+ return $arguments;
170
+ }
171
+
172
+ protected function normalizeName($name)
173
+ {
174
+ return strtolower(preg_replace(array('/([A-Z]+)([A-Z][a-z])/', '/([a-z\d])([A-Z])/'), array('\\1_\\2', '\\1_\\2'), $name));
175
+ }
176
+ }
classes/Twig/Node/Expression/Conditional.php CHANGED
@@ -1,31 +1,31 @@
1
- <?php
2
-
3
- /*
4
- * This file is part of Twig.
5
- *
6
- * (c) 2009 Fabien Potencier
7
- * (c) 2009 Armin Ronacher
8
- *
9
- * For the full copyright and license information, please view the LICENSE
10
- * file that was distributed with this source code.
11
- */
12
- class Twig_Node_Expression_Conditional extends Twig_Node_Expression
13
- {
14
- public function __construct(Twig_Node_Expression $expr1, Twig_Node_Expression $expr2, Twig_Node_Expression $expr3, $lineno)
15
- {
16
- parent::__construct(array('expr1' => $expr1, 'expr2' => $expr2, 'expr3' => $expr3), array(), $lineno);
17
- }
18
-
19
- public function compile(Twig_Compiler $compiler)
20
- {
21
- $compiler
22
- ->raw('((')
23
- ->subcompile($this->getNode('expr1'))
24
- ->raw(') ? (')
25
- ->subcompile($this->getNode('expr2'))
26
- ->raw(') : (')
27
- ->subcompile($this->getNode('expr3'))
28
- ->raw('))')
29
- ;
30
- }
31
- }
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2009 Fabien Potencier
7
+ * (c) 2009 Armin Ronacher
8
+ *
9
+ * For the full copyright and license information, please view the LICENSE
10
+ * file that was distributed with this source code.
11
+ */
12
+ class Twig_Node_Expression_Conditional extends Twig_Node_Expression
13
+ {
14
+ public function __construct(Twig_Node_Expression $expr1, Twig_Node_Expression $expr2, Twig_Node_Expression $expr3, $lineno)
15
+ {
16
+ parent::__construct(array('expr1' => $expr1, 'expr2' => $expr2, 'expr3' => $expr3), array(), $lineno);
17
+ }
18
+
19
+ public function compile(Twig_Compiler $compiler)
20
+ {
21
+ $compiler
22
+ ->raw('((')
23
+ ->subcompile($this->getNode('expr1'))
24
+ ->raw(') ? (')
25
+ ->subcompile($this->getNode('expr2'))
26
+ ->raw(') : (')
27
+ ->subcompile($this->getNode('expr3'))
28
+ ->raw('))')
29
+ ;
30
+ }
31
+ }
classes/Twig/Node/Expression/Constant.php CHANGED
@@ -1,23 +1,23 @@
1
- <?php
2
-
3
- /*
4
- * This file is part of Twig.
5
- *
6
- * (c) 2009 Fabien Potencier
7
- * (c) 2009 Armin Ronacher
8
- *
9
- * For the full copyright and license information, please view the LICENSE
10
- * file that was distributed with this source code.
11
- */
12
- class Twig_Node_Expression_Constant extends Twig_Node_Expression
13
- {
14
- public function __construct($value, $lineno)
15
- {
16
- parent::__construct(array(), array('value' => $value), $lineno);
17
- }
18
-
19
- public function compile(Twig_Compiler $compiler)
20
- {
21
- $compiler->repr($this->getAttribute('value'));
22
- }
23
- }
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2009 Fabien Potencier
7
+ * (c) 2009 Armin Ronacher
8
+ *
9
+ * For the full copyright and license information, please view the LICENSE
10
+ * file that was distributed with this source code.
11
+ */
12
+ class Twig_Node_Expression_Constant extends Twig_Node_Expression
13
+ {
14
+ public function __construct($value, $lineno)
15
+ {
16
+ parent::__construct(array(), array('value' => $value), $lineno);
17
+ }
18
+
19
+ public function compile(Twig_Compiler $compiler)
20
+ {
21
+ $compiler->repr($this->getAttribute('value'));
22
+ }
23
+ }
classes/Twig/Node/Expression/ExtensionReference.php CHANGED
@@ -1,33 +1,33 @@
1
- <?php
2
-
3
- /*
4
- * This file is part of Twig.
5
- *
6
- * (c) 2009 Fabien Potencier
7
- *
8
- * For the full copyright and license information, please view the LICENSE
9
- * file that was distributed with this source code.
10
- */
11
-
12
- /**
13
- * Represents an extension call node.
14
- *
15
- * @author Fabien Potencier <fabien@symfony.com>
16
- */
17
- class Twig_Node_Expression_ExtensionReference extends Twig_Node_Expression
18
- {
19
- public function __construct($name, $lineno, $tag = null)
20
- {
21
- parent::__construct(array(), array('name' => $name), $lineno, $tag);
22
- }
23
-
24
- /**
25
- * Compiles the node to PHP.
26
- *
27
- * @param Twig_Compiler A Twig_Compiler instance
28
- */
29
- public function compile(Twig_Compiler $compiler)
30
- {
31
- $compiler->raw(sprintf("\$this->env->getExtension('%s')", $this->getAttribute('name')));
32
- }
33
- }
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2009 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ /**
13
+ * Represents an extension call node.
14
+ *
15
+ * @author Fabien Potencier <fabien@symfony.com>
16
+ */
17
+ class Twig_Node_Expression_ExtensionReference extends Twig_Node_Expression
18
+ {
19
+ public function __construct($name, $lineno, $tag = null)
20
+ {
21
+ parent::__construct(array(), array('name' => $name), $lineno, $tag);
22
+ }
23
+
24
+ /**
25
+ * Compiles the node to PHP.
26
+ *
27
+ * @param Twig_Compiler A Twig_Compiler instance
28
+ */
29
+ public function compile(Twig_Compiler $compiler)
30
+ {
31
+ $compiler->raw(sprintf("\$this->env->getExtension('%s')", $this->getAttribute('name')));
32
+ }
33
+ }
classes/Twig/Node/Expression/Filter.php CHANGED
@@ -1,36 +1,36 @@
1
- <?php
2
-
3
- /*
4
- * This file is part of Twig.
5
- *
6
- * (c) 2009 Fabien Potencier
7
- * (c) 2009 Armin Ronacher
8
- *
9
- * For the full copyright and license information, please view the LICENSE
10
- * file that was distributed with this source code.
11
- */
12
- class Twig_Node_Expression_Filter extends Twig_Node_Expression_Call
13
- {
14
- public function __construct(Twig_NodeInterface $node, Twig_Node_Expression_Constant $filterName, Twig_NodeInterface $arguments, $lineno, $tag = null)
15
- {
16
- parent::__construct(array('node' => $node, 'filter' => $filterName, 'arguments' => $arguments), array(), $lineno, $tag);
17
- }
18
-
19
- public function compile(Twig_Compiler $compiler)
20
- {
21
- $name = $this->getNode('filter')->getAttribute('value');
22
- $filter = $compiler->getEnvironment()->getFilter($name);
23
-
24
- $this->setAttribute('name', $name);
25
- $this->setAttribute('type', 'filter');
26
- $this->setAttribute('thing', $filter);
27
- $this->setAttribute('needs_environment', $filter->needsEnvironment());
28
- $this->setAttribute('needs_context', $filter->needsContext());
29
- $this->setAttribute('arguments', $filter->getArguments());
30
- if ($filter instanceof Twig_FilterCallableInterface || $filter instanceof Twig_SimpleFilter) {
31
- $this->setAttribute('callable', $filter->getCallable());
32
- }
33
-
34
- $this->compileCallable($compiler);
35
- }
36
- }
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2009 Fabien Potencier
7
+ * (c) 2009 Armin Ronacher
8
+ *
9
+ * For the full copyright and license information, please view the LICENSE
10
+ * file that was distributed with this source code.
11
+ */
12
+ class Twig_Node_Expression_Filter extends Twig_Node_Expression_Call
13
+ {
14
+ public function __construct(Twig_NodeInterface $node, Twig_Node_Expression_Constant $filterName, Twig_NodeInterface $arguments, $lineno, $tag = null)
15
+ {
16
+ parent::__construct(array('node' => $node, 'filter' => $filterName, 'arguments' => $arguments), array(), $lineno, $tag);
17
+ }
18
+
19
+ public function compile(Twig_Compiler $compiler)
20
+ {
21
+ $name = $this->getNode('filter')->getAttribute('value');
22
+ $filter = $compiler->getEnvironment()->getFilter($name);
23
+
24
+ $this->setAttribute('name', $name);
25
+ $this->setAttribute('type', 'filter');
26
+ $this->setAttribute('thing', $filter);
27
+ $this->setAttribute('needs_environment', $filter->needsEnvironment());
28
+ $this->setAttribute('needs_context', $filter->needsContext());
29
+ $this->setAttribute('arguments', $filter->getArguments());
30
+ if ($filter instanceof Twig_FilterCallableInterface || $filter instanceof Twig_SimpleFilter) {
31
+ $this->setAttribute('callable', $filter->getCallable());
32
+ }
33
+
34
+ $this->compileCallable($compiler);
35
+ }
36
+ }
classes/Twig/Node/Expression/Filter/Default.php CHANGED
@@ -1,43 +1,43 @@
1
- <?php
2
-
3
- /*
4
- * This file is part of Twig.
5
- *
6
- * (c) 2011 Fabien Potencier
7
- *
8
- * For the full copyright and license information, please view the LICENSE
9
- * file that was distributed with this source code.
10
- */
11
-
12
- /**
13
- * Returns the value or the default value when it is undefined or empty.
14
- *
15
- * <pre>
16
- * {{ var.foo|default('foo item on var is not defined') }}
17
- * </pre>
18
- *
19
- * @author Fabien Potencier <fabien@symfony.com>
20
- */
21
- class Twig_Node_Expression_Filter_Default extends Twig_Node_Expression_Filter
22
- {
23
- public function __construct(Twig_NodeInterface $node, Twig_Node_Expression_Constant $filterName, Twig_NodeInterface $arguments, $lineno, $tag = null)
24
- {
25
- $default = new Twig_Node_Expression_Filter($node, new Twig_Node_Expression_Constant('default', $node->getLine()), $arguments, $node->getLine());
26
-
27
- if ('default' === $filterName->getAttribute('value') && ($node instanceof Twig_Node_Expression_Name || $node instanceof Twig_Node_Expression_GetAttr)) {
28
- $test = new Twig_Node_Expression_Test_Defined(clone $node, 'defined', new Twig_Node(), $node->getLine());
29
- $false = count($arguments) ? $arguments->getNode(0) : new Twig_Node_Expression_Constant('', $node->getLine());
30
-
31
- $node = new Twig_Node_Expression_Conditional($test, $default, $false, $node->getLine());
32
- } else {
33
- $node = $default;
34
- }
35
-
36
- parent::__construct($node, $filterName, $arguments, $lineno, $tag);
37
- }
38
-
39
- public function compile(Twig_Compiler $compiler)
40
- {
41
- $compiler->subcompile($this->getNode('node'));
42
- }
43
- }
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2011 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ /**
13
+ * Returns the value or the default value when it is undefined or empty.
14
+ *
15
+ * <pre>
16
+ * {{ var.foo|default('foo item on var is not defined') }}
17
+ * </pre>
18
+ *
19
+ * @author Fabien Potencier <fabien@symfony.com>
20
+ */
21
+ class Twig_Node_Expression_Filter_Default extends Twig_Node_Expression_Filter
22
+ {
23
+ public function __construct(Twig_NodeInterface $node, Twig_Node_Expression_Constant $filterName, Twig_NodeInterface $arguments, $lineno, $tag = null)
24
+ {
25
+ $default = new Twig_Node_Expression_Filter($node, new Twig_Node_Expression_Constant('default', $node->getLine()), $arguments, $node->getLine());
26
+
27
+ if ('default' === $filterName->getAttribute('value') && ($node instanceof Twig_Node_Expression_Name || $node instanceof Twig_Node_Expression_GetAttr)) {
28
+ $test = new Twig_Node_Expression_Test_Defined(clone $node, 'defined', new Twig_Node(), $node->getLine());
29
+ $false = count($arguments) ? $arguments->getNode(0) : new Twig_Node_Expression_Constant('', $node->getLine());
30
+
31
+ $node = new Twig_Node_Expression_Conditional($test, $default, $false, $node->getLine());
32
+ } else {
33
+ $node = $default;
34
+ }
35
+
36
+ parent::__construct($node, $filterName, $arguments, $lineno, $tag);
37
+ }
38
+
39
+ public function compile(Twig_Compiler $compiler)
40
+ {
41
+ $compiler->subcompile($this->getNode('node'));
42
+ }
43
+ }
classes/Twig/Node/Expression/Function.php CHANGED
@@ -1,35 +1,35 @@
1
- <?php
2
-
3
- /*
4
- * This file is part of Twig.
5
- *
6
- * (c) 2010 Fabien Potencier
7
- *
8
- * For the full copyright and license information, please view the LICENSE
9
- * file that was distributed with this source code.
10
- */
11
- class Twig_Node_Expression_Function extends Twig_Node_Expression_Call
12
- {
13
- public function __construct($name, Twig_NodeInterface $arguments, $lineno)
14
- {
15
- parent::__construct(array('arguments' => $arguments), array('name' => $name), $lineno);
16
- }
17
-
18
- public function compile(Twig_Compiler $compiler)
19
- {
20
- $name = $this->getAttribute('name');
21
- $function = $compiler->getEnvironment()->getFunction($name);
22
-
23
- $this->setAttribute('name', $name);
24
- $this->setAttribute('type', 'function');
25
- $this->setAttribute('thing', $function);
26
- $this->setAttribute('needs_environment', $function->needsEnvironment());
27
- $this->setAttribute('needs_context', $function->needsContext());
28
- $this->setAttribute('arguments', $function->getArguments());
29
- if ($function instanceof Twig_FunctionCallableInterface || $function instanceof Twig_SimpleFunction) {
30
- $this->setAttribute('callable', $function->getCallable());
31
- }
32
-
33
- $this->compileCallable($compiler);
34
- }
35
- }
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2010 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+ class Twig_Node_Expression_Function extends Twig_Node_Expression_Call
12
+ {
13
+ public function __construct($name, Twig_NodeInterface $arguments, $lineno)
14
+ {
15
+ parent::__construct(array('arguments' => $arguments), array('name' => $name), $lineno);
16
+ }
17
+
18
+ public function compile(Twig_Compiler $compiler)
19
+ {
20
+ $name = $this->getAttribute('name');
21
+ $function = $compiler->getEnvironment()->getFunction($name);
22
+
23
+ $this->setAttribute('name', $name);
24
+ $this->setAttribute('type', 'function');
25
+ $this->setAttribute('thing', $function);
26
+ $this->setAttribute('needs_environment', $function->needsEnvironment());
27
+ $this->setAttribute('needs_context', $function->needsContext());
28
+ $this->setAttribute('arguments', $function->getArguments());
29
+ if ($function instanceof Twig_FunctionCallableInterface || $function instanceof Twig_SimpleFunction) {
30
+ $this->setAttribute('callable', $function->getCallable());
31
+ }
32
+
33
+ $this->compileCallable($compiler);
34
+ }
35
+ }
classes/Twig/Node/Expression/GetAttr.php CHANGED
@@ -1,53 +1,53 @@
1
- <?php
2
-
3
- /*
4
- * This file is part of Twig.
5
- *
6
- * (c) 2009 Fabien Potencier
7
- * (c) 2009 Armin Ronacher
8
- *
9
- * For the full copyright and license information, please view the LICENSE
10
- * file that was distributed with this source code.
11
- */
12
- class Twig_Node_Expression_GetAttr extends Twig_Node_Expression
13
- {
14
- public function __construct(Twig_Node_Expression $node, Twig_Node_Expression $attribute, Twig_Node_Expression_Array $arguments, $type, $lineno)
15
- {
16
- parent::__construct(array('node' => $node, 'attribute' => $attribute, 'arguments' => $arguments), array('type' => $type, 'is_defined_test' => false, 'ignore_strict_check' => false, 'disable_c_ext' => false), $lineno);
17
- }
18
-
19
- public function compile(Twig_Compiler $compiler)
20
- {
21
- if (function_exists('twig_template_get_attributes') && !$this->getAttribute('disable_c_ext')) {
22
- $compiler->raw('twig_template_get_attributes($this, ');
23
- } else {
24
- $compiler->raw('$this->getAttribute(');
25
- }
26
-
27
- if ($this->getAttribute('ignore_strict_check')) {
28
- $this->getNode('node')->setAttribute('ignore_strict_check', true);
29
- }
30
-
31
- $compiler->subcompile($this->getNode('node'));
32
-
33
- $compiler->raw(', ')->subcompile($this->getNode('attribute'));
34
-
35
- if (count($this->getNode('arguments')) || Twig_Template::ANY_CALL !== $this->getAttribute('type') || $this->getAttribute('is_defined_test') || $this->getAttribute('ignore_strict_check')) {
36
- $compiler->raw(', ')->subcompile($this->getNode('arguments'));
37
-
38
- if (Twig_Template::ANY_CALL !== $this->getAttribute('type') || $this->getAttribute('is_defined_test') || $this->getAttribute('ignore_strict_check')) {
39
- $compiler->raw(', ')->repr($this->getAttribute('type'));
40
- }
41
-
42
- if ($this->getAttribute('is_defined_test') || $this->getAttribute('ignore_strict_check')) {
43
- $compiler->raw(', '.($this->getAttribute('is_defined_test') ? 'true' : 'false'));
44
- }
45
-
46
- if ($this->getAttribute('ignore_strict_check')) {
47
- $compiler->raw(', '.($this->getAttribute('ignore_strict_check') ? 'true' : 'false'));
48
- }
49
- }
50
-
51
- $compiler->raw(')');
52
- }
53
- }
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2009 Fabien Potencier
7
+ * (c) 2009 Armin Ronacher
8
+ *
9
+ * For the full copyright and license information, please view the LICENSE
10
+ * file that was distributed with this source code.
11
+ */
12
+ class Twig_Node_Expression_GetAttr extends Twig_Node_Expression
13
+ {
14
+ public function __construct(Twig_Node_Expression $node, Twig_Node_Expression $attribute, Twig_Node_Expression_Array $arguments, $type, $lineno)
15
+ {
16
+ parent::__construct(array('node' => $node, 'attribute' => $attribute, 'arguments' => $arguments), array('type' => $type, 'is_defined_test' => false, 'ignore_strict_check' => false, 'disable_c_ext' => false), $lineno);
17
+ }
18
+
19
+ public function compile(Twig_Compiler $compiler)
20
+ {
21
+ if (function_exists('twig_template_get_attributes') && !$this->getAttribute('disable_c_ext')) {
22
+ $compiler->raw('twig_template_get_attributes($this, ');
23
+ } else {
24
+ $compiler->raw('$this->getAttribute(');
25
+ }
26
+
27
+ if ($this->getAttribute('ignore_strict_check')) {
28
+ $this->getNode('node')->setAttribute('ignore_strict_check', true);
29
+ }
30
+
31
+ $compiler->subcompile($this->getNode('node'));
32
+
33
+ $compiler->raw(', ')->subcompile($this->getNode('attribute'));
34
+
35
+ if (count($this->getNode('arguments')) || Twig_Template::ANY_CALL !== $this->getAttribute('type') || $this->getAttribute('is_defined_test') || $this->getAttribute('ignore_strict_check')) {
36
+ $compiler->raw(', ')->subcompile($this->getNode('arguments'));
37
+
38
+ if (Twig_Template::ANY_CALL !== $this->getAttribute('type') || $this->getAttribute('is_defined_test') || $this->getAttribute('ignore_strict_check')) {
39
+ $compiler->raw(', ')->repr($this->getAttribute('type'));
40
+ }
41
+
42
+ if ($this->getAttribute('is_defined_test') || $this->getAttribute('ignore_strict_check')) {
43
+ $compiler->raw(', '.($this->getAttribute('is_defined_test') ? 'true' : 'false'));
44
+ }
45
+
46
+ if ($this->getAttribute('ignore_strict_check')) {
47
+ $compiler->raw(', '.($this->getAttribute('ignore_strict_check') ? 'true' : 'false'));
48
+ }
49
+ }
50
+
51
+ $compiler->raw(')');
52
+ }
53
+ }
classes/Twig/Node/Expression/MethodCall.php CHANGED
@@ -1,41 +1,41 @@
1
- <?php
2
-
3
- /*
4
- * This file is part of Twig.
5
- *
6
- * (c) 2012 Fabien Potencier
7
- *
8
- * For the full copyright and license information, please view the LICENSE
9
- * file that was distributed with this source code.
10
- */
11
- class Twig_Node_Expression_MethodCall extends Twig_Node_Expression
12
- {
13
- public function __construct(Twig_Node_Expression $node, $method, Twig_Node_Expression_Array $arguments, $lineno)
14
- {
15
- parent::__construct(array('node' => $node, 'arguments' => $arguments), array('method' => $method, 'safe' => false), $lineno);
16
-
17
- if ($node instanceof Twig_Node_Expression_Name) {
18
- $node->setAttribute('always_defined', true);
19
- }
20
- }
21
-
22
- public function compile(Twig_Compiler $compiler)
23
- {
24
- $compiler
25
- ->subcompile($this->getNode('node'))
26
- ->raw('->')
27
- ->raw($this->getAttribute('method'))
28
- ->raw('(')
29
- ;
30
- $first = true;
31
- foreach ($this->getNode('arguments')->getKeyValuePairs() as $pair) {
32
- if (!$first) {
33
- $compiler->raw(', ');
34
- }
35
- $first = false;
36
-
37
- $compiler->subcompile($pair['value']);
38
- }
39
- $compiler->raw(')');
40
- }
41
- }
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2012 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+ class Twig_Node_Expression_MethodCall extends Twig_Node_Expression
12
+ {
13
+ public function __construct(Twig_Node_Expression $node, $method, Twig_Node_Expression_Array $arguments, $lineno)
14
+ {
15
+ parent::__construct(array('node' => $node, 'arguments' => $arguments), array('method' => $method, 'safe' => false), $lineno);
16
+
17
+ if ($node instanceof Twig_Node_Expression_Name) {
18
+ $node->setAttribute('always_defined', true);
19
+ }
20
+ }
21
+
22
+ public function compile(Twig_Compiler $compiler)
23
+ {
24
+ $compiler
25
+ ->subcompile($this->getNode('node'))
26
+ ->raw('->')
27
+ ->raw($this->getAttribute('method'))
28
+ ->raw('(')
29
+ ;
30
+ $first = true;
31
+ foreach ($this->getNode('arguments')->getKeyValuePairs() as $pair) {
32
+ if (!$first) {
33
+ $compiler->raw(', ');
34
+ }
35
+ $first = false;
36
+
37
+ $compiler->subcompile($pair['value']);
38
+ }
39
+ $compiler->raw(')');
40
+ }
41
+ }
classes/Twig/Node/Expression/Name.php CHANGED
@@ -1,88 +1,88 @@
1
- <?php
2
-
3
- /*
4
- * This file is part of Twig.
5
- *
6
- * (c) 2009 Fabien Potencier
7
- * (c) 2009 Armin Ronacher
8
- *
9
- * For the full copyright and license information, please view the LICENSE
10
- * file that was distributed with this source code.
11
- */
12
- class Twig_Node_Expression_Name extends Twig_Node_Expression
13
- {
14
- protected $specialVars = array(
15
- '_self' => '$this',
16
- '_context' => '$context',
17
- '_charset' => '$this->env->getCharset()',
18
- );
19
-
20
- public function __construct($name, $lineno)
21
- {
22
- parent::__construct(array(), array('name' => $name, 'is_defined_test' => false, 'ignore_strict_check' => false, 'always_defined' => false), $lineno);
23
- }
24
-
25
- public function compile(Twig_Compiler $compiler)
26
- {
27
- $name = $this->getAttribute('name');
28
-
29
- if ($this->getAttribute('is_defined_test')) {
30
- if ($this->isSpecial()) {
31
- $compiler->repr(true);
32
- } else {
33
- $compiler->raw('array_key_exists(')->repr($name)->raw(', $context)');
34
- }
35
- } elseif ($this->isSpecial()) {
36
- $compiler->raw($this->specialVars[$name]);
37
- } elseif ($this->getAttribute('always_defined')) {
38
- $compiler
39
- ->raw('$context[')
40
- ->string($name)
41
- ->raw(']')
42
- ;
43
- } else {
44
- // remove the non-PHP 5.4 version when PHP 5.3 support is dropped
45
- // as the non-optimized version is just a workaround for slow ternary operator
46
- // when the context has a lot of variables
47
- if (version_compare(phpversion(), '5.4.0RC1', '>=')) {
48
- // PHP 5.4 ternary operator performance was optimized
49
- $compiler
50
- ->raw('(isset($context[')
51
- ->string($name)
52
- ->raw(']) ? $context[')
53
- ->string($name)
54
- ->raw('] : ')
55
- ;
56
-
57
- if ($this->getAttribute('ignore_strict_check') || !$compiler->getEnvironment()->isStrictVariables()) {
58
- $compiler->raw('null)');
59
- } else {
60
- $compiler->raw('$this->getContext($context, ')->string($name)->raw('))');
61
- }
62
- } else {
63
- $compiler
64
- ->raw('$this->getContext($context, ')
65
- ->string($name)
66
- ;
67
-
68
- if ($this->getAttribute('ignore_strict_check')) {
69
- $compiler->raw(', true');
70
- }
71
-
72
- $compiler
73
- ->raw(')')
74
- ;
75
- }
76
- }
77
- }
78
-
79
- public function isSpecial()
80
- {
81
- return isset($this->specialVars[$this->getAttribute('name')]);
82
- }
83
-
84
- public function isSimple()
85
- {
86
- return !$this->isSpecial() && !$this->getAttribute('is_defined_test');
87
- }
88
- }
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2009 Fabien Potencier
7
+ * (c) 2009 Armin Ronacher
8
+ *
9
+ * For the full copyright and license information, please view the LICENSE
10
+ * file that was distributed with this source code.
11
+ */
12
+ class Twig_Node_Expression_Name extends Twig_Node_Expression
13
+ {
14
+ protected $specialVars = array(
15
+ '_self' => '$this',
16
+ '_context' => '$context',
17
+ '_charset' => '$this->env->getCharset()',
18
+ );
19
+
20
+ public function __construct($name, $lineno)
21
+ {
22
+ parent::__construct(array(), array('name' => $name, 'is_defined_test' => false, 'ignore_strict_check' => false, 'always_defined' => false), $lineno);
23
+ }
24
+
25
+ public function compile(Twig_Compiler $compiler)
26
+ {
27
+ $name = $this->getAttribute('name');
28
+
29
+ if ($this->getAttribute('is_defined_test')) {
30
+ if ($this->isSpecial()) {
31
+ $compiler->repr(true);
32
+ } else {
33
+ $compiler->raw('array_key_exists(')->repr($name)->raw(', $context)');
34
+ }
35
+ } elseif ($this->isSpecial()) {
36
+ $compiler->raw($this->specialVars[$name]);
37
+ } elseif ($this->getAttribute('always_defined')) {
38
+ $compiler
39
+ ->raw('$context[')
40
+ ->string($name)
41
+ ->raw(']')
42
+ ;
43
+ } else {
44
+ // remove the non-PHP 5.4 version when PHP 5.3 support is dropped
45
+ // as the non-optimized version is just a workaround for slow ternary operator
46
+ // when the context has a lot of variables
47
+ if (version_compare(phpversion(), '5.4.0RC1', '>=')) {
48
+ // PHP 5.4 ternary operator performance was optimized
49
+ $compiler
50
+ ->raw('(isset($context[')
51
+ ->string($name)
52
+ ->raw(']) ? $context[')
53
+ ->string($name)
54
+ ->raw('] : ')
55
+ ;
56
+
57
+ if ($this->getAttribute('ignore_strict_check') || !$compiler->getEnvironment()->isStrictVariables()) {
58
+ $compiler->raw('null)');
59
+ } else {
60
+ $compiler->raw('$this->getContext($context, ')->string($name)->raw('))');
61
+ }
62
+ } else {
63
+ $compiler
64
+ ->raw('$this->getContext($context, ')
65
+ ->string($name)
66
+ ;
67
+
68
+ if ($this->getAttribute('ignore_strict_check')) {
69
+ $compiler->raw(', true');
70
+ }
71
+
72
+ $compiler
73
+ ->raw(')')
74
+ ;
75
+ }
76
+ }
77
+ }
78
+
79
+ public function isSpecial()
80
+ {
81
+ return isset($this->specialVars[$this->getAttribute('name')]);
82
+ }
83
+
84
+ public function isSimple()
85
+ {
86
+ return !$this->isSpecial() && !$this->getAttribute('is_defined_test');
87
+ }
88
+ }
classes/Twig/Node/Expression/Parent.php CHANGED
@@ -1,47 +1,47 @@
1
- <?php
2
-
3
- /*
4
- * This file is part of Twig.
5
- *
6
- * (c) 2009 Fabien Potencier
7
- * (c) 2009 Armin Ronacher
8
- *
9
- * For the full copyright and license information, please view the LICENSE
10
- * file that was distributed with this source code.
11
- */
12
-
13
- /**
14
- * Represents a parent node.
15
- *
16
- * @author Fabien Potencier <fabien@symfony.com>
17
- */
18
- class Twig_Node_Expression_Parent extends Twig_Node_Expression
19
- {
20
- public function __construct($name, $lineno, $tag = null)
21
- {
22
- parent::__construct(array(), array('output' => false, 'name' => $name), $lineno, $tag);
23
- }
24
-
25
- /**
26
- * Compiles the node to PHP.
27
- *
28
- * @param Twig_Compiler A Twig_Compiler instance
29
- */
30
- public function compile(Twig_Compiler $compiler)
31
- {
32
- if ($this->getAttribute('output')) {
33
- $compiler
34
- ->addDebugInfo($this)
35
- ->write("\$this->displayParentBlock(")
36
- ->string($this->getAttribute('name'))
37
- ->raw(", \$context, \$blocks);\n")
38
- ;
39
- } else {
40
- $compiler
41
- ->raw("\$this->renderParentBlock(")
42
- ->string($this->getAttribute('name'))
43
- ->raw(", \$context, \$blocks)")
44
- ;
45
- }
46
- }
47
- }
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2009 Fabien Potencier
7
+ * (c) 2009 Armin Ronacher
8
+ *
9
+ * For the full copyright and license information, please view the LICENSE
10
+ * file that was distributed with this source code.
11
+ */
12
+
13
+ /**
14
+ * Represents a parent node.
15
+ *
16
+ * @author Fabien Potencier <fabien@symfony.com>
17
+ */
18
+ class Twig_Node_Expression_Parent extends Twig_Node_Expression
19
+ {
20
+ public function __construct($name, $lineno, $tag = null)
21
+ {
22
+ parent::__construct(array(), array('output' => false, 'name' => $name), $lineno, $tag);
23
+ }
24
+
25
+ /**
26
+ * Compiles the node to PHP.
27
+ *
28
+ * @param Twig_Compiler A Twig_Compiler instance
29
+ */
30
+ public function compile(Twig_Compiler $compiler)
31
+ {
32
+ if ($this->getAttribute('output')) {
33
+ $compiler
34
+ ->addDebugInfo($this)
35
+ ->write("\$this->displayParentBlock(")
36
+ ->string($this->getAttribute('name'))
37
+ ->raw(", \$context, \$blocks);\n")
38
+ ;
39
+ } else {
40
+ $compiler
41
+ ->raw("\$this->renderParentBlock(")
42
+ ->string($this->getAttribute('name'))
43
+ ->raw(", \$context, \$blocks)")
44
+ ;
45
+ }
46
+ }
47
+ }
classes/Twig/Node/Expression/TempName.php CHANGED
@@ -1,26 +1,26 @@
1
- <?php
2
-
3
- /*
4
- * This file is part of Twig.
5
- *
6
- * (c) 2011 Fabien Potencier
7
- *
8
- * For the full copyright and license information, please view the LICENSE
9
- * file that was distributed with this source code.
10
- */
11
- class Twig_Node_Expression_TempName extends Twig_Node_Expression
12
- {
13
- public function __construct($name, $lineno)
14
- {
15
- parent::__construct(array(), array('name' => $name), $lineno);
16
- }
17
-
18
- public function compile(Twig_Compiler $compiler)
19
- {
20
- $compiler
21
- ->raw('$_')
22
- ->raw($this->getAttribute('name'))
23
- ->raw('_')
24
- ;
25
- }
26
- }
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2011 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+ class Twig_Node_Expression_TempName extends Twig_Node_Expression
12
+ {
13
+ public function __construct($name, $lineno)
14
+ {
15
+ parent::__construct(array(), array('name' => $name), $lineno);
16
+ }
17
+
18
+ public function compile(Twig_Compiler $compiler)
19
+ {
20
+ $compiler
21
+ ->raw('$_')
22
+ ->raw($this->getAttribute('name'))
23
+ ->raw('_')
24
+ ;
25
+ }
26
+ }
classes/Twig/Node/Expression/Test.php CHANGED
@@ -1,32 +1,32 @@
1
- <?php
2
-
3
- /*
4
- * This file is part of Twig.
5
- *
6
- * (c) 2010 Fabien Potencier
7
- *
8
- * For the full copyright and license information, please view the LICENSE
9
- * file that was distributed with this source code.
10
- */
11
- class Twig_Node_Expression_Test extends Twig_Node_Expression_Call
12
- {
13
- public function __construct(Twig_NodeInterface $node, $name, Twig_NodeInterface $arguments = null, $lineno)
14
- {
15
- parent::__construct(array('node' => $node, 'arguments' => $arguments), array('name' => $name), $lineno);
16
- }
17
-
18
- public function compile(Twig_Compiler $compiler)
19
- {
20
- $name = $this->getAttribute('name');
21
- $test = $compiler->getEnvironment()->getTest($name);
22
-
23
- $this->setAttribute('name', $name);
24
- $this->setAttribute('type', 'test');
25
- $this->setAttribute('thing', $test);
26
- if ($test instanceof Twig_TestCallableInterface || $test instanceof Twig_SimpleTest) {
27
- $this->setAttribute('callable', $test->getCallable());
28
- }
29
-
30
- $this->compileCallable($compiler);
31
- }
32
- }
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2010 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+ class Twig_Node_Expression_Test extends Twig_Node_Expression_Call
12
+ {
13
+ public function __construct(Twig_NodeInterface $node, $name, Twig_NodeInterface $arguments = null, $lineno)
14
+ {
15
+ parent::__construct(array('node' => $node, 'arguments' => $arguments), array('name' => $name), $lineno);
16
+ }
17
+
18
+ public function compile(Twig_Compiler $compiler)
19
+ {
20
+ $name = $this->getAttribute('name');
21
+ $test = $compiler->getEnvironment()->getTest($name);
22
+
23
+ $this->setAttribute('name', $name);
24
+ $this->setAttribute('type', 'test');
25
+ $this->setAttribute('thing', $test);
26
+ if ($test instanceof Twig_TestCallableInterface || $test instanceof Twig_SimpleTest) {
27
+ $this->setAttribute('callable', $test->getCallable());
28
+ }
29
+
30
+ $this->compileCallable($compiler);
31
+ }
32
+ }
classes/Twig/Node/Expression/Test/Constant.php CHANGED
@@ -1,46 +1,46 @@
1
- <?php
2
-
3
- /*
4
- * This file is part of Twig.
5
- *
6
- * (c) 2011 Fabien Potencier
7
- *
8
- * For the full copyright and license information, please view the LICENSE
9
- * file that was distributed with this source code.
10
- */
11
-
12
- /**
13
- * Checks if a variable is the exact same value as a constant.
14
- *
15
- * <pre>
16
- * {% if post.status is constant('Post::PUBLISHED') %}
17
- * the status attribute is exactly the same as Post::PUBLISHED
18
- * {% endif %}
19
- * </pre>
20
- *
21
- * @author Fabien Potencier <fabien@symfony.com>
22
- */
23
- class Twig_Node_Expression_Test_Constant extends Twig_Node_Expression_Test
24
- {
25
- public function compile(Twig_Compiler $compiler)
26
- {
27
- $compiler
28
- ->raw('(')
29
- ->subcompile($this->getNode('node'))
30
- ->raw(' === constant(')
31
- ;
32
-
33
- if ($this->getNode('arguments')->hasNode(1)) {
34
- $compiler
35
- ->raw('get_class(')
36
- ->subcompile($this->getNode('arguments')->getNode(1))
37
- ->raw(')."::".')
38
- ;
39
- }
40
-
41
- $compiler
42
- ->subcompile($this->getNode('arguments')->getNode(0))
43
- ->raw('))')
44
- ;
45
- }
46
- }
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2011 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ /**
13
+ * Checks if a variable is the exact same value as a constant.
14
+ *
15
+ * <pre>
16
+ * {% if post.status is constant('Post::PUBLISHED') %}
17
+ * the status attribute is exactly the same as Post::PUBLISHED
18
+ * {% endif %}
19
+ * </pre>
20
+ *
21
+ * @author Fabien Potencier <fabien@symfony.com>
22
+ */
23
+ class Twig_Node_Expression_Test_Constant extends Twig_Node_Expression_Test
24
+ {
25
+ public function compile(Twig_Compiler $compiler)
26
+ {
27
+ $compiler
28
+ ->raw('(')
29
+ ->subcompile($this->getNode('node'))
30
+ ->raw(' === constant(')
31
+ ;
32
+
33
+ if ($this->getNode('arguments')->hasNode(1)) {
34
+ $compiler
35
+ ->raw('get_class(')
36
+ ->subcompile($this->getNode('arguments')->getNode(1))
37
+ ->raw(')."::".')
38
+ ;
39
+ }
40
+
41
+ $compiler
42
+ ->subcompile($this->getNode('arguments')->getNode(0))
43
+ ->raw('))')
44
+ ;
45
+ }
46
+ }
classes/Twig/Node/Expression/Test/Defined.php CHANGED
@@ -1,54 +1,54 @@
1
- <?php
2
-
3
- /*
4
- * This file is part of Twig.
5
- *
6
- * (c) 2011 Fabien Potencier
7
- *
8
- * For the full copyright and license information, please view the LICENSE
9
- * file that was distributed with this source code.
10
- */
11
-
12
- /**
13
- * Checks if a variable is defined in the current context.
14
- *
15
- * <pre>
16
- * {# defined works with variable names and variable attributes #}
17
- * {% if foo is defined %}
18
- * {# ... #}
19
- * {% endif %}
20
- * </pre>
21
- *
22
- * @author Fabien Potencier <fabien@symfony.com>
23
- */
24
- class Twig_Node_Expression_Test_Defined extends Twig_Node_Expression_Test
25
- {
26
- public function __construct(Twig_NodeInterface $node, $name, Twig_NodeInterface $arguments = null, $lineno)
27
- {
28
- parent::__construct($node, $name, $arguments, $lineno);
29
-
30
- if ($node instanceof Twig_Node_Expression_Name) {
31
- $node->setAttribute('is_defined_test', true);
32
- } elseif ($node instanceof Twig_Node_Expression_GetAttr) {
33
- $node->setAttribute('is_defined_test', true);
34
-
35
- $this->changeIgnoreStrictCheck($node);
36
- } else {
37
- throw new Twig_Error_Syntax('The "defined" test only works with simple variables', $this->getLine());
38
- }
39
- }
40
-
41
- protected function changeIgnoreStrictCheck(Twig_Node_Expression_GetAttr $node)
42
- {
43
- $node->setAttribute('ignore_strict_check', true);
44
-
45
- if ($node->getNode('node') instanceof Twig_Node_Expression_GetAttr) {
46
- $this->changeIgnoreStrictCheck($node->getNode('node'));
47
- }
48
- }
49
-
50
- public function compile(Twig_Compiler $compiler)
51
- {
52
- $compiler->subcompile($this->getNode('node'));
53
- }
54
- }
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2011 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ /**
13
+ * Checks if a variable is defined in the current context.
14
+ *
15
+ * <pre>
16
+ * {# defined works with variable names and variable attributes #}
17
+ * {% if foo is defined %}
18
+ * {# ... #}
19
+ * {% endif %}
20
+ * </pre>
21
+ *
22
+ * @author Fabien Potencier <fabien@symfony.com>
23
+ */
24
+ class Twig_Node_Expression_Test_Defined extends Twig_Node_Expression_Test
25
+ {
26
+ public function __construct(Twig_NodeInterface $node, $name, Twig_NodeInterface $arguments = null, $lineno)
27
+ {
28
+ parent::__construct($node, $name, $arguments, $lineno);
29
+
30
+ if ($node instanceof Twig_Node_Expression_Name) {
31
+ $node->setAttribute('is_defined_test', true);
32
+ } elseif ($node instanceof Twig_Node_Expression_GetAttr) {
33
+ $node->setAttribute('is_defined_test', true);
34
+
35
+ $this->changeIgnoreStrictCheck($node);
36
+ } else {
37
+ throw new Twig_Error_Syntax('The "defined" test only works with simple variables', $this->getLine());
38
+ }
39
+ }
40
+
41
+ protected function changeIgnoreStrictCheck(Twig_Node_Expression_GetAttr $node)
42
+ {
43
+ $node->setAttribute('ignore_strict_check', true);
44
+
45
+ if ($node->getNode('node') instanceof Twig_Node_Expression_GetAttr) {
46
+ $this->changeIgnoreStrictCheck($node->getNode('node'));
47
+ }
48
+ }
49
+
50
+ public function compile(Twig_Compiler $compiler)
51
+ {
52
+ $compiler->subcompile($this->getNode('node'));
53
+ }
54
+ }
classes/Twig/Node/Expression/Test/Divisibleby.php CHANGED
@@ -1,33 +1,33 @@
1
- <?php
2
-
3
- /*
4
- * This file is part of Twig.
5
- *
6
- * (c) 2011 Fabien Potencier
7
- *
8
- * For the full copyright and license information, please view the LICENSE
9
- * file that was distributed with this source code.
10
- */
11
-
12
- /**
13
- * Checks if a variable is divisible by a number.
14
- *
15
- * <pre>
16
- * {% if loop.index is divisible by(3) %}
17
- * </pre>
18
- *
19
- * @author Fabien Potencier <fabien@symfony.com>
20
- */
21
- class Twig_Node_Expression_Test_Divisibleby extends Twig_Node_Expression_Test
22
- {
23
- public function compile(Twig_Compiler $compiler)
24
- {
25
- $compiler
26
- ->raw('(0 == ')
27
- ->subcompile($this->getNode('node'))
28
- ->raw(' % ')
29
- ->subcompile($this->getNode('arguments')->getNode(0))
30
- ->raw(')')
31
- ;
32
- }
33
- }
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2011 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ /**
13
+ * Checks if a variable is divisible by a number.
14
+ *
15
+ * <pre>
16
+ * {% if loop.index is divisible by(3) %}
17
+ * </pre>
18
+ *
19
+ * @author Fabien Potencier <fabien@symfony.com>
20
+ */
21
+ class Twig_Node_Expression_Test_Divisibleby extends Twig_Node_Expression_Test
22
+ {
23
+ public function compile(Twig_Compiler $compiler)
24
+ {
25
+ $compiler
26
+ ->raw('(0 == ')
27
+ ->subcompile($this->getNode('node'))
28
+ ->raw(' % ')
29
+ ->subcompile($this->getNode('arguments')->getNode(0))
30
+ ->raw(')')
31
+ ;
32
+ }
33
+ }
classes/Twig/Node/Expression/Test/Even.php CHANGED
@@ -1,32 +1,32 @@
1
- <?php
2
-
3
- /*
4
- * This file is part of Twig.
5
- *
6
- * (c) 2011 Fabien Potencier
7
- *
8
- * For the full copyright and license information, please view the LICENSE
9
- * file that was distributed with this source code.
10
- */
11
-
12
- /**
13
- * Checks if a number is even.
14
- *
15
- * <pre>
16
- * {{ var is even }}
17
- * </pre>
18
- *
19
- * @author Fabien Potencier <fabien@symfony.com>
20
- */
21
- class Twig_Node_Expression_Test_Even extends Twig_Node_Expression_Test
22
- {
23
- public function compile(Twig_Compiler $compiler)
24
- {
25
- $compiler
26
- ->raw('(')
27
- ->subcompile($this->getNode('node'))
28
- ->raw(' % 2 == 0')
29
- ->raw(')')
30
- ;
31
- }
32
- }
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2011 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ /**
13
+ * Checks if a number is even.
14
+ *
15
+ * <pre>
16
+ * {{ var is even }}
17
+ * </pre>
18
+ *
19
+ * @author Fabien Potencier <fabien@symfony.com>
20
+ */
21
+ class Twig_Node_Expression_Test_Even extends Twig_Node_Expression_Test
22
+ {
23
+ public function compile(Twig_Compiler $compiler)
24
+ {
25
+ $compiler
26
+ ->raw('(')
27
+ ->subcompile($this->getNode('node'))
28
+ ->raw(' % 2 == 0')
29
+ ->raw(')')
30
+ ;
31
+ }
32
+ }
classes/Twig/Node/Expression/Test/Null.php CHANGED
@@ -1,31 +1,31 @@
1
- <?php
2
-
3
- /*
4
- * This file is part of Twig.
5
- *
6
- * (c) 2011 Fabien Potencier
7
- *
8
- * For the full copyright and license information, please view the LICENSE
9
- * file that was distributed with this source code.
10
- */
11
-
12
- /**
13
- * Checks that a variable is null.
14
- *
15
- * <pre>
16
- * {{ var is none }}
17
- * </pre>
18
- *
19
- * @author Fabien Potencier <fabien@symfony.com>
20
- */
21
- class Twig_Node_Expression_Test_Null extends Twig_Node_Expression_Test
22
- {
23
- public function compile(Twig_Compiler $compiler)
24
- {
25
- $compiler
26
- ->raw('(null === ')
27
- ->subcompile($this->getNode('node'))
28
- ->raw(')')
29
- ;
30
- }
31
- }
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2011 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ /**
13
+ * Checks that a variable is null.
14
+ *
15
+ * <pre>
16
+ * {{ var is none }}
17
+ * </pre>
18
+ *
19
+ * @author Fabien Potencier <fabien@symfony.com>
20
+ */
21
+ class Twig_Node_Expression_Test_Null extends Twig_Node_Expression_Test
22
+ {
23
+ public function compile(Twig_Compiler $compiler)
24
+ {
25
+ $compiler
26
+ ->raw('(null === ')
27
+ ->subcompile($this->getNode('node'))
28
+ ->raw(')')
29
+ ;
30
+ }
31
+ }
classes/Twig/Node/Expression/Test/Odd.php CHANGED
@@ -1,32 +1,32 @@
1
- <?php
2
-
3
- /*
4
- * This file is part of Twig.
5
- *
6
- * (c) 2011 Fabien Potencier
7
- *
8
- * For the full copyright and license information, please view the LICENSE
9
- * file that was distributed with this source code.
10
- */
11
-
12
- /**
13
- * Checks if a number is odd.
14
- *
15
- * <pre>
16
- * {{ var is odd }}
17
- * </pre>
18
- *
19
- * @author Fabien Potencier <fabien@symfony.com>
20
- */
21
- class Twig_Node_Expression_Test_Odd extends Twig_Node_Expression_Test
22
- {
23
- public function compile(Twig_Compiler $compiler)
24
- {
25
- $compiler
26
- ->raw('(')
27
- ->subcompile($this->getNode('node'))
28
- ->raw(' % 2 == 1')
29
- ->raw(')')
30
- ;
31
- }
32
- }
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2011 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ /**
13
+ * Checks if a number is odd.
14
+ *
15
+ * <pre>
16
+ * {{ var is odd }}
17
+ * </pre>
18
+ *
19
+ * @author Fabien Potencier <fabien@symfony.com>
20
+ */
21
+ class Twig_Node_Expression_Test_Odd extends Twig_Node_Expression_Test
22
+ {
23
+ public function compile(Twig_Compiler $compiler)
24
+ {
25
+ $compiler
26
+ ->raw('(')
27
+ ->subcompile($this->getNode('node'))
28
+ ->raw(' % 2 == 1')
29
+ ->raw(')')
30
+ ;
31
+ }
32
+ }
classes/Twig/Node/Expression/Test/Sameas.php CHANGED
@@ -1,29 +1,29 @@
1
- <?php
2
-
3
- /*
4
- * This file is part of Twig.
5
- *
6
- * (c) 2011 Fabien Potencier
7
- *
8
- * For the full copyright and license information, please view the LICENSE
9
- * file that was distributed with this source code.
10
- */
11
-
12
- /**
13
- * Checks if a variable is the same as another one (=== in PHP).
14
- *
15
- * @author Fabien Potencier <fabien@symfony.com>
16
- */
17
- class Twig_Node_Expression_Test_Sameas extends Twig_Node_Expression_Test
18
- {
19
- public function compile(Twig_Compiler $compiler)
20
- {
21
- $compiler
22
- ->raw('(')
23
- ->subcompile($this->getNode('node'))
24
- ->raw(' === ')
25
- ->subcompile($this->getNode('arguments')->getNode(0))
26
- ->raw(')')
27
- ;
28
- }
29
- }
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2011 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ /**
13
+ * Checks if a variable is the same as another one (=== in PHP).
14
+ *
15
+ * @author Fabien Potencier <fabien@symfony.com>
16
+ */
17
+ class Twig_Node_Expression_Test_Sameas extends Twig_Node_Expression_Test
18
+ {
19
+ public function compile(Twig_Compiler $compiler)
20
+ {
21
+ $compiler
22
+ ->raw('(')
23
+ ->subcompile($this->getNode('node'))
24
+ ->raw(' === ')
25
+ ->subcompile($this->getNode('arguments')->getNode(0))
26
+ ->raw(')')
27
+ ;
28
+ }
29
+ }
classes/Twig/Node/Expression/Unary.php CHANGED
@@ -1,30 +1,30 @@
1
- <?php
2
-
3
- /*
4
- * This file is part of Twig.
5
- *
6
- * (c) 2009 Fabien Potencier
7
- * (c) 2009 Armin Ronacher
8
- *
9
- * For the full copyright and license information, please view the LICENSE
10
- * file that was distributed with this source code.
11
- */
12
- abstract class Twig_Node_Expression_Unary extends Twig_Node_Expression
13
- {
14
- public function __construct(Twig_NodeInterface $node, $lineno)
15
- {
16
- parent::__construct(array('node' => $node), array(), $lineno);
17
- }
18
-
19
- public function compile(Twig_Compiler $compiler)
20
- {
21
- $compiler->raw('(');
22
- $this->operator($compiler);
23
- $compiler
24
- ->subcompile($this->getNode('node'))
25
- ->raw(')')
26
- ;
27
- }
28
-
29
- abstract public function operator(Twig_Compiler $compiler);
30
- }
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2009 Fabien Potencier
7
+ * (c) 2009 Armin Ronacher
8
+ *
9
+ * For the full copyright and license information, please view the LICENSE
10
+ * file that was distributed with this source code.
11
+ */
12
+ abstract class Twig_Node_Expression_Unary extends Twig_Node_Expression
13
+ {
14
+ public function __construct(Twig_NodeInterface $node, $lineno)
15
+ {
16
+ parent::__construct(array('node' => $node), array(), $lineno);
17
+ }
18
+
19
+ public function compile(Twig_Compiler $compiler)
20
+ {
21
+ $compiler->raw('(');
22
+ $this->operator($compiler);
23
+ $compiler
24
+ ->subcompile($this->getNode('node'))
25
+ ->raw(')')
26
+ ;
27
+ }
28
+
29
+ abstract public function operator(Twig_Compiler $compiler);
30
+ }
classes/Twig/Node/Expression/Unary/Neg.php CHANGED
@@ -1,18 +1,18 @@
1
- <?php
2
-
3
- /*
4
- * This file is part of Twig.
5
- *
6
- * (c) 2009 Fabien Potencier
7
- * (c) 2009 Armin Ronacher
8
- *
9
- * For the full copyright and license information, please view the LICENSE
10
- * file that was distributed with this source code.
11
- */
12
- class Twig_Node_Expression_Unary_Neg extends Twig_Node_Expression_Unary
13
- {
14
- public function operator(Twig_Compiler $compiler)
15
- {
16
- $compiler->raw('-');
17
- }
18
- }
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2009 Fabien Potencier
7
+ * (c) 2009 Armin Ronacher
8
+ *
9
+ * For the full copyright and license information, please view the LICENSE
10
+ * file that was distributed with this source code.
11
+ */
12
+ class Twig_Node_Expression_Unary_Neg extends Twig_Node_Expression_Unary
13
+ {
14
+ public function operator(Twig_Compiler $compiler)
15
+ {
16
+ $compiler->raw('-');
17
+ }
18
+ }
classes/Twig/Node/Expression/Unary/Not.php CHANGED
@@ -1,18 +1,18 @@
1
- <?php
2
-
3
- /*
4
- * This file is part of Twig.
5
- *
6
- * (c) 2009 Fabien Potencier
7
- * (c) 2009 Armin Ronacher
8
- *
9
- * For the full copyright and license information, please view the LICENSE
10
- * file that was distributed with this source code.
11
- */
12
- class Twig_Node_Expression_Unary_Not extends Twig_Node_Expression_Unary
13
- {
14
- public function operator(Twig_Compiler $compiler)
15
- {
16
- $compiler->raw('!');
17
- }
18
- }
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2009 Fabien Potencier
7
+ * (c) 2009 Armin Ronacher
8
+ *
9
+ * For the full copyright and license information, please view the LICENSE
10
+ * file that was distributed with this source code.
11
+ */
12
+ class Twig_Node_Expression_Unary_Not extends Twig_Node_Expression_Unary
13
+ {
14
+ public function operator(Twig_Compiler $compiler)
15
+ {
16
+ $compiler->raw('!');
17
+ }
18
+ }
classes/Twig/Node/Expression/Unary/Pos.php CHANGED
@@ -1,18 +1,18 @@
1
- <?php
2
-
3
- /*
4
- * This file is part of Twig.
5
- *
6
- * (c) 2009 Fabien Potencier
7
- * (c) 2009 Armin Ronacher
8
- *
9
- * For the full copyright and license information, please view the LICENSE
10
- * file that was distributed with this source code.
11
- */
12
- class Twig_Node_Expression_Unary_Pos extends Twig_Node_Expression_Unary
13
- {
14
- public function operator(Twig_Compiler $compiler)
15
- {
16
- $compiler->raw('+');
17
- }
18
- }
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2009 Fabien Potencier
7
+ * (c) 2009 Armin Ronacher
8
+ *
9
+ * For the full copyright and license information, please view the LICENSE
10
+ * file that was distributed with this source code.
11
+ */
12
+ class Twig_Node_Expression_Unary_Pos extends Twig_Node_Expression_Unary
13
+ {
14
+ public function operator(Twig_Compiler $compiler)
15
+ {
16
+ $compiler->raw('+');
17
+ }
18
+ }
classes/Twig/Node/Flush.php CHANGED
@@ -1,36 +1,36 @@
1
- <?php
2
-
3
- /*
4
- * This file is part of Twig.
5
- *
6
- * (c) 2011 Fabien Potencier
7
- *
8
- * For the full copyright and license information, please view the LICENSE
9
- * file that was distributed with this source code.
10
- */
11
-
12
- /**
13
- * Represents a flush node.
14
- *
15
- * @author Fabien Potencier <fabien@symfony.com>
16
- */
17
- class Twig_Node_Flush extends Twig_Node
18
- {
19
- public function __construct($lineno, $tag)
20
- {
21
- parent::__construct(array(), array(), $lineno, $tag);
22
- }
23
-
24
- /**
25
- * Compiles the node to PHP.
26
- *
27
- * @param Twig_Compiler A Twig_Compiler instance
28
- */
29
- public function compile(Twig_Compiler $compiler)
30
- {
31
- $compiler
32
- ->addDebugInfo($this)
33
- ->write("flush();\n")
34
- ;
35
- }
36
- }
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2011 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ /**
13
+ * Represents a flush node.
14
+ *
15
+ * @author Fabien Potencier <fabien@symfony.com>
16
+ */
17
+ class Twig_Node_Flush extends Twig_Node
18
+ {
19
+ public function __construct($lineno, $tag)
20
+ {
21
+ parent::__construct(array(), array(), $lineno, $tag);
22
+ }
23
+
24
+ /**
25
+ * Compiles the node to PHP.
26
+ *
27
+ * @param Twig_Compiler A Twig_Compiler instance
28
+ */
29
+ public function compile(Twig_Compiler $compiler)
30
+ {
31
+ $compiler
32
+ ->addDebugInfo($this)
33
+ ->write("flush();\n")
34
+ ;
35
+ }
36
+ }
classes/Twig/Node/For.php CHANGED
@@ -1,112 +1,112 @@
1
- <?php
2
-
3
- /*
4
- * This file is part of Twig.
5
- *
6
- * (c) 2009 Fabien Potencier
7
- * (c) 2009 Armin Ronacher
8
- *
9
- * For the full copyright and license information, please view the LICENSE
10
- * file that was distributed with this source code.
11
- */
12
-
13
- /**
14
- * Represents a for node.
15
- *
16
- * @author Fabien Potencier <fabien@symfony.com>
17
- */
18
- class Twig_Node_For extends Twig_Node
19
- {
20
- protected $loop;
21
-
22
- public function __construct(Twig_Node_Expression_AssignName $keyTarget, Twig_Node_Expression_AssignName $valueTarget, Twig_Node_Expression $seq, Twig_Node_Expression $ifexpr = null, Twig_NodeInterface $body, Twig_NodeInterface $else = null, $lineno, $tag = null)
23
- {
24
- $body = new Twig_Node(array($body, $this->loop = new Twig_Node_ForLoop($lineno, $tag)));
25
-
26
- if (null !== $ifexpr) {
27
- $body = new Twig_Node_If(new Twig_Node(array($ifexpr, $body)), null, $lineno, $tag);
28
- }
29
-
30
- parent::__construct(array('key_target' => $keyTarget, 'value_target' => $valueTarget, 'seq' => $seq, 'body' => $body, 'else' => $else), array('with_loop' => true, 'ifexpr' => null !== $ifexpr), $lineno, $tag);
31
- }
32
-
33
- /**
34
- * Compiles the node to PHP.
35
- *
36
- * @param Twig_Compiler A Twig_Compiler instance
37
- */
38
- public function compile(Twig_Compiler $compiler)
39
- {
40
- $compiler
41
- ->addDebugInfo($this)
42
- // the (array) cast bypasses a PHP 5.2.6 bug
43
- ->write("\$context['_parent'] = (array) \$context;\n")
44
- ->write("\$context['_seq'] = twig_ensure_traversable(")
45
- ->subcompile($this->getNode('seq'))
46
- ->raw(");\n")
47
- ;
48
-
49
- if (null !== $this->getNode('else')) {
50
- $compiler->write("\$context['_iterated'] = false;\n");
51
- }
52
-
53
- if ($this->getAttribute('with_loop')) {
54
- $compiler
55
- ->write("\$context['loop'] = array(\n")
56
- ->write(" 'parent' => \$context['_parent'],\n")
57
- ->write(" 'index0' => 0,\n")
58
- ->write(" 'index' => 1,\n")
59
- ->write(" 'first' => true,\n")
60
- ->write(");\n")
61
- ;
62
-
63
- if (!$this->getAttribute('ifexpr')) {
64
- $compiler
65
- ->write("if (is_array(\$context['_seq']) || (is_object(\$context['_seq']) && \$context['_seq'] instanceof Countable)) {\n")
66
- ->indent()
67
- ->write("\$length = count(\$context['_seq']);\n")
68
- ->write("\$context['loop']['revindex0'] = \$length - 1;\n")
69
- ->write("\$context['loop']['revindex'] = \$length;\n")
70
- ->write("\$context['loop']['length'] = \$length;\n")
71
- ->write("\$context['loop']['last'] = 1 === \$length;\n")
72
- ->outdent()
73
- ->write("}\n")
74
- ;
75
- }
76
- }
77
-
78
- $this->loop->setAttribute('else', null !== $this->getNode('else'));
79
- $this->loop->setAttribute('with_loop', $this->getAttribute('with_loop'));
80
- $this->loop->setAttribute('ifexpr', $this->getAttribute('ifexpr'));
81
-
82
- $compiler
83
- ->write("foreach (\$context['_seq'] as ")
84
- ->subcompile($this->getNode('key_target'))
85
- ->raw(" => ")
86
- ->subcompile($this->getNode('value_target'))
87
- ->raw(") {\n")
88
- ->indent()
89
- ->subcompile($this->getNode('body'))
90
- ->outdent()
91
- ->write("}\n")
92
- ;
93
-
94
- if (null !== $this->getNode('else')) {
95
- $compiler
96
- ->write("if (!\$context['_iterated']) {\n")
97
- ->indent()
98
- ->subcompile($this->getNode('else'))
99
- ->outdent()
100
- ->write("}\n")
101
- ;
102
- }
103
-
104
- $compiler->write("\$_parent = \$context['_parent'];\n");
105
-
106
- // remove some "private" loop variables (needed for nested loops)
107
- $compiler->write('unset($context[\'_seq\'], $context[\'_iterated\'], $context[\''.$this->getNode('key_target')->getAttribute('name').'\'], $context[\''.$this->getNode('value_target')->getAttribute('name').'\'], $context[\'_parent\'], $context[\'loop\']);'."\n");
108
-
109
- // keep the values set in the inner context for variables defined in the outer context
110
- $compiler->write("\$context = array_intersect_key(\$context, \$_parent) + \$_parent;\n");
111
- }
112
- }
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2009 Fabien Potencier
7
+ * (c) 2009 Armin Ronacher
8
+ *
9
+ * For the full copyright and license information, please view the LICENSE
10
+ * file that was distributed with this source code.
11
+ */
12
+
13
+ /**
14
+ * Represents a for node.
15
+ *
16
+ * @author Fabien Potencier <fabien@symfony.com>
17
+ */
18
+ class Twig_Node_For extends Twig_Node
19
+ {
20
+ protected $loop;
21
+
22
+ public function __construct(Twig_Node_Expression_AssignName $keyTarget, Twig_Node_Expression_AssignName $valueTarget, Twig_Node_Expression $seq, Twig_Node_Expression $ifexpr = null, Twig_NodeInterface $body, Twig_NodeInterface $else = null, $lineno, $tag = null)
23
+ {
24
+ $body = new Twig_Node(array($body, $this->loop = new Twig_Node_ForLoop($lineno, $tag)));
25
+
26
+ if (null !== $ifexpr) {
27
+ $body = new Twig_Node_If(new Twig_Node(array($ifexpr, $body)), null, $lineno, $tag);
28
+ }
29
+
30
+ parent::__construct(array('key_target' => $keyTarget, 'value_target' => $valueTarget, 'seq' => $seq, 'body' => $body, 'else' => $else), array('with_loop' => true, 'ifexpr' => null !== $ifexpr), $lineno, $tag);
31
+ }
32
+
33
+ /**
34
+ * Compiles the node to PHP.
35
+ *
36
+ * @param Twig_Compiler A Twig_Compiler instance
37
+ */
38
+ public function compile(Twig_Compiler $compiler)
39
+ {
40
+ $compiler
41
+ ->addDebugInfo($this)
42
+ // the (array) cast bypasses a PHP 5.2.6 bug
43
+ ->write("\$context['_parent'] = (array) \$context;\n")
44
+ ->write("\$context['_seq'] = twig_ensure_traversable(")
45
+ ->subcompile($this->getNode('seq'))
46
+ ->raw(");\n")
47
+ ;
48
+
49
+ if (null !== $this->getNode('else')) {
50
+ $compiler->write("\$context['_iterated'] = false;\n");
51
+ }
52
+
53
+ if ($this->getAttribute('with_loop')) {
54
+ $compiler
55
+ ->write("\$context['loop'] = array(\n")
56
+ ->write(" 'parent' => \$context['_parent'],\n")
57
+ ->write(" 'index0' => 0,\n")
58
+ ->write(" 'index' => 1,\n")
59
+ ->write(" 'first' => true,\n")
60
+ ->write(");\n")
61
+ ;
62
+
63
+ if (!$this->getAttribute('ifexpr')) {
64
+ $compiler
65
+ ->write("if (is_array(\$context['_seq']) || (is_object(\$context['_seq']) && \$context['_seq'] instanceof Countable)) {\n")
66
+ ->indent()
67
+ ->write("\$length = count(\$context['_seq']);\n")
68
+ ->write("\$context['loop']['revindex0'] = \$length - 1;\n")
69
+ ->write("\$context['loop']['revindex'] = \$length;\n")
70
+ ->write("\$context['loop']['length'] = \$length;\n")
71
+ ->write("\$context['loop']['last'] = 1 === \$length;\n")
72
+ ->outdent()
73
+ ->write("}\n")
74
+ ;
75
+ }
76
+ }
77
+
78
+ $this->loop->setAttribute('else', null !== $this->getNode('else'));
79
+ $this->loop->setAttribute('with_loop', $this->getAttribute('with_loop'));
80
+ $this->loop->setAttribute('ifexpr', $this->getAttribute('ifexpr'));
81
+
82
+ $compiler
83
+ ->write("foreach (\$context['_seq'] as ")
84
+ ->subcompile($this->getNode('key_target'))
85
+ ->raw(" => ")
86
+ ->subcompile($this->getNode('value_target'))
87
+ ->raw(") {\n")
88
+ ->indent()
89
+ ->subcompile($this->getNode('body'))
90
+ ->outdent()
91
+ ->write("}\n")
92
+ ;
93
+
94
+ if (null !== $this->getNode('else')) {
95
+ $compiler
96
+ ->write("if (!\$context['_iterated']) {\n")
97
+ ->indent()
98
+ ->subcompile($this->getNode('else'))
99
+ ->outdent()
100
+ ->write("}\n")
101
+ ;
102
+ }
103
+
104
+ $compiler->write("\$_parent = \$context['_parent'];\n");
105
+
106
+ // remove some "private" loop variables (needed for nested loops)
107
+ $compiler->write('unset($context[\'_seq\'], $context[\'_iterated\'], $context[\''.$this->getNode('key_target')->getAttribute('name').'\'], $context[\''.$this->getNode('value_target')->getAttribute('name').'\'], $context[\'_parent\'], $context[\'loop\']);'."\n");
108
+
109
+ // keep the values set in the inner context for variables defined in the outer context
110
+ $compiler->write("\$context = array_intersect_key(\$context, \$_parent) + \$_parent;\n");
111
+ }
112
+ }
classes/Twig/Node/ForLoop.php CHANGED
@@ -1,55 +1,55 @@
1
- <?php
2
-
3
- /*
4
- * This file is part of Twig.
5
- *
6
- * (c) 2011 Fabien Potencier
7
- *
8
- * For the full copyright and license information, please view the LICENSE
9
- * file that was distributed with this source code.
10
- */
11
-
12
- /**
13
- * Internal node used by the for node.
14
- *
15
- * @author Fabien Potencier <fabien@symfony.com>
16
- */
17
- class Twig_Node_ForLoop extends Twig_Node
18
- {
19
- public function __construct($lineno, $tag = null)
20
- {
21
- parent::__construct(array(), array('with_loop' => false, 'ifexpr' => false, 'else' => false), $lineno, $tag);
22
- }
23
-
24
- /**
25
- * Compiles the node to PHP.
26
- *
27
- * @param Twig_Compiler A Twig_Compiler instance
28
- */
29
- public function compile(Twig_Compiler $compiler)
30
- {
31
- if ($this->getAttribute('else')) {
32
- $compiler->write("\$context['_iterated'] = true;\n");
33
- }
34
-
35
- if ($this->getAttribute('with_loop')) {
36
- $compiler
37
- ->write("++\$context['loop']['index0'];\n")
38
- ->write("++\$context['loop']['index'];\n")
39
- ->write("\$context['loop']['first'] = false;\n")
40
- ;
41
-
42
- if (!$this->getAttribute('ifexpr')) {
43
- $compiler
44
- ->write("if (isset(\$context['loop']['length'])) {\n")
45
- ->indent()
46
- ->write("--\$context['loop']['revindex0'];\n")
47
- ->write("--\$context['loop']['revindex'];\n")
48
- ->write("\$context['loop']['last'] = 0 === \$context['loop']['revindex0'];\n")
49
- ->outdent()
50
- ->write("}\n")
51
- ;
52
- }
53
- }
54
- }
55
- }
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2011 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ /**
13
+ * Internal node used by the for node.
14
+ *
15
+ * @author Fabien Potencier <fabien@symfony.com>
16
+ */
17
+ class Twig_Node_ForLoop extends Twig_Node
18
+ {
19
+ public function __construct($lineno, $tag = null)
20
+ {
21
+ parent::__construct(array(), array('with_loop' => false, 'ifexpr' => false, 'else' => false), $lineno, $tag);
22
+ }
23
+
24
+ /**
25
+ * Compiles the node to PHP.
26
+ *
27
+ * @param Twig_Compiler A Twig_Compiler instance
28
+ */
29
+ public function compile(Twig_Compiler $compiler)
30
+ {
31
+ if ($this->getAttribute('else')) {
32
+ $compiler->write("\$context['_iterated'] = true;\n");
33
+ }
34
+
35
+ if ($this->getAttribute('with_loop')) {
36
+ $compiler
37
+ ->write("++\$context['loop']['index0'];\n")
38
+ ->write("++\$context['loop']['index'];\n")
39
+ ->write("\$context['loop']['first'] = false;\n")
40
+ ;
41
+
42
+ if (!$this->getAttribute('ifexpr')) {
43
+ $compiler
44
+ ->write("if (isset(\$context['loop']['length'])) {\n")
45
+ ->indent()
46
+ ->write("--\$context['loop']['revindex0'];\n")
47
+ ->write("--\$context['loop']['revindex'];\n")
48
+ ->write("\$context['loop']['last'] = 0 === \$context['loop']['revindex0'];\n")
49
+ ->outdent()
50
+ ->write("}\n")
51
+ ;
52
+ }
53
+ }
54
+ }
55
+ }
classes/Twig/Node/If.php CHANGED
@@ -1,66 +1,66 @@
1
- <?php
2
-
3
- /*
4
- * This file is part of Twig.
5
- *
6
- * (c) 2009 Fabien Potencier
7
- * (c) 2009 Armin Ronacher
8
- *
9
- * For the full copyright and license information, please view the LICENSE
10
- * file that was distributed with this source code.
11
- */
12
-
13
- /**
14
- * Represents an if node.
15
- *
16
- * @author Fabien Potencier <fabien@symfony.com>
17
- */
18
- class Twig_Node_If extends Twig_Node
19
- {
20
- public function __construct(Twig_NodeInterface $tests, Twig_NodeInterface $else = null, $lineno, $tag = null)
21
- {
22
- parent::__construct(array('tests' => $tests, 'else' => $else), array(), $lineno, $tag);
23
- }
24
-
25
- /**
26
- * Compiles the node to PHP.
27
- *
28
- * @param Twig_Compiler A Twig_Compiler instance
29
- */
30
- public function compile(Twig_Compiler $compiler)
31
- {
32
- $compiler->addDebugInfo($this);
33
- for ($i = 0, $count = count($this->getNode('tests')); $i < $count; $i += 2) {
34
- if ($i > 0) {
35
- $compiler
36
- ->outdent()
37
- ->write("} elseif (")
38
- ;
39
- } else {
40
- $compiler
41
- ->write('if (')
42
- ;
43
- }
44
-
45
- $compiler
46
- ->subcompile($this->getNode('tests')->getNode($i))
47
- ->raw(") {\n")
48
- ->indent()
49
- ->subcompile($this->getNode('tests')->getNode($i + 1))
50
- ;
51
- }
52
-
53
- if ($this->hasNode('else') && null !== $this->getNode('else')) {
54
- $compiler
55
- ->outdent()
56
- ->write("} else {\n")
57
- ->indent()
58
- ->subcompile($this->getNode('else'))
59
- ;
60
- }
61
-
62
- $compiler
63
- ->outdent()
64
- ->write("}\n");
65
- }
66
- }
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2009 Fabien Potencier
7
+ * (c) 2009 Armin Ronacher
8
+ *
9
+ * For the full copyright and license information, please view the LICENSE
10
+ * file that was distributed with this source code.
11
+ */
12
+
13
+ /**
14
+ * Represents an if node.
15
+ *
16
+ * @author Fabien Potencier <fabien@symfony.com>
17
+ */
18
+ class Twig_Node_If extends Twig_Node
19
+ {
20
+ public function __construct(Twig_NodeInterface $tests, Twig_NodeInterface $else = null, $lineno, $tag = null)
21
+ {
22
+ parent::__construct(array('tests' => $tests, 'else' => $else), array(), $lineno, $tag);
23
+ }
24
+
25
+ /**
26
+ * Compiles the node to PHP.
27
+ *
28
+ * @param Twig_Compiler A Twig_Compiler instance
29
+ */
30
+ public function compile(Twig_Compiler $compiler)
31
+ {
32
+ $compiler->addDebugInfo($this);
33
+ for ($i = 0, $count = count($this->getNode('tests')); $i < $count; $i += 2) {
34
+ if ($i > 0) {
35
+ $compiler
36
+ ->outdent()
37
+ ->write("} elseif (")
38
+ ;
39
+ } else {
40
+ $compiler
41
+ ->write('if (')
42
+ ;
43
+ }
44
+
45
+ $compiler
46
+ ->subcompile($this->getNode('tests')->getNode($i))
47
+ ->raw(") {\n")
48
+ ->indent()
49
+ ->subcompile($this->getNode('tests')->getNode($i + 1))
50
+ ;
51
+ }
52
+
53
+ if ($this->hasNode('else') && null !== $this->getNode('else')) {
54
+ $compiler
55
+ ->outdent()
56
+ ->write("} else {\n")
57
+ ->indent()
58
+ ->subcompile($this->getNode('else'))
59
+ ;
60
+ }
61
+
62
+ $compiler
63
+ ->outdent()
64
+ ->write("}\n");
65
+ }
66
+ }
classes/Twig/Node/Import.php CHANGED
@@ -1,50 +1,50 @@
1
- <?php
2
-
3
- /*
4
- * This file is part of Twig.
5
- *
6
- * (c) 2009 Fabien Potencier
7
- *
8
- * For the full copyright and license information, please view the LICENSE
9
- * file that was distributed with this source code.
10
- */
11
-
12
- /**
13
- * Represents an import node.
14
- *
15
- * @author Fabien Potencier <fabien@symfony.com>
16
- */
17
- class Twig_Node_Import extends Twig_Node
18
- {
19
- public function __construct(Twig_Node_Expression $expr, Twig_Node_Expression $var, $lineno, $tag = null)
20
- {
21
- parent::__construct(array('expr' => $expr, 'var' => $var), array(), $lineno, $tag);
22
- }
23
-
24
- /**
25
- * Compiles the node to PHP.
26
- *
27
- * @param Twig_Compiler A Twig_Compiler instance
28
- */
29
- public function compile(Twig_Compiler $compiler)
30
- {
31
- $compiler
32
- ->addDebugInfo($this)
33
- ->write('')
34
- ->subcompile($this->getNode('var'))
35
- ->raw(' = ')
36
- ;
37
-
38
- if ($this->getNode('expr') instanceof Twig_Node_Expression_Name && '_self' === $this->getNode('expr')->getAttribute('name')) {
39
- $compiler->raw("\$this");
40
- } else {
41
- $compiler
42
- ->raw('$this->env->loadTemplate(')
43
- ->subcompile($this->getNode('expr'))
44
- ->raw(")")
45
- ;
46
- }
47
-
48
- $compiler->raw(";\n");
49
- }
50
- }
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2009 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ /**
13
+ * Represents an import node.
14
+ *
15
+ * @author Fabien Potencier <fabien@symfony.com>
16
+ */
17
+ class Twig_Node_Import extends Twig_Node
18
+ {
19
+ public function __construct(Twig_Node_Expression $expr, Twig_Node_Expression $var, $lineno, $tag = null)
20
+ {
21
+ parent::__construct(array('expr' => $expr, 'var' => $var), array(), $lineno, $tag);
22
+ }
23
+
24
+ /**
25
+ * Compiles the node to PHP.
26
+ *
27
+ * @param Twig_Compiler A Twig_Compiler instance
28
+ */
29
+ public function compile(Twig_Compiler $compiler)
30
+ {
31
+ $compiler
32
+ ->addDebugInfo($this)
33
+ ->write('')
34
+ ->subcompile($this->getNode('var'))
35
+ ->raw(' = ')
36
+ ;
37
+
38
+ if ($this->getNode('expr') instanceof Twig_Node_Expression_Name && '_self' === $this->getNode('expr')->getAttribute('name')) {
39
+ $compiler->raw("\$this");
40
+ } else {
41
+ $compiler
42
+ ->raw('$this->env->loadTemplate(')
43
+ ->subcompile($this->getNode('expr'))
44
+ ->raw(")")
45
+ ;
46
+ }
47
+
48
+ $compiler->raw(";\n");
49
+ }
50
+ }
classes/Twig/Node/Include.php CHANGED
@@ -1,99 +1,99 @@
1
- <?php
2
-
3
- /*
4
- * This file is part of Twig.
5
- *
6
- * (c) 2009 Fabien Potencier
7
- * (c) 2009 Armin Ronacher
8
- *
9
- * For the full copyright and license information, please view the LICENSE
10
- * file that was distributed with this source code.
11
- */
12
-
13
- /**
14
- * Represents an include node.
15
- *
16
- * @author Fabien Potencier <fabien@symfony.com>
17
- */
18
- class Twig_Node_Include extends Twig_Node implements Twig_NodeOutputInterface
19
- {
20
- public function __construct(Twig_Node_Expression $expr, Twig_Node_Expression $variables = null, $only = false, $ignoreMissing = false, $lineno, $tag = null)
21
- {
22
- parent::__construct(array('expr' => $expr, 'variables' => $variables), array('only' => (bool) $only, 'ignore_missing' => (bool) $ignoreMissing), $lineno, $tag);
23
- }
24
-
25
- /**
26
- * Compiles the node to PHP.
27
- *
28
- * @param Twig_Compiler A Twig_Compiler instance
29
- */
30
- public function compile(Twig_Compiler $compiler)
31
- {
32
- $compiler->addDebugInfo($this);
33
-
34
- if ($this->getAttribute('ignore_missing')) {
35
- $compiler
36
- ->write("try {\n")
37
- ->indent()
38
- ;
39
- }
40
-
41
- $this->addGetTemplate($compiler);
42
-
43
- $compiler->raw('->display(');
44
-
45
- $this->addTemplateArguments($compiler);
46
-
47
- $compiler->raw(");\n");
48
-
49
- if ($this->getAttribute('ignore_missing')) {
50
- $compiler
51
- ->outdent()
52
- ->write("} catch (Twig_Error_Loader \$e) {\n")
53
- ->indent()
54
- ->write("// ignore missing template\n")
55
- ->outdent()
56
- ->write("}\n\n")
57
- ;
58
- }
59
- }
60
-
61
- protected function addGetTemplate(Twig_Compiler $compiler)
62
- {
63
- if ($this->getNode('expr') instanceof Twig_Node_Expression_Constant) {
64
- $compiler
65
- ->write("\$this->env->loadTemplate(")
66
- ->subcompile($this->getNode('expr'))
67
- ->raw(")")
68
- ;
69
- } else {
70
- $compiler
71
- ->write("\$template = \$this->env->resolveTemplate(")
72
- ->subcompile($this->getNode('expr'))
73
- ->raw(");\n")
74
- ->write('$template')
75
- ;
76
- }
77
- }
78
-
79
- protected function addTemplateArguments(Twig_Compiler $compiler)
80
- {
81
- if (false === $this->getAttribute('only')) {
82
- if (null === $this->getNode('variables')) {
83
- $compiler->raw('$context');
84
- } else {
85
- $compiler
86
- ->raw('array_merge($context, ')
87
- ->subcompile($this->getNode('variables'))
88
- ->raw(')')
89
- ;
90
- }
91
- } else {
92
- if (null === $this->getNode('variables')) {
93
- $compiler->raw('array()');
94
- } else {
95
- $compiler->subcompile($this->getNode('variables'));
96
- }
97
- }
98
- }
99
- }
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2009 Fabien Potencier
7
+ * (c) 2009 Armin Ronacher
8
+ *
9
+ * For the full copyright and license information, please view the LICENSE
10
+ * file that was distributed with this source code.
11
+ */
12
+
13
+ /**
14
+ * Represents an include node.
15
+ *
16
+ * @author Fabien Potencier <fabien@symfony.com>
17
+ */
18
+ class Twig_Node_Include extends Twig_Node implements Twig_NodeOutputInterface
19
+ {
20
+ public function __construct(Twig_Node_Expression $expr, Twig_Node_Expression $variables = null, $only = false, $ignoreMissing = false, $lineno, $tag = null)
21
+ {
22
+ parent::__construct(array('expr' => $expr, 'variables' => $variables), array('only' => (bool) $only, 'ignore_missing' => (bool) $ignoreMissing), $lineno, $tag);
23
+ }
24
+
25
+ /**
26
+ * Compiles the node to PHP.
27
+ *
28
+ * @param Twig_Compiler A Twig_Compiler instance
29
+ */
30
+ public function compile(Twig_Compiler $compiler)
31
+ {
32
+ $compiler->addDebugInfo($this);
33
+
34
+ if ($this->getAttribute('ignore_missing')) {
35
+ $compiler
36
+ ->write("try {\n")
37
+ ->indent()
38
+ ;
39
+ }
40
+
41
+ $this->addGetTemplate($compiler);
42
+
43
+ $compiler->raw('->display(');
44
+
45
+ $this->addTemplateArguments($compiler);
46
+
47
+ $compiler->raw(");\n");
48
+
49
+ if ($this->getAttribute('ignore_missing')) {
50
+ $compiler
51
+ ->outdent()
52
+ ->write("} catch (Twig_Error_Loader \$e) {\n")
53
+ ->indent()
54
+ ->write("// ignore missing template\n")
55
+ ->outdent()
56
+ ->write("}\n\n")
57
+ ;
58
+ }
59
+ }
60
+
61
+ protected function addGetTemplate(Twig_Compiler $compiler)
62
+ {
63
+ if ($this->getNode('expr') instanceof Twig_Node_Expression_Constant) {
64
+ $compiler
65
+ ->write("\$this->env->loadTemplate(")
66
+ ->subcompile($this->getNode('expr'))
67
+ ->raw(")")
68
+ ;
69
+ } else {
70
+ $compiler
71
+ ->write("\$template = \$this->env->resolveTemplate(")
72
+ ->subcompile($this->getNode('expr'))
73
+ ->raw(");\n")
74
+ ->write('$template')
75
+ ;
76
+ }
77
+ }
78
+
79
+ protected function addTemplateArguments(Twig_Compiler $compiler)
80
+ {
81
+ if (false === $this->getAttribute('only')) {
82
+ if (null === $this->getNode('variables')) {
83
+ $compiler->raw('$context');
84
+ } else {
85
+ $compiler
86
+ ->raw('array_merge($context, ')
87
+ ->subcompile($this->getNode('variables'))
88
+ ->raw(')')
89
+ ;
90
+ }
91
+ } else {
92
+ if (null === $this->getNode('variables')) {
93
+ $compiler->raw('array()');
94
+ } else {
95
+ $compiler->subcompile($this->getNode('variables'));
96
+ }
97
+ }
98
+ }
99
+ }
classes/Twig/Node/Macro.php CHANGED
@@ -1,96 +1,96 @@
1
- <?php
2
-
3
- /*
4
- * This file is part of Twig.
5
- *
6
- * (c) 2009 Fabien Potencier
7
- *
8
- * For the full copyright and license information, please view the LICENSE
9
- * file that was distributed with this source code.
10
- */
11
-
12
- /**
13
- * Represents a macro node.
14
- *
15
- * @author Fabien Potencier <fabien@symfony.com>
16
- */
17
- class Twig_Node_Macro extends Twig_Node
18
- {
19
- public function __construct($name, Twig_NodeInterface $body, Twig_NodeInterface $arguments, $lineno, $tag = null)
20
- {
21
- parent::__construct(array('body' => $body, 'arguments' => $arguments), array('name' => $name), $lineno, $tag);
22
- }
23
-
24
- /**
25
- * Compiles the node to PHP.
26
- *
27
- * @param Twig_Compiler A Twig_Compiler instance
28
- */
29
- public function compile(Twig_Compiler $compiler)
30
- {
31
- $compiler
32
- ->addDebugInfo($this)
33
- ->write(sprintf("public function get%s(", $this->getAttribute('name')))
34
- ;
35
-
36
- $count = count($this->getNode('arguments'));
37
- $pos = 0;
38
- foreach ($this->getNode('arguments') as $name => $default) {
39
- $compiler
40
- ->raw('$_'.$name.' = ')
41
- ->subcompile($default)
42
- ;
43
-
44
- if (++$pos < $count) {
45
- $compiler->raw(', ');
46
- }
47
- }
48
-
49
- $compiler
50
- ->raw(")\n")
51
- ->write("{\n")
52
- ->indent()
53
- ;
54
-
55
- if (!count($this->getNode('arguments'))) {
56
- $compiler->write("\$context = \$this->env->getGlobals();\n\n");
57
- } else {
58
- $compiler
59
- ->write("\$context = \$this->env->mergeGlobals(array(\n")
60
- ->indent()
61
- ;
62
-
63
- foreach ($this->getNode('arguments') as $name => $default) {
64
- $compiler
65
- ->write('')
66
- ->string($name)
67
- ->raw(' => $_'.$name)
68
- ->raw(",\n")
69
- ;
70
- }
71
-
72
- $compiler
73
- ->outdent()
74
- ->write("));\n\n")
75
- ;
76
- }
77
-
78
- $compiler
79
- ->write("\$blocks = array();\n\n")
80
- ->write("ob_start();\n")
81
- ->write("try {\n")
82
- ->indent()
83
- ->subcompile($this->getNode('body'))
84
- ->outdent()
85
- ->write("} catch (Exception \$e) {\n")
86
- ->indent()
87
- ->write("ob_end_clean();\n\n")
88
- ->write("throw \$e;\n")
89
- ->outdent()
90
- ->write("}\n\n")
91
- ->write("return ('' === \$tmp = ob_get_clean()) ? '' : new Twig_Markup(\$tmp, \$this->env->getCharset());\n")
92
- ->outdent()
93
- ->write("}\n\n")
94
- ;
95
- }
96
- }
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2009 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ /**
13
+ * Represents a macro node.
14
+ *
15
+ * @author Fabien Potencier <fabien@symfony.com>
16
+ */
17
+ class Twig_Node_Macro extends Twig_Node
18
+ {
19
+ public function __construct($name, Twig_NodeInterface $body, Twig_NodeInterface $arguments, $lineno, $tag = null)
20
+ {
21
+ parent::__construct(array('body' => $body, 'arguments' => $arguments), array('name' => $name), $lineno, $tag);
22
+ }
23
+
24
+ /**
25
+ * Compiles the node to PHP.
26
+ *
27
+ * @param Twig_Compiler A Twig_Compiler instance
28
+ */
29
+ public function compile(Twig_Compiler $compiler)
30
+ {
31
+ $compiler
32
+ ->addDebugInfo($this)
33
+ ->write(sprintf("public function get%s(", $this->getAttribute('name')))
34
+ ;
35
+
36
+ $count = count($this->getNode('arguments'));
37
+ $pos = 0;
38
+ foreach ($this->getNode('arguments') as $name => $default) {
39
+ $compiler
40
+ ->raw('$_'.$name.' = ')
41
+ ->subcompile($default)
42
+ ;
43
+
44
+ if (++$pos < $count) {
45
+ $compiler->raw(', ');
46
+ }
47
+ }
48
+
49
+ $compiler
50
+ ->raw(")\n")
51
+ ->write("{\n")
52
+ ->indent()
53
+ ;
54
+
55
+ if (!count($this->getNode('arguments'))) {
56
+ $compiler->write("\$context = \$this->env->getGlobals();\n\n");
57
+ } else {
58
+ $compiler
59
+ ->write("\$context = \$this->env->mergeGlobals(array(\n")
60
+ ->indent()
61
+ ;
62
+
63
+ foreach ($this->getNode('arguments') as $name => $default) {
64
+ $compiler
65
+ ->write('')
66
+ ->string($name)
67
+ ->raw(' => $_'.$name)
68
+ ->raw(",\n")
69
+ ;
70
+ }
71
+
72
+ $compiler
73
+ ->outdent()
74
+ ->write("));\n\n")
75
+ ;
76
+ }
77
+
78
+ $compiler
79
+ ->write("\$blocks = array();\n\n")
80
+ ->write("ob_start();\n")
81
+ ->write("try {\n")
82
+ ->indent()
83
+ ->subcompile($this->getNode('body'))
84
+ ->outdent()
85
+ ->write("} catch (Exception \$e) {\n")
86
+ ->indent()
87
+ ->write("ob_end_clean();\n\n")
88
+ ->write("throw \$e;\n")
89
+ ->outdent()
90
+ ->write("}\n\n")
91
+ ->write("return ('' === \$tmp = ob_get_clean()) ? '' : new Twig_Markup(\$tmp, \$this->env->getCharset());\n")
92
+ ->outdent()
93
+ ->write("}\n\n")
94
+ ;
95
+ }
96
+ }
classes/Twig/Node/Module.php CHANGED
@@ -1,383 +1,383 @@
1
- <?php
2
-
3
- /*
4
- * This file is part of Twig.
5
- *
6
- * (c) 2009 Fabien Potencier
7
- * (c) 2009 Armin Ronacher
8
- *
9
- * For the full copyright and license information, please view the LICENSE
10
- * file that was distributed with this source code.
11
- */
12
-
13
- /**
14
- * Represents a module node.
15
- *
16
- * @author Fabien Potencier <fabien@symfony.com>
17
- */
18
- class Twig_Node_Module extends Twig_Node
19
- {
20
- public function __construct(Twig_NodeInterface $body, Twig_Node_Expression $parent = null, Twig_NodeInterface $blocks, Twig_NodeInterface $macros, Twig_NodeInterface $traits, $embeddedTemplates, $filename)
21
- {
22
- // embedded templates are set as attributes so that they are only visited once by the visitors
23
- parent::__construct(array('parent' => $parent, 'body' => $body, 'blocks' => $blocks, 'macros' => $macros, 'traits' => $traits), array('filename' => $filename, 'index' => null, 'embedded_templates' => $embeddedTemplates), 1);
24
- }
25
-
26
- public function setIndex($index)
27
- {
28
- $this->setAttribute('index', $index);
29
- }
30
-
31
- /**
32
- * Compiles the node to PHP.
33
- *
34
- * @param Twig_Compiler A Twig_Compiler instance
35
- */
36
- public function compile(Twig_Compiler $compiler)
37
- {
38
- $this->compileTemplate($compiler);
39
-
40
- foreach ($this->getAttribute('embedded_templates') as $template) {
41
- $compiler->subcompile($template);
42
- }
43
- }
44
-
45
- protected function compileTemplate(Twig_Compiler $compiler)
46
- {
47
- if (!$this->getAttribute('index')) {
48
- $compiler->write('<?php');
49
- }
50
-
51
- $this->compileClassHeader($compiler);
52
-
53
- if (count($this->getNode('blocks')) || count($this->getNode('traits')) || null === $this->getNode('parent') || $this->getNode('parent') instanceof Twig_Node_Expression_Constant) {
54
- $this->compileConstructor($compiler);
55
- }
56
-
57
- $this->compileGetParent($compiler);
58
-
59
- $this->compileDisplayHeader($compiler);
60
-
61
- $this->compileDisplayBody($compiler);
62
-
63
- $this->compileDisplayFooter($compiler);
64
-
65
- $compiler->subcompile($this->getNode('blocks'));
66
-
67
- $this->compileMacros($compiler);
68
-
69
- $this->compileGetTemplateName($compiler);
70
-
71
- $this->compileIsTraitable($compiler);
72
-
73
- $this->compileDebugInfo($compiler);
74
-
75
- $this->compileClassFooter($compiler);
76
- }
77
-
78
- protected function compileGetParent(Twig_Compiler $compiler)
79
- {
80
- if (null === $this->getNode('parent')) {
81
- return;
82
- }
83
-
84
- $compiler
85
- ->write("protected function doGetParent(array \$context)\n", "{\n")
86
- ->indent()
87
- ->write("return ")
88
- ;
89
-
90
- if ($this->getNode('parent') instanceof Twig_Node_Expression_Constant) {
91
- $compiler->subcompile($this->getNode('parent'));
92
- } else {
93
- $compiler
94
- ->raw("\$this->env->resolveTemplate(")
95
- ->subcompile($this->getNode('parent'))
96
- ->raw(")")
97
- ;
98
- }
99
-
100
- $compiler
101
- ->raw(";\n")
102
- ->outdent()
103
- ->write("}\n\n")
104
- ;
105
- }
106
-
107
- protected function compileDisplayBody(Twig_Compiler $compiler)
108
- {
109
- $compiler->subcompile($this->getNode('body'));
110
-
111
- if (null !== $this->getNode('parent')) {
112
- if ($this->getNode('parent') instanceof Twig_Node_Expression_Constant) {
113
- $compiler->write("\$this->parent");
114
- } else {
115
- $compiler->write("\$this->getParent(\$context)");
116
- }
117
- $compiler->raw("->display(\$context, array_merge(\$this->blocks, \$blocks));\n");
118
- }
119
- }
120
-
121
- protected function compileClassHeader(Twig_Compiler $compiler)
122
- {
123
- $compiler
124
- ->write("\n\n")
125
- // if the filename contains */, add a blank to avoid a PHP parse error
126
- ->write("/* ".str_replace('*/', '* /', $this->getAttribute('filename'))." */\n")
127
- ->write('class '.$compiler->getEnvironment()->getTemplateClass($this->getAttribute('filename'), $this->getAttribute('index')))
128
- ->raw(sprintf(" extends %s\n", $compiler->getEnvironment()->getBaseTemplateClass()))
129
- ->write("{\n")
130
- ->indent()
131
- ;
132
- }
133
-
134
- protected function compileConstructor(Twig_Compiler $compiler)
135
- {
136
- $compiler
137
- ->write("public function __construct(Twig_Environment \$env)\n", "{\n")
138
- ->indent()
139
- ->write("parent::__construct(\$env);\n\n")
140
- ;
141
-
142
- // parent
143
- if (null === $this->getNode('parent')) {
144
- $compiler->write("\$this->parent = false;\n\n");
145
- } elseif ($this->getNode('parent') instanceof Twig_Node_Expression_Constant) {
146
- $compiler
147
- ->write("\$this->parent = \$this->env->loadTemplate(")
148
- ->subcompile($this->getNode('parent'))
149
- ->raw(");\n\n")
150
- ;
151
- }
152
-
153
- $countTraits = count($this->getNode('traits'));
154
- if ($countTraits) {
155
- // traits
156
- foreach ($this->getNode('traits') as $i => $trait) {
157
- $this->compileLoadTemplate($compiler, $trait->getNode('template'), sprintf('$_trait_%s', $i));
158
-
159
- $compiler
160
- ->addDebugInfo($trait->getNode('template'))
161
- ->write(sprintf("if (!\$_trait_%s->isTraitable()) {\n", $i))
162
- ->indent()
163
- ->write("throw new Twig_Error_Runtime('Template \"'.")
164
- ->subcompile($trait->getNode('template'))
165
- ->raw(".'\" cannot be used as a trait.');\n")
166
- ->outdent()
167
- ->write("}\n")
168
- ->write(sprintf("\$_trait_%s_blocks = \$_trait_%s->getBlocks();\n\n", $i, $i))
169
- ;
170
-
171
- foreach ($trait->getNode('targets') as $key => $value) {
172
- $compiler
173
- ->write(sprintf("if (!isset(\$_trait_%s_blocks[", $i))
174
- ->string($key)
175
- ->raw("])) {\n")
176
- ->indent()
177
- ->write("throw new Twig_Error_Runtime(sprintf('Block ")
178
- ->string($key)
179
- ->raw(" is not defined in trait ")
180
- ->subcompile($trait->getNode('template'))
181
- ->raw(".'));\n")
182
- ->outdent()
183
- ->write("}\n\n")
184
-
185
- ->write(sprintf("\$_trait_%s_blocks[", $i))
186
- ->subcompile($value)
187
- ->raw(sprintf("] = \$_trait_%s_blocks[", $i))
188
- ->string($key)
189
- ->raw(sprintf("]; unset(\$_trait_%s_blocks[", $i))
190
- ->string($key)
191
- ->raw("]);\n\n")
192
- ;
193
- }
194
- }
195
-
196
- if ($countTraits > 1) {
197
- $compiler
198
- ->write("\$this->traits = array_merge(\n")
199
- ->indent()
200
- ;
201
-
202
- for ($i = 0; $i < $countTraits; $i++) {
203
- $compiler
204
- ->write(sprintf("\$_trait_%s_blocks".($i == $countTraits - 1 ? '' : ',')."\n", $i))
205
- ;
206
- }
207
-
208
- $compiler
209
- ->outdent()
210
- ->write(");\n\n")
211
- ;
212
- } else {
213
- $compiler
214
- ->write("\$this->traits = \$_trait_0_blocks;\n\n")
215
- ;
216
- }
217
-
218
- $compiler
219
- ->write("\$this->blocks = array_merge(\n")
220
- ->indent()
221
- ->write("\$this->traits,\n")
222
- ->write("array(\n")
223
- ;
224
- } else {
225
- $compiler
226
- ->write("\$this->blocks = array(\n")
227
- ;
228
- }
229
-
230
- // blocks
231
- $compiler
232
- ->indent()
233
- ;
234
-
235
- foreach ($this->getNode('blocks') as $name => $node) {
236
- $compiler
237
- ->write(sprintf("'%s' => array(\$this, 'block_%s'),\n", $name, $name))
238
- ;
239
- }
240
-
241
- if ($countTraits) {
242
- $compiler
243
- ->outdent()
244
- ->write(")\n")
245
- ;
246
- }
247
-
248
- $compiler
249
- ->outdent()
250
- ->write(");\n")
251
- ->outdent()
252
- ->write("}\n\n");
253
- ;
254
- }
255
-
256
- protected function compileDisplayHeader(Twig_Compiler $compiler)
257
- {
258
- $compiler
259
- ->write("protected function doDisplay(array \$context, array \$blocks = array())\n", "{\n")
260
- ->indent()
261
- ;
262
- }
263
-
264
- protected function compileDisplayFooter(Twig_Compiler $compiler)
265
- {
266
- $compiler
267
- ->outdent()
268
- ->write("}\n\n")
269
- ;
270
- }
271
-
272
- protected function compileClassFooter(Twig_Compiler $compiler)
273
- {
274
- $compiler
275
- ->outdent()
276
- ->write("}\n")
277
- ;
278
- }
279
-
280
- protected function compileMacros(Twig_Compiler $compiler)
281
- {
282
- $compiler->subcompile($this->getNode('macros'));
283
- }
284
-
285
- protected function compileGetTemplateName(Twig_Compiler $compiler)
286
- {
287
- $compiler
288
- ->write("public function getTemplateName()\n", "{\n")
289
- ->indent()
290
- ->write('return ')
291
- ->repr($this->getAttribute('filename'))
292
- ->raw(";\n")
293
- ->outdent()
294
- ->write("}\n\n")
295
- ;
296
- }
297
-
298
- protected function compileIsTraitable(Twig_Compiler $compiler)
299
- {
300
- // A template can be used as a trait if:
301
- // * it has no parent
302
- // * it has no macros
303
- // * it has no body
304
- //
305
- // Put another way, a template can be used as a trait if it
306
- // only contains blocks and use statements.
307
- $traitable = null === $this->getNode('parent') && 0 === count($this->getNode('macros'));
308
- if ($traitable) {
309
- if ($this->getNode('body') instanceof Twig_Node_Body) {
310
- $nodes = $this->getNode('body')->getNode(0);
311
- } else {
312
- $nodes = $this->getNode('body');
313
- }
314
-
315
- if (!count($nodes)) {
316
- $nodes = new Twig_Node(array($nodes));
317
- }
318
-
319
- foreach ($nodes as $node) {
320
- if (!count($node)) {
321
- continue;
322
- }
323
-
324
- if ($node instanceof Twig_Node_Text && ctype_space($node->getAttribute('data'))) {
325
- continue;
326
- }
327
-
328
- if ($node instanceof Twig_Node_BlockReference) {
329
- continue;
330
- }
331
-
332
- $traitable = false;
333
- break;
334
- }
335
- }
336
-
337
- if ($traitable) {
338
- return;
339
- }
340
-
341
- $compiler
342
- ->write("public function isTraitable()\n", "{\n")
343
- ->indent()
344
- ->write(sprintf("return %s;\n", $traitable ? 'true' : 'false'))
345
- ->outdent()
346
- ->write("}\n\n")
347
- ;
348
- }
349
-
350
- protected function compileDebugInfo(Twig_Compiler $compiler)
351
- {
352
- $compiler
353
- ->write("public function getDebugInfo()\n", "{\n")
354
- ->indent()
355
- ->write(sprintf("return %s;\n", str_replace("\n", '', var_export(array_reverse($compiler->getDebugInfo(), true), true))))
356
- ->outdent()
357
- ->write("}\n")
358
- ;
359
- }
360
-
361
- protected function compileLoadTemplate(Twig_Compiler $compiler, $node, $var)
362
- {
363
- if ($node instanceof Twig_Node_Expression_Constant) {
364
- $compiler
365
- ->write(sprintf("%s = \$this->env->loadTemplate(", $var))
366
- ->subcompile($node)
367
- ->raw(");\n")
368
- ;
369
- } else {
370
- $compiler
371
- ->write(sprintf("%s = ", $var))
372
- ->subcompile($node)
373
- ->raw(";\n")
374
- ->write(sprintf("if (!%s", $var))
375
- ->raw(" instanceof Twig_Template) {\n")
376
- ->indent()
377
- ->write(sprintf("%s = \$this->env->loadTemplate(%s);\n", $var, $var))
378
- ->outdent()
379
- ->write("}\n")
380
- ;
381
- }
382
- }
383
- }
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2009 Fabien Potencier
7
+ * (c) 2009 Armin Ronacher
8
+ *
9
+ * For the full copyright and license information, please view the LICENSE
10
+ * file that was distributed with this source code.
11
+ */
12
+
13
+ /**
14
+ * Represents a module node.
15
+ *
16
+ * @author Fabien Potencier <fabien@symfony.com>
17
+ */
18
+ class Twig_Node_Module extends Twig_Node
19
+ {
20
+ public function __construct(Twig_NodeInterface $body, Twig_Node_Expression $parent = null, Twig_NodeInterface $blocks, Twig_NodeInterface $macros, Twig_NodeInterface $traits, $embeddedTemplates, $filename)
21
+ {
22
+ // embedded templates are set as attributes so that they are only visited once by the visitors
23
+ parent::__construct(array('parent' => $parent, 'body' => $body, 'blocks' => $blocks, 'macros' => $macros, 'traits' => $traits), array('filename' => $filename, 'index' => null, 'embedded_templates' => $embeddedTemplates), 1);
24
+ }
25
+
26
+ public function setIndex($index)
27
+ {
28
+ $this->setAttribute('index', $index);
29
+ }
30
+
31
+ /**
32
+ * Compiles the node to PHP.
33
+ *
34
+ * @param Twig_Compiler A Twig_Compiler instance
35
+ */
36
+ public function compile(Twig_Compiler $compiler)
37
+ {
38
+ $this->compileTemplate($compiler);
39
+
40
+ foreach ($this->getAttribute('embedded_templates') as $template) {
41
+ $compiler->subcompile($template);
42
+ }
43
+ }
44
+
45
+ protected function compileTemplate(Twig_Compiler $compiler)
46
+ {
47
+ if (!$this->getAttribute('index')) {
48
+ $compiler->write('<?php');
49
+ }
50
+
51
+ $this->compileClassHeader($compiler);
52
+
53
+ if (count($this->getNode('blocks')) || count($this->getNode('traits')) || null === $this->getNode('parent') || $this->getNode('parent') instanceof Twig_Node_Expression_Constant) {
54
+ $this->compileConstructor($compiler);
55
+ }
56
+
57
+ $this->compileGetParent($compiler);
58
+
59
+ $this->compileDisplayHeader($compiler);
60
+
61
+ $this->compileDisplayBody($compiler);
62
+
63
+ $this->compileDisplayFooter($compiler);
64
+
65
+ $compiler->subcompile($this->getNode('blocks'));
66
+
67
+ $this->compileMacros($compiler);
68
+
69
+ $this->compileGetTemplateName($compiler);
70
+
71
+ $this->compileIsTraitable($compiler);
72
+
73
+ $this->compileDebugInfo($compiler);
74
+
75
+ $this->compileClassFooter($compiler);
76
+ }
77
+
78
+ protected function compileGetParent(Twig_Compiler $compiler)
79
+ {
80
+ if (null === $this->getNode('parent')) {
81
+ return;
82
+ }
83
+
84
+ $compiler
85
+ ->write("protected function doGetParent(array \$context)\n", "{\n")
86
+ ->indent()
87
+ ->write("return ")
88
+ ;
89
+
90
+ if ($this->getNode('parent') instanceof Twig_Node_Expression_Constant) {
91
+ $compiler->subcompile($this->getNode('parent'));
92
+ } else {
93
+ $compiler
94
+ ->raw("\$this->env->resolveTemplate(")
95
+ ->subcompile($this->getNode('parent'))
96
+ ->raw(")")
97
+ ;
98
+ }
99
+
100
+ $compiler
101
+ ->raw(";\n")
102
+ ->outdent()
103
+ ->write("}\n\n")
104
+ ;
105
+ }
106
+
107
+ protected function compileDisplayBody(Twig_Compiler $compiler)
108
+ {
109
+ $compiler->subcompile($this->getNode('body'));
110
+
111
+ if (null !== $this->getNode('parent')) {
112
+ if ($this->getNode('parent') instanceof Twig_Node_Expression_Constant) {
113
+ $compiler->write("\$this->parent");
114
+ } else {
115
+ $compiler->write("\$this->getParent(\$context)");
116
+ }
117
+ $compiler->raw("->display(\$context, array_merge(\$this->blocks, \$blocks));\n");
118
+ }
119
+ }
120
+
121
+ protected function compileClassHeader(Twig_Compiler $compiler)
122
+ {
123
+ $compiler
124
+ ->write("\n\n")
125
+ // if the filename contains */, add a blank to avoid a PHP parse error
126
+ ->write("/* ".str_replace('*/', '* /', $this->getAttribute('filename'))." */\n")
127
+ ->write('class '.$compiler->getEnvironment()->getTemplateClass($this->getAttribute('filename'), $this->getAttribute('index')))
128
+ ->raw(sprintf(" extends %s\n", $compiler->getEnvironment()->getBaseTemplateClass()))
129
+ ->write("{\n")
130
+ ->indent()
131
+ ;
132
+ }
133
+
134
+ protected function compileConstructor(Twig_Compiler $compiler)
135
+ {
136
+ $compiler
137
+ ->write("public function __construct(Twig_Environment \$env)\n", "{\n")
138
+ ->indent()
139
+ ->write("parent::__construct(\$env);\n\n")
140
+ ;
141
+
142
+ // parent
143
+ if (null === $this->getNode('parent')) {
144
+ $compiler->write("\$this->parent = false;\n\n");
145
+ } elseif ($this->getNode('parent') instanceof Twig_Node_Expression_Constant) {
146
+ $compiler
147
+ ->write("\$this->parent = \$this->env->loadTemplate(")
148
+ ->subcompile($this->getNode('parent'))
149
+ ->raw(");\n\n")
150
+ ;
151
+ }
152
+
153
+ $countTraits = count($this->getNode('traits'));
154
+ if ($countTraits) {
155
+ // traits
156
+ foreach ($this->getNode('traits') as $i => $trait) {
157
+ $this->compileLoadTemplate($compiler, $trait->getNode('template'), sprintf('$_trait_%s', $i));
158
+
159
+ $compiler
160
+ ->addDebugInfo($trait->getNode('template'))
161
+ ->write(sprintf("if (!\$_trait_%s->isTraitable()) {\n", $i))
162
+ ->indent()
163
+ ->write("throw new Twig_Error_Runtime('Template \"'.")
164
+ ->subcompile($trait->getNode('template'))
165
+ ->raw(".'\" cannot be used as a trait.');\n")
166
+ ->outdent()
167
+ ->write("}\n")
168
+ ->write(sprintf("\$_trait_%s_blocks = \$_trait_%s->getBlocks();\n\n", $i, $i))
169
+ ;
170
+
171
+ foreach ($trait->getNode('targets') as $key => $value) {
172
+ $compiler
173
+ ->write(sprintf("if (!isset(\$_trait_%s_blocks[", $i))
174
+ ->string($key)
175
+ ->raw("])) {\n")
176
+ ->indent()
177
+ ->write("throw new Twig_Error_Runtime(sprintf('Block ")
178
+ ->string($key)
179
+ ->raw(" is not defined in trait ")
180
+ ->subcompile($trait->getNode('template'))
181
+ ->raw(".'));\n")
182
+ ->outdent()
183
+ ->write("}\n\n")
184
+
185
+ ->write(sprintf("\$_trait_%s_blocks[", $i))
186
+ ->subcompile($value)
187
+ ->raw(sprintf("] = \$_trait_%s_blocks[", $i))
188
+ ->string($key)
189
+ ->raw(sprintf("]; unset(\$_trait_%s_blocks[", $i))
190
+ ->string($key)
191
+ ->raw("]);\n\n")
192
+ ;
193
+ }
194
+ }
195
+
196
+ if ($countTraits > 1) {
197
+ $compiler
198
+ ->write("\$this->traits = array_merge(\n")
199
+ ->indent()
200
+ ;
201
+
202
+ for ($i = 0; $i < $countTraits; $i++) {
203
+ $compiler
204
+ ->write(sprintf("\$_trait_%s_blocks".($i == $countTraits - 1 ? '' : ',')."\n", $i))
205
+ ;
206
+ }
207
+
208
+ $compiler
209
+ ->outdent()
210
+ ->write(");\n\n")
211
+ ;
212
+ } else {
213
+ $compiler
214
+ ->write("\$this->traits = \$_trait_0_blocks;\n\n")
215
+ ;
216
+ }
217
+
218
+ $compiler
219
+ ->write("\$this->blocks = array_merge(\n")
220
+ ->indent()
221
+ ->write("\$this->traits,\n")
222
+ ->write("array(\n")
223
+ ;
224
+ } else {
225
+ $compiler
226
+ ->write("\$this->blocks = array(\n")
227
+ ;
228
+ }
229
+
230
+ // blocks
231
+ $compiler
232
+ ->indent()
233
+ ;
234
+
235
+ foreach ($this->getNode('blocks') as $name => $node) {
236
+ $compiler
237
+ ->write(sprintf("'%s' => array(\$this, 'block_%s'),\n", $name, $name))
238
+ ;
239
+ }
240
+
241
+ if ($countTraits) {
242
+ $compiler
243
+ ->outdent()
244
+ ->write(")\n")
245
+ ;
246
+ }
247
+
248
+ $compiler
249
+ ->outdent()
250
+ ->write(");\n")
251
+ ->outdent()
252
+ ->write("}\n\n");
253
+ ;
254
+ }
255
+
256
+ protected function compileDisplayHeader(Twig_Compiler $compiler)
257
+ {
258
+ $compiler
259
+ ->write("protected function doDisplay(array \$context, array \$blocks = array())\n", "{\n")
260
+ ->indent()
261
+ ;
262
+ }
263
+
264
+ protected function compileDisplayFooter(Twig_Compiler $compiler)
265
+ {
266
+ $compiler
267
+ ->outdent()
268
+ ->write("}\n\n")
269
+ ;
270
+ }
271
+
272
+ protected function compileClassFooter(Twig_Compiler $compiler)
273
+ {
274
+ $compiler
275
+ ->outdent()
276
+ ->write("}\n")
277
+ ;
278
+ }
279
+
280
+ protected function compileMacros(Twig_Compiler $compiler)
281
+ {
282
+ $compiler->subcompile($this->getNode('macros'));
283
+ }
284
+
285
+ protected function compileGetTemplateName(Twig_Compiler $compiler)
286
+ {
287
+ $compiler
288
+ ->write("public function getTemplateName()\n", "{\n")
289
+ ->indent()
290
+ ->write('return ')
291
+ ->repr($this->getAttribute('filename'))
292
+ ->raw(";\n")
293
+ ->outdent()
294
+ ->write("}\n\n")
295
+ ;
296
+ }
297
+
298
+ protected function compileIsTraitable(Twig_Compiler $compiler)
299
+ {
300
+ // A template can be used as a trait if:
301
+ // * it has no parent
302
+ // * it has no macros
303
+ // * it has no body
304
+ //
305
+ // Put another way, a template can be used as a trait if it
306
+ // only contains blocks and use statements.
307
+ $traitable = null === $this->getNode('parent') && 0 === count($this->getNode('macros'));
308
+ if ($traitable) {
309
+ if ($this->getNode('body') instanceof Twig_Node_Body) {
310
+ $nodes = $this->getNode('body')->getNode(0);
311
+ } else {
312
+ $nodes = $this->getNode('body');
313
+ }
314
+
315
+ if (!count($nodes)) {
316
+ $nodes = new Twig_Node(array($nodes));
317
+ }
318
+
319
+ foreach ($nodes as $node) {
320
+ if (!count($node)) {
321
+ continue;
322
+ }
323
+
324
+ if ($node instanceof Twig_Node_Text && ctype_space($node->getAttribute('data'))) {
325
+ continue;
326
+ }
327
+
328
+ if ($node instanceof Twig_Node_BlockReference) {
329
+ continue;
330
+ }
331
+
332
+ $traitable = false;
333
+ break;
334
+ }
335
+ }
336
+
337
+ if ($traitable) {
338
+ return;
339
+ }
340
+
341
+ $compiler
342
+ ->write("public function isTraitable()\n", "{\n")
343
+ ->indent()
344
+ ->write(sprintf("return %s;\n", $traitable ? 'true' : 'false'))
345
+ ->outdent()
346
+ ->write("}\n\n")
347
+ ;
348
+ }
349
+
350
+ protected function compileDebugInfo(Twig_Compiler $compiler)
351
+ {
352
+ $compiler
353
+ ->write("public function getDebugInfo()\n", "{\n")
354
+ ->indent()
355
+ ->write(sprintf("return %s;\n", str_replace("\n", '', var_export(array_reverse($compiler->getDebugInfo(), true), true))))
356
+ ->outdent()
357
+ ->write("}\n")
358
+ ;
359
+ }
360
+
361
+ protected function compileLoadTemplate(Twig_Compiler $compiler, $node, $var)
362
+ {
363
+ if ($node instanceof Twig_Node_Expression_Constant) {
364
+ $compiler
365
+ ->write(sprintf("%s = \$this->env->loadTemplate(", $var))
366
+ ->subcompile($node)
367
+ ->raw(");\n")
368
+ ;
369
+ } else {
370
+ $compiler
371
+ ->write(sprintf("%s = ", $var))
372
+ ->subcompile($node)
373
+ ->raw(";\n")
374
+ ->write(sprintf("if (!%s", $var))
375
+ ->raw(" instanceof Twig_Template) {\n")
376
+ ->indent()
377
+ ->write(sprintf("%s = \$this->env->loadTemplate(%s);\n", $var, $var))
378
+ ->outdent()
379
+ ->write("}\n")
380
+ ;
381
+ }
382
+ }
383
+ }
classes/Twig/Node/Print.php CHANGED
@@ -1,39 +1,39 @@
1
- <?php
2
-
3
- /*
4
- * This file is part of Twig.
5
- *
6
- * (c) 2009 Fabien Potencier
7
- * (c) 2009 Armin Ronacher
8
- *
9
- * For the full copyright and license information, please view the LICENSE
10
- * file that was distributed with this source code.
11
- */
12
-
13
- /**
14
- * Represents a node that outputs an expression.
15
- *
16
- * @author Fabien Potencier <fabien@symfony.com>
17
- */
18
- class Twig_Node_Print extends Twig_Node implements Twig_NodeOutputInterface
19
- {
20
- public function __construct(Twig_Node_Expression $expr, $lineno, $tag = null)
21
- {
22
- parent::__construct(array('expr' => $expr), array(), $lineno, $tag);
23
- }
24
-
25
- /**
26
- * Compiles the node to PHP.
27
- *
28
- * @param Twig_Compiler A Twig_Compiler instance
29
- */
30
- public function compile(Twig_Compiler $compiler)
31
- {
32
- $compiler
33
- ->addDebugInfo($this)
34
- ->write('echo ')
35
- ->subcompile($this->getNode('expr'))
36
- ->raw(";\n")
37
- ;
38
- }
39
- }
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2009 Fabien Potencier
7
+ * (c) 2009 Armin Ronacher
8
+ *
9
+ * For the full copyright and license information, please view the LICENSE
10
+ * file that was distributed with this source code.
11
+ */
12
+
13
+ /**
14
+ * Represents a node that outputs an expression.
15
+ *
16
+ * @author Fabien Potencier <fabien@symfony.com>
17
+ */
18
+ class Twig_Node_Print extends Twig_Node implements Twig_NodeOutputInterface
19
+ {
20
+ public function __construct(Twig_Node_Expression $expr, $lineno, $tag = null)
21
+ {
22
+ parent::__construct(array('expr' => $expr), array(), $lineno, $tag);
23
+ }
24
+
25
+ /**
26
+ * Compiles the node to PHP.
27
+ *
28
+ * @param Twig_Compiler A Twig_Compiler instance
29
+ */
30
+ public function compile(Twig_Compiler $compiler)
31
+ {
32
+ $compiler
33
+ ->addDebugInfo($this)
34
+ ->write('echo ')
35
+ ->subcompile($this->getNode('expr'))
36
+ ->raw(";\n")
37
+ ;
38
+ }
39
+ }
classes/Twig/Node/Sandbox.php CHANGED
@@ -1,47 +1,47 @@
1
- <?php
2
-
3
- /*
4
- * This file is part of Twig.
5
- *
6
- * (c) 2010 Fabien Potencier
7
- *
8
- * For the full copyright and license information, please view the LICENSE
9
- * file that was distributed with this source code.
10
- */
11
-
12
- /**
13
- * Represents a sandbox node.
14
- *
15
- * @author Fabien Potencier <fabien@symfony.com>
16
- */
17
- class Twig_Node_Sandbox extends Twig_Node
18
- {
19
- public function __construct(Twig_NodeInterface $body, $lineno, $tag = null)
20
- {
21
- parent::__construct(array('body' => $body), array(), $lineno, $tag);
22
- }
23
-
24
- /**
25
- * Compiles the node to PHP.
26
- *
27
- * @param Twig_Compiler A Twig_Compiler instance
28
- */
29
- public function compile(Twig_Compiler $compiler)
30
- {
31
- $compiler
32
- ->addDebugInfo($this)
33
- ->write("\$sandbox = \$this->env->getExtension('sandbox');\n")
34
- ->write("if (!\$alreadySandboxed = \$sandbox->isSandboxed()) {\n")
35
- ->indent()
36
- ->write("\$sandbox->enableSandbox();\n")
37
- ->outdent()
38
- ->write("}\n")
39
- ->subcompile($this->getNode('body'))
40
- ->write("if (!\$alreadySandboxed) {\n")
41
- ->indent()
42
- ->write("\$sandbox->disableSandbox();\n")
43
- ->outdent()
44
- ->write("}\n")
45
- ;
46
- }
47
- }
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2010 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ /**
13
+ * Represents a sandbox node.
14
+ *
15
+ * @author Fabien Potencier <fabien@symfony.com>
16
+ */
17
+ class Twig_Node_Sandbox extends Twig_Node
18
+ {
19
+ public function __construct(Twig_NodeInterface $body, $lineno, $tag = null)
20
+ {
21
+ parent::__construct(array('body' => $body), array(), $lineno, $tag);
22
+ }
23
+
24
+ /**
25
+ * Compiles the node to PHP.
26
+ *
27
+ * @param Twig_Compiler A Twig_Compiler instance
28
+ */
29
+ public function compile(Twig_Compiler $compiler)
30
+ {
31
+ $compiler
32
+ ->addDebugInfo($this)
33
+ ->write("\$sandbox = \$this->env->getExtension('sandbox');\n")
34
+ ->write("if (!\$alreadySandboxed = \$sandbox->isSandboxed()) {\n")
35
+ ->indent()
36
+ ->write("\$sandbox->enableSandbox();\n")
37
+ ->outdent()
38
+ ->write("}\n")
39
+ ->subcompile($this->getNode('body'))
40
+ ->write("if (!\$alreadySandboxed) {\n")
41
+ ->indent()
42
+ ->write("\$sandbox->disableSandbox();\n")
43
+ ->outdent()
44
+ ->write("}\n")
45
+ ;
46
+ }
47
+ }
classes/Twig/Node/SandboxedModule.php CHANGED
@@ -1,60 +1,60 @@
1
- <?php
2
-
3
- /*
4
- * This file is part of Twig.
5
- *
6
- * (c) 2009 Fabien Potencier
7
- * (c) 2009 Armin Ronacher
8
- *
9
- * For the full copyright and license information, please view the LICENSE
10
- * file that was distributed with this source code.
11
- */
12
-
13
- /**
14
- * Represents a module node.
15
- *
16
- * @author Fabien Potencier <fabien@symfony.com>
17
- */
18
- class Twig_Node_SandboxedModule extends Twig_Node_Module
19
- {
20
- protected $usedFilters;
21
- protected $usedTags;
22
- protected $usedFunctions;
23
-
24
- public function __construct(Twig_Node_Module $node, array $usedFilters, array $usedTags, array $usedFunctions)
25
- {
26
- parent::__construct($node->getNode('body'), $node->getNode('parent'), $node->getNode('blocks'), $node->getNode('macros'), $node->getNode('traits'), $node->getAttribute('embedded_templates'), $node->getAttribute('filename'));
27
-
28
- $this->setAttribute('index', $node->getAttribute('index'));
29
-
30
- $this->usedFilters = $usedFilters;
31
- $this->usedTags = $usedTags;
32
- $this->usedFunctions = $usedFunctions;
33
- }
34
-
35
- protected function compileDisplayBody(Twig_Compiler $compiler)
36
- {
37
- $compiler->write("\$this->checkSecurity();\n");
38
-
39
- parent::compileDisplayBody($compiler);
40
- }
41
-
42
- protected function compileDisplayFooter(Twig_Compiler $compiler)
43
- {
44
- parent::compileDisplayFooter($compiler);
45
-
46
- $compiler
47
- ->write("protected function checkSecurity()\n", "{\n")
48
- ->indent()
49
- ->write("\$this->env->getExtension('sandbox')->checkSecurity(\n")
50
- ->indent()
51
- ->write(!$this->usedTags ? "array(),\n" : "array('".implode('\', \'', $this->usedTags)."'),\n")
52
- ->write(!$this->usedFilters ? "array(),\n" : "array('".implode('\', \'', $this->usedFilters)."'),\n")
53
- ->write(!$this->usedFunctions ? "array()\n" : "array('".implode('\', \'', $this->usedFunctions)."')\n")
54
- ->outdent()
55
- ->write(");\n")
56
- ->outdent()
57
- ->write("}\n\n")
58
- ;
59
- }
60
- }
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2009 Fabien Potencier
7
+ * (c) 2009 Armin Ronacher
8
+ *
9
+ * For the full copyright and license information, please view the LICENSE
10
+ * file that was distributed with this source code.
11
+ */
12
+
13
+ /**
14
+ * Represents a module node.
15
+ *
16
+ * @author Fabien Potencier <fabien@symfony.com>
17
+ */
18
+ class Twig_Node_SandboxedModule extends Twig_Node_Module
19
+ {
20
+ protected $usedFilters;
21
+ protected $usedTags;
22
+ protected $usedFunctions;
23
+
24
+ public function __construct(Twig_Node_Module $node, array $usedFilters, array $usedTags, array $usedFunctions)
25
+ {
26
+ parent::__construct($node->getNode('body'), $node->getNode('parent'), $node->getNode('blocks'), $node->getNode('macros'), $node->getNode('traits'), $node->getAttribute('embedded_templates'), $node->getAttribute('filename'));
27
+
28
+ $this->setAttribute('index', $node->getAttribute('index'));
29
+
30
+ $this->usedFilters = $usedFilters;
31
+ $this->usedTags = $usedTags;
32
+ $this->usedFunctions = $usedFunctions;
33
+ }
34
+
35
+ protected function compileDisplayBody(Twig_Compiler $compiler)
36
+ {
37
+ $compiler->write("\$this->checkSecurity();\n");
38
+
39
+ parent::compileDisplayBody($compiler);
40
+ }
41
+
42
+ protected function compileDisplayFooter(Twig_Compiler $compiler)
43
+ {
44
+ parent::compileDisplayFooter($compiler);
45
+
46
+ $compiler
47
+ ->write("protected function checkSecurity()\n", "{\n")
48
+ ->indent()
49
+ ->write("\$this->env->getExtension('sandbox')->checkSecurity(\n")
50
+ ->indent()
51
+ ->write(!$this->usedTags ? "array(),\n" : "array('".implode('\', \'', $this->usedTags)."'),\n")
52
+ ->write(!$this->usedFilters ? "array(),\n" : "array('".implode('\', \'', $this->usedFilters)."'),\n")
53
+ ->write(!$this->usedFunctions ? "array()\n" : "array('".implode('\', \'', $this->usedFunctions)."')\n")
54
+ ->outdent()
55
+ ->write(");\n")
56
+ ->outdent()
57
+ ->write("}\n\n")
58
+ ;
59
+ }
60
+ }
classes/Twig/Node/SandboxedPrint.php CHANGED
@@ -1,59 +1,59 @@
1
- <?php
2
-
3
- /*
4
- * This file is part of Twig.
5
- *
6
- * (c) 2010 Fabien Potencier
7
- *
8
- * For the full copyright and license information, please view the LICENSE
9
- * file that was distributed with this source code.
10
- */
11
-
12
- /**
13
- * Twig_Node_SandboxedPrint adds a check for the __toString() method
14
- * when the variable is an object and the sandbox is activated.
15
- *
16
- * When there is a simple Print statement, like {{ article }},
17
- * and if the sandbox is enabled, we need to check that the __toString()
18
- * method is allowed if 'article' is an object.
19
- *
20
- * @author Fabien Potencier <fabien@symfony.com>
21
- */
22
- class Twig_Node_SandboxedPrint extends Twig_Node_Print
23
- {
24
- public function __construct(Twig_Node_Expression $expr, $lineno, $tag = null)
25
- {
26
- parent::__construct($expr, $lineno, $tag);
27
- }
28
-
29
- /**
30
- * Compiles the node to PHP.
31
- *
32
- * @param Twig_Compiler A Twig_Compiler instance
33
- */
34
- public function compile(Twig_Compiler $compiler)
35
- {
36
- $compiler
37
- ->addDebugInfo($this)
38
- ->write('echo $this->env->getExtension(\'sandbox\')->ensureToStringAllowed(')
39
- ->subcompile($this->getNode('expr'))
40
- ->raw(");\n")
41
- ;
42
- }
43
-
44
- /**
45
- * Removes node filters.
46
- *
47
- * This is mostly needed when another visitor adds filters (like the escaper one).
48
- *
49
- * @param Twig_Node $node A Node
50
- */
51
- protected function removeNodeFilter($node)
52
- {
53
- if ($node instanceof Twig_Node_Expression_Filter) {
54
- return $this->removeNodeFilter($node->getNode('node'));
55
- }
56
-
57
- return $node;
58
- }
59
- }
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2010 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ /**
13
+ * Twig_Node_SandboxedPrint adds a check for the __toString() method
14
+ * when the variable is an object and the sandbox is activated.
15
+ *
16
+ * When there is a simple Print statement, like {{ article }},
17
+ * and if the sandbox is enabled, we need to check that the __toString()
18
+ * method is allowed if 'article' is an object.
19
+ *
20
+ * @author Fabien Potencier <fabien@symfony.com>
21
+ */
22
+ class Twig_Node_SandboxedPrint extends Twig_Node_Print
23
+ {
24
+ public function __construct(Twig_Node_Expression $expr, $lineno, $tag = null)
25
+ {
26
+ parent::__construct($expr, $lineno, $tag);
27
+ }
28
+
29
+ /**
30
+ * Compiles the node to PHP.
31
+ *
32
+ * @param Twig_Compiler A Twig_Compiler instance
33
+ */
34
+ public function compile(Twig_Compiler $compiler)
35
+ {
36
+ $compiler
37
+ ->addDebugInfo($this)
38
+ ->write('echo $this->env->getExtension(\'sandbox\')->ensureToStringAllowed(')
39
+ ->subcompile($this->getNode('expr'))
40
+ ->raw(");\n")
41
+ ;
42
+ }
43
+
44
+ /**
45
+ * Removes node filters.
46
+ *
47
+ * This is mostly needed when another visitor adds filters (like the escaper one).
48
+ *
49
+ * @param Twig_Node $node A Node
50
+ */
51
+ protected function removeNodeFilter($node)
52
+ {
53
+ if ($node instanceof Twig_Node_Expression_Filter) {
54
+ return $this->removeNodeFilter($node->getNode('node'));
55
+ }
56
+
57
+ return $node;
58
+ }
59
+ }
classes/Twig/Node/Set.php CHANGED
@@ -1,101 +1,101 @@
1
- <?php
2
-
3
- /*
4
- * This file is part of Twig.
5
- *
6
- * (c) 2010 Fabien Potencier
7
- *
8
- * For the full copyright and license information, please view the LICENSE
9
- * file that was distributed with this source code.
10
- */
11
-
12
- /**
13
- * Represents a set node.
14
- *
15
- * @author Fabien Potencier <fabien@symfony.com>
16
- */
17
- class Twig_Node_Set extends Twig_Node
18
- {
19
- public function __construct($capture, Twig_NodeInterface $names, Twig_NodeInterface $values, $lineno, $tag = null)
20
- {
21
- parent::__construct(array('names' => $names, 'values' => $values), array('capture' => $capture, 'safe' => false), $lineno, $tag);
22
-
23
- /*
24
- * Optimizes the node when capture is used for a large block of text.
25
- *
26
- * {% set foo %}foo{% endset %} is compiled to $context['foo'] = new Twig_Markup("foo");
27
- */
28
- if ($this->getAttribute('capture')) {
29
- $this->setAttribute('safe', true);
30
-
31
- $values = $this->getNode('values');
32
- if ($values instanceof Twig_Node_Text) {
33
- $this->setNode('values', new Twig_Node_Expression_Constant($values->getAttribute('data'), $values->getLine()));
34
- $this->setAttribute('capture', false);
35
- }
36
- }
37
- }
38
-
39
- /**
40
- * Compiles the node to PHP.
41
- *
42
- * @param Twig_Compiler A Twig_Compiler instance
43
- */
44
- public function compile(Twig_Compiler $compiler)
45
- {
46
- $compiler->addDebugInfo($this);
47
-
48
- if (count($this->getNode('names')) > 1) {
49
- $compiler->write('list(');
50
- foreach ($this->getNode('names') as $idx => $node) {
51
- if ($idx) {
52
- $compiler->raw(', ');
53
- }
54
-
55
- $compiler->subcompile($node);
56
- }
57
- $compiler->raw(')');
58
- } else {
59
- if ($this->getAttribute('capture')) {
60
- $compiler
61
- ->write("ob_start();\n")
62
- ->subcompile($this->getNode('values'))
63
- ;
64
- }
65
-
66
- $compiler->subcompile($this->getNode('names'), false);
67
-
68
- if ($this->getAttribute('capture')) {
69
- $compiler->raw(" = ('' === \$tmp = ob_get_clean()) ? '' : new Twig_Markup(\$tmp, \$this->env->getCharset())");
70
- }
71
- }
72
-
73
- if (!$this->getAttribute('capture')) {
74
- $compiler->raw(' = ');
75
-
76
- if (count($this->getNode('names')) > 1) {
77
- $compiler->write('array(');
78
- foreach ($this->getNode('values') as $idx => $value) {
79
- if ($idx) {
80
- $compiler->raw(', ');
81
- }
82
-
83
- $compiler->subcompile($value);
84
- }
85
- $compiler->raw(')');
86
- } else {
87
- if ($this->getAttribute('safe')) {
88
- $compiler
89
- ->raw("('' === \$tmp = ")
90
- ->subcompile($this->getNode('values'))
91
- ->raw(") ? '' : new Twig_Markup(\$tmp, \$this->env->getCharset())")
92
- ;
93
- } else {
94
- $compiler->subcompile($this->getNode('values'));
95
- }
96
- }
97
- }
98
-
99
- $compiler->raw(";\n");
100
- }
101
- }
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2010 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ /**
13
+ * Represents a set node.
14
+ *
15
+ * @author Fabien Potencier <fabien@symfony.com>
16
+ */
17
+ class Twig_Node_Set extends Twig_Node
18
+ {
19
+ public function __construct($capture, Twig_NodeInterface $names, Twig_NodeInterface $values, $lineno, $tag = null)
20
+ {
21
+ parent::__construct(array('names' => $names, 'values' => $values), array('capture' => $capture, 'safe' => false), $lineno, $tag);
22
+
23
+ /*
24
+ * Optimizes the node when capture is used for a large block of text.
25
+ *
26
+ * {% set foo %}foo{% endset %} is compiled to $context['foo'] = new Twig_Markup("foo");
27
+ */
28
+ if ($this->getAttribute('capture')) {
29
+ $this->setAttribute('safe', true);
30
+
31
+ $values = $this->getNode('values');
32
+ if ($values instanceof Twig_Node_Text) {
33
+ $this->setNode('values', new Twig_Node_Expression_Constant($values->getAttribute('data'), $values->getLine()));
34
+ $this->setAttribute('capture', false);
35
+ }
36
+ }
37
+ }
38
+
39
+ /**
40
+ * Compiles the node to PHP.
41
+ *
42
+ * @param Twig_Compiler A Twig_Compiler instance
43
+ */
44
+ public function compile(Twig_Compiler $compiler)
45
+ {
46
+ $compiler->addDebugInfo($this);
47
+
48
+ if (count($this->getNode('names')) > 1) {
49
+ $compiler->write('list(');
50
+ foreach ($this->getNode('names') as $idx => $node) {
51
+ if ($idx) {
52
+ $compiler->raw(', ');
53
+ }
54
+
55
+ $compiler->subcompile($node);
56
+ }
57
+ $compiler->raw(')');
58
+ } else {
59
+ if ($this->getAttribute('capture')) {
60
+ $compiler
61
+ ->write("ob_start();\n")
62
+ ->subcompile($this->getNode('values'))
63
+ ;
64
+ }
65
+
66
+ $compiler->subcompile($this->getNode('names'), false);
67
+
68
+ if ($this->getAttribute('capture')) {
69
+ $compiler->raw(" = ('' === \$tmp = ob_get_clean()) ? '' : new Twig_Markup(\$tmp, \$this->env->getCharset())");
70
+ }
71
+ }
72
+
73
+ if (!$this->getAttribute('capture')) {
74
+ $compiler->raw(' = ');
75
+
76
+ if (count($this->getNode('names')) > 1) {
77
+ $compiler->write('array(');
78
+ foreach ($this->getNode('values') as $idx => $value) {
79
+ if ($idx) {
80
+ $compiler->raw(', ');
81
+ }
82
+
83
+ $compiler->subcompile($value);
84
+ }
85
+ $compiler->raw(')');
86
+ } else {
87
+ if ($this->getAttribute('safe')) {
88
+ $compiler
89
+ ->raw("('' === \$tmp = ")
90
+ ->subcompile($this->getNode('values'))
91
+ ->raw(") ? '' : new Twig_Markup(\$tmp, \$this->env->getCharset())")
92
+ ;
93
+ } else {
94
+ $compiler->subcompile($this->getNode('values'));
95
+ }
96
+ }
97
+ }
98
+
99
+ $compiler->raw(";\n");
100
+ }
101
+ }
classes/Twig/Node/SetTemp.php CHANGED
@@ -1,35 +1,35 @@
1
- <?php
2
-
3
- /*
4
- * This file is part of Twig.
5
- *
6
- * (c) 2011 Fabien Potencier
7
- *
8
- * For the full copyright and license information, please view the LICENSE
9
- * file that was distributed with this source code.
10
- */
11
-
12
- class Twig_Node_SetTemp extends Twig_Node
13
- {
14
- public function __construct($name, $lineno)
15
- {
16
- parent::__construct(array(), array('name' => $name), $lineno);
17
- }
18
-
19
- public function compile(Twig_Compiler $compiler)
20
- {
21
- $name = $this->getAttribute('name');
22
- $compiler
23
- ->addDebugInfo($this)
24
- ->write('if (isset($context[')
25
- ->string($name)
26
- ->raw('])) { $_')
27
- ->raw($name)
28
- ->raw('_ = $context[')
29
- ->repr($name)
30
- ->raw(']; } else { $_')
31
- ->raw($name)
32
- ->raw("_ = null; }\n")
33
- ;
34
- }
35
- }
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2011 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ class Twig_Node_SetTemp extends Twig_Node
13
+ {
14
+ public function __construct($name, $lineno)
15
+ {
16
+ parent::__construct(array(), array('name' => $name), $lineno);
17
+ }
18
+
19
+ public function compile(Twig_Compiler $compiler)
20
+ {
21
+ $name = $this->getAttribute('name');
22
+ $compiler
23
+ ->addDebugInfo($this)
24
+ ->write('if (isset($context[')
25
+ ->string($name)
26
+ ->raw('])) { $_')
27
+ ->raw($name)
28
+ ->raw('_ = $context[')
29
+ ->repr($name)
30
+ ->raw(']; } else { $_')
31
+ ->raw($name)
32
+ ->raw("_ = null; }\n")
33
+ ;
34
+ }
35
+ }
classes/Twig/Node/Spaceless.php CHANGED
@@ -1,40 +1,40 @@
1
- <?php
2
-
3
- /*
4
- * This file is part of Twig.
5
- *
6
- * (c) 2010 Fabien Potencier
7
- *
8
- * For the full copyright and license information, please view the LICENSE
9
- * file that was distributed with this source code.
10
- */
11
-
12
- /**
13
- * Represents a spaceless node.
14
- *
15
- * It removes spaces between HTML tags.
16
- *
17
- * @author Fabien Potencier <fabien@symfony.com>
18
- */
19
- class Twig_Node_Spaceless extends Twig_Node
20
- {
21
- public function __construct(Twig_NodeInterface $body, $lineno, $tag = 'spaceless')
22
- {
23
- parent::__construct(array('body' => $body), array(), $lineno, $tag);
24
- }
25
-
26
- /**
27
- * Compiles the node to PHP.
28
- *
29
- * @param Twig_Compiler A Twig_Compiler instance
30
- */
31
- public function compile(Twig_Compiler $compiler)
32
- {
33
- $compiler
34
- ->addDebugInfo($this)
35
- ->write("ob_start();\n")
36
- ->subcompile($this->getNode('body'))
37
- ->write("echo trim(preg_replace('/>\s+</', '><', ob_get_clean()));\n")
38
- ;
39
- }
40
- }
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2010 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ /**
13
+ * Represents a spaceless node.
14
+ *
15
+ * It removes spaces between HTML tags.
16
+ *
17
+ * @author Fabien Potencier <fabien@symfony.com>
18
+ */
19
+ class Twig_Node_Spaceless extends Twig_Node
20
+ {
21
+ public function __construct(Twig_NodeInterface $body, $lineno, $tag = 'spaceless')
22
+ {
23
+ parent::__construct(array('body' => $body), array(), $lineno, $tag);
24
+ }
25
+
26
+ /**
27
+ * Compiles the node to PHP.
28
+ *
29
+ * @param Twig_Compiler A Twig_Compiler instance
30
+ */
31
+ public function compile(Twig_Compiler $compiler)
32
+ {
33
+ $compiler
34
+ ->addDebugInfo($this)
35
+ ->write("ob_start();\n")
36
+ ->subcompile($this->getNode('body'))
37
+ ->write("echo trim(preg_replace('/>\s+</', '><', ob_get_clean()));\n")
38
+ ;
39
+ }
40
+ }
classes/Twig/Node/Text.php CHANGED
@@ -1,39 +1,39 @@
1
- <?php
2
-
3
- /*
4
- * This file is part of Twig.
5
- *
6
- * (c) 2009 Fabien Potencier
7
- * (c) 2009 Armin Ronacher
8
- *
9
- * For the full copyright and license information, please view the LICENSE
10
- * file that was distributed with this source code.
11
- */
12
-
13
- /**
14
- * Represents a text node.
15
- *
16
- * @author Fabien Potencier <fabien@symfony.com>
17
- */
18
- class Twig_Node_Text extends Twig_Node implements Twig_NodeOutputInterface
19
- {
20
- public function __construct($data, $lineno)
21
- {
22
- parent::__construct(array(), array('data' => $data), $lineno);
23
- }
24
-
25
- /**
26
- * Compiles the node to PHP.
27
- *
28
- * @param Twig_Compiler A Twig_Compiler instance
29
- */
30
- public function compile(Twig_Compiler $compiler)
31
- {
32
- $compiler
33
- ->addDebugInfo($this)
34
- ->write('echo ')
35
- ->string($this->getAttribute('data'))
36
- ->raw(";\n")
37
- ;
38
- }
39
- }
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2009 Fabien Potencier
7
+ * (c) 2009 Armin Ronacher
8
+ *
9
+ * For the full copyright and license information, please view the LICENSE
10
+ * file that was distributed with this source code.
11
+ */
12
+
13
+ /**
14
+ * Represents a text node.
15
+ *
16
+ * @author Fabien Potencier <fabien@symfony.com>
17
+ */
18
+ class Twig_Node_Text extends Twig_Node implements Twig_NodeOutputInterface
19
+ {
20
+ public function __construct($data, $lineno)
21
+ {
22
+ parent::__construct(array(), array('data' => $data), $lineno);
23
+ }
24
+
25
+ /**
26
+ * Compiles the node to PHP.
27
+ *
28
+ * @param Twig_Compiler A Twig_Compiler instance
29
+ */
30
+ public function compile(Twig_Compiler $compiler)
31
+ {
32
+ $compiler
33
+ ->addDebugInfo($this)
34
+ ->write('echo ')
35
+ ->string($this->getAttribute('data'))
36
+ ->raw(";\n")
37
+ ;
38
+ }
39
+ }
classes/Twig/NodeInterface.php CHANGED
@@ -1,31 +1,31 @@
1
- <?php
2
-
3
- /*
4
- * This file is part of Twig.
5
- *
6
- * (c) 2010 Fabien Potencier
7
- *
8
- * For the full copyright and license information, please view the LICENSE
9
- * file that was distributed with this source code.
10
- */
11
-
12
- /**
13
- * Represents a node in the AST.
14
- *
15
- * @author Fabien Potencier <fabien@symfony.com>
16
- *
17
- * @deprecated since 1.12 (to be removed in 3.0)
18
- */
19
- interface Twig_NodeInterface extends Countable, IteratorAggregate
20
- {
21
- /**
22
- * Compiles the node to PHP.
23
- *
24
- * @param Twig_Compiler A Twig_Compiler instance
25
- */
26
- public function compile(Twig_Compiler $compiler);
27
-
28
- public function getLine();
29
-
30
- public function getNodeTag();
31
- }
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2010 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ /**
13
+ * Represents a node in the AST.
14
+ *
15
+ * @author Fabien Potencier <fabien@symfony.com>
16
+ *
17
+ * @deprecated since 1.12 (to be removed in 3.0)
18
+ */
19
+ interface Twig_NodeInterface extends Countable, IteratorAggregate
20
+ {
21
+ /**
22
+ * Compiles the node to PHP.
23
+ *
24
+ * @param Twig_Compiler A Twig_Compiler instance
25
+ */
26
+ public function compile(Twig_Compiler $compiler);
27
+
28
+ public function getLine();
29
+
30
+ public function getNodeTag();
31
+ }
classes/Twig/NodeOutputInterface.php CHANGED
@@ -1,19 +1,19 @@
1
- <?php
2
-
3
- /*
4
- * This file is part of Twig.
5
- *
6
- * (c) 2010 Fabien Potencier
7
- *
8
- * For the full copyright and license information, please view the LICENSE
9
- * file that was distributed with this source code.
10
- */
11
-
12
- /**
13
- * Represents a displayable node in the AST.
14
- *
15
- * @author Fabien Potencier <fabien@symfony.com>
16
- */
17
- interface Twig_NodeOutputInterface
18
- {
19
- }
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2010 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ /**
13
+ * Represents a displayable node in the AST.
14
+ *
15
+ * @author Fabien Potencier <fabien@symfony.com>
16
+ */
17
+ interface Twig_NodeOutputInterface
18
+ {
19
+ }
classes/Twig/NodeTraverser.php CHANGED
@@ -1,88 +1,88 @@
1
- <?php
2
-
3
- /*
4
- * This file is part of Twig.
5
- *
6
- * (c) 2009 Fabien Potencier
7
- *
8
- * For the full copyright and license information, please view the LICENSE
9
- * file that was distributed with this source code.
10
- */
11
-
12
- /**
13
- * Twig_NodeTraverser is a node traverser.
14
- *
15
- * It visits all nodes and their children and calls the given visitor for each.
16
- *
17
- * @author Fabien Potencier <fabien@symfony.com>
18
- */
19
- class Twig_NodeTraverser
20
- {
21
- protected $env;
22
- protected $visitors;
23
-
24
- /**
25
- * Constructor.
26
- *
27
- * @param Twig_Environment $env A Twig_Environment instance
28
- * @param Twig_NodeVisitorInterface[] $visitors An array of Twig_NodeVisitorInterface instances
29
- */
30
- public function __construct(Twig_Environment $env, array $visitors = array())
31
- {
32
- $this->env = $env;
33
- $this->visitors = array();
34
- foreach ($visitors as $visitor) {
35
- $this->addVisitor($visitor);
36
- }
37
- }
38
-
39
- /**
40
- * Adds a visitor.
41
- *
42
- * @param Twig_NodeVisitorInterface $visitor A Twig_NodeVisitorInterface instance
43
- */
44
- public function addVisitor(Twig_NodeVisitorInterface $visitor)
45
- {
46
- if (!isset($this->visitors[$visitor->getPriority()])) {
47
- $this->visitors[$visitor->getPriority()] = array();
48
- }
49
-
50
- $this->visitors[$visitor->getPriority()][] = $visitor;
51
- }
52
-
53
- /**
54
- * Traverses a node and calls the registered visitors.
55
- *
56
- * @param Twig_NodeInterface $node A Twig_NodeInterface instance
57
- */
58
- public function traverse(Twig_NodeInterface $node)
59
- {
60
- ksort($this->visitors);
61
- foreach ($this->visitors as $visitors) {
62
- foreach ($visitors as $visitor) {
63
- $node = $this->traverseForVisitor($visitor, $node);
64
- }
65
- }
66
-
67
- return $node;
68
- }
69
-
70
- protected function traverseForVisitor(Twig_NodeVisitorInterface $visitor, Twig_NodeInterface $node = null)
71
- {
72
- if (null === $node) {
73
- return;
74
- }
75
-
76
- $node = $visitor->enterNode($node, $this->env);
77
-
78
- foreach ($node as $k => $n) {
79
- if (false !== $n = $this->traverseForVisitor($visitor, $n)) {
80
- $node->setNode($k, $n);
81
- } else {
82
- $node->removeNode($k);
83
- }
84
- }
85
-
86
- return $visitor->leaveNode($node, $this->env);
87
- }
88
- }
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2009 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ /**
13
+ * Twig_NodeTraverser is a node traverser.
14
+ *
15
+ * It visits all nodes and their children and calls the given visitor for each.
16
+ *
17
+ * @author Fabien Potencier <fabien@symfony.com>
18
+ */
19
+ class Twig_NodeTraverser
20
+ {
21
+ protected $env;
22
+ protected $visitors;
23
+
24
+ /**
25
+ * Constructor.
26
+ *
27
+ * @param Twig_Environment $env A Twig_Environment instance
28
+ * @param Twig_NodeVisitorInterface[] $visitors An array of Twig_NodeVisitorInterface instances
29
+ */
30
+ public function __construct(Twig_Environment $env, array $visitors = array())
31
+ {
32
+ $this->env = $env;
33
+ $this->visitors = array();
34
+ foreach ($visitors as $visitor) {
35
+ $this->addVisitor($visitor);
36
+ }
37
+ }
38
+
39
+ /**
40
+ * Adds a visitor.
41
+ *
42
+ * @param Twig_NodeVisitorInterface $visitor A Twig_NodeVisitorInterface instance
43
+ */
44
+ public function addVisitor(Twig_NodeVisitorInterface $visitor)
45
+ {
46
+ if (!isset($this->visitors[$visitor->getPriority()])) {
47
+ $this->visitors[$visitor->getPriority()] = array();
48
+ }
49
+
50
+ $this->visitors[$visitor->getPriority()][] = $visitor;
51
+ }
52
+
53
+ /**
54
+ * Traverses a node and calls the registered visitors.
55
+ *
56
+ * @param Twig_NodeInterface $node A Twig_NodeInterface instance
57
+ */
58
+ public function traverse(Twig_NodeInterface $node)
59
+ {
60
+ ksort($this->visitors);
61
+ foreach ($this->visitors as $visitors) {
62
+ foreach ($visitors as $visitor) {
63
+ $node = $this->traverseForVisitor($visitor, $node);
64
+ }
65
+ }
66
+
67
+ return $node;
68
+ }
69
+
70
+ protected function traverseForVisitor(Twig_NodeVisitorInterface $visitor, Twig_NodeInterface $node = null)
71
+ {
72
+ if (null === $node) {
73
+ return;
74
+ }
75
+
76
+ $node = $visitor->enterNode($node, $this->env);
77
+
78
+ foreach ($node as $k => $n) {
79
+ if (false !== $n = $this->traverseForVisitor($visitor, $n)) {
80
+ $node->setNode($k, $n);
81
+ } else {
82
+ $node->removeNode($k);
83
+ }
84
+ }
85
+
86
+ return $visitor->leaveNode($node, $this->env);
87
+ }
88
+ }
classes/Twig/NodeVisitor/Escaper.php CHANGED
@@ -1,167 +1,167 @@
1
- <?php
2
-
3
- /*
4
- * This file is part of Twig.
5
- *
6
- * (c) 2009 Fabien Potencier
7
- *
8
- * For the full copyright and license information, please view the LICENSE
9
- * file that was distributed with this source code.
10
- */
11
-
12
- /**
13
- * Twig_NodeVisitor_Escaper implements output escaping.
14
- *
15
- * @author Fabien Potencier <fabien@symfony.com>
16
- */
17
- class Twig_NodeVisitor_Escaper implements Twig_NodeVisitorInterface
18
- {
19
- protected $statusStack = array();
20
- protected $blocks = array();
21
- protected $safeAnalysis;
22
- protected $traverser;
23
- protected $defaultStrategy = false;
24
- protected $safeVars = array();
25
-
26
- public function __construct()
27
- {
28
- $this->safeAnalysis = new Twig_NodeVisitor_SafeAnalysis();
29
- }
30
-
31
- /**
32
- * Called before child nodes are visited.
33
- *
34
- * @param Twig_NodeInterface $node The node to visit
35
- * @param Twig_Environment $env The Twig environment instance
36
- *
37
- * @return Twig_NodeInterface The modified node
38
- */
39
- public function enterNode(Twig_NodeInterface $node, Twig_Environment $env)
40
- {
41
- if ($node instanceof Twig_Node_Module) {
42
- if ($env->hasExtension('escaper') && $defaultStrategy = $env->getExtension('escaper')->getDefaultStrategy($node->getAttribute('filename'))) {
43
- $this->defaultStrategy = $defaultStrategy;
44
- }
45
- $this->safeVars = array();
46
- } elseif ($node instanceof Twig_Node_AutoEscape) {
47
- $this->statusStack[] = $node->getAttribute('value');
48
- } elseif ($node instanceof Twig_Node_Block) {
49
- $this->statusStack[] = isset($this->blocks[$node->getAttribute('name')]) ? $this->blocks[$node->getAttribute('name')] : $this->needEscaping($env);
50
- } elseif ($node instanceof Twig_Node_Import) {
51
- $this->safeVars[] = $node->getNode('var')->getAttribute('name');
52
- }
53
-
54
- return $node;
55
- }
56
-
57
- /**
58
- * Called after child nodes are visited.
59
- *
60
- * @param Twig_NodeInterface $node The node to visit
61
- * @param Twig_Environment $env The Twig environment instance
62
- *
63
- * @return Twig_NodeInterface The modified node
64
- */
65
- public function leaveNode(Twig_NodeInterface $node, Twig_Environment $env)
66
- {
67
- if ($node instanceof Twig_Node_Module) {
68
- $this->defaultStrategy = false;
69
- $this->safeVars = array();
70
- } elseif ($node instanceof Twig_Node_Expression_Filter) {
71
- return $this->preEscapeFilterNode($node, $env);
72
- } elseif ($node instanceof Twig_Node_Print) {
73
- return $this->escapePrintNode($node, $env, $this->needEscaping($env));
74
- }
75
-
76
- if ($node instanceof Twig_Node_AutoEscape || $node instanceof Twig_Node_Block) {
77
- array_pop($this->statusStack);
78
- } elseif ($node instanceof Twig_Node_BlockReference) {
79
- $this->blocks[$node->getAttribute('name')] = $this->needEscaping($env);
80
- }
81
-
82
- return $node;
83
- }
84
-
85
- protected function escapePrintNode(Twig_Node_Print $node, Twig_Environment $env, $type)
86
- {
87
- if (false === $type) {
88
- return $node;
89
- }
90
-
91
- $expression = $node->getNode('expr');
92
-
93
- if ($this->isSafeFor($type, $expression, $env)) {
94
- return $node;
95
- }
96
-
97
- $class = get_class($node);
98
-
99
- return new $class(
100
- $this->getEscaperFilter($type, $expression),
101
- $node->getLine()
102
- );
103
- }
104
-
105
- protected function preEscapeFilterNode(Twig_Node_Expression_Filter $filter, Twig_Environment $env)
106
- {
107
- $name = $filter->getNode('filter')->getAttribute('value');
108
-
109
- $type = $env->getFilter($name)->getPreEscape();
110
- if (null === $type) {
111
- return $filter;
112
- }
113
-
114
- $node = $filter->getNode('node');
115
- if ($this->isSafeFor($type, $node, $env)) {
116
- return $filter;
117
- }
118
-
119
- $filter->setNode('node', $this->getEscaperFilter($type, $node));
120
-
121
- return $filter;
122
- }
123
-
124
- protected function isSafeFor($type, Twig_NodeInterface $expression, $env)
125
- {
126
- $safe = $this->safeAnalysis->getSafe($expression);
127
-
128
- if (null === $safe) {
129
- if (null === $this->traverser) {
130
- $this->traverser = new Twig_NodeTraverser($env, array($this->safeAnalysis));
131
- }
132
-
133
- $this->safeAnalysis->setSafeVars($this->safeVars);
134
-
135
- $this->traverser->traverse($expression);
136
- $safe = $this->safeAnalysis->getSafe($expression);
137
- }
138
-
139
- return in_array($type, $safe) || in_array('all', $safe);
140
- }
141
-
142
- protected function needEscaping(Twig_Environment $env)
143
- {
144
- if (count($this->statusStack)) {
145
- return $this->statusStack[count($this->statusStack) - 1];
146
- }
147
-
148
- return $this->defaultStrategy ? $this->defaultStrategy : false;
149
- }
150
-
151
- protected function getEscaperFilter($type, Twig_NodeInterface $node)
152
- {
153
- $line = $node->getLine();
154
- $name = new Twig_Node_Expression_Constant('escape', $line);
155
- $args = new Twig_Node(array(new Twig_Node_Expression_Constant((string) $type, $line), new Twig_Node_Expression_Constant(null, $line), new Twig_Node_Expression_Constant(true, $line)));
156
-
157
- return new Twig_Node_Expression_Filter($node, $name, $args, $line);
158
- }
159
-
160
- /**
161
- * {@inheritdoc}
162
- */
163
- public function getPriority()
164
- {
165
- return 0;
166
- }
167
- }
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2009 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ /**
13
+ * Twig_NodeVisitor_Escaper implements output escaping.
14
+ *
15
+ * @author Fabien Potencier <fabien@symfony.com>
16
+ */
17
+ class Twig_NodeVisitor_Escaper implements Twig_NodeVisitorInterface
18
+ {
19
+ protected $statusStack = array();
20
+ protected $blocks = array();
21
+ protected $safeAnalysis;
22
+ protected $traverser;
23
+ protected $defaultStrategy = false;
24
+ protected $safeVars = array();
25
+
26
+ public function __construct()
27
+ {
28
+ $this->safeAnalysis = new Twig_NodeVisitor_SafeAnalysis();
29
+ }
30
+
31
+ /**
32
+ * Called before child nodes are visited.
33
+ *
34
+ * @param Twig_NodeInterface $node The node to visit
35
+ * @param Twig_Environment $env The Twig environment instance
36
+ *
37
+ * @return Twig_NodeInterface The modified node
38
+ */
39
+ public function enterNode(Twig_NodeInterface $node, Twig_Environment $env)
40
+ {
41
+ if ($node instanceof Twig_Node_Module) {
42
+ if ($env->hasExtension('escaper') && $defaultStrategy = $env->getExtension('escaper')->getDefaultStrategy($node->getAttribute('filename'))) {
43
+ $this->defaultStrategy = $defaultStrategy;
44
+ }
45
+ $this->safeVars = array();
46
+ } elseif ($node instanceof Twig_Node_AutoEscape) {
47
+ $this->statusStack[] = $node->getAttribute('value');
48
+ } elseif ($node instanceof Twig_Node_Block) {
49
+ $this->statusStack[] = isset($this->blocks[$node->getAttribute('name')]) ? $this->blocks[$node->getAttribute('name')] : $this->needEscaping($env);
50
+ } elseif ($node instanceof Twig_Node_Import) {
51
+ $this->safeVars[] = $node->getNode('var')->getAttribute('name');
52
+ }
53
+
54
+ return $node;
55
+ }
56
+
57
+ /**
58
+ * Called after child nodes are visited.
59
+ *
60
+ * @param Twig_NodeInterface $node The node to visit
61
+ * @param Twig_Environment $env The Twig environment instance
62
+ *
63
+ * @return Twig_NodeInterface The modified node
64
+ */
65
+ public function leaveNode(Twig_NodeInterface $node, Twig_Environment $env)
66
+ {
67
+ if ($node instanceof Twig_Node_Module) {
68
+ $this->defaultStrategy = false;
69
+ $this->safeVars = array();
70
+ } elseif ($node instanceof Twig_Node_Expression_Filter) {
71
+ return $this->preEscapeFilterNode($node, $env);
72
+ } elseif ($node instanceof Twig_Node_Print) {
73
+ return $this->escapePrintNode($node, $env, $this->needEscaping($env));
74
+ }
75
+
76
+ if ($node instanceof Twig_Node_AutoEscape || $node instanceof Twig_Node_Block) {
77
+ array_pop($this->statusStack);
78
+ } elseif ($node instanceof Twig_Node_BlockReference) {
79
+ $this->blocks[$node->getAttribute('name')] = $this->needEscaping($env);
80
+ }
81
+
82
+ return $node;
83
+ }
84
+
85
+ protected function escapePrintNode(Twig_Node_Print $node, Twig_Environment $env, $type)
86
+ {
87
+ if (false === $type) {
88
+ return $node;
89
+ }
90
+
91
+ $expression = $node->getNode('expr');
92
+
93
+ if ($this->isSafeFor($type, $expression, $env)) {
94
+ return $node;
95
+ }
96
+
97
+ $class = get_class($node);
98
+
99
+ return new $class(
100
+ $this->getEscaperFilter($type, $expression),
101
+ $node->getLine()
102
+ );
103
+ }
104
+
105
+ protected function preEscapeFilterNode(Twig_Node_Expression_Filter $filter, Twig_Environment $env)
106
+ {
107
+ $name = $filter->getNode('filter')->getAttribute('value');
108
+
109
+ $type = $env->getFilter($name)->getPreEscape();
110
+ if (null === $type) {
111
+ return $filter;
112
+ }
113
+
114
+ $node = $filter->getNode('node');
115
+ if ($this->isSafeFor($type, $node, $env)) {
116
+ return $filter;
117
+ }
118
+
119
+ $filter->setNode('node', $this->getEscaperFilter($type, $node));
120
+
121
+ return $filter;
122
+ }
123
+
124
+ protected function isSafeFor($type, Twig_NodeInterface $expression, $env)
125
+ {
126
+ $safe = $this->safeAnalysis->getSafe($expression);
127
+
128
+ if (null === $safe) {
129
+ if (null === $this->traverser) {
130
+ $this->traverser = new Twig_NodeTraverser($env, array($this->safeAnalysis));
131
+ }
132
+
133
+ $this->safeAnalysis->setSafeVars($this->safeVars);
134
+
135
+ $this->traverser->traverse($expression);
136
+ $safe = $this->safeAnalysis->getSafe($expression);
137
+ }
138
+
139
+ return in_array($type, $safe) || in_array('all', $safe);
140
+ }
141
+
142
+ protected function needEscaping(Twig_Environment $env)
143
+ {
144
+ if (count($this->statusStack)) {
145
+ return $this->statusStack[count($this->statusStack) - 1];
146
+ }
147
+
148
+ return $this->defaultStrategy ? $this->defaultStrategy : false;
149
+ }
150
+
151
+ protected function getEscaperFilter($type, Twig_NodeInterface $node)
152
+ {
153
+ $line = $node->getLine();
154
+ $name = new Twig_Node_Expression_Constant('escape', $line);
155
+ $args = new Twig_Node(array(new Twig_Node_Expression_Constant((string) $type, $line), new Twig_Node_Expression_Constant(null, $line), new Twig_Node_Expression_Constant(true, $line)));
156
+
157
+ return new Twig_Node_Expression_Filter($node, $name, $args, $line);
158
+ }
159
+
160
+ /**
161
+ * {@inheritdoc}
162
+ */
163
+ public function getPriority()
164
+ {
165
+ return 0;
166
+ }
167
+ }
classes/Twig/NodeVisitor/Optimizer.php CHANGED
@@ -1,246 +1,246 @@
1
- <?php
2
-
3
- /*
4
- * This file is part of Twig.
5
- *
6
- * (c) 2010 Fabien Potencier
7
- *
8
- * For the full copyright and license information, please view the LICENSE
9
- * file that was distributed with this source code.
10
- */
11
-
12
- /**
13
- * Twig_NodeVisitor_Optimizer tries to optimizes the AST.
14
- *
15
- * This visitor is always the last registered one.
16
- *
17
- * You can configure which optimizations you want to activate via the
18
- * optimizer mode.
19
- *
20
- * @author Fabien Potencier <fabien@symfony.com>
21
- */
22
- class Twig_NodeVisitor_Optimizer implements Twig_NodeVisitorInterface
23
- {
24
- const OPTIMIZE_ALL = -1;
25
- const OPTIMIZE_NONE = 0;
26
- const OPTIMIZE_FOR = 2;
27
- const OPTIMIZE_RAW_FILTER = 4;
28
- const OPTIMIZE_VAR_ACCESS = 8;
29
-
30
- protected $loops = array();
31
- protected $optimizers;
32
- protected $prependedNodes = array();
33
- protected $inABody = false;
34
-
35
- /**
36
- * Constructor.
37
- *
38
- * @param int $optimizers The optimizer mode
39
- */
40
- public function __construct($optimizers = -1)
41
- {
42
- if (!is_int($optimizers) || $optimizers > (self::OPTIMIZE_FOR | self::OPTIMIZE_RAW_FILTER | self::OPTIMIZE_VAR_ACCESS)) {
43
- throw new InvalidArgumentException(sprintf('Optimizer mode "%s" is not valid.', $optimizers));
44
- }
45
-
46
- $this->optimizers = $optimizers;
47
- }
48
-
49
- /**
50
- * {@inheritdoc}
51
- */
52
- public function enterNode(Twig_NodeInterface $node, Twig_Environment $env)
53
- {
54
- if (self::OPTIMIZE_FOR === (self::OPTIMIZE_FOR & $this->optimizers)) {
55
- $this->enterOptimizeFor($node, $env);
56
- }
57
-
58
- if (!version_compare(phpversion(), '5.4.0RC1', '>=') && self::OPTIMIZE_VAR_ACCESS === (self::OPTIMIZE_VAR_ACCESS & $this->optimizers) && !$env->isStrictVariables() && !$env->hasExtension('sandbox')) {
59
- if ($this->inABody) {
60
- if (!$node instanceof Twig_Node_Expression) {
61
- if (get_class($node) !== 'Twig_Node') {
62
- array_unshift($this->prependedNodes, array());
63
- }
64
- } else {
65
- $node = $this->optimizeVariables($node, $env);
66
- }
67
- } elseif ($node instanceof Twig_Node_Body) {
68
- $this->inABody = true;
69
- }
70
- }
71
-
72
- return $node;
73
- }
74
-
75
- /**
76
- * {@inheritdoc}
77
- */
78
- public function leaveNode(Twig_NodeInterface $node, Twig_Environment $env)
79
- {
80
- $expression = $node instanceof Twig_Node_Expression;
81
-
82
- if (self::OPTIMIZE_FOR === (self::OPTIMIZE_FOR & $this->optimizers)) {
83
- $this->leaveOptimizeFor($node, $env);
84
- }
85
-
86
- if (self::OPTIMIZE_RAW_FILTER === (self::OPTIMIZE_RAW_FILTER & $this->optimizers)) {
87
- $node = $this->optimizeRawFilter($node, $env);
88
- }
89
-
90
- $node = $this->optimizePrintNode($node, $env);
91
-
92
- if (self::OPTIMIZE_VAR_ACCESS === (self::OPTIMIZE_VAR_ACCESS & $this->optimizers) && !$env->isStrictVariables() && !$env->hasExtension('sandbox')) {
93
- if ($node instanceof Twig_Node_Body) {
94
- $this->inABody = false;
95
- } elseif ($this->inABody) {
96
- if (!$expression && get_class($node) !== 'Twig_Node' && $prependedNodes = array_shift($this->prependedNodes)) {
97
- $nodes = array();
98
- foreach (array_unique($prependedNodes) as $name) {
99
- $nodes[] = new Twig_Node_SetTemp($name, $node->getLine());
100
- }
101
-
102
- $nodes[] = $node;
103
- $node = new Twig_Node($nodes);
104
- }
105
- }
106
- }
107
-
108
- return $node;
109
- }
110
-
111
- protected function optimizeVariables(Twig_NodeInterface $node, Twig_Environment $env)
112
- {
113
- if ('Twig_Node_Expression_Name' === get_class($node) && $node->isSimple()) {
114
- $this->prependedNodes[0][] = $node->getAttribute('name');
115
-
116
- return new Twig_Node_Expression_TempName($node->getAttribute('name'), $node->getLine());
117
- }
118
-
119
- return $node;
120
- }
121
-
122
- /**
123
- * Optimizes print nodes.
124
- *
125
- * It replaces:
126
- *
127
- * * "echo $this->render(Parent)Block()" with "$this->display(Parent)Block()"
128
- *
129
- * @param Twig_NodeInterface $node A Node
130
- * @param Twig_Environment $env The current Twig environment
131
- */
132
- protected function optimizePrintNode(Twig_NodeInterface $node, Twig_Environment $env)
133
- {
134
- if (!$node instanceof Twig_Node_Print) {
135
- return $node;
136
- }
137
-
138
- if (
139
- $node->getNode('expr') instanceof Twig_Node_Expression_BlockReference ||
140
- $node->getNode('expr') instanceof Twig_Node_Expression_Parent
141
- ) {
142
- $node->getNode('expr')->setAttribute('output', true);
143
-
144
- return $node->getNode('expr');
145
- }
146
-
147
- return $node;
148
- }
149
-
150
- /**
151
- * Removes "raw" filters.
152
- *
153
- * @param Twig_NodeInterface $node A Node
154
- * @param Twig_Environment $env The current Twig environment
155
- */
156
- protected function optimizeRawFilter(Twig_NodeInterface $node, Twig_Environment $env)
157
- {
158
- if ($node instanceof Twig_Node_Expression_Filter && 'raw' == $node->getNode('filter')->getAttribute('value')) {
159
- return $node->getNode('node');
160
- }
161
-
162
- return $node;
163
- }
164
-
165
- /**
166
- * Optimizes "for" tag by removing the "loop" variable creation whenever possible.
167
- *
168
- * @param Twig_NodeInterface $node A Node
169
- * @param Twig_Environment $env The current Twig environment
170
- */
171
- protected function enterOptimizeFor(Twig_NodeInterface $node, Twig_Environment $env)
172
- {
173
- if ($node instanceof Twig_Node_For) {
174
- // disable the loop variable by default
175
- $node->setAttribute('with_loop', false);
176
- array_unshift($this->loops, $node);
177
- } elseif (!$this->loops) {
178
- // we are outside a loop
179
- return;
180
- }
181
-
182
- // when do we need to add the loop variable back?
183
-
184
- // the loop variable is referenced for the current loop
185
- elseif ($node instanceof Twig_Node_Expression_Name && 'loop' === $node->getAttribute('name')) {
186
- $this->addLoopToCurrent();
187
- }
188
-
189
- // block reference
190
- elseif ($node instanceof Twig_Node_BlockReference || $node instanceof Twig_Node_Expression_BlockReference) {
191
- $this->addLoopToCurrent();
192
- }
193
-
194
- // include without the only attribute
195
- elseif ($node instanceof Twig_Node_Include && !$node->getAttribute('only')) {
196
- $this->addLoopToAll();
197
- }
198
-
199
- // the loop variable is referenced via an attribute
200
- elseif ($node instanceof Twig_Node_Expression_GetAttr
201
- && (!$node->getNode('attribute') instanceof Twig_Node_Expression_Constant
202
- || 'parent' === $node->getNode('attribute')->getAttribute('value')
203
- )
204
- && (true === $this->loops[0]->getAttribute('with_loop')
205
- || ($node->getNode('node') instanceof Twig_Node_Expression_Name
206
- && 'loop' === $node->getNode('node')->getAttribute('name')
207
- )
208
- )
209
- ) {
210
- $this->addLoopToAll();
211
- }
212
- }
213
-
214
- /**
215
- * Optimizes "for" tag by removing the "loop" variable creation whenever possible.
216
- *
217
- * @param Twig_NodeInterface $node A Node
218
- * @param Twig_Environment $env The current Twig environment
219
- */
220
- protected function leaveOptimizeFor(Twig_NodeInterface $node, Twig_Environment $env)
221
- {
222
- if ($node instanceof Twig_Node_For) {
223
- array_shift($this->loops);
224
- }
225
- }
226
-
227
- protected function addLoopToCurrent()
228
- {
229
- $this->loops[0]->setAttribute('with_loop', true);
230
- }
231
-
232
- protected function addLoopToAll()
233
- {
234
- foreach ($this->loops as $loop) {
235
- $loop->setAttribute('with_loop', true);
236
- }
237
- }
238
-
239
- /**
240
- * {@inheritdoc}
241
- */
242
- public function getPriority()
243
- {
244
- return 255;
245
- }
246
- }
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2010 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ /**
13
+ * Twig_NodeVisitor_Optimizer tries to optimizes the AST.
14
+ *
15
+ * This visitor is always the last registered one.
16
+ *
17
+ * You can configure which optimizations you want to activate via the
18
+ * optimizer mode.
19
+ *
20
+ * @author Fabien Potencier <fabien@symfony.com>
21
+ */
22
+ class Twig_NodeVisitor_Optimizer implements Twig_NodeVisitorInterface
23
+ {
24
+ const OPTIMIZE_ALL = -1;
25
+ const OPTIMIZE_NONE = 0;
26
+ const OPTIMIZE_FOR = 2;
27
+ const OPTIMIZE_RAW_FILTER = 4;
28
+ const OPTIMIZE_VAR_ACCESS = 8;
29
+
30
+ protected $loops = array();
31
+ protected $optimizers;
32
+ protected $prependedNodes = array();
33
+ protected $inABody = false;
34
+
35
+ /**
36
+ * Constructor.
37
+ *
38
+ * @param int $optimizers The optimizer mode
39
+ */
40
+ public function __construct($optimizers = -1)
41
+ {
42
+ if (!is_int($optimizers) || $optimizers > (self::OPTIMIZE_FOR | self::OPTIMIZE_RAW_FILTER | self::OPTIMIZE_VAR_ACCESS)) {
43
+ throw new InvalidArgumentException(sprintf('Optimizer mode "%s" is not valid.', $optimizers));
44
+ }
45
+
46
+ $this->optimizers = $optimizers;
47
+ }
48
+
49
+ /**
50
+ * {@inheritdoc}
51
+ */
52
+ public function enterNode(Twig_NodeInterface $node, Twig_Environment $env)
53
+ {
54
+ if (self::OPTIMIZE_FOR === (self::OPTIMIZE_FOR & $this->optimizers)) {
55
+ $this->enterOptimizeFor($node, $env);
56
+ }
57
+
58
+ if (!version_compare(phpversion(), '5.4.0RC1', '>=') && self::OPTIMIZE_VAR_ACCESS === (self::OPTIMIZE_VAR_ACCESS & $this->optimizers) && !$env->isStrictVariables() && !$env->hasExtension('sandbox')) {
59
+ if ($this->inABody) {
60
+ if (!$node instanceof Twig_Node_Expression) {
61
+ if (get_class($node) !== 'Twig_Node') {
62
+ array_unshift($this->prependedNodes, array());
63
+ }
64
+ } else {
65
+ $node = $this->optimizeVariables($node, $env);
66
+ }
67
+ } elseif ($node instanceof Twig_Node_Body) {
68
+ $this->inABody = true;
69
+ }
70
+ }
71
+
72
+ return $node;
73
+ }
74
+
75
+ /**
76
+ * {@inheritdoc}
77
+ */
78
+ public function leaveNode(Twig_NodeInterface $node, Twig_Environment $env)
79
+ {
80
+ $expression = $node instanceof Twig_Node_Expression;
81
+
82
+ if (self::OPTIMIZE_FOR === (self::OPTIMIZE_FOR & $this->optimizers)) {
83
+ $this->leaveOptimizeFor($node, $env);
84
+ }
85
+
86
+ if (self::OPTIMIZE_RAW_FILTER === (self::OPTIMIZE_RAW_FILTER & $this->optimizers)) {
87
+ $node = $this->optimizeRawFilter($node, $env);
88
+ }
89
+
90
+ $node = $this->optimizePrintNode($node, $env);
91
+
92
+ if (self::OPTIMIZE_VAR_ACCESS === (self::OPTIMIZE_VAR_ACCESS & $this->optimizers) && !$env->isStrictVariables() && !$env->hasExtension('sandbox')) {
93
+ if ($node instanceof Twig_Node_Body) {
94
+ $this->inABody = false;
95
+ } elseif ($this->inABody) {
96
+ if (!$expression && get_class($node) !== 'Twig_Node' && $prependedNodes = array_shift($this->prependedNodes)) {
97
+ $nodes = array();
98
+ foreach (array_unique($prependedNodes) as $name) {
99
+ $nodes[] = new Twig_Node_SetTemp($name, $node->getLine());
100
+ }
101
+
102
+ $nodes[] = $node;
103
+ $node = new Twig_Node($nodes);
104
+ }
105
+ }
106
+ }
107
+
108
+ return $node;
109
+ }
110
+
111
+ protected function optimizeVariables(Twig_NodeInterface $node, Twig_Environment $env)
112
+ {
113
+ if ('Twig_Node_Expression_Name' === get_class($node) && $node->isSimple()) {
114
+ $this->prependedNodes[0][] = $node->getAttribute('name');
115
+
116
+ return new Twig_Node_Expression_TempName($node->getAttribute('name'), $node->getLine());
117
+ }
118
+
119
+ return $node;
120
+ }
121
+
122
+ /**
123
+ * Optimizes print nodes.
124
+ *
125
+ * It replaces:
126
+ *
127
+ * * "echo $this->render(Parent)Block()" with "$this->display(Parent)Block()"
128
+ *
129
+ * @param Twig_NodeInterface $node A Node
130
+ * @param Twig_Environment $env The current Twig environment
131
+ */
132
+ protected function optimizePrintNode(Twig_NodeInterface $node, Twig_Environment $env)
133
+ {
134
+ if (!$node instanceof Twig_Node_Print) {
135
+ return $node;
136
+ }
137
+
138
+ if (
139
+ $node->getNode('expr') instanceof Twig_Node_Expression_BlockReference ||
140
+ $node->getNode('expr') instanceof Twig_Node_Expression_Parent
141
+ ) {
142
+ $node->getNode('expr')->setAttribute('output', true);
143
+
144
+ return $node->getNode('expr');
145
+ }
146
+
147
+ return $node;
148
+ }
149
+
150
+ /**
151
+ * Removes "raw" filters.
152
+ *
153
+ * @param Twig_NodeInterface $node A Node
154
+ * @param Twig_Environment $env The current Twig environment
155
+ */
156
+ protected function optimizeRawFilter(Twig_NodeInterface $node, Twig_Environment $env)
157
+ {
158
+ if ($node instanceof Twig_Node_Expression_Filter && 'raw' == $node->getNode('filter')->getAttribute('value')) {
159
+ return $node->getNode('node');
160
+ }
161
+
162
+ return $node;
163
+ }
164
+
165
+ /**
166
+ * Optimizes "for" tag by removing the "loop" variable creation whenever possible.
167
+ *
168
+ * @param Twig_NodeInterface $node A Node
169
+ * @param Twig_Environment $env The current Twig environment
170
+ */
171
+ protected function enterOptimizeFor(Twig_NodeInterface $node, Twig_Environment $env)
172
+ {
173
+ if ($node instanceof Twig_Node_For) {
174
+ // disable the loop variable by default
175
+ $node->setAttribute('with_loop', false);
176
+ array_unshift($this->loops, $node);
177
+ } elseif (!$this->loops) {
178
+ // we are outside a loop
179
+ return;
180
+ }
181
+
182
+ // when do we need to add the loop variable back?
183
+
184
+ // the loop variable is referenced for the current loop
185
+ elseif ($node instanceof Twig_Node_Expression_Name && 'loop' === $node->getAttribute('name')) {
186
+ $this->addLoopToCurrent();
187
+ }
188
+
189
+ // block reference
190
+ elseif ($node instanceof Twig_Node_BlockReference || $node instanceof Twig_Node_Expression_BlockReference) {
191
+ $this->addLoopToCurrent();
192
+ }
193
+
194
+ // include without the only attribute
195
+ elseif ($node instanceof Twig_Node_Include && !$node->getAttribute('only')) {
196
+ $this->addLoopToAll();
197
+ }
198
+
199
+ // the loop variable is referenced via an attribute
200
+ elseif ($node instanceof Twig_Node_Expression_GetAttr
201
+ && (!$node->getNode('attribute') instanceof Twig_Node_Expression_Constant
202
+ || 'parent' === $node->getNode('attribute')->getAttribute('value')
203
+ )
204
+ && (true === $this->loops[0]->getAttribute('with_loop')
205
+ || ($node->getNode('node') instanceof Twig_Node_Expression_Name
206
+ && 'loop' === $node->getNode('node')->getAttribute('name')
207
+ )
208
+ )
209
+ ) {
210
+ $this->addLoopToAll();
211
+ }
212
+ }
213
+
214
+ /**
215
+ * Optimizes "for" tag by removing the "loop" variable creation whenever possible.
216
+ *
217
+ * @param Twig_NodeInterface $node A Node
218
+ * @param Twig_Environment $env The current Twig environment
219
+ */
220
+ protected function leaveOptimizeFor(Twig_NodeInterface $node, Twig_Environment $env)
221
+ {
222
+ if ($node instanceof Twig_Node_For) {
223
+ array_shift($this->loops);
224
+ }
225
+ }
226
+
227
+ protected function addLoopToCurrent()
228
+ {
229
+ $this->loops[0]->setAttribute('with_loop', true);
230
+ }
231
+
232
+ protected function addLoopToAll()
233
+ {
234
+ foreach ($this->loops as $loop) {
235
+ $loop->setAttribute('with_loop', true);
236
+ }
237
+ }
238
+
239
+ /**
240
+ * {@inheritdoc}
241
+ */
242
+ public function getPriority()
243
+ {
244
+ return 255;
245
+ }
246
+ }
classes/Twig/NodeVisitor/SafeAnalysis.php CHANGED
@@ -1,139 +1,139 @@
1
- <?php
2
-
3
- class Twig_NodeVisitor_SafeAnalysis implements Twig_NodeVisitorInterface
4
- {
5
- protected $data = array();
6
- protected $safeVars = array();
7
-
8
- public function setSafeVars($safeVars)
9
- {
10
- $this->safeVars = $safeVars;
11
- }
12
-
13
- public function getSafe(Twig_NodeInterface $node)
14
- {
15
- $hash = spl_object_hash($node);
16
- if (!isset($this->data[$hash])) {
17
- return;
18
- }
19
-
20
- foreach ($this->data[$hash] as $bucket) {
21
- if ($bucket['key'] !== $node) {
22
- continue;
23
- }
24
-
25
- if (in_array('html_attr', $bucket['value'])) {
26
- $bucket['value'][] = 'html';
27
- }
28
-
29
- return $bucket['value'];
30
- }
31
- }
32
-
33
- protected function setSafe(Twig_NodeInterface $node, array $safe)
34
- {
35
- $hash = spl_object_hash($node);
36
- if (isset($this->data[$hash])) {
37
- foreach ($this->data[$hash] as &$bucket) {
38
- if ($bucket['key'] === $node) {
39
- $bucket['value'] = $safe;
40
-
41
- return;
42
- }
43
- }
44
- }
45
- $this->data[$hash][] = array(
46
- 'key' => $node,
47
- 'value' => $safe,
48
- );
49
- }
50
-
51
- public function enterNode(Twig_NodeInterface $node, Twig_Environment $env)
52
- {
53
- return $node;
54
- }
55
-
56
- public function leaveNode(Twig_NodeInterface $node, Twig_Environment $env)
57
- {
58
- if ($node instanceof Twig_Node_Expression_Constant) {
59
- // constants are marked safe for all
60
- $this->setSafe($node, array('all'));
61
- } elseif ($node instanceof Twig_Node_Expression_BlockReference) {
62
- // blocks are safe by definition
63
- $this->setSafe($node, array('all'));
64
- } elseif ($node instanceof Twig_Node_Expression_Parent) {
65
- // parent block is safe by definition
66
- $this->setSafe($node, array('all'));
67
- } elseif ($node instanceof Twig_Node_Expression_Conditional) {
68
- // intersect safeness of both operands
69
- $safe = $this->intersectSafe($this->getSafe($node->getNode('expr2')), $this->getSafe($node->getNode('expr3')));
70
- $this->setSafe($node, $safe);
71
- } elseif ($node instanceof Twig_Node_Expression_Filter) {
72
- // filter expression is safe when the filter is safe
73
- $name = $node->getNode('filter')->getAttribute('value');
74
- $args = $node->getNode('arguments');
75
- if (false !== $filter = $env->getFilter($name)) {
76
- $safe = $filter->getSafe($args);
77
- if (null === $safe) {
78
- $safe = $this->intersectSafe($this->getSafe($node->getNode('node')), $filter->getPreservesSafety());
79
- }
80
- $this->setSafe($node, $safe);
81
- } else {
82
- $this->setSafe($node, array());
83
- }
84
- } elseif ($node instanceof Twig_Node_Expression_Function) {
85
- // function expression is safe when the function is safe
86
- $name = $node->getAttribute('name');
87
- $args = $node->getNode('arguments');
88
- $function = $env->getFunction($name);
89
- if (false !== $function) {
90
- $this->setSafe($node, $function->getSafe($args));
91
- } else {
92
- $this->setSafe($node, array());
93
- }
94
- } elseif ($node instanceof Twig_Node_Expression_MethodCall) {
95
- if ($node->getAttribute('safe')) {
96
- $this->setSafe($node, array('all'));
97
- } else {
98
- $this->setSafe($node, array());
99
- }
100
- } elseif ($node instanceof Twig_Node_Expression_GetAttr && $node->getNode('node') instanceof Twig_Node_Expression_Name) {
101
- $name = $node->getNode('node')->getAttribute('name');
102
- // attributes on template instances are safe
103
- if ('_self' == $name || in_array($name, $this->safeVars)) {
104
- $this->setSafe($node, array('all'));
105
- } else {
106
- $this->setSafe($node, array());
107
- }
108
- } else {
109
- $this->setSafe($node, array());
110
- }
111
-
112
- return $node;
113
- }
114
-
115
- protected function intersectSafe(array $a = null, array $b = null)
116
- {
117
- if (null === $a || null === $b) {
118
- return array();
119
- }
120
-
121
- if (in_array('all', $a)) {
122
- return $b;
123
- }
124
-
125
- if (in_array('all', $b)) {
126
- return $a;
127
- }
128
-
129
- return array_intersect($a, $b);
130
- }
131
-
132
- /**
133
- * {@inheritdoc}
134
- */
135
- public function getPriority()
136
- {
137
- return 0;
138
- }
139
- }
1
+ <?php
2
+
3
+ class Twig_NodeVisitor_SafeAnalysis implements Twig_NodeVisitorInterface
4
+ {
5
+ protected $data = array();
6
+ protected $safeVars = array();
7
+
8
+ public function setSafeVars($safeVars)
9
+ {
10
+ $this->safeVars = $safeVars;
11
+ }
12
+
13
+ public function getSafe(Twig_NodeInterface $node)
14
+ {
15
+ $hash = spl_object_hash($node);
16
+ if (!isset($this->data[$hash])) {
17
+ return;
18
+ }
19
+
20
+ foreach ($this->data[$hash] as $bucket) {
21
+ if ($bucket['key'] !== $node) {
22
+ continue;
23
+ }
24
+
25
+ if (in_array('html_attr', $bucket['value'])) {
26
+ $bucket['value'][] = 'html';
27
+ }
28
+
29
+ return $bucket['value'];
30
+ }
31
+ }
32
+
33
+ protected function setSafe(Twig_NodeInterface $node, array $safe)
34
+ {
35
+ $hash = spl_object_hash($node);
36
+ if (isset($this->data[$hash])) {
37
+ foreach ($this->data[$hash] as &$bucket) {
38
+ if ($bucket['key'] === $node) {
39
+ $bucket['value'] = $safe;
40
+
41
+ return;
42
+ }
43
+ }
44
+ }
45
+ $this->data[$hash][] = array(
46
+ 'key' => $node,
47
+ 'value' => $safe,
48
+ );
49
+ }
50
+
51
+ public function enterNode(Twig_NodeInterface $node, Twig_Environment $env)
52
+ {
53
+ return $node;
54
+ }
55
+
56
+ public function leaveNode(Twig_NodeInterface $node, Twig_Environment $env)
57
+ {
58
+ if ($node instanceof Twig_Node_Expression_Constant) {
59
+ // constants are marked safe for all
60
+ $this->setSafe($node, array('all'));
61
+ } elseif ($node instanceof Twig_Node_Expression_BlockReference) {
62
+ // blocks are safe by definition
63
+ $this->setSafe($node, array('all'));
64
+ } elseif ($node instanceof Twig_Node_Expression_Parent) {
65
+ // parent block is safe by definition
66
+ $this->setSafe($node, array('all'));
67
+ } elseif ($node instanceof Twig_Node_Expression_Conditional) {
68
+ // intersect safeness of both operands
69
+ $safe = $this->intersectSafe($this->getSafe($node->getNode('expr2')), $this->getSafe($node->getNode('expr3')));
70
+ $this->setSafe($node, $safe);
71
+ } elseif ($node instanceof Twig_Node_Expression_Filter) {
72
+ // filter expression is safe when the filter is safe
73
+ $name = $node->getNode('filter')->getAttribute('value');
74
+ $args = $node->getNode('arguments');
75
+ if (false !== $filter = $env->getFilter($name)) {
76
+ $safe = $filter->getSafe($args);
77
+ if (null === $safe) {
78
+ $safe = $this->intersectSafe($this->getSafe($node->getNode('node')), $filter->getPreservesSafety());
79
+ }
80
+ $this->setSafe($node, $safe);
81
+ } else {
82
+ $this->setSafe($node, array());
83
+ }
84
+ } elseif ($node instanceof Twig_Node_Expression_Function) {
85
+ // function expression is safe when the function is safe
86
+ $name = $node->getAttribute('name');
87
+ $args = $node->getNode('arguments');
88
+ $function = $env->getFunction($name);
89
+ if (false !== $function) {
90
+ $this->setSafe($node, $function->getSafe($args));
91
+ } else {
92
+ $this->setSafe($node, array());
93
+ }
94
+ } elseif ($node instanceof Twig_Node_Expression_MethodCall) {
95
+ if ($node->getAttribute('safe')) {
96
+ $this->setSafe($node, array('all'));
97
+ } else {
98
+ $this->setSafe($node, array());
99
+ }
100
+ } elseif ($node instanceof Twig_Node_Expression_GetAttr && $node->getNode('node') instanceof Twig_Node_Expression_Name) {
101
+ $name = $node->getNode('node')->getAttribute('name');
102
+ // attributes on template instances are safe
103
+ if ('_self' == $name || in_array($name, $this->safeVars)) {
104
+ $this->setSafe($node, array('all'));
105
+ } else {
106
+ $this->setSafe($node, array());
107
+ }
108
+ } else {
109
+ $this->setSafe($node, array());
110
+ }
111
+
112
+ return $node;
113
+ }
114
+
115
+ protected function intersectSafe(array $a = null, array $b = null)
116
+ {
117
+ if (null === $a || null === $b) {
118
+ return array();
119
+ }
120
+
121
+ if (in_array('all', $a)) {
122
+ return $b;
123
+ }
124
+
125
+ if (in_array('all', $b)) {
126
+ return $a;
127
+ }
128
+
129
+ return array_intersect($a, $b);
130
+ }
131
+
132
+ /**
133
+ * {@inheritdoc}
134
+ */
135
+ public function getPriority()
136
+ {
137
+ return 0;
138
+ }
139
+ }
classes/Twig/NodeVisitor/Sandbox.php CHANGED
@@ -1,92 +1,92 @@
1
- <?php
2
-
3
- /*
4
- * This file is part of Twig.
5
- *
6
- * (c) 2009 Fabien Potencier
7
- *
8
- * For the full copyright and license information, please view the LICENSE
9
- * file that was distributed with this source code.
10
- */
11
-
12
- /**
13
- * Twig_NodeVisitor_Sandbox implements sandboxing.
14
- *
15
- * @author Fabien Potencier <fabien@symfony.com>
16
- */
17
- class Twig_NodeVisitor_Sandbox implements Twig_NodeVisitorInterface
18
- {
19
- protected $inAModule = false;
20
- protected $tags;
21
- protected $filters;
22
- protected $functions;
23
-
24
- /**
25
- * Called before child nodes are visited.
26
- *
27
- * @param Twig_NodeInterface $node The node to visit
28
- * @param Twig_Environment $env The Twig environment instance
29
- *
30
- * @return Twig_NodeInterface The modified node
31
- */
32
- public function enterNode(Twig_NodeInterface $node, Twig_Environment $env)
33
- {
34
- if ($node instanceof Twig_Node_Module) {
35
- $this->inAModule = true;
36
- $this->tags = array();
37
- $this->filters = array();
38
- $this->functions = array();
39
-
40
- return $node;
41
- } elseif ($this->inAModule) {
42
- // look for tags
43
- if ($node->getNodeTag()) {
44
- $this->tags[] = $node->getNodeTag();
45
- }
46
-
47
- // look for filters
48
- if ($node instanceof Twig_Node_Expression_Filter) {
49
- $this->filters[] = $node->getNode('filter')->getAttribute('value');
50
- }
51
-
52
- // look for functions
53
- if ($node instanceof Twig_Node_Expression_Function) {
54
- $this->functions[] = $node->getAttribute('name');
55
- }
56
-
57
- // wrap print to check __toString() calls
58
- if ($node instanceof Twig_Node_Print) {
59
- return new Twig_Node_SandboxedPrint($node->getNode('expr'), $node->getLine(), $node->getNodeTag());
60
- }
61
- }
62
-
63
- return $node;
64
- }
65
-
66
- /**
67
- * Called after child nodes are visited.
68
- *
69
- * @param Twig_NodeInterface $node The node to visit
70
- * @param Twig_Environment $env The Twig environment instance
71
- *
72
- * @return Twig_NodeInterface The modified node
73
- */
74
- public function leaveNode(Twig_NodeInterface $node, Twig_Environment $env)
75
- {
76
- if ($node instanceof Twig_Node_Module) {
77
- $this->inAModule = false;
78
-
79
- return new Twig_Node_SandboxedModule($node, array_unique($this->filters), array_unique($this->tags), array_unique($this->functions));
80
- }
81
-
82
- return $node;
83
- }
84
-
85
- /**
86
- * {@inheritdoc}
87
- */
88
- public function getPriority()
89
- {
90
- return 0;
91
- }
92
- }
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2009 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ /**
13
+ * Twig_NodeVisitor_Sandbox implements sandboxing.
14
+ *
15
+ * @author Fabien Potencier <fabien@symfony.com>
16
+ */
17
+ class Twig_NodeVisitor_Sandbox implements Twig_NodeVisitorInterface
18
+ {
19
+ protected $inAModule = false;
20
+ protected $tags;
21
+ protected $filters;
22
+ protected $functions;
23
+
24
+ /**
25
+ * Called before child nodes are visited.
26
+ *
27
+ * @param Twig_NodeInterface $node The node to visit
28
+ * @param Twig_Environment $env The Twig environment instance
29
+ *
30
+ * @return Twig_NodeInterface The modified node
31
+ */
32
+ public function enterNode(Twig_NodeInterface $node, Twig_Environment $env)
33
+ {
34
+ if ($node instanceof Twig_Node_Module) {
35
+ $this->inAModule = true;
36
+ $this->tags = array();
37
+ $this->filters = array();
38
+ $this->functions = array();
39
+
40
+ return $node;
41
+ } elseif ($this->inAModule) {
42
+ // look for tags
43
+ if ($node->getNodeTag()) {
44
+ $this->tags[] = $node->getNodeTag();
45
+ }
46
+
47
+ // look for filters
48
+ if ($node instanceof Twig_Node_Expression_Filter) {
49
+ $this->filters[] = $node->getNode('filter')->getAttribute('value');
50
+ }
51
+
52
+ // look for functions
53
+ if ($node instanceof Twig_Node_Expression_Function) {
54
+ $this->functions[] = $node->getAttribute('name');
55
+ }
56
+
57
+ // wrap print to check __toString() calls
58
+ if ($node instanceof Twig_Node_Print) {
59
+ return new Twig_Node_SandboxedPrint($node->getNode('expr'), $node->getLine(), $node->getNodeTag());
60
+ }
61
+ }
62
+
63
+ return $node;
64
+ }
65
+
66
+ /**
67
+ * Called after child nodes are visited.
68
+ *
69
+ * @param Twig_NodeInterface $node The node to visit
70
+ * @param Twig_Environment $env The Twig environment instance
71
+ *
72
+ * @return Twig_NodeInterface The modified node
73
+ */
74
+ public function leaveNode(Twig_NodeInterface $node, Twig_Environment $env)
75
+ {
76
+ if ($node instanceof Twig_Node_Module) {
77
+ $this->inAModule = false;
78
+
79
+ return new Twig_Node_SandboxedModule($node, array_unique($this->filters), array_unique($this->tags), array_unique($this->functions));
80
+ }
81
+
82
+ return $node;
83
+ }
84
+
85
+ /**
86
+ * {@inheritdoc}
87
+ */
88
+ public function getPriority()
89
+ {
90
+ return 0;
91
+ }
92
+ }
classes/Twig/NodeVisitorInterface.php CHANGED
@@ -1,47 +1,47 @@
1
- <?php
2
-
3
- /*
4
- * This file is part of Twig.
5
- *
6
- * (c) 2009 Fabien Potencier
7
- *
8
- * For the full copyright and license information, please view the LICENSE
9
- * file that was distributed with this source code.
10
- */
11
-
12
- /**
13
- * Twig_NodeVisitorInterface is the interface the all node visitor classes must implement.
14
- *
15
- * @author Fabien Potencier <fabien@symfony.com>
16
- */
17
- interface Twig_NodeVisitorInterface
18
- {
19
- /**
20
- * Called before child nodes are visited.
21
- *
22
- * @param Twig_NodeInterface $node The node to visit
23
- * @param Twig_Environment $env The Twig environment instance
24
- *
25
- * @return Twig_NodeInterface The modified node
26
- */
27
- public function enterNode(Twig_NodeInterface $node, Twig_Environment $env);
28
-
29
- /**
30
- * Called after child nodes are visited.
31
- *
32
- * @param Twig_NodeInterface $node The node to visit
33
- * @param Twig_Environment $env The Twig environment instance
34
- *
35
- * @return Twig_NodeInterface|false The modified node or false if the node must be removed
36
- */
37
- public function leaveNode(Twig_NodeInterface $node, Twig_Environment $env);
38
-
39
- /**
40
- * Returns the priority for this visitor.
41
- *
42
- * Priority should be between -10 and 10 (0 is the default).
43
- *
44
- * @return int The priority level
45
- */
46
- public function getPriority();
47
- }
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2009 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ /**
13
+ * Twig_NodeVisitorInterface is the interface the all node visitor classes must implement.
14
+ *
15
+ * @author Fabien Potencier <fabien@symfony.com>
16
+ */
17
+ interface Twig_NodeVisitorInterface
18
+ {
19
+ /**
20
+ * Called before child nodes are visited.
21
+ *
22
+ * @param Twig_NodeInterface $node The node to visit
23
+ * @param Twig_Environment $env The Twig environment instance
24
+ *
25
+ * @return Twig_NodeInterface The modified node
26
+ */
27
+ public function enterNode(Twig_NodeInterface $node, Twig_Environment $env);
28
+
29
+ /**
30
+ * Called after child nodes are visited.
31
+ *
32
+ * @param Twig_NodeInterface $node The node to visit
33
+ * @param Twig_Environment $env The Twig environment instance
34
+ *
35
+ * @return Twig_NodeInterface|false The modified node or false if the node must be removed
36
+ */
37
+ public function leaveNode(Twig_NodeInterface $node, Twig_Environment $env);
38
+
39
+ /**
40
+ * Returns the priority for this visitor.
41
+ *
42
+ * Priority should be between -10 and 10 (0 is the default).
43
+ *
44
+ * @return int The priority level
45
+ */
46
+ public function getPriority();
47
+ }
classes/Twig/Parser.php CHANGED
@@ -1,390 +1,390 @@
1
- <?php
2
-
3
- /*
4
- * This file is part of Twig.
5
- *
6
- * (c) 2009 Fabien Potencier
7
- * (c) 2009 Armin Ronacher
8
- *
9
- * For the full copyright and license information, please view the LICENSE
10
- * file that was distributed with this source code.
11
- */
12
-
13
- /**
14
- * Default parser implementation.
15
- *
16
- * @author Fabien Potencier <fabien@symfony.com>
17
- */
18
- class Twig_Parser implements Twig_ParserInterface
19
- {
20
- protected $stack = array();
21
- protected $stream;
22
- protected $parent;
23
- protected $handlers;
24
- protected $visitors;
25
- protected $expressionParser;
26
- protected $blocks;
27
- protected $blockStack;
28
- protected $macros;
29
- protected $env;
30
- protected $reservedMacroNames;
31
- protected $importedSymbols;
32
- protected $traits;
33
- protected $embeddedTemplates = array();
34
-
35
- /**
36
- * Constructor.
37
- *
38
- * @param Twig_Environment $env A Twig_Environment instance
39
- */
40
- public function __construct(Twig_Environment $env)
41
- {
42
- $this->env = $env;
43
- }
44
-
45
- public function getEnvironment()
46
- {
47
- return $this->env;
48
- }
49
-
50
- public function getVarName()
51
- {
52
- return sprintf('__internal_%s', hash('sha256', uniqid(mt_rand(), true), false));
53
- }
54
-
55
- public function getFilename()
56
- {
57
- return $this->stream->getFilename();
58
- }
59
-
60
- /**
61
- * {@inheritdoc}
62
- */
63
- public function parse(Twig_TokenStream $stream, $test = null, $dropNeedle = false)
64
- {
65
- // push all variables into the stack to keep the current state of the parser
66
- $vars = get_object_vars($this);
67
- unset($vars['stack'], $vars['env'], $vars['handlers'], $vars['visitors'], $vars['expressionParser']);
68
- $this->stack[] = $vars;
69
-
70
- // tag handlers
71
- if (null === $this->handlers) {
72
- $this->handlers = $this->env->getTokenParsers();
73
- $this->handlers->setParser($this);
74
- }
75
-
76
- // node visitors
77
- if (null === $this->visitors) {
78
- $this->visitors = $this->env->getNodeVisitors();
79
- }
80
-
81
- if (null === $this->expressionParser) {
82
- $this->expressionParser = new Twig_ExpressionParser($this, $this->env->getUnaryOperators(), $this->env->getBinaryOperators());
83
- }
84
-
85
- $this->stream = $stream;
86
- $this->parent = null;
87
- $this->blocks = array();
88
- $this->macros = array();
89
- $this->traits = array();
90
- $this->blockStack = array();
91
- $this->importedSymbols = array(array());
92
- $this->embeddedTemplates = array();
93
-
94
- try {
95
- $body = $this->subparse($test, $dropNeedle);
96
-
97
- if (null !== $this->parent) {
98
- if (null === $body = $this->filterBodyNodes($body)) {
99
- $body = new Twig_Node();
100
- }
101
- }
102
- } catch (Twig_Error_Syntax $e) {
103
- if (!$e->getTemplateFile()) {
104
- $e->setTemplateFile($this->getFilename());
105
- }
106
-
107
- if (!$e->getTemplateLine()) {
108
- $e->setTemplateLine($this->stream->getCurrent()->getLine());
109
- }
110
-
111
- throw $e;
112
- }
113
-
114
- $node = new Twig_Node_Module(new Twig_Node_Body(array($body)), $this->parent, new Twig_Node($this->blocks), new Twig_Node($this->macros), new Twig_Node($this->traits), $this->embeddedTemplates, $this->getFilename());
115
-
116
- $traverser = new Twig_NodeTraverser($this->env, $this->visitors);
117
-
118
- $node = $traverser->traverse($node);
119
-
120
- // restore previous stack so previous parse() call can resume working
121
- foreach (array_pop($this->stack) as $key => $val) {
122
- $this->$key = $val;
123
- }
124
-
125
- return $node;
126
- }
127
-
128
- public function subparse($test, $dropNeedle = false)
129
- {
130
- $lineno = $this->getCurrentToken()->getLine();
131
- $rv = array();
132
- while (!$this->stream->isEOF()) {
133
- switch ($this->getCurrentToken()->getType()) {
134
- case Twig_Token::TEXT_TYPE:
135
- $token = $this->stream->next();
136
- $rv[] = new Twig_Node_Text($token->getValue(), $token->getLine());
137
- break;
138
-
139
- case Twig_Token::VAR_START_TYPE:
140
- $token = $this->stream->next();
141
- $expr = $this->expressionParser->parseExpression();
142
- $this->stream->expect(Twig_Token::VAR_END_TYPE);
143
- $rv[] = new Twig_Node_Print($expr, $token->getLine());
144
- break;
145
-
146
- case Twig_Token::BLOCK_START_TYPE:
147
- $this->stream->next();
148
- $token = $this->getCurrentToken();
149
-
150
- if ($token->getType() !== Twig_Token::NAME_TYPE) {
151
- throw new Twig_Error_Syntax('A block must start with a tag name', $token->getLine(), $this->getFilename());
152
- }
153
-
154
- if (null !== $test && call_user_func($test, $token)) {
155
- if ($dropNeedle) {
156
- $this->stream->next();
157
- }
158
-
159
- if (1 === count($rv)) {
160
- return $rv[0];
161
- }
162
-
163
- return new Twig_Node($rv, array(), $lineno);
164
- }
165
-
166
- $subparser = $this->handlers->getTokenParser($token->getValue());
167
- if (null === $subparser) {
168
- if (null !== $test) {
169
- $error = sprintf('Unexpected tag name "%s"', $token->getValue());
170
- if (is_array($test) && isset($test[0]) && $test[0] instanceof Twig_TokenParserInterface) {
171
- $error .= sprintf(' (expecting closing tag for the "%s" tag defined near line %s)', $test[0]->getTag(), $lineno);
172
- }
173
-
174
- throw new Twig_Error_Syntax($error, $token->getLine(), $this->getFilename());
175
- }
176
-
177
- $message = sprintf('Unknown tag name "%s"', $token->getValue());
178
- if ($alternatives = $this->env->computeAlternatives($token->getValue(), array_keys($this->env->getTags()))) {
179
- $message = sprintf('%s. Did you mean "%s"', $message, implode('", "', $alternatives));
180
- }
181
-
182
- throw new Twig_Error_Syntax($message, $token->getLine(), $this->getFilename());
183
- }
184
-
185
- $this->stream->next();
186
-
187
- $node = $subparser->parse($token);
188
- if (null !== $node) {
189
- $rv[] = $node;
190
- }
191
- break;
192
-
193
- default:
194
- throw new Twig_Error_Syntax('Lexer or parser ended up in unsupported state.', 0, $this->getFilename());
195
- }
196
- }
197
-
198
- if (1 === count($rv)) {
199
- return $rv[0];
200
- }
201
-
202
- return new Twig_Node($rv, array(), $lineno);
203
- }
204
-
205
- public function addHandler($name, $class)
206
- {
207
- $this->handlers[$name] = $class;
208
- }
209
-
210
- public function addNodeVisitor(Twig_NodeVisitorInterface $visitor)
211
- {
212
- $this->visitors[] = $visitor;
213
- }
214
-
215
- public function getBlockStack()
216
- {
217
- return $this->blockStack;
218
- }
219
-
220
- public function peekBlockStack()
221
- {
222
- return $this->blockStack[count($this->blockStack) - 1];
223
- }
224
-
225
- public function popBlockStack()
226
- {
227
- array_pop($this->blockStack);
228
- }
229
-
230
- public function pushBlockStack($name)
231
- {
232
- $this->blockStack[] = $name;
233
- }
234
-
235
- public function hasBlock($name)
236
- {
237
- return isset($this->blocks[$name]);
238
- }
239
-
240
- public function getBlock($name)
241
- {
242
- return $this->blocks[$name];
243
- }
244
-
245
- public function setBlock($name, Twig_Node_Block $value)
246
- {
247
- $this->blocks[$name] = new Twig_Node_Body(array($value), array(), $value->getLine());
248
- }
249
-
250
- public function hasMacro($name)
251
- {
252
- return isset($this->macros[$name]);
253
- }
254
-
255
- public function setMacro($name, Twig_Node_Macro $node)
256
- {
257
- if (null === $this->reservedMacroNames) {
258
- $this->reservedMacroNames = array();
259
- $r = new ReflectionClass($this->env->getBaseTemplateClass());
260
- foreach ($r->getMethods() as $method) {
261
- $this->reservedMacroNames[] = $method->getName();
262
- }
263
- }
264
-
265
- if (in_array($name, $this->reservedMacroNames)) {
266
- throw new Twig_Error_Syntax(sprintf('"%s" cannot be used as a macro name as it is a reserved keyword', $name), $node->getLine(), $this->getFilename());
267
- }
268
-
269
- $this->macros[$name] = $node;
270
- }
271
-
272
- public function addTrait($trait)
273
- {
274
- $this->traits[] = $trait;
275
- }
276
-
277
- public function hasTraits()
278
- {
279
- return count($this->traits) > 0;
280
- }
281
-
282
- public function embedTemplate(Twig_Node_Module $template)
283
- {
284
- $template->setIndex(mt_rand());
285
-
286
- $this->embeddedTemplates[] = $template;
287
- }
288
-
289
- public function addImportedSymbol($type, $alias, $name = null, Twig_Node_Expression $node = null)
290
- {
291
- $this->importedSymbols[0][$type][$alias] = array('name' => $name, 'node' => $node);
292
- }
293
-
294
- public function getImportedSymbol($type, $alias)
295
- {
296
- foreach ($this->importedSymbols as $functions) {
297
- if (isset($functions[$type][$alias])) {
298
- return $functions[$type][$alias];
299
- }
300
- }
301
- }
302
-
303
- public function isMainScope()
304
- {
305
- return 1 === count($this->importedSymbols);
306
- }
307
-
308
- public function pushLocalScope()
309
- {
310
- array_unshift($this->importedSymbols, array());
311
- }
312
-
313
- public function popLocalScope()
314
- {
315
- array_shift($this->importedSymbols);
316
- }
317
-
318
- /**
319
- * Gets the expression parser.
320
- *
321
- * @return Twig_ExpressionParser The expression parser
322
- */
323
- public function getExpressionParser()
324
- {
325
- return $this->expressionParser;
326
- }
327
-
328
- public function getParent()
329
- {
330
- return $this->parent;
331
- }
332
-
333
- public function setParent($parent)
334
- {
335
- $this->parent = $parent;
336
- }
337
-
338
- /**
339
- * Gets the token stream.
340
- *
341
- * @return Twig_TokenStream The token stream
342
- */
343
- public function getStream()
344
- {
345
- return $this->stream;
346
- }
347
-
348
- /**
349
- * Gets the current token.
350
- *
351
- * @return Twig_Token The current token
352
- */
353
- public function getCurrentToken()
354
- {
355
- return $this->stream->getCurrent();
356
- }
357
-
358
- protected function filterBodyNodes(Twig_NodeInterface $node)
359
- {
360
- // check that the body does not contain non-empty output nodes
361
- if (
362
- ($node instanceof Twig_Node_Text && !ctype_space($node->getAttribute('data')))
363
- ||
364
- (!$node instanceof Twig_Node_Text && !$node instanceof Twig_Node_BlockReference && $node instanceof Twig_NodeOutputInterface)
365
- ) {
366
- if (false !== strpos((string) $node, chr(0xEF).chr(0xBB).chr(0xBF))) {
367
- throw new Twig_Error_Syntax('A template that extends another one cannot have a body but a byte order mark (BOM) has been detected; it must be removed.', $node->getLine(), $this->getFilename());
368
- }
369
-
370
- throw new Twig_Error_Syntax('A template that extends another one cannot have a body.', $node->getLine(), $this->getFilename());
371
- }
372
-
373
- // bypass "set" nodes as they "capture" the output
374
- if ($node instanceof Twig_Node_Set) {
375
- return $node;
376
- }
377
-
378
- if ($node instanceof Twig_NodeOutputInterface) {
379
- return;
380
- }
381
-
382
- foreach ($node as $k => $n) {
383
- if (null !== $n && null === $this->filterBodyNodes($n)) {
384
- $node->removeNode($k);
385
- }
386
- }
387
-
388
- return $node;
389
- }
390
- }
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2009 Fabien Potencier
7
+ * (c) 2009 Armin Ronacher
8
+ *
9
+ * For the full copyright and license information, please view the LICENSE
10
+ * file that was distributed with this source code.
11
+ */
12
+
13
+ /**
14
+ * Default parser implementation.
15
+ *
16
+ * @author Fabien Potencier <fabien@symfony.com>
17
+ */
18
+ class Twig_Parser implements Twig_ParserInterface
19
+ {
20
+ protected $stack = array();
21
+ protected $stream;
22
+ protected $parent;
23
+ protected $handlers;
24
+ protected $visitors;
25
+ protected $expressionParser;
26
+ protected $blocks;
27
+ protected $blockStack;
28
+ protected $macros;
29
+ protected $env;
30
+ protected $reservedMacroNames;
31
+ protected $importedSymbols;
32
+ protected $traits;
33
+ protected $embeddedTemplates = array();
34
+
35
+ /**
36
+ * Constructor.
37
+ *
38
+ * @param Twig_Environment $env A Twig_Environment instance
39
+ */
40
+ public function __construct(Twig_Environment $env)
41
+ {
42
+ $this->env = $env;
43
+ }
44
+
45
+ public function getEnvironment()
46
+ {
47
+ return $this->env;
48
+ }
49
+
50
+ public function getVarName()
51
+ {
52
+ return sprintf('__internal_%s', hash('sha256', uniqid(mt_rand(), true), false));
53
+ }
54
+
55
+ public function getFilename()
56
+ {
57
+ return $this->stream->getFilename();
58
+ }
59
+
60
+ /**
61
+ * {@inheritdoc}
62
+ */
63
+ public function parse(Twig_TokenStream $stream, $test = null, $dropNeedle = false)
64
+ {
65
+ // push all variables into the stack to keep the current state of the parser
66
+ $vars = get_object_vars($this);
67
+ unset($vars['stack'], $vars['env'], $vars['handlers'], $vars['visitors'], $vars['expressionParser']);
68
+ $this->stack[] = $vars;
69
+
70
+ // tag handlers
71
+ if (null === $this->handlers) {
72
+ $this->handlers = $this->env->getTokenParsers();
73
+ $this->handlers->setParser($this);
74
+ }
75
+
76
+ // node visitors
77
+ if (null === $this->visitors) {
78
+ $this->visitors = $this->env->getNodeVisitors();
79
+ }
80
+
81
+ if (null === $this->expressionParser) {
82
+ $this->expressionParser = new Twig_ExpressionParser($this, $this->env->getUnaryOperators(), $this->env->getBinaryOperators());
83
+ }
84
+
85
+ $this->stream = $stream;
86
+ $this->parent = null;
87
+ $this->blocks = array();
88
+ $this->macros = array();
89
+ $this->traits = array();
90
+ $this->blockStack = array();
91
+ $this->importedSymbols = array(array());
92
+ $this->embeddedTemplates = array();
93
+
94
+ try {
95
+ $body = $this->subparse($test, $dropNeedle);
96
+
97
+ if (null !== $this->parent) {
98
+ if (null === $body = $this->filterBodyNodes($body)) {
99
+ $body = new Twig_Node();
100
+ }
101
+ }
102
+ } catch (Twig_Error_Syntax $e) {
103
+ if (!$e->getTemplateFile()) {
104
+ $e->setTemplateFile($this->getFilename());
105
+ }
106
+
107
+ if (!$e->getTemplateLine()) {
108
+ $e->setTemplateLine($this->stream->getCurrent()->getLine());
109
+ }
110
+
111
+ throw $e;
112
+ }
113
+
114
+ $node = new Twig_Node_Module(new Twig_Node_Body(array($body)), $this->parent, new Twig_Node($this->blocks), new Twig_Node($this->macros), new Twig_Node($this->traits), $this->embeddedTemplates, $this->getFilename());
115
+
116
+ $traverser = new Twig_NodeTraverser($this->env, $this->visitors);
117
+
118
+ $node = $traverser->traverse($node);
119
+
120
+ // restore previous stack so previous parse() call can resume working
121
+ foreach (array_pop($this->stack) as $key => $val) {
122
+ $this->$key = $val;
123
+ }
124
+
125
+ return $node;
126
+ }
127
+
128
+ public function subparse($test, $dropNeedle = false)
129
+ {
130
+ $lineno = $this->getCurrentToken()->getLine();
131
+ $rv = array();
132
+ while (!$this->stream->isEOF()) {
133
+ switch ($this->getCurrentToken()->getType()) {
134
+ case Twig_Token::TEXT_TYPE:
135
+ $token = $this->stream->next();
136
+ $rv[] = new Twig_Node_Text($token->getValue(), $token->getLine());
137
+ break;
138
+
139
+ case Twig_Token::VAR_START_TYPE:
140
+ $token = $this->stream->next();
141
+ $expr = $this->expressionParser->parseExpression();
142
+ $this->stream->expect(Twig_Token::VAR_END_TYPE);
143
+ $rv[] = new Twig_Node_Print($expr, $token->getLine());
144
+ break;
145
+
146
+ case Twig_Token::BLOCK_START_TYPE:
147
+ $this->stream->next();
148
+ $token = $this->getCurrentToken();
149
+
150
+ if ($token->getType() !== Twig_Token::NAME_TYPE) {
151
+ throw new Twig_Error_Syntax('A block must start with a tag name', $token->getLine(), $this->getFilename());
152
+ }
153
+
154
+ if (null !== $test && call_user_func($test, $token)) {
155
+ if ($dropNeedle) {
156
+ $this->stream->next();
157
+ }
158
+
159
+ if (1 === count($rv)) {
160
+ return $rv[0];
161
+ }
162
+
163
+ return new Twig_Node($rv, array(), $lineno);
164
+ }
165
+
166
+ $subparser = $this->handlers->getTokenParser($token->getValue());
167
+ if (null === $subparser) {
168
+ if (null !== $test) {
169
+ $error = sprintf('Unexpected tag name "%s"', $token->getValue());
170
+ if (is_array($test) && isset($test[0]) && $test[0] instanceof Twig_TokenParserInterface) {
171
+ $error .= sprintf(' (expecting closing tag for the "%s" tag defined near line %s)', $test[0]->getTag(), $lineno);
172
+ }
173
+
174
+ throw new Twig_Error_Syntax($error, $token->getLine(), $this->getFilename());
175
+ }
176
+
177
+ $message = sprintf('Unknown tag name "%s"', $token->getValue());
178
+ if ($alternatives = $this->env->computeAlternatives($token->getValue(), array_keys($this->env->getTags()))) {
179
+ $message = sprintf('%s. Did you mean "%s"', $message, implode('", "', $alternatives));
180
+ }
181
+
182
+ throw new Twig_Error_Syntax($message, $token->getLine(), $this->getFilename());
183
+ }
184
+
185
+ $this->stream->next();
186
+
187
+ $node = $subparser->parse($token);
188
+ if (null !== $node) {
189
+ $rv[] = $node;
190
+ }
191
+ break;
192
+
193
+ default:
194
+ throw new Twig_Error_Syntax('Lexer or parser ended up in unsupported state.', 0, $this->getFilename());
195
+ }
196
+ }
197
+
198
+ if (1 === count($rv)) {
199
+ return $rv[0];
200
+ }
201
+
202
+ return new Twig_Node($rv, array(), $lineno);
203
+ }
204
+
205
+ public function addHandler($name, $class)
206
+ {
207
+ $this->handlers[$name] = $class;
208
+ }
209
+
210
+ public function addNodeVisitor(Twig_NodeVisitorInterface $visitor)
211
+ {
212
+ $this->visitors[] = $visitor;
213
+ }
214
+
215
+ public function getBlockStack()
216
+ {
217
+ return $this->blockStack;
218
+ }
219
+
220
+ public function peekBlockStack()
221
+ {
222
+ return $this->blockStack[count($this->blockStack) - 1];
223
+ }
224
+
225
+ public function popBlockStack()
226
+ {
227
+ array_pop($this->blockStack);
228
+ }
229
+
230
+ public function pushBlockStack($name)
231
+ {
232
+ $this->blockStack[] = $name;
233
+ }
234
+
235
+ public function hasBlock($name)
236
+ {
237
+ return isset($this->blocks[$name]);
238
+ }
239
+
240
+ public function getBlock($name)
241
+ {
242
+ return $this->blocks[$name];
243
+ }
244
+
245
+ public function setBlock($name, Twig_Node_Block $value)
246
+ {
247
+ $this->blocks[$name] = new Twig_Node_Body(array($value), array(), $value->getLine());
248
+ }
249
+
250
+ public function hasMacro($name)
251
+ {
252
+ return isset($this->macros[$name]);
253
+ }
254
+
255
+ public function setMacro($name, Twig_Node_Macro $node)
256
+ {
257
+ if (null === $this->reservedMacroNames) {
258
+ $this->reservedMacroNames = array();
259
+ $r = new ReflectionClass($this->env->getBaseTemplateClass());
260
+ foreach ($r->getMethods() as $method) {
261
+ $this->reservedMacroNames[] = $method->getName();
262
+ }
263
+ }
264
+
265
+ if (in_array($name, $this->reservedMacroNames)) {
266
+ throw new Twig_Error_Syntax(sprintf('"%s" cannot be used as a macro name as it is a reserved keyword', $name), $node->getLine(), $this->getFilename());
267
+ }
268
+
269
+ $this->macros[$name] = $node;
270
+ }
271
+
272
+ public function addTrait($trait)
273
+ {
274
+ $this->traits[] = $trait;
275
+ }
276
+
277
+ public function hasTraits()
278
+ {
279
+ return count($this->traits) > 0;
280
+ }
281
+
282
+ public function embedTemplate(Twig_Node_Module $template)
283
+ {
284
+ $template->setIndex(mt_rand());
285
+
286
+ $this->embeddedTemplates[] = $template;
287
+ }
288
+
289
+ public function addImportedSymbol($type, $alias, $name = null, Twig_Node_Expression $node = null)
290
+ {
291
+ $this->importedSymbols[0][$type][$alias] = array('name' => $name, 'node' => $node);
292
+ }
293
+
294
+ public function getImportedSymbol($type, $alias)
295
+ {
296
+ foreach ($this->importedSymbols as $functions) {
297
+ if (isset($functions[$type][$alias])) {
298
+ return $functions[$type][$alias];
299
+ }
300
+ }
301
+ }
302
+
303
+ public function isMainScope()
304
+ {
305
+ return 1 === count($this->importedSymbols);
306
+ }
307
+
308
+ public function pushLocalScope()
309
+ {
310
+ array_unshift($this->importedSymbols, array());
311
+ }
312
+
313
+ public function popLocalScope()
314
+ {
315
+ array_shift($this->importedSymbols);
316
+ }
317
+
318
+ /**
319
+ * Gets the expression parser.
320
+ *
321
+ * @return Twig_ExpressionParser The expression parser
322
+ */
323
+ public function getExpressionParser()
324
+ {
325
+ return $this->expressionParser;
326
+ }
327
+
328
+ public function getParent()
329
+ {
330
+ return $this->parent;
331
+ }
332
+
333
+ public function setParent($parent)
334
+ {
335
+ $this->parent = $parent;
336
+ }
337
+
338
+ /**
339
+ * Gets the token stream.
340
+ *
341
+ * @return Twig_TokenStream The token stream
342
+ */
343
+ public function getStream()
344
+ {
345
+ return $this->stream;
346
+ }
347
+
348
+ /**
349
+ * Gets the current token.
350
+ *
351
+ * @return Twig_Token The current token
352
+ */
353
+ public function getCurrentToken()
354
+ {
355
+ return $this->stream->getCurrent();
356
+ }
357
+
358
+ protected function filterBodyNodes(Twig_NodeInterface $node)
359
+ {
360
+ // check that the body does not contain non-empty output nodes
361
+ if (
362
+ ($node instanceof Twig_Node_Text && !ctype_space($node->getAttribute('data')))
363
+ ||
364
+ (!$node instanceof Twig_Node_Text && !$node instanceof Twig_Node_BlockReference && $node instanceof Twig_NodeOutputInterface)
365
+ ) {
366
+ if (false !== strpos((string) $node, chr(0xEF).chr(0xBB).chr(0xBF))) {
367
+ throw new Twig_Error_Syntax('A template that extends another one cannot have a body but a byte order mark (BOM) has been detected; it must be removed.', $node->getLine(), $this->getFilename());
368
+ }
369
+
370
+ throw new Twig_Error_Syntax('A template that extends another one cannot have a body.', $node->getLine(), $this->getFilename());
371
+ }
372
+
373
+ // bypass "set" nodes as they "capture" the output
374
+ if ($node instanceof Twig_Node_Set) {
375
+ return $node;
376
+ }
377
+
378
+ if ($node instanceof Twig_NodeOutputInterface) {
379
+ return;
380
+ }
381
+
382
+ foreach ($node as $k => $n) {
383
+ if (null !== $n && null === $this->filterBodyNodes($n)) {
384
+ $node->removeNode($k);
385
+ }
386
+ }
387
+
388
+ return $node;
389
+ }
390
+ }
classes/Twig/ParserInterface.php CHANGED
@@ -1,31 +1,31 @@
1
- <?php
2
-
3
- /*
4
- * This file is part of Twig.
5
- *
6
- * (c) 2009 Fabien Potencier
7
- *
8
- * For the full copyright and license information, please view the LICENSE
9
- * file that was distributed with this source code.
10
- */
11
-
12
- /**
13
- * Interface implemented by parser classes.
14
- *
15
- * @author Fabien Potencier <fabien@symfony.com>
16
- *
17
- * @deprecated since 1.12 (to be removed in 3.0)
18
- */
19
- interface Twig_ParserInterface
20
- {
21
- /**
22
- * Converts a token stream to a node tree.
23
- *
24
- * @param Twig_TokenStream $stream A token stream instance
25
- *
26
- * @return Twig_Node_Module A node tree
27
- *
28
- * @throws Twig_Error_Syntax When the token stream is syntactically or semantically wrong
29
- */
30
- public function parse(Twig_TokenStream $stream);
31
- }
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2009 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ /**
13
+ * Interface implemented by parser classes.
14
+ *
15
+ * @author Fabien Potencier <fabien@symfony.com>
16
+ *
17
+ * @deprecated since 1.12 (to be removed in 3.0)
18
+ */
19
+ interface Twig_ParserInterface
20
+ {
21
+ /**
22
+ * Converts a token stream to a node tree.
23
+ *
24
+ * @param Twig_TokenStream $stream A token stream instance
25
+ *
26
+ * @return Twig_Node_Module A node tree
27
+ *
28
+ * @throws Twig_Error_Syntax When the token stream is syntactically or semantically wrong
29
+ */
30
+ public function parse(Twig_TokenStream $stream);
31
+ }
classes/Twig/Sandbox/SecurityError.php CHANGED
@@ -1,19 +1,19 @@
1
- <?php
2
-
3
- /*
4
- * This file is part of Twig.
5
- *
6
- * (c) 2009 Fabien Potencier
7
- *
8
- * For the full copyright and license information, please view the LICENSE
9
- * file that was distributed with this source code.
10
- */
11
-
12
- /**
13
- * Exception thrown when a security error occurs at runtime.
14
- *
15
- * @author Fabien Potencier <fabien@symfony.com>
16
- */
17
- class Twig_Sandbox_SecurityError extends Twig_Error
18
- {
19
- }
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2009 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ /**
13
+ * Exception thrown when a security error occurs at runtime.
14
+ *
15
+ * @author Fabien Potencier <fabien@symfony.com>
16
+ */
17
+ class Twig_Sandbox_SecurityError extends Twig_Error
18
+ {
19
+ }
classes/Twig/Sandbox/SecurityPolicy.php CHANGED
@@ -1,119 +1,119 @@
1
- <?php
2
-
3
- /*
4
- * This file is part of Twig.
5
- *
6
- * (c) 2009 Fabien Potencier
7
- *
8
- * For the full copyright and license information, please view the LICENSE
9
- * file that was distributed with this source code.
10
- */
11
-
12
- /**
13
- * Represents a security policy which need to be enforced when sandbox mode is enabled.
14
- *
15
- * @author Fabien Potencier <fabien@symfony.com>
16
- */
17
- class Twig_Sandbox_SecurityPolicy implements Twig_Sandbox_SecurityPolicyInterface
18
- {
19
- protected $allowedTags;
20
- protected $allowedFilters;
21
- protected $allowedMethods;
22
- protected $allowedProperties;
23
- protected $allowedFunctions;
24
-
25
- public function __construct(array $allowedTags = array(), array $allowedFilters = array(), array $allowedMethods = array(), array $allowedProperties = array(), array $allowedFunctions = array())
26
- {
27
- $this->allowedTags = $allowedTags;
28
- $this->allowedFilters = $allowedFilters;
29
- $this->setAllowedMethods($allowedMethods);
30
- $this->allowedProperties = $allowedProperties;
31
- $this->allowedFunctions = $allowedFunctions;
32
- }
33
-
34
- public function setAllowedTags(array $tags)
35
- {
36
- $this->allowedTags = $tags;
37
- }
38
-
39
- public function setAllowedFilters(array $filters)
40
- {
41
- $this->allowedFilters = $filters;
42
- }
43
-
44
- public function setAllowedMethods(array $methods)
45
- {
46
- $this->allowedMethods = array();
47
- foreach ($methods as $class => $m) {
48
- $this->allowedMethods[$class] = array_map('strtolower', is_array($m) ? $m : array($m));
49
- }
50
- }
51
-
52
- public function setAllowedProperties(array $properties)
53
- {
54
- $this->allowedProperties = $properties;
55
- }
56
-
57
- public function setAllowedFunctions(array $functions)
58
- {
59
- $this->allowedFunctions = $functions;
60
- }
61
-
62
- public function checkSecurity($tags, $filters, $functions)
63
- {
64
- foreach ($tags as $tag) {
65
- if (!in_array($tag, $this->allowedTags)) {
66
- throw new Twig_Sandbox_SecurityError(sprintf('Tag "%s" is not allowed.', $tag));
67
- }
68
- }
69
-
70
- foreach ($filters as $filter) {
71
- if (!in_array($filter, $this->allowedFilters)) {
72
- throw new Twig_Sandbox_SecurityError(sprintf('Filter "%s" is not allowed.', $filter));
73
- }
74
- }
75
-
76
- foreach ($functions as $function) {
77
- if (!in_array($function, $this->allowedFunctions)) {
78
- throw new Twig_Sandbox_SecurityError(sprintf('Function "%s" is not allowed.', $function));
79
- }
80
- }
81
- }
82
-
83
- public function checkMethodAllowed($obj, $method)
84
- {
85
- if ($obj instanceof Twig_TemplateInterface || $obj instanceof Twig_Markup) {
86
- return true;
87
- }
88
-
89
- $allowed = false;
90
- $method = strtolower($method);
91
- foreach ($this->allowedMethods as $class => $methods) {
92
- if ($obj instanceof $class) {
93
- $allowed = in_array($method, $methods);
94
-
95
- break;
96
- }
97
- }
98
-
99
- if (!$allowed) {
100
- throw new Twig_Sandbox_SecurityError(sprintf('Calling "%s" method on a "%s" object is not allowed.', $method, get_class($obj)));
101
- }
102
- }
103
-
104
- public function checkPropertyAllowed($obj, $property)
105
- {
106
- $allowed = false;
107
- foreach ($this->allowedProperties as $class => $properties) {
108
- if ($obj instanceof $class) {
109
- $allowed = in_array($property, is_array($properties) ? $properties : array($properties));
110
-
111
- break;
112
- }
113
- }
114
-
115
- if (!$allowed) {
116
- throw new Twig_Sandbox_SecurityError(sprintf('Calling "%s" property on a "%s" object is not allowed.', $property, get_class($obj)));
117
- }
118
- }
119
- }
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2009 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ /**
13
+ * Represents a security policy which need to be enforced when sandbox mode is enabled.
14
+ *
15
+ * @author Fabien Potencier <fabien@symfony.com>
16
+ */
17
+ class Twig_Sandbox_SecurityPolicy implements Twig_Sandbox_SecurityPolicyInterface
18
+ {
19
+ protected $allowedTags;
20
+ protected $allowedFilters;
21
+ protected $allowedMethods;
22
+ protected $allowedProperties;
23
+ protected $allowedFunctions;
24
+
25
+ public function __construct(array $allowedTags = array(), array $allowedFilters = array(), array $allowedMethods = array(), array $allowedProperties = array(), array $allowedFunctions = array())
26
+ {
27
+ $this->allowedTags = $allowedTags;
28
+ $this->allowedFilters = $allowedFilters;
29
+ $this->setAllowedMethods($allowedMethods);
30
+ $this->allowedProperties = $allowedProperties;
31
+ $this->allowedFunctions = $allowedFunctions;
32
+ }
33
+
34
+ public function setAllowedTags(array $tags)
35
+ {
36
+ $this->allowedTags = $tags;
37
+ }
38
+
39
+ public function setAllowedFilters(array $filters)
40
+ {
41
+ $this->allowedFilters = $filters;
42
+ }
43
+
44
+ public function setAllowedMethods(array $methods)
45
+ {
46
+ $this->allowedMethods = array();
47
+ foreach ($methods as $class => $m) {
48
+ $this->allowedMethods[$class] = array_map('strtolower', is_array($m) ? $m : array($m));
49
+ }
50
+ }
51
+
52
+ public function setAllowedProperties(array $properties)
53
+ {
54
+ $this->allowedProperties = $properties;
55
+ }
56
+
57
+ public function setAllowedFunctions(array $functions)
58
+ {
59
+ $this->allowedFunctions = $functions;
60
+ }
61
+
62
+ public function checkSecurity($tags, $filters, $functions)
63
+ {
64
+ foreach ($tags as $tag) {
65
+ if (!in_array($tag, $this->allowedTags)) {
66
+ throw new Twig_Sandbox_SecurityError(sprintf('Tag "%s" is not allowed.', $tag));
67
+ }
68
+ }
69
+
70
+ foreach ($filters as $filter) {
71
+ if (!in_array($filter, $this->allowedFilters)) {
72
+ throw new Twig_Sandbox_SecurityError(sprintf('Filter "%s" is not allowed.', $filter));
73
+ }
74
+ }
75
+
76
+ foreach ($functions as $function) {
77
+ if (!in_array($function, $this->allowedFunctions)) {
78
+ throw new Twig_Sandbox_SecurityError(sprintf('Function "%s" is not allowed.', $function));
79
+ }
80
+ }
81
+ }
82
+
83
+ public function checkMethodAllowed($obj, $method)
84
+ {
85
+ if ($obj instanceof Twig_TemplateInterface || $obj instanceof Twig_Markup) {
86
+ return true;
87
+ }
88
+
89
+ $allowed = false;
90
+ $method = strtolower($method);
91
+ foreach ($this->allowedMethods as $class => $methods) {
92
+ if ($obj instanceof $class) {
93
+ $allowed = in_array($method, $methods);
94
+
95
+ break;
96
+ }
97
+ }
98
+
99
+ if (!$allowed) {
100
+ throw new Twig_Sandbox_SecurityError(sprintf('Calling "%s" method on a "%s" object is not allowed.', $method, get_class($obj)));
101
+ }
102
+ }
103
+
104
+ public function checkPropertyAllowed($obj, $property)
105
+ {
106
+ $allowed = false;
107
+ foreach ($this->allowedProperties as $class => $properties) {
108
+ if ($obj instanceof $class) {
109
+ $allowed = in_array($property, is_array($properties) ? $properties : array($properties));
110
+
111
+ break;
112
+ }
113
+ }
114
+
115
+ if (!$allowed) {
116
+ throw new Twig_Sandbox_SecurityError(sprintf('Calling "%s" property on a "%s" object is not allowed.', $property, get_class($obj)));
117
+ }
118
+ }
119
+ }
classes/Twig/Sandbox/SecurityPolicyInterface.php CHANGED
@@ -1,24 +1,24 @@
1
- <?php
2
-
3
- /*
4
- * This file is part of Twig.
5
- *
6
- * (c) 2009 Fabien Potencier
7
- *
8
- * For the full copyright and license information, please view the LICENSE
9
- * file that was distributed with this source code.
10
- */
11
-
12
- /**
13
- * Interfaces that all security policy classes must implements.
14
- *
15
- * @author Fabien Potencier <fabien@symfony.com>
16
- */
17
- interface Twig_Sandbox_SecurityPolicyInterface
18
- {
19
- public function checkSecurity($tags, $filters, $functions);
20
-
21
- public function checkMethodAllowed($obj, $method);
22
-
23
- public function checkPropertyAllowed($obj, $method);
24
- }
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2009 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ /**
13
+ * Interfaces that all security policy classes must implements.
14
+ *
15
+ * @author Fabien Potencier <fabien@symfony.com>
16
+ */
17
+ interface Twig_Sandbox_SecurityPolicyInterface
18
+ {
19
+ public function checkSecurity($tags, $filters, $functions);
20
+
21
+ public function checkMethodAllowed($obj, $method);
22
+
23
+ public function checkPropertyAllowed($obj, $method);
24
+ }
classes/Twig/SimpleFilter.php CHANGED
@@ -1,94 +1,94 @@
1
- <?php
2
-
3
- /*
4
- * This file is part of Twig.
5
- *
6
- * (c) 2009-2012 Fabien Potencier
7
- *
8
- * For the full copyright and license information, please view the LICENSE
9
- * file that was distributed with this source code.
10
- */
11
-
12
- /**
13
- * Represents a template filter.
14
- *
15
- * @author Fabien Potencier <fabien@symfony.com>
16
- */
17
- class Twig_SimpleFilter
18
- {
19
- protected $name;
20
- protected $callable;
21
- protected $options;
22
- protected $arguments = array();
23
-
24
- public function __construct($name, $callable, array $options = array())
25
- {
26
- $this->name = $name;
27
- $this->callable = $callable;
28
- $this->options = array_merge(array(
29
- 'needs_environment' => false,
30
- 'needs_context' => false,
31
- 'is_safe' => null,
32
- 'is_safe_callback' => null,
33
- 'pre_escape' => null,
34
- 'preserves_safety' => null,
35
- 'node_class' => 'Twig_Node_Expression_Filter',
36
- ), $options);
37
- }
38
-
39
- public function getName()
40
- {
41
- return $this->name;
42
- }
43
-
44
- public function getCallable()
45
- {
46
- return $this->callable;
47
- }
48
-
49
- public function getNodeClass()
50
- {
51
- return $this->options['node_class'];
52
- }
53
-
54
- public function setArguments($arguments)
55
- {
56
- $this->arguments = $arguments;
57
- }
58
-
59
- public function getArguments()
60
- {
61
- return $this->arguments;
62
- }
63
-
64
- public function needsEnvironment()
65
- {
66
- return $this->options['needs_environment'];
67
- }
68
-
69
- public function needsContext()
70
- {
71
- return $this->options['needs_context'];
72
- }
73
-
74
- public function getSafe(Twig_Node $filterArgs)
75
- {
76
- if (null !== $this->options['is_safe']) {
77
- return $this->options['is_safe'];
78
- }
79
-
80
- if (null !== $this->options['is_safe_callback']) {
81
- return call_user_func($this->options['is_safe_callback'], $filterArgs);
82
- }
83
- }
84
-
85
- public function getPreservesSafety()
86
- {
87
- return $this->options['preserves_safety'];
88
- }
89
-
90
- public function getPreEscape()
91
- {
92
- return $this->options['pre_escape'];
93
- }
94
- }
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2009-2012 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ /**
13
+ * Represents a template filter.
14
+ *
15
+ * @author Fabien Potencier <fabien@symfony.com>
16
+ */
17
+ class Twig_SimpleFilter
18
+ {
19
+ protected $name;
20
+ protected $callable;
21
+ protected $options;
22
+ protected $arguments = array();
23
+
24
+ public function __construct($name, $callable, array $options = array())
25
+ {
26
+ $this->name = $name;
27
+ $this->callable = $callable;
28
+ $this->options = array_merge(array(
29
+ 'needs_environment' => false,
30
+ 'needs_context' => false,
31
+ 'is_safe' => null,
32
+ 'is_safe_callback' => null,
33
+ 'pre_escape' => null,
34
+ 'preserves_safety' => null,
35
+ 'node_class' => 'Twig_Node_Expression_Filter',
36
+ ), $options);
37
+ }
38
+
39
+ public function getName()
40
+ {
41
+ return $this->name;
42
+ }
43
+
44
+ public function getCallable()
45
+ {
46
+ return $this->callable;
47
+ }
48
+
49
+ public function getNodeClass()
50
+ {
51
+ return $this->options['node_class'];
52
+ }
53
+
54
+ public function setArguments($arguments)
55
+ {
56
+ $this->arguments = $arguments;
57
+ }
58
+
59
+ public function getArguments()
60
+ {
61
+ return $this->arguments;
62
+ }
63
+
64
+ public function needsEnvironment()
65
+ {
66
+ return $this->options['needs_environment'];
67
+ }
68
+
69
+ public function needsContext()
70
+ {
71
+ return $this->options['needs_context'];
72
+ }
73
+
74
+ public function getSafe(Twig_Node $filterArgs)
75
+ {
76
+ if (null !== $this->options['is_safe']) {
77
+ return $this->options['is_safe'];
78
+ }
79
+
80
+ if (null !== $this->options['is_safe_callback']) {
81
+ return call_user_func($this->options['is_safe_callback'], $filterArgs);
82
+ }
83
+ }
84
+
85
+ public function getPreservesSafety()
86
+ {
87
+ return $this->options['preserves_safety'];
88
+ }
89
+
90
+ public function getPreEscape()
91
+ {
92
+ return $this->options['pre_escape'];
93
+ }
94
+ }
classes/Twig/SimpleFunction.php CHANGED
@@ -1,84 +1,84 @@
1
- <?php
2
-
3
- /*
4
- * This file is part of Twig.
5
- *
6
- * (c) 2010-2012 Fabien Potencier
7
- *
8
- * For the full copyright and license information, please view the LICENSE
9
- * file that was distributed with this source code.
10
- */
11
-
12
- /**
13
- * Represents a template function.
14
- *
15
- * @author Fabien Potencier <fabien@symfony.com>
16
- */
17
- class Twig_SimpleFunction
18
- {
19
- protected $name;
20
- protected $callable;
21
- protected $options;
22
- protected $arguments = array();
23
-
24
- public function __construct($name, $callable, array $options = array())
25
- {
26
- $this->name = $name;
27
- $this->callable = $callable;
28
- $this->options = array_merge(array(
29
- 'needs_environment' => false,
30
- 'needs_context' => false,
31
- 'is_safe' => null,
32
- 'is_safe_callback' => null,
33
- 'node_class' => 'Twig_Node_Expression_Function',
34
- ), $options);
35
- }
36
-
37
- public function getName()
38
- {
39
- return $this->name;
40
- }
41
-
42
- public function getCallable()
43
- {
44
- return $this->callable;
45
- }
46
-
47
- public function getNodeClass()
48
- {
49
- return $this->options['node_class'];
50
- }
51
-
52
- public function setArguments($arguments)
53
- {
54
- $this->arguments = $arguments;
55
- }
56
-
57
- public function getArguments()
58
- {
59
- return $this->arguments;
60
- }
61
-
62
- public function needsEnvironment()
63
- {
64
- return $this->options['needs_environment'];
65
- }
66
-
67
- public function needsContext()
68
- {
69
- return $this->options['needs_context'];
70
- }
71
-
72
- public function getSafe(Twig_Node $functionArgs)
73
- {
74
- if (null !== $this->options['is_safe']) {
75
- return $this->options['is_safe'];
76
- }
77
-
78
- if (null !== $this->options['is_safe_callback']) {
79
- return call_user_func($this->options['is_safe_callback'], $functionArgs);
80
- }
81
-
82
- return array();
83
- }
84
- }
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2010-2012 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ /**
13
+ * Represents a template function.
14
+ *
15
+ * @author Fabien Potencier <fabien@symfony.com>
16
+ */
17
+ class Twig_SimpleFunction
18
+ {
19
+ protected $name;
20
+ protected $callable;
21
+ protected $options;
22
+ protected $arguments = array();
23
+
24
+ public function __construct($name, $callable, array $options = array())
25
+ {
26
+ $this->name = $name;
27
+ $this->callable = $callable;
28
+ $this->options = array_merge(array(
29
+ 'needs_environment' => false,
30
+ 'needs_context' => false,
31
+ 'is_safe' => null,
32
+ 'is_safe_callback' => null,
33
+ 'node_class' => 'Twig_Node_Expression_Function',
34
+ ), $options);
35
+ }
36
+
37
+ public function getName()
38
+ {
39
+ return $this->name;
40
+ }
41
+
42
+ public function getCallable()
43
+ {
44
+ return $this->callable;
45
+ }
46
+
47
+ public function getNodeClass()
48
+ {
49
+ return $this->options['node_class'];
50
+ }
51
+
52
+ public function setArguments($arguments)
53
+ {
54
+ $this->arguments = $arguments;
55
+ }
56
+
57
+ public function getArguments()
58
+ {
59
+ return $this->arguments;
60
+ }
61
+
62
+ public function needsEnvironment()
63
+ {
64
+ return $this->options['needs_environment'];
65
+ }
66
+
67
+ public function needsContext()
68
+ {
69
+ return $this->options['needs_context'];
70
+ }
71
+
72
+ public function getSafe(Twig_Node $functionArgs)
73
+ {
74
+ if (null !== $this->options['is_safe']) {
75
+ return $this->options['is_safe'];
76
+ }
77
+
78
+ if (null !== $this->options['is_safe_callback']) {
79
+ return call_user_func($this->options['is_safe_callback'], $functionArgs);
80
+ }
81
+
82
+ return array();
83
+ }
84
+ }
classes/Twig/SimpleTest.php CHANGED
@@ -1,46 +1,46 @@
1
- <?php
2
-
3
- /*
4
- * This file is part of Twig.
5
- *
6
- * (c) 2010-2012 Fabien Potencier
7
- *
8
- * For the full copyright and license information, please view the LICENSE
9
- * file that was distributed with this source code.
10
- */
11
-
12
- /**
13
- * Represents a template test.
14
- *
15
- * @author Fabien Potencier <fabien@symfony.com>
16
- */
17
- class Twig_SimpleTest
18
- {
19
- protected $name;
20
- protected $callable;
21
- protected $options;
22
-
23
- public function __construct($name, $callable, array $options = array())
24
- {
25
- $this->name = $name;
26
- $this->callable = $callable;
27
- $this->options = array_merge(array(
28
- 'node_class' => 'Twig_Node_Expression_Test',
29
- ), $options);
30
- }
31
-
32
- public function getName()
33
- {
34
- return $this->name;
35
- }
36
-
37
- public function getCallable()
38
- {
39
- return $this->callable;
40
- }
41
-
42
- public function getNodeClass()
43
- {
44
- return $this->options['node_class'];
45
- }
46
- }
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2010-2012 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ /**
13
+ * Represents a template test.
14
+ *
15
+ * @author Fabien Potencier <fabien@symfony.com>
16
+ */
17
+ class Twig_SimpleTest
18
+ {
19
+ protected $name;
20
+ protected $callable;
21
+ protected $options;
22
+
23
+ public function __construct($name, $callable, array $options = array())
24
+ {
25
+ $this->name = $name;
26
+ $this->callable = $callable;
27
+ $this->options = array_merge(array(
28
+ 'node_class' => 'Twig_Node_Expression_Test',
29
+ ), $options);
30
+ }
31
+
32
+ public function getName()
33
+ {
34
+ return $this->name;
35
+ }
36
+
37
+ public function getCallable()
38
+ {
39
+ return $this->callable;
40
+ }
41
+
42
+ public function getNodeClass()
43
+ {
44
+ return $this->options['node_class'];
45
+ }
46
+ }
classes/Twig/Template.php CHANGED
@@ -1,485 +1,485 @@
1
- <?php
2
-
3
- /*
4
- * This file is part of Twig.
5
- *
6
- * (c) 2009 Fabien Potencier
7
- * (c) 2009 Armin Ronacher
8
- *
9
- * For the full copyright and license information, please view the LICENSE
10
- * file that was distributed with this source code.
11
- */
12
-
13
- /**
14
- * Default base class for compiled templates.
15
- *
16
- * @author Fabien Potencier <fabien@symfony.com>
17
- */
18
- abstract class Twig_Template implements Twig_TemplateInterface
19
- {
20
- protected static $cache = array();
21
-
22
- protected $parent;
23
- protected $parents;
24
- protected $env;
25
- protected $blocks;
26
- protected $traits;
27
-
28
- /**
29
- * Constructor.
30
- *
31
- * @param Twig_Environment $env A Twig_Environment instance
32
- */
33
- public function __construct(Twig_Environment $env)
34
- {
35
- $this->env = $env;
36
- $this->blocks = array();
37
- $this->traits = array();
38
- }
39
-
40
- /**
41
- * Returns the template name.
42
- *
43
- * @return string The template name
44
- */
45
- abstract public function getTemplateName();
46
-
47
- /**
48
- * {@inheritdoc}
49
- */
50
- public function getEnvironment()
51
- {
52
- return $this->env;
53
- }
54
-
55
- /**
56
- * Returns the parent template.
57
- *
58
- * This method is for internal use only and should never be called
59
- * directly.
60
- *
61
- * @return Twig_TemplateInterface|false The parent template or false if there is no parent
62
- */
63
- public function getParent(array $context)
64
- {
65
- if (null !== $this->parent) {
66
- return $this->parent;
67
- }
68
-
69
- $parent = $this->doGetParent($context);
70
- if (false === $parent) {
71
- return false;
72
- } elseif ($parent instanceof Twig_Template) {
73
- $name = $parent->getTemplateName();
74
- $this->parents[$name] = $parent;
75
- $parent = $name;
76
- } elseif (!isset($this->parents[$parent])) {
77
- $this->parents[$parent] = $this->env->loadTemplate($parent);
78
- }
79
-
80
- return $this->parents[$parent];
81
- }
82
-
83
- protected function doGetParent(array $context)
84
- {
85
- return false;
86
- }
87
-
88
- public function isTraitable()
89
- {
90
- return true;
91
- }
92
-
93
- /**
94
- * Displays a parent block.
95
- *
96
- * This method is for internal use only and should never be called
97
- * directly.
98
- *
99
- * @param string $name The block name to display from the parent
100
- * @param array $context The context
101
- * @param array $blocks The current set of blocks
102
- */
103
- public function displayParentBlock($name, array $context, array $blocks = array())
104
- {
105
- $name = (string) $name;
106
-
107
- if (isset($this->traits[$name])) {
108
- $this->traits[$name][0]->displayBlock($name, $context, $blocks, false);
109
- } elseif (false !== $parent = $this->getParent($context)) {
110
- $parent->displayBlock($name, $context, $blocks, false);
111
- } else {
112
- throw new Twig_Error_Runtime(sprintf('The template has no parent and no traits defining the "%s" block', $name), -1, $this->getTemplateName());
113
- }
114
- }
115
-
116
- /**
117
- * Displays a block.
118
- *
119
- * This method is for internal use only and should never be called
120
- * directly.
121
- *
122
- * @param string $name The block name to display
123
- * @param array $context The context
124
- * @param array $blocks The current set of blocks
125
- * @param bool $useBlocks Whether to use the current set of blocks
126
- */
127
- public function displayBlock($name, array $context, array $blocks = array(), $useBlocks = true)
128
- {
129
- $name = (string) $name;
130
-
131
- if ($useBlocks && isset($blocks[$name])) {
132
- $template = $blocks[$name][0];
133
- $block = $blocks[$name][1];
134
- } elseif (isset($this->blocks[$name])) {
135
- $template = $this->blocks[$name][0];
136
- $block = $this->blocks[$name][1];
137
- } else {
138
- $template = null;
139
- $block = null;
140
- }
141
-
142
- if (null !== $template) {
143
- try {
144
- $template->$block($context, $blocks);
145
- } catch (Twig_Error $e) {
146
- throw $e;
147
- } catch (Exception $e) {
148
- throw new Twig_Error_Runtime(sprintf('An exception has been thrown during the rendering of a template ("%s").', $e->getMessage()), -1, $template->getTemplateName(), $e);
149
- }
150
- } elseif (false !== $parent = $this->getParent($context)) {
151
- $parent->displayBlock($name, $context, array_merge($this->blocks, $blocks), false);
152
- }
153
- }
154
-
155
- /**
156
- * Renders a parent block.
157
- *
158
- * This method is for internal use only and should never be called
159
- * directly.
160
- *
161
- * @param string $name The block name to render from the parent
162
- * @param array $context The context
163
- * @param array $blocks The current set of blocks
164
- *
165
- * @return string The rendered block
166
- */
167
- public function renderParentBlock($name, array $context, array $blocks = array())
168
- {
169
- ob_start();
170
- $this->displayParentBlock($name, $context, $blocks);
171
-
172
- return ob_get_clean();
173
- }
174
-
175
- /**
176
- * Renders a block.
177
- *
178
- * This method is for internal use only and should never be called
179
- * directly.
180
- *
181
- * @param string $name The block name to render
182
- * @param array $context The context
183
- * @param array $blocks The current set of blocks
184
- * @param bool $useBlocks Whether to use the current set of blocks
185
- *
186
- * @return string The rendered block
187
- */
188
- public function renderBlock($name, array $context, array $blocks = array(), $useBlocks = true)
189
- {
190
- ob_start();
191
- $this->displayBlock($name, $context, $blocks, $useBlocks);
192
-
193
- return ob_get_clean();
194
- }
195
-
196
- /**
197
- * Returns whether a block exists or not.
198
- *
199
- * This method is for internal use only and should never be called
200
- * directly.
201
- *
202
- * This method does only return blocks defined in the current template
203
- * or defined in "used" traits.
204
- *
205
- * It does not return blocks from parent templates as the parent
206
- * template name can be dynamic, which is only known based on the
207
- * current context.
208
- *
209
- * @param string $name The block name
210
- *
211
- * @return bool true if the block exists, false otherwise
212
- */
213
- public function hasBlock($name)
214
- {
215
- return isset($this->blocks[(string) $name]);
216
- }
217
-
218
- /**
219
- * Returns all block names.
220
- *
221
- * This method is for internal use only and should never be called
222
- * directly.
223
- *
224
- * @return array An array of block names
225
- *
226
- * @see hasBlock
227
- */
228
- public function getBlockNames()
229
- {
230
- return array_keys($this->blocks);
231
- }
232
-
233
- /**
234
- * Returns all blocks.
235
- *
236
- * This method is for internal use only and should never be called
237
- * directly.
238
- *
239
- * @return array An array of blocks
240
- *
241
- * @see hasBlock
242
- */
243
- public function getBlocks()
244
- {
245
- return $this->blocks;
246
- }
247
-
248
- /**
249
- * {@inheritdoc}
250
- */
251
- public function display(array $context, array $blocks = array())
252
- {
253
- $this->displayWithErrorHandling($this->env->mergeGlobals($context), array_merge($this->blocks, $blocks));
254
- }
255
-
256
- /**
257
- * {@inheritdoc}
258
- */
259
- public function render(array $context)
260
- {
261
- $level = ob_get_level();
262
- ob_start();
263
- try {
264
- $this->display($context);
265
- } catch (Exception $e) {
266
- while (ob_get_level() > $level) {
267
- ob_end_clean();
268
- }
269
-
270
- throw $e;
271
- }
272
-
273
- return ob_get_clean();
274
- }
275
-
276
- protected function displayWithErrorHandling(array $context, array $blocks = array())
277
- {
278
- try {
279
- $this->doDisplay($context, $blocks);
280
- } catch (Twig_Error $e) {
281
- if (!$e->getTemplateFile()) {
282
- $e->setTemplateFile($this->getTemplateName());
283
- }
284
-
285
- // this is mostly useful for Twig_Error_Loader exceptions
286
- // see Twig_Error_Loader
287
- if (false === $e->getTemplateLine()) {
288
- $e->setTemplateLine(-1);
289
- $e->guess();
290
- }
291
-
292
- throw $e;
293
- } catch (Exception $e) {
294
- throw new Twig_Error_Runtime(sprintf('An exception has been thrown during the rendering of a template ("%s").', $e->getMessage()), -1, $this->getTemplateName(), $e);
295
- }
296
- }
297
-
298
- /**
299
- * Auto-generated method to display the template with the given context.
300
- *
301
- * @param array $context An array of parameters to pass to the template
302
- * @param array $blocks An array of blocks to pass to the template
303
- */
304
- abstract protected function doDisplay(array $context, array $blocks = array());
305
-
306
- /**
307
- * Returns a variable from the context.
308
- *
309
- * This method is for internal use only and should never be called
310
- * directly.
311
- *
312
- * This method should not be overridden in a sub-class as this is an
313
- * implementation detail that has been introduced to optimize variable
314
- * access for versions of PHP before 5.4. This is not a way to override
315
- * the way to get a variable value.
316
- *
317
- * @param array $context The context
318
- * @param string $item The variable to return from the context
319
- * @param bool $ignoreStrictCheck Whether to ignore the strict variable check or not
320
- *
321
- * @return The content of the context variable
322
- *
323
- * @throws Twig_Error_Runtime if the variable does not exist and Twig is running in strict mode
324
- */
325
- final protected function getContext($context, $item, $ignoreStrictCheck = false)
326
- {
327
- if (!array_key_exists($item, $context)) {
328
- if ($ignoreStrictCheck || !$this->env->isStrictVariables()) {
329
- return;
330
- }
331
-
332
- throw new Twig_Error_Runtime(sprintf('Variable "%s" does not exist', $item), -1, $this->getTemplateName());
333
- }
334
-
335
- return $context[$item];
336
- }
337
-
338
- /**
339
- * Returns the attribute value for a given array/object.
340
- *
341
- * @param mixed $object The object or array from where to get the item
342
- * @param mixed $item The item to get from the array or object
343
- * @param array $arguments An array of arguments to pass if the item is an object method
344
- * @param string $type The type of attribute (@see Twig_Template constants)
345
- * @param bool $isDefinedTest Whether this is only a defined check
346
- * @param bool $ignoreStrictCheck Whether to ignore the strict attribute check or not
347
- *
348
- * @return mixed The attribute value, or a Boolean when $isDefinedTest is true, or null when the attribute is not set and $ignoreStrictCheck is true
349
- *
350
- * @throws Twig_Error_Runtime if the attribute does not exist and Twig is running in strict mode and $isDefinedTest is false
351
- */
352
- protected function getAttribute($object, $item, array $arguments = array(), $type = Twig_Template::ANY_CALL, $isDefinedTest = false, $ignoreStrictCheck = false)
353
- {
354
- // array
355
- if (Twig_Template::METHOD_CALL !== $type) {
356
- $arrayItem = is_bool($item) || is_float($item) ? (int) $item : $item;
357
-
358
- if ((is_array($object) && array_key_exists($arrayItem, $object))
359
- || ($object instanceof ArrayAccess && isset($object[$arrayItem]))
360
- ) {
361
- if ($isDefinedTest) {
362
- return true;
363
- }
364
-
365
- return $object[$arrayItem];
366
- }
367
-
368
- if (Twig_Template::ARRAY_CALL === $type || !is_object($object)) {
369
- if ($isDefinedTest) {
370
- return false;
371
- }
372
-
373
- if ($ignoreStrictCheck || !$this->env->isStrictVariables()) {
374
- return;
375
- }
376
-
377
- if ($object instanceof ArrayAccess) {
378
- $message = sprintf('Key "%s" in object with ArrayAccess of class "%s" does not exist', $arrayItem, get_class($object));
379
- } elseif (is_object($object)) {
380
- $message = sprintf('Impossible to access a key "%s" on an object of class "%s" that does not implement ArrayAccess interface', $item, get_class($object));
381
- } elseif (is_array($object)) {
382
- $message = sprintf('Key "%s" for array with keys "%s" does not exist', $arrayItem, implode(', ', array_keys($object)));
383
- } elseif (Twig_Template::ARRAY_CALL === $type) {
384
- $message = sprintf('Impossible to access a key ("%s") on a %s variable ("%s")', $item, gettype($object), $object);
385
- } else {
386
- $message = sprintf('Impossible to access an attribute ("%s") on a %s variable ("%s")', $item, gettype($object), $object);
387
- }
388
-
389
- throw new Twig_Error_Runtime($message, -1, $this->getTemplateName());
390
- }
391
- }
392
-
393
- if (!is_object($object)) {
394
- if ($isDefinedTest) {
395
- return false;
396
- }
397
-
398
- if ($ignoreStrictCheck || !$this->env->isStrictVariables()) {
399
- return;
400
- }
401
-
402
- throw new Twig_Error_Runtime(sprintf('Impossible to invoke a method ("%s") on a %s variable ("%s")', $item, gettype($object), $object), -1, $this->getTemplateName());
403
- }
404
-
405
- // object property
406
- if (Twig_Template::METHOD_CALL !== $type) {
407
- if (isset($object->$item) || array_key_exists((string) $item, $object)) {
408
- if ($isDefinedTest) {
409
- return true;
410
- }
411
-
412
- if ($this->env->hasExtension('sandbox')) {
413
- $this->env->getExtension('sandbox')->checkPropertyAllowed($object, $item);
414
- }
415
-
416
- return $object->$item;
417
- }
418
- }
419
-
420
- $class = get_class($object);
421
-
422
- // object method
423
- if (!isset(self::$cache[$class]['methods'])) {
424
- self::$cache[$class]['methods'] = array_change_key_case(array_flip(get_class_methods($object)));
425
- }
426
-
427
- $call = false;
428
- $lcItem = strtolower($item);
429
- if (isset(self::$cache[$class]['methods'][$lcItem])) {
430
- $method = (string) $item;
431
- } elseif (isset(self::$cache[$class]['methods']['get'.$lcItem])) {
432
- $method = 'get'.$item;
433
- } elseif (isset(self::$cache[$class]['methods']['is'.$lcItem])) {
434
- $method = 'is'.$item;
435
- } elseif (isset(self::$cache[$class]['methods']['__call'])) {
436
- $method = (string) $item;
437
- $call = true;
438
- } else {
439
- if ($isDefinedTest) {
440
- return false;
441
- }
442
-
443
- if ($ignoreStrictCheck || !$this->env->isStrictVariables()) {
444
- return;
445
- }
446
-
447
- throw new Twig_Error_Runtime(sprintf('Method "%s" for object "%s" does not exist', $item, get_class($object)), -1, $this->getTemplateName());
448
- }
449
-
450
- if ($isDefinedTest) {
451
- return true;
452
- }
453
-
454
- if ($this->env->hasExtension('sandbox')) {
455
- $this->env->getExtension('sandbox')->checkMethodAllowed($object, $method);
456
- }
457
-
458
- // Some objects throw exceptions when they have __call, and the method we try
459
- // to call is not supported. If ignoreStrictCheck is true, we should return null.
460
- try {
461
- $ret = call_user_func_array(array($object, $method), $arguments);
462
- } catch (BadMethodCallException $e) {
463
- if ($call && ($ignoreStrictCheck || !$this->env->isStrictVariables())) {
464
- return;
465
- }
466
- throw $e;
467
- }
468
-
469
- // useful when calling a template method from a template
470
- // this is not supported but unfortunately heavily used in the Symfony profiler
471
- if ($object instanceof Twig_TemplateInterface) {
472
- return $ret === '' ? '' : new Twig_Markup($ret, $this->env->getCharset());
473
- }
474
-
475
- return $ret;
476
- }
477
-
478
- /**
479
- * This method is only useful when testing Twig. Do not use it.
480
- */
481
- public static function clearCache()
482
- {
483
- self::$cache = array();
484
- }
485
- }
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2009 Fabien Potencier
7
+ * (c) 2009 Armin Ronacher
8
+ *
9
+ * For the full copyright and license information, please view the LICENSE
10
+ * file that was distributed with this source code.
11
+ */
12
+
13
+ /**
14
+ * Default base class for compiled templates.
15
+ *
16
+ * @author Fabien Potencier <fabien@symfony.com>
17
+ */
18
+ abstract class Twig_Template implements Twig_TemplateInterface
19
+ {
20
+ protected static $cache = array();
21
+
22
+ protected $parent;
23
+ protected $parents;
24
+ protected $env;
25
+ protected $blocks;
26
+ protected $traits;
27
+
28
+ /**
29
+ * Constructor.
30
+ *
31
+ * @param Twig_Environment $env A Twig_Environment instance
32
+ */
33
+ public function __construct(Twig_Environment $env)
34
+ {
35
+ $this->env = $env;
36
+ $this->blocks = array();
37
+ $this->traits = array();
38
+ }
39
+
40
+ /**
41
+ * Returns the template name.
42
+ *
43
+ * @return string The template name
44
+ */
45
+ abstract public function getTemplateName();
46
+
47
+ /**
48
+ * {@inheritdoc}
49
+ */
50
+ public function getEnvironment()
51
+ {
52
+ return $this->env;
53
+ }
54
+
55
+ /**
56
+ * Returns the parent template.
57
+ *
58
+ * This method is for internal use only and should never be called
59
+ * directly.
60
+ *
61
+ * @return Twig_TemplateInterface|false The parent template or false if there is no parent
62
+ */
63
+ public function getParent(array $context)
64
+ {
65
+ if (null !== $this->parent) {
66
+ return $this->parent;
67
+ }
68
+
69
+ $parent = $this->doGetParent($context);
70
+ if (false === $parent) {
71
+ return false;
72
+ } elseif ($parent instanceof Twig_Template) {
73
+ $name = $parent->getTemplateName();
74
+ $this->parents[$name] = $parent;
75
+ $parent = $name;
76
+ } elseif (!isset($this->parents[$parent])) {
77
+ $this->parents[$parent] = $this->env->loadTemplate($parent);
78
+ }
79
+
80
+ return $this->parents[$parent];
81
+ }
82
+
83
+ protected function doGetParent(array $context)
84
+ {
85
+ return false;
86
+ }
87
+
88
+ public function isTraitable()
89
+ {
90
+ return true;
91
+ }
92
+
93
+ /**
94
+ * Displays a parent block.
95
+ *
96
+ * This method is for internal use only and should never be called
97
+ * directly.
98
+ *
99
+ * @param string $name The block name to display from the parent
100
+ * @param array $context The context
101
+ * @param array $blocks The current set of blocks
102
+ */
103
+ public function displayParentBlock($name, array $context, array $blocks = array())
104
+ {
105
+ $name = (string) $name;
106
+
107
+ if (isset($this->traits[$name])) {
108
+ $this->traits[$name][0]->displayBlock($name, $context, $blocks, false);
109
+ } elseif (false !== $parent = $this->getParent($context)) {
110
+ $parent->displayBlock($name, $context, $blocks, false);
111
+ } else {
112
+ throw new Twig_Error_Runtime(sprintf('The template has no parent and no traits defining the "%s" block', $name), -1, $this->getTemplateName());
113
+ }
114
+ }
115
+
116
+ /**
117
+ * Displays a block.
118
+ *
119
+ * This method is for internal use only and should never be called
120
+ * directly.
121
+ *
122
+ * @param string $name The block name to display
123
+ * @param array $context The context
124
+ * @param array $blocks The current set of blocks
125
+ * @param bool $useBlocks Whether to use the current set of blocks
126
+ */
127
+ public function displayBlock($name, array $context, array $blocks = array(), $useBlocks = true)
128
+ {
129
+ $name = (string) $name;
130
+
131
+ if ($useBlocks && isset($blocks[$name])) {
132
+ $template = $blocks[$name][0];
133
+ $block = $blocks[$name][1];
134
+ } elseif (isset($this->blocks[$name])) {
135
+ $template = $this->blocks[$name][0];
136
+ $block = $this->blocks[$name][1];
137
+ } else {
138
+ $template = null;
139
+ $block = null;
140
+ }
141
+
142
+ if (null !== $template) {
143
+ try {
144
+ $template->$block($context, $blocks);
145
+ } catch (Twig_Error $e) {
146
+ throw $e;
147
+ } catch (Exception $e) {
148
+ throw new Twig_Error_Runtime(sprintf('An exception has been thrown during the rendering of a template ("%s").', $e->getMessage()), -1, $template->getTemplateName(), $e);
149
+ }
150
+ } elseif (false !== $parent = $this->getParent($context)) {
151
+ $parent->displayBlock($name, $context, array_merge($this->blocks, $blocks), false);
152
+ }
153
+ }
154
+
155
+ /**
156
+ * Renders a parent block.
157
+ *
158
+ * This method is for internal use only and should never be called
159
+ * directly.
160
+ *
161
+ * @param string $name The block name to render from the parent
162
+ * @param array $context The context
163
+ * @param array $blocks The current set of blocks
164
+ *
165
+ * @return string The rendered block
166
+ */
167
+ public function renderParentBlock($name, array $context, array $blocks = array())
168
+ {
169
+ ob_start();
170
+ $this->displayParentBlock($name, $context, $blocks);
171
+
172
+ return ob_get_clean();
173
+ }
174
+
175
+ /**
176
+ * Renders a block.
177
+ *
178
+ * This method is for internal use only and should never be called
179
+ * directly.
180
+ *
181
+ * @param string $name The block name to render
182
+ * @param array $context The context
183
+ * @param array $blocks The current set of blocks
184
+ * @param bool $useBlocks Whether to use the current set of blocks
185
+ *
186
+ * @return string The rendered block
187
+ */
188
+ public function renderBlock($name, array $context, array $blocks = array(), $useBlocks = true)
189
+ {
190
+ ob_start();
191
+ $this->displayBlock($name, $context, $blocks, $useBlocks);
192
+
193
+ return ob_get_clean();
194
+ }
195
+
196
+ /**
197
+ * Returns whether a block exists or not.
198
+ *
199
+ * This method is for internal use only and should never be called
200
+ * directly.
201
+ *
202
+ * This method does only return blocks defined in the current template
203
+ * or defined in "used" traits.
204
+ *
205
+ * It does not return blocks from parent templates as the parent
206
+ * template name can be dynamic, which is only known based on the
207
+ * current context.
208
+ *
209
+ * @param string $name The block name
210
+ *
211
+ * @return bool true if the block exists, false otherwise
212
+ */
213
+ public function hasBlock($name)
214
+ {
215
+ return isset($this->blocks[(string) $name]);
216
+ }
217
+
218
+ /**
219
+ * Returns all block names.
220
+ *
221
+ * This method is for internal use only and should never be called
222
+ * directly.
223
+ *
224
+ * @return array An array of block names
225
+ *
226
+ * @see hasBlock
227
+ */
228
+ public function getBlockNames()
229
+ {
230
+ return array_keys($this->blocks);
231
+ }
232
+
233
+ /**
234
+ * Returns all blocks.
235
+ *
236
+ * This method is for internal use only and should never be called
237
+ * directly.
238
+ *
239
+ * @return array An array of blocks
240
+ *
241
+ * @see hasBlock
242
+ */
243
+ public function getBlocks()
244
+ {
245
+ return $this->blocks;
246
+ }
247
+
248
+ /**
249
+ * {@inheritdoc}
250
+ */
251
+ public function display(array $context, array $blocks = array())
252
+ {
253
+ $this->displayWithErrorHandling($this->env->mergeGlobals($context), array_merge($this->blocks, $blocks));
254
+ }
255
+
256
+ /**
257
+ * {@inheritdoc}
258
+ */
259
+ public function render(array $context)
260
+ {
261
+ $level = ob_get_level();
262
+ ob_start();
263
+ try {
264
+ $this->display($context);
265
+ } catch (Exception $e) {
266
+ while (ob_get_level() > $level) {
267
+ ob_end_clean();
268
+ }
269
+
270
+ throw $e;
271
+ }
272
+
273
+ return ob_get_clean();
274
+ }
275
+
276
+ protected function displayWithErrorHandling(array $context, array $blocks = array())
277
+ {
278
+ try {
279
+ $this->doDisplay($context, $blocks);
280
+ } catch (Twig_Error $e) {
281
+ if (!$e->getTemplateFile()) {
282
+ $e->setTemplateFile($this->getTemplateName());
283
+ }
284
+
285
+ // this is mostly useful for Twig_Error_Loader exceptions
286
+ // see Twig_Error_Loader
287
+ if (false === $e->getTemplateLine()) {
288
+ $e->setTemplateLine(-1);
289
+ $e->guess();
290
+ }
291
+
292
+ throw $e;
293
+ } catch (Exception $e) {
294
+ throw new Twig_Error_Runtime(sprintf('An exception has been thrown during the rendering of a template ("%s").', $e->getMessage()), -1, $this->getTemplateName(), $e);
295
+ }
296
+ }
297
+
298
+ /**
299
+ * Auto-generated method to display the template with the given context.
300
+ *
301
+ * @param array $context An array of parameters to pass to the template
302
+ * @param array $blocks An array of blocks to pass to the template
303
+ */
304
+ abstract protected function doDisplay(array $context, array $blocks = array());
305
+
306
+ /**
307
+ * Returns a variable from the context.
308
+ *
309
+ * This method is for internal use only and should never be called
310
+ * directly.
311
+ *
312
+ * This method should not be overridden in a sub-class as this is an
313
+ * implementation detail that has been introduced to optimize variable
314
+ * access for versions of PHP before 5.4. This is not a way to override
315
+ * the way to get a variable value.
316
+ *
317
+ * @param array $context The context
318
+ * @param string $item The variable to return from the context
319
+ * @param bool $ignoreStrictCheck Whether to ignore the strict variable check or not
320
+ *
321
+ * @return The content of the context variable
322
+ *
323
+ * @throws Twig_Error_Runtime if the variable does not exist and Twig is running in strict mode
324
+ */
325
+ final protected function getContext($context, $item, $ignoreStrictCheck = false)
326
+ {
327
+ if (!array_key_exists($item, $context)) {
328
+ if ($ignoreStrictCheck || !$this->env->isStrictVariables()) {
329
+ return;
330
+ }
331
+
332
+ throw new Twig_Error_Runtime(sprintf('Variable "%s" does not exist', $item), -1, $this->getTemplateName());
333
+ }
334
+
335
+ return $context[$item];
336
+ }
337
+
338
+ /**
339
+ * Returns the attribute value for a given array/object.
340
+ *
341
+ * @param mixed $object The object or array from where to get the item
342
+ * @param mixed $item The item to get from the array or object
343
+ * @param array $arguments An array of arguments to pass if the item is an object method
344
+ * @param string $type The type of attribute (@see Twig_Template constants)
345
+ * @param bool $isDefinedTest Whether this is only a defined check
346
+ * @param bool $ignoreStrictCheck Whether to ignore the strict attribute check or not
347
+ *
348
+ * @return mixed The attribute value, or a Boolean when $isDefinedTest is true, or null when the attribute is not set and $ignoreStrictCheck is true
349
+ *
350
+ * @throws Twig_Error_Runtime if the attribute does not exist and Twig is running in strict mode and $isDefinedTest is false
351
+ */
352
+ protected function getAttribute($object, $item, array $arguments = array(), $type = Twig_Template::ANY_CALL, $isDefinedTest = false, $ignoreStrictCheck = false)
353
+ {
354
+ // array
355
+ if (Twig_Template::METHOD_CALL !== $type) {
356
+ $arrayItem = is_bool($item) || is_float($item) ? (int) $item : $item;
357
+
358
+ if ((is_array($object) && array_key_exists($arrayItem, $object))
359
+ || ($object instanceof ArrayAccess && isset($object[$arrayItem]))
360
+ ) {
361
+ if ($isDefinedTest) {
362
+ return true;
363
+ }
364
+
365
+ return $object[$arrayItem];
366
+ }
367
+
368
+ if (Twig_Template::ARRAY_CALL === $type || !is_object($object)) {
369
+ if ($isDefinedTest) {
370
+ return false;
371
+ }
372
+
373
+ if ($ignoreStrictCheck || !$this->env->isStrictVariables()) {
374
+ return;
375
+ }
376
+
377
+ if ($object instanceof ArrayAccess) {
378
+ $message = sprintf('Key "%s" in object with ArrayAccess of class "%s" does not exist', $arrayItem, get_class($object));
379
+ } elseif (is_object($object)) {
380
+ $message = sprintf('Impossible to access a key "%s" on an object of class "%s" that does not implement ArrayAccess interface', $item, get_class($object));
381
+ } elseif (is_array($object)) {
382
+ $message = sprintf('Key "%s" for array with keys "%s" does not exist', $arrayItem, implode(', ', array_keys($object)));
383
+ } elseif (Twig_Template::ARRAY_CALL === $type) {
384
+ $message = sprintf('Impossible to access a key ("%s") on a %s variable ("%s")', $item, gettype($object), $object);
385
+ } else {
386
+ $message = sprintf('Impossible to access an attribute ("%s") on a %s variable ("%s")', $item, gettype($object), $object);
387
+ }
388
+
389
+ throw new Twig_Error_Runtime($message, -1, $this->getTemplateName());
390
+ }
391
+ }
392
+
393
+ if (!is_object($object)) {
394
+ if ($isDefinedTest) {
395
+ return false;
396
+ }
397
+
398
+ if ($ignoreStrictCheck || !$this->env->isStrictVariables()) {
399
+ return;
400
+ }
401
+
402
+ throw new Twig_Error_Runtime(sprintf('Impossible to invoke a method ("%s") on a %s variable ("%s")', $item, gettype($object), $object), -1, $this->getTemplateName());
403
+ }
404
+
405
+ // object property
406
+ if (Twig_Template::METHOD_CALL !== $type) {
407
+ if (isset($object->$item) || array_key_exists((string) $item, $object)) {
408
+ if ($isDefinedTest) {
409
+ return true;
410
+ }
411
+
412
+ if ($this->env->hasExtension('sandbox')) {
413
+ $this->env->getExtension('sandbox')->checkPropertyAllowed($object, $item);
414
+ }
415
+
416
+ return $object->$item;
417
+ }
418
+ }
419
+
420
+ $class = get_class($object);
421
+
422
+ // object method
423
+ if (!isset(self::$cache[$class]['methods'])) {
424
+ self::$cache[$class]['methods'] = array_change_key_case(array_flip(get_class_methods($object)));
425
+ }
426
+
427
+ $call = false;
428
+ $lcItem = strtolower($item);
429
+ if (isset(self::$cache[$class]['methods'][$lcItem])) {
430
+ $method = (string) $item;
431
+ } elseif (isset(self::$cache[$class]['methods']['get'.$lcItem])) {
432
+ $method = 'get'.$item;
433
+ } elseif (isset(self::$cache[$class]['methods']['is'.$lcItem])) {
434
+ $method = 'is'.$item;
435
+ } elseif (isset(self::$cache[$class]['methods']['__call'])) {
436
+ $method = (string) $item;
437
+ $call = true;
438
+ } else {
439
+ if ($isDefinedTest) {
440
+ return false;
441
+ }
442
+
443
+ if ($ignoreStrictCheck || !$this->env->isStrictVariables()) {
444
+ return;
445
+ }
446
+
447
+ throw new Twig_Error_Runtime(sprintf('Method "%s" for object "%s" does not exist', $item, get_class($object)), -1, $this->getTemplateName());
448
+ }
449
+
450
+ if ($isDefinedTest) {
451
+ return true;
452
+ }
453
+
454
+ if ($this->env->hasExtension('sandbox')) {
455
+ $this->env->getExtension('sandbox')->checkMethodAllowed($object, $method);
456
+ }
457
+
458
+ // Some objects throw exceptions when they have __call, and the method we try
459
+ // to call is not supported. If ignoreStrictCheck is true, we should return null.
460
+ try {
461
+ $ret = call_user_func_array(array($object, $method), $arguments);
462
+ } catch (BadMethodCallException $e) {
463
+ if ($call && ($ignoreStrictCheck || !$this->env->isStrictVariables())) {
464
+ return;
465
+ }
466
+ throw $e;
467
+ }
468
+
469
+ // useful when calling a template method from a template
470
+ // this is not supported but unfortunately heavily used in the Symfony profiler
471
+ if ($object instanceof Twig_TemplateInterface) {
472
+ return $ret === '' ? '' : new Twig_Markup($ret, $this->env->getCharset());
473
+ }
474
+
475
+ return $ret;
476
+ }
477
+
478
+ /**
479
+ * This method is only useful when testing Twig. Do not use it.
480
+ */
481
+ public static function clearCache()
482
+ {
483
+ self::$cache = array();
484
+ }
485
+ }
classes/Twig/TemplateInterface.php CHANGED
@@ -1,48 +1,48 @@
1
- <?php
2
-
3
- /*
4
- * This file is part of Twig.
5
- *
6
- * (c) 2009 Fabien Potencier
7
- *
8
- * For the full copyright and license information, please view the LICENSE
9
- * file that was distributed with this source code.
10
- */
11
-
12
- /**
13
- * Interface implemented by all compiled templates.
14
- *
15
- * @author Fabien Potencier <fabien@symfony.com>
16
- *
17
- * @deprecated since 1.12 (to be removed in 3.0)
18
- */
19
- interface Twig_TemplateInterface
20
- {
21
- const ANY_CALL = 'any';
22
- const ARRAY_CALL = 'array';
23
- const METHOD_CALL = 'method';
24
-
25
- /**
26
- * Renders the template with the given context and returns it as string.
27
- *
28
- * @param array $context An array of parameters to pass to the template
29
- *
30
- * @return string The rendered template
31
- */
32
- public function render(array $context);
33
-
34
- /**
35
- * Displays the template with the given context.
36
- *
37
- * @param array $context An array of parameters to pass to the template
38
- * @param array $blocks An array of blocks to pass to the template
39
- */
40
- public function display(array $context, array $blocks = array());
41
-
42
- /**
43
- * Returns the bound environment for this template.
44
- *
45
- * @return Twig_Environment The current environment
46
- */
47
- public function getEnvironment();
48
- }
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2009 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ /**
13
+ * Interface implemented by all compiled templates.
14
+ *
15
+ * @author Fabien Potencier <fabien@symfony.com>
16
+ *
17
+ * @deprecated since 1.12 (to be removed in 3.0)
18
+ */
19
+ interface Twig_TemplateInterface
20
+ {
21
+ const ANY_CALL = 'any';
22
+ const ARRAY_CALL = 'array';
23
+ const METHOD_CALL = 'method';
24
+
25
+ /**
26
+ * Renders the template with the given context and returns it as string.
27
+ *
28
+ * @param array $context An array of parameters to pass to the template
29
+ *
30
+ * @return string The rendered template
31
+ */
32
+ public function render(array $context);
33
+
34
+ /**
35
+ * Displays the template with the given context.
36
+ *
37
+ * @param array $context An array of parameters to pass to the template
38
+ * @param array $blocks An array of blocks to pass to the template
39
+ */
40
+ public function display(array $context, array $blocks = array());
41
+
42
+ /**
43
+ * Returns the bound environment for this template.
44
+ *
45
+ * @return Twig_Environment The current environment
46
+ */
47
+ public function getEnvironment();
48
+ }
classes/Twig/Test.php CHANGED
@@ -1,34 +1,34 @@
1
- <?php
2
-
3
- /*
4
- * This file is part of Twig.
5
- *
6
- * (c) 2012 Fabien Potencier
7
- *
8
- * For the full copyright and license information, please view the LICENSE
9
- * file that was distributed with this source code.
10
- */
11
-
12
- /**
13
- * Represents a template test.
14
- *
15
- * @author Fabien Potencier <fabien@symfony.com>
16
- * @deprecated since 1.12 (to be removed in 2.0)
17
- */
18
- abstract class Twig_Test implements Twig_TestInterface, Twig_TestCallableInterface
19
- {
20
- protected $options;
21
- protected $arguments = array();
22
-
23
- public function __construct(array $options = array())
24
- {
25
- $this->options = array_merge(array(
26
- 'callable' => null,
27
- ), $options);
28
- }
29
-
30
- public function getCallable()
31
- {
32
- return $this->options['callable'];
33
- }
34
- }
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2012 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ /**
13
+ * Represents a template test.
14
+ *
15
+ * @author Fabien Potencier <fabien@symfony.com>
16
+ * @deprecated since 1.12 (to be removed in 2.0)
17
+ */
18
+ abstract class Twig_Test implements Twig_TestInterface, Twig_TestCallableInterface
19
+ {
20
+ protected $options;
21
+ protected $arguments = array();
22
+
23
+ public function __construct(array $options = array())
24
+ {
25
+ $this->options = array_merge(array(
26
+ 'callable' => null,
27
+ ), $options);
28
+ }
29
+
30
+ public function getCallable()
31
+ {
32
+ return $this->options['callable'];
33
+ }
34
+ }
classes/Twig/TestCallableInterface.php CHANGED
@@ -1,21 +1,21 @@
1
- <?php
2
-
3
- /*
4
- * This file is part of Twig.
5
- *
6
- * (c) 2012 Fabien Potencier
7
- *
8
- * For the full copyright and license information, please view the LICENSE
9
- * file that was distributed with this source code.
10
- */
11
-
12
- /**
13
- * Represents a callable template test.
14
- *
15
- * @author Fabien Potencier <fabien@symfony.com>
16
- * @deprecated since 1.12 (to be removed in 2.0)
17
- */
18
- interface Twig_TestCallableInterface
19
- {
20
- public function getCallable();
21
- }
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2012 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ /**
13
+ * Represents a callable template test.
14
+ *
15
+ * @author Fabien Potencier <fabien@symfony.com>
16
+ * @deprecated since 1.12 (to be removed in 2.0)
17
+ */
18
+ interface Twig_TestCallableInterface
19
+ {
20
+ public function getCallable();
21
+ }
classes/Twig/TestInterface.php CHANGED
@@ -1,26 +1,26 @@
1
- <?php
2
-
3
- /*
4
- * This file is part of Twig.
5
- *
6
- * (c) 2010 Fabien Potencier
7
- *
8
- * For the full copyright and license information, please view the LICENSE
9
- * file that was distributed with this source code.
10
- */
11
-
12
- /**
13
- * Represents a template test.
14
- *
15
- * @author Fabien Potencier <fabien@symfony.com>
16
- * @deprecated since 1.12 (to be removed in 2.0)
17
- */
18
- interface Twig_TestInterface
19
- {
20
- /**
21
- * Compiles a test.
22
- *
23
- * @return string The PHP code for the test
24
- */
25
- public function compile();
26
- }
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2010 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ /**
13
+ * Represents a template test.
14
+ *
15
+ * @author Fabien Potencier <fabien@symfony.com>
16
+ * @deprecated since 1.12 (to be removed in 2.0)
17
+ */
18
+ interface Twig_TestInterface
19
+ {
20
+ /**
21
+ * Compiles a test.
22
+ *
23
+ * @return string The PHP code for the test
24
+ */
25
+ public function compile();
26
+ }
classes/Twig/Token.php CHANGED
@@ -1,216 +1,216 @@
1
- <?php
2
-
3
- /*
4
- * This file is part of Twig.
5
- *
6
- * (c) 2009 Fabien Potencier
7
- * (c) 2009 Armin Ronacher
8
- *
9
- * For the full copyright and license information, please view the LICENSE
10
- * file that was distributed with this source code.
11
- */
12
-
13
- /**
14
- * Represents a Token.
15
- *
16
- * @author Fabien Potencier <fabien@symfony.com>
17
- */
18
- class Twig_Token
19
- {
20
- protected $value;
21
- protected $type;
22
- protected $lineno;
23
-
24
- const EOF_TYPE = -1;
25
- const TEXT_TYPE = 0;
26
- const BLOCK_START_TYPE = 1;
27
- const VAR_START_TYPE = 2;
28
- const BLOCK_END_TYPE = 3;
29
- const VAR_END_TYPE = 4;
30
- const NAME_TYPE = 5;
31
- const NUMBER_TYPE = 6;
32
- const STRING_TYPE = 7;
33
- const OPERATOR_TYPE = 8;
34
- const PUNCTUATION_TYPE = 9;
35
- const INTERPOLATION_START_TYPE = 10;
36
- const INTERPOLATION_END_TYPE = 11;
37
-
38
- /**
39
- * Constructor.
40
- *
41
- * @param int $type The type of the token
42
- * @param string $value The token value
43
- * @param int $lineno The line position in the source
44
- */
45
- public function __construct($type, $value, $lineno)
46
- {
47
- $this->type = $type;
48
- $this->value = $value;
49
- $this->lineno = $lineno;
50
- }
51
-
52
- /**
53
- * Returns a string representation of the token.
54
- *
55
- * @return string A string representation of the token
56
- */
57
- public function __toString()
58
- {
59
- return sprintf('%s(%s)', self::typeToString($this->type, true), $this->value);
60
- }
61
-
62
- /**
63
- * Tests the current token for a type and/or a value.
64
- *
65
- * Parameters may be:
66
- * * just type
67
- * * type and value (or array of possible values)
68
- * * just value (or array of possible values) (NAME_TYPE is used as type)
69
- *
70
- * @param array|int $type The type to test
71
- * @param array|string|null $values The token value
72
- *
73
- * @return bool
74
- */
75
- public function test($type, $values = null)
76
- {
77
- if (null === $values && !is_int($type)) {
78
- $values = $type;
79
- $type = self::NAME_TYPE;
80
- }
81
-
82
- return ($this->type === $type) && (
83
- null === $values ||
84
- (is_array($values) && in_array($this->value, $values)) ||
85
- $this->value == $values
86
- );
87
- }
88
-
89
- /**
90
- * Gets the line.
91
- *
92
- * @return int The source line
93
- */
94
- public function getLine()
95
- {
96
- return $this->lineno;
97
- }
98
-
99
- /**
100
- * Gets the token type.
101
- *
102
- * @return int The token type
103
- */
104
- public function getType()
105
- {
106
- return $this->type;
107
- }
108
-
109
- /**
110
- * Gets the token value.
111
- *
112
- * @return string The token value
113
- */
114
- public function getValue()
115
- {
116
- return $this->value;
117
- }
118
-
119
- /**
120
- * Returns the constant representation (internal) of a given type.
121
- *
122
- * @param int $type The type as an integer
123
- * @param bool $short Whether to return a short representation or not
124
- *
125
- * @return string The string representation
126
- */
127
- public static function typeToString($type, $short = false)
128
- {
129
- switch ($type) {
130
- case self::EOF_TYPE:
131
- $name = 'EOF_TYPE';
132
- break;
133
- case self::TEXT_TYPE:
134
- $name = 'TEXT_TYPE';
135
- break;
136
- case self::BLOCK_START_TYPE:
137
- $name = 'BLOCK_START_TYPE';
138
- break;
139
- case self::VAR_START_TYPE:
140
- $name = 'VAR_START_TYPE';
141
- break;
142
- case self::BLOCK_END_TYPE:
143
- $name = 'BLOCK_END_TYPE';
144
- break;
145
- case self::VAR_END_TYPE:
146
- $name = 'VAR_END_TYPE';
147
- break;
148
- case self::NAME_TYPE:
149
- $name = 'NAME_TYPE';
150
- break;
151
- case self::NUMBER_TYPE:
152
- $name = 'NUMBER_TYPE';
153
- break;
154
- case self::STRING_TYPE:
155
- $name = 'STRING_TYPE';
156
- break;
157
- case self::OPERATOR_TYPE:
158
- $name = 'OPERATOR_TYPE';
159
- break;
160
- case self::PUNCTUATION_TYPE:
161
- $name = 'PUNCTUATION_TYPE';
162
- break;
163
- case self::INTERPOLATION_START_TYPE:
164
- $name = 'INTERPOLATION_START_TYPE';
165
- break;
166
- case self::INTERPOLATION_END_TYPE:
167
- $name = 'INTERPOLATION_END_TYPE';
168
- break;
169
- default:
170
- throw new LogicException(sprintf('Token of type "%s" does not exist.', $type));
171
- }
172
-
173
- return $short ? $name : 'Twig_Token::'.$name;
174
- }
175
-
176
- /**
177
- * Returns the english representation of a given type.
178
- *
179
- * @param int $type The type as an integer
180
- *
181
- * @return string The string representation
182
- */
183
- public static function typeToEnglish($type)
184
- {
185
- switch ($type) {
186
- case self::EOF_TYPE:
187
- return 'end of template';
188
- case self::TEXT_TYPE:
189
- return 'text';
190
- case self::BLOCK_START_TYPE:
191
- return 'begin of statement block';
192
- case self::VAR_START_TYPE:
193
- return 'begin of print statement';
194
- case self::BLOCK_END_TYPE:
195
- return 'end of statement block';
196
- case self::VAR_END_TYPE:
197
- return 'end of print statement';
198
- case self::NAME_TYPE:
199
- return 'name';
200
- case self::NUMBER_TYPE:
201
- return 'number';
202
- case self::STRING_TYPE:
203
- return 'string';
204
- case self::OPERATOR_TYPE:
205
- return 'operator';
206
- case self::PUNCTUATION_TYPE:
207
- return 'punctuation';
208
- case self::INTERPOLATION_START_TYPE:
209
- return 'begin of string interpolation';
210
- case self::INTERPOLATION_END_TYPE:
211
- return 'end of string interpolation';
212
- default:
213
- throw new LogicException(sprintf('Token of type "%s" does not exist.', $type));
214
- }
215
- }
216
- }
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2009 Fabien Potencier
7
+ * (c) 2009 Armin Ronacher
8
+ *
9
+ * For the full copyright and license information, please view the LICENSE
10
+ * file that was distributed with this source code.
11
+ */
12
+
13
+ /**
14
+ * Represents a Token.
15
+ *
16
+ * @author Fabien Potencier <fabien@symfony.com>
17
+ */
18
+ class Twig_Token
19
+ {
20
+ protected $value;
21
+ protected $type;
22
+ protected $lineno;
23
+
24
+ const EOF_TYPE = -1;
25
+ const TEXT_TYPE = 0;
26
+ const BLOCK_START_TYPE = 1;
27
+ const VAR_START_TYPE = 2;
28
+ const BLOCK_END_TYPE = 3;
29
+ const VAR_END_TYPE = 4;
30
+ const NAME_TYPE = 5;
31
+ const NUMBER_TYPE = 6;
32
+ const STRING_TYPE = 7;
33
+ const OPERATOR_TYPE = 8;
34
+ const PUNCTUATION_TYPE = 9;
35
+ const INTERPOLATION_START_TYPE = 10;
36
+ const INTERPOLATION_END_TYPE = 11;
37
+
38
+ /**
39
+ * Constructor.
40
+ *
41
+ * @param int $type The type of the token
42
+ * @param string $value The token value
43
+ * @param int $lineno The line position in the source
44
+ */
45
+ public function __construct($type, $value, $lineno)
46
+ {
47
+ $this->type = $type;
48
+ $this->value = $value;
49
+ $this->lineno = $lineno;
50
+ }
51
+
52
+ /**
53
+ * Returns a string representation of the token.
54
+ *
55
+ * @return string A string representation of the token
56
+ */
57
+ public function __toString()
58
+ {
59
+ return sprintf('%s(%s)', self::typeToString($this->type, true), $this->value);
60
+ }
61
+
62
+ /**
63
+ * Tests the current token for a type and/or a value.
64
+ *
65
+ * Parameters may be:
66
+ * * just type
67
+ * * type and value (or array of possible values)
68
+ * * just value (or array of possible values) (NAME_TYPE is used as type)
69
+ *
70
+ * @param array|int $type The type to test
71
+ * @param array|string|null $values The token value
72
+ *
73
+ * @return bool
74
+ */
75
+ public function test($type, $values = null)
76
+ {
77
+ if (null === $values && !is_int($type)) {
78
+ $values = $type;
79
+ $type = self::NAME_TYPE;
80
+ }
81
+
82
+ return ($this->type === $type) && (
83
+ null === $values ||
84
+ (is_array($values) && in_array($this->value, $values)) ||
85
+ $this->value == $values
86
+ );
87
+ }
88
+
89
+ /**
90
+ * Gets the line.
91
+ *
92
+ * @return int The source line
93
+ */
94
+ public function getLine()
95
+ {
96
+ return $this->lineno;
97
+ }
98
+
99
+ /**
100
+ * Gets the token type.
101
+ *
102
+ * @return int The token type
103
+ */
104
+ public function getType()
105
+ {
106
+ return $this->type;
107
+ }
108
+
109
+ /**
110
+ * Gets the token value.
111
+ *
112
+ * @return string The token value
113
+ */
114
+ public function getValue()
115
+ {
116
+ return $this->value;
117
+ }
118
+
119
+ /**
120
+ * Returns the constant representation (internal) of a given type.
121
+ *
122
+ * @param int $type The type as an integer
123
+ * @param bool $short Whether to return a short representation or not
124
+ *
125
+ * @return string The string representation
126
+ */
127
+ public static function typeToString($type, $short = false)
128
+ {
129
+ switch ($type) {
130
+ case self::EOF_TYPE:
131
+ $name = 'EOF_TYPE';
132
+ break;
133
+ case self::TEXT_TYPE:
134
+ $name = 'TEXT_TYPE';
135
+ break;
136
+ case self::BLOCK_START_TYPE:
137
+ $name = 'BLOCK_START_TYPE';
138
+ break;
139
+ case self::VAR_START_TYPE:
140
+ $name = 'VAR_START_TYPE';
141
+ break;
142
+ case self::BLOCK_END_TYPE:
143
+ $name = 'BLOCK_END_TYPE';
144
+ break;
145
+ case self::VAR_END_TYPE:
146
+ $name = 'VAR_END_TYPE';
147
+ break;
148
+ case self::NAME_TYPE:
149
+ $name = 'NAME_TYPE';
150
+ break;
151
+ case self::NUMBER_TYPE:
152
+ $name = 'NUMBER_TYPE';
153
+ break;
154
+ case self::STRING_TYPE:
155
+ $name = 'STRING_TYPE';
156
+ break;
157
+ case self::OPERATOR_TYPE:
158
+ $name = 'OPERATOR_TYPE';
159
+ break;
160
+ case self::PUNCTUATION_TYPE:
161
+ $name = 'PUNCTUATION_TYPE';
162
+ break;
163
+ case self::INTERPOLATION_START_TYPE:
164
+ $name = 'INTERPOLATION_START_TYPE';
165
+ break;
166
+ case self::INTERPOLATION_END_TYPE:
167
+ $name = 'INTERPOLATION_END_TYPE';
168
+ break;
169
+ default:
170
+ throw new LogicException(sprintf('Token of type "%s" does not exist.', $type));
171
+ }
172
+
173
+ return $short ? $name : 'Twig_Token::'.$name;
174
+ }
175
+
176
+ /**
177
+ * Returns the english representation of a given type.
178
+ *
179
+ * @param int $type The type as an integer
180
+ *
181
+ * @return string The string representation
182
+ */
183
+ public static function typeToEnglish($type)
184
+ {
185
+ switch ($type) {
186
+ case self::EOF_TYPE:
187
+ return 'end of template';
188
+ case self::TEXT_TYPE:
189
+ return 'text';
190
+ case self::BLOCK_START_TYPE:
191
+ return 'begin of statement block';
192
+ case self::VAR_START_TYPE:
193
+ return 'begin of print statement';
194
+ case self::BLOCK_END_TYPE:
195
+ return 'end of statement block';
196
+ case self::VAR_END_TYPE:
197
+ return 'end of print statement';
198
+ case self::NAME_TYPE:
199
+ return 'name';
200
+ case self::NUMBER_TYPE:
201
+ return 'number';
202
+ case self::STRING_TYPE:
203
+ return 'string';
204
+ case self::OPERATOR_TYPE:
205
+ return 'operator';
206
+ case self::PUNCTUATION_TYPE:
207
+ return 'punctuation';
208
+ case self::INTERPOLATION_START_TYPE:
209
+ return 'begin of string interpolation';
210
+ case self::INTERPOLATION_END_TYPE:
211
+ return 'end of string interpolation';
212
+ default:
213
+ throw new LogicException(sprintf('Token of type "%s" does not exist.', $type));
214
+ }
215
+ }
216
+ }
classes/Twig/TokenParser.php CHANGED
@@ -1,33 +1,33 @@
1
- <?php
2
-
3
- /*
4
- * This file is part of Twig.
5
- *
6
- * (c) 2009 Fabien Potencier
7
- *
8
- * For the full copyright and license information, please view the LICENSE
9
- * file that was distributed with this source code.
10
- */
11
-
12
- /**
13
- * Base class for all token parsers.
14
- *
15
- * @author Fabien Potencier <fabien@symfony.com>
16
- */
17
- abstract class Twig_TokenParser implements Twig_TokenParserInterface
18
- {
19
- /**
20
- * @var Twig_Parser
21
- */
22
- protected $parser;
23
-
24
- /**
25
- * Sets the parser associated with this token parser
26
- *
27
- * @param $parser A Twig_Parser instance
28
- */
29
- public function setParser(Twig_Parser $parser)
30
- {
31
- $this->parser = $parser;
32
- }
33
- }
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2009 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ /**
13
+ * Base class for all token parsers.
14
+ *
15
+ * @author Fabien Potencier <fabien@symfony.com>
16
+ */
17
+ abstract class Twig_TokenParser implements Twig_TokenParserInterface
18
+ {
19
+ /**
20
+ * @var Twig_Parser
21
+ */
22
+ protected $parser;
23
+
24
+ /**
25
+ * Sets the parser associated with this token parser
26
+ *
27
+ * @param $parser A Twig_Parser instance
28
+ */
29
+ public function setParser(Twig_Parser $parser)
30
+ {
31
+ $this->parser = $parser;
32
+ }
33
+ }
classes/Twig/TokenParser/AutoEscape.php CHANGED
@@ -1,89 +1,89 @@
1
- <?php
2
-
3
- /*
4
- * This file is part of Twig.
5
- *
6
- * (c) 2009 Fabien Potencier
7
- *
8
- * For the full copyright and license information, please view the LICENSE
9
- * file that was distributed with this source code.
10
- */
11
-
12
- /**
13
- * Marks a section of a template to be escaped or not.
14
- *
15
- * <pre>
16
- * {% autoescape true %}
17
- * Everything will be automatically escaped in this block
18
- * {% endautoescape %}
19
- *
20
- * {% autoescape false %}
21
- * Everything will be outputed as is in this block
22
- * {% endautoescape %}
23
- *
24
- * {% autoescape true js %}
25
- * Everything will be automatically escaped in this block
26
- * using the js escaping strategy
27
- * {% endautoescape %}
28
- * </pre>
29
- */
30
- class Twig_TokenParser_AutoEscape extends Twig_TokenParser
31
- {
32
- /**
33
- * Parses a token and returns a node.
34
- *
35
- * @param Twig_Token $token A Twig_Token instance
36
- *
37
- * @return Twig_NodeInterface A Twig_NodeInterface instance
38
- */
39
- public function parse(Twig_Token $token)
40
- {
41
- $lineno = $token->getLine();
42
- $stream = $this->parser->getStream();
43
-
44
- if ($stream->test(Twig_Token::BLOCK_END_TYPE)) {
45
- $value = 'html';
46
- } else {
47
- $expr = $this->parser->getExpressionParser()->parseExpression();
48
- if (!$expr instanceof Twig_Node_Expression_Constant) {
49
- throw new Twig_Error_Syntax('An escaping strategy must be a string or a Boolean.', $stream->getCurrent()->getLine(), $stream->getFilename());
50
- }
51
- $value = $expr->getAttribute('value');
52
-
53
- $compat = true === $value || false === $value;
54
-
55
- if (true === $value) {
56
- $value = 'html';
57
- }
58
-
59
- if ($compat && $stream->test(Twig_Token::NAME_TYPE)) {
60
- if (false === $value) {
61
- throw new Twig_Error_Syntax('Unexpected escaping strategy as you set autoescaping to false.', $stream->getCurrent()->getLine(), $stream->getFilename());
62
- }
63
-
64
- $value = $stream->next()->getValue();
65
- }
66
- }
67
-
68
- $stream->expect(Twig_Token::BLOCK_END_TYPE);
69
- $body = $this->parser->subparse(array($this, 'decideBlockEnd'), true);
70
- $stream->expect(Twig_Token::BLOCK_END_TYPE);
71
-
72
- return new Twig_Node_AutoEscape($value, $body, $lineno, $this->getTag());
73
- }
74
-
75
- public function decideBlockEnd(Twig_Token $token)
76
- {
77
- return $token->test('endautoescape');
78
- }
79
-
80
- /**
81
- * Gets the tag name associated with this token parser.
82
- *
83
- * @return string The tag name
84
- */
85
- public function getTag()
86
- {
87
- return 'autoescape';
88
- }
89
- }
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2009 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ /**
13
+ * Marks a section of a template to be escaped or not.
14
+ *
15
+ * <pre>
16
+ * {% autoescape true %}
17
+ * Everything will be automatically escaped in this block
18
+ * {% endautoescape %}
19
+ *
20
+ * {% autoescape false %}
21
+ * Everything will be outputed as is in this block
22
+ * {% endautoescape %}
23
+ *
24
+ * {% autoescape true js %}
25
+ * Everything will be automatically escaped in this block
26
+ * using the js escaping strategy
27
+ * {% endautoescape %}
28
+ * </pre>
29
+ */
30
+ class Twig_TokenParser_AutoEscape extends Twig_TokenParser
31
+ {
32
+ /**
33
+ * Parses a token and returns a node.
34
+ *
35
+ * @param Twig_Token $token A Twig_Token instance
36
+ *
37
+ * @return Twig_NodeInterface A Twig_NodeInterface instance
38
+ */
39
+ public function parse(Twig_Token $token)
40
+ {
41
+ $lineno = $token->getLine();
42
+ $stream = $this->parser->getStream();
43
+
44
+ if ($stream->test(Twig_Token::BLOCK_END_TYPE)) {
45
+ $value = 'html';
46
+ } else {
47
+ $expr = $this->parser->getExpressionParser()->parseExpression();
48
+ if (!$expr instanceof Twig_Node_Expression_Constant) {
49
+ throw new Twig_Error_Syntax('An escaping strategy must be a string or a Boolean.', $stream->getCurrent()->getLine(), $stream->getFilename());
50
+ }
51
+ $value = $expr->getAttribute('value');
52
+
53
+ $compat = true === $value || false === $value;
54
+
55
+ if (true === $value) {
56
+ $value = 'html';
57
+ }
58
+
59
+ if ($compat && $stream->test(Twig_Token::NAME_TYPE)) {
60
+ if (false === $value) {
61
+ throw new Twig_Error_Syntax('Unexpected escaping strategy as you set autoescaping to false.', $stream->getCurrent()->getLine(), $stream->getFilename());
62
+ }
63
+
64
+ $value = $stream->next()->getValue();
65
+ }
66
+ }
67
+
68
+ $stream->expect(Twig_Token::BLOCK_END_TYPE);
69
+ $body = $this->parser->subparse(array($this, 'decideBlockEnd'), true);
70
+ $stream->expect(Twig_Token::BLOCK_END_TYPE);
71
+
72
+ return new Twig_Node_AutoEscape($value, $body, $lineno, $this->getTag());
73
+ }
74
+
75
+ public function decideBlockEnd(Twig_Token $token)
76
+ {
77
+ return $token->test('endautoescape');
78
+ }
79
+
80
+ /**
81
+ * Gets the tag name associated with this token parser.
82
+ *
83
+ * @return string The tag name
84
+ */
85
+ public function getTag()
86
+ {
87
+ return 'autoescape';
88
+ }
89
+ }
classes/Twig/TokenParser/Block.php CHANGED
@@ -1,81 +1,81 @@
1
- <?php
2
-
3
- /*
4
- * This file is part of Twig.
5
- *
6
- * (c) 2009 Fabien Potencier
7
- * (c) 2009 Armin Ronacher
8
- *
9
- * For the full copyright and license information, please view the LICENSE
10
- * file that was distributed with this source code.
11
- */
12
-
13
- /**
14
- * Marks a section of a template as being reusable.
15
- *
16
- * <pre>
17
- * {% block head %}
18
- * <link rel="stylesheet" href="style.css" />
19
- * <title>{% block title %}{% endblock %} - My Webpage</title>
20
- * {% endblock %}
21
- * </pre>
22
- */
23
- class Twig_TokenParser_Block extends Twig_TokenParser
24
- {
25
- /**
26
- * Parses a token and returns a node.
27
- *
28
- * @param Twig_Token $token A Twig_Token instance
29
- *
30
- * @return Twig_NodeInterface A Twig_NodeInterface instance
31
- */
32
- public function parse(Twig_Token $token)
33
- {
34
- $lineno = $token->getLine();
35
- $stream = $this->parser->getStream();
36
- $name = $stream->expect(Twig_Token::NAME_TYPE)->getValue();
37
- if ($this->parser->hasBlock($name)) {
38
- throw new Twig_Error_Syntax(sprintf("The block '$name' has already been defined line %d", $this->parser->getBlock($name)->getLine()), $stream->getCurrent()->getLine(), $stream->getFilename());
39
- }
40
- $this->parser->setBlock($name, $block = new Twig_Node_Block($name, new Twig_Node(array()), $lineno));
41
- $this->parser->pushLocalScope();
42
- $this->parser->pushBlockStack($name);
43
-
44
- if ($stream->nextIf(Twig_Token::BLOCK_END_TYPE)) {
45
- $body = $this->parser->subparse(array($this, 'decideBlockEnd'), true);
46
- if ($token = $stream->nextIf(Twig_Token::NAME_TYPE)) {
47
- $value = $token->getValue();
48
-
49
- if ($value != $name) {
50
- throw new Twig_Error_Syntax(sprintf("Expected endblock for block '$name' (but %s given)", $value), $stream->getCurrent()->getLine(), $stream->getFilename());
51
- }
52
- }
53
- } else {
54
- $body = new Twig_Node(array(
55
- new Twig_Node_Print($this->parser->getExpressionParser()->parseExpression(), $lineno),
56
- ));
57
- }
58
- $stream->expect(Twig_Token::BLOCK_END_TYPE);
59
-
60
- $block->setNode('body', $body);
61
- $this->parser->popBlockStack();
62
- $this->parser->popLocalScope();
63
-
64
- return new Twig_Node_BlockReference($name, $lineno, $this->getTag());
65
- }
66
-
67
- public function decideBlockEnd(Twig_Token $token)
68
- {
69
- return $token->test('endblock');
70
- }
71
-
72
- /**
73
- * Gets the tag name associated with this token parser.
74
- *
75
- * @return string The tag name
76
- */
77
- public function getTag()
78
- {
79
- return 'block';
80
- }
81
- }
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2009 Fabien Potencier
7
+ * (c) 2009 Armin Ronacher
8
+ *
9
+ * For the full copyright and license information, please view the LICENSE
10
+ * file that was distributed with this source code.
11
+ */
12
+
13
+ /**
14
+ * Marks a section of a template as being reusable.
15
+ *
16
+ * <pre>
17
+ * {% block head %}
18
+ * <link rel="stylesheet" href="style.css" />
19
+ * <title>{% block title %}{% endblock %} - My Webpage</title>
20
+ * {% endblock %}
21
+ * </pre>
22
+ */
23
+ class Twig_TokenParser_Block extends Twig_TokenParser
24
+ {
25
+ /**
26
+ * Parses a token and returns a node.
27
+ *
28
+ * @param Twig_Token $token A Twig_Token instance
29
+ *
30
+ * @return Twig_NodeInterface A Twig_NodeInterface instance
31
+ */
32
+ public function parse(Twig_Token $token)
33
+ {
34
+ $lineno = $token->getLine();
35
+ $stream = $this->parser->getStream();
36
+ $name = $stream->expect(Twig_Token::NAME_TYPE)->getValue();
37
+ if ($this->parser->hasBlock($name)) {
38
+ throw new Twig_Error_Syntax(sprintf("The block '$name' has already been defined line %d", $this->parser->getBlock($name)->getLine()), $stream->getCurrent()->getLine(), $stream->getFilename());
39
+ }
40
+ $this->parser->setBlock($name, $block = new Twig_Node_Block($name, new Twig_Node(array()), $lineno));
41
+ $this->parser->pushLocalScope();
42
+ $this->parser->pushBlockStack($name);
43
+
44
+ if ($stream->nextIf(Twig_Token::BLOCK_END_TYPE)) {
45
+ $body = $this->parser->subparse(array($this, 'decideBlockEnd'), true);
46
+ if ($token = $stream->nextIf(Twig_Token::NAME_TYPE)) {
47
+ $value = $token->getValue();
48
+
49
+ if ($value != $name) {
50
+ throw new Twig_Error_Syntax(sprintf("Expected endblock for block '$name' (but %s given)", $value), $stream->getCurrent()->getLine(), $stream->getFilename());
51
+ }
52
+ }
53
+ } else {
54
+ $body = new Twig_Node(array(
55
+ new Twig_Node_Print($this->parser->getExpressionParser()->parseExpression(), $lineno),
56
+ ));
57
+ }
58
+ $stream->expect(Twig_Token::BLOCK_END_TYPE);
59
+
60
+ $block->setNode('body', $body);
61
+ $this->parser->popBlockStack();
62
+ $this->parser->popLocalScope();
63
+
64
+ return new Twig_Node_BlockReference($name, $lineno, $this->getTag());
65
+ }
66
+
67
+ public function decideBlockEnd(Twig_Token $token)
68
+ {
69
+ return $token->test('endblock');
70
+ }
71
+
72
+ /**
73
+ * Gets the tag name associated with this token parser.
74
+ *
75
+ * @return string The tag name
76
+ */
77
+ public function getTag()
78
+ {
79
+ return 'block';
80
+ }
81
+ }
classes/Twig/TokenParser/Do.php CHANGED
@@ -1,42 +1,42 @@
1
- <?php
2
-
3
- /*
4
- * This file is part of Twig.
5
- *
6
- * (c) 2011 Fabien Potencier
7
- *
8
- * For the full copyright and license information, please view the LICENSE
9
- * file that was distributed with this source code.
10
- */
11
-
12
- /**
13
- * Evaluates an expression, discarding the returned value.
14
- */
15
- class Twig_TokenParser_Do extends Twig_TokenParser
16
- {
17
- /**
18
- * Parses a token and returns a node.
19
- *
20
- * @param Twig_Token $token A Twig_Token instance
21
- *
22
- * @return Twig_NodeInterface A Twig_NodeInterface instance
23
- */
24
- public function parse(Twig_Token $token)
25
- {
26
- $expr = $this->parser->getExpressionParser()->parseExpression();
27
-
28
- $this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE);
29
-
30
- return new Twig_Node_Do($expr, $token->getLine(), $this->getTag());
31
- }
32
-
33
- /**
34
- * Gets the tag name associated with this token parser.
35
- *
36
- * @return string The tag name
37
- */
38
- public function getTag()
39
- {
40
- return 'do';
41
- }
42
- }
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2011 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ /**
13
+ * Evaluates an expression, discarding the returned value.
14
+ */
15
+ class Twig_TokenParser_Do extends Twig_TokenParser
16
+ {
17
+ /**
18
+ * Parses a token and returns a node.
19
+ *
20
+ * @param Twig_Token $token A Twig_Token instance
21
+ *
22
+ * @return Twig_NodeInterface A Twig_NodeInterface instance
23
+ */
24
+ public function parse(Twig_Token $token)
25
+ {
26
+ $expr = $this->parser->getExpressionParser()->parseExpression();
27
+
28
+ $this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE);
29
+
30
+ return new Twig_Node_Do($expr, $token->getLine(), $this->getTag());
31
+ }
32
+
33
+ /**
34
+ * Gets the tag name associated with this token parser.
35
+ *
36
+ * @return string The tag name
37
+ */
38
+ public function getTag()
39
+ {
40
+ return 'do';
41
+ }
42
+ }
classes/Twig/TokenParser/Embed.php CHANGED
@@ -1,66 +1,66 @@
1
- <?php
2
-
3
- /*
4
- * This file is part of Twig.
5
- *
6
- * (c) 2012 Fabien Potencier
7
- *
8
- * For the full copyright and license information, please view the LICENSE
9
- * file that was distributed with this source code.
10
- */
11
-
12
- /**
13
- * Embeds a template.
14
- */
15
- class Twig_TokenParser_Embed extends Twig_TokenParser_Include
16
- {
17
- /**
18
- * Parses a token and returns a node.
19
- *
20
- * @param Twig_Token $token A Twig_Token instance
21
- *
22
- * @return Twig_NodeInterface A Twig_NodeInterface instance
23
- */
24
- public function parse(Twig_Token $token)
25
- {
26
- $stream = $this->parser->getStream();
27
-
28
- $parent = $this->parser->getExpressionParser()->parseExpression();
29
-
30
- list($variables, $only, $ignoreMissing) = $this->parseArguments();
31
-
32
- // inject a fake parent to make the parent() function work
33
- $stream->injectTokens(array(
34
- new Twig_Token(Twig_Token::BLOCK_START_TYPE, '', $token->getLine()),
35
- new Twig_Token(Twig_Token::NAME_TYPE, 'extends', $token->getLine()),
36
- new Twig_Token(Twig_Token::STRING_TYPE, '__parent__', $token->getLine()),
37
- new Twig_Token(Twig_Token::BLOCK_END_TYPE, '', $token->getLine()),
38
- ));
39
-
40
- $module = $this->parser->parse($stream, array($this, 'decideBlockEnd'), true);
41
-
42
- // override the parent with the correct one
43
- $module->setNode('parent', $parent);
44
-
45
- $this->parser->embedTemplate($module);
46
-
47
- $stream->expect(Twig_Token::BLOCK_END_TYPE);
48
-
49
- return new Twig_Node_Embed($module->getAttribute('filename'), $module->getAttribute('index'), $variables, $only, $ignoreMissing, $token->getLine(), $this->getTag());
50
- }
51
-
52
- public function decideBlockEnd(Twig_Token $token)
53
- {
54
- return $token->test('endembed');
55
- }
56
-
57
- /**
58
- * Gets the tag name associated with this token parser.
59
- *
60
- * @return string The tag name
61
- */
62
- public function getTag()
63
- {
64
- return 'embed';
65
- }
66
- }
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2012 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ /**
13
+ * Embeds a template.
14
+ */
15
+ class Twig_TokenParser_Embed extends Twig_TokenParser_Include
16
+ {
17
+ /**
18
+ * Parses a token and returns a node.
19
+ *
20
+ * @param Twig_Token $token A Twig_Token instance
21
+ *
22
+ * @return Twig_NodeInterface A Twig_NodeInterface instance
23
+ */
24
+ public function parse(Twig_Token $token)
25
+ {
26
+ $stream = $this->parser->getStream();
27
+
28
+ $parent = $this->parser->getExpressionParser()->parseExpression();
29
+
30
+ list($variables, $only, $ignoreMissing) = $this->parseArguments();
31
+
32
+ // inject a fake parent to make the parent() function work
33
+ $stream->injectTokens(array(
34
+ new Twig_Token(Twig_Token::BLOCK_START_TYPE, '', $token->getLine()),
35
+ new Twig_Token(Twig_Token::NAME_TYPE, 'extends', $token->getLine()),
36
+ new Twig_Token(Twig_Token::STRING_TYPE, '__parent__', $token->getLine()),
37
+ new Twig_Token(Twig_Token::BLOCK_END_TYPE, '', $token->getLine()),
38
+ ));
39
+
40
+ $module = $this->parser->parse($stream, array($this, 'decideBlockEnd'), true);
41
+
42
+ // override the parent with the correct one
43
+ $module->setNode('parent', $parent);
44
+
45
+ $this->parser->embedTemplate($module);
46
+
47
+ $stream->expect(Twig_Token::BLOCK_END_TYPE);
48
+
49
+ return new Twig_Node_Embed($module->getAttribute('filename'), $module->getAttribute('index'), $variables, $only, $ignoreMissing, $token->getLine(), $this->getTag());
50
+ }
51
+
52
+ public function decideBlockEnd(Twig_Token $token)
53
+ {
54
+ return $token->test('endembed');
55
+ }
56
+
57
+ /**
58
+ * Gets the tag name associated with this token parser.
59
+ *
60
+ * @return string The tag name
61
+ */
62
+ public function getTag()
63
+ {
64
+ return 'embed';
65
+ }
66
+ }
classes/Twig/TokenParser/Extends.php CHANGED
@@ -1,52 +1,52 @@
1
- <?php
2
-
3
- /*
4
- * This file is part of Twig.
5
- *
6
- * (c) 2009 Fabien Potencier
7
- * (c) 2009 Armin Ronacher
8
- *
9
- * For the full copyright and license information, please view the LICENSE
10
- * file that was distributed with this source code.
11
- */
12
-
13
- /**
14
- * Extends a template by another one.
15
- *
16
- * <pre>
17
- * {% extends "base.html" %}
18
- * </pre>
19
- */
20
- class Twig_TokenParser_Extends extends Twig_TokenParser
21
- {
22
- /**
23
- * Parses a token and returns a node.
24
- *
25
- * @param Twig_Token $token A Twig_Token instance
26
- *
27
- * @return Twig_NodeInterface A Twig_NodeInterface instance
28
- */
29
- public function parse(Twig_Token $token)
30
- {
31
- if (!$this->parser->isMainScope()) {
32
- throw new Twig_Error_Syntax('Cannot extend from a block', $token->getLine(), $this->parser->getFilename());
33
- }
34
-
35
- if (null !== $this->parser->getParent()) {
36
- throw new Twig_Error_Syntax('Multiple extends tags are forbidden', $token->getLine(), $this->parser->getFilename());
37
- }
38
- $this->parser->setParent($this->parser->getExpressionParser()->parseExpression());
39
-
40
- $this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE);
41
- }
42
-
43
- /**
44
- * Gets the tag name associated with this token parser.
45
- *
46
- * @return string The tag name
47
- */
48
- public function getTag()
49
- {
50
- return 'extends';
51
- }
52
- }
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2009 Fabien Potencier
7
+ * (c) 2009 Armin Ronacher
8
+ *
9
+ * For the full copyright and license information, please view the LICENSE
10
+ * file that was distributed with this source code.
11
+ */
12
+
13
+ /**
14
+ * Extends a template by another one.
15
+ *
16
+ * <pre>
17
+ * {% extends "base.html" %}
18
+ * </pre>
19
+ */
20
+ class Twig_TokenParser_Extends extends Twig_TokenParser
21
+ {
22
+ /**
23
+ * Parses a token and returns a node.
24
+ *
25
+ * @param Twig_Token $token A Twig_Token instance
26
+ *
27
+ * @return Twig_NodeInterface A Twig_NodeInterface instance
28
+ */
29
+ public function parse(Twig_Token $token)
30
+ {
31
+ if (!$this->parser->isMainScope()) {
32
+ throw new Twig_Error_Syntax('Cannot extend from a block', $token->getLine(), $this->parser->getFilename());
33
+ }
34
+
35
+ if (null !== $this->parser->getParent()) {
36
+ throw new Twig_Error_Syntax('Multiple extends tags are forbidden', $token->getLine(), $this->parser->getFilename());
37
+ }
38
+ $this->parser->setParent($this->parser->getExpressionParser()->parseExpression());
39
+
40
+ $this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE);
41
+ }
42
+
43
+ /**
44
+ * Gets the tag name associated with this token parser.
45
+ *
46
+ * @return string The tag name
47
+ */
48
+ public function getTag()
49
+ {
50
+ return 'extends';
51
+ }
52
+ }
classes/Twig/TokenParser/Filter.php CHANGED
@@ -1,61 +1,61 @@
1
- <?php
2
-
3
- /*
4
- * This file is part of Twig.
5
- *
6
- * (c) 2009 Fabien Potencier
7
- *
8
- * For the full copyright and license information, please view the LICENSE
9
- * file that was distributed with this source code.
10
- */
11
-
12
- /**
13
- * Filters a section of a template by applying filters.
14
- *
15
- * <pre>
16
- * {% filter upper %}
17
- * This text becomes uppercase
18
- * {% endfilter %}
19
- * </pre>
20
- */
21
- class Twig_TokenParser_Filter extends Twig_TokenParser
22
- {
23
- /**
24
- * Parses a token and returns a node.
25
- *
26
- * @param Twig_Token $token A Twig_Token instance
27
- *
28
- * @return Twig_NodeInterface A Twig_NodeInterface instance
29
- */
30
- public function parse(Twig_Token $token)
31
- {
32
- $name = $this->parser->getVarName();
33
- $ref = new Twig_Node_Expression_BlockReference(new Twig_Node_Expression_Constant($name, $token->getLine()), true, $token->getLine(), $this->getTag());
34
-
35
- $filter = $this->parser->getExpressionParser()->parseFilterExpressionRaw($ref, $this->getTag());
36
- $this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE);
37
-
38
- $body = $this->parser->subparse(array($this, 'decideBlockEnd'), true);
39
- $this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE);
40
-
41
- $block = new Twig_Node_Block($name, $body, $token->getLine());
42
- $this->parser->setBlock($name, $block);
43
-
44
- return new Twig_Node_Print($filter, $token->getLine(), $this->getTag());
45
- }
46
-
47
- public function decideBlockEnd(Twig_Token $token)
48
- {
49
- return $token->test('endfilter');
50
- }
51
-
52
- /**
53
- * Gets the tag name associated with this token parser.
54
- *
55
- * @return string The tag name
56
- */
57
- public function getTag()
58
- {
59
- return 'filter';
60
- }
61
- }
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2009 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ /**
13
+ * Filters a section of a template by applying filters.
14
+ *
15
+ * <pre>
16
+ * {% filter upper %}
17
+ * This text becomes uppercase
18
+ * {% endfilter %}
19
+ * </pre>
20
+ */
21
+ class Twig_TokenParser_Filter extends Twig_TokenParser
22
+ {
23
+ /**
24
+ * Parses a token and returns a node.
25
+ *
26
+ * @param Twig_Token $token A Twig_Token instance
27
+ *
28
+ * @return Twig_NodeInterface A Twig_NodeInterface instance
29
+ */
30
+ public function parse(Twig_Token $token)
31
+ {
32
+ $name = $this->parser->getVarName();
33
+ $ref = new Twig_Node_Expression_BlockReference(new Twig_Node_Expression_Constant($name, $token->getLine()), true, $token->getLine(), $this->getTag());
34
+
35
+ $filter = $this->parser->getExpressionParser()->parseFilterExpressionRaw($ref, $this->getTag());
36
+ $this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE);
37
+
38
+ $body = $this->parser->subparse(array($this, 'decideBlockEnd'), true);
39
+ $this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE);
40
+
41
+ $block = new Twig_Node_Block($name, $body, $token->getLine());
42
+ $this->parser->setBlock($name, $block);
43
+
44
+ return new Twig_Node_Print($filter, $token->getLine(), $this->getTag());
45
+ }
46
+
47
+ public function decideBlockEnd(Twig_Token $token)
48
+ {
49
+ return $token->test('endfilter');
50
+ }
51
+
52
+ /**
53
+ * Gets the tag name associated with this token parser.
54
+ *
55
+ * @return string The tag name
56
+ */
57
+ public function getTag()
58
+ {
59
+ return 'filter';
60
+ }
61
+ }
classes/Twig/TokenParser/Flush.php CHANGED
@@ -1,42 +1,42 @@
1
- <?php
2
-
3
- /*
4
- * This file is part of Twig.
5
- *
6
- * (c) 2011 Fabien Potencier
7
- *
8
- * For the full copyright and license information, please view the LICENSE
9
- * file that was distributed with this source code.
10
- */
11
-
12
- /**
13
- * Flushes the output to the client.
14
- *
15
- * @see flush()
16
- */
17
- class Twig_TokenParser_Flush extends Twig_TokenParser
18
- {
19
- /**
20
- * Parses a token and returns a node.
21
- *
22
- * @param Twig_Token $token A Twig_Token instance
23
- *
24
- * @return Twig_NodeInterface A Twig_NodeInterface instance
25
- */
26
- public function parse(Twig_Token $token)
27
- {
28
- $this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE);
29
-
30
- return new Twig_Node_Flush($token->getLine(), $this->getTag());
31
- }
32
-
33
- /**
34
- * Gets the tag name associated with this token parser.
35
- *
36
- * @return string The tag name
37
- */
38
- public function getTag()
39
- {
40
- return 'flush';
41
- }
42
- }
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2011 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ /**
13
+ * Flushes the output to the client.
14
+ *
15
+ * @see flush()
16
+ */
17
+ class Twig_TokenParser_Flush extends Twig_TokenParser
18
+ {
19
+ /**
20
+ * Parses a token and returns a node.
21
+ *
22
+ * @param Twig_Token $token A Twig_Token instance
23
+ *
24
+ * @return Twig_NodeInterface A Twig_NodeInterface instance
25
+ */
26
+ public function parse(Twig_Token $token)
27
+ {
28
+ $this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE);
29
+
30
+ return new Twig_Node_Flush($token->getLine(), $this->getTag());
31
+ }
32
+
33
+ /**
34
+ * Gets the tag name associated with this token parser.
35
+ *
36
+ * @return string The tag name
37
+ */
38
+ public function getTag()
39
+ {
40
+ return 'flush';
41
+ }
42
+ }
classes/Twig/TokenParser/For.php CHANGED
@@ -1,135 +1,135 @@
1
- <?php
2
-
3
- /*
4
- * This file is part of Twig.
5
- *
6
- * (c) 2009 Fabien Potencier
7
- * (c) 2009 Armin Ronacher
8
- *
9
- * For the full copyright and license information, please view the LICENSE
10
- * file that was distributed with this source code.
11
- */
12
-
13
- /**
14
- * Loops over each item of a sequence.
15
- *
16
- * <pre>
17
- * <ul>
18
- * {% for user in users %}
19
- * <li>{{ user.username|e }}</li>
20
- * {% endfor %}
21
- * </ul>
22
- * </pre>
23
- */
24
- class Twig_TokenParser_For extends Twig_TokenParser
25
- {
26
- /**
27
- * Parses a token and returns a node.
28
- *
29
- * @param Twig_Token $token A Twig_Token instance
30
- *
31
- * @return Twig_NodeInterface A Twig_NodeInterface instance
32
- */
33
- public function parse(Twig_Token $token)
34
- {
35
- $lineno = $token->getLine();
36
- $stream = $this->parser->getStream();
37
- $targets = $this->parser->getExpressionParser()->parseAssignmentExpression();
38
- $stream->expect(Twig_Token::OPERATOR_TYPE, 'in');
39
- $seq = $this->parser->getExpressionParser()->parseExpression();
40
-
41
- $ifexpr = null;
42
- if ($stream->nextIf(Twig_Token::NAME_TYPE, 'if')) {
43
- $ifexpr = $this->parser->getExpressionParser()->parseExpression();
44
- }
45
-
46
- $stream->expect(Twig_Token::BLOCK_END_TYPE);
47
- $body = $this->parser->subparse(array($this, 'decideForFork'));
48
- if ($stream->next()->getValue() == 'else') {
49
- $stream->expect(Twig_Token::BLOCK_END_TYPE);
50
- $else = $this->parser->subparse(array($this, 'decideForEnd'), true);
51
- } else {
52
- $else = null;
53
- }
54
- $stream->expect(Twig_Token::BLOCK_END_TYPE);
55
-
56
- if (count($targets) > 1) {
57
- $keyTarget = $targets->getNode(0);
58
- $keyTarget = new Twig_Node_Expression_AssignName($keyTarget->getAttribute('name'), $keyTarget->getLine());
59
- $valueTarget = $targets->getNode(1);
60
- $valueTarget = new Twig_Node_Expression_AssignName($valueTarget->getAttribute('name'), $valueTarget->getLine());
61
- } else {
62
- $keyTarget = new Twig_Node_Expression_AssignName('_key', $lineno);
63
- $valueTarget = $targets->getNode(0);
64
- $valueTarget = new Twig_Node_Expression_AssignName($valueTarget->getAttribute('name'), $valueTarget->getLine());
65
- }
66
-
67
- if ($ifexpr) {
68
- $this->checkLoopUsageCondition($stream, $ifexpr);
69
- $this->checkLoopUsageBody($stream, $body);
70
- }
71
-
72
- return new Twig_Node_For($keyTarget, $valueTarget, $seq, $ifexpr, $body, $else, $lineno, $this->getTag());
73
- }
74
-
75
- public function decideForFork(Twig_Token $token)
76
- {
77
- return $token->test(array('else', 'endfor'));
78
- }
79
-
80
- public function decideForEnd(Twig_Token $token)
81
- {
82
- return $token->test('endfor');
83
- }
84
-
85
- // the loop variable cannot be used in the condition
86
- protected function checkLoopUsageCondition(Twig_TokenStream $stream, Twig_NodeInterface $node)
87
- {
88
- if ($node instanceof Twig_Node_Expression_GetAttr && $node->getNode('node') instanceof Twig_Node_Expression_Name && 'loop' == $node->getNode('node')->getAttribute('name')) {
89
- throw new Twig_Error_Syntax('The "loop" variable cannot be used in a looping condition', $node->getLine(), $stream->getFilename());
90
- }
91
-
92
- foreach ($node as $n) {
93
- if (!$n) {
94
- continue;
95
- }
96
-
97
- $this->checkLoopUsageCondition($stream, $n);
98
- }
99
- }
100
-
101
- // check usage of non-defined loop-items
102
- // it does not catch all problems (for instance when a for is included into another or when the variable is used in an include)
103
- protected function checkLoopUsageBody(Twig_TokenStream $stream, Twig_NodeInterface $node)
104
- {
105
- if ($node instanceof Twig_Node_Expression_GetAttr && $node->getNode('node') instanceof Twig_Node_Expression_Name && 'loop' == $node->getNode('node')->getAttribute('name')) {
106
- $attribute = $node->getNode('attribute');
107
- if ($attribute instanceof Twig_Node_Expression_Constant && in_array($attribute->getAttribute('value'), array('length', 'revindex0', 'revindex', 'last'))) {
108
- throw new Twig_Error_Syntax(sprintf('The "loop.%s" variable is not defined when looping with a condition', $attribute->getAttribute('value')), $node->getLine(), $stream->getFilename());
109
- }
110
- }
111
-
112
- // should check for parent.loop.XXX usage
113
- if ($node instanceof Twig_Node_For) {
114
- return;
115
- }
116
-
117
- foreach ($node as $n) {
118
- if (!$n) {
119
- continue;
120
- }
121
-
122
- $this->checkLoopUsageBody($stream, $n);
123
- }
124
- }
125
-
126
- /**
127
- * Gets the tag name associated with this token parser.
128
- *
129
- * @return string The tag name
130
- */
131
- public function getTag()
132
- {
133
- return 'for';
134
- }
135
- }
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2009 Fabien Potencier
7
+ * (c) 2009 Armin Ronacher
8
+ *
9
+ * For the full copyright and license information, please view the LICENSE
10
+ * file that was distributed with this source code.
11
+ */
12
+
13
+ /**
14
+ * Loops over each item of a sequence.
15
+ *
16
+ * <pre>
17
+ * <ul>
18
+ * {% for user in users %}
19
+ * <li>{{ user.username|e }}</li>
20
+ * {% endfor %}
21
+ * </ul>
22
+ * </pre>
23
+ */
24
+ class Twig_TokenParser_For extends Twig_TokenParser
25
+ {
26
+ /**
27
+ * Parses a token and returns a node.
28
+ *
29
+ * @param Twig_Token $token A Twig_Token instance
30
+ *
31
+ * @return Twig_NodeInterface A Twig_NodeInterface instance
32
+ */
33
+ public function parse(Twig_Token $token)
34
+ {
35
+ $lineno = $token->getLine();
36
+ $stream = $this->parser->getStream();
37
+ $targets = $this->parser->getExpressionParser()->parseAssignmentExpression();
38
+ $stream->expect(Twig_Token::OPERATOR_TYPE, 'in');
39
+ $seq = $this->parser->getExpressionParser()->parseExpression();
40
+
41
+ $ifexpr = null;
42
+ if ($stream->nextIf(Twig_Token::NAME_TYPE, 'if')) {
43
+ $ifexpr = $this->parser->getExpressionParser()->parseExpression();
44
+ }
45
+
46
+ $stream->expect(Twig_Token::BLOCK_END_TYPE);
47
+ $body = $this->parser->subparse(array($this, 'decideForFork'));
48
+ if ($stream->next()->getValue() == 'else') {
49
+ $stream->expect(Twig_Token::BLOCK_END_TYPE);
50
+ $else = $this->parser->subparse(array($this, 'decideForEnd'), true);
51
+ } else {
52
+ $else = null;
53
+ }
54
+ $stream->expect(Twig_Token::BLOCK_END_TYPE);
55
+
56
+ if (count($targets) > 1) {
57
+ $keyTarget = $targets->getNode(0);
58
+ $keyTarget = new Twig_Node_Expression_AssignName($keyTarget->getAttribute('name'), $keyTarget->getLine());
59
+ $valueTarget = $targets->getNode(1);
60
+ $valueTarget = new Twig_Node_Expression_AssignName($valueTarget->getAttribute('name'), $valueTarget->getLine());
61
+ } else {
62
+ $keyTarget = new Twig_Node_Expression_AssignName('_key', $lineno);
63
+ $valueTarget = $targets->getNode(0);
64
+ $valueTarget = new Twig_Node_Expression_AssignName($valueTarget->getAttribute('name'), $valueTarget->getLine());
65
+ }
66
+
67
+ if ($ifexpr) {
68
+ $this->checkLoopUsageCondition($stream, $ifexpr);
69
+ $this->checkLoopUsageBody($stream, $body);
70
+ }
71
+
72
+ return new Twig_Node_For($keyTarget, $valueTarget, $seq, $ifexpr, $body, $else, $lineno, $this->getTag());
73
+ }
74
+
75
+ public function decideForFork(Twig_Token $token)
76
+ {
77
+ return $token->test(array('else', 'endfor'));
78
+ }
79
+
80
+ public function decideForEnd(Twig_Token $token)
81
+ {
82
+ return $token->test('endfor');
83
+ }
84
+
85
+ // the loop variable cannot be used in the condition
86
+ protected function checkLoopUsageCondition(Twig_TokenStream $stream, Twig_NodeInterface $node)
87
+ {
88
+ if ($node instanceof Twig_Node_Expression_GetAttr && $node->getNode('node') instanceof Twig_Node_Expression_Name && 'loop' == $node->getNode('node')->getAttribute('name')) {
89
+ throw new Twig_Error_Syntax('The "loop" variable cannot be used in a looping condition', $node->getLine(), $stream->getFilename());
90
+ }
91
+
92
+ foreach ($node as $n) {
93
+ if (!$n) {
94
+ continue;
95
+ }
96
+
97
+ $this->checkLoopUsageCondition($stream, $n);
98
+ }
99
+ }
100
+
101
+ // check usage of non-defined loop-items
102
+ // it does not catch all problems (for instance when a for is included into another or when the variable is used in an include)
103
+ protected function checkLoopUsageBody(Twig_TokenStream $stream, Twig_NodeInterface $node)
104
+ {
105
+ if ($node instanceof Twig_Node_Expression_GetAttr && $node->getNode('node') instanceof Twig_Node_Expression_Name && 'loop' == $node->getNode('node')->getAttribute('name')) {
106
+ $attribute = $node->getNode('attribute');
107
+ if ($attribute instanceof Twig_Node_Expression_Constant && in_array($attribute->getAttribute('value'), array('length', 'revindex0', 'revindex', 'last'))) {
108
+ throw new Twig_Error_Syntax(sprintf('The "loop.%s" variable is not defined when looping with a condition', $attribute->getAttribute('value')), $node->getLine(), $stream->getFilename());
109
+ }
110
+ }
111
+
112
+ // should check for parent.loop.XXX usage
113
+ if ($node instanceof Twig_Node_For) {
114
+ return;
115
+ }
116
+
117
+ foreach ($node as $n) {
118
+ if (!$n) {
119
+ continue;
120
+ }
121
+
122
+ $this->checkLoopUsageBody($stream, $n);
123
+ }
124
+ }
125
+
126
+ /**
127
+ * Gets the tag name associated with this token parser.
128
+ *
129
+ * @return string The tag name
130
+ */
131
+ public function getTag()
132
+ {
133
+ return 'for';
134
+ }
135
+ }
classes/Twig/TokenParser/From.php CHANGED
@@ -1,70 +1,70 @@
1
- <?php
2
-
3
- /*
4
- * This file is part of Twig.
5
- *
6
- * (c) 2010 Fabien Potencier
7
- *
8
- * For the full copyright and license information, please view the LICENSE
9
- * file that was distributed with this source code.
10
- */
11
-
12
- /**
13
- * Imports macros.
14
- *
15
- * <pre>
16
- * {% from 'forms.html' import forms %}
17
- * </pre>
18
- */
19
- class Twig_TokenParser_From extends Twig_TokenParser
20
- {
21
- /**
22
- * Parses a token and returns a node.
23
- *
24
- * @param Twig_Token $token A Twig_Token instance
25
- *
26
- * @return Twig_NodeInterface A Twig_NodeInterface instance
27
- */
28
- public function parse(Twig_Token $token)
29
- {
30
- $macro = $this->parser->getExpressionParser()->parseExpression();
31
- $stream = $this->parser->getStream();
32
- $stream->expect('import');
33
-
34
- $targets = array();
35
- do {
36
- $name = $stream->expect(Twig_Token::NAME_TYPE)->getValue();
37
-
38
- $alias = $name;
39
- if ($stream->nextIf('as')) {
40
- $alias = $stream->expect(Twig_Token::NAME_TYPE)->getValue();
41
- }
42
-
43
- $targets[$name] = $alias;
44
-
45
- if (!$stream->nextIf(Twig_Token::PUNCTUATION_TYPE, ',')) {
46
- break;
47
- }
48
- } while (true);
49
-
50
- $stream->expect(Twig_Token::BLOCK_END_TYPE);
51
-
52
- $node = new Twig_Node_Import($macro, new Twig_Node_Expression_AssignName($this->parser->getVarName(), $token->getLine()), $token->getLine(), $this->getTag());
53
-
54
- foreach ($targets as $name => $alias) {
55
- $this->parser->addImportedSymbol('function', $alias, 'get'.$name, $node->getNode('var'));
56
- }
57
-
58
- return $node;
59
- }
60
-
61
- /**
62
- * Gets the tag name associated with this token parser.
63
- *
64
- * @return string The tag name
65
- */
66
- public function getTag()
67
- {
68
- return 'from';
69
- }
70
- }
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2010 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ /**
13
+ * Imports macros.
14
+ *
15
+ * <pre>
16
+ * {% from 'forms.html' import forms %}
17
+ * </pre>
18
+ */
19
+ class Twig_TokenParser_From extends Twig_TokenParser
20
+ {
21
+ /**
22
+ * Parses a token and returns a node.
23
+ *
24
+ * @param Twig_Token $token A Twig_Token instance
25
+ *
26
+ * @return Twig_NodeInterface A Twig_NodeInterface instance
27
+ */
28
+ public function parse(Twig_Token $token)
29
+ {
30
+ $macro = $this->parser->getExpressionParser()->parseExpression();
31
+ $stream = $this->parser->getStream();
32
+ $stream->expect('import');
33
+
34
+ $targets = array();
35
+ do {
36
+ $name = $stream->expect(Twig_Token::NAME_TYPE)->getValue();
37
+
38
+ $alias = $name;
39
+ if ($stream->nextIf('as')) {
40
+ $alias = $stream->expect(Twig_Token::NAME_TYPE)->getValue();
41
+ }
42
+
43
+ $targets[$name] = $alias;
44
+
45
+ if (!$stream->nextIf(Twig_Token::PUNCTUATION_TYPE, ',')) {
46
+ break;
47
+ }
48
+ } while (true);
49
+
50
+ $stream->expect(Twig_Token::BLOCK_END_TYPE);
51
+
52
+ $node = new Twig_Node_Import($macro, new Twig_Node_Expression_AssignName($this->parser->getVarName(), $token->getLine()), $token->getLine(), $this->getTag());
53
+
54
+ foreach ($targets as $name => $alias) {
55
+ $this->parser->addImportedSymbol('function', $alias, 'get'.$name, $node->getNode('var'));
56
+ }
57
+
58
+ return $node;
59
+ }
60
+
61
+ /**
62
+ * Gets the tag name associated with this token parser.
63
+ *
64
+ * @return string The tag name
65
+ */
66
+ public function getTag()
67
+ {
68
+ return 'from';
69
+ }
70
+ }
classes/Twig/TokenParser/If.php CHANGED
@@ -1,94 +1,94 @@
1
- <?php
2
-
3
- /*
4
- * This file is part of Twig.
5
- *
6
- * (c) 2009 Fabien Potencier
7
- * (c) 2009 Armin Ronacher
8
- *
9
- * For the full copyright and license information, please view the LICENSE
10
- * file that was distributed with this source code.
11
- */
12
-
13
- /**
14
- * Tests a condition.
15
- *
16
- * <pre>
17
- * {% if users %}
18
- * <ul>
19
- * {% for user in users %}
20
- * <li>{{ user.username|e }}</li>
21
- * {% endfor %}
22
- * </ul>
23
- * {% endif %}
24
- * </pre>
25
- */
26
- class Twig_TokenParser_If extends Twig_TokenParser
27
- {
28
- /**
29
- * Parses a token and returns a node.
30
- *
31
- * @param Twig_Token $token A Twig_Token instance
32
- *
33
- * @return Twig_NodeInterface A Twig_NodeInterface instance
34
- */
35
- public function parse(Twig_Token $token)
36
- {
37
- $lineno = $token->getLine();
38
- $expr = $this->parser->getExpressionParser()->parseExpression();
39
- $stream = $this->parser->getStream();
40
- $stream->expect(Twig_Token::BLOCK_END_TYPE);
41
- $body = $this->parser->subparse(array($this, 'decideIfFork'));
42
- $tests = array($expr, $body);
43
- $else = null;
44
-
45
- $end = false;
46
- while (!$end) {
47
- switch ($stream->next()->getValue()) {
48
- case 'else':
49
- $stream->expect(Twig_Token::BLOCK_END_TYPE);
50
- $else = $this->parser->subparse(array($this, 'decideIfEnd'));
51
- break;
52
-
53
- case 'elseif':
54
- $expr = $this->parser->getExpressionParser()->parseExpression();
55
- $stream->expect(Twig_Token::BLOCK_END_TYPE);
56
- $body = $this->parser->subparse(array($this, 'decideIfFork'));
57
- $tests[] = $expr;
58
- $tests[] = $body;
59
- break;
60
-
61
- case 'endif':
62
- $end = true;
63
- break;
64
-
65
- default:
66
- throw new Twig_Error_Syntax(sprintf('Unexpected end of template. Twig was looking for the following tags "else", "elseif", or "endif" to close the "if" block started at line %d)', $lineno), $stream->getCurrent()->getLine(), $stream->getFilename());
67
- }
68
- }
69
-
70
- $stream->expect(Twig_Token::BLOCK_END_TYPE);
71
-
72
- return new Twig_Node_If(new Twig_Node($tests), $else, $lineno, $this->getTag());
73
- }
74
-
75
- public function decideIfFork(Twig_Token $token)
76
- {
77
- return $token->test(array('elseif', 'else', 'endif'));
78
- }
79
-
80
- public function decideIfEnd(Twig_Token $token)
81
- {
82
- return $token->test(array('endif'));
83
- }
84
-
85
- /**
86
- * Gets the tag name associated with this token parser.
87
- *
88
- * @return string The tag name
89
- */
90
- public function getTag()
91
- {
92
- return 'if';
93
- }
94
- }
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2009 Fabien Potencier
7
+ * (c) 2009 Armin Ronacher
8
+ *
9
+ * For the full copyright and license information, please view the LICENSE
10
+ * file that was distributed with this source code.
11
+ */
12
+
13
+ /**
14
+ * Tests a condition.
15
+ *
16
+ * <pre>
17
+ * {% if users %}
18
+ * <ul>
19
+ * {% for user in users %}
20
+ * <li>{{ user.username|e }}</li>
21
+ * {% endfor %}
22
+ * </ul>
23
+ * {% endif %}
24
+ * </pre>
25
+ */
26
+ class Twig_TokenParser_If extends Twig_TokenParser
27
+ {
28
+ /**
29
+ * Parses a token and returns a node.
30
+ *
31
+ * @param Twig_Token $token A Twig_Token instance
32
+ *
33
+ * @return Twig_NodeInterface A Twig_NodeInterface instance
34
+ */
35
+ public function parse(Twig_Token $token)
36
+ {
37
+ $lineno = $token->getLine();
38
+ $expr = $this->parser->getExpressionParser()->parseExpression();
39
+ $stream = $this->parser->getStream();
40
+ $stream->expect(Twig_Token::BLOCK_END_TYPE);
41
+ $body = $this->parser->subparse(array($this, 'decideIfFork'));
42
+ $tests = array($expr, $body);
43
+ $else = null;
44
+
45
+ $end = false;
46
+ while (!$end) {
47
+ switch ($stream->next()->getValue()) {
48
+ case 'else':
49
+ $stream->expect(Twig_Token::BLOCK_END_TYPE);
50
+ $else = $this->parser->subparse(array($this, 'decideIfEnd'));
51
+ break;
52
+
53
+ case 'elseif':
54
+ $expr = $this->parser->getExpressionParser()->parseExpression();
55
+ $stream->expect(Twig_Token::BLOCK_END_TYPE);
56
+ $body = $this->parser->subparse(array($this, 'decideIfFork'));
57
+ $tests[] = $expr;
58
+ $tests[] = $body;
59
+ break;
60
+
61
+ case 'endif':
62
+ $end = true;
63
+ break;
64
+
65
+ default:
66
+ throw new Twig_Error_Syntax(sprintf('Unexpected end of template. Twig was looking for the following tags "else", "elseif", or "endif" to close the "if" block started at line %d)', $lineno), $stream->getCurrent()->getLine(), $stream->getFilename());
67
+ }
68
+ }
69
+
70
+ $stream->expect(Twig_Token::BLOCK_END_TYPE);
71
+
72
+ return new Twig_Node_If(new Twig_Node($tests), $else, $lineno, $this->getTag());
73
+ }
74
+
75
+ public function decideIfFork(Twig_Token $token)
76
+ {
77
+ return $token->test(array('elseif', 'else', 'endif'));
78
+ }
79
+
80
+ public function decideIfEnd(Twig_Token $token)
81
+ {
82
+ return $token->test(array('endif'));
83
+ }
84
+
85
+ /**
86
+ * Gets the tag name associated with this token parser.
87
+ *
88
+ * @return string The tag name
89
+ */
90
+ public function getTag()
91
+ {
92
+ return 'if';
93
+ }
94
+ }
classes/Twig/TokenParser/Import.php CHANGED
@@ -1,49 +1,49 @@
1
- <?php
2
-
3
- /*
4
- * This file is part of Twig.
5
- *
6
- * (c) 2009 Fabien Potencier
7
- *
8
- * For the full copyright and license information, please view the LICENSE
9
- * file that was distributed with this source code.
10
- */
11
-
12
- /**
13
- * Imports macros.
14
- *
15
- * <pre>
16
- * {% import 'forms.html' as forms %}
17
- * </pre>
18
- */
19
- class Twig_TokenParser_Import extends Twig_TokenParser
20
- {
21
- /**
22
- * Parses a token and returns a node.
23
- *
24
- * @param Twig_Token $token A Twig_Token instance
25
- *
26
- * @return Twig_NodeInterface A Twig_NodeInterface instance
27
- */
28
- public function parse(Twig_Token $token)
29
- {
30
- $macro = $this->parser->getExpressionParser()->parseExpression();
31
- $this->parser->getStream()->expect('as');
32
- $var = new Twig_Node_Expression_AssignName($this->parser->getStream()->expect(Twig_Token::NAME_TYPE)->getValue(), $token->getLine());
33
- $this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE);
34
-
35
- $this->parser->addImportedSymbol('template', $var->getAttribute('name'));
36
-
37
- return new Twig_Node_Import($macro, $var, $token->getLine(), $this->getTag());
38
- }
39
-
40
- /**
41
- * Gets the tag name associated with this token parser.
42
- *
43
- * @return string The tag name
44
- */
45
- public function getTag()
46
- {
47
- return 'import';
48
- }
49
- }
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2009 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ /**
13
+ * Imports macros.
14
+ *
15
+ * <pre>
16
+ * {% import 'forms.html' as forms %}
17
+ * </pre>
18
+ */
19
+ class Twig_TokenParser_Import extends Twig_TokenParser
20
+ {
21
+ /**
22
+ * Parses a token and returns a node.
23
+ *
24
+ * @param Twig_Token $token A Twig_Token instance
25
+ *
26
+ * @return Twig_NodeInterface A Twig_NodeInterface instance
27
+ */
28
+ public function parse(Twig_Token $token)
29
+ {
30
+ $macro = $this->parser->getExpressionParser()->parseExpression();
31
+ $this->parser->getStream()->expect('as');
32
+ $var = new Twig_Node_Expression_AssignName($this->parser->getStream()->expect(Twig_Token::NAME_TYPE)->getValue(), $token->getLine());
33
+ $this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE);
34
+
35
+ $this->parser->addImportedSymbol('template', $var->getAttribute('name'));
36
+
37
+ return new Twig_Node_Import($macro, $var, $token->getLine(), $this->getTag());
38
+ }
39
+
40
+ /**
41
+ * Gets the tag name associated with this token parser.
42
+ *
43
+ * @return string The tag name
44
+ */
45
+ public function getTag()
46
+ {
47
+ return 'import';
48
+ }
49
+ }
classes/Twig/TokenParser/Include.php CHANGED
@@ -1,75 +1,75 @@
1
- <?php
2
-
3
- /*
4
- * This file is part of Twig.
5
- *
6
- * (c) 2009 Fabien Potencier
7
- * (c) 2009 Armin Ronacher
8
- *
9
- * For the full copyright and license information, please view the LICENSE
10
- * file that was distributed with this source code.
11
- */
12
-
13
- /**
14
- * Includes a template.
15
- *
16
- * <pre>
17
- * {% include 'header.html' %}
18
- * Body
19
- * {% include 'footer.html' %}
20
- * </pre>
21
- */
22
- class Twig_TokenParser_Include extends Twig_TokenParser
23
- {
24
- /**
25
- * Parses a token and returns a node.
26
- *
27
- * @param Twig_Token $token A Twig_Token instance
28
- *
29
- * @return Twig_NodeInterface A Twig_NodeInterface instance
30
- */
31
- public function parse(Twig_Token $token)
32
- {
33
- $expr = $this->parser->getExpressionParser()->parseExpression();
34
-
35
- list($variables, $only, $ignoreMissing) = $this->parseArguments();
36
-
37
- return new Twig_Node_Include($expr, $variables, $only, $ignoreMissing, $token->getLine(), $this->getTag());
38
- }
39
-
40
- protected function parseArguments()
41
- {
42
- $stream = $this->parser->getStream();
43
-
44
- $ignoreMissing = false;
45
- if ($stream->nextIf(Twig_Token::NAME_TYPE, 'ignore')) {
46
- $stream->expect(Twig_Token::NAME_TYPE, 'missing');
47
-
48
- $ignoreMissing = true;
49
- }
50
-
51
- $variables = null;
52
- if ($stream->nextIf(Twig_Token::NAME_TYPE, 'with')) {
53
- $variables = $this->parser->getExpressionParser()->parseExpression();
54
- }
55
-
56
- $only = false;
57
- if ($stream->nextIf(Twig_Token::NAME_TYPE, 'only')) {
58
- $only = true;
59
- }
60
-
61
- $stream->expect(Twig_Token::BLOCK_END_TYPE);
62
-
63
- return array($variables, $only, $ignoreMissing);
64
- }
65
-
66
- /**
67
- * Gets the tag name associated with this token parser.
68
- *
69
- * @return string The tag name
70
- */
71
- public function getTag()
72
- {
73
- return 'include';
74
- }
75
- }
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2009 Fabien Potencier
7
+ * (c) 2009 Armin Ronacher
8
+ *
9
+ * For the full copyright and license information, please view the LICENSE
10
+ * file that was distributed with this source code.
11
+ */
12
+
13
+ /**
14
+ * Includes a template.
15
+ *
16
+ * <pre>
17
+ * {% include 'header.html' %}
18
+ * Body
19
+ * {% include 'footer.html' %}
20
+ * </pre>
21
+ */
22
+ class Twig_TokenParser_Include extends Twig_TokenParser
23
+ {
24
+ /**
25
+ * Parses a token and returns a node.
26
+ *
27
+ * @param Twig_Token $token A Twig_Token instance
28
+ *
29
+ * @return Twig_NodeInterface A Twig_NodeInterface instance
30
+ */
31
+ public function parse(Twig_Token $token)
32
+ {
33
+ $expr = $this->parser->getExpressionParser()->parseExpression();
34
+
35
+ list($variables, $only, $ignoreMissing) = $this->parseArguments();
36
+
37
+ return new Twig_Node_Include($expr, $variables, $only, $ignoreMissing, $token->getLine(), $this->getTag());
38
+ }
39
+
40
+ protected function parseArguments()
41
+ {
42
+ $stream = $this->parser->getStream();
43
+
44
+ $ignoreMissing = false;
45
+ if ($stream->nextIf(Twig_Token::NAME_TYPE, 'ignore')) {
46
+ $stream->expect(Twig_Token::NAME_TYPE, 'missing');
47
+
48
+ $ignoreMissing = true;
49
+ }
50
+
51
+ $variables = null;
52
+ if ($stream->nextIf(Twig_Token::NAME_TYPE, 'with')) {
53
+ $variables = $this->parser->getExpressionParser()->parseExpression();
54
+ }
55
+
56
+ $only = false;
57
+ if ($stream->nextIf(Twig_Token::NAME_TYPE, 'only')) {
58
+ $only = true;
59
+ }
60
+
61
+ $stream->expect(Twig_Token::BLOCK_END_TYPE);
62
+
63
+ return array($variables, $only, $ignoreMissing);
64
+ }
65
+
66
+ /**
67
+ * Gets the tag name associated with this token parser.
68
+ *
69
+ * @return string The tag name
70
+ */
71
+ public function getTag()
72
+ {
73
+ return 'include';
74
+ }
75
+ }
classes/Twig/TokenParser/Macro.php CHANGED
@@ -1,68 +1,68 @@
1
- <?php
2
-
3
- /*
4
- * This file is part of Twig.
5
- *
6
- * (c) 2009 Fabien Potencier
7
- *
8
- * For the full copyright and license information, please view the LICENSE
9
- * file that was distributed with this source code.
10
- */
11
-
12
- /**
13
- * Defines a macro.
14
- *
15
- * <pre>
16
- * {% macro input(name, value, type, size) %}
17
- * <input type="{{ type|default('text') }}" name="{{ name }}" value="{{ value|e }}" size="{{ size|default(20) }}" />
18
- * {% endmacro %}
19
- * </pre>
20
- */
21
- class Twig_TokenParser_Macro extends Twig_TokenParser
22
- {
23
- /**
24
- * Parses a token and returns a node.
25
- *
26
- * @param Twig_Token $token A Twig_Token instance
27
- *
28
- * @return Twig_NodeInterface A Twig_NodeInterface instance
29
- */
30
- public function parse(Twig_Token $token)
31
- {
32
- $lineno = $token->getLine();
33
- $stream = $this->parser->getStream();
34
- $name = $stream->expect(Twig_Token::NAME_TYPE)->getValue();
35
-
36
- $arguments = $this->parser->getExpressionParser()->parseArguments(true, true);
37
-
38
- $stream->expect(Twig_Token::BLOCK_END_TYPE);
39
- $this->parser->pushLocalScope();
40
- $body = $this->parser->subparse(array($this, 'decideBlockEnd'), true);
41
- if ($token = $stream->nextIf(Twig_Token::NAME_TYPE)) {
42
- $value = $token->getValue();
43
-
44
- if ($value != $name) {
45
- throw new Twig_Error_Syntax(sprintf("Expected endmacro for macro '$name' (but %s given)", $value), $stream->getCurrent()->getLine(), $stream->getFilename());
46
- }
47
- }
48
- $this->parser->popLocalScope();
49
- $stream->expect(Twig_Token::BLOCK_END_TYPE);
50
-
51
- $this->parser->setMacro($name, new Twig_Node_Macro($name, new Twig_Node_Body(array($body)), $arguments, $lineno, $this->getTag()));
52
- }
53
-
54
- public function decideBlockEnd(Twig_Token $token)
55
- {
56
- return $token->test('endmacro');
57
- }
58
-
59
- /**
60
- * Gets the tag name associated with this token parser.
61
- *
62
- * @return string The tag name
63
- */
64
- public function getTag()
65
- {
66
- return 'macro';
67
- }
68
- }
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2009 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ /**
13
+ * Defines a macro.
14
+ *
15
+ * <pre>
16
+ * {% macro input(name, value, type, size) %}
17
+ * <input type="{{ type|default('text') }}" name="{{ name }}" value="{{ value|e }}" size="{{ size|default(20) }}" />
18
+ * {% endmacro %}
19
+ * </pre>
20
+ */
21
+ class Twig_TokenParser_Macro extends Twig_TokenParser
22
+ {
23
+ /**
24
+ * Parses a token and returns a node.
25
+ *
26
+ * @param Twig_Token $token A Twig_Token instance
27
+ *
28
+ * @return Twig_NodeInterface A Twig_NodeInterface instance
29
+ */
30
+ public function parse(Twig_Token $token)
31
+ {
32
+ $lineno = $token->getLine();
33
+ $stream = $this->parser->getStream();
34
+ $name = $stream->expect(Twig_Token::NAME_TYPE)->getValue();
35
+
36
+ $arguments = $this->parser->getExpressionParser()->parseArguments(true, true);
37
+
38
+ $stream->expect(Twig_Token::BLOCK_END_TYPE);
39
+ $this->parser->pushLocalScope();
40
+ $body = $this->parser->subparse(array($this, 'decideBlockEnd'), true);
41
+ if ($token = $stream->nextIf(Twig_Token::NAME_TYPE)) {
42
+ $value = $token->getValue();
43
+
44
+ if ($value != $name) {
45
+ throw new Twig_Error_Syntax(sprintf("Expected endmacro for macro '$name' (but %s given)", $value), $stream->getCurrent()->getLine(), $stream->getFilename());
46
+ }
47
+ }
48
+ $this->parser->popLocalScope();
49
+ $stream->expect(Twig_Token::BLOCK_END_TYPE);
50
+
51
+ $this->parser->setMacro($name, new Twig_Node_Macro($name, new Twig_Node_Body(array($body)), $arguments, $lineno, $this->getTag()));
52
+ }
53
+
54
+ public function decideBlockEnd(Twig_Token $token)
55
+ {
56
+ return $token->test('endmacro');
57
+ }
58
+
59
+ /**
60
+ * Gets the tag name associated with this token parser.
61
+ *
62
+ * @return string The tag name
63
+ */
64
+ public function getTag()
65
+ {
66
+ return 'macro';
67
+ }
68
+ }
classes/Twig/TokenParser/Sandbox.php CHANGED
@@ -1,68 +1,68 @@
1
- <?php
2
-
3
- /*
4
- * This file is part of Twig.
5
- *
6
- * (c) 2010 Fabien Potencier
7
- *
8
- * For the full copyright and license information, please view the LICENSE
9
- * file that was distributed with this source code.
10
- */
11
-
12
- /**
13
- * Marks a section of a template as untrusted code that must be evaluated in the sandbox mode.
14
- *
15
- * <pre>
16
- * {% sandbox %}
17
- * {% include 'user.html' %}
18
- * {% endsandbox %}
19
- * </pre>
20
- *
21
- * @see http://www.twig-project.org/doc/api.html#sandbox-extension for details
22
- */
23
- class Twig_TokenParser_Sandbox extends Twig_TokenParser
24
- {
25
- /**
26
- * Parses a token and returns a node.
27
- *
28
- * @param Twig_Token $token A Twig_Token instance
29
- *
30
- * @return Twig_NodeInterface A Twig_NodeInterface instance
31
- */
32
- public function parse(Twig_Token $token)
33
- {
34
- $this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE);
35
- $body = $this->parser->subparse(array($this, 'decideBlockEnd'), true);
36
- $this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE);
37
-
38
- // in a sandbox tag, only include tags are allowed
39
- if (!$body instanceof Twig_Node_Include) {
40
- foreach ($body as $node) {
41
- if ($node instanceof Twig_Node_Text && ctype_space($node->getAttribute('data'))) {
42
- continue;
43
- }
44
-
45
- if (!$node instanceof Twig_Node_Include) {
46
- throw new Twig_Error_Syntax('Only "include" tags are allowed within a "sandbox" section', $node->getLine(), $this->parser->getFilename());
47
- }
48
- }
49
- }
50
-
51
- return new Twig_Node_Sandbox($body, $token->getLine(), $this->getTag());
52
- }
53
-
54
- public function decideBlockEnd(Twig_Token $token)
55
- {
56
- return $token->test('endsandbox');
57
- }
58
-
59
- /**
60
- * Gets the tag name associated with this token parser.
61
- *
62
- * @return string The tag name
63
- */
64
- public function getTag()
65
- {
66
- return 'sandbox';
67
- }
68
- }
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2010 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ /**
13
+ * Marks a section of a template as untrusted code that must be evaluated in the sandbox mode.
14
+ *
15
+ * <pre>
16
+ * {% sandbox %}
17
+ * {% include 'user.html' %}
18
+ * {% endsandbox %}
19
+ * </pre>
20
+ *
21
+ * @see http://www.twig-project.org/doc/api.html#sandbox-extension for details
22
+ */
23
+ class Twig_TokenParser_Sandbox extends Twig_TokenParser
24
+ {
25
+ /**
26
+ * Parses a token and returns a node.
27
+ *
28
+ * @param Twig_Token $token A Twig_Token instance
29
+ *
30
+ * @return Twig_NodeInterface A Twig_NodeInterface instance
31
+ */
32
+ public function parse(Twig_Token $token)
33
+ {
34
+ $this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE);
35
+ $body = $this->parser->subparse(array($this, 'decideBlockEnd'), true);
36
+ $this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE);
37
+
38
+ // in a sandbox tag, only include tags are allowed
39
+ if (!$body instanceof Twig_Node_Include) {
40
+ foreach ($body as $node) {
41
+ if ($node instanceof Twig_Node_Text && ctype_space($node->getAttribute('data'))) {
42
+ continue;
43
+ }
44
+
45
+ if (!$node instanceof Twig_Node_Include) {
46
+ throw new Twig_Error_Syntax('Only "include" tags are allowed within a "sandbox" section', $node->getLine(), $this->parser->getFilename());
47
+ }
48
+ }
49
+ }
50
+
51
+ return new Twig_Node_Sandbox($body, $token->getLine(), $this->getTag());
52
+ }
53
+
54
+ public function decideBlockEnd(Twig_Token $token)
55
+ {
56
+ return $token->test('endsandbox');
57
+ }
58
+
59
+ /**
60
+ * Gets the tag name associated with this token parser.
61
+ *
62
+ * @return string The tag name
63
+ */
64
+ public function getTag()
65
+ {
66
+ return 'sandbox';
67
+ }
68
+ }
classes/Twig/TokenParser/Set.php CHANGED
@@ -1,83 +1,83 @@
1
- <?php
2
-
3
- /*
4
- * This file is part of Twig.
5
- *
6
- * (c) 2009 Fabien Potencier
7
- *
8
- * For the full copyright and license information, please view the LICENSE
9
- * file that was distributed with this source code.
10
- */
11
-
12
- /**
13
- * Defines a variable.
14
- *
15
- * <pre>
16
- * {% set foo = 'foo' %}
17
- *
18
- * {% set foo = [1, 2] %}
19
- *
20
- * {% set foo = {'foo': 'bar'} %}
21
- *
22
- * {% set foo = 'foo' ~ 'bar' %}
23
- *
24
- * {% set foo, bar = 'foo', 'bar' %}
25
- *
26
- * {% set foo %}Some content{% endset %}
27
- * </pre>
28
- */
29
- class Twig_TokenParser_Set extends Twig_TokenParser
30
- {
31
- /**
32
- * Parses a token and returns a node.
33
- *
34
- * @param Twig_Token $token A Twig_Token instance
35
- *
36
- * @return Twig_NodeInterface A Twig_NodeInterface instance
37
- */
38
- public function parse(Twig_Token $token)
39
- {
40
- $lineno = $token->getLine();
41
- $stream = $this->parser->getStream();
42
- $names = $this->parser->getExpressionParser()->parseAssignmentExpression();
43
-
44
- $capture = false;
45
- if ($stream->nextIf(Twig_Token::OPERATOR_TYPE, '=')) {
46
- $values = $this->parser->getExpressionParser()->parseMultitargetExpression();
47
-
48
- $stream->expect(Twig_Token::BLOCK_END_TYPE);
49
-
50
- if (count($names) !== count($values)) {
51
- throw new Twig_Error_Syntax("When using set, you must have the same number of variables and assignments.", $stream->getCurrent()->getLine(), $stream->getFilename());
52
- }
53
- } else {
54
- $capture = true;
55
-
56
- if (count($names) > 1) {
57
- throw new Twig_Error_Syntax("When using set with a block, you cannot have a multi-target.", $stream->getCurrent()->getLine(), $stream->getFilename());
58
- }
59
-
60
- $stream->expect(Twig_Token::BLOCK_END_TYPE);
61
-
62
- $values = $this->parser->subparse(array($this, 'decideBlockEnd'), true);
63
- $stream->expect(Twig_Token::BLOCK_END_TYPE);
64
- }
65
-
66
- return new Twig_Node_Set($capture, $names, $values, $lineno, $this->getTag());
67
- }
68
-
69
- public function decideBlockEnd(Twig_Token $token)
70
- {
71
- return $token->test('endset');
72
- }
73
-
74
- /**
75
- * Gets the tag name associated with this token parser.
76
- *
77
- * @return string The tag name
78
- */
79
- public function getTag()
80
- {
81
- return 'set';
82
- }
83
- }
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2009 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ /**
13
+ * Defines a variable.
14
+ *
15
+ * <pre>
16
+ * {% set foo = 'foo' %}
17
+ *
18
+ * {% set foo = [1, 2] %}
19
+ *
20
+ * {% set foo = {'foo': 'bar'} %}
21
+ *
22
+ * {% set foo = 'foo' ~ 'bar' %}
23
+ *
24
+ * {% set foo, bar = 'foo', 'bar' %}
25
+ *
26
+ * {% set foo %}Some content{% endset %}
27
+ * </pre>
28
+ */
29
+ class Twig_TokenParser_Set extends Twig_TokenParser
30
+ {
31
+ /**
32
+ * Parses a token and returns a node.
33
+ *
34
+ * @param Twig_Token $token A Twig_Token instance
35
+ *
36
+ * @return Twig_NodeInterface A Twig_NodeInterface instance
37
+ */
38
+ public function parse(Twig_Token $token)
39
+ {
40
+ $lineno = $token->getLine();
41
+ $stream = $this->parser->getStream();
42
+ $names = $this->parser->getExpressionParser()->parseAssignmentExpression();
43
+
44
+ $capture = false;
45
+ if ($stream->nextIf(Twig_Token::OPERATOR_TYPE, '=')) {
46
+ $values = $this->parser->getExpressionParser()->parseMultitargetExpression();
47
+
48
+ $stream->expect(Twig_Token::BLOCK_END_TYPE);
49
+
50
+ if (count($names) !== count($values)) {
51
+ throw new Twig_Error_Syntax("When using set, you must have the same number of variables and assignments.", $stream->getCurrent()->getLine(), $stream->getFilename());
52
+ }
53
+ } else {
54
+ $capture = true;
55
+
56
+ if (count($names) > 1) {
57
+ throw new Twig_Error_Syntax("When using set with a block, you cannot have a multi-target.", $stream->getCurrent()->getLine(), $stream->getFilename());
58
+ }
59
+
60
+ $stream->expect(Twig_Token::BLOCK_END_TYPE);
61
+
62
+ $values = $this->parser->subparse(array($this, 'decideBlockEnd'), true);
63
+ $stream->expect(Twig_Token::BLOCK_END_TYPE);
64
+ }
65
+
66
+ return new Twig_Node_Set($capture, $names, $values, $lineno, $this->getTag());
67
+ }
68
+
69
+ public function decideBlockEnd(Twig_Token $token)
70
+ {
71
+ return $token->test('endset');
72
+ }
73
+
74
+ /**
75
+ * Gets the tag name associated with this token parser.
76
+ *
77
+ * @return string The tag name
78
+ */
79
+ public function getTag()
80
+ {
81
+ return 'set';
82
+ }
83
+ }
classes/Twig/TokenParser/Spaceless.php CHANGED
@@ -1,59 +1,59 @@
1
- <?php
2
-
3
- /*
4
- * This file is part of Twig.
5
- *
6
- * (c) 2010 Fabien Potencier
7
- *
8
- * For the full copyright and license information, please view the LICENSE
9
- * file that was distributed with this source code.
10
- */
11
-
12
- /**
13
- * Remove whitespaces between HTML tags.
14
- *
15
- * <pre>
16
- * {% spaceless %}
17
- * <div>
18
- * <strong>foo</strong>
19
- * </div>
20
- * {% endspaceless %}
21
- *
22
- * {# output will be <div><strong>foo</strong></div> #}
23
- * </pre>
24
- */
25
- class Twig_TokenParser_Spaceless extends Twig_TokenParser
26
- {
27
- /**
28
- * Parses a token and returns a node.
29
- *
30
- * @param Twig_Token $token A Twig_Token instance
31
- *
32
- * @return Twig_NodeInterface A Twig_NodeInterface instance
33
- */
34
- public function parse(Twig_Token $token)
35
- {
36
- $lineno = $token->getLine();
37
-
38
- $this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE);
39
- $body = $this->parser->subparse(array($this, 'decideSpacelessEnd'), true);
40
- $this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE);
41
-
42
- return new Twig_Node_Spaceless($body, $lineno, $this->getTag());
43
- }
44
-
45
- public function decideSpacelessEnd(Twig_Token $token)
46
- {
47
- return $token->test('endspaceless');
48
- }
49
-
50
- /**
51
- * Gets the tag name associated with this token parser.
52
- *
53
- * @return string The tag name
54
- */
55
- public function getTag()
56
- {
57
- return 'spaceless';
58
- }
59
- }
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2010 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ /**
13
+ * Remove whitespaces between HTML tags.
14
+ *
15
+ * <pre>
16
+ * {% spaceless %}
17
+ * <div>
18
+ * <strong>foo</strong>
19
+ * </div>
20
+ * {% endspaceless %}
21
+ *
22
+ * {# output will be <div><strong>foo</strong></div> #}
23
+ * </pre>
24
+ */
25
+ class Twig_TokenParser_Spaceless extends Twig_TokenParser
26
+ {
27
+ /**
28
+ * Parses a token and returns a node.
29
+ *
30
+ * @param Twig_Token $token A Twig_Token instance
31
+ *
32
+ * @return Twig_NodeInterface A Twig_NodeInterface instance
33
+ */
34
+ public function parse(Twig_Token $token)
35
+ {
36
+ $lineno = $token->getLine();
37
+
38
+ $this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE);
39
+ $body = $this->parser->subparse(array($this, 'decideSpacelessEnd'), true);
40
+ $this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE);
41
+
42
+ return new Twig_Node_Spaceless($body, $lineno, $this->getTag());
43
+ }
44
+
45
+ public function decideSpacelessEnd(Twig_Token $token)
46
+ {
47
+ return $token->test('endspaceless');
48
+ }
49
+
50
+ /**
51
+ * Gets the tag name associated with this token parser.
52
+ *
53
+ * @return string The tag name
54
+ */
55
+ public function getTag()
56
+ {
57
+ return 'spaceless';
58
+ }
59
+ }
classes/Twig/TokenParser/Use.php CHANGED
@@ -1,76 +1,76 @@
1
- <?php
2
-
3
- /*
4
- * This file is part of Twig.
5
- *
6
- * (c) 2011 Fabien Potencier
7
- *
8
- * For the full copyright and license information, please view the LICENSE
9
- * file that was distributed with this source code.
10
- */
11
-
12
- /**
13
- * Imports blocks defined in another template into the current template.
14
- *
15
- * <pre>
16
- * {% extends "base.html" %}
17
- *
18
- * {% use "blocks.html" %}
19
- *
20
- * {% block title %}{% endblock %}
21
- * {% block content %}{% endblock %}
22
- * </pre>
23
- *
24
- * @see http://www.twig-project.org/doc/templates.html#horizontal-reuse for details.
25
- */
26
- class Twig_TokenParser_Use extends Twig_TokenParser
27
- {
28
- /**
29
- * Parses a token and returns a node.
30
- *
31
- * @param Twig_Token $token A Twig_Token instance
32
- *
33
- * @return Twig_NodeInterface A Twig_NodeInterface instance
34
- */
35
- public function parse(Twig_Token $token)
36
- {
37
- $template = $this->parser->getExpressionParser()->parseExpression();
38
- $stream = $this->parser->getStream();
39
-
40
- if (!$template instanceof Twig_Node_Expression_Constant) {
41
- throw new Twig_Error_Syntax('The template references in a "use" statement must be a string.', $stream->getCurrent()->getLine(), $stream->getFilename());
42
- }
43
-
44
- $targets = array();
45
- if ($stream->nextIf('with')) {
46
- do {
47
- $name = $stream->expect(Twig_Token::NAME_TYPE)->getValue();
48
-
49
- $alias = $name;
50
- if ($stream->nextIf('as')) {
51
- $alias = $stream->expect(Twig_Token::NAME_TYPE)->getValue();
52
- }
53
-
54
- $targets[$name] = new Twig_Node_Expression_Constant($alias, -1);
55
-
56
- if (!$stream->nextIf(Twig_Token::PUNCTUATION_TYPE, ',')) {
57
- break;
58
- }
59
- } while (true);
60
- }
61
-
62
- $stream->expect(Twig_Token::BLOCK_END_TYPE);
63
-
64
- $this->parser->addTrait(new Twig_Node(array('template' => $template, 'targets' => new Twig_Node($targets))));
65
- }
66
-
67
- /**
68
- * Gets the tag name associated with this token parser.
69
- *
70
- * @return string The tag name
71
- */
72
- public function getTag()
73
- {
74
- return 'use';
75
- }
76
- }
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2011 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ /**
13
+ * Imports blocks defined in another template into the current template.
14
+ *
15
+ * <pre>
16
+ * {% extends "base.html" %}
17
+ *
18
+ * {% use "blocks.html" %}
19
+ *
20
+ * {% block title %}{% endblock %}
21
+ * {% block content %}{% endblock %}
22
+ * </pre>
23
+ *
24
+ * @see http://www.twig-project.org/doc/templates.html#horizontal-reuse for details.
25
+ */
26
+ class Twig_TokenParser_Use extends Twig_TokenParser
27
+ {
28
+ /**
29
+ * Parses a token and returns a node.
30
+ *
31
+ * @param Twig_Token $token A Twig_Token instance
32
+ *
33
+ * @return Twig_NodeInterface A Twig_NodeInterface instance
34
+ */
35
+ public function parse(Twig_Token $token)
36
+ {
37
+ $template = $this->parser->getExpressionParser()->parseExpression();
38
+ $stream = $this->parser->getStream();
39
+
40
+ if (!$template instanceof Twig_Node_Expression_Constant) {
41
+ throw new Twig_Error_Syntax('The template references in a "use" statement must be a string.', $stream->getCurrent()->getLine(), $stream->getFilename());
42
+ }
43
+
44
+ $targets = array();
45
+ if ($stream->nextIf('with')) {
46
+ do {
47
+ $name = $stream->expect(Twig_Token::NAME_TYPE)->getValue();
48
+
49
+ $alias = $name;
50
+ if ($stream->nextIf('as')) {
51
+ $alias = $stream->expect(Twig_Token::NAME_TYPE)->getValue();
52
+ }
53
+
54
+ $targets[$name] = new Twig_Node_Expression_Constant($alias, -1);
55
+
56
+ if (!$stream->nextIf(Twig_Token::PUNCTUATION_TYPE, ',')) {
57
+ break;
58
+ }
59
+ } while (true);
60
+ }
61
+
62
+ $stream->expect(Twig_Token::BLOCK_END_TYPE);
63
+
64
+ $this->parser->addTrait(new Twig_Node(array('template' => $template, 'targets' => new Twig_Node($targets))));
65
+ }
66
+
67
+ /**
68
+ * Gets the tag name associated with this token parser.
69
+ *
70
+ * @return string The tag name
71
+ */
72
+ public function getTag()
73
+ {
74
+ return 'use';
75
+ }
76
+ }
classes/Twig/TokenParserBroker.php CHANGED
@@ -1,136 +1,136 @@
1
- <?php
2
-
3
- /*
4
- * This file is part of Twig.
5
- *
6
- * (c) 2010 Fabien Potencier
7
- * (c) 2010 Arnaud Le Blanc
8
- *
9
- * For the full copyright and license information, please view the LICENSE
10
- * file that was distributed with this source code.
11
- */
12
-
13
- /**
14
- * Default implementation of a token parser broker.
15
- *
16
- * @author Arnaud Le Blanc <arnaud.lb@gmail.com>
17
- * @deprecated since 1.12 (to be removed in 2.0)
18
- */
19
- class Twig_TokenParserBroker implements Twig_TokenParserBrokerInterface
20
- {
21
- protected $parser;
22
- protected $parsers = array();
23
- protected $brokers = array();
24
-
25
- /**
26
- * Constructor.
27
- *
28
- * @param array|Traversable $parsers A Traversable of Twig_TokenParserInterface instances
29
- * @param array|Traversable $brokers A Traversable of Twig_TokenParserBrokerInterface instances
30
- */
31
- public function __construct($parsers = array(), $brokers = array())
32
- {
33
- foreach ($parsers as $parser) {
34
- if (!$parser instanceof Twig_TokenParserInterface) {
35
- throw new LogicException('$parsers must a an array of Twig_TokenParserInterface');
36
- }
37
- $this->parsers[$parser->getTag()] = $parser;
38
- }
39
- foreach ($brokers as $broker) {
40
- if (!$broker instanceof Twig_TokenParserBrokerInterface) {
41
- throw new LogicException('$brokers must a an array of Twig_TokenParserBrokerInterface');
42
- }
43
- $this->brokers[] = $broker;
44
- }
45
- }
46
-
47
- /**
48
- * Adds a TokenParser.
49
- *
50
- * @param Twig_TokenParserInterface $parser A Twig_TokenParserInterface instance
51
- */
52
- public function addTokenParser(Twig_TokenParserInterface $parser)
53
- {
54
- $this->parsers[$parser->getTag()] = $parser;
55
- }
56
-
57
- /**
58
- * Removes a TokenParser.
59
- *
60
- * @param Twig_TokenParserInterface $parser A Twig_TokenParserInterface instance
61
- */
62
- public function removeTokenParser(Twig_TokenParserInterface $parser)
63
- {
64
- $name = $parser->getTag();
65
- if (isset($this->parsers[$name]) && $parser === $this->parsers[$name]) {
66
- unset($this->parsers[$name]);
67
- }
68
- }
69
-
70
- /**
71
- * Adds a TokenParserBroker.
72
- *
73
- * @param Twig_TokenParserBroker $broker A Twig_TokenParserBroker instance
74
- */
75
- public function addTokenParserBroker(Twig_TokenParserBroker $broker)
76
- {
77
- $this->brokers[] = $broker;
78
- }
79
-
80
- /**
81
- * Removes a TokenParserBroker.
82
- *
83
- * @param Twig_TokenParserBroker $broker A Twig_TokenParserBroker instance
84
- */
85
- public function removeTokenParserBroker(Twig_TokenParserBroker $broker)
86
- {
87
- if (false !== $pos = array_search($broker, $this->brokers)) {
88
- unset($this->brokers[$pos]);
89
- }
90
- }
91
-
92
- /**
93
- * Gets a suitable TokenParser for a tag.
94
- *
95
- * First looks in parsers, then in brokers.
96
- *
97
- * @param string $tag A tag name
98
- *
99
- * @return null|Twig_TokenParserInterface A Twig_TokenParserInterface or null if no suitable TokenParser was found
100
- */
101
- public function getTokenParser($tag)
102
- {
103
- if (isset($this->parsers[$tag])) {
104
- return $this->parsers[$tag];
105
- }
106
- $broker = end($this->brokers);
107
- while (false !== $broker) {
108
- $parser = $broker->getTokenParser($tag);
109
- if (null !== $parser) {
110
- return $parser;
111
- }
112
- $broker = prev($this->brokers);
113
- }
114
- }
115
-
116
- public function getParsers()
117
- {
118
- return $this->parsers;
119
- }
120
-
121
- public function getParser()
122
- {
123
- return $this->parser;
124
- }
125
-
126
- public function setParser(Twig_ParserInterface $parser)
127
- {
128
- $this->parser = $parser;
129
- foreach ($this->parsers as $tokenParser) {
130
- $tokenParser->setParser($parser);
131
- }
132
- foreach ($this->brokers as $broker) {
133
- $broker->setParser($parser);
134
- }
135
- }
136
- }
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2010 Fabien Potencier
7
+ * (c) 2010 Arnaud Le Blanc
8
+ *
9
+ * For the full copyright and license information, please view the LICENSE
10
+ * file that was distributed with this source code.
11
+ */
12
+
13
+ /**
14
+ * Default implementation of a token parser broker.
15
+ *
16
+ * @author Arnaud Le Blanc <arnaud.lb@gmail.com>
17
+ * @deprecated since 1.12 (to be removed in 2.0)
18
+ */
19
+ class Twig_TokenParserBroker implements Twig_TokenParserBrokerInterface
20
+ {
21
+ protected $parser;
22
+ protected $parsers = array();
23
+ protected $brokers = array();
24
+
25
+ /**
26
+ * Constructor.
27
+ *
28
+ * @param array|Traversable $parsers A Traversable of Twig_TokenParserInterface instances
29
+ * @param array|Traversable $brokers A Traversable of Twig_TokenParserBrokerInterface instances
30
+ */
31
+ public function __construct($parsers = array(), $brokers = array())
32
+ {
33
+ foreach ($parsers as $parser) {
34
+ if (!$parser instanceof Twig_TokenParserInterface) {
35
+ throw new LogicException('$parsers must a an array of Twig_TokenParserInterface');
36
+ }
37
+ $this->parsers[$parser->getTag()] = $parser;
38
+ }
39
+ foreach ($brokers as $broker) {
40
+ if (!$broker instanceof Twig_TokenParserBrokerInterface) {
41
+ throw new LogicException('$brokers must a an array of Twig_TokenParserBrokerInterface');
42
+ }
43
+ $this->brokers[] = $broker;
44
+ }
45
+ }
46
+
47
+ /**
48
+ * Adds a TokenParser.
49
+ *
50
+ * @param Twig_TokenParserInterface $parser A Twig_TokenParserInterface instance
51
+ */
52
+ public function addTokenParser(Twig_TokenParserInterface $parser)
53
+ {
54
+ $this->parsers[$parser->getTag()] = $parser;
55
+ }
56
+
57
+ /**
58
+ * Removes a TokenParser.
59
+ *
60
+ * @param Twig_TokenParserInterface $parser A Twig_TokenParserInterface instance
61
+ */
62
+ public function removeTokenParser(Twig_TokenParserInterface $parser)
63
+ {
64
+ $name = $parser->getTag();
65
+ if (isset($this->parsers[$name]) && $parser === $this->parsers[$name]) {
66
+ unset($this->parsers[$name]);
67
+ }
68
+ }
69
+
70
+ /**
71
+ * Adds a TokenParserBroker.
72
+ *
73
+ * @param Twig_TokenParserBroker $broker A Twig_TokenParserBroker instance
74
+ */
75
+ public function addTokenParserBroker(Twig_TokenParserBroker $broker)
76
+ {
77
+ $this->brokers[] = $broker;
78
+ }
79
+
80
+ /**
81
+ * Removes a TokenParserBroker.
82
+ *
83
+ * @param Twig_TokenParserBroker $broker A Twig_TokenParserBroker instance
84
+ */
85
+ public function removeTokenParserBroker(Twig_TokenParserBroker $broker)
86
+ {
87
+ if (false !== $pos = array_search($broker, $this->brokers)) {
88
+ unset($this->brokers[$pos]);
89
+ }
90
+ }
91
+
92
+ /**
93
+ * Gets a suitable TokenParser for a tag.
94
+ *
95
+ * First looks in parsers, then in brokers.
96
+ *
97
+ * @param string $tag A tag name
98
+ *
99
+ * @return null|Twig_TokenParserInterface A Twig_TokenParserInterface or null if no suitable TokenParser was found
100
+ */
101
+ public function getTokenParser($tag)
102
+ {
103
+ if (isset($this->parsers[$tag])) {
104
+ return $this->parsers[$tag];
105
+ }
106
+ $broker = end($this->brokers);
107
+ while (false !== $broker) {
108
+ $parser = $broker->getTokenParser($tag);
109
+ if (null !== $parser) {
110
+ return $parser;
111
+ }
112
+ $broker = prev($this->brokers);
113
+ }
114
+ }
115
+
116
+ public function getParsers()
117
+ {
118
+ return $this->parsers;
119
+ }
120
+
121
+ public function getParser()
122
+ {
123
+ return $this->parser;
124
+ }
125
+
126
+ public function setParser(Twig_ParserInterface $parser)
127
+ {
128
+ $this->parser = $parser;
129
+ foreach ($this->parsers as $tokenParser) {
130
+ $tokenParser->setParser($parser);
131
+ }
132
+ foreach ($this->brokers as $broker) {
133
+ $broker->setParser($parser);
134
+ }
135
+ }
136
+ }
classes/Twig/TokenParserBrokerInterface.php CHANGED
@@ -1,45 +1,45 @@
1
- <?php
2
-
3
- /*
4
- * This file is part of Twig.
5
- *
6
- * (c) 2010 Fabien Potencier
7
- * (c) 2010 Arnaud Le Blanc
8
- *
9
- * For the full copyright and license information, please view the LICENSE
10
- * file that was distributed with this source code.
11
- */
12
-
13
- /**
14
- * Interface implemented by token parser brokers.
15
- *
16
- * Token parser brokers allows to implement custom logic in the process of resolving a token parser for a given tag name.
17
- *
18
- * @author Arnaud Le Blanc <arnaud.lb@gmail.com>
19
- * @deprecated since 1.12 (to be removed in 2.0)
20
- */
21
- interface Twig_TokenParserBrokerInterface
22
- {
23
- /**
24
- * Gets a TokenParser suitable for a tag.
25
- *
26
- * @param string $tag A tag name
27
- *
28
- * @return null|Twig_TokenParserInterface A Twig_TokenParserInterface or null if no suitable TokenParser was found
29
- */
30
- public function getTokenParser($tag);
31
-
32
- /**
33
- * Calls Twig_TokenParserInterface::setParser on all parsers the implementation knows of.
34
- *
35
- * @param Twig_ParserInterface $parser A Twig_ParserInterface interface
36
- */
37
- public function setParser(Twig_ParserInterface $parser);
38
-
39
- /**
40
- * Gets the Twig_ParserInterface.
41
- *
42
- * @return null|Twig_ParserInterface A Twig_ParserInterface instance or null
43
- */
44
- public function getParser();
45
- }
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2010 Fabien Potencier
7
+ * (c) 2010 Arnaud Le Blanc
8
+ *
9
+ * For the full copyright and license information, please view the LICENSE
10
+ * file that was distributed with this source code.
11
+ */
12
+
13
+ /**
14
+ * Interface implemented by token parser brokers.
15
+ *
16
+ * Token parser brokers allows to implement custom logic in the process of resolving a token parser for a given tag name.
17
+ *
18
+ * @author Arnaud Le Blanc <arnaud.lb@gmail.com>
19
+ * @deprecated since 1.12 (to be removed in 2.0)
20
+ */
21
+ interface Twig_TokenParserBrokerInterface
22
+ {
23
+ /**
24
+ * Gets a TokenParser suitable for a tag.
25
+ *
26
+ * @param string $tag A tag name
27
+ *
28
+ * @return null|Twig_TokenParserInterface A Twig_TokenParserInterface or null if no suitable TokenParser was found
29
+ */
30
+ public function getTokenParser($tag);
31
+
32
+ /**
33
+ * Calls Twig_TokenParserInterface::setParser on all parsers the implementation knows of.
34
+ *
35
+ * @param Twig_ParserInterface $parser A Twig_ParserInterface interface
36
+ */
37
+ public function setParser(Twig_ParserInterface $parser);
38
+
39
+ /**
40
+ * Gets the Twig_ParserInterface.
41
+ *
42
+ * @return null|Twig_ParserInterface A Twig_ParserInterface instance or null
43
+ */
44
+ public function getParser();
45
+ }
classes/Twig/TokenParserInterface.php CHANGED
@@ -1,43 +1,43 @@
1
- <?php
2
-
3
- /*
4
- * This file is part of Twig.
5
- *
6
- * (c) 2010 Fabien Potencier
7
- *
8
- * For the full copyright and license information, please view the LICENSE
9
- * file that was distributed with this source code.
10
- */
11
-
12
- /**
13
- * Interface implemented by token parsers.
14
- *
15
- * @author Fabien Potencier <fabien@symfony.com>
16
- */
17
- interface Twig_TokenParserInterface
18
- {
19
- /**
20
- * Sets the parser associated with this token parser
21
- *
22
- * @param $parser A Twig_Parser instance
23
- */
24
- public function setParser(Twig_Parser $parser);
25
-
26
- /**
27
- * Parses a token and returns a node.
28
- *
29
- * @param Twig_Token $token A Twig_Token instance
30
- *
31
- * @return Twig_NodeInterface A Twig_NodeInterface instance
32
- *
33
- * @throws Twig_Error_Syntax
34
- */
35
- public function parse(Twig_Token $token);
36
-
37
- /**
38
- * Gets the tag name associated with this token parser.
39
- *
40
- * @return string The tag name
41
- */
42
- public function getTag();
43
- }
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2010 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ /**
13
+ * Interface implemented by token parsers.
14
+ *
15
+ * @author Fabien Potencier <fabien@symfony.com>
16
+ */
17
+ interface Twig_TokenParserInterface
18
+ {
19
+ /**
20
+ * Sets the parser associated with this token parser
21
+ *
22
+ * @param $parser A Twig_Parser instance
23
+ */
24
+ public function setParser(Twig_Parser $parser);
25
+
26
+ /**
27
+ * Parses a token and returns a node.
28
+ *
29
+ * @param Twig_Token $token A Twig_Token instance
30
+ *
31
+ * @return Twig_NodeInterface A Twig_NodeInterface instance
32
+ *
33
+ * @throws Twig_Error_Syntax
34
+ */
35
+ public function parse(Twig_Token $token);
36
+
37
+ /**
38
+ * Gets the tag name associated with this token parser.
39
+ *
40
+ * @return string The tag name
41
+ */
42
+ public function getTag();
43
+ }
classes/Twig/TokenStream.php CHANGED
@@ -1,156 +1,156 @@
1
- <?php
2
-
3
- /*
4
- * This file is part of Twig.
5
- *
6
- * (c) 2009 Fabien Potencier
7
- * (c) 2009 Armin Ronacher
8
- *
9
- * For the full copyright and license information, please view the LICENSE
10
- * file that was distributed with this source code.
11
- */
12
-
13
- /**
14
- * Represents a token stream.
15
- *
16
- * @author Fabien Potencier <fabien@symfony.com>
17
- */
18
- class Twig_TokenStream
19
- {
20
- protected $tokens;
21
- protected $current;
22
- protected $filename;
23
-
24
- /**
25
- * Constructor.
26
- *
27
- * @param array $tokens An array of tokens
28
- * @param string $filename The name of the filename which tokens are associated with
29
- */
30
- public function __construct(array $tokens, $filename = null)
31
- {
32
- $this->tokens = $tokens;
33
- $this->current = 0;
34
- $this->filename = $filename;
35
- }
36
-
37
- /**
38
- * Returns a string representation of the token stream.
39
- *
40
- * @return string
41
- */
42
- public function __toString()
43
- {
44
- return implode("\n", $this->tokens);
45
- }
46
-
47
- public function injectTokens(array $tokens)
48
- {
49
- $this->tokens = array_merge(array_slice($this->tokens, 0, $this->current), $tokens, array_slice($this->tokens, $this->current));
50
- }
51
-
52
- /**
53
- * Sets the pointer to the next token and returns the old one.
54
- *
55
- * @return Twig_Token
56
- */
57
- public function next()
58
- {
59
- if (!isset($this->tokens[++$this->current])) {
60
- throw new Twig_Error_Syntax('Unexpected end of template', $this->tokens[$this->current - 1]->getLine(), $this->filename);
61
- }
62
-
63
- return $this->tokens[$this->current - 1];
64
- }
65
-
66
- /**
67
- * Tests a token, sets the pointer to the next one and returns it or throws a syntax error.
68
- *
69
- * @return Twig_Token|null The next token if the condition is true, null otherwise
70
- */
71
- public function nextIf($primary, $secondary = null)
72
- {
73
- if ($this->tokens[$this->current]->test($primary, $secondary)) {
74
- return $this->next();
75
- }
76
- }
77
-
78
- /**
79
- * Tests a token and returns it or throws a syntax error.
80
- *
81
- * @return Twig_Token
82
- */
83
- public function expect($type, $value = null, $message = null)
84
- {
85
- $token = $this->tokens[$this->current];
86
- if (!$token->test($type, $value)) {
87
- $line = $token->getLine();
88
- throw new Twig_Error_Syntax(sprintf('%sUnexpected token "%s" of value "%s" ("%s" expected%s)',
89
- $message ? $message.'. ' : '',
90
- Twig_Token::typeToEnglish($token->getType()), $token->getValue(),
91
- Twig_Token::typeToEnglish($type), $value ? sprintf(' with value "%s"', $value) : ''),
92
- $line,
93
- $this->filename
94
- );
95
- }
96
- $this->next();
97
-
98
- return $token;
99
- }
100
-
101
- /**
102
- * Looks at the next token.
103
- *
104
- * @param int $number
105
- *
106
- * @return Twig_Token
107
- */
108
- public function look($number = 1)
109
- {
110
- if (!isset($this->tokens[$this->current + $number])) {
111
- throw new Twig_Error_Syntax('Unexpected end of template', $this->tokens[$this->current + $number - 1]->getLine(), $this->filename);
112
- }
113
-
114
- return $this->tokens[$this->current + $number];
115
- }
116
-
117
- /**
118
- * Tests the current token
119
- *
120
- * @return bool
121
- */
122
- public function test($primary, $secondary = null)
123
- {
124
- return $this->tokens[$this->current]->test($primary, $secondary);
125
- }
126
-
127
- /**
128
- * Checks if end of stream was reached
129
- *
130
- * @return bool
131
- */
132
- public function isEOF()
133
- {
134
- return $this->tokens[$this->current]->getType() === Twig_Token::EOF_TYPE;
135
- }
136
-
137
- /**
138
- * Gets the current token
139
- *
140
- * @return Twig_Token
141
- */
142
- public function getCurrent()
143
- {
144
- return $this->tokens[$this->current];
145
- }
146
-
147
- /**
148
- * Gets the filename associated with this stream
149
- *
150
- * @return string
151
- */
152
- public function getFilename()
153
- {
154
- return $this->filename;
155
- }
156
- }
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2009 Fabien Potencier
7
+ * (c) 2009 Armin Ronacher
8
+ *
9
+ * For the full copyright and license information, please view the LICENSE
10
+ * file that was distributed with this source code.
11
+ */
12
+
13
+ /**
14
+ * Represents a token stream.
15
+ *
16
+ * @author Fabien Potencier <fabien@symfony.com>
17
+ */
18
+ class Twig_TokenStream
19
+ {
20
+ protected $tokens;
21
+ protected $current;
22
+ protected $filename;
23
+
24
+ /**
25
+ * Constructor.
26
+ *
27
+ * @param array $tokens An array of tokens
28
+ * @param string $filename The name of the filename which tokens are associated with
29
+ */
30
+ public function __construct(array $tokens, $filename = null)
31
+ {
32
+ $this->tokens = $tokens;
33
+ $this->current = 0;
34
+ $this->filename = $filename;
35
+ }
36
+
37
+ /**
38
+ * Returns a string representation of the token stream.
39
+ *
40
+ * @return string
41
+ */
42
+ public function __toString()
43
+ {
44
+ return implode("\n", $this->tokens);
45
+ }
46
+
47
+ public function injectTokens(array $tokens)
48
+ {
49
+ $this->tokens = array_merge(array_slice($this->tokens, 0, $this->current), $tokens, array_slice($this->tokens, $this->current));
50
+ }
51
+
52
+ /**
53
+ * Sets the pointer to the next token and returns the old one.
54
+ *
55
+ * @return Twig_Token
56
+ */
57
+ public function next()
58
+ {
59
+ if (!isset($this->tokens[++$this->current])) {
60
+ throw new Twig_Error_Syntax('Unexpected end of template', $this->tokens[$this->current - 1]->getLine(), $this->filename);
61
+ }
62
+
63
+ return $this->tokens[$this->current - 1];
64
+ }
65
+
66
+ /**
67
+ * Tests a token, sets the pointer to the next one and returns it or throws a syntax error.
68
+ *
69
+ * @return Twig_Token|null The next token if the condition is true, null otherwise
70
+ */
71
+ public function nextIf($primary, $secondary = null)
72
+ {
73
+ if ($this->tokens[$this->current]->test($primary, $secondary)) {
74
+ return $this->next();
75
+ }
76
+ }
77
+
78
+ /**
79
+ * Tests a token and returns it or throws a syntax error.
80
+ *
81
+ * @return Twig_Token
82
+ */
83
+ public function expect($type, $value = null, $message = null)
84
+ {
85
+ $token = $this->tokens[$this->current];
86
+ if (!$token->test($type, $value)) {
87
+ $line = $token->getLine();
88
+ throw new Twig_Error_Syntax(sprintf('%sUnexpected token "%s" of value "%s" ("%s" expected%s)',
89
+ $message ? $message.'. ' : '',
90
+ Twig_Token::typeToEnglish($token->getType()), $token->getValue(),
91
+ Twig_Token::typeToEnglish($type), $value ? sprintf(' with value "%s"', $value) : ''),
92
+ $line,
93
+ $this->filename
94
+ );
95
+ }
96
+ $this->next();
97
+
98
+ return $token;
99
+ }
100
+
101
+ /**
102
+ * Looks at the next token.
103
+ *
104
+ * @param int $number
105
+ *
106
+ * @return Twig_Token
107
+ */
108
+ public function look($number = 1)
109
+ {
110
+ if (!isset($this->tokens[$this->current + $number])) {
111
+ throw new Twig_Error_Syntax('Unexpected end of template', $this->tokens[$this->current + $number - 1]->getLine(), $this->filename);
112
+ }
113
+
114
+ return $this->tokens[$this->current + $number];
115
+ }
116
+
117
+ /**
118
+ * Tests the current token
119
+ *
120
+ * @return bool
121
+ */
122
+ public function test($primary, $secondary = null)
123
+ {
124
+ return $this->tokens[$this->current]->test($primary, $secondary);
125
+ }
126
+
127
+ /**
128
+ * Checks if end of stream was reached
129
+ *
130
+ * @return bool
131
+ */
132
+ public function isEOF()
133
+ {
134
+ return $this->tokens[$this->current]->getType() === Twig_Token::EOF_TYPE;
135
+ }
136
+
137
+ /**
138
+ * Gets the current token
139
+ *
140
+ * @return Twig_Token
141
+ */
142
+ public function getCurrent()
143
+ {
144
+ return $this->tokens[$this->current];
145
+ }
146
+
147
+ /**
148
+ * Gets the filename associated with this stream
149
+ *
150
+ * @return string
151
+ */
152
+ public function getFilename()
153
+ {
154
+ return $this->filename;
155
+ }
156
+ }
classes/baseObject.php CHANGED
@@ -1,22 +1,22 @@
1
- <?php
2
- abstract class baseObjectCfs {
3
- protected $_internalErrors = array();
4
- protected $_haveErrors = false;
5
- public function pushError($error, $key = '') {
6
- if(is_array($error)) {
7
- $this->_internalErrors = array_merge ($this->_internalErrors, $error);
8
- } elseif(empty($key)) {
9
- $this->_internalErrors[] = $error;
10
- } else {
11
- $this->_internalErrors[ $key ] = $error;
12
- }
13
- $this->_haveErrors = true;
14
- }
15
- public function getErrors() {
16
- return $this->_internalErrors;
17
- }
18
- public function haveErrors() {
19
- return $this->_haveErrors;
20
- }
21
- }
22
-
1
+ <?php
2
+ abstract class baseObjectCfs {
3
+ protected $_internalErrors = array();
4
+ protected $_haveErrors = false;
5
+ public function pushError($error, $key = '') {
6
+ if(is_array($error)) {
7
+ $this->_internalErrors = array_merge ($this->_internalErrors, $error);
8
+ } elseif(empty($key)) {
9
+ $this->_internalErrors[] = $error;
10
+ } else {
11
+ $this->_internalErrors[ $key ] = $error;
12
+ }
13
+ $this->_haveErrors = true;
14
+ }
15
+ public function getErrors() {
16
+ return $this->_internalErrors;
17
+ }
18
+ public function haveErrors() {
19
+ return $this->_haveErrors;
20
+ }
21
+ }
22
+
classes/controller.php CHANGED
@@ -1,234 +1,232 @@
1
- <?php
2
- abstract class controllerCfs {
3
- protected $_models = array();
4
- protected $_views = array();
5
- protected $_task = '';
6
- protected $_defaultView = '';
7
- protected $_code = '';
8
- public function __construct($code) {
9
- $this->setCode($code);
10
- $this->_defaultView = $this->getCode();
11
- }
12
- public function init() {
13
- /*load model and other preload data goes here*/
14
- }
15
- protected function _onBeforeInit() {
16
-
17
- }
18
- protected function _onAfterInit() {
19
-
20
- }
21
- public function setCode($code) {
22
- $this->_code = $code;
23
- }
24
- public function getCode() {
25
- return $this->_code;
26
- }
27
- public function exec($task = '') {
28
- if(method_exists($this, $task)) {
29
- $this->_task = $task; //For multicontrollers module version - who know, maybe that's will be?))
30
- return $this->$task();
31
- }
32
- return null;
33
- }
34
- public function getView($name = '') {
35
- if(empty($name)) $name = $this->getCode();
36
- if(!isset($this->_views[$name])) {
37
- $this->_views[$name] = $this->_createView($name);
38
- }
39
- return $this->_views[$name];
40
- }
41
- public function getModel($name = '') {
42
- if(!$name)
43
- $name = $this->_code;
44
- if(!isset($this->_models[$name])) {
45
- $this->_models[$name] = $this->_createModel($name);
46
- }
47
- return $this->_models[$name];
48
- }
49
- protected function _createModel($name = '') {
50
- if(empty($name)) $name = $this->getCode();
51
- $parentModule = frameCfs::_()->getModule( $this->getCode() );
52
- $className = '';
53
- if(importCfs($parentModule->getModDir(). 'models'. DS. $name. '.php')) {
54
- $className = toeGetClassNameCfs($name. 'Model');
55
- }
56
-
57
- if($className) {
58
- $model = new $className();
59
- $model->setCode( $this->getCode() );
60
- return $model;
61
- }
62
- return NULL;
63
- }
64
- protected function _createView($name = '') {
65
- if(empty($name)) $name = $this->getCode();
66
- $parentModule = frameCfs::_()->getModule( $this->getCode() );
67
- $className = '';
68
-
69
- if(importCfs($parentModule->getModDir(). 'views'. DS. $name. '.php')) {
70
- $className = toeGetClassNameCfs($name. 'View');
71
- }
72
-
73
- if($className) {
74
- $view = new $className();
75
- $view->setCode( $this->getCode() );
76
- return $view;
77
- }
78
- return NULL;
79
- }
80
- public function display($viewName = '') {
81
- $view = NULL;
82
- if(($view = $this->getView($viewName)) === NULL) {
83
- $view = $this->getView(); //Get default view
84
- }
85
- if($view) {
86
- $view->display();
87
- }
88
- }
89
- public function __call($name, $arguments) {
90
- $model = $this->getModel();
91
- if(method_exists($model, $name))
92
- return $model->$name($arguments[0]);
93
- else
94
- return false;
95
- }
96
- /**
97
- * Retrive permissions for controller methods if exist.
98
- * If need - should be redefined in each controller where it required.
99
- * @return array with permissions
100
- * @example :
101
- return array(
102
- S_METHODS => array(
103
- 'save' => array(CFS_ADMIN),
104
- 'remove' => array(CFS_ADMIN),
105
- 'restore' => CFS_ADMIN,
106
- ),
107
- S_USERLEVELS => array(
108
- S_ADMIN => array('save', 'remove', 'restore')
109
- ),
110
- );
111
- * Can be used on of sub-array - CFS_METHODS or CFS_USERLEVELS
112
- */
113
- public function getPermissions() {
114
- return array();
115
- }
116
- /**
117
- * Methods that require nonce to be generated
118
- * If need - should be redefined in each controller where it required.
119
- * @return array
120
- */
121
- public function getNoncedMethods() {
122
- return array();
123
- }
124
- public function getModule() {
125
- return frameCfs::_()->getModule( $this->getCode() );
126
- }
127
- protected function _prepareTextLikeSearch($val) {
128
- return ''; // Should be re-defined for each type
129
- }
130
- protected function _prepareModelBeforeListSelect($model) {
131
- return $model;
132
- }
133
- /**
134
- * Common method for list table data
135
- */
136
- public function getListForTbl() {
137
- $res = new responseCfs();
138
- $res->ignoreShellData();
139
- $model = $this->getModel();
140
-
141
- $page = (int) sanitize_text_field(reqCfs::getVar('page'));
142
- $rowsLimit = (int) sanitize_text_field(reqCfs::getVar('rows'));
143
- $sortOrder = sanitize_text_field(reqCfs::getVar('sord'));
144
-
145
- // Our custom search
146
- $search = reqCfs::getVar('search');
147
- if($search && !empty($search) && is_array($search)) {
148
- foreach($search as $k => $v) {
149
- $v = trim($v);
150
- if(empty($v)) continue;
151
- if($k == 'text_like') {
152
- $k = sanitize_text_field($k);
153
- $v = sanitize_text_field($v);
154
- $v = $this->_prepareTextLikeSearch( $v );
155
- if(!empty($v)) {
156
- $model->addWhere(array('additionalCondition' => $v));
157
- }
158
- } else {
159
- $k = sanitize_text_field($k);
160
- $v = sanitize_text_field($v);
161
- $model->addWhere(array($k => $v));
162
- }
163
- }
164
- }
165
- // jqGrid search
166
- $isSearch = reqCfs::getVar('_search');
167
- if($isSearch) {
168
- $searchField = sanitize_text_field(trim(reqCfs::getVar('searchField')));
169
- $searchString = sanitize_text_field(trim(reqCfs::getVar('searchString')));
170
- if(!empty($searchField) && !empty($searchString)) {
171
- // For some cases - we will need to modify search keys and/or values before put it to the model
172
- $model->addWhere(array(
173
- $this->_prepareSearchField($searchField) => $this->_prepareSearchString($searchString)
174
- ));
175
- }
176
- }
177
- $model = $this->_prepareModelBeforeListSelect($model);
178
- // Get total pages count for current request
179
- $totalCount = $model->getCount(array('clear' => array('selectFields')));
180
- $totalPages = 0;
181
- if($totalCount > 0) {
182
- $totalPages = ceil($totalCount / $rowsLimit);
183
- }
184
- if($page > $totalPages) {
185
- $page = $totalPages;
186
- }
187
- // Calc limits - to get data only for current set
188
- $limitStart = $rowsLimit * $page - $rowsLimit; // do not put $limit*($page - 1)
189
- if($limitStart < 0)
190
- $limitStart = 0;
191
-
192
- $data = $model
193
- ->setLimit($limitStart. ', '. $rowsLimit)
194
- ->setSortOrder( $sortOrder )
195
- ->setSimpleGetFields()
196
- ->getFromTbl();
197
-
198
- $data = $this->_prepareListForTbl( $data );
199
- $res->addData('page', $page);
200
- $res->addData('total', $totalPages);
201
- $res->addData('rows', $data);
202
- $res->addData('records', $model->getLastGetCount());
203
- $res = dispatcherCfs::applyFilters($this->getCode(). '_getListForTblResults', $res);
204
- $res->ajaxExec();
205
- }
206
- public function removeGroup() {
207
- $res = new responseCfs();
208
- if($this->getModel()->removeGroup(reqCfs::getVar('listIds', 'post'))) {
209
- $res->addMessage(__('Done', CFS_LANG_CODE));
210
- } else
211
- $res->pushError($this->getModel()->getErrors());
212
- $res->ajaxExec();
213
- }
214
- public function clear() {
215
- $res = new responseCfs();
216
- if($this->getModel()->clear()) {
217
- $res->addMessage(__('Done', CFS_LANG_CODE));
218
- } else
219
- $res->pushError($this->getModel()->getErrors());
220
- $res->ajaxExec();
221
- }
222
- protected function _prepareListForTbl($data) {
223
- return $data;
224
- }
225
- protected function _prepareSearchField($searchField) {
226
- return $searchField;
227
- }
228
- protected function _prepareSearchString($searchString) {
229
- return $searchString;
230
- }
231
- protected function _prepareSortOrder($sortOrder) {
232
- return $sortOrder;
233
- }
234
- }
1
+ <?php
2
+ abstract class controllerCfs {
3
+ protected $_models = array();
4
+ protected $_views = array();
5
+ protected $_task = '';
6
+ protected $_defaultView = '';
7
+ protected $_code = '';
8
+ public function __construct($code) {
9
+ $this->setCode($code);
10
+ $this->_defaultView = $this->getCode();
11
+ }
12
+ public function init() {
13
+ /*load model and other preload data goes here*/
14
+ }
15
+ protected function _onBeforeInit() {
16
+
17
+ }
18
+ protected function _onAfterInit() {
19
+
20
+ }
21
+ public function setCode($code) {
22
+ $this->_code = $code;
23
+ }
24
+ public function getCode() {
25
+ return $this->_code;
26
+ }
27
+ public function exec($task = '') {
28
+ if(method_exists($this, $task)) {
29
+ $this->_task = $task; //For multicontrollers module version - who know, maybe that's will be?))
30
+ return $this->$task();
31
+ }
32
+ return null;
33
+ }
34
+ public function getView($name = '') {
35
+ if(empty($name)) $name = $this->getCode();
36
+ if(!isset($this->_views[$name])) {
37
+ $this->_views[$name] = $this->_createView($name);
38
+ }
39
+ return $this->_views[$name];
40
+ }
41
+ public function getModel($name = '') {
42
+ if(!$name)
43
+ $name = $this->_code;
44
+ if(!isset($this->_models[$name])) {
45
+ $this->_models[$name] = $this->_createModel($name);
46
+ }
47
+ return $this->_models[$name];
48
+ }
49
+ protected function _createModel($name = '') {
50
+ if(empty($name)) $name = $this->getCode();
51
+ $parentModule = frameCfs::_()->getModule( $this->getCode() );
52
+ $className = '';
53
+ if(importCfs($parentModule->getModDir(). 'models'. DS. $name. '.php')) {
54
+ $className = toeGetClassNameCfs($name. 'Model');
55
+ }
56
+
57
+ if($className) {
58
+ $model = new $className();
59
+ $model->setCode( $this->getCode() );
60
+ return $model;
61
+ }
62
+ return NULL;
63
+ }
64
+ protected function _createView($name = '') {
65
+ if(empty($name)) $name = $this->getCode();
66
+ $parentModule = frameCfs::_()->getModule( $this->getCode() );
67
+ $className = '';
68
+
69
+ if(importCfs($parentModule->getModDir(). 'views'. DS. $name. '.php')) {
70
+ $className = toeGetClassNameCfs($name. 'View');
71
+ }
72
+
73
+ if($className) {
74
+ $view = new $className();
75
+ $view->setCode( $this->getCode() );
76
+ return $view;
77
+ }
78
+ return NULL;
79
+ }
80
+ public function display($viewName = '') {
81
+ $view = NULL;
82
+ if(($view = $this->getView($viewName)) === NULL) {
83
+ $view = $this->getView(); //Get default view
84
+ }
85
+ if($view) {
86
+ $view->display();
87
+ }
88
+ }
89
+ public function __call($name, $arguments) {
90
+ $model = $this->getModel();
91
+ if(method_exists($model, $name))
92
+ return $model->$name($arguments[0]);
93
+ else
94
+ return false;
95
+ }
96
+ /**
97
+ * Retrive permissions for controller methods if exist.
98
+ * If need - should be redefined in each controller where it required.
99
+ * @return array with permissions
100
+ * @example :
101
+ return array(
102
+ S_METHODS => array(
103
+ 'save' => array(CFS_ADMIN),
104
+ 'remove' => array(CFS_ADMIN),
105
+ 'restore' => CFS_ADMIN,
106
+ ),
107
+ S_USERLEVELS => array(
108
+ S_ADMIN => array('save', 'remove', 'restore')
109
+ ),
110
+ );
111
+ * Can be used on of sub-array - CFS_METHODS or CFS_USERLEVELS
112
+ */
113
+ public function getPermissions() {
114
+ return array();
115
+ }
116
+ /**
117
+ * Methods that require nonce to be generated
118
+ * If need - should be redefined in each controller where it required.
119
+ * @return array
120
+ */
121
+ public function getNoncedMethods() {
122
+ return array();
123
+ }
124
+ public function getModule() {
125
+ return frameCfs::_()->getModule( $this->getCode() );
126
+ }
127
+ // protected function _prepareTextLikeSearch($val) {
128
+ // return ''; // Should be re-defined for each type
129
+ // }
130
+ // protected function _prepareModelBeforeListSelect($model) {
131
+ // return $model;
132
+ // }
133
+ /**
134
+ * Common method for list table data
135
+ */
136
+ //public function getListForTbl() {
137
+ // $res = new responseCfs();
138
+ // $res->ignoreShellData();
139
+ // $model = $this->getModel();
140
+ //
141
+ // $page = (int) sanitize_text_field(reqCfs::getVar('page'));
142
+ // $rowsLimit = (int) sanitize_text_field(reqCfs::getVar('rows'));
143
+ //
144
+ // // Our custom search
145
+ // $search = reqCfs::getVar('search');
146
+ // if($search && !empty($search) && is_array($search)) {
147
+ // foreach($search as $k => $v) {
148
+ // $v = trim($v);
149
+ // if(empty($v)) continue;
150
+ // if($k == 'text_like') {
151
+ // $k = sanitize_text_field($k);
152
+ // $v = sanitize_text_field($v);
153
+ // $v = $this->_prepareTextLikeSearch( $v );
154
+ // if(!empty($v)) {
155
+ // $model->addWhere(array('additionalCondition' => $v));
156
+ // }
157
+ // } else {
158
+ // $k = sanitize_text_field($k);
159
+ // $v = sanitize_text_field($v);
160
+ // $model->addWhere(array($k => $v));
161
+ // }
162
+ // }
163
+ // }
164
+ // // jqGrid search
165
+ // $isSearch = reqCfs::getVar('_search');
166
+ // if($isSearch) {
167
+ // $searchField = sanitize_text_field(trim(reqCfs::getVar('searchField')));
168
+ // $searchString = sanitize_text_field(trim(reqCfs::getVar('searchString')));
169
+ // if(!empty($searchField) && !empty($searchString)) {
170
+ // // For some cases - we will need to modify search keys and/or values before put it to the model
171
+ // $model->addWhere(array(
172
+ // $this->_prepareSearchField($searchField) => $this->_prepareSearchString($searchString)
173
+ // ));
174
+ // }
175
+ // }
176
+ // $model = $this->_prepareModelBeforeListSelect($model);
177
+ // // Get total pages count for current request
178
+ // $totalCount = $model->getCount(array('clear' => array('selectFields')));
179
+ // $totalPages = 0;
180
+ // if($totalCount > 0) {
181
+ // $totalPages = ceil($totalCount / $rowsLimit);
182
+ // }
183
+ // if($page > $totalPages) {
184
+ // $page = $totalPages;
185
+ // }
186
+ // // Calc limits - to get data only for current set
187
+ // $limitStart = $rowsLimit * $page - $rowsLimit; // do not put $limit*($page - 1)
188
+ // if($limitStart < 0)
189
+ // $limitStart = 0;
190
+ //
191
+ // $data = $model
192
+ // ->setLimit($limitStart. ', '. $rowsLimit)
193
+ // ->setSimpleGetFields()
194
+ // ->getFromTbl();
195
+ //
196
+ // $data = $this->_prepareListForTbl( $data );
197
+ // $res->addData('page', $page);
198
+ // $res->addData('total', $totalPages);
199
+ // $res->addData('rows', $data);
200
+ // $res->addData('records', $model->getLastGetCount());
201
+ // $res = dispatcherCfs::applyFilters($this->getCode(). '_getListForTblResults', $res);
202
+ // $res->ajaxExec();
203
+ //}
204
+ public function removeGroup() {
205
+ $res = new responseCfs();
206
+ if($this->getModel()->removeGroup(reqCfs::getVar('listIds', 'post'))) {
207
+ $res->addMessage(__('Done', CFS_LANG_CODE));
208
+ } else
209
+ $res->pushError($this->getModel()->getErrors());
210
+ $res->ajaxExec();
211
+ }
212
+ public function clear() {
213
+ $res = new responseCfs();
214
+ if($this->getModel()->clear()) {
215
+ $res->addMessage(__('Done', CFS_LANG_CODE));
216
+ } else
217
+ $res->pushError($this->getModel()->getErrors());
218
+ $res->ajaxExec();
219
+ }
220
+ protected function _prepareListForTbl($data) {
221
+ return $data;
222
+ }
223
+ protected function _prepareSearchField($searchField) {
224
+ return $searchField;
225
+ }
226
+ protected function _prepareSearchString($searchString) {
227
+ return $searchString;
228
+ }
229
+ // protected function _prepareSortOrder($sortOrder) {
230
+ // return $sortOrder;
231
+ // }
232
+ }
 
 
classes/csvgenerator.php CHANGED
@@ -1,38 +1,38 @@
1
- <?php
2
- class csvgeneratorCfs {
3
- protected $_filename = '';
4
- protected $_delimiter = ';';
5
- protected $_enclosure = "\n";
6
- protected $_data = array();
7
- protected $_escape = '\\';
8
- public function __construct($filename) {
9
- $this->_filename = $filename;
10
- }
11
- public function addCell($x, $y, $value) {
12
- $this->_data[ $x ][ $y ] = '"'. $value. '"'; //If will not do "" then wymbol for example , will broke file
13
- }
14
- public function generate() {
15
- $strData = '';
16
- if(!empty($this->_data)) {
17
- $rows = array();
18
- foreach($this->_data as $cells) {
19
- $rows[] = implode($this->_delimiter, $cells);
20
- }
21
- $strData = implode($this->_enclosure, $rows);
22
- }
23
- filegeneratorCfs::_($this->_filename, $strData, 'csv')->generate();
24
- }
25
- public function getDelimiter() {
26
- return $this->_delimiter;
27
- }
28
- public function getEnclosure() {
29
- return $this->_enclosure;
30
- }
31
- public function getEscape() {
32
- return $this->_escape;
33
- }
34
- public function setDelimiter( $delimiter ) {
35
- $this->_delimiter = $delimiter;
36
- }
37
- }
38
-
1
+ <?php
2
+ class csvgeneratorCfs {
3
+ protected $_filename = '';
4
+ protected $_delimiter = ';';
5
+ protected $_enclosure = "\n";
6
+ protected $_data = array();
7
+ protected $_escape = '\\';
8
+ public function __construct($filename) {
9
+ $this->_filename = $filename;
10
+ }
11
+ public function addCell($x, $y, $value) {
12
+ $this->_data[ $x ][ $y ] = '"'. $value. '"'; //If will not do "" then wymbol for example , will broke file
13
+ }
14
+ public function generate() {
15
+ $strData = '';
16
+ if(!empty($this->_data)) {
17
+ $rows = array();
18
+ foreach($this->_data as $cells) {
19
+ $rows[] = implode($this->_delimiter, $cells);
20
+ }
21
+ $strData = implode($this->_enclosure, $rows);
22
+ }
23
+ filegeneratorCfs::_($this->_filename, $strData, 'csv')->generate();
24
+ }
25
+ public function getDelimiter() {
26
+ return $this->_delimiter;
27
+ }
28
+ public function getEnclosure() {
29
+ return $this->_enclosure;
30
+ }
31
+ public function getEscape() {
32
+ return $this->_escape;
33
+ }
34
+ public function setDelimiter( $delimiter ) {
35
+ $this->_delimiter = $delimiter;
36
+ }
37
+ }
38
+
classes/date.php CHANGED
@@ -1,9 +1,9 @@
1
- <?php
2
- class dateCfs {
3
- static public function _($time = NULL) {
4
- if(is_null($time)) {
5
- $time = time();
6
- }
7
- return date(CFS_DATE_FORMAT_HIS, $time);
8
- }
9
  }
1
+ <?php
2
+ class dateCfs {
3
+ static public function _($time = NULL) {
4
+ if(is_null($time)) {
5
+ $time = time();
6
+ }
7
+ return date(CFS_DATE_FORMAT_HIS, $time);
8
+ }
9
  }
classes/db.php CHANGED
@@ -1,141 +1,154 @@
1
- <?php
2
- /**
3
- * Shell - class to work with $wpdb global object
4
- */
5
- class dbCfs {
6
- /**
7
- * Execute query and return results
8
- * @param string $query query to be executed
9
- * @param string $get what must be returned - one value (one), one row (row), one col (col) or all results (all - by default)
10
- * @param const $outputType type of returned data
11
- * @return mixed data from DB
12
- */
13
- static public $query = '';
14
- static public function get($query, $get = 'all', $outputType = ARRAY_A) {
15
- global $wpdb;
16
- $get = strtolower($get);
17
- $res = NULL;
18
- $query = self::prepareQuery($query);
19
- self::$query = $query;
20
- switch($get) {
21
- case 'one':
22
- $res = $wpdb->get_var($query);
23
- break;
24
- case 'row':
25
- $res = $wpdb->get_row($query, $outputType);
26
- break;
27
- case 'col':
28
- $res = $wpdb->get_col($query);
29
- break;
30
- case 'all':
31
- default:
32
- $res = $wpdb->get_results($query, $outputType);
33
- break;
34
- }
35
- return $res;
36
- }
37
- /**
38
- * Execute one query
39
- * @return query results
40
- */
41
- static public function query($query) {
42
- global $wpdb;
43
- return ($wpdb->query( self::prepareQuery($query) ) === false ? false : true);
44
- }
45
- /**
46
- * Get last insert ID
47
- * @return int last ID
48
- */
49
- static public function insertID() {
50
- global $wpdb;
51
- return $wpdb->insert_id;
52
- }
53
- /**
54
- * Get number of rows returned by last query
55
- * @return int number of rows
56
- */
57
- static public function numRows() {
58
- global $wpdb;
59
- return $wpdb->num_rows;
60
- }
61
- /**
62
- * Replace prefixes in custom query. Suported next prefixes:
63
- * #__ Worcfsess prefix
64
- * ^__ Store plugin tables prefix (@see CFS_DB_PREF if config.php)
65
- * @__ Compared of WP table prefix + Store plugin prefix (@example wp_s_)
66
- * @param string $query query to be executed
67
- */
68
- static public function prepareQuery($query) {
69
- global $wpdb;
70
- return str_replace(
71
- array('#__', '^__', '@__'),
72
- array($wpdb->prefix, CFS_DB_PREF, $wpdb->prefix. CFS_DB_PREF),
73
- $query);
74
- }
75
- static public function getError() {
76
- global $wpdb;
77
- return $wpdb->last_error;
78
- }
79
- static public function lastID() {
80
- global $wpdb;
81
- return $wpdb->insert_id;
82
- }
83
- static public function timeToDate($timestamp = 0) {
84
- if($timestamp) {
85
- if(!is_numeric($timestamp))
86
- $timestamp = dateToTimestampCfs($timestamp);
87
- return date('Y-m-d', $timestamp);
88
- } else {
89
- return date('Y-m-d');
90
- }
91
- }
92
- static public function dateToTime($date) {
93
- if(empty($date)) return '';
94
- if(strpos($date, CFS_DATE_DL)) return dateToTimestampCfs($date);
95
- $arr = explode('-', $date);
96
- return dateToTimestampCfs($arr[2]. CFS_DATE_DL. $arr[1]. CFS_DATE_DL. $arr[0]);
97
- }
98
- static public function exist($table, $column = '', $value = '') {
99
- if(empty($column) && empty($value)) { //Check if table exist
100
- $res = self::get('SHOW TABLES LIKE "'. $table. '"', 'one');
101
- } elseif(empty($value)) { //Check if column exist
102
- $res = self::get('SHOW COLUMNS FROM '. $table. ' LIKE "'. $column. '"', 'one');
103
- } else { //Check if value in column table exist
104
- $res = self::get('SELECT COUNT(*) AS total FROM '. $table. ' WHERE '. $column. ' = "'. $value. '"', 'one');
105
- }
106
- return !empty($res);
107
- }
108
- static public function prepareHtml($d) {
109
- if(is_array($d)) {
110
- foreach($d as $i => $el) {
111
- $d[ $i ] = self::prepareHtml( $el );
112
- }
113
- } else {
114
- $d = esc_html($d);
115
- }
116
- return $d;
117
- }
118
- static public function prepareHtmlIn($d) {
119
- if(is_array($d)) {
120
- foreach($d as $i => $el) {
121
- $d[ $i ] = self::prepareHtml( $el );
122
- }
123
- } else {
124
- $d = wp_filter_nohtml_kses($d);
125
- }
126
- return $d;
127
- }
128
- static public function escape($data) {
129
- global $wpdb;
130
- return $wpdb->_escape($data);
131
- }
132
- static public function getAutoIncrement($table) {
133
- return (int) self::get('SELECT AUTO_INCREMENT
134
- FROM information_schema.tables
135
- WHERE table_name = "'. $table. '"
136
- AND table_schema = DATABASE( );', 'one');
137
- }
138
- static public function setAutoIncrement($table, $autoIncrement) {
139
- return self::query("ALTER TABLE `". $table. "` AUTO_INCREMENT = ". $autoIncrement. ";");
140
- }
141
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Shell - class to work with $wpdb global object
4
+ */
5
+ class dbCfs {
6
+ /**
7
+ * Execute query and return results
8
+ * @param string $query query to be executed
9
+ * @param string $get what must be returned - one value (one), one row (row), one col (col) or all results (all - by default)
10
+ * @param const $outputType type of returned data
11
+ * @return mixed data from DB
12
+ */
13
+ static public $query = '';
14
+ static public function get($query, $get = 'all', $outputType = ARRAY_A) {
15
+ return false;
16
+ //global $wpdb;
17
+ // $get = strtolower($get);
18
+ // $res = NULL;
19
+ // $query = self::prepareQuery($query);
20
+ //error_log('QUERY: '. $query);
21
+ }
22
+ /**
23
+ * Execute one query
24
+ * @return query results
25
+ */
26
+ static public function query($query) {
27
+ return false;
28
+ }
29
+ /**
30
+ * Get last insert ID
31
+ * @return int last ID
32
+ */
33
+ static public function insertID() {
34
+ global $wpdb;
35
+ return $wpdb->insert_id;
36
+ }
37
+ /**
38
+ * Get number of rows returned by last query
39
+ * @return int number of rows
40
+ */
41
+ static public function numRows() {
42
+ global $wpdb;
43
+ return $wpdb->num_rows;
44
+ }
45
+ /**
46
+ * Replace prefixes in custom query. Suported next prefixes:
47
+ * #__ Worcfsess prefix
48
+ * ^__ Store plugin tables prefix (@see CFS_DB_PREF if config.php)
49
+ * @__ Compared of WP table prefix + Store plugin prefix (@example wp_s_)
50
+ * @param string $query query to be executed
51
+ */
52
+ static public function prepareQuery($query) {
53
+ global $wpdb;
54
+ return str_replace(
55
+ array('#__', '^__', '@__'),
56
+ array($wpdb->prefix, CFS_DB_PREF, $wpdb->prefix. CFS_DB_PREF),
57
+ $query);
58
+ }
59
+ static public function getError() {
60
+ global $wpdb;
61
+ return $wpdb->last_error;
62
+ }
63
+ static public function lastID() {
64
+ global $wpdb;
65
+ return $wpdb->insert_id;
66
+ }
67
+ static public function timeToDate($timestamp = 0) {
68
+ if($timestamp) {
69
+ if(!is_numeric($timestamp))
70
+ $timestamp = dateToTimestampCfs($timestamp);
71
+ return date('Y-m-d', $timestamp);
72
+ } else {
73
+ return date('Y-m-d');
74
+ }
75
+ }
76
+ static public function dateToTime($date) {
77
+ if(empty($date)) return '';
78
+ if(strpos($date, CFS_DATE_DL)) return dateToTimestampCfs($date);
79
+ $arr = explode('-', $date);
80
+ return dateToTimestampCfs($arr[2]. CFS_DATE_DL. $arr[1]. CFS_DATE_DL. $arr[0]);
81
+ }
82
+ static public function exist($table) {
83
+ global $wpdb;
84
+ switch ($table) {
85
+ case 'cfs_contacts':
86
+ $res = $wpdb->get_var("SHOW TABLES LIKE '{$wpdb->prefix}cfs_contacts'");
87
+ break;
88
+ case 'cfs_countries':
89
+ $res = $wpdb->get_var("SHOW TABLES LIKE '{$wpdb->prefix}cfs_countries'");
90
+ break;
91
+ case 'cfs_files':
92
+ $res = $wpdb->get_var("SHOW TABLES LIKE '{$wpdb->prefix}cfs_files'");
93
+ break;
94
+ case 'cfs_forms':
95
+ $res = $wpdb->get_var("SHOW TABLES LIKE '{$wpdb->prefix}cfs_forms'");
96
+ break;
97
+ case 'cfs_forms_rating':
98
+ $res = $wpdb->get_var("SHOW TABLES LIKE '{$wpdb->prefix}cfs_forms_rating'");
99
+ break;
100
+ case 'cfs_membership_presets':
101
+ $res = $wpdb->get_var("SHOW TABLES LIKE '{$wpdb->prefix}cfs_membership_presets'");
102
+ break;
103
+ case 'cfs_modules':
104
+ $res = $wpdb->get_var("SHOW TABLES LIKE '{$wpdb->prefix}cfs_modules'");
105
+ break;
106
+ case 'cfs_statistics':
107
+ $res = $wpdb->get_var("SHOW TABLES LIKE '{$wpdb->prefix}cfs_statistics'");
108
+ break;
109
+ case 'cfs_modules_type':
110
+ $res = $wpdb->get_var("SHOW TABLES LIKE '{$wpdb->prefix}cfs_modules_type'");
111
+ break;
112
+ case 'cfs_subscribers':
113
+ $res = $wpdb->get_var("SHOW TABLES LIKE '{$wpdb->prefix}cfs_subscribers'");
114
+ break;
115
+ case 'cfs_usage_stat':
116
+ $res = $wpdb->get_var("SHOW TABLES LIKE '{$wpdb->prefix}cfs_usage_stat'");
117
+ break;
118
+ }
119
+ return !empty($res);
120
+ }
121
+ static public function prepareHtml($d) {
122
+ if(is_array($d)) {
123
+ foreach($d as $i => $el) {
124
+ $d[ $i ] = self::prepareHtml( $el );
125
+ }
126
+ } else {
127
+ $d = esc_html($d);
128
+ }
129
+ return $d;
130
+ }
131
+ static public function prepareHtmlIn($d) {
132
+ if(is_array($d)) {
133
+ foreach($d as $i => $el) {
134
+ $d[ $i ] = self::prepareHtml( $el );
135
+ }
136
+ } else {
137
+ $d = wp_filter_nohtml_kses($d);
138
+ }
139
+ return $d;
140
+ }
141
+ static public function escape($data) {
142
+ global $wpdb;
143
+ return $wpdb->_escape($data);
144
+ }
145
+ static public function getAutoIncrement($table) {
146
+ return (int) self::get('SELECT AUTO_INCREMENT
147
+ FROM information_schema.tables
148
+ WHERE table_name = "'. $table. '"
149
+ AND table_schema = DATABASE( );', 'one');
150
+ }
151
+ static public function setAutoIncrement($table, $autoIncrement) {
152
+ return self::query("ALTER TABLE `". $table. "` AUTO_INCREMENT = ". $autoIncrement. ";");
153
+ }
154
+ }
classes/dispatcher.php CHANGED
@@ -1,41 +1,41 @@
1
- <?php
2
- class dispatcherCfs {
3
- static protected $_pref = 'cfs_';
4
-
5
- static public function addAction($tag, $function_to_add, $priority = 10, $accepted_args = 1) {
6
- if(strpos($tag, 'cfs_') === false)
7
- $tag = self::$_pref. $tag;
8
- return add_action( $tag, $function_to_add, $priority, $accepted_args );
9
- }
10
- static public function doAction($tag) {
11
- if(strpos($tag, 'cfs_') === false)
12
- $tag = self::$_pref. $tag;
13
- $numArgs = func_num_args();
14
- if($numArgs > 1) {
15
- $args = array( $tag );
16
- for($i = 1; $i < $numArgs; $i++) {
17
- $args[] = func_get_arg($i);
18
- }
19
- return call_user_func_array('do_action', $args);
20
- }
21
- return do_action($tag);
22
- }
23
- static public function addFilter($tag, $function_to_add, $priority = 10, $accepted_args = 1) {
24
- if(strpos($tag, 'cfs_') === false)
25
- $tag = self::$_pref. $tag;
26
- return add_filter( $tag, $function_to_add, $priority, $accepted_args );
27
- }
28
- static public function applyFilters($tag, $value) {
29
- if(strpos($tag, 'cfs_') === false)
30
- $tag = self::$_pref. $tag;
31
- if(func_num_args() > 2) {
32
- $args = array($tag);
33
- for($i = 1; $i < func_num_args(); $i++) {
34
- $args[] = func_get_arg($i);
35
- }
36
- return call_user_func_array('apply_filters', $args);
37
- } else {
38
- return apply_filters( $tag, $value );
39
- }
40
- }
41
- }
1
+ <?php
2
+ class dispatcherCfs {
3
+ static protected $_pref = 'cfs_';
4
+
5
+ static public function addAction($tag, $function_to_add, $priority = 10, $accepted_args = 1) {
6
+ if(strpos($tag, 'cfs_') === false)
7
+ $tag = self::$_pref. $tag;
8
+ return add_action( $tag, $function_to_add, $priority, $accepted_args );
9
+ }
10
+ static public function doAction($tag) {
11
+ if(strpos($tag, 'cfs_') === false)
12
+ $tag = self::$_pref. $tag;
13
+ $numArgs = func_num_args();
14
+ if($numArgs > 1) {
15
+ $args = array( $tag );
16
+ for($i = 1; $i < $numArgs; $i++) {
17
+ $args[] = func_get_arg($i);
18
+ }
19
+ return call_user_func_array('do_action', $args);
20
+ }
21
+ return do_action($tag);
22
+ }
23
+ static public function addFilter($tag, $function_to_add, $priority = 10, $accepted_args = 1) {
24
+ if(strpos($tag, 'cfs_') === false)
25
+ $tag = self::$_pref. $tag;
26
+ return add_filter( $tag, $function_to_add, $priority, $accepted_args );
27
+ }
28
+ static public function applyFilters($tag, $value) {
29
+ if(strpos($tag, 'cfs_') === false)
30
+ $tag = self::$_pref. $tag;
31
+ if(func_num_args() > 2) {
32
+ $args = array($tag);
33
+ for($i = 1; $i < func_num_args(); $i++) {
34
+ $args[] = func_get_arg($i);
35
+ }
36
+ return call_user_func_array('apply_filters', $args);
37
+ } else {
38
+ return apply_filters( $tag, $value );
39
+ }
40
+ }
41
+ }
classes/errors.php CHANGED
@@ -1,93 +1,93 @@
1
- <?php
2
- class errorsCfs {
3
- const FATAL = 'fatal';
4
- const MOD_INSTALL = 'mod_install';
5
- static private $errors = array();
6
- static private $haveErrors = false;
7
-
8
- static public $current = array();
9
- static public $displayed = false;
10
-
11
- static public function push($error, $type = 'common') {
12
- if(!isset(self::$errors[$type]))
13
- self::$errors[$type] = array();
14
- if(is_array($error))
15
- self::$errors[$type] = array_merge(self::$errors[$type], $error);
16
- else
17
- self::$errors[$type][] = $error;
18
- self::$haveErrors = true;
19
-
20
- if($type == 'session')
21
- self::setSession(self::$errors[$type]);
22
- }
23
- static public function setSession($error) {
24
- $sesErrors = self::getSession();
25
- if(empty($sesErrors))
26
- $sesErrors = array();
27
- if(is_array($error))
28
- $sesErrors = array_merge($sesErrors, $error);
29
- else
30
- $sesErrors[] = $error;
31
- reqCfs::setVar('sesErrors', $sesErrors, 'session');
32
- }
33
- static public function init() {
34
- $cfsErrors = reqCfs::getVar('cfsErrors');
35
- if(!empty($cfsErrors)) {
36
- if(!is_array($cfsErrors)) {
37
- $cfsErrors = array( $cfsErrors );
38
- }
39
- $cfsErrors = array_map('htmlspecialchars', array_map('stripslashes', array_map('trim', $cfsErrors)));
40
- if(!empty($cfsErrors)) {
41
- self::$current = $cfsErrors;
42
- if(is_admin()) {
43
- add_action('admin_notices', array('errorsCfs', 'showAdminErrors'));
44
- } else {
45
- add_filter('the_content', array('errorsCfs', 'appendErrorsContent'), 99999);
46
- }
47
- }
48
- }
49
- }
50
- static public function showAdminErrors() {
51
- if(self::$current) {
52
- $html = '';
53
- foreach(self::$current as $error) {
54
- $html .= '<div class="error"><p><strong style="font-size: 15px;">'. $error. '</strong></p></div>';
55
- }
56
- echo $html;
57
- }
58
- }
59
- static public function appendErrorsContent($content) {
60
- if(!self::$displayed && !empty(self::$current)) {
61
- $content = '<div class="toeErrorMsg">'. implode('<br />', self::$current). '</div>'. $content;
62
- self::$displayed = true;
63
- }
64
- return $content;
65
- }
66
- static public function getSession() {
67
- return reqCfs::getVar('sesErrors', 'session');
68
- }
69
- static public function clearSession() {
70
- reqCfs::clearVar('sesErrors', 'session');
71
- }
72
- static public function get($type = '') {
73
- $res = array();
74
- if(!empty(self::$errors)) {
75
- if(empty($type)) {
76
- foreach(self::$errors as $e) {
77
- foreach($e as $error) {
78
- $res[] = $error;
79
- }
80
- }
81
- } else
82
- $res = self::$errors[$type];
83
- }
84
- return $res;
85
- }
86
- static public function haveErrors($type = '') {
87
- if(empty($type))
88
- return self::$haveErrors;
89
- else
90
- return isset(self::$errors[$type]);
91
- }
92
- }
93
-
1
+ <?php
2
+ class errorsCfs {
3
+ const FATAL = 'fatal';
4
+ const MOD_INSTALL = 'mod_install';
5
+ static private $errors = array();
6
+ static private $haveErrors = false;
7
+
8
+ static public $current = array();
9
+ static public $displayed = false;
10
+
11
+ static public function push($error, $type = 'common') {
12
+ if(!isset(self::$errors[$type]))
13
+ self::$errors[$type] = array();
14
+ if(is_array($error))
15
+ self::$errors[$type] = array_merge(self::$errors[$type], $error);
16
+ else
17
+ self::$errors[$type][] = $error;
18
+ self::$haveErrors = true;
19
+
20
+ if($type == 'session')
21
+ self::setSession(self::$errors[$type]);
22
+ }
23
+ static public function setSession($error) {
24
+ $sesErrors = self::getSession();
25
+ if(empty($sesErrors))
26
+ $sesErrors = array();
27
+ if(is_array($error))
28
+ $sesErrors = array_merge($sesErrors, $error);
29
+ else
30
+ $sesErrors[] = $error;
31
+ reqCfs::setVar('sesErrors', $sesErrors, 'session');
32
+ }
33
+ static public function init() {
34
+ $cfsErrors = reqCfs::getVar('cfsErrors');
35
+ if(!empty($cfsErrors)) {
36
+ if(!is_array($cfsErrors)) {
37
+ $cfsErrors = array( $cfsErrors );
38
+ }
39
+ $cfsErrors = array_map('htmlspecialchars', array_map('stripslashes', array_map('trim', $cfsErrors)));
40
+ if(!empty($cfsErrors)) {
41
+ self::$current = $cfsErrors;
42
+ if(is_admin()) {
43
+ add_action('admin_notices', array('errorsCfs', 'showAdminErrors'));
44
+ } else {
45
+ add_filter('the_content', array('errorsCfs', 'appendErrorsContent'), 99999);
46
+ }
47
+ }
48
+ }
49
+ }
50
+ static public function showAdminErrors() {
51
+ if(self::$current) {
52
+ $html = '';
53
+ foreach(self::$current as $error) {
54
+ $html .= '<div class="error"><p><strong style="font-size: 15px;">'. $error. '</strong></p></div>';
55
+ }
56
+ echo $html;
57
+ }
58
+ }
59
+ static public function appendErrorsContent($content) {
60
+ if(!self::$displayed && !empty(self::$current)) {
61
+ $content = '<div class="toeErrorMsg">'. implode('<br />', self::$current). '</div>'. $content;
62
+ self::$displayed = true;
63
+ }
64
+ return $content;
65
+ }
66
+ static public function getSession() {
67
+ return reqCfs::getVar('sesErrors', 'session');
68
+ }
69
+ static public function clearSession() {
70
+ reqCfs::clearVar('sesErrors', 'session');
71
+ }
72
+ static public function get($type = '') {
73
+ $res = array();
74
+ if(!empty(self::$errors)) {
75
+ if(empty($type)) {
76
+ foreach(self::$errors as $e) {
77
+ foreach($e as $error) {
78
+ $res[] = $error;
79
+ }
80
+ }
81
+ } else
82
+ $res = self::$errors[$type];
83
+ }
84
+ return $res;
85
+ }
86
+ static public function haveErrors($type = '') {
87
+ if(empty($type))
88
+ return self::$haveErrors;
89
+ else
90
+ return isset(self::$errors[$type]);
91
+ }
92
+ }
93
+
classes/field.php CHANGED
@@ -1,518 +1,518 @@
1
- <?php
2
- class fieldCfs {
3
- public $name = '';
4
- public $html = '';
5
- public $type = '';
6
- public $default = '';
7
- public $value = '';
8
- public $label = '';
9
- public $maxlen = 0;
10
- public $id = 0;
11
- public $htmlParams = array();
12
- public $validate = array();
13
- public $description = '';
14
- /**
15
- * Wheter or not add error html element right after input field
16
- * if bool - will be added standard element
17
- * if string - it will be add this string
18
- */
19
- public $errorEl = false;
20
- /**
21
- * Name of method in table object to prepare data before insert / update operations
22
- */
23
- public $adapt = array('htmlCfs' => '', 'dbFrom' => '', 'dbTo' => '');
24
- /**
25
- * Init database field representation
26
- * @param string $html html type of field (text, textarea, etc. @see html class)
27
- * @param string $type database type (int, varcahr, etc.)
28
- * @param mixed $default default value for this field
29
- */
30
- public function __construct($name, $html = 'text', $type = 'other', $default = '', $label = '', $maxlen = 0, $adaption = array(), $validate = '', $description = '') {
31
- $this->name = $name;
32
- $this->html = $html;
33
- $this->type = $type;
34
- $this->default = $default;
35
- $this->value = $default; //Init field value same as default
36
- $this->label = $label;
37
- $this->maxlen = $maxlen;
38
- $this->description = $description;
39
- if($adaption)
40
- $this->adapt = $adaption;
41
- if($validate) {
42
- $this->setValidation($validate);
43
- }
44
- if($type == 'varchar' && !empty($maxlen) && !in_array('validLen', $this->validate)) {
45
- $this->addValidation('validLen');
46
- }
47
- }
48
- /**
49
- * @param mixed $errorEl - if bool and "true" - than we will use standard error element, if string - we will use this string as error element
50
- */
51
- public function setErrorEl($errorEl) {
52
- $this->errorEl = $errorEl;
53
- }
54
- public function getErrorEl() {
55
- return $this->errorEl;
56
- }
57
- public function setValidation($validate) {
58
- if(is_array($validate))
59
- $this->validate = $validate;
60
- else {
61
- if(strpos($validate, ','))
62
- $this->validate = array_map('trim', explode(',', $validate));
63
- else
64
- $this->validate = array(trim($validate));
65
- }
66
- }
67
- public function addValidation($validate) {
68
- $this->validate[] = $validate;
69
- }
70
- /**
71
- * Set $value property.
72
- * Sure - it is public and can be set directly, but it can be more
73
- * comfortable to use this method in future
74
- * @param mixed $value value to be set
75
- */
76
- public function setValue($value, $fromDB = false) {
77
- if(isset($this->adapt['dbFrom']) && $this->adapt['dbFrom'] && $fromDB)
78
- $value = fieldAdapterCfs::_($value, $this->adapt['dbFrom'], fieldAdapterCfs::DB);
79
- $this->value = $value;
80
- }
81
- public function setLabel($label) {
82
- $this->label = $label;
83
- }
84
- public function setHtml($html) {
85
- $this->html = $html;
86
- }
87
- public function getHtml() {
88
- return $this->html;
89
- }
90
- public function setName($name) {
91
- $this->name = $name;
92
- }
93
- public function getName() {
94
- return $this->name;
95
- }
96
- public function getValue() {
97
- return $this->value;
98
- }
99
- public function getLabel() {
100
- return $this->label;
101
- }
102
- public function setID($id) {
103
- $this->id = $id;
104
- }
105
- public function getID() {
106
- return $this->id;
107
- }
108
- public function setAdapt($adapt) {
109
- $this->adapt = $adapt;
110
- }
111
- public function drawHtml($tag, $id) {
112
- if(method_exists('htmlCfs', $this->html)) {
113
- $method = $this->html;
114
- //echo $this->name. ': '. $this->value. '<br />';
115
- if(!empty($this->value))
116
- $this->htmlParams['value'] = $this->value;
117
- if ($method == 'checkbox') {
118
- if ($this->value == 1) {
119
- $this->htmlParams['checked'] = 1;
120
- }
121
- }
122
- if($this->adapt['html']) {
123
- fieldAdapterCfs::_($this, $this->adapt['html'], fieldAdapterCfs::HTML);
124
- }
125
- $params = $this->processParams($tag, $id);
126
- if ($params != '')
127
- return $params;
128
- if ($this->name == 'default_value') {
129
- $optionsFromDb = frameCfs::_()->getModule('optionsCfs')->getHelper()->getOptions($id);
130
- if (!empty($optionsFromDb)) {
131
- $options = array(0 => __('Select', CFS_LANG_CODE));
132
- foreach($optionsFromDb as $k => $v)
133
- $options[$k] = $v;
134
- $method = 'selectbox';
135
- $this->htmlParams['optionsCfs'] = $options;
136
- }
137
- }
138
- $htmlContent = htmlCfs::$method($this->name, $this->htmlParams);
139
- if(!empty($this->errorEl)) {
140
- if(is_bool($this->errorEl))
141
- $errorEl = '<div class="toeErrorForField toe_'. htmlCfs::nameToClassId($this->name). '"></div>';
142
- else //if it is string
143
- $errorEl = $this->errorEl;
144
- $htmlContent .= $errorEl;
145
- }
146
- return $htmlContent;
147
- }
148
- return false;
149
- }
150
- public function displayValue() {
151
- $value = '';
152
- switch($this->html) {
153
- case 'countryList':
154
- $value = fieldAdapterCfs::displayCountry($this->value);
155
- break;
156
- case 'statesList':
157
- $value = fieldAdapterCfs::displayState($this->value);
158
- break;
159
- case 'checkboxlist':
160
- $options = $this->getHtmlParam('optionsCfs');
161
- $value = array();
162
- if(!empty($options) && is_array($options)) {
163
- foreach($options as $opt) {
164
- if(isset($opt['checked']) && $opt['checked']) {
165
- $value[] = $opt['text'];
166
- }
167
- }
168
- }
169
- if(empty($value))
170
- $value = __('N/A', CFS_LANG_CODE);
171
- else
172
- $value = implode('<br />', $value);
173
- break;
174
- case 'selectbox': case 'radiobuttons':
175
- $options = $this->getHtmlParam('optionsCfs');
176
- if(!empty($options) && !empty($options[ $this->value ])) {
177
- $value = $options[ $this->value ];
178
- } else {
179
- $value = __('N/A', CFS_LANG_CODE);
180
- }
181
- break;
182
- default:
183
- if ($this->value == '') {
184
- $value = __('N/A', CFS_LANG_CODE);
185
- } else {
186
- if(is_array($this->value)) {
187
- $options = $this->getHtmlParam('optionsCfs');
188
- if(!empty($options) && is_array($options)) {
189
- $valArr = array();
190
- foreach($this->value as $v) {
191
- $valArr[] = $options[$v];
192
- }
193
- $value = recImplode('<br />', $valArr);
194
- } else {
195
- $value = recImplode('<br />', $this->value);
196
- }
197
- } else
198
- $value = $this->value;
199
- }
200
- break;
201
- }
202
- if($echo)
203
- echo $value;
204
- else
205
- return $value;
206
- }
207
- public function showValue() {
208
- echo $this->displayValue();
209
- }
210
- public function display($tag = 1, $id = 0) {
211
- echo $this->drawHtml($tag, $id);
212
- }
213
- public function addHtmlParam($name, $value) {
214
- $this->htmlParams[$name] = $value;
215
- }
216
- /**
217
- * Alias for addHtmlParam();
218
- */
219
- public function setHtmlParam($name, $value) {
220
- $this->addHtmlParam($name, $value);
221
- }
222
- public function setHtmlParams($params) {
223
- $this->htmlParams = $params;
224
- }
225
- public function getHtmlParam($name) {
226
- return isset($this->htmlParams[$name]) ? $this->htmlParams[$name] : false;
227
- }
228
- /**
229
- * Function to display userfields in front-end
230
- *
231
- * @param string $name
232
- * @param mixed $fieldValue
233
- * @return string
234
- */
235
- public function viewField($name, $fieldValue = '') {
236
- $method = $this->html;
237
- $options = frameCfs::_()->getModule('optionsCfs')->getHelper()->getOptions($this->id);
238
- $attrs = '';
239
- if (is_object($this->htmlParams['attr']) && count($this->htmlParams['attr']) > 0) {
240
- foreach ($this->htmlParams['attr'] as $attribute=>$value) {
241
- if ($value != '') {
242
- $attrs .= $attribute.'="'.$value.'" ';
243
- }
244
- }
245
- }
246
- if ($fieldValue == $this->default_value) {
247
- $checked = 1;
248
- } else {
249
- $checked = 0;
250
- }
251
- if ($fieldValue == '') {
252
- $fieldValue = $this->default_value;
253
- }
254
- $params = array('optionsCfs'=>$options, 'attrs' => $attrs, 'value' => $fieldValue, 'checked' => $checked);
255
- $output = '';
256
- if(method_exists('htmlCfs', $method)) {
257
- $output .= htmlCfs::$method($name, $params);
258
- $output .= htmlCfs::hidden('extra_field['.$this->name.']',array('value'=>$this->id));
259
- }
260
- return $output;
261
- }
262
-
263
- /**
264
- * Function to process field params
265
- */
266
- public function processParams($tag, $id){
267
- return '';
268
- if ($this->name == "params") {
269
- if(is_array($this->value) || is_object($this->value)) {
270
- $params = $this->value;
271
- } else {
272
- $params = json_decode($this->value);
273
- }
274
- $add_option = '';
275
- switch ($tag) {
276
- case 5:
277
- $add_option = __('Add Checkbox', CFS_LANG_CODE);
278
- $options_tag = '';
279
- $image_tag = ' style="display:none"';
280
- break;
281
- case 9:
282
- $add_option = __('Add Item', CFS_LANG_CODE);
283
- $options_tag = '';
284
- $image_tag = ' style="display:none"';
285
- break;
286
- case 12:
287
- $add_option = __('Add Item', CFS_LANG_CODE);
288
- $options_tag = '';
289
- $image_tag = ' style="display:none"';
290
- break;
291
- case 10:
292
- $options_tag = '';
293
- $add_option = __('Add Radio Button', CFS_LANG_CODE);
294
- $image_tag = ' style="display:none"';
295
- break;
296
- case 8:
297
- $image_tag = '';
298
- $options_tag = ' style="display:none"';
299
- break;
300
- default:
301
- $options_tag = ' style="display:none"';
302
- $image_tag = ' style="display:none"';
303
- break;
304
- }
305
- if ($tag > 0 || $id == 0) {
306
- $output .= '<div class="options options_tag"'.$options_tag.'>';
307
- $output .= '<span class="add_option">'.$add_option.'</span>';
308
- $output .= fieldAdapterCfs::_($id,'getExtraFieldOptions',fieldAdapterCfs::STR);
309
- $output .= '</div>';
310
-
311
- $output .= '<div class="options image_tag"'.$image_tag.'>'.__('Dimensions', CFS_LANG_CODE).':<br />';
312
- $params->width?$width = $params->width:'';
313
- $params->height?$height = $params->height:'';
314
- $output .= __('width', CFS_LANG_CODE).':<br />';
315
- $output .= htmlCfs::text('params[width]',array('value'=>$width)).'<br />';
316
- $output .= __('height', CFS_LANG_CODE).':<br />';
317
- $output .= htmlCfs::text('params[height]',array('value'=>$height)).'<br />';
318
- $output .= '</div>';
319
- }
320
- if($this->adapt['htmlParams']) {
321
- $output .= fieldAdapterCfs::_($this, $this->adapt['htmlParams'], fieldAdapterCfs::STR);
322
- } else {
323
- $output .= '<a href="javascript:void(0);" class="set_properties">'.__('Click to set field "id" and "class"', CFS_LANG_CODE).'</a>';
324
- $output .= '<div class="attributes" style="display:none;">'.__('Attributes', CFS_LANG_CODE).':<br />';
325
- $output .= fieldAdapterCfs::_($params,'getFieldAttributes', fieldAdapterCfs::STR);
326
- $output .= '</div>';
327
- }
328
- return $output;
329
- }
330
- }
331
-
332
- /**
333
- * Check if the element exists in array
334
- * @param array $param
335
- */
336
- function checkVarFromParam($param, $element) {
337
- return utilsCfs::xmlAttrToStr($param, $element);
338
- /*if (isset($param[$element])) {
339
- // convert object element to string
340
- return (string)$param[$element];
341
- } else {
342
- return '';
343
- }*/
344
- }
345
-
346
- /**
347
- * Prepares configuration options
348
- *
349
- * @param file $xml
350
- * @return array $config_params
351
- */
352
- public function prepareConfigOptions($xml) {
353
- // load xml structure of parameters
354
- $config = simplexml_load_file($xml);
355
- $config_params = array();
356
- foreach ($config->params->param as $param) {
357
- // read the variables
358
- $name = $this->checkVarFromParam($param,'name');
359
- $type = $this->checkVarFromParam($param,'type');
360
- $label = $this->checkVarFromParam($param,'label');
361
- $helper = $this->checkVarFromParam($param,'helperCfs');
362
- $module = $this->checkVarFromParam($param,'moduleCfs');
363
- $values = $this->checkVarFromParam($param,'values');
364
- $default = $this->checkVarFromParam($param,'default');
365
- $description = $this->checkVarFromParam($param,'description');
366
- if ($name == '') continue;
367
- // fill in the variables to configuration array
368
- $config_params[$name] = array('type'=>$type,
369
- 'label'=>$label,
370
- 'helperCfs'=>$helper,
371
- 'moduleCfs'=>$module,
372
- 'values'=>$values,
373
- 'default'=>$default,
374
- 'description'=>$description,
375
- );
376
- }
377
- return $config_params;
378
- }
379
- public function setDescription($desc) {
380
- $this->description = $desc;
381
- }
382
- public function getDescription() {
383
- return $this->description;
384
- }
385
- /**
386
- * Displays the config options for given module
387
- *
388
- * @param string $module
389
- * @param array $addDefaultOptions - if you want to add some additionsl options - specify it here
390
- */
391
- public function drawConfig($module, $additionalOptions = array()) {
392
- if(!frameCfs::_()->getModule($module))
393
- return false;
394
- // check for xml file with params structure
395
- if(frameCfs::_()->getModule($module)->isExternal())
396
- $config_xml = frameCfs::_()->getModule($module)->getModDir(). 'mod.xml';
397
- else
398
- $config_xml = CFS_MODULES_DIR.$module.DS.'mod.xml';
399
-
400
- if (!file_exists($config_xml)) {
401
- // if there is no configuration file for this $module
402
- return __('There are no configuration options for this module', CFS_LANG_CODE);
403
- }
404
- $output = '';
405
- // reading params structure
406
- $configOptions = $this->prepareConfigOptions($config_xml);
407
- // reading params from database
408
- //bugodel2nia..............
409
- if(is_string($this->value))
410
- $params = Utils::jsonDecode($this->value);
411
- elseif(is_object($this->value) || is_array($this->value))
412
- $params = toeObjectToArray($this->value);
413
- //if (!empty($params)) {
414
- if (!empty($configOptions)){
415
- $i = 0;
416
- if (empty($params)) {
417
- $params = array('0'=>array());
418
- }
419
- if(is_array($additionalOptions) && !empty($additionalOptions)) {
420
- $configOptions = array_merge($configOptions, $additionalOptions);
421
- }
422
- foreach ($params as $param) {
423
- $output .= '<div class="module_options">';
424
- foreach ($configOptions as $key=>$value){
425
- $fieldValue = '';
426
- $output .= '<div class="module_option">';
427
- $method = $configOptions[$key]['type'];
428
- $name = 'params['.$i.']['.$key.']';
429
- $options = array();
430
- // if the values attribute is set
431
- if ($configOptions[$key]['values'] != ''){
432
- $extract_options = explode(',', $configOptions[$key]['values']);
433
- if (count($extract_options) > 1) {
434
- foreach ($extract_options as $item=>$string) {
435
- if(strpos($string, '=>')) {
436
- $keyVal = array_map('trim', explode('=>', $string));
437
- $options[ $keyVal[0] ] = $keyVal[1];
438
- } else {
439
- $options[$string] = $string;
440
- }
441
- }
442
- } else {
443
- $fieldValue = $configOptions[$key]['default'];
444
- }
445
- // if helper is needed to render the object
446
- } elseif ($configOptions[$key]['helper'] != '') {
447
- $helper_name = $configOptions[$key]['helper'];
448
- // is helper from current module or other?
449
- if ($configOptions[$key]['module'] != '') {
450
- $hmodule = $configOptions[$key]['module'];
451
- } else {
452
- $hmodule = $module;
453
- }
454
- // calling the helper class
455
- $helper = frameCfs::_()->getModule($hmodule)->getHelper();
456
- if ($helper) {
457
- // calling the helper method for current option
458
- if (method_exists($helper, $helper_name))
459
- $options = $helper->$helper_name();
460
- }
461
- }
462
- if (isset($param[$key])) {
463
- $fieldValue = $param[$key];
464
- } else {
465
- if ($fieldValue == '')
466
- $fieldValue = $configOptions[$key]['default'];
467
- }
468
- // filling the parameters to build html element
469
- $htmlParams = array('value'=>$fieldValue,'optionsCfs'=>$options);
470
- if($method == 'checkbox') {
471
- $htmlParams['value'] = 1;
472
- $htmlParams['checked'] = (bool)$fieldValue;
473
- }
474
- if(!empty($configOptions[$key]['htmlParams']) && is_array($configOptions[$key]['htmlParams'])) {
475
- $htmlParams = array_merge($htmlParams, $configOptions[$key]['htmlParams']);
476
- }
477
- // output label and html element
478
- $output .= '<label>'.__($configOptions[$key]['label']);
479
- if ($configOptions[$key]['description'] != '') {
480
- $output .= '<a class="toeOptTip" tip="'.__($configOptions[$key]['description']).'"></a>';
481
- }
482
- $output .= '</label><br />';
483
- $output .= htmlCfs::$method($name,$htmlParams).'<br />';
484
- $output .= '</div>';
485
- }
486
- $i++;
487
- $output .= '</div>';
488
- }
489
- }
490
- return $output;
491
- }
492
-
493
- public function displayConfig($module) {
494
- echo $this->drawConfig($module);
495
- }
496
- /**
497
- * This method will prepare internal value to it's type
498
- * @see $this->type
499
- * @return mixed - prepared value on the basis of $this->type
500
- */
501
- public function valToType() {
502
- switch($this->type) {
503
- case 'int':
504
- case 'mediumint':
505
- case 'smallint':
506
- $this->value = (int) $this->value;
507
- break;
508
- case 'float':
509
- $this->value = (float) $this->value;
510
- break;
511
- case 'double':
512
- case 'decimal':
513
- $this->value = (double) $this->value;
514
- break;
515
- }
516
- return $this->type;
517
- }
518
- }
1
+ <?php
2
+ class fieldCfs {
3
+ public $name = '';
4
+ public $html = '';
5
+ public $type = '';
6
+ public $default = '';
7
+ public $value = '';
8
+ public $label = '';
9
+ public $maxlen = 0;
10
+ public $id = 0;
11
+ public $htmlParams = array();
12
+ public $validate = array();
13
+ public $description = '';
14
+ /**
15
+ * Wheter or not add error html element right after input field
16
+ * if bool - will be added standard element
17
+ * if string - it will be add this string
18
+ */
19
+ public $errorEl = false;
20
+ /**
21
+ * Name of method in table object to prepare data before insert / update operations
22
+ */
23
+ public $adapt = array('htmlCfs' => '', 'dbFrom' => '', 'dbTo' => '');
24
+ /**
25
+ * Init database field representation
26
+ * @param string $html html type of field (text, textarea, etc. @see html class)
27
+ * @param string $type database type (int, varcahr, etc.)
28
+ * @param mixed $default default value for this field
29
+ */
30
+ public function __construct($name, $html = 'text', $type = 'other', $default = '', $label = '', $maxlen = 0, $adaption = array(), $validate = '', $description = '') {
31
+ $this->name = $name;
32
+ $this->html = $html;
33
+ $this->type = $type;
34
+ $this->default = $default;
35
+ $this->value = $default; //Init field value same as default
36
+ $this->label = $label;
37
+ $this->maxlen = $maxlen;
38
+ $this->description = $description;
39
+ if($adaption)
40
+ $this->adapt = $adaption;
41
+ if($validate) {
42
+ $this->setValidation($validate);
43
+ }
44
+ if($type == 'varchar' && !empty($maxlen) && !in_array('validLen', $this->validate)) {
45
+ $this->addValidation('validLen');
46
+ }
47
+ }
48
+ /**
49
+ * @param mixed $errorEl - if bool and "true" - than we will use standard error element, if string - we will use this string as error element
50
+ */
51
+ public function setErrorEl($errorEl) {
52
+ $this->errorEl = $errorEl;
53
+ }
54
+ public function getErrorEl() {
55
+ return $this->errorEl;
56
+ }
57
+ public function setValidation($validate) {
58
+ if(is_array($validate))
59
+ $this->validate = $validate;
60
+ else {
61
+ if(strpos($validate, ','))
62
+ $this->validate = array_map('trim', explode(',', $validate));
63
+ else
64
+ $this->validate = array(trim($validate));
65
+ }
66
+ }
67
+ public function addValidation($validate) {
68
+ $this->validate[] = $validate;
69
+ }
70
+ /**
71
+ * Set $value property.
72
+ * Sure - it is public and can be set directly, but it can be more
73
+ * comfortable to use this method in future
74
+ * @param mixed $value value to be set
75
+ */
76
+ public function setValue($value, $fromDB = false) {
77
+ if(isset($this->adapt['dbFrom']) && $this->adapt['dbFrom'] && $fromDB)
78
+ $value = fieldAdapterCfs::_($value, $this->adapt['dbFrom'], fieldAdapterCfs::DB);
79
+ $this->value = $value;
80
+ }
81
+ public function setLabel($label) {
82
+ $this->label = $label;
83
+ }
84
+ public function setHtml($html) {
85
+ $this->html = $html;
86
+ }
87
+ public function getHtml() {
88
+ return $this->html;
89
+ }
90
+ public function setName($name) {
91
+ $this->name = $name;
92
+ }
93
+ public function getName() {
94
+ return $this->name;
95
+ }
96
+ public function getValue() {
97
+ return $this->value;
98
+ }
99
+ public function getLabel() {
100
+ return $this->label;
101
+ }
102
+ public function setID($id) {
103
+ $this->id = $id;
104
+ }
105
+ public function getID() {
106
+ return $this->id;
107
+ }
108
+ public function setAdapt($adapt) {
109
+ $this->adapt = $adapt;
110
+ }
111
+ public function drawHtml($tag, $id) {
112
+ if(method_exists('htmlCfs', $this->html)) {
113
+ $method = $this->html;
114
+ //echo $this->name. ': '. $this->value. '<br />';
115
+ if(!empty($this->value))
116
+ $this->htmlParams['value'] = $this->value;
117
+ if ($method == 'checkbox') {
118
+ if ($this->value == 1) {
119
+ $this->htmlParams['checked'] = 1;
120
+ }
121
+ }
122
+ if($this->adapt['html']) {
123
+ fieldAdapterCfs::_($this, $this->adapt['html'], fieldAdapterCfs::HTML);
124
+ }
125
+ $params = $this->processParams($tag, $id);
126
+ if ($params != '')
127
+ return $params;
128
+ if ($this->name == 'default_value') {
129
+ $optionsFromDb = frameCfs::_()->getModule('optionsCfs')->getHelper()->getOptions($id);
130
+ if (!empty($optionsFromDb)) {
131
+ $options = array(0 => __('Select', CFS_LANG_CODE));
132
+ foreach($optionsFromDb as $k => $v)
133
+ $options[$k] = $v;
134
+ $method = 'selectbox';
135
+ $this->htmlParams['optionsCfs'] = $options;
136
+ }
137
+ }
138
+ $htmlContent = htmlCfs::$method($this->name, $this->htmlParams);
139
+ if(!empty($this->errorEl)) {
140
+ if(is_bool($this->errorEl))
141
+ $errorEl = '<div class="toeErrorForField toe_'. htmlCfs::nameToClassId($this->name). '"></div>';
142
+ else //if it is string
143
+ $errorEl = $this->errorEl;
144
+ $htmlContent .= $errorEl;
145
+ }
146
+ return $htmlContent;
147
+ }
148
+ return false;
149
+ }
150
+ public function displayValue() {
151
+ $value = '';
152
+ switch($this->html) {
153
+ case 'countryList':
154
+ $value = fieldAdapterCfs::displayCountry($this->value);
155
+ break;
156
+ case 'statesList':
157
+ $value = fieldAdapterCfs::displayState($this->value);
158
+ break;
159
+ case 'checkboxlist':
160
+ $options = $this->getHtmlParam('optionsCfs');
161
+ $value = array();
162
+ if(!empty($options) && is_array($options)) {
163
+ foreach($options as $opt) {
164
+ if(isset($opt['checked']) && $opt['checked']) {
165
+ $value[] = $opt['text'];
166
+ }
167
+ }
168
+ }
169
+ if(empty($value))
170
+ $value = __('N/A', CFS_LANG_CODE);
171
+ else
172
+ $value = implode('<br />', $value);
173
+ break;
174
+ case 'selectbox': case 'radiobuttons':
175
+ $options = $this->getHtmlParam('optionsCfs');
176
+ if(!empty($options) && !empty($options[ $this->value ])) {
177
+ $value = $options[ $this->value ];
178
+ } else {
179
+ $value = __('N/A', CFS_LANG_CODE);
180
+ }
181
+ break;
182
+ default:
183
+ if ($this->value == '') {
184
+ $value = __('N/A', CFS_LANG_CODE);
185
+ } else {
186
+ if(is_array($this->value)) {
187
+ $options = $this->getHtmlParam('optionsCfs');
188
+ if(!empty($options) && is_array($options)) {
189
+ $valArr = array();
190
+ foreach($this->value as $v) {
191
+ $valArr[] = $options[$v];
192
+ }
193
+ $value = recImplode('<br />', $valArr);
194
+ } else {
195
+ $value = recImplode('<br />', $this->value);
196
+ }
197
+ } else
198
+ $value = $this->value;
199
+ }
200
+ break;
201
+ }
202
+ if($echo)
203
+ echo $value;
204
+ else
205
+ return $value;
206
+ }
207
+ public function showValue() {
208
+ echo $this->displayValue();
209
+ }
210
+ public function display($tag = 1, $id = 0) {
211
+ echo $this->drawHtml($tag, $id);
212
+ }
213
+ public function addHtmlParam($name, $value) {
214
+ $this->htmlParams[$name] = $value;
215
+ }
216
+ /**
217
+ * Alias for addHtmlParam();
218
+ */
219
+ public function setHtmlParam($name, $value) {
220
+ $this->addHtmlParam($name, $value);
221
+ }
222
+ public function setHtmlParams($params) {
223
+ $this->htmlParams = $params;
224
+ }
225
+ public function getHtmlParam($name) {
226
+ return isset($this->htmlParams[$name]) ? $this->htmlParams[$name] : false;
227
+ }
228
+ /**
229
+ * Function to display userfields in front-end
230
+ *
231
+ * @param string $name
232
+ * @param mixed $fieldValue
233
+ * @return string
234
+ */
235
+ public function viewField($name, $fieldValue = '') {
236
+ $method = $this->html;
237
+ $options = frameCfs::_()->getModule('optionsCfs')->getHelper()->getOptions($this->id);
238
+ $attrs = '';
239
+ if (is_object($this->htmlParams['attr']) && count($this->htmlParams['attr']) > 0) {
240
+ foreach ($this->htmlParams['attr'] as $attribute=>$value) {
241
+ if ($value != '') {
242
+ $attrs .= $attribute.'="'.$value.'" ';
243
+ }
244
+ }
245
+ }
246
+ if ($fieldValue == $this->default_value) {
247
+ $checked = 1;
248
+ } else {
249
+ $checked = 0;
250
+ }
251
+ if ($fieldValue == '') {
252
+ $fieldValue = $this->default_value;
253
+ }
254
+ $params = array('optionsCfs'=>$options, 'attrs' => $attrs, 'value' => $fieldValue, 'checked' => $checked);
255
+ $output = '';
256
+ if(method_exists('htmlCfs', $method)) {
257
+ $output .= htmlCfs::$method($name, $params);
258
+ $output .= htmlCfs::hidden('extra_field['.$this->name.']',array('value'=>$this->id));
259
+ }
260
+ return $output;
261
+ }
262
+
263
+ /**
264
+ * Function to process field params
265
+ */
266
+ public function processParams($tag, $id){
267
+ return '';
268
+ if ($this->name == "params") {
269
+ if(is_array($this->value) || is_object($this->value)) {
270
+ $params = $this->value;
271
+ } else {
272
+ $params = json_decode($this->value);
273
+ }
274
+ $add_option = '';
275
+ switch ($tag) {
276
+ case 5:
277
+ $add_option = __('Add Checkbox', CFS_LANG_CODE);
278
+ $options_tag = '';
279
+ $image_tag = ' style="display:none"';
280
+ break;
281
+ case 9:
282
+ $add_option = __('Add Item', CFS_LANG_CODE);
283
+ $options_tag = '';
284
+ $image_tag = ' style="display:none"';
285
+ break;
286
+ case 12:
287
+ $add_option = __('Add Item', CFS_LANG_CODE);
288
+ $options_tag = '';
289
+ $image_tag = ' style="display:none"';
290
+ break;
291
+ case 10:
292
+ $options_tag = '';
293
+ $add_option = __('Add Radio Button', CFS_LANG_CODE);
294
+ $image_tag = ' style="display:none"';
295
+ break;
296
+ case 8:
297
+ $image_tag = '';
298
+ $options_tag = ' style="display:none"';
299
+ break;
300
+ default:
301
+ $options_tag = ' style="display:none"';
302
+ $image_tag = ' style="display:none"';
303
+ break;
304
+ }
305
+ if ($tag > 0 || $id == 0) {
306
+ $output .= '<div class="options options_tag"'.$options_tag.'>';
307
+ $output .= '<span class="add_option">'.$add_option.'</span>';
308
+ $output .= fieldAdapterCfs::_($id,'getExtraFieldOptions',fieldAdapterCfs::STR);
309
+ $output .= '</div>';
310
+
311
+ $output .= '<div class="options image_tag"'.$image_tag.'>'.__('Dimensions', CFS_LANG_CODE).':<br />';
312
+ $params->width?$width = $params->width:'';
313
+ $params->height?$height = $params->height:'';
314
+ $output .= __('width', CFS_LANG_CODE).':<br />';
315
+ $output .= htmlCfs::text('params[width]',array('value'=>$width)).'<br />';
316
+ $output .= __('height', CFS_LANG_CODE).':<br />';
317
+ $output .= htmlCfs::text('params[height]',array('value'=>$height)).'<br />';
318
+ $output .= '</div>';
319
+ }
320
+ if($this->adapt['htmlParams']) {
321
+ $output .= fieldAdapterCfs::_($this, $this->adapt['htmlParams'], fieldAdapterCfs::STR);
322
+ } else {
323
+ $output .= '<a href="javascript:void(0);" class="set_properties">'.__('Click to set field "id" and "class"', CFS_LANG_CODE).'</a>';
324
+ $output .= '<div class="attributes" style="display:none;">'.__('Attributes', CFS_LANG_CODE).':<br />';
325
+ $output .= fieldAdapterCfs::_($params,'getFieldAttributes', fieldAdapterCfs::STR);
326
+ $output .= '</div>';
327
+ }
328
+ return $output;
329
+ }
330
+ }
331
+
332
+ /**
333
+ * Check if the element exists in array
334
+ * @param array $param
335
+ */
336
+ function checkVarFromParam($param, $element) {
337
+ return utilsCfs::xmlAttrToStr($param, $element);
338
+ /*if (isset($param[$element])) {
339
+ // convert object element to string
340
+ return (string)$param[$element];
341
+ } else {
342
+ return '';
343
+ }*/
344
+ }
345
+
346
+ /**
347
+ * Prepares configuration options
348
+ *
349
+ * @param file $xml
350
+ * @return array $config_params
351
+ */
352
+ public function prepareConfigOptions($xml) {
353
+ // load xml structure of parameters
354
+ $config = simplexml_load_file($xml);
355
+ $config_params = array();
356
+ foreach ($config->params->param as $param) {
357
+ // read the variables
358
+ $name = $this->checkVarFromParam($param,'name');
359
+ $type = $this->checkVarFromParam($param,'type');
360
+ $label = $this->checkVarFromParam($param,'label');
361
+ $helper = $this->checkVarFromParam($param,'helperCfs');
362
+ $module = $this->checkVarFromParam($param,'moduleCfs');
363
+ $values = $this->checkVarFromParam($param,'values');
364
+ $default = $this->checkVarFromParam($param,'default');
365
+ $description = $this->checkVarFromParam($param,'description');
366
+ if ($name == '') continue;
367
+ // fill in the variables to configuration array
368
+ $config_params[$name] = array('type'=>$type,
369
+ 'label'=>$label,
370
+ 'helperCfs'=>$helper,
371
+ 'moduleCfs'=>$module,
372
+ 'values'=>$values,
373
+ 'default'=>$default,
374
+ 'description'=>$description,
375
+ );
376
+ }
377
+ return $config_params;
378
+ }
379
+ public function setDescription($desc) {
380
+ $this->description = $desc;
381
+ }
382
+ public function getDescription() {
383
+ return $this->description;
384
+ }
385
+ /**
386
+ * Displays the config options for given module
387
+ *
388
+ * @param string $module
389
+ * @param array $addDefaultOptions - if you want to add some additionsl options - specify it here
390
+ */
391
+ public function drawConfig($module, $additionalOptions = array()) {
392
+ if(!frameCfs::_()->getModule($module))
393
+ return false;
394
+ // check for xml file with params structure
395
+ if(frameCfs::_()->getModule($module)->isExternal())
396
+ $config_xml = frameCfs::_()->getModule($module)->getModDir(). 'mod.xml';
397
+ else
398
+ $config_xml = CFS_MODULES_DIR.$module.DS.'mod.xml';
399
+
400
+ if (!file_exists($config_xml)) {
401
+ // if there is no configuration file for this $module
402
+ return __('There are no configuration options for this module', CFS_LANG_CODE);
403
+ }
404
+ $output = '';
405
+ // reading params structure
406
+ $configOptions = $this->prepareConfigOptions($config_xml);
407
+ // reading params from database
408
+ //bugodel2nia..............
409
+ if(is_string($this->value))
410
+ $params = Utils::jsonDecode($this->value);
411
+ elseif(is_object($this->value) || is_array($this->value))
412
+ $params = toeObjectToArray($this->value);
413
+ //if (!empty($params)) {
414
+ if (!empty($configOptions)){
415
+ $i = 0;
416
+ if (empty($params)) {
417
+ $params = array('0'=>array());
418
+ }
419
+ if(is_array($additionalOptions) && !empty($additionalOptions)) {
420
+ $configOptions = array_merge($configOptions, $additionalOptions);
421
+ }
422
+ foreach ($params as $param) {
423
+ $output .= '<div class="module_options">';
424
+ foreach ($configOptions as $key=>$value){
425
+ $fieldValue = '';
426
+ $output .= '<div class="module_option">';
427
+ $method = $configOptions[$key]['type'];
428
+ $name = 'params['.$i.']['.$key.']';
429
+ $options = array();
430
+ // if the values attribute is set
431
+ if ($configOptions[$key]['values'] != ''){
432
+ $extract_options = explode(',', $configOptions[$key]['values']);
433
+ if (count($extract_options) > 1) {
434
+ foreach ($extract_options as $item=>$string) {
435
+ if(strpos($string, '=>')) {
436
+ $keyVal = array_map('trim', explode('=>', $string));
437
+ $options[ $keyVal[0] ] = $keyVal[1];
438
+ } else {
439
+ $options[$string] = $string;
440
+ }
441
+ }
442
+ } else {
443
+ $fieldValue = $configOptions[$key]['default'];
444
+ }
445
+ // if helper is needed to render the object
446
+ } elseif ($configOptions[$key]['helper'] != '') {
447
+ $helper_name = $configOptions[$key]['helper'];
448
+ // is helper from current module or other?
449
+ if ($configOptions[$key]['module'] != '') {
450
+ $hmodule = $configOptions[$key]['module'];
451
+ } else {
452
+ $hmodule = $module;
453
+ }
454
+ // calling the helper class
455
+ $helper = frameCfs::_()->getModule($hmodule)->getHelper();
456
+ if ($helper) {
457
+ // calling the helper method for current option
458
+ if (method_exists($helper, $helper_name))
459
+ $options = $helper->$helper_name();
460
+ }
461
+ }
462
+ if (isset($param[$key])) {
463
+ $fieldValue = $param[$key];
464
+ } else {
465
+ if ($fieldValue == '')
466
+ $fieldValue = $configOptions[$key]['default'];
467
+ }
468
+ // filling the parameters to build html element
469
+ $htmlParams = array('value'=>$fieldValue,'optionsCfs'=>$options);
470
+ if($method == 'checkbox') {
471
+ $htmlParams['value'] = 1;
472
+ $htmlParams['checked'] = (bool)$fieldValue;
473
+ }
474
+ if(!empty($configOptions[$key]['htmlParams']) && is_array($configOptions[$key]['htmlParams'])) {
475
+ $htmlParams = array_merge($htmlParams, $configOptions[$key]['htmlParams']);
476
+ }
477
+ // output label and html element
478
+ $output .= '<label>'.__($configOptions[$key]['label']);
479
+ if ($configOptions[$key]['description'] != '') {
480
+ $output .= '<a class="toeOptTip" tip="'.__($configOptions[$key]['description']).'"></a>';
481
+ }
482
+ $output .= '</label><br />';
483
+ $output .= htmlCfs::$method($name,$htmlParams).'<br />';
484
+ $output .= '</div>';
485
+ }
486
+ $i++;
487
+ $output .= '</div>';
488
+ }
489
+ }
490
+ return $output;
491
+ }
492
+
493
+ public function displayConfig($module) {
494
+ echo $this->drawConfig($module);
495
+ }
496
+ /**
497
+ * This method will prepare internal value to it's type
498
+ * @see $this->type
499
+ * @return mixed - prepared value on the basis of $this->type
500
+ */
501
+ public function valToType() {
502
+ switch($this->type) {
503
+ case 'int':
504
+ case 'mediumint':
505
+ case 'smallint':
506
+ $this->value = (int) $this->value;
507
+ break;
508
+ case 'float':
509
+ $this->value = (float) $this->value;
510
+ break;
511
+ case 'double':
512
+ case 'decimal':
513
+ $this->value = (double) $this->value;
514
+ break;
515
+ }
516
+ return $this->type;
517
+ }
518
+ }
classes/fieldAdapter.php CHANGED
@@ -1,310 +1,315 @@
1
- <?php
2
- /**
3
- * Class to adapt field before display
4
- * return ONLY htmlParams property
5
- * @see field
6
- */
7
- class fieldAdapterCfs {
8
- const DB = 'dbCfs';
9
- const HTML = 'htmlCfs';
10
- const STR = 'str';
11
- static public $userfieldDest = array('registration', 'shipping', 'billing');
12
- static public $countries = array();
13
- static public $states = array();
14
- /**
15
- * Executes field Adaption process
16
- * @param object type field or value $fieldOrValue if DB adaption - this must be a value of field, elase if html - field object
17
- */
18
- static public function _($fieldOrValue, $method, $type) {
19
- if(method_exists('fieldAdapterCfs', $method)) {
20
- switch($type) {
21
- case self::DB:
22
- return self::$method($fieldOrValue);
23
- break;
24
- case self::HTML:
25
- self::$method($fieldOrValue);
26
- break;
27
- case self::STR:
28
- return self::$method($fieldOrValue);
29
- break;
30
- }
31
- }
32
- return $fieldOrValue;
33
- }
34
- static public function userFieldDestHtml($field) {
35
- $field->htmlParams['optionsCfs'] = array();
36
- if(!is_array($field->value)) {
37
- if(empty($field->value))
38
- $field->value = array();
39
- else
40
- $field->value = json_decode($field->value);
41
- }
42
- foreach(self::$userfieldDest as $d) {
43
- $field->htmlParams['optionsCfs'][] = array(
44
- 'id' => $d,
45
- 'text' => $d,
46
- 'checked' => in_array($d, $field->value)
47
- );
48
- }
49
- }
50
- static public function userFieldDestToDB($value) {
51
- return utilsCfs::jsonEncode($value);
52
- }
53
- static public function userFieldDestFromDB($value) {
54
- return utilsCfs::jsonDecode($value);
55
- }
56
- static public function taxDataHtml($field) {
57
- $listOfDest = array();
58
- if(!is_array($field->value)) {
59
- if(empty($field->value))
60
- $field->value = array();
61
- else
62
- $field->value = (array)json_decode($field->value, true);
63
- }
64
- foreach(self::$userfieldDest as $d) {
65
- $listOfDest[] = array(
66
- 'id' => $d,
67
- 'text' => $d,
68
- 'checked' => (is_array($field->value['dest']) && in_array($d, $field->value['dest']))
69
- );
70
- }
71
- $categories = frameCfs::_()->getModule('products')->getCategories();
72
- $brands = frameCfs::_()->getModule('products')->getBrands();
73
- $cOptions = array();
74
- $bOptions = array();
75
- if(!empty($categories)) {
76
- if(!is_array($field->value['categories']))
77
- $field->value['categories'] = array();
78
- foreach($categories as $c) {
79
- $cOptions[] = array('id' => $c->term_taxonomy_id,
80
- 'text' => $c->cat_name,
81
- 'checked' => in_array($c->term_taxonomy_id, $field->value['categories']));
82
- }
83
- }
84
- if(!empty($brands)) {
85
- if(!is_array($field->value['brands']))
86
- $field->value['brands'] = array();
87
- foreach($brands as $b) {
88
- $bOptions[] = array('id' => $b->term_taxonomy_id,
89
- 'text' => $b->cat_name,
90
- 'checked' => in_array($b->term_taxonomy_id, $field->value['brands']));
91
- }
92
- }
93
- return '<div>'. __('Apply To', CFS_LANG_CODE). '
94
- <div id="tax_address">
95
- <b>'. __('Address', CFS_LANG_CODE). '</b><br />
96
- '. __('Destination', CFS_LANG_CODE). ':'. htmlCfs::checkboxlist('params[dest]', array('optionsCfs' => $listOfDest)). '<br />
97
- '. __('Country', CFS_LANG_CODE). ':'. htmlCfs::countryList('params[country]', array('notSelected' => true, 'value' => $field->value['country'])). '<br />
98
- </div>
99
- <div id="tax_category">
100
- <b>'. __('Categories', CFS_LANG_CODE). '</b><br />
101
- '. (empty($cOptions) ? __('You have no categories', CFS_LANG_CODE) : htmlCfs::checkboxlist('params[categories][]', array('optionsCfs' => $cOptions))). '<br />
102
- <b>'. __('Brands', CFS_LANG_CODE). '</b><br />
103
- '. (empty($bOptions) ? __('You have no brands', CFS_LANG_CODE) : htmlCfs::checkboxlist('params[brands][]', array('optionsCfs' => $bOptions))). '<br />
104
- </div>
105
- <div>'. __('Tax Rate', CFS_LANG_CODE).': '. htmlCfs::text('params[rate]', array('value' => $field->value['rate'])).'</div>
106
- <div>'. __('Absolute', CFS_LANG_CODE).': '. htmlCfs::checkbox('params[absolute]', array('checked' => $field->value['absolute'])).'</div>
107
- </div>';
108
- }
109
- static public function displayCountry($cid, $key = 'name') {
110
- if($key == 'name') {
111
- $countries = self::getCountries();
112
- return $countries[$cid];
113
- } else {
114
- if(empty(self::$countries))
115
- self::$countries = self::getCachedCountries();
116
- foreach(self::$countries as $c) {
117
- if($c['id'] == $cid)
118
- return $c[ $key ];
119
- }
120
- }
121
- return false;
122
- }
123
- static public function displayState($sid, $key = 'name') {
124
- $states = self::getStates();
125
- return empty($states[$sid]) ? $sid : $states[$sid][$key];
126
- }
127
- static public function getCountries($notSelected = false, $listBy = 'id') {
128
- $options = array();
129
- if(empty(self::$countries))
130
- self::$countries = self::getCachedCountries();
131
- if($notSelected) {
132
- $options[0] = is_bool($notSelected) ? __('Not selected', CFS_LANG_CODE) : __($notSelected);
133
- }
134
- foreach(self::$countries as $c) {
135
- $options[$c[ $listBy ]] = $c['name'];
136
- }
137
- return $options;
138
- }
139
- static public function getStates($notSelected = false) {
140
- static $options = array();
141
- if(empty($options[ $notSelected ])) {
142
- $options[ $notSelected ] = array();
143
- if(empty(self::$states))
144
- self::$states = self::getCachedStates();
145
- if($notSelected) {
146
- $notSelectedLabel = is_bool($notSelected) ? 'Not selected' : $notSelected;
147
- $options[ $notSelected ][0] = array('name' => __( $notSelectedLabel ), 'country_id' => NULL);
148
- }
149
- foreach(self::$states as $s) $options[ $notSelected ][$s['id']] = $s;
150
- }
151
- return $options[ $notSelected ];
152
- }
153
- /**
154
- * Function to get extra field options
155
- *
156
- * @param object $field
157
- * @return string
158
- */
159
- static public function getExtraFieldOptions($field_id) {
160
- $output = '';
161
- if ($field_id == 0) return '';
162
- $options = frameCfs::_()->getModule('optionsCfs')->getHelper()->getOptions($field_id);
163
- if (!empty($options)) {
164
- foreach ($options as $key=>$value) {
165
- $output .= '<p>'.$value.'<span class="delete_option" rel="'.$key.'"></span></p>';
166
- }
167
- }
168
- return $output;
169
- }
170
- /**
171
- * Function to get field params
172
- *
173
- * @param object $params
174
- */
175
- static public function getFieldAttributes($params){
176
- $output = '';
177
- if (!empty($params->attr)) {
178
- foreach ($params->attr as $key=>$value) {
179
- $output .= __($key).':<br />';
180
- $output .= htmlCfs::text('params[attr]['.$key.']',array('value'=>$value)).'<br />';
181
- }
182
- } else {
183
- $output .= __('class', CFS_LANG_CODE).':<br />';
184
- $output .= htmlCfs::text('params[attr][class]',array('value'=>'')).'<br />';
185
- $output .= __('id', CFS_LANG_CODE).':<br />';
186
- $output .= htmlCfs::text('params[attr][id]',array('value'=>'')).'<br />';
187
- }
188
- return $output;
189
- }
190
- /**
191
- * Generating the list of categories for product extra fields
192
- *
193
- * @param object $field
194
- */
195
- static function productFieldCategories($field){
196
- if(!empty($field->htmlParams['optionsCfs']))
197
- return;
198
- /*$field->htmlParams['attrs'] = 'id="select_product_field_cat" rel="0"';
199
- $field->htmlParams['optionsCfs'] = array();
200
- $categories = frameCfs::_()->getModule('products')->getCategories();
201
- if(!empty($categories)) {
202
- if(!is_array($field->value['categories']))
203
- $field->value['categories'] = array();
204
- $field->htmlParams['optionsCfs'][0] = in_array(0,$field->value['categories'])?__('Deselect All'):__('Select All', CFS_LANG_CODE);
205
- foreach($categories as $c) {
206
- $field->htmlParams['optionsCfs'][$c->term_taxonomy_id] = $c->cat_name;
207
- }
208
- }*/
209
- }
210
- static public function intToDB($val) {
211
- return intval($val);
212
- }
213
- static public function floatToDB($val) {
214
- return floatval($val);
215
- }
216
- /**
217
- * Save this in static var - to futher usage
218
- * @return array with countries
219
- */
220
- static public function getCachedCountries($clearCache = false) {
221
- if(empty(self::$countries) || $clearCache)
222
- self::$countries = frameCfs::_()->getTable('countries')->getAll('id, name, iso_code_2, iso_code_3');
223
- return self::$countries;
224
- }
225
- /**
226
- * Save this in static var - to futher usage
227
- * @return array with states
228
- */
229
- static public function getCachedStates($clearCache = false) {
230
- if(empty(self::$states) || $clearCache)
231
- self::$states = frameCfs::_()->getTable('states')
232
- ->leftJoin( frameCfs::_()->getTable('countries'), 'country_id' )
233
- ->getAll('toe_states.id,
234
- toe_states.name,
235
- toe_states.code,
236
- toe_states.country_id,
237
- toe_cry.name AS c_name,
238
- toe_cry.iso_code_2 AS c_iso_code_2,
239
- toe_cry.iso_code_3 AS c_iso_code_3');
240
- return self::$states;
241
- }
242
- static public function getFontsList() {
243
- return array("Abel", "Abril Fatface", "Aclonica", "Acme", "Actor", "Adamina", "Advent Pro",
244
- "Aguafina Script", "Aladin", "Aldrich", "Alegreya", "Alegreya SC", "Alex Brush", "Alfa Slab One", "Alice",
245
- "Alike", "Alike Angular", "Allan", "Allerta", "Allerta Stencil", "Allura", "Almendra", "Almendra SC", "Amaranth",
246
- "Amatic SC", "Amethysta", "Andada", "Andika", "Angkor", "Annie Use Your Telescope", "Anonymous Pro", "Antic",
247
- "Antic Didone", "Antic Slab", "Anton", "Arapey", "Arbutus", "Architects Daughter", "Arimo", "Arizonia", "Armata",
248
- "Artifika", "Arvo", "Asap", "Asset", "Astloch", "Asul", "Atomic Age", "Aubrey", "Audiowide", "Average",
249
- "Averia Gruesa Libre", "Averia Libre", "Averia Sans Libre", "Averia Serif Libre", "Bad Script", "Balthazar",
250
- "Bangers", "Basic", "Battambang", "Baumans", "Bayon", "Belgrano", "Belleza", "Bentham", "Berkshire Swash",
251
- "Bevan", "Bigshot One", "Bilbo", "Bilbo Swash Caps", "Bitter", "Black Ops One", "Bokor", "Bonbon", "Boogaloo",
252
- "Bowlby One", "Bowlby One SC", "Brawler", "Bree Serif", "Bubblegum Sans", "Buda", "Buenard", "Butcherman",
253
- "Butterfly Kids", "Cabin", "Cabin Condensed", "Cabin Sketch", "Caesar Dressing", "Cagliostro", "Calligraffitti",
254
- "Cambo", "Candal", "Cantarell", "Cantata One", "Cardo", "Carme", "Carter One", "Caudex", "Cedarville Cursive",
255
- "Ceviche One", "Changa One", "Chango", "Chau Philomene One", "Chelsea Market", "Chenla", "Cherry Cream Soda",
256
- "Chewy", "Chicle", "Chivo", "Coda", "Coda Caption", "Codystar", "Comfortaa", "Coming Soon", "Concert One",
257
- "Condiment", "Content", "Contrail One", "Convergence", "Cookie", "Copse", "Corben", "Cousine", "Coustard",
258
- "Covered By Your Grace", "Crafty Girls", "Creepster", "Crete Round", "Crimson Text", "Crushed", "Cuprum", "Cutive",
259
- "Damion", "Dancing Script", "Dangrek", "Dawning of a New Day", "Days One", "Delius", "Delius Swash Caps",
260
- "Delius Unicase", "Della Respira", "Devonshire", "Didact Gothic", "Diplomata", "Diplomata SC", "Doppio One",
261
- "Dorsa", "Dosis", "Dr Sugiyama", "Droid Sans", "Droid Sans Mono", "Droid Serif", "Duru Sans", "Dynalight",
262
- "EB Garamond", "Eater", "Economica", "Electrolize", "Emblema One", "Emilys Candy", "Engagement", "Enriqueta",
263
- "Erica One", "Esteban", "Euphoria Script", "Ewert", "Exo", "Expletus Sans", "Fanwood Text", "Fascinate", "Fascinate Inline",
264
- "Federant", "Federo", "Felipa", "Fjord One", "Flamenco", "Flavors", "Fondamento", "Fontdiner Swanky", "Forum",
265
- "Francois One", "Fredericka the Great", "Fredoka One", "Freehand", "Fresca", "Frijole", "Fugaz One", "GFS Didot",
266
- "GFS Neohellenic", "Galdeano", "Gentium Basic", "Gentium Book Basic", "Geo", "Geostar", "Geostar Fill", "Germania One",
267
- "Give You Glory", "Glass Antiqua", "Glegoo", "Gloria Hallelujah", "Goblin One", "Gochi Hand", "Gorditas",
268
- "Goudy Bookletter 1911", "Graduate", "Gravitas One", "Great Vibes", "Gruppo", "Gudea", "Habibi", "Hammersmith One",
269
- "Handlee", "Hanuman", "Happy Monkey", "Henny Penny", "Herr Von Muellerhoff", "Holtwood One SC", "Homemade Apple",
270
- "Homenaje", "IM Fell DW Pica", "IM Fell DW Pica SC", "IM Fell Double Pica", "IM Fell Double Pica SC",
271
- "IM Fell English", "IM Fell English SC", "IM Fell French Canon", "IM Fell French Canon SC", "IM Fell Great Primer",
272
- "IM Fell Great Primer SC", "Iceberg", "Iceland", "Imprima", "Inconsolata", "Inder", "Indie Flower", "Inika",
273
- "Irish Grover", "Istok Web", "Italiana", "Italianno", "Jim Nightshade", "Jockey One", "Jolly Lodger", "Josefin Sans",
274
- "Josefin Slab", "Judson", "Julee", "Junge", "Jura", "Just Another Hand", "Just Me Again Down Here", "Kameron",
275
- "Karla", "Kaushan Script", "Kelly Slab", "Kenia", "Khmer", "Knewave", "Kotta One", "Koulen", "Kranky", "Kreon",
276
- "Kristi", "Krona One", "La Belle Aurore", "Lancelot", "Lato", "League Script", "Leckerli One", "Ledger", "Lekton",
277
- "Lemon", "Lilita One", "Limelight", "Linden Hill", "Lobster", "Lobster Two", "Londrina Outline", "Londrina Shadow",
278
- "Londrina Sketch", "Londrina Solid", "Lora", "Love Ya Like A Sister", "Loved by the King", "Lovers Quarrel",
279
- "Luckiest Guy", "Lusitana", "Lustria", "Macondo", "Macondo Swash Caps", "Magra", "Maiden Orange", "Mako", "Marck Script",
280
- "Marko One", "Marmelad", "Marvel", "Mate", "Mate SC", "Maven Pro", "Meddon", "MedievalSharp", "Medula One", "Merriweather",
281
- "Metal", "Metamorphous", "Michroma", "Miltonian", "Miltonian Tattoo", "Miniver", "Miss Fajardose", "Modern Antiqua",
282
- "Molengo", "Monofett", "Monoton", "Monsieur La Doulaise", "Montaga", "Montez", "Montserrat", "Moul", "Moulpali",
283
- "Mountains of Christmas", "Mr Bedfort", "Mr Dafoe", "Mr De Haviland", "Mrs Saint Delafield", "Mrs Sheppards",
284
- "Muli", "Mystery Quest", "Neucha", "Neuton", "News Cycle", "Niconne", "Nixie One", "Nobile", "Nokora", "Norican",
285
- "Nosifer", "Nothing You Could Do", "Noticia Text", "Nova Cut", "Nova Flat", "Nova Mono", "Nova Oval", "Nova Round",
286
- "Nova Script", "Nova Slim", "Nova Square", "Numans", "Nunito", "Odor Mean Chey", "Old Standard TT", "Oldenburg",
287
- "Oleo Script", "Open Sans", "Open Sans Condensed", "Orbitron", "Original Surfer", "Oswald", "Over the Rainbow",
288
- "Overlock", "Overlock SC", "Ovo", "Oxygen", "PT Mono", "PT Sans", "PT Sans Caption", "PT Sans Narrow", "PT Serif",
289
- "PT Serif Caption", "Pacifico", "Parisienne", "Passero One", "Passion One", "Patrick Hand", "Patua One", "Paytone One",
290
- "Permanent Marker", "Petrona", "Philosopher", "Piedra", "Pinyon Script", "Plaster", "Play", "Playball", "Playfair Display",
291
- "Podkova", "Poiret One", "Poller One", "Poly", "Pompiere", "Pontano Sans", "Port Lligat Sans", "Port Lligat Slab",
292
- "Prata", "Preahvihear", "Press Start 2P", "Princess Sofia", "Prociono", "Prosto One", "Puritan", "Quantico",
293
- "Quattrocento", "Quattrocento Sans", "Questrial", "Quicksand", "Qwigley", "Radley", "Raleway", "Rammetto One",
294
- "Rancho", "Rationale", "Redressed", "Reenie Beanie", "Revalia", "Ribeye", "Ribeye Marrow", "Righteous", "Rochester",
295
- "Rock Salt", "Rokkitt", "Ropa Sans", "Rosario", "Rosarivo", "Rouge Script", "Ruda", "Ruge Boogie", "Ruluko",
296
- "Ruslan Display", "Russo One", "Ruthie", "Sail", "Salsa", "Sancreek", "Sansita One", "Sarina", "Satisfy", "Schoolbell",
297
- "Seaweed Script", "Sevillana", "Shadows Into Light", "Shadows Into Light Two", "Shanti", "Share", "Shojumaru",
298
- "Short Stack", "Siemreap", "Sigmar One", "Signika", "Signika Negative", "Simonetta", "Sirin Stencil", "Six Caps",
299
- "Slackey", "Smokum", "Smythe", "Sniglet", "Snippet", "Sofia", "Sonsie One", "Sorts Mill Goudy", "Special Elite",
300
- "Spicy Rice", "Spinnaker", "Spirax", "Squada One", "Stardos Stencil", "Stint Ultra Condensed", "Stint Ultra Expanded",
301
- "Stoke", "Sue Ellen Francisco", "Sunshiney", "Supermercado One", "Suwannaphum", "Swanky and Moo Moo", "Syncopate",
302
- "Tangerine", "Taprom", "Telex", "Tenor Sans", "The Girl Next Door", "Tienne", "Tinos", "Titan One", "Trade Winds",
303
- "Trocchi", "Trochut", "Trykker", "Tulpen One", "Ubuntu", "Ubuntu Condensed", "Ubuntu Mono", "Ultra", "Uncial Antiqua",
304
- "UnifrakturCook", "UnifrakturMaguntia", "Unkempt", "Unlock", "Unna", "VT323", "Varela", "Varela Round", "Vast Shadow",
305
- "Vibur", "Vidaloka", "Viga", "Voces", "Volkhov", "Vollkorn", "Voltaire", "Waiting for the Sunrise", "Wallpoet",
306
- "Walter Turncoat", "Wellfleet", "Wire One", "Yanone Kaffeesatz", "Yellowtail", "Yeseva One", "Yesteryear", "Zeyada"
307
- );
308
- }
309
- }
310
- ?>
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Class to adapt field before display
4
+ * return ONLY htmlParams property
5
+ * @see field
6
+ */
7
+ class fieldAdapterCfs {
8
+ const DB = 'dbCfs';
9
+ const HTML = 'htmlCfs';
10
+ const STR = 'str';
11
+ static public $userfieldDest = array('registration', 'shipping', 'billing');
12
+ static public $countries = array();
13
+ static public $states = array();
14
+ /**
15
+ * Executes field Adaption process
16
+ * @param object type field or value $fieldOrValue if DB adaption - this must be a value of field, elase if html - field object
17
+ */
18
+ static public function _($fieldOrValue, $method, $type) {
19
+ if(method_exists('fieldAdapterCfs', $method)) {
20
+ switch($type) {
21
+ case self::DB:
22
+ return self::$method($fieldOrValue);
23
+ break;
24
+ case self::HTML:
25
+ self::$method($fieldOrValue);
26
+ break;
27
+ case self::STR:
28
+ return self::$method($fieldOrValue);
29
+ break;
30
+ }
31
+ }
32
+ return $fieldOrValue;
33
+ }
34
+ static public function userFieldDestHtml($field) {
35
+ $field->htmlParams['optionsCfs'] = array();
36
+ if(!is_array($field->value)) {
37
+ if(empty($field->value))
38
+ $field->value = array();
39
+ else
40
+ $field->value = json_decode($field->value);
41
+ }
42
+ foreach(self::$userfieldDest as $d) {
43
+ $field->htmlParams['optionsCfs'][] = array(
44
+ 'id' => $d,
45
+ 'text' => $d,
46
+ 'checked' => in_array($d, $field->value)
47
+ );
48
+ }
49
+ }
50
+ static public function userFieldDestToDB($value) {
51
+ return utilsCfs::jsonEncode($value);
52
+ }
53
+ static public function userFieldDestFromDB($value) {
54
+ return utilsCfs::jsonDecode($value);
55
+ }
56
+ static public function taxDataHtml($field) {
57
+ $listOfDest = array();
58
+ if(!is_array($field->value)) {
59
+ if(empty($field->value))
60
+ $field->value = array();
61
+ else
62
+ $field->value = (array)json_decode($field->value, true);
63
+ }
64
+ foreach(self::$userfieldDest as $d) {
65
+ $listOfDest[] = array(
66
+ 'id' => $d,
67
+ 'text' => $d,
68
+ 'checked' => (is_array($field->value['dest']) && in_array($d, $field->value['dest']))
69
+ );
70
+ }
71
+ $categories = frameCfs::_()->getModule('products')->getCategories();
72
+ $brands = frameCfs::_()->getModule('products')->getBrands();
73
+ $cOptions = array();
74
+ $bOptions = array();
75
+ if(!empty($categories)) {
76
+ if(!is_array($field->value['categories']))
77
+ $field->value['categories'] = array();
78
+ foreach($categories as $c) {
79
+ $cOptions[] = array('id' => $c->term_taxonomy_id,
80
+ 'text' => $c->cat_name,
81
+ 'checked' => in_array($c->term_taxonomy_id, $field->value['categories']));
82
+ }
83
+ }
84
+ if(!empty($brands)) {
85
+ if(!is_array($field->value['brands']))
86
+ $field->value['brands'] = array();
87
+ foreach($brands as $b) {
88
+ $bOptions[] = array('id' => $b->term_taxonomy_id,
89
+ 'text' => $b->cat_name,
90
+ 'checked' => in_array($b->term_taxonomy_id, $field->value['brands']));
91
+ }
92
+ }
93
+ return '<div>'. __('Apply To', CFS_LANG_CODE). '
94
+ <div id="tax_address">
95
+ <b>'. __('Address', CFS_LANG_CODE). '</b><br />
96
+ '. __('Destination', CFS_LANG_CODE). ':'. htmlCfs::checkboxlist('params[dest]', array('optionsCfs' => $listOfDest)). '<br />
97
+ '. __('Country', CFS_LANG_CODE). ':'. htmlCfs::countryList('params[country]', array('notSelected' => true, 'value' => $field->value['country'])). '<br />
98
+ </div>
99
+ <div id="tax_category">
100
+ <b>'. __('Categories', CFS_LANG_CODE). '</b><br />
101
+ '. (empty($cOptions) ? __('You have no categories', CFS_LANG_CODE) : htmlCfs::checkboxlist('params[categories][]', array('optionsCfs' => $cOptions))). '<br />
102
+ <b>'. __('Brands', CFS_LANG_CODE). '</b><br />
103
+ '. (empty($bOptions) ? __('You have no brands', CFS_LANG_CODE) : htmlCfs::checkboxlist('params[brands][]', array('optionsCfs' => $bOptions))). '<br />
104
+ </div>
105
+ <div>'. __('Tax Rate', CFS_LANG_CODE).': '. htmlCfs::text('params[rate]', array('value' => $field->value['rate'])).'</div>
106
+ <div>'. __('Absolute', CFS_LANG_CODE).': '. htmlCfs::checkbox('params[absolute]', array('checked' => $field->value['absolute'])).'</div>
107
+ </div>';
108
+ }
109
+ static public function displayCountry($cid, $key = 'name') {
110
+ if($key == 'name') {
111
+ $countries = self::getCountries();
112
+ return $countries[$cid];
113
+ } else {
114
+ if(empty(self::$countries))
115
+ self::$countries = self::getCachedCountries();
116
+ foreach(self::$countries as $c) {
117
+ if($c['id'] == $cid)
118
+ return $c[ $key ];
119
+ }
120
+ }
121
+ return false;
122
+ }
123
+ static public function displayState($sid, $key = 'name') {
124
+ $states = self::getStates();
125
+ return empty($states[$sid]) ? $sid : $states[$sid][$key];
126
+ }
127
+ static public function getCountries($notSelected = false, $listBy = 'id') {
128
+ $options = array();
129
+ if(empty(self::$countries))
130
+ self::$countries = self::getCachedCountries();
131
+ if($notSelected) {
132
+ $options[0] = is_bool($notSelected) ? __('Not selected', CFS_LANG_CODE) : __($notSelected);
133
+ }
134
+ foreach(self::$countries as $c) {
135
+ $options[$c[ $listBy ]] = $c['name'];
136
+ }
137
+ return $options;
138
+ }
139
+ static public function getStates($notSelected = false) {
140
+ static $options = array();
141
+ if(empty($options[ $notSelected ])) {
142
+ $options[ $notSelected ] = array();
143
+ if(empty(self::$states))
144
+ self::$states = self::getCachedStates();
145
+ if($notSelected) {
146
+ $notSelectedLabel = is_bool($notSelected) ? 'Not selected' : $notSelected;
147
+ $options[ $notSelected ][0] = array('name' => __( $notSelectedLabel ), 'country_id' => NULL);
148
+ }
149
+ foreach(self::$states as $s) $options[ $notSelected ][$s['id']] = $s;
150
+ }
151
+ return $options[ $notSelected ];
152
+ }
153
+ /**
154
+ * Function to get extra field options
155
+ *
156
+ * @param object $field
157
+ * @return string
158
+ */
159
+ static public function getExtraFieldOptions($field_id) {
160
+ $output = '';
161
+ if ($field_id == 0) return '';
162
+ $options = frameCfs::_()->getModule('optionsCfs')->getHelper()->getOptions($field_id);
163
+ if (!empty($options)) {
164
+ foreach ($options as $key=>$value) {
165
+ $output .= '<p>'.$value.'<span class="delete_option" rel="'.$key.'"></span></p>';
166
+ }
167
+ }
168
+ return $output;
169
+ }
170
+ /**
171
+ * Function to get field params
172
+ *
173
+ * @param object $params
174
+ */
175
+ static public function getFieldAttributes($params){
176
+ $output = '';
177
+ if (!empty($params->attr)) {
178
+ foreach ($params->attr as $key=>$value) {
179
+ $output .= __($key).':<br />';
180
+ $output .= htmlCfs::text('params[attr]['.$key.']',array('value'=>$value)).'<br />';
181
+ }
182
+ } else {
183
+ $output .= __('class', CFS_LANG_CODE).':<br />';
184
+ $output .= htmlCfs::text('params[attr][class]',array('value'=>'')).'<br />';
185
+ $output .= __('id', CFS_LANG_CODE).':<br />';
186
+ $output .= htmlCfs::text('params[attr][id]',array('value'=>'')).'<br />';
187
+ }
188
+ return $output;
189
+ }
190
+ /**
191
+ * Generating the list of categories for product extra fields
192
+ *
193
+ * @param object $field
194
+ */
195
+ static function productFieldCategories($field){
196
+ if(!empty($field->htmlParams['optionsCfs']))
197
+ return;
198
+ /*$field->htmlParams['attrs'] = 'id="select_product_field_cat" rel="0"';
199
+ $field->htmlParams['optionsCfs'] = array();
200
+ $categories = frameCfs::_()->getModule('products')->getCategories();
201
+ if(!empty($categories)) {
202
+ if(!is_array($field->value['categories']))
203
+ $field->value['categories'] = array();
204
+ $field->htmlParams['optionsCfs'][0] = in_array(0,$field->value['categories'])?__('Deselect All'):__('Select All', CFS_LANG_CODE);
205
+ foreach($categories as $c) {
206
+ $field->htmlParams['optionsCfs'][$c->term_taxonomy_id] = $c->cat_name;
207
+ }
208
+ }*/
209
+ }
210
+ static public function intToDB($val) {
211
+ return intval($val);
212
+ }
213
+ static public function floatToDB($val) {
214
+ return floatval($val);
215
+ }
216
+ /**
217
+ * Save this in static var - to futher usage
218
+ * @return array with countries
219
+ */
220
+ static public function getCachedCountries($clearCache = false) {
221
+ if(empty(self::$countries) || $clearCache)
222
+ global $wpdb;
223
+ $data = $wpdb->get_results(
224
+ "SELECT id, name, iso_code_2, iso_code_3 FROM {$wpdb->prefix}cfs_countries", ARRAY_A
225
+ );
226
+ //frameCfs::_()->getTable('countries')->getAll('id, name, iso_code_2, iso_code_3');
227
+ self::$countries = $data;
228
+ return self::$countries;
229
+ }
230
+ /**
231
+ * Save this in static var - to futher usage
232
+ * @return array with states
233
+ */
234
+ static public function getCachedStates($clearCache = false) {
235
+ if(empty(self::$states) || $clearCache)
236
+ self::$states = frameCfs::_()->getTable('states')
237
+ ->leftJoin( frameCfs::_()->getTable('countries'), 'country_id' )
238
+ ->getAll('toe_states.id,
239
+ toe_states.name,
240
+ toe_states.code,
241
+ toe_states.country_id,
242
+ toe_cry.name AS c_name,
243
+ toe_cry.iso_code_2 AS c_iso_code_2,
244
+ toe_cry.iso_code_3 AS c_iso_code_3');
245
+ return self::$states;
246
+ }
247
+ static public function getFontsList() {
248
+ return array("Abel", "Abril Fatface", "Aclonica", "Acme", "Actor", "Adamina", "Advent Pro",
249
+ "Aguafina Script", "Aladin", "Aldrich", "Alegreya", "Alegreya SC", "Alex Brush", "Alfa Slab One", "Alice",
250
+ "Alike", "Alike Angular", "Allan", "Allerta", "Allerta Stencil", "Allura", "Almendra", "Almendra SC", "Amaranth",
251
+ "Amatic SC", "Amethysta", "Andada", "Andika", "Angkor", "Annie Use Your Telescope", "Anonymous Pro", "Antic",
252
+ "Antic Didone", "Antic Slab", "Anton", "Arapey", "Arbutus", "Architects Daughter", "Arimo", "Arizonia", "Armata",
253
+ "Artifika", "Arvo", "Asap", "Asset", "Astloch", "Asul", "Atomic Age", "Aubrey", "Audiowide", "Average",
254
+ "Averia Gruesa Libre", "Averia Libre", "Averia Sans Libre", "Averia Serif Libre", "Bad Script", "Balthazar",
255
+ "Bangers", "Basic", "Battambang", "Baumans", "Bayon", "Belgrano", "Belleza", "Bentham", "Berkshire Swash",
256
+ "Bevan", "Bigshot One", "Bilbo", "Bilbo Swash Caps", "Bitter", "Black Ops One", "Bokor", "Bonbon", "Boogaloo",
257
+ "Bowlby One", "Bowlby One SC", "Brawler", "Bree Serif", "Bubblegum Sans", "Buda", "Buenard", "Butcherman",
258
+ "Butterfly Kids", "Cabin", "Cabin Condensed", "Cabin Sketch", "Caesar Dressing", "Cagliostro", "Calligraffitti",
259
+ "Cambo", "Candal", "Cantarell", "Cantata One", "Cardo", "Carme", "Carter One", "Caudex", "Cedarville Cursive",
260
+ "Ceviche One", "Changa One", "Chango", "Chau Philomene One", "Chelsea Market", "Chenla", "Cherry Cream Soda",
261
+ "Chewy", "Chicle", "Chivo", "Coda", "Coda Caption", "Codystar", "Comfortaa", "Coming Soon", "Concert One",
262
+ "Condiment", "Content", "Contrail One", "Convergence", "Cookie", "Copse", "Corben", "Cousine", "Coustard",
263
+ "Covered By Your Grace", "Crafty Girls", "Creepster", "Crete Round", "Crimson Text", "Crushed", "Cuprum", "Cutive",
264
+ "Damion", "Dancing Script", "Dangrek", "Dawning of a New Day", "Days One", "Delius", "Delius Swash Caps",
265
+ "Delius Unicase", "Della Respira", "Devonshire", "Didact Gothic", "Diplomata", "Diplomata SC", "Doppio One",
266
+ "Dorsa", "Dosis", "Dr Sugiyama", "Droid Sans", "Droid Sans Mono", "Droid Serif", "Duru Sans", "Dynalight",
267
+ "EB Garamond", "Eater", "Economica", "Electrolize", "Emblema One", "Emilys Candy", "Engagement", "Enriqueta",
268
+ "Erica One", "Esteban", "Euphoria Script", "Ewert", "Exo", "Expletus Sans", "Fanwood Text", "Fascinate", "Fascinate Inline",
269
+ "Federant", "Federo", "Felipa", "Fjord One", "Flamenco", "Flavors", "Fondamento", "Fontdiner Swanky", "Forum",
270
+ "Francois One", "Fredericka the Great", "Fredoka One", "Freehand", "Fresca", "Frijole", "Fugaz One", "GFS Didot",
271
+ "GFS Neohellenic", "Galdeano", "Gentium Basic", "Gentium Book Basic", "Geo", "Geostar", "Geostar Fill", "Germania One",
272
+ "Give You Glory", "Glass Antiqua", "Glegoo", "Gloria Hallelujah", "Goblin One", "Gochi Hand", "Gorditas",
273
+ "Goudy Bookletter 1911", "Graduate", "Gravitas One", "Great Vibes", "Gruppo", "Gudea", "Habibi", "Hammersmith One",
274
+ "Handlee", "Hanuman", "Happy Monkey", "Henny Penny", "Herr Von Muellerhoff", "Holtwood One SC", "Homemade Apple",
275
+ "Homenaje", "IM Fell DW Pica", "IM Fell DW Pica SC", "IM Fell Double Pica", "IM Fell Double Pica SC",
276
+ "IM Fell English", "IM Fell English SC", "IM Fell French Canon", "IM Fell French Canon SC", "IM Fell Great Primer",
277
+ "IM Fell Great Primer SC", "Iceberg", "Iceland", "Imprima", "Inconsolata", "Inder", "Indie Flower", "Inika",
278
+ "Irish Grover", "Istok Web", "Italiana", "Italianno", "Jim Nightshade", "Jockey One", "Jolly Lodger", "Josefin Sans",
279
+ "Josefin Slab", "Judson", "Julee", "Junge", "Jura", "Just Another Hand", "Just Me Again Down Here", "Kameron",
280
+ "Karla", "Kaushan Script", "Kelly Slab", "Kenia", "Khmer", "Knewave", "Kotta One", "Koulen", "Kranky", "Kreon",
281
+ "Kristi", "Krona One", "La Belle Aurore", "Lancelot", "Lato", "League Script", "Leckerli One", "Ledger", "Lekton",
282
+ "Lemon", "Lilita One", "Limelight", "Linden Hill", "Lobster", "Lobster Two", "Londrina Outline", "Londrina Shadow",
283
+ "Londrina Sketch", "Londrina Solid", "Lora", "Love Ya Like A Sister", "Loved by the King", "Lovers Quarrel",
284
+ "Luckiest Guy", "Lusitana", "Lustria", "Macondo", "Macondo Swash Caps", "Magra", "Maiden Orange", "Mako", "Marck Script",
285
+ "Marko One", "Marmelad", "Marvel", "Mate", "Mate SC", "Maven Pro", "Meddon", "MedievalSharp", "Medula One", "Merriweather",
286
+ "Metal", "Metamorphous", "Michroma", "Miltonian", "Miltonian Tattoo", "Miniver", "Miss Fajardose", "Modern Antiqua",
287
+ "Molengo", "Monofett", "Monoton", "Monsieur La Doulaise", "Montaga", "Montez", "Montserrat", "Moul", "Moulpali",
288
+ "Mountains of Christmas", "Mr Bedfort", "Mr Dafoe", "Mr De Haviland", "Mrs Saint Delafield", "Mrs Sheppards",
289
+ "Muli", "Mystery Quest", "Neucha", "Neuton", "News Cycle", "Niconne", "Nixie One", "Nobile", "Nokora", "Norican",
290
+ "Nosifer", "Nothing You Could Do", "Noticia Text", "Nova Cut", "Nova Flat", "Nova Mono", "Nova Oval", "Nova Round",
291
+ "Nova Script", "Nova Slim", "Nova Square", "Numans", "Nunito", "Odor Mean Chey", "Old Standard TT", "Oldenburg",
292
+ "Oleo Script", "Open Sans", "Open Sans Condensed", "Orbitron", "Original Surfer", "Oswald", "Over the Rainbow",
293
+ "Overlock", "Overlock SC", "Ovo", "Oxygen", "PT Mono", "PT Sans", "PT Sans Caption", "PT Sans Narrow", "PT Serif",
294
+ "PT Serif Caption", "Pacifico", "Parisienne", "Passero One", "Passion One", "Patrick Hand", "Patua One", "Paytone One",
295
+ "Permanent Marker", "Petrona", "Philosopher", "Piedra", "Pinyon Script", "Plaster", "Play", "Playball", "Playfair Display",
296
+ "Podkova", "Poiret One", "Poller One", "Poly", "Pompiere", "Pontano Sans", "Port Lligat Sans", "Port Lligat Slab",
297
+ "Prata", "Preahvihear", "Press Start 2P", "Princess Sofia", "Prociono", "Prosto One", "Puritan", "Quantico",
298
+ "Quattrocento", "Quattrocento Sans", "Questrial", "Quicksand", "Qwigley", "Radley", "Raleway", "Rammetto One",
299
+ "Rancho", "Rationale", "Redressed", "Reenie Beanie", "Revalia", "Ribeye", "Ribeye Marrow", "Righteous", "Rochester",
300
+ "Rock Salt", "Rokkitt", "Ropa Sans", "Rosario", "Rosarivo", "Rouge Script", "Ruda", "Ruge Boogie", "Ruluko",
301
+ "Ruslan Display", "Russo One", "Ruthie", "Sail", "Salsa", "Sancreek", "Sansita One", "Sarina", "Satisfy", "Schoolbell",
302
+ "Seaweed Script", "Sevillana", "Shadows Into Light", "Shadows Into Light Two", "Shanti", "Share", "Shojumaru",
303
+ "Short Stack", "Siemreap", "Sigmar One", "Signika", "Signika Negative", "Simonetta", "Sirin Stencil", "Six Caps",
304
+ "Slackey", "Smokum", "Smythe", "Sniglet", "Snippet", "Sofia", "Sonsie One", "Sorts Mill Goudy", "Special Elite",
305
+ "Spicy Rice", "Spinnaker", "Spirax", "Squada One", "Stardos Stencil", "Stint Ultra Condensed", "Stint Ultra Expanded",
306
+ "Stoke", "Sue Ellen Francisco", "Sunshiney", "Supermercado One", "Suwannaphum", "Swanky and Moo Moo", "Syncopate",
307
+ "Tangerine", "Taprom", "Telex", "Tenor Sans", "The Girl Next Door", "Tienne", "Tinos", "Titan One", "Trade Winds",
308
+ "Trocchi", "Trochut", "Trykker", "Tulpen One", "Ubuntu", "Ubuntu Condensed", "Ubuntu Mono", "Ultra", "Uncial Antiqua",
309
+ "UnifrakturCook", "UnifrakturMaguntia", "Unkempt", "Unlock", "Unna", "VT323", "Varela", "Varela Round", "Vast Shadow",
310
+ "Vibur", "Vidaloka", "Viga", "Voces", "Volkhov", "Vollkorn", "Voltaire", "Waiting for the Sunrise", "Wallpoet",
311
+ "Walter Turncoat", "Wellfleet", "Wire One", "Yanone Kaffeesatz", "Yellowtail", "Yeseva One", "Yesteryear", "Zeyada"
312
+ );
313
+ }
314
+ }
315
+ ?>
classes/filegenerator.php CHANGED
@@ -1,52 +1,52 @@
1
- <?php
2
- /**
3
- * Class to generate fiels and output them in attachment by http (https) protocol
4
- */
5
- class filegeneratorCfs {
6
- static protected $_instances = array();
7
- protected $_filename = '';
8
- protected $_data = '';
9
- protected $_type = '';
10
- public function __construct($filename, $data, $type) {
11
- $this->_filename = $filename;
12
- $this->_data = $data;
13
- $this->_type = strtolower($type);
14
- }
15
- static public function getInstance($filename, $data, $type) {
16
- $name = md5($filename. $data. $type);
17
- if(!isset(self::$_instances[$name])) {
18
- self::$_instances[$name] = new filegeneratorCfs($filename, $data, $type);
19
- }
20
- return self::$_instances[$name];
21
- }
22
- static public function _($filename, $data, $type) {
23
- return self::getInstance($filename, $data, $type);
24
- }
25
- public function generate() {
26
- switch($this->_type) {
27
- case 'txt':
28
- $this->_getTxtHeader();
29
- break;
30
- case 'csv':
31
- $this->_getCsvHeader();
32
- break;
33
- default:
34
- $this->_getDefaultHeader();
35
- break;
36
- }
37
- echo $this->_data;
38
- exit();
39
- }
40
- protected function _getTxtHeader() {
41
- header('Content-Disposition: attachment; filename="'. $this->_filename. '.txt"');
42
- header('Content-type: text/plain');
43
- }
44
- protected function _getCsvHeader() {
45
- header('Content-Disposition: attachment; filename="'. $this->_filename. '.csv"');
46
- header('Content-type: application/csv');
47
- }
48
- protected function _getDefaultHeader() {
49
- header('Content-Disposition: attachment; filename="'. $this->_filename. '"');
50
- header('Content-type: '. $this->_type);
51
- }
52
- }
1
+ <?php
2
+ /**
3
+ * Class to generate fiels and output them in attachment by http (https) protocol
4
+ */
5
+ class filegeneratorCfs {
6
+ static protected $_instances = array();
7
+ protected $_filename = '';
8
+ protected $_data = '';
9
+ protected $_type = '';
10
+ public function __construct($filename, $data, $type) {
11
+ $this->_filename = $filename;
12
+ $this->_data = $data;
13
+ $this->_type = strtolower($type);
14
+ }
15
+ static public function getInstance($filename, $data, $type) {
16
+ $name = md5($filename. $data. $type);
17
+ if(!isset(self::$_instances[$name])) {
18
+ self::$_instances[$name] = new filegeneratorCfs($filename, $data, $type);
19
+ }
20
+ return self::$_instances[$name];
21
+ }
22
+ static public function _($filename, $data, $type) {
23
+ return self::getInstance($filename, $data, $type);
24
+ }
25
+ public function generate() {
26
+ switch($this->_type) {
27
+ case 'txt':
28
+ $this->_getTxtHeader();
29
+ break;
30
+ case 'csv':
31
+ $this->_getCsvHeader();
32
+ break;
33
+ default:
34
+ $this->_getDefaultHeader();
35
+ break;
36
+ }
37
+ echo $this->_data;
38
+ exit();
39
+ }
40
+ protected function _getTxtHeader() {
41
+ header('Content-Disposition: attachment; filename="'. $this->_filename. '.txt"');
42
+ header('Content-type: text/plain');
43
+ }
44
+ protected function _getCsvHeader() {
45
+ header('Content-Disposition: attachment; filename="'. $this->_filename. '.csv"');
46
+ header('Content-type: application/csv');
47
+ }
48
+ protected function _getDefaultHeader() {
49
+ header('Content-Disposition: attachment; filename="'. $this->_filename. '"');
50
+ header('Content-type: '. $this->_type);
51
+ }
52
+ }
classes/fileuploader.php CHANGED
@@ -1,142 +1,147 @@
1
- <?php
2
- class fileuploaderCfs {
3
- private $_error = '';
4
- private $_dest = '';
5
- private $_file = '';
6
- /**
7
- * Result filename, if empty - it will be randon generated string
8
- */
9
- private $_destFilename = '';
10
- /**
11
- * Return last error
12
- * @return string error message
13
- */
14
- public function getError() {
15
- return $this->_error;
16
- }
17
- /**
18
- * Validate before upload
19
- * @param string $inputname name of the input HTML document (key in $_FILES array)
20
- * @param string $destSubDir destination for uploaded file, for wp this should be directory in wp-content/uploads/ dir
21
- * @param string $destFilename name of a file that be uploaded
22
- */
23
- public function validate($inputname, $destSubDir, $destFilename = '') {
24
- $file = is_array($inputname) ? $inputname : $_FILES[$inputname];
25
- $res = false;
26
- if(!empty($file['error'])) {
27
- switch($file['error']) {
28
- case '1':
29
- $this->_error = __('The uploaded file exceeds the upload_max_filesize directive in php.ini', CFS_LANG_CODE);
30
- break;
31
- case '2':
32
- $this->_error = __('The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form', CFS_LANG_CODE);
33
- break;
34
- case '3':
35
- $this->_error = __('The uploaded file was only partially uploaded', CFS_LANG_CODE);
36
- break;
37
- case '4':
38
- $this->_error = __('No file was uploaded.', CFS_LANG_CODE);
39
- break;
40
- case '6':
41
- $this->_error = __('Missing a temporary folder', CFS_LANG_CODE);
42
- break;
43
- case '7':
44
- $this->_error = __('Failed to write file to disk', CFS_LANG_CODE);
45
- break;
46
- case '8':
47
- $this->_error = __('File upload stopped by extension', CFS_LANG_CODE);
48
- break;
49
- case '999':
50
- default:
51
- $this->_error = __('No error code avaiable', CFS_LANG_CODE);
52
- }
53
- } elseif(empty($file['tmp_name']) || $file['tmp_name'] == 'none') {
54
- $this->_error = __('No file was uploaded..', CFS_LANG_CODE);
55
- } else {
56
- $res = true;
57
- }
58
- if($res) {
59
- //$this->_fileSize = $file['size'];
60
- $this->_dest = $destSubDir;
61
- $this->_file = $file;
62
- $this->_destFilename = $destFilename;
63
- }
64
- return $res;
65
- }
66
- /**
67
- * Upload valid file
68
- */
69
- public function upload($d = array()) {
70
- $d['ignore_db_insert'] = isset($d['ignore_db_insert']) ? $d['ignore_db_insert'] : false;
71
- $res = false;
72
- add_filter('upload_dir', array($this,'changeUploadDir'));
73
- add_filter('wp_handle_upload_prefilter', array($this,'changeFileName'));
74
- // File name will be changed during upload process - we will bring it back after upload
75
- $fileName = $this->_file['name'];
76
- $upload = wp_handle_upload($this->_file, array('test_form' => FALSE));
77
- $this->_file['name'] = $fileName;
78
- if (!empty($upload['type'])) {
79
- if(!isset($d['ignore_db_insert']) || !$d['ignore_db_insert']) {
80
- $saveData = array(
81
- 'fid' => (isset($d['fid']) ? $d['fid'] : 0),
82
- 'field_name' => (isset($d['field_name']) ? $d['field_name'] : ''),
83
- 'name' => $this->_file['name'],
84
- 'dest_name' => $this->_destFilename,
85
- 'path' => str_replace(DS, '\\'. DS, $this->_dest),
86
- 'mime_type' => $upload['type'],
87
- 'size' => $this->_file['size'],
88
- 'hash' => md5(mt_rand(1, 9999999)),
89
- );
90
- $this->_file['id'] = frameCfs::_()->getTable('files')->insert($saveData);
91
- $this->_file['hash'] = $saveData['hash'];
92
- $this->_file['field_name'] = $saveData['field_name'];
93
- $this->_file['url'] = $upload['url'];
94
- }
95
- $res = true;
96
- } elseif($upload['error']) {
97
- $this->_error = $upload['error'];
98
- }
99
- remove_filter('upload_dir', array($this,'changeUploadDir'));
100
- remove_filter('wp_handle_upload_prefilter', array($this,'changeFileName'));
101
- return $res;
102
- }
103
- public function getFileInfo() {
104
- return $this->_file;
105
- }
106
- public function changeUploadDir($uploads) {
107
- $uploads['subdir'] = $this->_dest;
108
- if(empty($uploads['subdir'])) {
109
- $uploads['path'] = $uploads['basedir'];
110
- $uploads['url'] = $uploads['baseurl'];
111
- } else {
112
- $uploads['path'] = $uploads['basedir'] . DS. $uploads['subdir'];
113
- $uploads['url'] = $uploads['baseurl'] . '/'.$uploads['subdir'];
114
- }
115
- return $uploads;
116
- }
117
- public function changeFileName($file) {
118
- $ext = pathinfo($file['name'], PATHINFO_EXTENSION);
119
- if(empty($this->_destFilename)) {
120
- $this->_destFilename = $this->createFileName();
121
- }
122
- $this->_destFilename .= '.'. $ext;
123
- $file['name'] = $this->_destFilename;
124
- return $file;
125
- }
126
- private function createFileName() {
127
- return utilsCfs::getRandStr(). '-'. utilsCfs::getRandStr(). '-'. utilsCfs::getRandStr(). '-'. utilsCfs::getRandStr();
128
- }
129
- /**
130
- * Delete uploaded file
131
- * @param int|array $id ID of file in files table, or file row data from files table
132
- */
133
- public function delete($id) {
134
- $file = is_array($id) ? $id : frameCfs::_()->getTable('files')->get('*', array('id' => $id), '', 'row');
135
- if($file) {
136
- frameCfs::_()->getTable('files')->delete($file['id']);
137
- $uploadsDir = wp_upload_dir( null, false );
138
- @unlink( $uploadsDir['basedir']. (empty($file['path']) ? '' : DS. $file['path']). DS. $file['dest_name'] );
139
- }
140
- return false;
141
- }
142
- }
 
 
 
 
 
1
+ <?php
2
+ class fileuploaderCfs {
3
+ private $_error = '';
4
+ private $_dest = '';
5
+ private $_file = '';
6
+ /**
7
+ * Result filename, if empty - it will be randon generated string
8
+ */
9
+ private $_destFilename = '';
10
+ /**
11
+ * Return last error
12
+ * @return string error message
13
+ */
14
+ public function getError() {
15
+ return $this->_error;
16
+ }
17
+ /**
18
+ * Validate before upload
19
+ * @param string $inputname name of the input HTML document (key in $_FILES array)
20
+ * @param string $destSubDir destination for uploaded file, for wp this should be directory in wp-content/uploads/ dir
21
+ * @param string $destFilename name of a file that be uploaded
22
+ */
23
+ public function validate($inputname, $destSubDir, $destFilename = '') {
24
+ if (is_array($inputname) && !empty($inputname['name'])) {
25
+ $inputname['name'] = sanitize_file_name($inputname['name']);
26
+ } else {
27
+ return false;
28
+ }
29
+ $file = $inputname;
30
+ $res = false;
31
+ if(!empty($file['error'])) {
32
+ switch($file['error']) {
33
+ case '1':
34
+ $this->_error = __('The uploaded file exceeds the upload_max_filesize directive in php.ini', CFS_LANG_CODE);
35
+ break;
36
+ case '2':
37
+ $this->_error = __('The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form', CFS_LANG_CODE);
38
+ break;
39
+ case '3':
40
+ $this->_error = __('The uploaded file was only partially uploaded', CFS_LANG_CODE);
41
+ break;
42
+ case '4':
43
+ $this->_error = __('No file was uploaded.', CFS_LANG_CODE);
44
+ break;
45
+ case '6':
46
+ $this->_error = __('Missing a temporary folder', CFS_LANG_CODE);
47
+ break;
48
+ case '7':
49
+ $this->_error = __('Failed to write file to disk', CFS_LANG_CODE);
50
+ break;
51
+ case '8':
52
+ $this->_error = __('File upload stopped by extension', CFS_LANG_CODE);
53
+ break;
54
+ case '999':
55
+ default:
56
+ $this->_error = __('No error code avaiable', CFS_LANG_CODE);
57
+ }
58
+ } elseif(empty($file['tmp_name']) || $file['tmp_name'] == 'none') {
59
+ $this->_error = __('No file was uploaded..', CFS_LANG_CODE);
60
+ } else {
61
+ $res = true;
62
+ }
63
+ if($res) {
64
+ //$this->_fileSize = $file['size'];
65
+ $this->_dest = $destSubDir;
66
+ $this->_file = $file;
67
+ $this->_destFilename = $destFilename;
68
+ }
69
+ return $res;
70
+ }
71
+ /**
72
+ * Upload valid file
73
+ */
74
+ public function upload($d = array()) {
75
+ $d['ignore_db_insert'] = isset($d['ignore_db_insert']) ? $d['ignore_db_insert'] : false;
76
+ $res = false;
77
+ add_filter('upload_dir', array($this,'changeUploadDir'));
78
+ add_filter('wp_handle_upload_prefilter', array($this,'changeFileName'));
79
+ // File name will be changed during upload process - we will bring it back after upload
80
+ $fileName = $this->_file['name'];
81
+ $upload = wp_handle_upload($this->_file, array('test_form' => FALSE));
82
+ $this->_file['name'] = $fileName;
83
+ if (!empty($upload['type'])) {
84
+ if(!isset($d['ignore_db_insert']) || !$d['ignore_db_insert']) {
85
+ $saveData = array(
86
+ 'fid' => (isset($d['fid']) ? $d['fid'] : 0),
87
+ 'field_name' => (isset($d['field_name']) ? $d['field_name'] : ''),
88
+ 'name' => $this->_file['name'],
89
+ 'dest_name' => $this->_destFilename,
90
+ 'path' => str_replace(DS, '\\'. DS, $this->_dest),
91
+ 'mime_type' => $upload['type'],
92
+ 'size' => $this->_file['size'],
93
+ 'hash' => md5(mt_rand(1, 9999999)),
94
+ );
95
+ $this->_file['id'] = frameCfs::_()->getTable('files')->insert($saveData);
96
+ $this->_file['hash'] = $saveData['hash'];
97
+ $this->_file['field_name'] = $saveData['field_name'];
98
+ $this->_file['url'] = $upload['url'];
99
+ }
100
+ $res = true;
101
+ } elseif($upload['error']) {
102
+ $this->_error = $upload['error'];
103
+ }
104
+ remove_filter('upload_dir', array($this,'changeUploadDir'));
105
+ remove_filter('wp_handle_upload_prefilter', array($this,'changeFileName'));
106
+ return $res;
107
+ }
108
+ public function getFileInfo() {
109
+ return $this->_file;
110
+ }
111
+ public function changeUploadDir($uploads) {
112
+ $uploads['subdir'] = $this->_dest;
113
+ if(empty($uploads['subdir'])) {
114
+ $uploads['path'] = $uploads['basedir'];
115
+ $uploads['url'] = $uploads['baseurl'];
116
+ } else {
117
+ $uploads['path'] = $uploads['basedir'] . DS. $uploads['subdir'];
118
+ $uploads['url'] = $uploads['baseurl'] . '/'.$uploads['subdir'];
119
+ }
120
+ return $uploads;
121
+ }
122
+ public function changeFileName($file) {
123
+ $ext = pathinfo($file['name'], PATHINFO_EXTENSION);
124
+ if(empty($this->_destFilename)) {
125
+ $this->_destFilename = $this->createFileName();
126
+ }
127
+ $this->_destFilename .= '.'. $ext;
128
+ $file['name'] = $this->_destFilename;
129
+ return $file;
130
+ }
131
+ private function createFileName() {
132
+ return utilsCfs::getRandStr(). '-'. utilsCfs::getRandStr(). '-'. utilsCfs::getRandStr(). '-'. utilsCfs::getRandStr();
133
+ }
134
+ /**
135
+ * Delete uploaded file
136
+ * @param int|array $id ID of file in files table, or file row data from files table
137
+ */
138
+ public function delete($id) {
139
+ $file = is_array($id) ? $id : frameCfs::_()->getTable('files')->get('*', array('id' => $id), '', 'row');
140
+ if($file) {
141
+ frameCfs::_()->getTable('files')->delete($file['id']);
142
+ $uploadsDir = wp_upload_dir( null, false );
143
+ @unlink( $uploadsDir['basedir']. (empty($file['path']) ? '' : DS. $file['path']). DS. $file['dest_name'] );
144
+ }
145
+ return false;
146
+ }
147
+ }
classes/frame.php CHANGED
@@ -1,500 +1,509 @@
1
- <?php
2
- class frameCfs {
3
- private $_modules = array();
4
- private $_tables = array();
5
- private $_allModules = array();
6
- /**
7
- * bool Uses to know if we are on one of the plugin pages
8
- */
9
- private $_inPlugin = false;
10
- /**
11
- * Array to hold all scripts and add them in one time in addScripts method
12
- */
13
- private $_scripts = array();
14
- private $_scriptsInitialized = false;
15
- private $_styles = array();
16
- private $_stylesInitialized = false;
17
- private $_useFootAssets = false;
18
-
19
- private $_scriptsVars = array();
20
- private $_mod = '';
21
- private $_action = '';
22
- /**
23
- * Object with result of executing non-ajax module request
24
- */
25
- private $_res = null;
26
-
27
- public function __construct() {
28
- $this->_res = toeCreateObjCfs('response', array());
29
-
30
- }
31
- static public function getInstance() {
32
- static $instance;
33
- if(!$instance) {
34
- $instance = new frameCfs();
35
- }
36
- return $instance;
37
- }
38
- static public function _() {
39
- return self::getInstance();
40
- }
41
- public function parseRoute() {
42
- // Check plugin
43
- $pl = reqCfs::getVar('pl');
44
- if($pl == CFS_CODE) {
45
- $mod = reqCfs::getMode();
46
- if($mod)
47
- $this->_mod = $mod;
48
- $action = reqCfs::getVar('action');
49
- if($action)
50
- $this->_action = $action;
51
- }
52
- }
53
- public function setMod($mod) {
54
- $this->_mod = $mod;
55
- }
56
- public function getMod() {
57
- return $this->_mod;
58
- }
59
- public function setAction($action) {
60
- $this->_action = $action;
61
- }
62
- public function getAction() {
63
- return $this->_action;
64
- }
65
- protected function _extractModules() {
66
- $activeModules = $this->getTable('modules')
67
- ->innerJoin( $this->getTable('modules_type'), 'type_id' )
68
- ->orderBy('id ASC')
69
- ->get($this->getTable('modules')->alias(). '.*, '. $this->getTable('modules_type')->alias(). '.label as type_name');
70
- if($activeModules) {
71
- foreach($activeModules as $m) {
72
- $code = $m['code'];
73
- $moduleLocationDir = CFS_MODULES_DIR;
74
- if(!empty($m['ex_plug_dir'])) {
75
- $moduleLocationDir = utilsCfs::getExtModDir( $m['ex_plug_dir'] );
76
- }
77
- if(is_dir($moduleLocationDir. $code)) {
78
- $this->_allModules[$m['code']] = 1;
79
- if((bool)$m['active']) {
80
- importClassCfs($code. strFirstUp(CFS_CODE), $moduleLocationDir. $code. DS. 'mod.php');
81
- $moduleClass = toeGetClassNameCfs($code);
82
- if(class_exists($moduleClass)) {
83
- $this->_modules[$code] = new $moduleClass($m);
84
- if(is_dir($moduleLocationDir. $code. DS. 'tables')) {
85
- $this->_extractTables($moduleLocationDir. $code. DS. 'tables'. DS);
86
- }
87
- }
88
- }
89
- }
90
- }
91
- }
92
- //$operationTime = microtime(true) - $startTime;
93
- }
94
- protected function _initModules() {
95
- if(!empty($this->_modules)) {
96
- foreach($this->_modules as $mod) {
97
- $mod->init();
98
- }
99
- }
100
- }
101
- public function init() {
102
- //$startTime = microtime(true);
103
- reqCfs::init();
104
- $this->_extractTables();
105
- $this->_extractModules();
106
-
107
- $this->_initModules();
108
-
109
- dispatcherCfs::doAction('afterModulesInit');
110
-
111
- modInstallerCfs::checkActivationMessages();
112
-
113
- $this->_execModules();
114
-
115
- $addAssetsAction = $this->usePackAssets() && !is_admin() ? 'wp_footer' : 'init';
116
-
117
- add_action($addAssetsAction, array($this, 'addScripts'));
118
- add_action($addAssetsAction, array($this, 'addStyles'));
119
-
120
- register_activation_hook( CFS_DIR. DS. CFS_MAIN_FILE, array('utilsCfs', 'activatePlugin') ); //See classes/install.php file
121
- register_uninstall_hook(CFS_DIR. DS. CFS_MAIN_FILE, array('utilsCfs', 'deletePlugin'));
122
- register_deactivation_hook(CFS_DIR. DS. CFS_MAIN_FILE, array( 'utilsCfs', 'deactivatePlugin' ) );
123
-
124
- add_action('init', array($this, 'connectLang'));
125
- add_filter('do_not_defer', array($this, 'excludeDeferScripts'));
126
- add_filter('script_loader_tag', array($this, 'add_defer_attribute'), 10, 2);
127
- //$operationTime = microtime(true) - $startTime;
128
- }
129
- public function add_defer_attribute($tag, $handle) {
130
- // add script handles to the array below
131
- switch ($handle) {
132
- case 'google.recaptcha':
133
- return str_replace(' src', ' defer="defer" src', $tag);
134
- break;
135
- case 'google.recaptcha.frontend':
136
- return str_replace(' src', ' defer="defer" src', $tag);
137
- break;
138
- }
139
- return $tag;
140
- }
141
- public function excludeDeferScripts($do_not_defer) {
142
- //Need when WP deferred javaScript is activated
143
- global $wp_scripts;
144
- foreach($wp_scripts->queue as $handle) {
145
- $do_not_defer[] = $handle;
146
- }
147
- return $do_not_defer;
148
- }
149
- public function connectLang() {
150
- load_plugin_textdomain(CFS_LANG_CODE, false, CFS_PLUG_NAME. '/languages/');
151
- }
152
- /**
153
- * Check permissions for action in controller by $code and made corresponding action
154
- * @param string $code Code of controller that need to be checked
155
- * @param string $action Action that need to be checked
156
- * @return bool true if ok, else - should exit from application
157
- */
158
- public function checkPermissions($code, $action) {
159
- if($this->havePermissions($code, $action))
160
- return true;
161
- else {
162
- exit(_e('You have no permissions to view this page', CFS_LANG_CODE));
163
- }
164
- }
165
- /**
166
- * Check permissions for action in controller by $code
167
- * @param string $code Code of controller that need to be checked
168
- * @param string $action Action that need to be checked
169
- * @return bool true if ok, else - false
170
- */
171
- public function havePermissions($code, $action) {
172
- $res = true;
173
- $mod = $this->getModule($code);
174
- $action = strtolower($action);
175
- if($mod) {
176
- $permissions = $mod->getController()->getPermissions();
177
- if(!empty($permissions)) { // Special permissions
178
- if(isset($permissions[CFS_METHODS])
179
- && !empty($permissions[CFS_METHODS])
180
- ) {
181
- foreach($permissions[CFS_METHODS] as $method => $permissions) { // Make case-insensitive
182
- $permissions[CFS_METHODS][strtolower($method)] = $permissions;
183
- }
184
- if(array_key_exists($action, $permissions[CFS_METHODS])) { // Permission for this method exists
185
- $currentUserPosition = frameCfs::_()->getModule('user')->getCurrentUserPosition();
186
- if((is_array($permissions[ CFS_METHODS ][ $action ]) && !in_array($currentUserPosition, $permissions[ CFS_METHODS ][ $action ]))
187
- || (!is_array($permissions[ CFS_METHODS ][ $action ]) && $permissions[CFS_METHODS][$action] != $currentUserPosition)
188
- ) {
189
- $res = false;
190
- }
191
- }
192
- }
193
- if(isset($permissions[CFS_USERLEVELS])
194
- && !empty($permissions[CFS_USERLEVELS])
195
- ) {
196
- $currentUserPosition = frameCfs::_()->getModule('user')->getCurrentUserPosition();
197
- // For multi-sites network admin role is undefined, let's do this here
198
- if(is_multisite() && is_admin() && is_super_admin()) {
199
- $currentUserPosition = CFS_ADMIN;
200
- }
201
- foreach($permissions[CFS_USERLEVELS] as $userlevel => $methods) {
202
- if(is_array($methods)) {
203
- $lowerMethods = array_map('strtolower', $methods); // Make case-insensitive
204
- if(in_array($action, $lowerMethods)) { // Permission for this method exists
205
- if($currentUserPosition != $userlevel)
206
- $res = false;
207
- break;
208
- }
209
- } else {
210
- $lowerMethod = strtolower($methods); // Make case-insensitive
211
- if($lowerMethod == $action) { // Permission for this method exists
212
- if($currentUserPosition != $userlevel)
213
- $res = false;
214
- break;
215
- }
216
- }
217
- }
218
- }
219
- }
220
- if($res) { // Additional check for nonces
221
- $noncedMethods = $mod->getController()->getNoncedMethods();
222
- if(!empty($noncedMethods)) {
223
- $noncedMethods = array_map('strtolower', $noncedMethods);
224
- if(in_array($action, $noncedMethods)) {
225
- $nonce = isset($_REQUEST['_wpnonce']) ? $_REQUEST['_wpnonce'] : reqCfs::getVar('_wpnonce');
226
- if(!wp_verify_nonce( $nonce, $action )) {
227
- $res = false;
228
- }
229
- }
230
- }
231
- }
232
- }
233
- return $res;
234
- }
235
- public function getRes() {
236
- return $this->_res;
237
- }
238
- public function execAfterWpInit() {
239
- $this->_doExec();
240
- }
241
- /**
242
- * Check if method for module require some special permission. We can detect users permissions only after wp init action was done.
243
- */
244
- protected function _execOnlyAfterWpInit() {
245
- $res = false;
246
- $mod = $this->getModule( $this->_mod );
247
- $action = strtolower( $this->_action );
248
- if($mod) {
249
- $permissions = $mod->getController()->getPermissions();
250
- if(!empty($permissions)) { // Special permissions
251
- if(isset($permissions[CFS_METHODS])
252
- && !empty($permissions[CFS_METHODS])
253
- ) {
254
- foreach($permissions[CFS_METHODS] as $method => $permissions) { // Make case-insensitive
255
- $permissions[CFS_METHODS][strtolower($method)] = $permissions;
256
- }
257
- if(array_key_exists($action, $permissions[CFS_METHODS])) { // Permission for this method exists
258
- $res = true;
259
- }
260
- }
261
- if(isset($permissions[CFS_USERLEVELS])
262
- && !empty($permissions[CFS_USERLEVELS])
263
- ) {
264
- foreach($permissions[CFS_USERLEVELS] as $level => $methods) {
265
- if(!empty($methods)) {
266
- $res = true;
267
- break;
268
- }
269
- }
270
- }
271
- }
272
- }
273
- return $res;
274
- }
275
- protected function _execModules() {
276
- if($this->_mod) {
277
- // If module exist and is active
278
- $mod = $this->getModule($this->_mod);
279
- if($mod && !empty($this->_action)) {
280
- if($this->_execOnlyAfterWpInit()) {
281
- add_action('init', array($this, 'execAfterWpInit'));
282
- } else {
283
- $this->_doExec();
284
- }
285
- }
286
- }
287
- }
288
- protected function _doExec() {
289
- $mod = $this->getModule($this->_mod);
290
- if($mod && $this->checkPermissions($this->_mod, $this->_action)) {
291
- switch(reqCfs::getVar('reqType')) {
292
- case 'ajax':
293
- add_action('wp_ajax_'. $this->_action, array($mod->getController(), $this->_action));
294
- add_action('wp_ajax_nopriv_'. $this->_action, array($mod->getController(), $this->_action));
295
- break;
296
- default:
297
- $this->_res = $mod->exec($this->_action);
298
- break;
299
- }
300
- }
301
- }
302
- protected function _extractTables($tablesDir = CFS_TABLES_DIR) {
303
- $mDirHandle = opendir($tablesDir);
304
- while(($file = readdir($mDirHandle)) !== false) {
305
- if(is_file($tablesDir. $file) && $file != '.' && $file != '..' && strpos($file, '.php')) {
306
- $this->_extractTable( str_replace('.php', '', $file), $tablesDir );
307
- }
308
- }
309
- }
310
- protected function _extractTable($tableName, $tablesDir = CFS_TABLES_DIR) {
311
- importClassCfs('noClassNameHere', $tablesDir. $tableName. '.php');
312
- $this->_tables[$tableName] = tableCfs::_($tableName);
313
- }
314
- /**
315
- * public alias for _extractTables method
316
- * @see _extractTables
317
- */
318
- public function extractTables($tablesDir) {
319
- if(!empty($tablesDir))
320
- $this->_extractTables($tablesDir);
321
- }
322
- public function exec() {
323
- /**
324
- * @deprecated
325
- */
326
- /*if(!empty($this->_modules)) {
327
- foreach($this->_modules as $mod) {
328
- $mod->exec();
329
- }
330
- }*/
331
- }
332
- public function getTables () {
333
- return $this->_tables;
334
- }
335
- /**
336
- * Return table by name
337
- * @param string $tableName table name in database
338
- * @return object table
339
- * @example frameCfs::_()->getTable('products')->getAll()
340
- */
341
- public function getTable($tableName) {
342
- if(empty($this->_tables[$tableName])) {
343
- $this->_extractTable($tableName);
344
- }
345
- return $this->_tables[$tableName];
346
- }
347
- public function getModules($filter = array()) {
348
- $res = array();
349
- if(empty($filter))
350
- $res = $this->_modules;
351
- else {
352
- foreach($this->_modules as $code => $mod) {
353
- if(isset($filter['type'])) {
354
- if(is_numeric($filter['type']) && $filter['type'] == $mod->getTypeID())
355
- $res[$code] = $mod;
356
- elseif($filter['type'] == $mod->getType())
357
- $res[$code] = $mod;
358
- }
359
- }
360
- }
361
- return $res;
362
- }
363
-
364
- public function getModule($code) {
365
- return (isset($this->_modules[$code]) ? $this->_modules[$code] : NULL);
366
- }
367
- public function inPlugin() {
368
- return $this->_inPlugin;
369
- }
370
- public function usePackAssets() {
371
- if(!$this->_useFootAssets && $this->getModule('options') && $this->getModule('options')->get('foot_assets')) {
372
- $this->_useFootAssets = true;
373
- }
374
- return $this->_useFootAssets;
375
- }
376
- /**
377
- * Push data to script array to use it all in addScripts method
378
- * @see wp_enqueue_script definition
379
- */
380
-
381
- public function addScript($handle, $src = '', $deps = array(), $ver = false, $in_footer = false, $vars = array()) {
382
- $src = empty($src) ? $src : uriCfs::_($src);
383
- if(!$ver)
384
- $ver = CFS_VERSION;
385
- if($this->_scriptsInitialized) {
386
- wp_enqueue_script($handle, $src, $deps, $ver, $in_footer);
387
- } else {
388
- $this->_scripts[] = array(
389
- 'handle' => $handle,
390
- 'src' => $src,
391
- 'deps' => $deps,
392
- 'ver' => $ver,
393
- 'in_footer' => $in_footer,
394
- 'vars' => $vars
395
- );
396
- }
397
- }
398
- /**
399
- * Add all scripts from _scripts array to worcfsess
400
- */
401
- public function addScripts() {
402
- if(!empty($this->_scripts)) {
403
- foreach($this->_scripts as $s) {
404
- wp_enqueue_script($s['handle'], $s['src'], $s['deps'], $s['ver'], $s['in_footer']);
405
-
406
- if($s['vars'] || isset($this->_scriptsVars[$s['handle']])) {
407
- $vars = array();
408
- if($s['vars'])
409
- $vars = $s['vars'];
410
- if($this->_scriptsVars[$s['handle']])
411
- $vars = array_merge($vars, $this->_scriptsVars[$s['handle']]);
412
- if($vars) {
413
- foreach($vars as $k => $v) {
414
- wp_localize_script($s['handle'], $k, $v);
415
- }
416
- }
417
- }
418
- }
419
- }
420
- $this->_scriptsInitialized = true;
421
- }
422
- public function addJSVar($script, $name, $val) {
423
- if($this->_scriptsInitialized) {
424
- wp_localize_script($script, $name, $val);
425
- } else {
426
- $this->_scriptsVars[$script][$name] = $val;
427
- }
428
- }
429
-
430
- public function addStyle($handle, $src = false, $deps = array(), $ver = false, $media = 'all') {
431
- $src = empty($src) ? $src : uriCfs::_($src);
432
- if(!$ver)
433
- $ver = CFS_VERSION;
434
- if($this->_stylesInitialized) {
435
- wp_enqueue_style($handle, $src, $deps, $ver, $media);
436
- } else {
437
- $this->_styles[] = array(
438
- 'handle' => $handle,
439
- 'src' => $src,
440
- 'deps' => $deps,
441
- 'ver' => $ver,
442
- 'media' => $media
443
- );
444
- }
445
- }
446
- public function addStyles() {
447
- if(!empty($this->_styles)) {
448
- foreach($this->_styles as $s) {
449
- wp_enqueue_style($s['handle'], $s['src'], $s['deps'], $s['ver'], $s['media']);
450
- }
451
- }
452
- $this->_stylesInitialized = true;
453
- }
454
- //Very interesting thing going here.............
455
- public function loadPlugins() {
456
- require_once(ABSPATH. 'wp-includes/pluggable.php');
457
- }
458
- public function loadWPSettings() {
459
- require_once(ABSPATH. 'wp-settings.php');
460
- }
461
- public function loadLocale() {
462
- require_once(ABSPATH. 'wp-includes/locale.php');
463
- }
464
- public function moduleActive($code) {
465
- return isset($this->_modules[$code]);
466
- }
467
- public function moduleExists($code) {
468
- if($this->moduleActive($code))
469
- return true;
470
- return isset($this->_allModules[$code]);
471
- }
472
- public function isTplEditor() {
473
- $tplEditor = reqCfs::getVar('tplEditor');
474
- return (bool) $tplEditor;
475
- }
476
- /**
477
- * This is custom method for each plugin and should be modified if you create copy from this instance.
478
- */
479
- public function isAdminPlugOptsPage() {
480
- $page = reqCfs::getVar('page');
481
- if(is_admin() && strpos($page, frameCfs::_()->getModule('adminmenu')->getMainSlug()) !== false)
482
- return true;
483
- return false;
484
- }
485
- public function isAdminPlugPage() {
486
- if($this->isAdminPlugOptsPage()) {
487
- return true;
488
- }
489
- return false;
490
- }
491
- public function licenseDeactivated() {
492
- return (!$this->getModule('license') && $this->moduleExists('license'));
493
- }
494
- public function savePluginActivationErrors() {
495
- update_option(CFS_CODE. '_plugin_activation_errors', ob_get_contents());
496
- }
497
- public function getActivationErrors() {
498
- return get_option(CFS_CODE. '_plugin_activation_errors');
499
- }
500
- }
1
+ <?php
2
+ class frameCfs {
3
+ private $_modules = array();
4
+ private $_tables = array();
5
+ private $_allModules = array();
6
+ /**
7
+ * bool Uses to know if we are on one of the plugin pages
8
+ */
9
+ private $_inPlugin = false;
10
+ /**
11
+ * Array to hold all scripts and add them in one time in addScripts method
12
+ */
13
+ private $_scripts = array();
14
+ private $_scriptsInitialized = false;
15
+ private $_styles = array();
16
+ private $_stylesInitialized = false;
17
+ private $_useFootAssets = false;
18
+
19
+ private $_scriptsVars = array();
20
+ private $_mod = '';
21
+ private $_action = '';
22
+ /**
23
+ * Object with result of executing non-ajax module request
24
+ */
25
+ private $_res = null;
26
+
27
+ public function __construct() {
28
+ $this->_res = toeCreateObjCfs('response', array());
29
+
30
+ }
31
+ static public function getInstance() {
32
+ static $instance;
33
+ if(!$instance) {
34
+ $instance = new frameCfs();
35
+ }
36
+ return $instance;
37
+ }
38
+ static public function _() {
39
+ return self::getInstance();
40
+ }
41
+ public function parseRoute() {
42
+ // Check plugin
43
+ $pl = reqCfs::getVar('pl');
44
+ if($pl == CFS_CODE) {
45
+ $mod = reqCfs::getMode();
46
+ if($mod)
47
+ $this->_mod = $mod;
48
+ $action = reqCfs::getVar('action');
49
+ if($action)
50
+ $this->_action = $action;
51
+ }
52
+ }
53
+ public function setMod($mod) {
54
+ $this->_mod = $mod;
55
+ }
56
+ public function getMod() {
57
+ return $this->_mod;
58
+ }
59
+ public function setAction($action) {
60
+ $this->_action = $action;
61
+ }
62
+ public function getAction() {
63
+ return $this->_action;
64
+ }
65
+ protected function _extractModules() {
66
+ global $wpdb;
67
+ $wpPrefix = $wpdb->prefix; /* add to 0.0.3 Versiom */
68
+ if (dbCfs::exist("cfs_modules")) {
69
+
70
+ $activeModules = $wpdb->get_results(
71
+ "SELECT sup_m.*, sup_m_t.label as type_name FROM {$wpdb->prefix}cfs_modules as sup_m INNER JOIN {$wpdb->prefix}cfs_modules_type sup_m_t ON sup_m_t.id = sup_m.type_id ORDER BY id ASC", ARRAY_A
72
+ );
73
+ //$activeModules = $this->getTable('modules')
74
+ //->innerJoin( $this->getTable('modules_type'), 'type_id' )
75
+ //->orderBy('id ASC')
76
+ //->get($this->getTable('modules')->alias(). '.*, '. $this->getTable('modules_type')->alias(). '.label as type_name');
77
+
78
+ if($activeModules) {
79
+ foreach($activeModules as $m) {
80
+ $code = $m['code'];
81
+ $moduleLocationDir = CFS_MODULES_DIR;
82
+ if(!empty($m['ex_plug_dir'])) {
83
+ $moduleLocationDir = utilsCfs::getExtModDir( $m['ex_plug_dir'] );
84
+ }
85
+ if(is_dir($moduleLocationDir. $code)) {
86
+ $this->_allModules[$m['code']] = 1;
87
+ if((bool)$m['active']) {
88
+ importClassCfs($code. strFirstUp(CFS_CODE), $moduleLocationDir. $code. DS. 'mod.php');
89
+ $moduleClass = toeGetClassNameCfs($code);
90
+ if(class_exists($moduleClass)) {
91
+ $this->_modules[$code] = new $moduleClass($m);
92
+ if(is_dir($moduleLocationDir. $code. DS. 'tables')) {
93
+ $this->_extractTables($moduleLocationDir. $code. DS. 'tables'. DS);
94
+ }
95
+ }
96
+ }
97
+ }
98
+ }
99
+ }
100
+ }
101
+ //$operationTime = microtime(true) - $startTime;
102
+ }
103
+ protected function _initModules() {
104
+ if(!empty($this->_modules)) {
105
+ foreach($this->_modules as $mod) {
106
+ $mod->init();
107
+ }
108
+ }
109
+ }
110
+ public function init() {
111
+ //$startTime = microtime(true);
112
+ reqCfs::init();
113
+ $this->_extractTables();
114
+ $this->_extractModules();
115
+
116
+ $this->_initModules();
117
+
118
+ dispatcherCfs::doAction('afterModulesInit');
119
+
120
+ modInstallerCfs::checkActivationMessages();
121
+
122
+ $this->_execModules();
123
+
124
+ $addAssetsAction = $this->usePackAssets() && !is_admin() ? 'wp_footer' : 'init';
125
+
126
+ add_action($addAssetsAction, array($this, 'addScripts'));
127
+ add_action($addAssetsAction, array($this, 'addStyles'));
128
+
129
+ register_activation_hook( CFS_DIR. DS. CFS_MAIN_FILE, array('utilsCfs', 'activatePlugin') ); //See classes/install.php file
130
+ register_uninstall_hook(CFS_DIR. DS. CFS_MAIN_FILE, array('utilsCfs', 'deletePlugin'));
131
+ register_deactivation_hook(CFS_DIR. DS. CFS_MAIN_FILE, array( 'utilsCfs', 'deactivatePlugin' ) );
132
+
133
+ add_action('init', array($this, 'connectLang'));
134
+ add_filter('do_not_defer', array($this, 'excludeDeferScripts'));
135
+ add_filter('script_loader_tag', array($this, 'add_defer_attribute'), 10, 2);
136
+ //$operationTime = microtime(true) - $startTime;
137
+ }
138
+ public function add_defer_attribute($tag, $handle) {
139
+ // add script handles to the array below
140
+ switch ($handle) {
141
+ case 'google.recaptcha':
142
+ return str_replace(' src', ' defer="defer" src', $tag);
143
+ break;
144
+ case 'google.recaptcha.frontend':
145
+ return str_replace(' src', ' defer="defer" src', $tag);
146
+ break;
147
+ }
148
+ return $tag;
149
+ }
150
+ public function excludeDeferScripts($do_not_defer) {
151
+ //Need when WP deferred javaScript is activated
152
+ global $wp_scripts;
153
+ foreach($wp_scripts->queue as $handle) {
154
+ $do_not_defer[] = $handle;
155
+ }
156
+ return $do_not_defer;
157
+ }
158
+ public function connectLang() {
159
+ load_plugin_textdomain(CFS_LANG_CODE, false, CFS_PLUG_NAME. '/languages/');
160
+ }
161
+ /**
162
+ * Check permissions for action in controller by $code and made corresponding action
163
+ * @param string $code Code of controller that need to be checked
164
+ * @param string $action Action that need to be checked
165
+ * @return bool true if ok, else - should exit from application
166
+ */
167
+ public function checkPermissions($code, $action) {
168
+ if($this->havePermissions($code, $action))
169
+ return true;
170
+ else {
171
+ exit(_e('You have no permissions to view this page', CFS_LANG_CODE));
172
+ }
173
+ }
174
+ /**
175
+ * Check permissions for action in controller by $code
176
+ * @param string $code Code of controller that need to be checked
177
+ * @param string $action Action that need to be checked
178
+ * @return bool true if ok, else - false
179
+ */
180
+ public function havePermissions($code, $action) {
181
+ $res = true;
182
+ $mod = $this->getModule($code);
183
+ $action = strtolower($action);
184
+ if($mod) {
185
+ $permissions = $mod->getController()->getPermissions();
186
+ if(!empty($permissions)) { // Special permissions
187
+ if(isset($permissions[CFS_METHODS])
188
+ && !empty($permissions[CFS_METHODS])
189
+ ) {
190
+ foreach($permissions[CFS_METHODS] as $method => $permissions) { // Make case-insensitive
191
+ $permissions[CFS_METHODS][strtolower($method)] = $permissions;
192
+ }
193
+ if(array_key_exists($action, $permissions[CFS_METHODS])) { // Permission for this method exists
194
+ $currentUserPosition = frameCfs::_()->getModule('user')->getCurrentUserPosition();
195
+ if((is_array($permissions[ CFS_METHODS ][ $action ]) && !in_array($currentUserPosition, $permissions[ CFS_METHODS ][ $action ]))
196
+ || (!is_array($permissions[ CFS_METHODS ][ $action ]) && $permissions[CFS_METHODS][$action] != $currentUserPosition)
197
+ ) {
198
+ $res = false;
199
+ }
200
+ }
201
+ }
202
+ if(isset($permissions[CFS_USERLEVELS])
203
+ && !empty($permissions[CFS_USERLEVELS])
204
+ ) {
205
+ $currentUserPosition = frameCfs::_()->getModule('user')->getCurrentUserPosition();
206
+ // For multi-sites network admin role is undefined, let's do this here
207
+ if(is_multisite() && is_admin() && is_super_admin()) {
208
+ $currentUserPosition = CFS_ADMIN;
209
+ }
210
+ foreach($permissions[CFS_USERLEVELS] as $userlevel => $methods) {
211
+ if(is_array($methods)) {
212
+ $lowerMethods = array_map('strtolower', $methods); // Make case-insensitive
213
+ if(in_array($action, $lowerMethods)) { // Permission for this method exists
214
+ if($currentUserPosition != $userlevel)
215
+ $res = false;
216
+ break;
217
+ }
218
+ } else {
219
+ $lowerMethod = strtolower($methods); // Make case-insensitive
220
+ if($lowerMethod == $action) { // Permission for this method exists
221
+ if($currentUserPosition != $userlevel)
222
+ $res = false;
223
+ break;
224
+ }
225
+ }
226
+ }
227
+ }
228
+ }
229
+ if($res) { // Additional check for nonces
230
+ $noncedMethods = $mod->getController()->getNoncedMethods();
231
+ if(!empty($noncedMethods)) {
232
+ $noncedMethods = array_map('strtolower', $noncedMethods);
233
+ if(in_array($action, $noncedMethods)) {
234
+ $nonce = isset($_REQUEST['_wpnonce']) ? $_REQUEST['_wpnonce'] : reqCfs::getVar('_wpnonce');
235
+ if(!wp_verify_nonce( $nonce, $action )) {
236
+ $res = false;
237
+ }
238
+ }
239
+ }
240
+ }
241
+ }
242
+ return $res;
243
+ }
244
+ public function getRes() {
245
+ return $this->_res;
246
+ }
247
+ public function execAfterWpInit() {
248
+ $this->_doExec();
249
+ }
250
+ /**
251
+ * Check if method for module require some special permission. We can detect users permissions only after wp init action was done.
252
+ */
253
+ protected function _execOnlyAfterWpInit() {
254
+ $res = false;
255
+ $mod = $this->getModule( $this->_mod );
256
+ $action = strtolower( $this->_action );
257
+ if($mod) {
258
+ $permissions = $mod->getController()->get