diff options
author | Nicolas Lœuillet <nicolas.loeuillet@gmail.com> | 2013-08-03 19:26:54 +0200 |
---|---|---|
committer | Nicolas Lœuillet <nicolas.loeuillet@gmail.com> | 2013-08-03 19:26:54 +0200 |
commit | 4f5b44bd3bd490309eb2ba7b44df4769816ba729 (patch) | |
tree | 6cefe170dfe0a5a361cb1e2d1fc4d580a3316d02 /vendor/twig | |
parent | 2b840e0cfb63a453bea67a98541f3df9c273c5f5 (diff) | |
download | wallabag-4f5b44bd3bd490309eb2ba7b44df4769816ba729.tar.gz wallabag-4f5b44bd3bd490309eb2ba7b44df4769816ba729.tar.zst wallabag-4f5b44bd3bd490309eb2ba7b44df4769816ba729.zip |
twig implementation
Diffstat (limited to 'vendor/twig')
530 files changed, 32998 insertions, 0 deletions
diff --git a/vendor/twig/extensions b/vendor/twig/extensions new file mode 160000 | |||
Subproject f5b0c84f3699e494c84ee627d7d583e115d2c4a | |||
diff --git a/vendor/twig/twig/.editorconfig b/vendor/twig/twig/.editorconfig new file mode 100644 index 00000000..270f1d1b --- /dev/null +++ b/vendor/twig/twig/.editorconfig | |||
@@ -0,0 +1,18 @@ | |||
1 | ; top-most EditorConfig file | ||
2 | root = true | ||
3 | |||
4 | ; Unix-style newlines | ||
5 | [*] | ||
6 | end_of_line = LF | ||
7 | |||
8 | [*.php] | ||
9 | indent_style = space | ||
10 | indent_size = 4 | ||
11 | |||
12 | [*.test] | ||
13 | indent_style = space | ||
14 | indent_size = 4 | ||
15 | |||
16 | [*.rst] | ||
17 | indent_style = space | ||
18 | indent_size = 4 | ||
diff --git a/vendor/twig/twig/.gitignore b/vendor/twig/twig/.gitignore new file mode 100644 index 00000000..840b78e7 --- /dev/null +++ b/vendor/twig/twig/.gitignore | |||
@@ -0,0 +1,2 @@ | |||
1 | /ext/twig/autom4te.cache/ | ||
2 | |||
diff --git a/vendor/twig/twig/.travis.yml b/vendor/twig/twig/.travis.yml new file mode 100644 index 00000000..8569a395 --- /dev/null +++ b/vendor/twig/twig/.travis.yml | |||
@@ -0,0 +1,15 @@ | |||
1 | language: php | ||
2 | |||
3 | php: | ||
4 | - 5.2 | ||
5 | - 5.3 | ||
6 | - 5.4 | ||
7 | - 5.5 | ||
8 | |||
9 | env: | ||
10 | - TWIG_EXT=no | ||
11 | - TWIG_EXT=yes | ||
12 | |||
13 | before_script: | ||
14 | - if [ "$TWIG_EXT" == "yes" ]; then sh -c "cd ext/twig && phpize && ./configure --enable-twig && make && sudo make install"; fi | ||
15 | - if [ "$TWIG_EXT" == "yes" ]; then echo "extension=twig.so" >> `php --ini | grep "Loaded Configuration" | sed -e "s|.*:\s*||"`; fi | ||
diff --git a/vendor/twig/twig/AUTHORS b/vendor/twig/twig/AUTHORS new file mode 100644 index 00000000..eb5db051 --- /dev/null +++ b/vendor/twig/twig/AUTHORS | |||
@@ -0,0 +1,9 @@ | |||
1 | Twig is written and maintained by the Twig Team: | ||
2 | |||
3 | Lead Developer: | ||
4 | |||
5 | - Fabien Potencier <fabien.potencier@symfony-project.org> | ||
6 | |||
7 | Project Founder: | ||
8 | |||
9 | - Armin Ronacher <armin.ronacher@active-4.com> | ||
diff --git a/vendor/twig/twig/CHANGELOG b/vendor/twig/twig/CHANGELOG new file mode 100644 index 00000000..80ff9d2d --- /dev/null +++ b/vendor/twig/twig/CHANGELOG | |||
@@ -0,0 +1,637 @@ | |||
1 | * 1.13.2 (2013-08-03) | ||
2 | |||
3 | * fixed the error line number for an error occurs in and embedded template | ||
4 | * fixed crashes of the C extension on some edge cases | ||
5 | |||
6 | * 1.13.1 (2013-06-06) | ||
7 | |||
8 | * added the possibility to ignore the filesystem constructor argument in Twig_Loader_Filesystem | ||
9 | * fixed Twig_Loader_Chain::exists() for a loader which implements Twig_ExistsLoaderInterface | ||
10 | * adjusted backtrace call to reduce memory usage when an error occurs | ||
11 | * added support for object instances as the second argument of the constant test | ||
12 | * fixed the include function when used in an assignment | ||
13 | |||
14 | * 1.13.0 (2013-05-10) | ||
15 | |||
16 | * fixed getting a numeric-like item on a variable ('09' for instance) | ||
17 | * fixed getting a boolean or float key on an array, so it is consistent with PHP's array access: | ||
18 | `{{ array[false] }}` behaves the same as `echo $array[false];` (equals `$array[0]`) | ||
19 | * made the escape filter 20% faster for happy path (escaping string for html with UTF-8) | ||
20 | * changed ☃ to § in tests | ||
21 | * enforced usage of named arguments after positional ones | ||
22 | |||
23 | * 1.12.3 (2013-04-08) | ||
24 | |||
25 | * fixed a security issue in the filesystem loader where it was possible to include a template one | ||
26 | level above the configured path | ||
27 | * fixed fatal error that should be an exception when adding a filter/function/test too late | ||
28 | * added a batch filter | ||
29 | * added support for encoding an array as query string in the url_encode filter | ||
30 | |||
31 | * 1.12.2 (2013-02-09) | ||
32 | |||
33 | * fixed the timezone used by the date filter and function when the given date contains a timezone (like 2010-01-28T15:00:00+02:00) | ||
34 | * fixed globals when getGlobals is called early on | ||
35 | * added the first and last filter | ||
36 | |||
37 | * 1.12.1 (2013-01-15) | ||
38 | |||
39 | * added support for object instances as the second argument of the constant function | ||
40 | * relaxed globals management to avoid a BC break | ||
41 | * added support for {{ some_string[:2] }} | ||
42 | |||
43 | * 1.12.0 (2013-01-08) | ||
44 | |||
45 | * added verbatim as an alias for the raw tag to avoid confusion with the raw filter | ||
46 | * fixed registration of tests and functions as anonymous functions | ||
47 | * fixed globals management | ||
48 | |||
49 | * 1.12.0-RC1 (2012-12-29) | ||
50 | |||
51 | * added an include function (does the same as the include tag but in a more flexible way) | ||
52 | * added the ability to use any PHP callable to define filters, functions, and tests | ||
53 | * added a syntax error when using a loop variable that is not defined | ||
54 | * added the ability to set default values for macro arguments | ||
55 | * added support for named arguments for filters, tests, and functions | ||
56 | * moved filters/functions/tests syntax errors to the parser | ||
57 | * added support for extended ternary operator syntaxes | ||
58 | |||
59 | * 1.11.1 (2012-11-11) | ||
60 | |||
61 | * fixed debug info line numbering (was off by 2) | ||
62 | * fixed escaping when calling a macro inside another one (regression introduced in 1.9.1) | ||
63 | * optimized variable access on PHP 5.4 | ||
64 | * fixed a crash of the C extension when an exception was thrown from a macro called without being imported (using _self.XXX) | ||
65 | |||
66 | * 1.11.0 (2012-11-07) | ||
67 | |||
68 | * fixed macro compilation when a variable name is a PHP reserved keyword | ||
69 | * changed the date filter behavior to always apply the default timezone, except if false is passed as the timezone | ||
70 | * fixed bitwise operator precedences | ||
71 | * added the template_from_string function | ||
72 | * fixed default timezone usage for the date function | ||
73 | * optimized the way Twig exceptions are managed (to make them faster) | ||
74 | * added Twig_ExistsLoaderInterface (implementing this interface in your loader make the chain loader much faster) | ||
75 | |||
76 | * 1.10.3 (2012-10-19) | ||
77 | |||
78 | * fixed wrong template location in some error messages | ||
79 | * reverted a BC break introduced in 1.10.2 | ||
80 | * added a split filter | ||
81 | |||
82 | * 1.10.2 (2012-10-15) | ||
83 | |||
84 | * fixed macro calls on PHP 5.4 | ||
85 | |||
86 | * 1.10.1 (2012-10-15) | ||
87 | |||
88 | * made a speed optimization to macro calls when imported via the "import" tag | ||
89 | * fixed C extension compilation on Windows | ||
90 | * fixed a segfault in the C extension when using DateTime objects | ||
91 | |||
92 | * 1.10.0 (2012-09-28) | ||
93 | |||
94 | * extracted functional tests framework to make it reusable for third-party extensions | ||
95 | * added namespaced templates support in Twig_Loader_Filesystem | ||
96 | * added Twig_Loader_Filesystem::prependPath() | ||
97 | * fixed an error when a token parser pass a closure as a test to the subparse() method | ||
98 | |||
99 | * 1.9.2 (2012-08-25) | ||
100 | |||
101 | * fixed the in operator for objects that contain circular references | ||
102 | * fixed the C extension when accessing a public property of an object implementing the \ArrayAccess interface | ||
103 | |||
104 | * 1.9.1 (2012-07-22) | ||
105 | |||
106 | * optimized macro calls when auto-escaping is on | ||
107 | * fixed wrong parent class for Twig_Function_Node | ||
108 | * made Twig_Loader_Chain more explicit about problems | ||
109 | |||
110 | * 1.9.0 (2012-07-13) | ||
111 | |||
112 | * made the parsing independent of the template loaders | ||
113 | * fixed exception trace when an error occurs when rendering a child template | ||
114 | * added escaping strategies for CSS, URL, and HTML attributes | ||
115 | * fixed nested embed tag calls | ||
116 | * added the date_modify filter | ||
117 | |||
118 | * 1.8.3 (2012-06-17) | ||
119 | |||
120 | * fixed paths in the filesystem loader when passing a path that ends with a slash or a backslash | ||
121 | * fixed escaping when a project defines a function named html or js | ||
122 | * fixed chmod mode to apply the umask correctly | ||
123 | |||
124 | * 1.8.2 (2012-05-30) | ||
125 | |||
126 | * added the abs filter | ||
127 | * fixed a regression when using a number in template attributes | ||
128 | * fixed compiler when mbstring.func_overload is set to 2 | ||
129 | * fixed DateTimeZone support in date filter | ||
130 | |||
131 | * 1.8.1 (2012-05-17) | ||
132 | |||
133 | * fixed a regression when dealing with SimpleXMLElement instances in templates | ||
134 | * fixed "is_safe" value for the "dump" function when "html_errors" is not defined in php.ini | ||
135 | * switched to use mbstring whenever possible instead of iconv (you might need to update your encoding as mbstring and iconv encoding names sometimes differ) | ||
136 | |||
137 | * 1.8.0 (2012-05-08) | ||
138 | |||
139 | * enforced interface when adding tests, filters, functions, and node visitors from extensions | ||
140 | * fixed a side-effect of the date filter where the timezone might be changed | ||
141 | * simplified usage of the autoescape tag; the only (optional) argument is now the escaping strategy or false (with a BC layer) | ||
142 | * added a way to dynamically change the auto-escaping strategy according to the template "filename" | ||
143 | * changed the autoescape option to also accept a supported escaping strategy (for BC, true is equivalent to html) | ||
144 | * added an embed tag | ||
145 | |||
146 | * 1.7.0 (2012-04-24) | ||
147 | |||
148 | * fixed a PHP warning when using CIFS | ||
149 | * fixed template line number in some exceptions | ||
150 | * added an iterable test | ||
151 | * added an error when defining two blocks with the same name in a template | ||
152 | * added the preserves_safety option for filters | ||
153 | * fixed a PHP notice when trying to access a key on a non-object/array variable | ||
154 | * enhanced error reporting when the template file is an instance of SplFileInfo | ||
155 | * added Twig_Environment::mergeGlobals() | ||
156 | * added compilation checks to avoid misuses of the sandbox tag | ||
157 | * fixed filesystem loader freshness logic for high traffic websites | ||
158 | * fixed random function when charset is null | ||
159 | |||
160 | * 1.6.5 (2012-04-11) | ||
161 | |||
162 | * fixed a regression when a template only extends another one without defining any blocks | ||
163 | |||
164 | * 1.6.4 (2012-04-02) | ||
165 | |||
166 | * fixed PHP notice in Twig_Error::guessTemplateLine() introduced in 1.6.3 | ||
167 | * fixed performance when compiling large files | ||
168 | * optimized parent template creation when the template does not use dynamic inheritance | ||
169 | |||
170 | * 1.6.3 (2012-03-22) | ||
171 | |||
172 | * fixed usage of Z_ADDREF_P for PHP 5.2 in the C extension | ||
173 | * fixed compilation of numeric values used in templates when using a locale where the decimal separator is not a dot | ||
174 | * made the strategy used to guess the real template file name and line number in exception messages much faster and more accurate | ||
175 | |||
176 | * 1.6.2 (2012-03-18) | ||
177 | |||
178 | * fixed sandbox mode when used with inheritance | ||
179 | * added preserveKeys support for the slice filter | ||
180 | * fixed the date filter when a DateTime instance is passed with a specific timezone | ||
181 | * added a trim filter | ||
182 | |||
183 | * 1.6.1 (2012-02-29) | ||
184 | |||
185 | * fixed Twig C extension | ||
186 | * removed the creation of Twig_Markup instances when not needed | ||
187 | * added a way to set the default global timezone for dates | ||
188 | * fixed the slice filter on strings when the length is not specified | ||
189 | * fixed the creation of the cache directory in case of a race condition | ||
190 | |||
191 | * 1.6.0 (2012-02-04) | ||
192 | |||
193 | * fixed raw blocks when used with the whitespace trim option | ||
194 | * made a speed optimization to macro calls when imported via the "from" tag | ||
195 | * fixed globals, parsers, visitors, filters, tests, and functions management in Twig_Environment when a new one or new extension is added | ||
196 | * fixed the attribute function when passing arguments | ||
197 | * added slice notation support for the [] operator (syntactic sugar for the slice operator) | ||
198 | * added a slice filter | ||
199 | * added string support for the reverse filter | ||
200 | * fixed the empty test and the length filter for Twig_Markup instances | ||
201 | * added a date function to ease date comparison | ||
202 | * fixed unary operators precedence | ||
203 | * added recursive parsing support in the parser | ||
204 | * added string and integer handling for the random function | ||
205 | |||
206 | * 1.5.1 (2012-01-05) | ||
207 | |||
208 | * fixed a regression when parsing strings | ||
209 | |||
210 | * 1.5.0 (2012-01-04) | ||
211 | |||
212 | * added Traversable objects support for the join filter | ||
213 | |||
214 | * 1.5.0-RC2 (2011-12-30) | ||
215 | |||
216 | * added a way to set the default global date interval format | ||
217 | * fixed the date filter for DateInterval instances (setTimezone() does not exist for them) | ||
218 | * refactored Twig_Template::display() to ease its extension | ||
219 | * added a number_format filter | ||
220 | |||
221 | * 1.5.0-RC1 (2011-12-26) | ||
222 | |||
223 | * removed the need to quote hash keys | ||
224 | * allowed hash keys to be any expression | ||
225 | * added a do tag | ||
226 | * added a flush tag | ||
227 | * added support for dynamically named filters and functions | ||
228 | * added a dump function to help debugging templates | ||
229 | * added a nl2br filter | ||
230 | * added a random function | ||
231 | * added a way to change the default format for the date filter | ||
232 | * fixed the lexer when an operator ending with a letter ends a line | ||
233 | * added string interpolation support | ||
234 | * enhanced exceptions for unknown filters, functions, tests, and tags | ||
235 | |||
236 | * 1.4.0 (2011-12-07) | ||
237 | |||
238 | * fixed lexer when using big numbers (> PHP_INT_MAX) | ||
239 | * added missing preserveKeys argument to the reverse filter | ||
240 | * fixed macros containing filter tag calls | ||
241 | |||
242 | * 1.4.0-RC2 (2011-11-27) | ||
243 | |||
244 | * removed usage of Reflection in Twig_Template::getAttribute() | ||
245 | * added a C extension that can optionally replace Twig_Template::getAttribute() | ||
246 | * added negative timestamp support to the date filter | ||
247 | |||
248 | * 1.4.0-RC1 (2011-11-20) | ||
249 | |||
250 | * optimized variable access when using PHP 5.4 | ||
251 | * changed the precedence of the .. operator to be more consistent with languages that implements such a feature like Ruby | ||
252 | * added an Exception to Twig_Loader_Array::isFresh() method when the template does not exist to be consistent with other loaders | ||
253 | * added Twig_Function_Node to allow more complex functions to have their own Node class | ||
254 | * added Twig_Filter_Node to allow more complex filters to have their own Node class | ||
255 | * added Twig_Test_Node to allow more complex tests to have their own Node class | ||
256 | * added a better error message when a template is empty but contain a BOM | ||
257 | * fixed "in" operator for empty strings | ||
258 | * fixed the "defined" test and the "default" filter (now works with more than one call (foo.bar.foo) and for both values of the strict_variables option) | ||
259 | * changed the way extensions are loaded (addFilter/addFunction/addGlobal/addTest/addNodeVisitor/addTokenParser/addExtension can now be called in any order) | ||
260 | * added Twig_Environment::display() | ||
261 | * made the escape filter smarter when the encoding is not supported by PHP | ||
262 | * added a convert_encoding filter | ||
263 | * moved all node manipulations outside the compile() Node method | ||
264 | * made several speed optimizations | ||
265 | |||
266 | * 1.3.0 (2011-10-08) | ||
267 | |||
268 | no changes | ||
269 | |||
270 | * 1.3.0-RC1 (2011-10-04) | ||
271 | |||
272 | * added an optimization for the parent() function | ||
273 | * added cache reloading when auto_reload is true and an extension has been modified | ||
274 | * added the possibility to force the escaping of a string already marked as safe (instance of Twig_Markup) | ||
275 | * allowed empty templates to be used as traits | ||
276 | * added traits support for the "parent" function | ||
277 | |||
278 | * 1.2.0 (2011-09-13) | ||
279 | |||
280 | no changes | ||
281 | |||
282 | * 1.2.0-RC1 (2011-09-10) | ||
283 | |||
284 | * enhanced the exception when a tag remains unclosed | ||
285 | * added support for empty Countable objects for the "empty" test | ||
286 | * fixed algorithm that determines if a template using inheritance is valid (no output between block definitions) | ||
287 | * added better support for encoding problems when escaping a string (available as of PHP 5.4) | ||
288 | * added a way to ignore a missing template when using the "include" tag ({% include "foo" ignore missing %}) | ||
289 | * added support for an array of templates to the "include" and "extends" tags ({% include ['foo', 'bar'] %}) | ||
290 | * added support for bitwise operators in expressions | ||
291 | * added the "attribute" function to allow getting dynamic attributes on variables | ||
292 | * added Twig_Loader_Chain | ||
293 | * added Twig_Loader_Array::setTemplate() | ||
294 | * added an optimization for the set tag when used to capture a large chunk of static text | ||
295 | * changed name regex to match PHP one "[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*" (works for blocks, tags, functions, filters, and macros) | ||
296 | * removed the possibility to use the "extends" tag from a block | ||
297 | * added "if" modifier support to "for" loops | ||
298 | |||
299 | * 1.1.2 (2011-07-30) | ||
300 | |||
301 | * fixed json_encode filter on PHP 5.2 | ||
302 | * fixed regression introduced in 1.1.1 ({{ block(foo|lower) }}) | ||
303 | * fixed inheritance when using conditional parents | ||
304 | * fixed compilation of templates when the body of a child template is not empty | ||
305 | * fixed output when a macro throws an exception | ||
306 | * fixed a parsing problem when a large chunk of text is enclosed in a comment tag | ||
307 | * added PHPDoc for all Token parsers and Core extension functions | ||
308 | |||
309 | * 1.1.1 (2011-07-17) | ||
310 | |||
311 | * added a performance optimization in the Optimizer (also helps to lower the number of nested level calls) | ||
312 | * made some performance improvement for some edge cases | ||
313 | |||
314 | * 1.1.0 (2011-06-28) | ||
315 | |||
316 | * fixed json_encode filter | ||
317 | |||
318 | * 1.1.0-RC3 (2011-06-24) | ||
319 | |||
320 | * fixed method case-sensitivity when using the sandbox mode | ||
321 | * added timezone support for the date filter | ||
322 | * fixed possible security problems with NUL bytes | ||
323 | |||
324 | * 1.1.0-RC2 (2011-06-16) | ||
325 | |||
326 | * added an exception when the template passed to "use" is not a string | ||
327 | * made 'a.b is defined' not throw an exception if a is not defined (in strict mode) | ||
328 | * added {% line \d+ %} directive | ||
329 | |||
330 | * 1.1.0-RC1 (2011-05-28) | ||
331 | |||
332 | Flush your cache after upgrading. | ||
333 | |||
334 | * fixed date filter when using a timestamp | ||
335 | * fixed the defined test for some cases | ||
336 | * fixed a parsing problem when a large chunk of text is enclosed in a raw tag | ||
337 | * added support for horizontal reuse of template blocks (see docs for more information) | ||
338 | * added whitespace control modifier to all tags (see docs for more information) | ||
339 | * added null as an alias for none (the null test is also an alias for the none test now) | ||
340 | * made TRUE, FALSE, NONE equivalent to their lowercase counterparts | ||
341 | * wrapped all compilation and runtime exceptions with Twig_Error_Runtime and added logic to guess the template name and line | ||
342 | * moved display() method to Twig_Template (generated templates should now use doDisplay() instead) | ||
343 | |||
344 | * 1.0.0 (2011-03-27) | ||
345 | |||
346 | * fixed output when using mbstring | ||
347 | * fixed duplicate call of methods when using the sandbox | ||
348 | * made the charset configurable for the escape filter | ||
349 | |||
350 | * 1.0.0-RC2 (2011-02-21) | ||
351 | |||
352 | * changed the way {% set %} works when capturing (the content is now marked as safe) | ||
353 | * added support for macro name in the endmacro tag | ||
354 | * make Twig_Error compatible with PHP 5.3.0 > | ||
355 | * fixed an infinite loop on some Windows configurations | ||
356 | * fixed the "length" filter for numbers | ||
357 | * fixed Template::getAttribute() as properties in PHP are case sensitive | ||
358 | * removed coupling between Twig_Node and Twig_Template | ||
359 | * fixed the ternary operator precedence rule | ||
360 | |||
361 | * 1.0.0-RC1 (2011-01-09) | ||
362 | |||
363 | Backward incompatibilities: | ||
364 | |||
365 | * the "items" filter, which has been deprecated for quite a long time now, has been removed | ||
366 | * the "range" filter has been converted to a function: 0|range(10) -> range(0, 10) | ||
367 | * the "constant" filter has been converted to a function: {{ some_date|date('DATE_W3C'|constant) }} -> {{ some_date|date(constant('DATE_W3C')) }} | ||
368 | * the "cycle" filter has been converted to a function: {{ ['odd', 'even']|cycle(i) }} -> {{ cycle(['odd', 'even'], i) }} | ||
369 | * the "for" tag does not support "joined by" anymore | ||
370 | * the "autoescape" first argument is now "true"/"false" (instead of "on"/"off") | ||
371 | * the "parent" tag has been replaced by a "parent" function ({{ parent() }} instead of {% parent %}) | ||
372 | * the "display" tag has been replaced by a "block" function ({{ block('title') }} instead of {% display title %}) | ||
373 | * removed the grammar and simple token parser (moved to the Twig Extensions repository) | ||
374 | |||
375 | Changes: | ||
376 | |||
377 | * added "needs_context" option for filters and functions (the context is then passed as a first argument) | ||
378 | * added global variables support | ||
379 | * made macros return their value instead of echoing directly (fixes calling a macro in sandbox mode) | ||
380 | * added the "from" tag to import macros as functions | ||
381 | * added support for functions (a function is just syntactic sugar for a getAttribute() call) | ||
382 | * made macros callable when sandbox mode is enabled | ||
383 | * added an exception when a macro uses a reserved name | ||
384 | * the "default" filter now uses the "empty" test instead of just checking for null | ||
385 | * added the "empty" test | ||
386 | |||
387 | * 0.9.10 (2010-12-16) | ||
388 | |||
389 | Backward incompatibilities: | ||
390 | |||
391 | * The Escaper extension is enabled by default, which means that all displayed | ||
392 | variables are now automatically escaped. You can revert to the previous | ||
393 | behavior by removing the extension via $env->removeExtension('escaper') | ||
394 | or just set the 'autoescape' option to 'false'. | ||
395 | * removed the "without loop" attribute for the "for" tag (not needed anymore | ||
396 | as the Optimizer take care of that for most cases) | ||
397 | * arrays and hashes have now a different syntax | ||
398 | * arrays keep the same syntax with square brackets: [1, 2] | ||
399 | * hashes now use curly braces (["a": "b"] should now be written as {"a": "b"}) | ||
400 | * support for "arrays with keys" and "hashes without keys" is not supported anymore ([1, "foo": "bar"] or {"foo": "bar", 1}) | ||
401 | * the i18n extension is now part of the Twig Extensions repository | ||
402 | |||
403 | Changes: | ||
404 | |||
405 | * added the merge filter | ||
406 | * removed 'is_escaper' option for filters (a left over from the previous version) -- you must use 'is_safe' now instead | ||
407 | * fixed usage of operators as method names (like is, in, and not) | ||
408 | * changed the order of execution for node visitors | ||
409 | * fixed default() filter behavior when used with strict_variables set to on | ||
410 | * fixed filesystem loader compatibility with PHAR files | ||
411 | * enhanced error messages when an unexpected token is parsed in an expression | ||
412 | * fixed filename not being added to syntax error messages | ||
413 | * added the autoescape option to enable/disable autoescaping | ||
414 | * removed the newline after a comment (mimics PHP behavior) | ||
415 | * added a syntax error exception when parent block is used on a template that does not extend another one | ||
416 | * made the Escaper extension enabled by default | ||
417 | * fixed sandbox extension when used with auto output escaping | ||
418 | * fixed escaper when wrapping a Twig_Node_Print (the original class must be preserved) | ||
419 | * added an Optimizer extension (enabled by default; optimizes "for" loops and "raw" filters) | ||
420 | * added priority to node visitors | ||
421 | |||
422 | * 0.9.9 (2010-11-28) | ||
423 | |||
424 | Backward incompatibilities: | ||
425 | * the self special variable has been renamed to _self | ||
426 | * the odd and even filters are now tests: | ||
427 | {{ foo|odd }} must now be written {{ foo is odd }} | ||
428 | * the "safe" filter has been renamed to "raw" | ||
429 | * in Node classes, | ||
430 | sub-nodes are now accessed via getNode() (instead of property access) | ||
431 | attributes via getAttribute() (instead of array access) | ||
432 | * the urlencode filter had been renamed to url_encode | ||
433 | * the include tag now merges the passed variables with the current context by default | ||
434 | (the old behavior is still possible by adding the "only" keyword) | ||
435 | * moved Exceptions to Twig_Error_* (Twig_SyntaxError/Twig_RuntimeError are now Twig_Error_Syntax/Twig_Error_Runtime) | ||
436 | * removed support for {{ 1 < i < 3 }} (use {{ i > 1 and i < 3 }} instead) | ||
437 | * the "in" filter has been removed ({{ a|in(b) }} should now be written {{ a in b }}) | ||
438 | |||
439 | Changes: | ||
440 | * added file and line to Twig_Error_Runtime exceptions thrown from Twig_Template | ||
441 | * changed trans tag to accept any variable for the plural count | ||
442 | * fixed sandbox mode (__toString() method check was not enforced if called implicitly from complex statements) | ||
443 | * added the ** (power) operator | ||
444 | * changed the algorithm used for parsing expressions | ||
445 | * added the spaceless tag | ||
446 | * removed trim_blocks option | ||
447 | * added support for is*() methods for attributes (foo.bar now looks for foo->getBar() or foo->isBar()) | ||
448 | * changed all exceptions to extend Twig_Error | ||
449 | * fixed unary expressions ({{ not(1 or 0) }}) | ||
450 | * fixed child templates (with an extend tag) that uses one or more imports | ||
451 | * added support for {{ 1 not in [2, 3] }} (more readable than the current {{ not (1 in [2, 3]) }}) | ||
452 | * escaping has been rewritten | ||
453 | * the implementation of template inheritance has been rewritten | ||
454 | (blocks can now be called individually and still work with inheritance) | ||
455 | * fixed error handling for if tag when a syntax error occurs within a subparse process | ||
456 | * added a way to implement custom logic for resolving token parsers given a tag name | ||
457 | * fixed js escaper to be stricter (now uses a whilelist-based js escaper) | ||
458 | * added the following filers: "constant", "trans", "replace", "json_encode" | ||
459 | * added a "constant" test | ||
460 | * fixed objects with __toString() not being autoescaped | ||
461 | * fixed subscript expressions when calling __call() (methods now keep the case) | ||
462 | * added "test" feature (accessible via the "is" operator) | ||
463 | * removed the debug tag (should be done in an extension) | ||
464 | * fixed trans tag when no vars are used in plural form | ||
465 | * fixed race condition when writing template cache | ||
466 | * added the special _charset variable to reference the current charset | ||
467 | * added the special _context variable to reference the current context | ||
468 | * renamed self to _self (to avoid conflict) | ||
469 | * fixed Twig_Template::getAttribute() for protected properties | ||
470 | |||
471 | * 0.9.8 (2010-06-28) | ||
472 | |||
473 | Backward incompatibilities: | ||
474 | * the trans tag plural count is now attached to the plural tag: | ||
475 | old: `{% trans count %}...{% plural %}...{% endtrans %}` | ||
476 | new: `{% trans %}...{% plural count %}...{% endtrans %}` | ||
477 | |||
478 | * added a way to translate strings coming from a variable ({% trans var %}) | ||
479 | * fixed trans tag when used with the Escaper extension | ||
480 | * fixed default cache umask | ||
481 | * removed Twig_Template instances from the debug tag output | ||
482 | * fixed objects with __isset() defined | ||
483 | * fixed set tag when used with a capture | ||
484 | * fixed type hinting for Twig_Environment::addFilter() method | ||
485 | |||
486 | * 0.9.7 (2010-06-12) | ||
487 | |||
488 | Backward incompatibilities: | ||
489 | * changed 'as' to '=' for the set tag ({% set title as "Title" %} must now be {% set title = "Title" %}) | ||
490 | * removed the sandboxed attribute of the include tag (use the new sandbox tag instead) | ||
491 | * refactored the Node system (if you have custom nodes, you will have to update them to use the new API) | ||
492 | |||
493 | * added self as a special variable that refers to the current template (useful for importing macros from the current template) | ||
494 | * added Twig_Template instance support to the include tag | ||
495 | * added support for dynamic and conditional inheritance ({% extends some_var %} and {% extends standalone ? "minimum" : "base" %}) | ||
496 | * added a grammar sub-framework to ease the creation of custom tags | ||
497 | * fixed the for tag for large arrays (some loop variables are now only available for arrays and objects that implement the Countable interface) | ||
498 | * removed the Twig_Resource::resolveMissingFilter() method | ||
499 | * fixed the filter tag which did not apply filtering to included files | ||
500 | * added a bunch of unit tests | ||
501 | * added a bunch of phpdoc | ||
502 | * added a sandbox tag in the sandbox extension | ||
503 | * changed the date filter to support any date format supported by DateTime | ||
504 | * added strict_variable setting to throw an exception when an invalid variable is used in a template (disabled by default) | ||
505 | * added the lexer, parser, and compiler as arguments to the Twig_Environment constructor | ||
506 | * changed the cache option to only accepts an explicit path to a cache directory or false | ||
507 | * added a way to add token parsers, filters, and visitors without creating an extension | ||
508 | * added three interfaces: Twig_NodeInterface, Twig_TokenParserInterface, and Twig_FilterInterface | ||
509 | * changed the generated code to match the new coding standards | ||
510 | * fixed sandbox mode (__toString() method check was not enforced if called implicitly from a simple statement like {{ article }}) | ||
511 | * added an exception when a child template has a non-empty body (as it is always ignored when rendering) | ||
512 | |||
513 | * 0.9.6 (2010-05-12) | ||
514 | |||
515 | * fixed variables defined outside a loop and for which the value changes in a for loop | ||
516 | * fixed the test suite for PHP 5.2 and older versions of PHPUnit | ||
517 | * added support for __call() in expression resolution | ||
518 | * fixed node visiting for macros (macros are now visited by visitors as any other node) | ||
519 | * fixed nested block definitions with a parent call (rarely useful but nonetheless supported now) | ||
520 | * added the cycle filter | ||
521 | * fixed the Lexer when mbstring.func_overload is used with an mbstring.internal_encoding different from ASCII | ||
522 | * added a long-syntax for the set tag ({% set foo %}...{% endset %}) | ||
523 | * unit tests are now powered by PHPUnit | ||
524 | * added support for gettext via the `i18n` extension | ||
525 | * fixed twig_capitalize_string_filter() and fixed twig_length_filter() when used with UTF-8 values | ||
526 | * added a more useful exception if an if tag is not closed properly | ||
527 | * added support for escaping strategy in the autoescape tag | ||
528 | * fixed lexer when a template has a big chunk of text between/in a block | ||
529 | |||
530 | * 0.9.5 (2010-01-20) | ||
531 | |||
532 | As for any new release, don't forget to remove all cached templates after | ||
533 | upgrading. | ||
534 | |||
535 | If you have defined custom filters, you MUST upgrade them for this release. To | ||
536 | upgrade, replace "array" with "new Twig_Filter_Function", and replace the | ||
537 | environment constant by the "needs_environment" option: | ||
538 | |||
539 | // before | ||
540 | 'even' => array('twig_is_even_filter', false), | ||
541 | 'escape' => array('twig_escape_filter', true), | ||
542 | |||
543 | // after | ||
544 | 'even' => new Twig_Filter_Function('twig_is_even_filter'), | ||
545 | 'escape' => new Twig_Filter_Function('twig_escape_filter', array('needs_environment' => true)), | ||
546 | |||
547 | If you have created NodeTransformer classes, you will need to upgrade them to | ||
548 | the new interface (please note that the interface is not yet considered | ||
549 | stable). | ||
550 | |||
551 | * fixed list nodes that did not extend the Twig_NodeListInterface | ||
552 | * added the "without loop" option to the for tag (it disables the generation of the loop variable) | ||
553 | * refactored node transformers to node visitors | ||
554 | * fixed automatic-escaping for blocks | ||
555 | * added a way to specify variables to pass to an included template | ||
556 | * changed the automatic-escaping rules to be more sensible and more configurable in custom filters (the documentation lists all the rules) | ||
557 | * improved the filter system to allow object methods to be used as filters | ||
558 | * changed the Array and String loaders to actually make use of the cache mechanism | ||
559 | * included the default filter function definitions in the extension class files directly (Core, Escaper) | ||
560 | * added the // operator (like the floor() PHP function) | ||
561 | * added the .. operator (as a syntactic sugar for the range filter when the step is 1) | ||
562 | * added the in operator (as a syntactic sugar for the in filter) | ||
563 | * added the following filters in the Core extension: in, range | ||
564 | * added support for arrays (same behavior as in PHP, a mix between lists and dictionaries, arrays and hashes) | ||
565 | * enhanced some error messages to provide better feedback in case of parsing errors | ||
566 | |||
567 | * 0.9.4 (2009-12-02) | ||
568 | |||
569 | If you have custom loaders, you MUST upgrade them for this release: The | ||
570 | Twig_Loader base class has been removed, and the Twig_LoaderInterface has also | ||
571 | been changed (see the source code for more information or the documentation). | ||
572 | |||
573 | * added support for DateTime instances for the date filter | ||
574 | * fixed loop.last when the array only has one item | ||
575 | * made it possible to insert newlines in tag and variable blocks | ||
576 | * fixed a bug when a literal '\n' were present in a template text | ||
577 | * fixed bug when the filename of a template contains */ | ||
578 | * refactored loaders | ||
579 | |||
580 | * 0.9.3 (2009-11-11) | ||
581 | |||
582 | This release is NOT backward compatible with the previous releases. | ||
583 | |||
584 | The loaders do not take the cache and autoReload arguments anymore. Instead, | ||
585 | the Twig_Environment class has two new options: cache and auto_reload. | ||
586 | Upgrading your code means changing this kind of code: | ||
587 | |||
588 | $loader = new Twig_Loader_Filesystem('/path/to/templates', '/path/to/compilation_cache', true); | ||
589 | $twig = new Twig_Environment($loader); | ||
590 | |||
591 | to something like this: | ||
592 | |||
593 | $loader = new Twig_Loader_Filesystem('/path/to/templates'); | ||
594 | $twig = new Twig_Environment($loader, array( | ||
595 | 'cache' => '/path/to/compilation_cache', | ||
596 | 'auto_reload' => true, | ||
597 | )); | ||
598 | |||
599 | * deprecated the "items" filter as it is not needed anymore | ||
600 | * made cache and auto_reload options of Twig_Environment instead of arguments of Twig_Loader | ||
601 | * optimized template loading speed | ||
602 | * removed output when an error occurs in a template and render() is used | ||
603 | * made major speed improvements for loops (up to 300% on even the smallest loops) | ||
604 | * added properties as part of the sandbox mode | ||
605 | * added public properties support (obj.item can now be the item property on the obj object) | ||
606 | * extended set tag to support expression as value ({% set foo as 'foo' ~ 'bar' %} ) | ||
607 | * fixed bug when \ was used in HTML | ||
608 | |||
609 | * 0.9.2 (2009-10-29) | ||
610 | |||
611 | * made some speed optimizations | ||
612 | * changed the cache extension to .php | ||
613 | * added a js escaping strategy | ||
614 | * added support for short block tag | ||
615 | * changed the filter tag to allow chained filters | ||
616 | * made lexer more flexible as you can now change the default delimiters | ||
617 | * added set tag | ||
618 | * changed default directory permission when cache dir does not exist (more secure) | ||
619 | * added macro support | ||
620 | * changed filters first optional argument to be a Twig_Environment instance instead of a Twig_Template instance | ||
621 | * made Twig_Autoloader::autoload() a static method | ||
622 | * avoid writing template file if an error occurs | ||
623 | * added $ escaping when outputting raw strings | ||
624 | * enhanced some error messages to ease debugging | ||
625 | * fixed empty cache files when the template contains an error | ||
626 | |||
627 | * 0.9.1 (2009-10-14) | ||
628 | |||
629 | * fixed a bug in PHP 5.2.6 | ||
630 | * fixed numbers with one than one decimal | ||
631 | * added support for method calls with arguments ({{ foo.bar('a', 43) }}) | ||
632 | * made small speed optimizations | ||
633 | * made minor tweaks to allow better extensibility and flexibility | ||
634 | |||
635 | * 0.9.0 (2009-10-12) | ||
636 | |||
637 | * Initial release | ||
diff --git a/vendor/twig/twig/LICENSE b/vendor/twig/twig/LICENSE new file mode 100644 index 00000000..3384cc55 --- /dev/null +++ b/vendor/twig/twig/LICENSE | |||
@@ -0,0 +1,31 @@ | |||
1 | Copyright (c) 2009-2013 by the Twig Team, see AUTHORS for more details. | ||
2 | |||
3 | Some rights reserved. | ||
4 | |||
5 | Redistribution and use in source and binary forms, with or without | ||
6 | modification, are permitted provided that the following conditions are | ||
7 | met: | ||
8 | |||
9 | * Redistributions of source code must retain the above copyright | ||
10 | notice, this list of conditions and the following disclaimer. | ||
11 | |||
12 | * Redistributions in binary form must reproduce the above | ||
13 | copyright notice, this list of conditions and the following | ||
14 | disclaimer in the documentation and/or other materials provided | ||
15 | with the distribution. | ||
16 | |||
17 | * The names of the contributors may not be used to endorse or | ||
18 | promote products derived from this software without specific | ||
19 | prior written permission. | ||
20 | |||
21 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
22 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
23 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
24 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
25 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
26 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
27 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
28 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
29 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
30 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
31 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
diff --git a/vendor/twig/twig/README.markdown b/vendor/twig/twig/README.markdown new file mode 100644 index 00000000..88d6fabc --- /dev/null +++ b/vendor/twig/twig/README.markdown | |||
@@ -0,0 +1,17 @@ | |||
1 | Twig, the flexible, fast, and secure template language for PHP | ||
2 | ============================================================== | ||
3 | |||
4 | [![Build Status](https://secure.travis-ci.org/fabpot/Twig.png?branch=master)](http://travis-ci.org/fabpot/Twig) | ||
5 | |||
6 | Twig is a template language for PHP, released under the new BSD license (code | ||
7 | and documentation). | ||
8 | |||
9 | Twig uses a syntax similar to the Django and Jinja template languages which | ||
10 | inspired the Twig runtime environment. | ||
11 | |||
12 | More Information | ||
13 | ---------------- | ||
14 | |||
15 | Read the [documentation][1] for more information. | ||
16 | |||
17 | [1]: http://twig.sensiolabs.org/documentation | ||
diff --git a/vendor/twig/twig/composer.json b/vendor/twig/twig/composer.json new file mode 100644 index 00000000..67a08aad --- /dev/null +++ b/vendor/twig/twig/composer.json | |||
@@ -0,0 +1,31 @@ | |||
1 | { | ||
2 | "name": "twig/twig", | ||
3 | "type": "library", | ||
4 | "description": "Twig, the flexible, fast, and secure template language for PHP", | ||
5 | "keywords": ["templating"], | ||
6 | "homepage": "http://twig.sensiolabs.org", | ||
7 | "license": "BSD-3-Clause", | ||
8 | "authors": [ | ||
9 | { | ||
10 | "name": "Fabien Potencier", | ||
11 | "email": "fabien@symfony.com" | ||
12 | }, | ||
13 | { | ||
14 | "name": "Armin Ronacher", | ||
15 | "email": "armin.ronacher@active-4.com" | ||
16 | } | ||
17 | ], | ||
18 | "require": { | ||
19 | "php": ">=5.2.4" | ||
20 | }, | ||
21 | "autoload": { | ||
22 | "psr-0" : { | ||
23 | "Twig_" : "lib/" | ||
24 | } | ||
25 | }, | ||
26 | "extra": { | ||
27 | "branch-alias": { | ||
28 | "dev-master": "1.13-dev" | ||
29 | } | ||
30 | } | ||
31 | } | ||
diff --git a/vendor/twig/twig/doc/advanced.rst b/vendor/twig/twig/doc/advanced.rst new file mode 100644 index 00000000..e1945ebb --- /dev/null +++ b/vendor/twig/twig/doc/advanced.rst | |||
@@ -0,0 +1,829 @@ | |||
1 | Extending Twig | ||
2 | ============== | ||
3 | |||
4 | .. caution:: | ||
5 | |||
6 | This section describes how to extend Twig as of **Twig 1.12**. If you are | ||
7 | using an older version, read the :doc:`legacy<advanced_legacy>` chapter | ||
8 | instead. | ||
9 | |||
10 | Twig can be extended in many ways; you can add extra tags, filters, tests, | ||
11 | operators, global variables, and functions. You can even extend the parser | ||
12 | itself with node visitors. | ||
13 | |||
14 | .. note:: | ||
15 | |||
16 | The first section of this chapter describes how to extend Twig easily. If | ||
17 | you want to reuse your changes in different projects or if you want to | ||
18 | share them with others, you should then create an extension as described | ||
19 | in the following section. | ||
20 | |||
21 | .. caution:: | ||
22 | |||
23 | When extending Twig without creating an extension, Twig won't be able to | ||
24 | recompile your templates when the PHP code is updated. To see your changes | ||
25 | in real-time, either disable template caching or package your code into an | ||
26 | extension (see the next section of this chapter). | ||
27 | |||
28 | Before extending Twig, you must understand the differences between all the | ||
29 | different possible extension points and when to use them. | ||
30 | |||
31 | First, remember that Twig has two main language constructs: | ||
32 | |||
33 | * ``{{ }}``: used to print the result of an expression evaluation; | ||
34 | |||
35 | * ``{% %}``: used to execute statements. | ||
36 | |||
37 | To understand why Twig exposes so many extension points, let's see how to | ||
38 | implement a *Lorem ipsum* generator (it needs to know the number of words to | ||
39 | generate). | ||
40 | |||
41 | You can use a ``lipsum`` *tag*: | ||
42 | |||
43 | .. code-block:: jinja | ||
44 | |||
45 | {% lipsum 40 %} | ||
46 | |||
47 | That works, but using a tag for ``lipsum`` is not a good idea for at least | ||
48 | three main reasons: | ||
49 | |||
50 | * ``lipsum`` is not a language construct; | ||
51 | * The tag outputs something; | ||
52 | * The tag is not flexible as you cannot use it in an expression: | ||
53 | |||
54 | .. code-block:: jinja | ||
55 | |||
56 | {{ 'some text' ~ {% lipsum 40 %} ~ 'some more text' }} | ||
57 | |||
58 | In fact, you rarely need to create tags; and that's good news because tags are | ||
59 | the most complex extension point of Twig. | ||
60 | |||
61 | Now, let's use a ``lipsum`` *filter*: | ||
62 | |||
63 | .. code-block:: jinja | ||
64 | |||
65 | {{ 40|lipsum }} | ||
66 | |||
67 | Again, it works, but it looks weird. A filter transforms the passed value to | ||
68 | something else but here we use the value to indicate the number of words to | ||
69 | generate (so, ``40`` is an argument of the filter, not the value we want to | ||
70 | transform). | ||
71 | |||
72 | Next, let's use a ``lipsum`` *function*: | ||
73 | |||
74 | .. code-block:: jinja | ||
75 | |||
76 | {{ lipsum(40) }} | ||
77 | |||
78 | Here we go. For this specific example, the creation of a function is the | ||
79 | extension point to use. And you can use it anywhere an expression is accepted: | ||
80 | |||
81 | .. code-block:: jinja | ||
82 | |||
83 | {{ 'some text' ~ lipsum(40) ~ 'some more text' }} | ||
84 | |||
85 | {% set lipsum = lipsum(40) %} | ||
86 | |||
87 | Last but not the least, you can also use a *global* object with a method able | ||
88 | to generate lorem ipsum text: | ||
89 | |||
90 | .. code-block:: jinja | ||
91 | |||
92 | {{ text.lipsum(40) }} | ||
93 | |||
94 | As a rule of thumb, use functions for frequently used features and global | ||
95 | objects for everything else. | ||
96 | |||
97 | Keep in mind the following when you want to extend Twig: | ||
98 | |||
99 | ========== ========================== ========== ========================= | ||
100 | What? Implementation difficulty? How often? When? | ||
101 | ========== ========================== ========== ========================= | ||
102 | *macro* trivial frequent Content generation | ||
103 | *global* trivial frequent Helper object | ||
104 | *function* trivial frequent Content generation | ||
105 | *filter* trivial frequent Value transformation | ||
106 | *tag* complex rare DSL language construct | ||
107 | *test* trivial rare Boolean decision | ||
108 | *operator* trivial rare Values transformation | ||
109 | ========== ========================== ========== ========================= | ||
110 | |||
111 | Globals | ||
112 | ------- | ||
113 | |||
114 | A global variable is like any other template variable, except that it's | ||
115 | available in all templates and macros:: | ||
116 | |||
117 | $twig = new Twig_Environment($loader); | ||
118 | $twig->addGlobal('text', new Text()); | ||
119 | |||
120 | You can then use the ``text`` variable anywhere in a template: | ||
121 | |||
122 | .. code-block:: jinja | ||
123 | |||
124 | {{ text.lipsum(40) }} | ||
125 | |||
126 | Filters | ||
127 | ------- | ||
128 | |||
129 | Creating a filter is as simple as associating a name with a PHP callable:: | ||
130 | |||
131 | // an anonymous function | ||
132 | $filter = new Twig_SimpleFilter('rot13', function ($string) { | ||
133 | return str_rot13($string); | ||
134 | }); | ||
135 | |||
136 | // or a simple PHP function | ||
137 | $filter = new Twig_SimpleFilter('rot13', 'str_rot13'); | ||
138 | |||
139 | // or a class method | ||
140 | $filter = new Twig_SimpleFilter('rot13', array('SomeClass', 'rot13Filter')); | ||
141 | |||
142 | The first argument passed to the ``Twig_SimpleFilter`` constructor is the name | ||
143 | of the filter you will use in templates and the second one is the PHP callable | ||
144 | to associate with it. | ||
145 | |||
146 | Then, add the filter to your Twig environment:: | ||
147 | |||
148 | $twig = new Twig_Environment($loader); | ||
149 | $twig->addFilter($filter); | ||
150 | |||
151 | And here is how to use it in a template: | ||
152 | |||
153 | .. code-block:: jinja | ||
154 | |||
155 | {{ 'Twig'|rot13 }} | ||
156 | |||
157 | {# will output Gjvt #} | ||
158 | |||
159 | When called by Twig, the PHP callable receives the left side of the filter | ||
160 | (before the pipe ``|``) as the first argument and the extra arguments passed | ||
161 | to the filter (within parentheses ``()``) as extra arguments. | ||
162 | |||
163 | For instance, the following code: | ||
164 | |||
165 | .. code-block:: jinja | ||
166 | |||
167 | {{ 'TWIG'|lower }} | ||
168 | {{ now|date('d/m/Y') }} | ||
169 | |||
170 | is compiled to something like the following:: | ||
171 | |||
172 | <?php echo strtolower('TWIG') ?> | ||
173 | <?php echo twig_date_format_filter($now, 'd/m/Y') ?> | ||
174 | |||
175 | The ``Twig_SimpleFilter`` class takes an array of options as its last | ||
176 | argument:: | ||
177 | |||
178 | $filter = new Twig_SimpleFilter('rot13', 'str_rot13', $options); | ||
179 | |||
180 | Environment aware Filters | ||
181 | ~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
182 | |||
183 | If you want to access the current environment instance in your filter, set the | ||
184 | ``needs_environment`` option to ``true``; Twig will pass the current | ||
185 | environment as the first argument to the filter call:: | ||
186 | |||
187 | $filter = new Twig_SimpleFilter('rot13', function (Twig_Environment $env, $string) { | ||
188 | // get the current charset for instance | ||
189 | $charset = $env->getCharset(); | ||
190 | |||
191 | return str_rot13($string); | ||
192 | }, array('needs_environment' => true)); | ||
193 | |||
194 | Context aware Filters | ||
195 | ~~~~~~~~~~~~~~~~~~~~~ | ||
196 | |||
197 | If you want to access the current context in your filter, set the | ||
198 | ``needs_context`` option to ``true``; Twig will pass the current context as | ||
199 | the first argument to the filter call (or the second one if | ||
200 | ``needs_environment`` is also set to ``true``):: | ||
201 | |||
202 | $filter = new Twig_SimpleFilter('rot13', function ($context, $string) { | ||
203 | // ... | ||
204 | }, array('needs_context' => true)); | ||
205 | |||
206 | $filter = new Twig_SimpleFilter('rot13', function (Twig_Environment $env, $context, $string) { | ||
207 | // ... | ||
208 | }, array('needs_context' => true, 'needs_environment' => true)); | ||
209 | |||
210 | Automatic Escaping | ||
211 | ~~~~~~~~~~~~~~~~~~ | ||
212 | |||
213 | If automatic escaping is enabled, the output of the filter may be escaped | ||
214 | before printing. If your filter acts as an escaper (or explicitly outputs html | ||
215 | or JavaScript code), you will want the raw output to be printed. In such a | ||
216 | case, set the ``is_safe`` option:: | ||
217 | |||
218 | $filter = new Twig_SimpleFilter('nl2br', 'nl2br', array('is_safe' => array('html'))); | ||
219 | |||
220 | Some filters may need to work on input that is already escaped or safe, for | ||
221 | example when adding (safe) html tags to originally unsafe output. In such a | ||
222 | case, set the ``pre_escape`` option to escape the input data before it is run | ||
223 | through your filter:: | ||
224 | |||
225 | $filter = new Twig_SimpleFilter('somefilter', 'somefilter', array('pre_escape' => 'html', 'is_safe' => array('html'))); | ||
226 | |||
227 | Dynamic Filters | ||
228 | ~~~~~~~~~~~~~~~ | ||
229 | |||
230 | A filter name containing the special ``*`` character is a dynamic filter as | ||
231 | the ``*`` can be any string:: | ||
232 | |||
233 | $filter = new Twig_SimpleFilter('*_path', function ($name, $arguments) { | ||
234 | // ... | ||
235 | }); | ||
236 | |||
237 | The following filters will be matched by the above defined dynamic filter: | ||
238 | |||
239 | * ``product_path`` | ||
240 | * ``category_path`` | ||
241 | |||
242 | A dynamic filter can define more than one dynamic parts:: | ||
243 | |||
244 | $filter = new Twig_SimpleFilter('*_path_*', function ($name, $suffix, $arguments) { | ||
245 | // ... | ||
246 | }); | ||
247 | |||
248 | The filter will receive all dynamic part values before the normal filter | ||
249 | arguments, but after the environment and the context. For instance, a call to | ||
250 | ``'foo'|a_path_b()`` will result in the following arguments to be passed to | ||
251 | the filter: ``('a', 'b', 'foo')``. | ||
252 | |||
253 | Functions | ||
254 | --------- | ||
255 | |||
256 | Functions are defined in the exact same way as filters, but you need to create | ||
257 | an instance of ``Twig_SimpleFunction``:: | ||
258 | |||
259 | $twig = new Twig_Environment($loader); | ||
260 | $function = new Twig_SimpleFunction('function_name', function () { | ||
261 | // ... | ||
262 | }); | ||
263 | $twig->addFunction($function); | ||
264 | |||
265 | Functions support the same features as filters, except for the ``pre_escape`` | ||
266 | and ``preserves_safety`` options. | ||
267 | |||
268 | Tests | ||
269 | ----- | ||
270 | |||
271 | Tests are defined in the exact same way as filters and functions, but you need | ||
272 | to create an instance of ``Twig_SimpleTest``:: | ||
273 | |||
274 | $twig = new Twig_Environment($loader); | ||
275 | $test = new Twig_SimpleTest('test_name', function () { | ||
276 | // ... | ||
277 | }); | ||
278 | $twig->addTest($test); | ||
279 | |||
280 | Tests allow you to create custom application specific logic for evaluating | ||
281 | boolean conditions. As a simple, example let's create a Twig test that checks if | ||
282 | objects are 'red':: | ||
283 | |||
284 | $twig = new Twig_Environment($loader) | ||
285 | $test = new Twig_SimpleTest('red', function ($value) { | ||
286 | if (isset($value->color) && $value->color == 'red') { | ||
287 | return true; | ||
288 | } | ||
289 | if (isset($value->paint) && $value->paint == 'red') { | ||
290 | return true; | ||
291 | } | ||
292 | return false; | ||
293 | }); | ||
294 | $twig->addTest($test); | ||
295 | |||
296 | Test functions should always return true/false. | ||
297 | |||
298 | When creating tests you can use the ``node_class`` option to provide custom test | ||
299 | compilation. This is useful if your test can be compiled into PHP primitives. | ||
300 | This is used by many of the tests built into Twig:: | ||
301 | |||
302 | $twig = new Twig_Environment($loader) | ||
303 | $test = new Twig_SimpleTest( | ||
304 | 'odd', | ||
305 | null, | ||
306 | array('node_class' => 'Twig_Node_Expression_Test_Odd')); | ||
307 | $twig->addTest($test); | ||
308 | |||
309 | class Twig_Node_Expression_Test_Odd extends Twig_Node_Expression_Test | ||
310 | { | ||
311 | public function compile(Twig_Compiler $compiler) | ||
312 | { | ||
313 | $compiler | ||
314 | ->raw('(') | ||
315 | ->subcompile($this->getNode('node')) | ||
316 | ->raw(' % 2 == 1') | ||
317 | ->raw(')') | ||
318 | ; | ||
319 | } | ||
320 | } | ||
321 | |||
322 | The above example, shows how you can create tests that use a node class. The | ||
323 | node class has access to one sub-node called 'node'. This sub-node contains the | ||
324 | value that is being tested. When the ``odd`` filter is used in code like: | ||
325 | |||
326 | .. code-block:: jinja | ||
327 | |||
328 | {% if my_value is odd %} | ||
329 | |||
330 | The ``node`` sub-node will contain an expression of ``my_value``. Node based | ||
331 | tests also have access to the ``arguments`` node. This node will contain the | ||
332 | various other arguments that have been provided to your test. | ||
333 | |||
334 | Tags | ||
335 | ---- | ||
336 | |||
337 | One of the most exciting feature of a template engine like Twig is the | ||
338 | possibility to define new language constructs. This is also the most complex | ||
339 | feature as you need to understand how Twig's internals work. | ||
340 | |||
341 | Let's create a simple ``set`` tag that allows the definition of simple | ||
342 | variables from within a template. The tag can be used like follows: | ||
343 | |||
344 | .. code-block:: jinja | ||
345 | |||
346 | {% set name = "value" %} | ||
347 | |||
348 | {{ name }} | ||
349 | |||
350 | {# should output value #} | ||
351 | |||
352 | .. note:: | ||
353 | |||
354 | The ``set`` tag is part of the Core extension and as such is always | ||
355 | available. The built-in version is slightly more powerful and supports | ||
356 | multiple assignments by default (cf. the template designers chapter for | ||
357 | more information). | ||
358 | |||
359 | Three steps are needed to define a new tag: | ||
360 | |||
361 | * Defining a Token Parser class (responsible for parsing the template code); | ||
362 | |||
363 | * Defining a Node class (responsible for converting the parsed code to PHP); | ||
364 | |||
365 | * Registering the tag. | ||
366 | |||
367 | Registering a new tag | ||
368 | ~~~~~~~~~~~~~~~~~~~~~ | ||
369 | |||
370 | Adding a tag is as simple as calling the ``addTokenParser`` method on the | ||
371 | ``Twig_Environment`` instance:: | ||
372 | |||
373 | $twig = new Twig_Environment($loader); | ||
374 | $twig->addTokenParser(new Project_Set_TokenParser()); | ||
375 | |||
376 | Defining a Token Parser | ||
377 | ~~~~~~~~~~~~~~~~~~~~~~~ | ||
378 | |||
379 | Now, let's see the actual code of this class:: | ||
380 | |||
381 | class Project_Set_TokenParser extends Twig_TokenParser | ||
382 | { | ||
383 | public function parse(Twig_Token $token) | ||
384 | { | ||
385 | $parser = $this->parser; | ||
386 | $stream = $parser->getStream(); | ||
387 | |||
388 | $name = $stream->expect(Twig_Token::NAME_TYPE)->getValue(); | ||
389 | $stream->expect(Twig_Token::OPERATOR_TYPE, '='); | ||
390 | $value = $parser->getExpressionParser()->parseExpression(); | ||
391 | $stream->expect(Twig_Token::BLOCK_END_TYPE); | ||
392 | |||
393 | return new Project_Set_Node($name, $value, $token->getLine(), $this->getTag()); | ||
394 | } | ||
395 | |||
396 | public function getTag() | ||
397 | { | ||
398 | return 'set'; | ||
399 | } | ||
400 | } | ||
401 | |||
402 | The ``getTag()`` method must return the tag we want to parse, here ``set``. | ||
403 | |||
404 | The ``parse()`` method is invoked whenever the parser encounters a ``set`` | ||
405 | tag. It should return a ``Twig_Node`` instance that represents the node (the | ||
406 | ``Project_Set_Node`` calls creating is explained in the next section). | ||
407 | |||
408 | The parsing process is simplified thanks to a bunch of methods you can call | ||
409 | from the token stream (``$this->parser->getStream()``): | ||
410 | |||
411 | * ``getCurrent()``: Gets the current token in the stream. | ||
412 | |||
413 | * ``next()``: Moves to the next token in the stream, *but returns the old one*. | ||
414 | |||
415 | * ``test($type)``, ``test($value)`` or ``test($type, $value)``: Determines whether | ||
416 | the current token is of a particular type or value (or both). The value may be an | ||
417 | array of several possible values. | ||
418 | |||
419 | * ``expect($type[, $value[, $message]])``: If the current token isn't of the given | ||
420 | type/value a syntax error is thrown. Otherwise, if the type and value are correct, | ||
421 | the token is returned and the stream moves to the next token. | ||
422 | |||
423 | * ``look()``: Looks a the next token without consuming it. | ||
424 | |||
425 | Parsing expressions is done by calling the ``parseExpression()`` like we did for | ||
426 | the ``set`` tag. | ||
427 | |||
428 | .. tip:: | ||
429 | |||
430 | Reading the existing ``TokenParser`` classes is the best way to learn all | ||
431 | the nitty-gritty details of the parsing process. | ||
432 | |||
433 | Defining a Node | ||
434 | ~~~~~~~~~~~~~~~ | ||
435 | |||
436 | The ``Project_Set_Node`` class itself is rather simple:: | ||
437 | |||
438 | class Project_Set_Node extends Twig_Node | ||
439 | { | ||
440 | public function __construct($name, Twig_Node_Expression $value, $line, $tag = null) | ||
441 | { | ||
442 | parent::__construct(array('value' => $value), array('name' => $name), $line, $tag); | ||
443 | } | ||
444 | |||
445 | public function compile(Twig_Compiler $compiler) | ||
446 | { | ||
447 | $compiler | ||
448 | ->addDebugInfo($this) | ||
449 | ->write('$context[\''.$this->getAttribute('name').'\'] = ') | ||
450 | ->subcompile($this->getNode('value')) | ||
451 | ->raw(";\n") | ||
452 | ; | ||
453 | } | ||
454 | } | ||
455 | |||
456 | The compiler implements a fluid interface and provides methods that helps the | ||
457 | developer generate beautiful and readable PHP code: | ||
458 | |||
459 | * ``subcompile()``: Compiles a node. | ||
460 | |||
461 | * ``raw()``: Writes the given string as is. | ||
462 | |||
463 | * ``write()``: Writes the given string by adding indentation at the beginning | ||
464 | of each line. | ||
465 | |||
466 | * ``string()``: Writes a quoted string. | ||
467 | |||
468 | * ``repr()``: Writes a PHP representation of a given value (see | ||
469 | ``Twig_Node_For`` for a usage example). | ||
470 | |||
471 | * ``addDebugInfo()``: Adds the line of the original template file related to | ||
472 | the current node as a comment. | ||
473 | |||
474 | * ``indent()``: Indents the generated code (see ``Twig_Node_Block`` for a | ||
475 | usage example). | ||
476 | |||
477 | * ``outdent()``: Outdents the generated code (see ``Twig_Node_Block`` for a | ||
478 | usage example). | ||
479 | |||
480 | .. _creating_extensions: | ||
481 | |||
482 | Creating an Extension | ||
483 | --------------------- | ||
484 | |||
485 | The main motivation for writing an extension is to move often used code into a | ||
486 | reusable class like adding support for internationalization. An extension can | ||
487 | define tags, filters, tests, operators, global variables, functions, and node | ||
488 | visitors. | ||
489 | |||
490 | Creating an extension also makes for a better separation of code that is | ||
491 | executed at compilation time and code needed at runtime. As such, it makes | ||
492 | your code faster. | ||
493 | |||
494 | Most of the time, it is useful to create a single extension for your project, | ||
495 | to host all the specific tags and filters you want to add to Twig. | ||
496 | |||
497 | .. tip:: | ||
498 | |||
499 | When packaging your code into an extension, Twig is smart enough to | ||
500 | recompile your templates whenever you make a change to it (when | ||
501 | ``auto_reload`` is enabled). | ||
502 | |||
503 | .. note:: | ||
504 | |||
505 | Before writing your own extensions, have a look at the Twig official | ||
506 | extension repository: http://github.com/fabpot/Twig-extensions. | ||
507 | |||
508 | An extension is a class that implements the following interface:: | ||
509 | |||
510 | interface Twig_ExtensionInterface | ||
511 | { | ||
512 | /** | ||
513 | * Initializes the runtime environment. | ||
514 | * | ||
515 | * This is where you can load some file that contains filter functions for instance. | ||
516 | * | ||
517 | * @param Twig_Environment $environment The current Twig_Environment instance | ||
518 | */ | ||
519 | function initRuntime(Twig_Environment $environment); | ||
520 | |||
521 | /** | ||
522 | * Returns the token parser instances to add to the existing list. | ||
523 | * | ||
524 | * @return array An array of Twig_TokenParserInterface or Twig_TokenParserBrokerInterface instances | ||
525 | */ | ||
526 | function getTokenParsers(); | ||
527 | |||
528 | /** | ||
529 | * Returns the node visitor instances to add to the existing list. | ||
530 | * | ||
531 | * @return array An array of Twig_NodeVisitorInterface instances | ||
532 | */ | ||
533 | function getNodeVisitors(); | ||
534 | |||
535 | /** | ||
536 | * Returns a list of filters to add to the existing list. | ||
537 | * | ||
538 | * @return array An array of filters | ||
539 | */ | ||
540 | function getFilters(); | ||
541 | |||
542 | /** | ||
543 | * Returns a list of tests to add to the existing list. | ||
544 | * | ||
545 | * @return array An array of tests | ||
546 | */ | ||
547 | function getTests(); | ||
548 | |||
549 | /** | ||
550 | * Returns a list of functions to add to the existing list. | ||
551 | * | ||
552 | * @return array An array of functions | ||
553 | */ | ||
554 | function getFunctions(); | ||
555 | |||
556 | /** | ||
557 | * Returns a list of operators to add to the existing list. | ||
558 | * | ||
559 | * @return array An array of operators | ||
560 | */ | ||
561 | function getOperators(); | ||
562 | |||
563 | /** | ||
564 | * Returns a list of global variables to add to the existing list. | ||
565 | * | ||
566 | * @return array An array of global variables | ||
567 | */ | ||
568 | function getGlobals(); | ||
569 | |||
570 | /** | ||
571 | * Returns the name of the extension. | ||
572 | * | ||
573 | * @return string The extension name | ||
574 | */ | ||
575 | function getName(); | ||
576 | } | ||
577 | |||
578 | To keep your extension class clean and lean, it can inherit from the built-in | ||
579 | ``Twig_Extension`` class instead of implementing the whole interface. That | ||
580 | way, you just need to implement the ``getName()`` method as the | ||
581 | ``Twig_Extension`` provides empty implementations for all other methods. | ||
582 | |||
583 | The ``getName()`` method must return a unique identifier for your extension. | ||
584 | |||
585 | Now, with this information in mind, let's create the most basic extension | ||
586 | possible:: | ||
587 | |||
588 | class Project_Twig_Extension extends Twig_Extension | ||
589 | { | ||
590 | public function getName() | ||
591 | { | ||
592 | return 'project'; | ||
593 | } | ||
594 | } | ||
595 | |||
596 | .. note:: | ||
597 | |||
598 | Of course, this extension does nothing for now. We will customize it in | ||
599 | the next sections. | ||
600 | |||
601 | Twig does not care where you save your extension on the filesystem, as all | ||
602 | extensions must be registered explicitly to be available in your templates. | ||
603 | |||
604 | You can register an extension by using the ``addExtension()`` method on your | ||
605 | main ``Environment`` object:: | ||
606 | |||
607 | $twig = new Twig_Environment($loader); | ||
608 | $twig->addExtension(new Project_Twig_Extension()); | ||
609 | |||
610 | Of course, you need to first load the extension file by either using | ||
611 | ``require_once()`` or by using an autoloader (see `spl_autoload_register()`_). | ||
612 | |||
613 | .. tip:: | ||
614 | |||
615 | The bundled extensions are great examples of how extensions work. | ||
616 | |||
617 | Globals | ||
618 | ~~~~~~~ | ||
619 | |||
620 | Global variables can be registered in an extension via the ``getGlobals()`` | ||
621 | method:: | ||
622 | |||
623 | class Project_Twig_Extension extends Twig_Extension | ||
624 | { | ||
625 | public function getGlobals() | ||
626 | { | ||
627 | return array( | ||
628 | 'text' => new Text(), | ||
629 | ); | ||
630 | } | ||
631 | |||
632 | // ... | ||
633 | } | ||
634 | |||
635 | Functions | ||
636 | ~~~~~~~~~ | ||
637 | |||
638 | Functions can be registered in an extension via the ``getFunctions()`` | ||
639 | method:: | ||
640 | |||
641 | class Project_Twig_Extension extends Twig_Extension | ||
642 | { | ||
643 | public function getFunctions() | ||
644 | { | ||
645 | return array( | ||
646 | new Twig_SimpleFunction('lipsum', 'generate_lipsum'), | ||
647 | ); | ||
648 | } | ||
649 | |||
650 | // ... | ||
651 | } | ||
652 | |||
653 | Filters | ||
654 | ~~~~~~~ | ||
655 | |||
656 | To add a filter to an extension, you need to override the ``getFilters()`` | ||
657 | method. This method must return an array of filters to add to the Twig | ||
658 | environment:: | ||
659 | |||
660 | class Project_Twig_Extension extends Twig_Extension | ||
661 | { | ||
662 | public function getFilters() | ||
663 | { | ||
664 | return array( | ||
665 | new Twig_SimpleFilter('rot13', 'str_rot13'), | ||
666 | ); | ||
667 | } | ||
668 | |||
669 | // ... | ||
670 | } | ||
671 | |||
672 | Tags | ||
673 | ~~~~ | ||
674 | |||
675 | Adding a tag in an extension can be done by overriding the | ||
676 | ``getTokenParsers()`` method. This method must return an array of tags to add | ||
677 | to the Twig environment:: | ||
678 | |||
679 | class Project_Twig_Extension extends Twig_Extension | ||
680 | { | ||
681 | public function getTokenParsers() | ||
682 | { | ||
683 | return array(new Project_Set_TokenParser()); | ||
684 | } | ||
685 | |||
686 | // ... | ||
687 | } | ||
688 | |||
689 | In the above code, we have added a single new tag, defined by the | ||
690 | ``Project_Set_TokenParser`` class. The ``Project_Set_TokenParser`` class is | ||
691 | responsible for parsing the tag and compiling it to PHP. | ||
692 | |||
693 | Operators | ||
694 | ~~~~~~~~~ | ||
695 | |||
696 | The ``getOperators()`` methods allows to add new operators. Here is how to add | ||
697 | ``!``, ``||``, and ``&&`` operators:: | ||
698 | |||
699 | class Project_Twig_Extension extends Twig_Extension | ||
700 | { | ||
701 | public function getOperators() | ||
702 | { | ||
703 | return array( | ||
704 | array( | ||
705 | '!' => array('precedence' => 50, 'class' => 'Twig_Node_Expression_Unary_Not'), | ||
706 | ), | ||
707 | array( | ||
708 | '||' => array('precedence' => 10, 'class' => 'Twig_Node_Expression_Binary_Or', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT), | ||
709 | '&&' => array('precedence' => 15, 'class' => 'Twig_Node_Expression_Binary_And', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT), | ||
710 | ), | ||
711 | ); | ||
712 | } | ||
713 | |||
714 | // ... | ||
715 | } | ||
716 | |||
717 | Tests | ||
718 | ~~~~~ | ||
719 | |||
720 | The ``getTests()`` methods allows to add new test functions:: | ||
721 | |||
722 | class Project_Twig_Extension extends Twig_Extension | ||
723 | { | ||
724 | public function getTests() | ||
725 | { | ||
726 | return array( | ||
727 | new Twig_SimpleTest('even', 'twig_test_even'), | ||
728 | ); | ||
729 | } | ||
730 | |||
731 | // ... | ||
732 | } | ||
733 | |||
734 | Overloading | ||
735 | ----------- | ||
736 | |||
737 | To overload an already defined filter, test, operator, global variable, or | ||
738 | function, define it again **as late as possible**:: | ||
739 | |||
740 | $twig = new Twig_Environment($loader); | ||
741 | $twig->addFilter(new Twig_SimpleFilter('date', function ($timestamp, $format = 'F j, Y H:i') { | ||
742 | // do something different from the built-in date filter | ||
743 | })); | ||
744 | |||
745 | Here, we have overloaded the built-in ``date`` filter with a custom one. | ||
746 | |||
747 | That also works with an extension:: | ||
748 | |||
749 | class MyCoreExtension extends Twig_Extension | ||
750 | { | ||
751 | public function getFilters() | ||
752 | { | ||
753 | return array( | ||
754 | new Twig_SimpleFilter('date', array($this, 'dateFilter')), | ||
755 | ); | ||
756 | } | ||
757 | |||
758 | public function dateFilter($timestamp, $format = 'F j, Y H:i') | ||
759 | { | ||
760 | // do something different from the built-in date filter | ||
761 | } | ||
762 | |||
763 | public function getName() | ||
764 | { | ||
765 | return 'project'; | ||
766 | } | ||
767 | } | ||
768 | |||
769 | $twig = new Twig_Environment($loader); | ||
770 | $twig->addExtension(new MyCoreExtension()); | ||
771 | |||
772 | .. caution:: | ||
773 | |||
774 | Note that overloading the built-in Twig elements is not recommended as it | ||
775 | might be confusing. | ||
776 | |||
777 | Testing an Extension | ||
778 | -------------------- | ||
779 | |||
780 | Functional Tests | ||
781 | ~~~~~~~~~~~~~~~~ | ||
782 | |||
783 | You can create functional tests for extensions simply by creating the | ||
784 | following file structure in your test directory:: | ||
785 | |||
786 | Fixtures/ | ||
787 | filters/ | ||
788 | foo.test | ||
789 | bar.test | ||
790 | functions/ | ||
791 | foo.test | ||
792 | bar.test | ||
793 | tags/ | ||
794 | foo.test | ||
795 | bar.test | ||
796 | IntegrationTest.php | ||
797 | |||
798 | The ``IntegrationTest.php`` file should look like this:: | ||
799 | |||
800 | class Project_Tests_IntegrationTest extends Twig_Test_IntegrationTestCase | ||
801 | { | ||
802 | public function getExtensions() | ||
803 | { | ||
804 | return array( | ||
805 | new Project_Twig_Extension1(), | ||
806 | new Project_Twig_Extension2(), | ||
807 | ); | ||
808 | } | ||
809 | |||
810 | public function getFixturesDir() | ||
811 | { | ||
812 | return dirname(__FILE__).'/Fixtures/'; | ||
813 | } | ||
814 | } | ||
815 | |||
816 | Fixtures examples can be found within the Twig repository | ||
817 | `tests/Twig/Fixtures`_ directory. | ||
818 | |||
819 | Node Tests | ||
820 | ~~~~~~~~~~ | ||
821 | |||
822 | Testing the node visitors can be complex, so extend your test cases from | ||
823 | ``Twig_Test_NodeTestCase``. Examples can be found in the Twig repository | ||
824 | `tests/Twig/Node`_ directory. | ||
825 | |||
826 | .. _`spl_autoload_register()`: http://www.php.net/spl_autoload_register | ||
827 | .. _`rot13`: http://www.php.net/manual/en/function.str-rot13.php | ||
828 | .. _`tests/Twig/Fixtures`: https://github.com/fabpot/Twig/tree/master/test/Twig/Tests/Fixtures | ||
829 | .. _`tests/Twig/Node`: https://github.com/fabpot/Twig/tree/master/test/Twig/Tests/Node | ||
diff --git a/vendor/twig/twig/doc/advanced_legacy.rst b/vendor/twig/twig/doc/advanced_legacy.rst new file mode 100644 index 00000000..3d34f932 --- /dev/null +++ b/vendor/twig/twig/doc/advanced_legacy.rst | |||
@@ -0,0 +1,887 @@ | |||
1 | Extending Twig | ||
2 | ============== | ||
3 | |||
4 | .. caution:: | ||
5 | |||
6 | This section describes how to extends Twig for versions **older than | ||
7 | 1.12**. If you are using a newer version, read the :doc:`newer<advanced>` | ||
8 | chapter instead. | ||
9 | |||
10 | Twig can be extended in many ways; you can add extra tags, filters, tests, | ||
11 | operators, global variables, and functions. You can even extend the parser | ||
12 | itself with node visitors. | ||
13 | |||
14 | .. note:: | ||
15 | |||
16 | The first section of this chapter describes how to extend Twig easily. If | ||
17 | you want to reuse your changes in different projects or if you want to | ||
18 | share them with others, you should then create an extension as described | ||
19 | in the following section. | ||
20 | |||
21 | .. caution:: | ||
22 | |||
23 | When extending Twig by calling methods on the Twig environment instance, | ||
24 | Twig won't be able to recompile your templates when the PHP code is | ||
25 | updated. To see your changes in real-time, either disable template caching | ||
26 | or package your code into an extension (see the next section of this | ||
27 | chapter). | ||
28 | |||
29 | Before extending Twig, you must understand the differences between all the | ||
30 | different possible extension points and when to use them. | ||
31 | |||
32 | First, remember that Twig has two main language constructs: | ||
33 | |||
34 | * ``{{ }}``: used to print the result of an expression evaluation; | ||
35 | |||
36 | * ``{% %}``: used to execute statements. | ||
37 | |||
38 | To understand why Twig exposes so many extension points, let's see how to | ||
39 | implement a *Lorem ipsum* generator (it needs to know the number of words to | ||
40 | generate). | ||
41 | |||
42 | You can use a ``lipsum`` *tag*: | ||
43 | |||
44 | .. code-block:: jinja | ||
45 | |||
46 | {% lipsum 40 %} | ||
47 | |||
48 | That works, but using a tag for ``lipsum`` is not a good idea for at least | ||
49 | three main reasons: | ||
50 | |||
51 | * ``lipsum`` is not a language construct; | ||
52 | * The tag outputs something; | ||
53 | * The tag is not flexible as you cannot use it in an expression: | ||
54 | |||
55 | .. code-block:: jinja | ||
56 | |||
57 | {{ 'some text' ~ {% lipsum 40 %} ~ 'some more text' }} | ||
58 | |||
59 | In fact, you rarely need to create tags; and that's good news because tags are | ||
60 | the most complex extension point of Twig. | ||
61 | |||
62 | Now, let's use a ``lipsum`` *filter*: | ||
63 | |||
64 | .. code-block:: jinja | ||
65 | |||
66 | {{ 40|lipsum }} | ||
67 | |||
68 | Again, it works, but it looks weird. A filter transforms the passed value to | ||
69 | something else but here we use the value to indicate the number of words to | ||
70 | generate (so, ``40`` is an argument of the filter, not the value we want to | ||
71 | transform). | ||
72 | |||
73 | Next, let's use a ``lipsum`` *function*: | ||
74 | |||
75 | .. code-block:: jinja | ||
76 | |||
77 | {{ lipsum(40) }} | ||
78 | |||
79 | Here we go. For this specific example, the creation of a function is the | ||
80 | extension point to use. And you can use it anywhere an expression is accepted: | ||
81 | |||
82 | .. code-block:: jinja | ||
83 | |||
84 | {{ 'some text' ~ ipsum(40) ~ 'some more text' }} | ||
85 | |||
86 | {% set ipsum = ipsum(40) %} | ||
87 | |||
88 | Last but not the least, you can also use a *global* object with a method able | ||
89 | to generate lorem ipsum text: | ||
90 | |||
91 | .. code-block:: jinja | ||
92 | |||
93 | {{ text.lipsum(40) }} | ||
94 | |||
95 | As a rule of thumb, use functions for frequently used features and global | ||
96 | objects for everything else. | ||
97 | |||
98 | Keep in mind the following when you want to extend Twig: | ||
99 | |||
100 | ========== ========================== ========== ========================= | ||
101 | What? Implementation difficulty? How often? When? | ||
102 | ========== ========================== ========== ========================= | ||
103 | *macro* trivial frequent Content generation | ||
104 | *global* trivial frequent Helper object | ||
105 | *function* trivial frequent Content generation | ||
106 | *filter* trivial frequent Value transformation | ||
107 | *tag* complex rare DSL language construct | ||
108 | *test* trivial rare Boolean decision | ||
109 | *operator* trivial rare Values transformation | ||
110 | ========== ========================== ========== ========================= | ||
111 | |||
112 | Globals | ||
113 | ------- | ||
114 | |||
115 | A global variable is like any other template variable, except that it's | ||
116 | available in all templates and macros:: | ||
117 | |||
118 | $twig = new Twig_Environment($loader); | ||
119 | $twig->addGlobal('text', new Text()); | ||
120 | |||
121 | You can then use the ``text`` variable anywhere in a template: | ||
122 | |||
123 | .. code-block:: jinja | ||
124 | |||
125 | {{ text.lipsum(40) }} | ||
126 | |||
127 | Filters | ||
128 | ------- | ||
129 | |||
130 | A filter is a regular PHP function or an object method that takes the left | ||
131 | side of the filter (before the pipe ``|``) as first argument and the extra | ||
132 | arguments passed to the filter (within parentheses ``()``) as extra arguments. | ||
133 | |||
134 | Defining a filter is as easy as associating the filter name with a PHP | ||
135 | callable. For instance, let's say you have the following code in a template: | ||
136 | |||
137 | .. code-block:: jinja | ||
138 | |||
139 | {{ 'TWIG'|lower }} | ||
140 | |||
141 | When compiling this template to PHP, Twig looks for the PHP callable | ||
142 | associated with the ``lower`` filter. The ``lower`` filter is a built-in Twig | ||
143 | filter, and it is simply mapped to the PHP ``strtolower()`` function. After | ||
144 | compilation, the generated PHP code is roughly equivalent to: | ||
145 | |||
146 | .. code-block:: html+php | ||
147 | |||
148 | <?php echo strtolower('TWIG') ?> | ||
149 | |||
150 | As you can see, the ``'TWIG'`` string is passed as a first argument to the PHP | ||
151 | function. | ||
152 | |||
153 | A filter can also take extra arguments like in the following example: | ||
154 | |||
155 | .. code-block:: jinja | ||
156 | |||
157 | {{ now|date('d/m/Y') }} | ||
158 | |||
159 | In this case, the extra arguments are passed to the function after the main | ||
160 | argument, and the compiled code is equivalent to: | ||
161 | |||
162 | .. code-block:: html+php | ||
163 | |||
164 | <?php echo twig_date_format_filter($now, 'd/m/Y') ?> | ||
165 | |||
166 | Let's see how to create a new filter. | ||
167 | |||
168 | In this section, we will create a ``rot13`` filter, which should return the | ||
169 | `rot13`_ transformation of a string. Here is an example of its usage and the | ||
170 | expected output: | ||
171 | |||
172 | .. code-block:: jinja | ||
173 | |||
174 | {{ "Twig"|rot13 }} | ||
175 | |||
176 | {# should displays Gjvt #} | ||
177 | |||
178 | Adding a filter is as simple as calling the ``addFilter()`` method on the | ||
179 | ``Twig_Environment`` instance:: | ||
180 | |||
181 | $twig = new Twig_Environment($loader); | ||
182 | $twig->addFilter('rot13', new Twig_Filter_Function('str_rot13')); | ||
183 | |||
184 | The second argument of ``addFilter()`` is an instance of ``Twig_Filter``. | ||
185 | Here, we use ``Twig_Filter_Function`` as the filter is a PHP function. The | ||
186 | first argument passed to the ``Twig_Filter_Function`` constructor is the name | ||
187 | of the PHP function to call, here ``str_rot13``, a native PHP function. | ||
188 | |||
189 | Let's say I now want to be able to add a prefix before the converted string: | ||
190 | |||
191 | .. code-block:: jinja | ||
192 | |||
193 | {{ "Twig"|rot13('prefix_') }} | ||
194 | |||
195 | {# should displays prefix_Gjvt #} | ||
196 | |||
197 | As the PHP ``str_rot13()`` function does not support this requirement, let's | ||
198 | create a new PHP function:: | ||
199 | |||
200 | function project_compute_rot13($string, $prefix = '') | ||
201 | { | ||
202 | return $prefix.str_rot13($string); | ||
203 | } | ||
204 | |||
205 | As you can see, the ``prefix`` argument of the filter is passed as an extra | ||
206 | argument to the ``project_compute_rot13()`` function. | ||
207 | |||
208 | Adding this filter is as easy as before:: | ||
209 | |||
210 | $twig->addFilter('rot13', new Twig_Filter_Function('project_compute_rot13')); | ||
211 | |||
212 | For better encapsulation, a filter can also be defined as a static method of a | ||
213 | class. The ``Twig_Filter_Function`` class can also be used to register such | ||
214 | static methods as filters:: | ||
215 | |||
216 | $twig->addFilter('rot13', new Twig_Filter_Function('SomeClass::rot13Filter')); | ||
217 | |||
218 | .. tip:: | ||
219 | |||
220 | In an extension, you can also define a filter as a static method of the | ||
221 | extension class. | ||
222 | |||
223 | Environment aware Filters | ||
224 | ~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
225 | |||
226 | The ``Twig_Filter`` classes take options as their last argument. For instance, | ||
227 | if you want access to the current environment instance in your filter, set the | ||
228 | ``needs_environment`` option to ``true``:: | ||
229 | |||
230 | $filter = new Twig_Filter_Function('str_rot13', array('needs_environment' => true)); | ||
231 | |||
232 | Twig will then pass the current environment as the first argument to the | ||
233 | filter call:: | ||
234 | |||
235 | function twig_compute_rot13(Twig_Environment $env, $string) | ||
236 | { | ||
237 | // get the current charset for instance | ||
238 | $charset = $env->getCharset(); | ||
239 | |||
240 | return str_rot13($string); | ||
241 | } | ||
242 | |||
243 | Automatic Escaping | ||
244 | ~~~~~~~~~~~~~~~~~~ | ||
245 | |||
246 | If automatic escaping is enabled, the output of the filter may be escaped | ||
247 | before printing. If your filter acts as an escaper (or explicitly outputs html | ||
248 | or javascript code), you will want the raw output to be printed. In such a | ||
249 | case, set the ``is_safe`` option:: | ||
250 | |||
251 | $filter = new Twig_Filter_Function('nl2br', array('is_safe' => array('html'))); | ||
252 | |||
253 | Some filters may need to work on input that is already escaped or safe, for | ||
254 | example when adding (safe) html tags to originally unsafe output. In such a | ||
255 | case, set the ``pre_escape`` option to escape the input data before it is run | ||
256 | through your filter:: | ||
257 | |||
258 | $filter = new Twig_Filter_Function('somefilter', array('pre_escape' => 'html', 'is_safe' => array('html'))); | ||
259 | |||
260 | Dynamic Filters | ||
261 | ~~~~~~~~~~~~~~~ | ||
262 | |||
263 | .. versionadded:: 1.5 | ||
264 | Dynamic filters support was added in Twig 1.5. | ||
265 | |||
266 | A filter name containing the special ``*`` character is a dynamic filter as | ||
267 | the ``*`` can be any string:: | ||
268 | |||
269 | $twig->addFilter('*_path_*', new Twig_Filter_Function('twig_path')); | ||
270 | |||
271 | function twig_path($name, $arguments) | ||
272 | { | ||
273 | // ... | ||
274 | } | ||
275 | |||
276 | The following filters will be matched by the above defined dynamic filter: | ||
277 | |||
278 | * ``product_path`` | ||
279 | * ``category_path`` | ||
280 | |||
281 | A dynamic filter can define more than one dynamic parts:: | ||
282 | |||
283 | $twig->addFilter('*_path_*', new Twig_Filter_Function('twig_path')); | ||
284 | |||
285 | function twig_path($name, $suffix, $arguments) | ||
286 | { | ||
287 | // ... | ||
288 | } | ||
289 | |||
290 | The filter will receive all dynamic part values before the normal filters | ||
291 | arguments. For instance, a call to ``'foo'|a_path_b()`` will result in the | ||
292 | following PHP call: ``twig_path('a', 'b', 'foo')``. | ||
293 | |||
294 | Functions | ||
295 | --------- | ||
296 | |||
297 | A function is a regular PHP function or an object method that can be called from | ||
298 | templates. | ||
299 | |||
300 | .. code-block:: jinja | ||
301 | |||
302 | {{ constant("DATE_W3C") }} | ||
303 | |||
304 | When compiling this template to PHP, Twig looks for the PHP callable | ||
305 | associated with the ``constant`` function. The ``constant`` function is a built-in Twig | ||
306 | function, and it is simply mapped to the PHP ``constant()`` function. After | ||
307 | compilation, the generated PHP code is roughly equivalent to: | ||
308 | |||
309 | .. code-block:: html+php | ||
310 | |||
311 | <?php echo constant('DATE_W3C') ?> | ||
312 | |||
313 | Adding a function is similar to adding a filter. This can be done by calling the | ||
314 | ``addFunction()`` method on the ``Twig_Environment`` instance:: | ||
315 | |||
316 | $twig = new Twig_Environment($loader); | ||
317 | $twig->addFunction('functionName', new Twig_Function_Function('someFunction')); | ||
318 | |||
319 | You can also expose extension methods as functions in your templates:: | ||
320 | |||
321 | // $this is an object that implements Twig_ExtensionInterface. | ||
322 | $twig = new Twig_Environment($loader); | ||
323 | $twig->addFunction('otherFunction', new Twig_Function_Method($this, 'someMethod')); | ||
324 | |||
325 | Functions also support ``needs_environment`` and ``is_safe`` parameters. | ||
326 | |||
327 | Dynamic Functions | ||
328 | ~~~~~~~~~~~~~~~~~ | ||
329 | |||
330 | .. versionadded:: 1.5 | ||
331 | Dynamic functions support was added in Twig 1.5. | ||
332 | |||
333 | A function name containing the special ``*`` character is a dynamic function | ||
334 | as the ``*`` can be any string:: | ||
335 | |||
336 | $twig->addFunction('*_path', new Twig_Function_Function('twig_path')); | ||
337 | |||
338 | function twig_path($name, $arguments) | ||
339 | { | ||
340 | // ... | ||
341 | } | ||
342 | |||
343 | The following functions will be matched by the above defined dynamic function: | ||
344 | |||
345 | * ``product_path`` | ||
346 | * ``category_path`` | ||
347 | |||
348 | A dynamic function can define more than one dynamic parts:: | ||
349 | |||
350 | $twig->addFilter('*_path_*', new Twig_Filter_Function('twig_path')); | ||
351 | |||
352 | function twig_path($name, $suffix, $arguments) | ||
353 | { | ||
354 | // ... | ||
355 | } | ||
356 | |||
357 | The function will receive all dynamic part values before the normal functions | ||
358 | arguments. For instance, a call to ``a_path_b('foo')`` will result in the | ||
359 | following PHP call: ``twig_path('a', 'b', 'foo')``. | ||
360 | |||
361 | Tags | ||
362 | ---- | ||
363 | |||
364 | One of the most exciting feature of a template engine like Twig is the | ||
365 | possibility to define new language constructs. This is also the most complex | ||
366 | feature as you need to understand how Twig's internals work. | ||
367 | |||
368 | Let's create a simple ``set`` tag that allows the definition of simple | ||
369 | variables from within a template. The tag can be used like follows: | ||
370 | |||
371 | .. code-block:: jinja | ||
372 | |||
373 | {% set name = "value" %} | ||
374 | |||
375 | {{ name }} | ||
376 | |||
377 | {# should output value #} | ||
378 | |||
379 | .. note:: | ||
380 | |||
381 | The ``set`` tag is part of the Core extension and as such is always | ||
382 | available. The built-in version is slightly more powerful and supports | ||
383 | multiple assignments by default (cf. the template designers chapter for | ||
384 | more information). | ||
385 | |||
386 | Three steps are needed to define a new tag: | ||
387 | |||
388 | * Defining a Token Parser class (responsible for parsing the template code); | ||
389 | |||
390 | * Defining a Node class (responsible for converting the parsed code to PHP); | ||
391 | |||
392 | * Registering the tag. | ||
393 | |||
394 | Registering a new tag | ||
395 | ~~~~~~~~~~~~~~~~~~~~~ | ||
396 | |||
397 | Adding a tag is as simple as calling the ``addTokenParser`` method on the | ||
398 | ``Twig_Environment`` instance:: | ||
399 | |||
400 | $twig = new Twig_Environment($loader); | ||
401 | $twig->addTokenParser(new Project_Set_TokenParser()); | ||
402 | |||
403 | Defining a Token Parser | ||
404 | ~~~~~~~~~~~~~~~~~~~~~~~ | ||
405 | |||
406 | Now, let's see the actual code of this class:: | ||
407 | |||
408 | class Project_Set_TokenParser extends Twig_TokenParser | ||
409 | { | ||
410 | public function parse(Twig_Token $token) | ||
411 | { | ||
412 | $lineno = $token->getLine(); | ||
413 | $name = $this->parser->getStream()->expect(Twig_Token::NAME_TYPE)->getValue(); | ||
414 | $this->parser->getStream()->expect(Twig_Token::OPERATOR_TYPE, '='); | ||
415 | $value = $this->parser->getExpressionParser()->parseExpression(); | ||
416 | |||
417 | $this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE); | ||
418 | |||
419 | return new Project_Set_Node($name, $value, $lineno, $this->getTag()); | ||
420 | } | ||
421 | |||
422 | public function getTag() | ||
423 | { | ||
424 | return 'set'; | ||
425 | } | ||
426 | } | ||
427 | |||
428 | The ``getTag()`` method must return the tag we want to parse, here ``set``. | ||
429 | |||
430 | The ``parse()`` method is invoked whenever the parser encounters a ``set`` | ||
431 | tag. It should return a ``Twig_Node`` instance that represents the node (the | ||
432 | ``Project_Set_Node`` calls creating is explained in the next section). | ||
433 | |||
434 | The parsing process is simplified thanks to a bunch of methods you can call | ||
435 | from the token stream (``$this->parser->getStream()``): | ||
436 | |||
437 | * ``getCurrent()``: Gets the current token in the stream. | ||
438 | |||
439 | * ``next()``: Moves to the next token in the stream, *but returns the old one*. | ||
440 | |||
441 | * ``test($type)``, ``test($value)`` or ``test($type, $value)``: Determines whether | ||
442 | the current token is of a particular type or value (or both). The value may be an | ||
443 | array of several possible values. | ||
444 | |||
445 | * ``expect($type[, $value[, $message]])``: If the current token isn't of the given | ||
446 | type/value a syntax error is thrown. Otherwise, if the type and value are correct, | ||
447 | the token is returned and the stream moves to the next token. | ||
448 | |||
449 | * ``look()``: Looks a the next token without consuming it. | ||
450 | |||
451 | Parsing expressions is done by calling the ``parseExpression()`` like we did for | ||
452 | the ``set`` tag. | ||
453 | |||
454 | .. tip:: | ||
455 | |||
456 | Reading the existing ``TokenParser`` classes is the best way to learn all | ||
457 | the nitty-gritty details of the parsing process. | ||
458 | |||
459 | Defining a Node | ||
460 | ~~~~~~~~~~~~~~~ | ||
461 | |||
462 | The ``Project_Set_Node`` class itself is rather simple:: | ||
463 | |||
464 | class Project_Set_Node extends Twig_Node | ||
465 | { | ||
466 | public function __construct($name, Twig_Node_Expression $value, $lineno, $tag = null) | ||
467 | { | ||
468 | parent::__construct(array('value' => $value), array('name' => $name), $lineno, $tag); | ||
469 | } | ||
470 | |||
471 | public function compile(Twig_Compiler $compiler) | ||
472 | { | ||
473 | $compiler | ||
474 | ->addDebugInfo($this) | ||
475 | ->write('$context[\''.$this->getAttribute('name').'\'] = ') | ||
476 | ->subcompile($this->getNode('value')) | ||
477 | ->raw(";\n") | ||
478 | ; | ||
479 | } | ||
480 | } | ||
481 | |||
482 | The compiler implements a fluid interface and provides methods that helps the | ||
483 | developer generate beautiful and readable PHP code: | ||
484 | |||
485 | * ``subcompile()``: Compiles a node. | ||
486 | |||
487 | * ``raw()``: Writes the given string as is. | ||
488 | |||
489 | * ``write()``: Writes the given string by adding indentation at the beginning | ||
490 | of each line. | ||
491 | |||
492 | * ``string()``: Writes a quoted string. | ||
493 | |||
494 | * ``repr()``: Writes a PHP representation of a given value (see | ||
495 | ``Twig_Node_For`` for a usage example). | ||
496 | |||
497 | * ``addDebugInfo()``: Adds the line of the original template file related to | ||
498 | the current node as a comment. | ||
499 | |||
500 | * ``indent()``: Indents the generated code (see ``Twig_Node_Block`` for a | ||
501 | usage example). | ||
502 | |||
503 | * ``outdent()``: Outdents the generated code (see ``Twig_Node_Block`` for a | ||
504 | usage example). | ||
505 | |||
506 | .. _creating_extensions: | ||
507 | |||
508 | Creating an Extension | ||
509 | --------------------- | ||
510 | |||
511 | The main motivation for writing an extension is to move often used code into a | ||
512 | reusable class like adding support for internationalization. An extension can | ||
513 | define tags, filters, tests, operators, global variables, functions, and node | ||
514 | visitors. | ||
515 | |||
516 | Creating an extension also makes for a better separation of code that is | ||
517 | executed at compilation time and code needed at runtime. As such, it makes | ||
518 | your code faster. | ||
519 | |||
520 | Most of the time, it is useful to create a single extension for your project, | ||
521 | to host all the specific tags and filters you want to add to Twig. | ||
522 | |||
523 | .. tip:: | ||
524 | |||
525 | When packaging your code into an extension, Twig is smart enough to | ||
526 | recompile your templates whenever you make a change to it (when the | ||
527 | ``auto_reload`` is enabled). | ||
528 | |||
529 | .. note:: | ||
530 | |||
531 | Before writing your own extensions, have a look at the Twig official | ||
532 | extension repository: http://github.com/fabpot/Twig-extensions. | ||
533 | |||
534 | An extension is a class that implements the following interface:: | ||
535 | |||
536 | interface Twig_ExtensionInterface | ||
537 | { | ||
538 | /** | ||
539 | * Initializes the runtime environment. | ||
540 | * | ||
541 | * This is where you can load some file that contains filter functions for instance. | ||
542 | * | ||
543 | * @param Twig_Environment $environment The current Twig_Environment instance | ||
544 | */ | ||
545 | function initRuntime(Twig_Environment $environment); | ||
546 | |||
547 | /** | ||
548 | * Returns the token parser instances to add to the existing list. | ||
549 | * | ||
550 | * @return array An array of Twig_TokenParserInterface or Twig_TokenParserBrokerInterface instances | ||
551 | */ | ||
552 | function getTokenParsers(); | ||
553 | |||
554 | /** | ||
555 | * Returns the node visitor instances to add to the existing list. | ||
556 | * | ||
557 | * @return array An array of Twig_NodeVisitorInterface instances | ||
558 | */ | ||
559 | function getNodeVisitors(); | ||
560 | |||
561 | /** | ||
562 | * Returns a list of filters to add to the existing list. | ||
563 | * | ||
564 | * @return array An array of filters | ||
565 | */ | ||
566 | function getFilters(); | ||
567 | |||
568 | /** | ||
569 | * Returns a list of tests to add to the existing list. | ||
570 | * | ||
571 | * @return array An array of tests | ||
572 | */ | ||
573 | function getTests(); | ||
574 | |||
575 | /** | ||
576 | * Returns a list of functions to add to the existing list. | ||
577 | * | ||
578 | * @return array An array of functions | ||
579 | */ | ||
580 | function getFunctions(); | ||
581 | |||
582 | /** | ||
583 | * Returns a list of operators to add to the existing list. | ||
584 | * | ||
585 | * @return array An array of operators | ||
586 | */ | ||
587 | function getOperators(); | ||
588 | |||
589 | /** | ||
590 | * Returns a list of global variables to add to the existing list. | ||
591 | * | ||
592 | * @return array An array of global variables | ||
593 | */ | ||
594 | function getGlobals(); | ||
595 | |||
596 | /** | ||
597 | * Returns the name of the extension. | ||
598 | * | ||
599 | * @return string The extension name | ||
600 | */ | ||
601 | function getName(); | ||
602 | } | ||
603 | |||
604 | To keep your extension class clean and lean, it can inherit from the built-in | ||
605 | ``Twig_Extension`` class instead of implementing the whole interface. That | ||
606 | way, you just need to implement the ``getName()`` method as the | ||
607 | ``Twig_Extension`` provides empty implementations for all other methods. | ||
608 | |||
609 | The ``getName()`` method must return a unique identifier for your extension. | ||
610 | |||
611 | Now, with this information in mind, let's create the most basic extension | ||
612 | possible:: | ||
613 | |||
614 | class Project_Twig_Extension extends Twig_Extension | ||
615 | { | ||
616 | public function getName() | ||
617 | { | ||
618 | return 'project'; | ||
619 | } | ||
620 | } | ||
621 | |||
622 | .. note:: | ||
623 | |||
624 | Of course, this extension does nothing for now. We will customize it in | ||
625 | the next sections. | ||
626 | |||
627 | Twig does not care where you save your extension on the filesystem, as all | ||
628 | extensions must be registered explicitly to be available in your templates. | ||
629 | |||
630 | You can register an extension by using the ``addExtension()`` method on your | ||
631 | main ``Environment`` object:: | ||
632 | |||
633 | $twig = new Twig_Environment($loader); | ||
634 | $twig->addExtension(new Project_Twig_Extension()); | ||
635 | |||
636 | Of course, you need to first load the extension file by either using | ||
637 | ``require_once()`` or by using an autoloader (see `spl_autoload_register()`_). | ||
638 | |||
639 | .. tip:: | ||
640 | |||
641 | The bundled extensions are great examples of how extensions work. | ||
642 | |||
643 | Globals | ||
644 | ~~~~~~~ | ||
645 | |||
646 | Global variables can be registered in an extension via the ``getGlobals()`` | ||
647 | method:: | ||
648 | |||
649 | class Project_Twig_Extension extends Twig_Extension | ||
650 | { | ||
651 | public function getGlobals() | ||
652 | { | ||
653 | return array( | ||
654 | 'text' => new Text(), | ||
655 | ); | ||
656 | } | ||
657 | |||
658 | // ... | ||
659 | } | ||
660 | |||
661 | Functions | ||
662 | ~~~~~~~~~ | ||
663 | |||
664 | Functions can be registered in an extension via the ``getFunctions()`` | ||
665 | method:: | ||
666 | |||
667 | class Project_Twig_Extension extends Twig_Extension | ||
668 | { | ||
669 | public function getFunctions() | ||
670 | { | ||
671 | return array( | ||
672 | 'lipsum' => new Twig_Function_Function('generate_lipsum'), | ||
673 | ); | ||
674 | } | ||
675 | |||
676 | // ... | ||
677 | } | ||
678 | |||
679 | Filters | ||
680 | ~~~~~~~ | ||
681 | |||
682 | To add a filter to an extension, you need to override the ``getFilters()`` | ||
683 | method. This method must return an array of filters to add to the Twig | ||
684 | environment:: | ||
685 | |||
686 | class Project_Twig_Extension extends Twig_Extension | ||
687 | { | ||
688 | public function getFilters() | ||
689 | { | ||
690 | return array( | ||
691 | 'rot13' => new Twig_Filter_Function('str_rot13'), | ||
692 | ); | ||
693 | } | ||
694 | |||
695 | // ... | ||
696 | } | ||
697 | |||
698 | As you can see in the above code, the ``getFilters()`` method returns an array | ||
699 | where keys are the name of the filters (``rot13``) and the values the | ||
700 | definition of the filter (``new Twig_Filter_Function('str_rot13')``). | ||
701 | |||
702 | As seen in the previous chapter, you can also define filters as static methods | ||
703 | on the extension class:: | ||
704 | |||
705 | $twig->addFilter('rot13', new Twig_Filter_Function('Project_Twig_Extension::rot13Filter')); | ||
706 | |||
707 | You can also use ``Twig_Filter_Method`` instead of ``Twig_Filter_Function`` | ||
708 | when defining a filter to use a method:: | ||
709 | |||
710 | class Project_Twig_Extension extends Twig_Extension | ||
711 | { | ||
712 | public function getFilters() | ||
713 | { | ||
714 | return array( | ||
715 | 'rot13' => new Twig_Filter_Method($this, 'rot13Filter'), | ||
716 | ); | ||
717 | } | ||
718 | |||
719 | public function rot13Filter($string) | ||
720 | { | ||
721 | return str_rot13($string); | ||
722 | } | ||
723 | |||
724 | // ... | ||
725 | } | ||
726 | |||
727 | The first argument of the ``Twig_Filter_Method`` constructor is always | ||
728 | ``$this``, the current extension object. The second one is the name of the | ||
729 | method to call. | ||
730 | |||
731 | Using methods for filters is a great way to package your filter without | ||
732 | polluting the global namespace. This also gives the developer more flexibility | ||
733 | at the cost of a small overhead. | ||
734 | |||
735 | Overriding default Filters | ||
736 | .......................... | ||
737 | |||
738 | If some default core filters do not suit your needs, you can easily override | ||
739 | them by creating your own extension. Just use the same names as the one you | ||
740 | want to override:: | ||
741 | |||
742 | class MyCoreExtension extends Twig_Extension | ||
743 | { | ||
744 | public function getFilters() | ||
745 | { | ||
746 | return array( | ||
747 | 'date' => new Twig_Filter_Method($this, 'dateFilter'), | ||
748 | // ... | ||
749 | ); | ||
750 | } | ||
751 | |||
752 | public function dateFilter($timestamp, $format = 'F j, Y H:i') | ||
753 | { | ||
754 | return '...'.twig_date_format_filter($timestamp, $format); | ||
755 | } | ||
756 | |||
757 | public function getName() | ||
758 | { | ||
759 | return 'project'; | ||
760 | } | ||
761 | } | ||
762 | |||
763 | Here, we override the ``date`` filter with a custom one. Using this extension | ||
764 | is as simple as registering the ``MyCoreExtension`` extension by calling the | ||
765 | ``addExtension()`` method on the environment instance:: | ||
766 | |||
767 | $twig = new Twig_Environment($loader); | ||
768 | $twig->addExtension(new MyCoreExtension()); | ||
769 | |||
770 | Tags | ||
771 | ~~~~ | ||
772 | |||
773 | Adding a tag in an extension can be done by overriding the | ||
774 | ``getTokenParsers()`` method. This method must return an array of tags to add | ||
775 | to the Twig environment:: | ||
776 | |||
777 | class Project_Twig_Extension extends Twig_Extension | ||
778 | { | ||
779 | public function getTokenParsers() | ||
780 | { | ||
781 | return array(new Project_Set_TokenParser()); | ||
782 | } | ||
783 | |||
784 | // ... | ||
785 | } | ||
786 | |||
787 | In the above code, we have added a single new tag, defined by the | ||
788 | ``Project_Set_TokenParser`` class. The ``Project_Set_TokenParser`` class is | ||
789 | responsible for parsing the tag and compiling it to PHP. | ||
790 | |||
791 | Operators | ||
792 | ~~~~~~~~~ | ||
793 | |||
794 | The ``getOperators()`` methods allows to add new operators. Here is how to add | ||
795 | ``!``, ``||``, and ``&&`` operators:: | ||
796 | |||
797 | class Project_Twig_Extension extends Twig_Extension | ||
798 | { | ||
799 | public function getOperators() | ||
800 | { | ||
801 | return array( | ||
802 | array( | ||
803 | '!' => array('precedence' => 50, 'class' => 'Twig_Node_Expression_Unary_Not'), | ||
804 | ), | ||
805 | array( | ||
806 | '||' => array('precedence' => 10, 'class' => 'Twig_Node_Expression_Binary_Or', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT), | ||
807 | '&&' => array('precedence' => 15, 'class' => 'Twig_Node_Expression_Binary_And', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT), | ||
808 | ), | ||
809 | ); | ||
810 | } | ||
811 | |||
812 | // ... | ||
813 | } | ||
814 | |||
815 | Tests | ||
816 | ~~~~~ | ||
817 | |||
818 | The ``getTests()`` methods allows to add new test functions:: | ||
819 | |||
820 | class Project_Twig_Extension extends Twig_Extension | ||
821 | { | ||
822 | public function getTests() | ||
823 | { | ||
824 | return array( | ||
825 | 'even' => new Twig_Test_Function('twig_test_even'), | ||
826 | ); | ||
827 | } | ||
828 | |||
829 | // ... | ||
830 | } | ||
831 | |||
832 | Testing an Extension | ||
833 | -------------------- | ||
834 | |||
835 | .. versionadded:: 1.10 | ||
836 | Support for functional tests was added in Twig 1.10. | ||
837 | |||
838 | Functional Tests | ||
839 | ~~~~~~~~~~~~~~~~ | ||
840 | |||
841 | You can create functional tests for extensions simply by creating the | ||
842 | following file structure in your test directory:: | ||
843 | |||
844 | Fixtures/ | ||
845 | filters/ | ||
846 | foo.test | ||
847 | bar.test | ||
848 | functions/ | ||
849 | foo.test | ||
850 | bar.test | ||
851 | tags/ | ||
852 | foo.test | ||
853 | bar.test | ||
854 | IntegrationTest.php | ||
855 | |||
856 | The ``IntegrationTest.php`` file should look like this:: | ||
857 | |||
858 | class Project_Tests_IntegrationTest extends Twig_Test_IntegrationTestCase | ||
859 | { | ||
860 | public function getExtensions() | ||
861 | { | ||
862 | return array( | ||
863 | new Project_Twig_Extension1(), | ||
864 | new Project_Twig_Extension2(), | ||
865 | ); | ||
866 | } | ||
867 | |||
868 | public function getFixturesDir() | ||
869 | { | ||
870 | return dirname(__FILE__).'/Fixtures/'; | ||
871 | } | ||
872 | } | ||
873 | |||
874 | Fixtures examples can be found within the Twig repository | ||
875 | `tests/Twig/Fixtures`_ directory. | ||
876 | |||
877 | Node Tests | ||
878 | ~~~~~~~~~~ | ||
879 | |||
880 | Testing the node visitors can be complex, so extend your test cases from | ||
881 | ``Twig_Test_NodeTestCase``. Examples can be found in the Twig repository | ||
882 | `tests/Twig/Node`_ directory. | ||
883 | |||
884 | .. _`spl_autoload_register()`: http://www.php.net/spl_autoload_register | ||
885 | .. _`rot13`: http://www.php.net/manual/en/function.str-rot13.php | ||
886 | .. _`tests/Twig/Fixtures`: https://github.com/fabpot/Twig/tree/master/test/Twig/Tests/Fixtures | ||
887 | .. _`tests/Twig/Node`: https://github.com/fabpot/Twig/tree/master/test/Twig/Tests/Node | ||
diff --git a/vendor/twig/twig/doc/api.rst b/vendor/twig/twig/doc/api.rst new file mode 100644 index 00000000..cbccb0f7 --- /dev/null +++ b/vendor/twig/twig/doc/api.rst | |||
@@ -0,0 +1,529 @@ | |||
1 | Twig for Developers | ||
2 | =================== | ||
3 | |||
4 | This chapter describes the API to Twig and not the template language. It will | ||
5 | be most useful as reference to those implementing the template interface to | ||
6 | the application and not those who are creating Twig templates. | ||
7 | |||
8 | Basics | ||
9 | ------ | ||
10 | |||
11 | Twig uses a central object called the **environment** (of class | ||
12 | ``Twig_Environment``). Instances of this class are used to store the | ||
13 | configuration and extensions, and are used to load templates from the file | ||
14 | system or other locations. | ||
15 | |||
16 | Most applications will create one ``Twig_Environment`` object on application | ||
17 | initialization and use that to load templates. In some cases it's however | ||
18 | useful to have multiple environments side by side, if different configurations | ||
19 | are in use. | ||
20 | |||
21 | The simplest way to configure Twig to load templates for your application | ||
22 | looks roughly like this:: | ||
23 | |||
24 | require_once '/path/to/lib/Twig/Autoloader.php'; | ||
25 | Twig_Autoloader::register(); | ||
26 | |||
27 | $loader = new Twig_Loader_Filesystem('/path/to/templates'); | ||
28 | $twig = new Twig_Environment($loader, array( | ||
29 | 'cache' => '/path/to/compilation_cache', | ||
30 | )); | ||
31 | |||
32 | This will create a template environment with the default settings and a loader | ||
33 | that looks up the templates in the ``/path/to/templates/`` folder. Different | ||
34 | loaders are available and you can also write your own if you want to load | ||
35 | templates from a database or other resources. | ||
36 | |||
37 | .. note:: | ||
38 | |||
39 | Notice that the second argument of the environment is an array of options. | ||
40 | The ``cache`` option is a compilation cache directory, where Twig caches | ||
41 | the compiled templates to avoid the parsing phase for sub-sequent | ||
42 | requests. It is very different from the cache you might want to add for | ||
43 | the evaluated templates. For such a need, you can use any available PHP | ||
44 | cache library. | ||
45 | |||
46 | To load a template from this environment you just have to call the | ||
47 | ``loadTemplate()`` method which then returns a ``Twig_Template`` instance:: | ||
48 | |||
49 | $template = $twig->loadTemplate('index.html'); | ||
50 | |||
51 | To render the template with some variables, call the ``render()`` method:: | ||
52 | |||
53 | echo $template->render(array('the' => 'variables', 'go' => 'here')); | ||
54 | |||
55 | .. note:: | ||
56 | |||
57 | The ``display()`` method is a shortcut to output the template directly. | ||
58 | |||
59 | You can also load and render the template in one fell swoop:: | ||
60 | |||
61 | echo $twig->render('index.html', array('the' => 'variables', 'go' => 'here')); | ||
62 | |||
63 | .. _environment_options: | ||
64 | |||
65 | Environment Options | ||
66 | ------------------- | ||
67 | |||
68 | When creating a new ``Twig_Environment`` instance, you can pass an array of | ||
69 | options as the constructor second argument:: | ||
70 | |||
71 | $twig = new Twig_Environment($loader, array('debug' => true)); | ||
72 | |||
73 | The following options are available: | ||
74 | |||
75 | * ``debug``: When set to ``true``, the generated templates have a | ||
76 | ``__toString()`` method that you can use to display the generated nodes | ||
77 | (default to ``false``). | ||
78 | |||
79 | * ``charset``: The charset used by the templates (default to ``utf-8``). | ||
80 | |||
81 | * ``base_template_class``: The base template class to use for generated | ||
82 | templates (default to ``Twig_Template``). | ||
83 | |||
84 | * ``cache``: An absolute path where to store the compiled templates, or | ||
85 | ``false`` to disable caching (which is the default). | ||
86 | |||
87 | * ``auto_reload``: When developing with Twig, it's useful to recompile the | ||
88 | template whenever the source code changes. If you don't provide a value for | ||
89 | the ``auto_reload`` option, it will be determined automatically based on the | ||
90 | ``debug`` value. | ||
91 | |||
92 | * ``strict_variables``: If set to ``false``, Twig will silently ignore invalid | ||
93 | variables (variables and or attributes/methods that do not exist) and | ||
94 | replace them with a ``null`` value. When set to ``true``, Twig throws an | ||
95 | exception instead (default to ``false``). | ||
96 | |||
97 | * ``autoescape``: If set to ``true``, auto-escaping will be enabled by default | ||
98 | for all templates (default to ``true``). As of Twig 1.8, you can set the | ||
99 | escaping strategy to use (``html``, ``js``, ``false`` to disable). | ||
100 | As of Twig 1.9, you can set the escaping strategy to use (``css``, ``url``, | ||
101 | ``html_attr``, or a PHP callback that takes the template "filename" and must | ||
102 | return the escaping strategy to use -- the callback cannot be a function name | ||
103 | to avoid collision with built-in escaping strategies). | ||
104 | |||
105 | * ``optimizations``: A flag that indicates which optimizations to apply | ||
106 | (default to ``-1`` -- all optimizations are enabled; set it to ``0`` to | ||
107 | disable). | ||
108 | |||
109 | Loaders | ||
110 | ------- | ||
111 | |||
112 | Loaders are responsible for loading templates from a resource such as the file | ||
113 | system. | ||
114 | |||
115 | Compilation Cache | ||
116 | ~~~~~~~~~~~~~~~~~ | ||
117 | |||
118 | All template loaders can cache the compiled templates on the filesystem for | ||
119 | future reuse. It speeds up Twig a lot as templates are only compiled once; and | ||
120 | the performance boost is even larger if you use a PHP accelerator such as APC. | ||
121 | See the ``cache`` and ``auto_reload`` options of ``Twig_Environment`` above | ||
122 | for more information. | ||
123 | |||
124 | Built-in Loaders | ||
125 | ~~~~~~~~~~~~~~~~ | ||
126 | |||
127 | Here is a list of the built-in loaders Twig provides: | ||
128 | |||
129 | ``Twig_Loader_Filesystem`` | ||
130 | .......................... | ||
131 | |||
132 | .. versionadded:: 1.10 | ||
133 | The ``prependPath()`` and support for namespaces were added in Twig 1.10. | ||
134 | |||
135 | ``Twig_Loader_Filesystem`` loads templates from the file system. This loader | ||
136 | can find templates in folders on the file system and is the preferred way to | ||
137 | load them:: | ||
138 | |||
139 | $loader = new Twig_Loader_Filesystem($templateDir); | ||
140 | |||
141 | It can also look for templates in an array of directories:: | ||
142 | |||
143 | $loader = new Twig_Loader_Filesystem(array($templateDir1, $templateDir2)); | ||
144 | |||
145 | With such a configuration, Twig will first look for templates in | ||
146 | ``$templateDir1`` and if they do not exist, it will fallback to look for them | ||
147 | in the ``$templateDir2``. | ||
148 | |||
149 | You can add or prepend paths via the ``addPath()`` and ``prependPath()`` | ||
150 | methods:: | ||
151 | |||
152 | $loader->addPath($templateDir3); | ||
153 | $loader->prependPath($templateDir4); | ||
154 | |||
155 | The filesystem loader also supports namespaced templates. This allows to group | ||
156 | your templates under different namespaces which have their own template paths. | ||
157 | |||
158 | When using the ``setPaths()``, ``addPath()``, and ``prependPath()`` methods, | ||
159 | specify the namespace as the second argument (when not specified, these | ||
160 | methods act on the "main" namespace):: | ||
161 | |||
162 | $loader->addPath($templateDir, 'admin'); | ||
163 | |||
164 | Namespaced templates can be accessed via the special | ||
165 | ``@namespace_name/template_path`` notation:: | ||
166 | |||
167 | $twig->render('@admin/index.html', array()); | ||
168 | |||
169 | ``Twig_Loader_String`` | ||
170 | ...................... | ||
171 | |||
172 | ``Twig_Loader_String`` loads templates from strings. It's a dummy loader as | ||
173 | the template reference is the template source code:: | ||
174 | |||
175 | $loader = new Twig_Loader_String(); | ||
176 | $twig = new Twig_Environment($loader); | ||
177 | |||
178 | echo $twig->render('Hello {{ name }}!', array('name' => 'Fabien')); | ||
179 | |||
180 | This loader should only be used for unit testing as it has severe limitations: | ||
181 | several tags, like ``extends`` or ``include`` do not make sense to use as the | ||
182 | reference to the template is the template source code itself. | ||
183 | |||
184 | ``Twig_Loader_Array`` | ||
185 | ..................... | ||
186 | |||
187 | ``Twig_Loader_Array`` loads a template from a PHP array. It's passed an array | ||
188 | of strings bound to template names:: | ||
189 | |||
190 | $loader = new Twig_Loader_Array(array( | ||
191 | 'index.html' => 'Hello {{ name }}!', | ||
192 | )); | ||
193 | $twig = new Twig_Environment($loader); | ||
194 | |||
195 | echo $twig->render('index.html', array('name' => 'Fabien')); | ||
196 | |||
197 | This loader is very useful for unit testing. It can also be used for small | ||
198 | projects where storing all templates in a single PHP file might make sense. | ||
199 | |||
200 | .. tip:: | ||
201 | |||
202 | When using the ``Array`` or ``String`` loaders with a cache mechanism, you | ||
203 | should know that a new cache key is generated each time a template content | ||
204 | "changes" (the cache key being the source code of the template). If you | ||
205 | don't want to see your cache grows out of control, you need to take care | ||
206 | of clearing the old cache file by yourself. | ||
207 | |||
208 | ``Twig_Loader_Chain`` | ||
209 | ..................... | ||
210 | |||
211 | ``Twig_Loader_Chain`` delegates the loading of templates to other loaders:: | ||
212 | |||
213 | $loader1 = new Twig_Loader_Array(array( | ||
214 | 'base.html' => '{% block content %}{% endblock %}', | ||
215 | )); | ||
216 | $loader2 = new Twig_Loader_Array(array( | ||
217 | 'index.html' => '{% extends "base.twig" %}{% block content %}Hello {{ name }}{% endblock %}', | ||
218 | 'base.html' => 'Will never be loaded', | ||
219 | )); | ||
220 | |||
221 | $loader = new Twig_Loader_Chain(array($loader1, $loader2)); | ||
222 | |||
223 | $twig = new Twig_Environment($loader); | ||
224 | |||
225 | When looking for a template, Twig will try each loader in turn and it will | ||
226 | return as soon as the template is found. When rendering the ``index.html`` | ||
227 | template from the above example, Twig will load it with ``$loader2`` but the | ||
228 | ``base.html`` template will be loaded from ``$loader1``. | ||
229 | |||
230 | ``Twig_Loader_Chain`` accepts any loader that implements | ||
231 | ``Twig_LoaderInterface``. | ||
232 | |||
233 | .. note:: | ||
234 | |||
235 | You can also add loaders via the ``addLoader()`` method. | ||
236 | |||
237 | Create your own Loader | ||
238 | ~~~~~~~~~~~~~~~~~~~~~~ | ||
239 | |||
240 | All loaders implement the ``Twig_LoaderInterface``:: | ||
241 | |||
242 | interface Twig_LoaderInterface | ||
243 | { | ||
244 | /** | ||
245 | * Gets the source code of a template, given its name. | ||
246 | * | ||
247 | * @param string $name string The name of the template to load | ||
248 | * | ||
249 | * @return string The template source code | ||
250 | */ | ||
251 | function getSource($name); | ||
252 | |||
253 | /** | ||
254 | * Gets the cache key to use for the cache for a given template name. | ||
255 | * | ||
256 | * @param string $name string The name of the template to load | ||
257 | * | ||
258 | * @return string The cache key | ||
259 | */ | ||
260 | function getCacheKey($name); | ||
261 | |||
262 | /** | ||
263 | * Returns true if the template is still fresh. | ||
264 | * | ||
265 | * @param string $name The template name | ||
266 | * @param timestamp $time The last modification time of the cached template | ||
267 | */ | ||
268 | function isFresh($name, $time); | ||
269 | } | ||
270 | |||
271 | As an example, here is how the built-in ``Twig_Loader_String`` reads:: | ||
272 | |||
273 | class Twig_Loader_String implements Twig_LoaderInterface | ||
274 | { | ||
275 | public function getSource($name) | ||
276 | { | ||
277 | return $name; | ||
278 | } | ||
279 | |||
280 | public function getCacheKey($name) | ||
281 | { | ||
282 | return $name; | ||
283 | } | ||
284 | |||
285 | public function isFresh($name, $time) | ||
286 | { | ||
287 | return false; | ||
288 | } | ||
289 | } | ||
290 | |||
291 | The ``isFresh()`` method must return ``true`` if the current cached template | ||
292 | is still fresh, given the last modification time, or ``false`` otherwise. | ||
293 | |||
294 | .. tip:: | ||
295 | |||
296 | As of Twig 1.11.0, you can also implement ``Twig_ExistsLoaderInterface`` | ||
297 | to make your loader faster when used with the chain loader. | ||
298 | |||
299 | Using Extensions | ||
300 | ---------------- | ||
301 | |||
302 | Twig extensions are packages that add new features to Twig. Using an | ||
303 | extension is as simple as using the ``addExtension()`` method:: | ||
304 | |||
305 | $twig->addExtension(new Twig_Extension_Sandbox()); | ||
306 | |||
307 | Twig comes bundled with the following extensions: | ||
308 | |||
309 | * *Twig_Extension_Core*: Defines all the core features of Twig. | ||
310 | |||
311 | * *Twig_Extension_Escaper*: Adds automatic output-escaping and the possibility | ||
312 | to escape/unescape blocks of code. | ||
313 | |||
314 | * *Twig_Extension_Sandbox*: Adds a sandbox mode to the default Twig | ||
315 | environment, making it safe to evaluate untrusted code. | ||
316 | |||
317 | * *Twig_Extension_Optimizer*: Optimizes the node tree before compilation. | ||
318 | |||
319 | The core, escaper, and optimizer extensions do not need to be added to the | ||
320 | Twig environment, as they are registered by default. | ||
321 | |||
322 | Built-in Extensions | ||
323 | ------------------- | ||
324 | |||
325 | This section describes the features added by the built-in extensions. | ||
326 | |||
327 | .. tip:: | ||
328 | |||
329 | Read the chapter about extending Twig to learn how to create your own | ||
330 | extensions. | ||
331 | |||
332 | Core Extension | ||
333 | ~~~~~~~~~~~~~~ | ||
334 | |||
335 | The ``core`` extension defines all the core features of Twig: | ||
336 | |||
337 | * :doc:`Tags <tags/index>`; | ||
338 | * :doc:`Filters <filters/index>`; | ||
339 | * :doc:`Functions <functions/index>`; | ||
340 | * :doc:`Tests <tests/index>`. | ||
341 | |||
342 | Escaper Extension | ||
343 | ~~~~~~~~~~~~~~~~~ | ||
344 | |||
345 | The ``escaper`` extension adds automatic output escaping to Twig. It defines a | ||
346 | tag, ``autoescape``, and a filter, ``raw``. | ||
347 | |||
348 | When creating the escaper extension, you can switch on or off the global | ||
349 | output escaping strategy:: | ||
350 | |||
351 | $escaper = new Twig_Extension_Escaper('html'); | ||
352 | $twig->addExtension($escaper); | ||
353 | |||
354 | If set to ``html``, all variables in templates are escaped (using the ``html`` | ||
355 | escaping strategy), except those using the ``raw`` filter: | ||
356 | |||
357 | .. code-block:: jinja | ||
358 | |||
359 | {{ article.to_html|raw }} | ||
360 | |||
361 | You can also change the escaping mode locally by using the ``autoescape`` tag | ||
362 | (see the :doc:`autoescape<tags/autoescape>` doc for the syntax used before | ||
363 | Twig 1.8): | ||
364 | |||
365 | .. code-block:: jinja | ||
366 | |||
367 | {% autoescape 'html' %} | ||
368 | {{ var }} | ||
369 | {{ var|raw }} {# var won't be escaped #} | ||
370 | {{ var|escape }} {# var won't be double-escaped #} | ||
371 | {% endautoescape %} | ||
372 | |||
373 | .. warning:: | ||
374 | |||
375 | The ``autoescape`` tag has no effect on included files. | ||
376 | |||
377 | The escaping rules are implemented as follows: | ||
378 | |||
379 | * Literals (integers, booleans, arrays, ...) used in the template directly as | ||
380 | variables or filter arguments are never automatically escaped: | ||
381 | |||
382 | .. code-block:: jinja | ||
383 | |||
384 | {{ "Twig<br />" }} {# won't be escaped #} | ||
385 | |||
386 | {% set text = "Twig<br />" %} | ||
387 | {{ text }} {# will be escaped #} | ||
388 | |||
389 | * Expressions which the result is always a literal or a variable marked safe | ||
390 | are never automatically escaped: | ||
391 | |||
392 | .. code-block:: jinja | ||
393 | |||
394 | {{ foo ? "Twig<br />" : "<br />Twig" }} {# won't be escaped #} | ||
395 | |||
396 | {% set text = "Twig<br />" %} | ||
397 | {{ foo ? text : "<br />Twig" }} {# will be escaped #} | ||
398 | |||
399 | {% set text = "Twig<br />" %} | ||
400 | {{ foo ? text|raw : "<br />Twig" }} {# won't be escaped #} | ||
401 | |||
402 | {% set text = "Twig<br />" %} | ||
403 | {{ foo ? text|escape : "<br />Twig" }} {# the result of the expression won't be escaped #} | ||
404 | |||
405 | * Escaping is applied before printing, after any other filter is applied: | ||
406 | |||
407 | .. code-block:: jinja | ||
408 | |||
409 | {{ var|upper }} {# is equivalent to {{ var|upper|escape }} #} | ||
410 | |||
411 | * The `raw` filter should only be used at the end of the filter chain: | ||
412 | |||
413 | .. code-block:: jinja | ||
414 | |||
415 | {{ var|raw|upper }} {# will be escaped #} | ||
416 | |||
417 | {{ var|upper|raw }} {# won't be escaped #} | ||
418 | |||
419 | * Automatic escaping is not applied if the last filter in the chain is marked | ||
420 | safe for the current context (e.g. ``html`` or ``js``). ``escaper`` and | ||
421 | ``escaper('html')`` are marked safe for html, ``escaper('js')`` is marked | ||
422 | safe for javascript, ``raw`` is marked safe for everything. | ||
423 | |||
424 | .. code-block:: jinja | ||
425 | |||
426 | {% autoescape 'js' %} | ||
427 | {{ var|escape('html') }} {# will be escaped for html and javascript #} | ||
428 | {{ var }} {# will be escaped for javascript #} | ||
429 | {{ var|escape('js') }} {# won't be double-escaped #} | ||
430 | {% endautoescape %} | ||
431 | |||
432 | .. note:: | ||
433 | |||
434 | Note that autoescaping has some limitations as escaping is applied on | ||
435 | expressions after evaluation. For instance, when working with | ||
436 | concatenation, ``{{ foo|raw ~ bar }}`` won't give the expected result as | ||
437 | escaping is applied on the result of the concatenation, not on the | ||
438 | individual variables (so, the ``raw`` filter won't have any effect here). | ||
439 | |||
440 | Sandbox Extension | ||
441 | ~~~~~~~~~~~~~~~~~ | ||
442 | |||
443 | The ``sandbox`` extension can be used to evaluate untrusted code. Access to | ||
444 | unsafe attributes and methods is prohibited. The sandbox security is managed | ||
445 | by a policy instance. By default, Twig comes with one policy class: | ||
446 | ``Twig_Sandbox_SecurityPolicy``. This class allows you to white-list some | ||
447 | tags, filters, properties, and methods:: | ||
448 | |||
449 | $tags = array('if'); | ||
450 | $filters = array('upper'); | ||
451 | $methods = array( | ||
452 | 'Article' => array('getTitle', 'getBody'), | ||
453 | ); | ||
454 | $properties = array( | ||
455 | 'Article' => array('title', 'body'), | ||
456 | ); | ||
457 | $functions = array('range'); | ||
458 | $policy = new Twig_Sandbox_SecurityPolicy($tags, $filters, $methods, $properties, $functions); | ||
459 | |||
460 | With the previous configuration, the security policy will only allow usage of | ||
461 | the ``if`` tag, and the ``upper`` filter. Moreover, the templates will only be | ||
462 | able to call the ``getTitle()`` and ``getBody()`` methods on ``Article`` | ||
463 | objects, and the ``title`` and ``body`` public properties. Everything else | ||
464 | won't be allowed and will generate a ``Twig_Sandbox_SecurityError`` exception. | ||
465 | |||
466 | The policy object is the first argument of the sandbox constructor:: | ||
467 | |||
468 | $sandbox = new Twig_Extension_Sandbox($policy); | ||
469 | $twig->addExtension($sandbox); | ||
470 | |||
471 | By default, the sandbox mode is disabled and should be enabled when including | ||
472 | untrusted template code by using the ``sandbox`` tag: | ||
473 | |||
474 | .. code-block:: jinja | ||
475 | |||
476 | {% sandbox %} | ||
477 | {% include 'user.html' %} | ||
478 | {% endsandbox %} | ||
479 | |||
480 | You can sandbox all templates by passing ``true`` as the second argument of | ||
481 | the extension constructor:: | ||
482 | |||
483 | $sandbox = new Twig_Extension_Sandbox($policy, true); | ||
484 | |||
485 | Optimizer Extension | ||
486 | ~~~~~~~~~~~~~~~~~~~ | ||
487 | |||
488 | The ``optimizer`` extension optimizes the node tree before compilation:: | ||
489 | |||
490 | $twig->addExtension(new Twig_Extension_Optimizer()); | ||
491 | |||
492 | By default, all optimizations are turned on. You can select the ones you want | ||
493 | to enable by passing them to the constructor:: | ||
494 | |||
495 | $optimizer = new Twig_Extension_Optimizer(Twig_NodeVisitor_Optimizer::OPTIMIZE_FOR); | ||
496 | |||
497 | $twig->addExtension($optimizer); | ||
498 | |||
499 | Twig supports the following optimizations: | ||
500 | |||
501 | * ``Twig_NodeVisitor_Optimizer::OPTIMIZE_ALL``, enables all optimizations | ||
502 | (this is the default value). | ||
503 | * ``Twig_NodeVisitor_Optimizer::OPTIMIZE_NONE``, disables all optimizations. | ||
504 | This reduces the compilation time, but it can increase the execution time | ||
505 | and the consumed memory. | ||
506 | * ``Twig_NodeVisitor_Optimizer::OPTIMIZE_FOR``, optimizes the ``for`` tag by | ||
507 | removing the ``loop`` variable creation whenever possible. | ||
508 | * ``Twig_NodeVisitor_Optimizer::OPTIMIZE_RAW_FILTER``, removes the ``raw`` | ||
509 | filter whenever possible. | ||
510 | * ``Twig_NodeVisitor_Optimizer::OPTIMIZE_VAR_ACCESS``, simplifies the creation | ||
511 | and access of variables in the compiled templates whenever possible. | ||
512 | |||
513 | Exceptions | ||
514 | ---------- | ||
515 | |||
516 | Twig can throw exceptions: | ||
517 | |||
518 | * ``Twig_Error``: The base exception for all errors. | ||
519 | |||
520 | * ``Twig_Error_Syntax``: Thrown to tell the user that there is a problem with | ||
521 | the template syntax. | ||
522 | |||
523 | * ``Twig_Error_Runtime``: Thrown when an error occurs at runtime (when a filter | ||
524 | does not exist for instance). | ||
525 | |||
526 | * ``Twig_Error_Loader``: Thrown when an error occurs during template loading. | ||
527 | |||
528 | * ``Twig_Sandbox_SecurityError``: Thrown when an unallowed tag, filter, or | ||
529 | method is called in a sandboxed template. | ||
diff --git a/vendor/twig/twig/doc/coding_standards.rst b/vendor/twig/twig/doc/coding_standards.rst new file mode 100644 index 00000000..e0aab35e --- /dev/null +++ b/vendor/twig/twig/doc/coding_standards.rst | |||
@@ -0,0 +1,101 @@ | |||
1 | Coding Standards | ||
2 | ================ | ||
3 | |||
4 | When writing Twig templates, we recommend you to follow these official coding | ||
5 | standards: | ||
6 | |||
7 | * Put one (and only one) space after the start of a delimiter (``{{``, ``{%``, | ||
8 | and ``{#``) and before the end of a delimiter (``}}``, ``%}``, and ``#}``): | ||
9 | |||
10 | .. code-block:: jinja | ||
11 | |||
12 | {{ foo }} | ||
13 | {# comment #} | ||
14 | {% if foo %}{% endif %} | ||
15 | |||
16 | When using the whitespace control character, do not put any spaces between | ||
17 | it and the delimiter: | ||
18 | |||
19 | .. code-block:: jinja | ||
20 | |||
21 | {{- foo -}} | ||
22 | {#- comment -#} | ||
23 | {%- if foo -%}{%- endif -%} | ||
24 | |||
25 | * Put one (and only one) space before and after the following operators: | ||
26 | comparison operators (``==``, ``!=``, ``<``, ``>``, ``>=``, ``<=``), math | ||
27 | operators (``+``, ``-``, ``/``, ``*``, ``%``, ``//``, ``**``), logic | ||
28 | operators (``not``, ``and``, ``or``), ``~``, ``is``, ``in``, and the ternary | ||
29 | operator (``?:``): | ||
30 | |||
31 | .. code-block:: jinja | ||
32 | |||
33 | {{ 1 + 2 }} | ||
34 | {{ foo ~ bar }} | ||
35 | {{ true ? true : false }} | ||
36 | |||
37 | * Put one (and only one) space after the ``:`` sign in hashes and ``,`` in | ||
38 | arrays and hashes: | ||
39 | |||
40 | .. code-block:: jinja | ||
41 | |||
42 | {{ [1, 2, 3] }} | ||
43 | {{ {'foo': 'bar'} }} | ||
44 | |||
45 | * Do not put any spaces after an opening parenthesis and before a closing | ||
46 | parenthesis in expressions: | ||
47 | |||
48 | .. code-block:: jinja | ||
49 | |||
50 | {{ 1 + (2 * 3) }} | ||
51 | |||
52 | * Do not put any spaces before and after string delimiters: | ||
53 | |||
54 | .. code-block:: jinja | ||
55 | |||
56 | {{ 'foo' }} | ||
57 | {{ "foo" }} | ||
58 | |||
59 | * Do not put any spaces before and after the following operators: ``|``, | ||
60 | ``.``, ``..``, ``[]``: | ||
61 | |||
62 | .. code-block:: jinja | ||
63 | |||
64 | {{ foo|upper|lower }} | ||
65 | {{ user.name }} | ||
66 | {{ user[name] }} | ||
67 | {% for i in 1..12 %}{% endfor %} | ||
68 | |||
69 | * Do not put any spaces before and after the parenthesis used for filter and | ||
70 | function calls: | ||
71 | |||
72 | .. code-block:: jinja | ||
73 | |||
74 | {{ foo|default('foo') }} | ||
75 | {{ range(1..10) }} | ||
76 | |||
77 | * Do not put any spaces before and after the opening and the closing of arrays | ||
78 | and hashes: | ||
79 | |||
80 | .. code-block:: jinja | ||
81 | |||
82 | {{ [1, 2, 3] }} | ||
83 | {{ {'foo': 'bar'} }} | ||
84 | |||
85 | * Use lower cased and underscored variable names: | ||
86 | |||
87 | .. code-block:: jinja | ||
88 | |||
89 | {% set foo = 'foo' %} | ||
90 | {% set foo_bar = 'foo' %} | ||
91 | |||
92 | * Indent your code inside tags (use the same indentation as the one used for | ||
93 | the main language of the file): | ||
94 | |||
95 | .. code-block:: jinja | ||
96 | |||
97 | {% block foo %} | ||
98 | {% if true %} | ||
99 | true | ||
100 | {% endif %} | ||
101 | {% endblock %} | ||
diff --git a/vendor/twig/twig/doc/deprecated.rst b/vendor/twig/twig/doc/deprecated.rst new file mode 100644 index 00000000..f0a3a0f0 --- /dev/null +++ b/vendor/twig/twig/doc/deprecated.rst | |||
@@ -0,0 +1,98 @@ | |||
1 | Deprecated Features | ||
2 | =================== | ||
3 | |||
4 | This document lists all deprecated features in Twig. Deprecated features are | ||
5 | kept for backward compatibility and removed in the next major release (a | ||
6 | feature that was deprecated in Twig 1.x is removed in Twig 2.0). | ||
7 | |||
8 | Token Parsers | ||
9 | ------------- | ||
10 | |||
11 | * As of Twig 1.x, the token parser broker sub-system is deprecated. The | ||
12 | following class and interface will be removed in 2.0: | ||
13 | |||
14 | * ``Twig_TokenParserBrokerInterface`` | ||
15 | * ``Twig_TokenParserBroker`` | ||
16 | |||
17 | Extensions | ||
18 | ---------- | ||
19 | |||
20 | * As of Twig 1.x, the ability to remove an extension is deprecated and the | ||
21 | ``Twig_Environment::removeExtension()`` method will be removed in 2.0. | ||
22 | |||
23 | PEAR | ||
24 | ---- | ||
25 | |||
26 | PEAR support will be discontinued in Twig 2.0, and no PEAR packages will be | ||
27 | provided. Use Composer instead. | ||
28 | |||
29 | Filters | ||
30 | ------- | ||
31 | |||
32 | * As of Twig 1.x, use ``Twig_SimpleFilter`` to add a filter. The following | ||
33 | classes and interfaces will be removed in 2.0: | ||
34 | |||
35 | * ``Twig_FilterInterface`` | ||
36 | * ``Twig_FilterCallableInterface`` | ||
37 | * ``Twig_Filter`` | ||
38 | * ``Twig_Filter_Function`` | ||
39 | * ``Twig_Filter_Method`` | ||
40 | * ``Twig_Filter_Node`` | ||
41 | |||
42 | * As of Twig 2.x, the ``Twig_SimpleFilter`` class is deprecated and will be | ||
43 | removed in Twig 3.x (use ``Twig_Filter`` instead). In Twig 2.x, | ||
44 | ``Twig_SimpleFilter`` is just an alias for ``Twig_Filter``. | ||
45 | |||
46 | Functions | ||
47 | --------- | ||
48 | |||
49 | * As of Twig 1.x, use ``Twig_SimpleFunction`` to add a function. The following | ||
50 | classes and interfaces will be removed in 2.0: | ||
51 | |||
52 | * ``Twig_FunctionInterface`` | ||
53 | * ``Twig_FunctionCallableInterface`` | ||
54 | * ``Twig_Function`` | ||
55 | * ``Twig_Function_Function`` | ||
56 | * ``Twig_Function_Method`` | ||
57 | * ``Twig_Function_Node`` | ||
58 | |||
59 | * As of Twig 2.x, the ``Twig_SimpleFunction`` class is deprecated and will be | ||
60 | removed in Twig 3.x (use ``Twig_Function`` instead). In Twig 2.x, | ||
61 | ``Twig_SimpleFunction`` is just an alias for ``Twig_Function``. | ||
62 | |||
63 | Tests | ||
64 | ----- | ||
65 | |||
66 | * As of Twig 1.x, use ``Twig_SimpleTest`` to add a test. The following classes | ||
67 | and interfaces will be removed in 2.0: | ||
68 | |||
69 | * ``Twig_TestInterface`` | ||
70 | * ``Twig_TestCallableInterface`` | ||
71 | * ``Twig_Test`` | ||
72 | * ``Twig_Test_Function`` | ||
73 | * ``Twig_Test_Method`` | ||
74 | * ``Twig_Test_Node`` | ||
75 | |||
76 | * As of Twig 2.x, the ``Twig_SimpleTest`` class is deprecated and will be | ||
77 | removed in Twig 3.x (use ``Twig_Test`` instead). In Twig 2.x, | ||
78 | ``Twig_SimpleTest`` is just an alias for ``Twig_Test``. | ||
79 | |||
80 | Interfaces | ||
81 | ---------- | ||
82 | |||
83 | * As of Twig 2.x, the following interfaces are deprecated and empty (they will | ||
84 | be removed in Twig 3.0): | ||
85 | |||
86 | * ``Twig_CompilerInterface`` (use ``Twig_Compiler`` instead) | ||
87 | * ``Twig_LexerInterface`` (use ``Twig_Lexer`` instead) | ||
88 | * ``Twig_NodeInterface`` (use ``Twig_Node`` instead) | ||
89 | * ``Twig_ParserInterface`` (use ``Twig_Parser`` instead) | ||
90 | * ``Twig_ExistsLoaderInterface`` (merged with ``Twig_LoaderInterface``) | ||
91 | * ``Twig_TemplateInterface`` (use ``Twig_Template`` instead) | ||
92 | |||
93 | Globals | ||
94 | ------- | ||
95 | |||
96 | * As of Twig 2.x, the ability to register a global variable after the runtime | ||
97 | or the extensions have been initialized is not possible anymore (but | ||
98 | changing the value of an already registered global is possible). | ||
diff --git a/vendor/twig/twig/doc/filters/abs.rst b/vendor/twig/twig/doc/filters/abs.rst new file mode 100644 index 00000000..3a82f62e --- /dev/null +++ b/vendor/twig/twig/doc/filters/abs.rst | |||
@@ -0,0 +1,18 @@ | |||
1 | ``abs`` | ||
2 | ======= | ||
3 | |||
4 | The ``abs`` filter returns the absolute value. | ||
5 | |||
6 | .. code-block:: jinja | ||
7 | |||
8 | {# number = -5 #} | ||
9 | |||
10 | {{ number|abs }} | ||
11 | |||
12 | {# outputs 5 #} | ||
13 | |||
14 | .. note:: | ||
15 | |||
16 | Internally, Twig uses the PHP `abs`_ function. | ||
17 | |||
18 | .. _`abs`: http://php.net/abs | ||
diff --git a/vendor/twig/twig/doc/filters/batch.rst b/vendor/twig/twig/doc/filters/batch.rst new file mode 100644 index 00000000..4366b57b --- /dev/null +++ b/vendor/twig/twig/doc/filters/batch.rst | |||
@@ -0,0 +1,45 @@ | |||
1 | ``batch`` | ||
2 | ========= | ||
3 | |||
4 | .. versionadded:: 1.12.3 | ||
5 | The batch filter was added in Twig 1.12.3. | ||
6 | |||
7 | The ``batch`` filter "batches" items by returning a list of lists with the | ||
8 | given number of items. If you provide a second parameter, it is used to fill | ||
9 | missing items: | ||
10 | |||
11 | .. code-block:: jinja | ||
12 | |||
13 | {% set items = ['a', 'b', 'c', 'd', 'e', 'f', 'g'] %} | ||
14 | |||
15 | <table> | ||
16 | {% for row in items|batch(3, 'No item') %} | ||
17 | <tr> | ||
18 | {% for column in row %} | ||
19 | <td>{{ column }}</td> | ||
20 | {% endfor %} | ||
21 | </tr> | ||
22 | {% endfor %} | ||
23 | </table> | ||
24 | |||
25 | The above example will be rendered as: | ||
26 | |||
27 | .. code-block:: jinja | ||
28 | |||
29 | <table> | ||
30 | <tr> | ||
31 | <td>a</td> | ||
32 | <td>b</td> | ||
33 | <td>c</td> | ||
34 | </tr> | ||
35 | <tr> | ||
36 | <td>d</td> | ||
37 | <td>e</td> | ||
38 | <td>f</td> | ||
39 | </tr> | ||
40 | <tr> | ||
41 | <td>g</td> | ||
42 | <td>No item</td> | ||
43 | <td>No item</td> | ||
44 | </tr> | ||
45 | </table> | ||
diff --git a/vendor/twig/twig/doc/filters/capitalize.rst b/vendor/twig/twig/doc/filters/capitalize.rst new file mode 100644 index 00000000..10546a1f --- /dev/null +++ b/vendor/twig/twig/doc/filters/capitalize.rst | |||
@@ -0,0 +1,11 @@ | |||
1 | ``capitalize`` | ||
2 | ============== | ||
3 | |||
4 | The ``capitalize`` filter capitalizes a value. The first character will be | ||
5 | uppercase, all others lowercase: | ||
6 | |||
7 | .. code-block:: jinja | ||
8 | |||
9 | {{ 'my first car'|capitalize }} | ||
10 | |||
11 | {# outputs 'My first car' #} | ||
diff --git a/vendor/twig/twig/doc/filters/convert_encoding.rst b/vendor/twig/twig/doc/filters/convert_encoding.rst new file mode 100644 index 00000000..1b0eb60c --- /dev/null +++ b/vendor/twig/twig/doc/filters/convert_encoding.rst | |||
@@ -0,0 +1,28 @@ | |||
1 | ``convert_encoding`` | ||
2 | ==================== | ||
3 | |||
4 | .. versionadded:: 1.4 | ||
5 | The ``convert_encoding`` filter was added in Twig 1.4. | ||
6 | |||
7 | The ``convert_encoding`` filter converts a string from one encoding to | ||
8 | another. The first argument is the expected output charset and the second one | ||
9 | is the input charset: | ||
10 | |||
11 | .. code-block:: jinja | ||
12 | |||
13 | {{ data|convert_encoding('UTF-8', 'iso-2022-jp') }} | ||
14 | |||
15 | .. note:: | ||
16 | |||
17 | This filter relies on the `iconv`_ or `mbstring`_ extension, so one of | ||
18 | them must be installed. In case both are installed, `mbstring`_ is used by | ||
19 | default (Twig before 1.8.1 uses `iconv`_ by default). | ||
20 | |||
21 | Arguments | ||
22 | --------- | ||
23 | |||
24 | * ``from``: The input charset | ||
25 | * ``to``: The output charset | ||
26 | |||
27 | .. _`iconv`: http://php.net/iconv | ||
28 | .. _`mbstring`: http://php.net/mbstring | ||
diff --git a/vendor/twig/twig/doc/filters/date.rst b/vendor/twig/twig/doc/filters/date.rst new file mode 100644 index 00000000..8e2f31fa --- /dev/null +++ b/vendor/twig/twig/doc/filters/date.rst | |||
@@ -0,0 +1,88 @@ | |||
1 | ``date`` | ||
2 | ======== | ||
3 | |||
4 | .. versionadded:: 1.1 | ||
5 | The timezone support has been added in Twig 1.1. | ||
6 | |||
7 | .. versionadded:: 1.5 | ||
8 | The default date format support has been added in Twig 1.5. | ||
9 | |||
10 | .. versionadded:: 1.6.1 | ||
11 | The default timezone support has been added in Twig 1.6.1. | ||
12 | |||
13 | .. versionadded:: 1.11.0 | ||
14 | The introduction of the false value for the timezone was introduced in Twig 1.11.0 | ||
15 | |||
16 | The ``date`` filter formats a date to a given format: | ||
17 | |||
18 | .. code-block:: jinja | ||
19 | |||
20 | {{ post.published_at|date("m/d/Y") }} | ||
21 | |||
22 | The ``date`` filter accepts strings (it must be in a format supported by the | ||
23 | `strtotime`_ function), `DateTime`_ instances, or `DateInterval`_ instances. For | ||
24 | instance, to display the current date, filter the word "now": | ||
25 | |||
26 | .. code-block:: jinja | ||
27 | |||
28 | {{ "now"|date("m/d/Y") }} | ||
29 | |||
30 | To escape words and characters in the date format use ``\\`` in front of each | ||
31 | character: | ||
32 | |||
33 | .. code-block:: jinja | ||
34 | |||
35 | {{ post.published_at|date("F jS \\a\\t g:ia") }} | ||
36 | |||
37 | If the value passed to the ``date`` filter is ``null``, it will return the | ||
38 | current date by default. If an empty string is desired instead of the current | ||
39 | date, use a ternary operator: | ||
40 | |||
41 | .. code-block:: jinja | ||
42 | |||
43 | {{ post.published_at is empty ? "" : post.published_at|date("m/d/Y") }} | ||
44 | |||
45 | If no format is provided, Twig will use the default one: ``F j, Y H:i``. This | ||
46 | default can be easily changed by calling the ``setDateFormat()`` method on the | ||
47 | ``core`` extension instance. The first argument is the default format for | ||
48 | dates and the second one is the default format for date intervals: | ||
49 | |||
50 | .. code-block:: php | ||
51 | |||
52 | $twig = new Twig_Environment($loader); | ||
53 | $twig->getExtension('core')->setDateFormat('d/m/Y', '%d days'); | ||
54 | |||
55 | Timezone | ||
56 | -------- | ||
57 | |||
58 | By default, the date is displayed by applying the default timezone (the one | ||
59 | specified in php.ini or declared in Twig -- see below), but you can override | ||
60 | it by explicitly specifying a timezone: | ||
61 | |||
62 | .. code-block:: jinja | ||
63 | |||
64 | {{ post.published_at|date("m/d/Y", "Europe/Paris") }} | ||
65 | |||
66 | If the date is already a DateTime object, and if you want to keep its current | ||
67 | timezone, pass ``false`` as the timezone value: | ||
68 | |||
69 | .. code-block:: jinja | ||
70 | |||
71 | {{ post.published_at|date("m/d/Y", false) }} | ||
72 | |||
73 | The default timezone can also be set globally by calling ``setTimezone()``: | ||
74 | |||
75 | .. code-block:: php | ||
76 | |||
77 | $twig = new Twig_Environment($loader); | ||
78 | $twig->getExtension('core')->setTimezone('Europe/Paris'); | ||
79 | |||
80 | Arguments | ||
81 | --------- | ||
82 | |||
83 | * ``format``: The date format | ||
84 | * ``timezone``: The date timezone | ||
85 | |||
86 | .. _`strtotime`: http://www.php.net/strtotime | ||
87 | .. _`DateTime`: http://www.php.net/DateTime | ||
88 | .. _`DateInterval`: http://www.php.net/DateInterval | ||
diff --git a/vendor/twig/twig/doc/filters/date_modify.rst b/vendor/twig/twig/doc/filters/date_modify.rst new file mode 100644 index 00000000..6a5c73d6 --- /dev/null +++ b/vendor/twig/twig/doc/filters/date_modify.rst | |||
@@ -0,0 +1,23 @@ | |||
1 | ``date_modify`` | ||
2 | =============== | ||
3 | |||
4 | .. versionadded:: 1.9.0 | ||
5 | The date_modify filter has been added in Twig 1.9.0. | ||
6 | |||
7 | The ``date_modify`` filter modifies a date with a given modifier string: | ||
8 | |||
9 | .. code-block:: jinja | ||
10 | |||
11 | {{ post.published_at|date_modify("+1 day")|date("m/d/Y") }} | ||
12 | |||
13 | The ``date_modify`` filter accepts strings (it must be in a format supported | ||
14 | by the `strtotime`_ function) or `DateTime`_ instances. You can easily combine | ||
15 | it with the :doc:`date<date>` filter for formatting. | ||
16 | |||
17 | Arguments | ||
18 | --------- | ||
19 | |||
20 | * ``modifier``: The modifier | ||
21 | |||
22 | .. _`strtotime`: http://www.php.net/strtotime | ||
23 | .. _`DateTime`: http://www.php.net/DateTime | ||
diff --git a/vendor/twig/twig/doc/filters/default.rst b/vendor/twig/twig/doc/filters/default.rst new file mode 100644 index 00000000..46ed9636 --- /dev/null +++ b/vendor/twig/twig/doc/filters/default.rst | |||
@@ -0,0 +1,33 @@ | |||
1 | ``default`` | ||
2 | =========== | ||
3 | |||
4 | The ``default`` filter returns the passed default value if the value is | ||
5 | undefined or empty, otherwise the value of the variable: | ||
6 | |||
7 | .. code-block:: jinja | ||
8 | |||
9 | {{ var|default('var is not defined') }} | ||
10 | |||
11 | {{ var.foo|default('foo item on var is not defined') }} | ||
12 | |||
13 | {{ var['foo']|default('foo item on var is not defined') }} | ||
14 | |||
15 | {{ ''|default('passed var is empty') }} | ||
16 | |||
17 | When using the ``default`` filter on an expression that uses variables in some | ||
18 | method calls, be sure to use the ``default`` filter whenever a variable can be | ||
19 | undefined: | ||
20 | |||
21 | .. code-block:: jinja | ||
22 | |||
23 | {{ var.method(foo|default('foo'))|default('foo') }} | ||
24 | |||
25 | .. note:: | ||
26 | |||
27 | Read the documentation for the :doc:`defined<../tests/defined>` and | ||
28 | :doc:`empty<../tests/empty>` tests to learn more about their semantics. | ||
29 | |||
30 | Arguments | ||
31 | --------- | ||
32 | |||
33 | * ``default``: The default value | ||
diff --git a/vendor/twig/twig/doc/filters/escape.rst b/vendor/twig/twig/doc/filters/escape.rst new file mode 100644 index 00000000..5ade7d74 --- /dev/null +++ b/vendor/twig/twig/doc/filters/escape.rst | |||
@@ -0,0 +1,93 @@ | |||
1 | ``escape`` | ||
2 | ========== | ||
3 | |||
4 | .. versionadded:: 1.9.0 | ||
5 | The ``css``, ``url``, and ``html_attr`` strategies were added in Twig | ||
6 | 1.9.0. | ||
7 | |||
8 | The ``escape`` filter escapes a string for safe insertion into the final | ||
9 | output. It supports different escaping strategies depending on the template | ||
10 | context. | ||
11 | |||
12 | By default, it uses the HTML escaping strategy: | ||
13 | |||
14 | .. code-block:: jinja | ||
15 | |||
16 | {{ user.username|escape }} | ||
17 | |||
18 | For convenience, the ``e`` filter is defined as an alias: | ||
19 | |||
20 | .. code-block:: jinja | ||
21 | |||
22 | {{ user.username|e }} | ||
23 | |||
24 | The ``escape`` filter can also be used in other contexts than HTML thanks to | ||
25 | an optional argument which defines the escaping strategy to use: | ||
26 | |||
27 | .. code-block:: jinja | ||
28 | |||
29 | {{ user.username|e }} | ||
30 | {# is equivalent to #} | ||
31 | {{ user.username|e('html') }} | ||
32 | |||
33 | And here is how to escape variables included in JavaScript code: | ||
34 | |||
35 | .. code-block:: jinja | ||
36 | |||
37 | {{ user.username|escape('js') }} | ||
38 | {{ user.username|e('js') }} | ||
39 | |||
40 | The ``escape`` filter supports the following escaping strategies: | ||
41 | |||
42 | * ``html``: escapes a string for the **HTML body** context. | ||
43 | |||
44 | * ``js``: escapes a string for the **JavaScript context**. | ||
45 | |||
46 | * ``css``: escapes a string for the **CSS context**. CSS escaping can be | ||
47 | applied to any string being inserted into CSS and escapes everything except | ||
48 | alphanumerics. | ||
49 | |||
50 | * ``url``: escapes a string for the **URI or parameter contexts**. This should | ||
51 | not be used to escape an entire URI; only a subcomponent being inserted. | ||
52 | |||
53 | * ``html_attr``: escapes a string for the **HTML attribute** context. | ||
54 | |||
55 | .. note:: | ||
56 | |||
57 | Internally, ``escape`` uses the PHP native `htmlspecialchars`_ function | ||
58 | for the HTML escaping strategy. | ||
59 | |||
60 | .. caution:: | ||
61 | |||
62 | When using automatic escaping, Twig tries to not double-escape a variable | ||
63 | when the automatic escaping strategy is the same as the one applied by the | ||
64 | escape filter; but that does not work when using a variable as the | ||
65 | escaping strategy: | ||
66 | |||
67 | .. code-block:: jinja | ||
68 | |||
69 | {% set strategy = 'html' %} | ||
70 | |||
71 | {% autoescape 'html' %} | ||
72 | {{ var|escape('html') }} {# won't be double-escaped #} | ||
73 | {{ var|escape(strategy) }} {# will be double-escaped #} | ||
74 | {% endautoescape %} | ||
75 | |||
76 | When using a variable as the escaping strategy, you should disable | ||
77 | automatic escaping: | ||
78 | |||
79 | .. code-block:: jinja | ||
80 | |||
81 | {% set strategy = 'html' %} | ||
82 | |||
83 | {% autoescape 'html' %} | ||
84 | {{ var|escape(strategy)|raw }} {# won't be double-escaped #} | ||
85 | {% endautoescape %} | ||
86 | |||
87 | Arguments | ||
88 | --------- | ||
89 | |||
90 | * ``strategy``: The escaping strategy | ||
91 | * ``charset``: The string charset | ||
92 | |||
93 | .. _`htmlspecialchars`: http://php.net/htmlspecialchars | ||
diff --git a/vendor/twig/twig/doc/filters/first.rst b/vendor/twig/twig/doc/filters/first.rst new file mode 100644 index 00000000..4295e833 --- /dev/null +++ b/vendor/twig/twig/doc/filters/first.rst | |||
@@ -0,0 +1,25 @@ | |||
1 | ``first`` | ||
2 | ========= | ||
3 | |||
4 | .. versionadded:: 1.12.2 | ||
5 | The first filter was added in Twig 1.12.2. | ||
6 | |||
7 | The ``first`` filter returns the first "element" of a sequence, a mapping, or | ||
8 | a string: | ||
9 | |||
10 | .. code-block:: jinja | ||
11 | |||
12 | {{ [1, 2, 3, 4]|first }} | ||
13 | {# outputs 1 #} | ||
14 | |||
15 | {{ { a: 1, b: 2, c: 3, d: 4 }|first }} | ||
16 | {# outputs 1 #} | ||
17 | |||
18 | {{ '1234'|first }} | ||
19 | {# outputs 1 #} | ||
20 | |||
21 | .. note:: | ||
22 | |||
23 | It also works with objects implementing the `Traversable`_ interface. | ||
24 | |||
25 | .. _`Traversable`: http://php.net/manual/en/class.traversable.php | ||
diff --git a/vendor/twig/twig/doc/filters/format.rst b/vendor/twig/twig/doc/filters/format.rst new file mode 100644 index 00000000..fe55a09e --- /dev/null +++ b/vendor/twig/twig/doc/filters/format.rst | |||
@@ -0,0 +1,16 @@ | |||
1 | ``format`` | ||
2 | ========== | ||
3 | |||
4 | The ``format`` filter formats a given string by replacing the placeholders | ||
5 | (placeholders follows the `sprintf`_ notation): | ||
6 | |||
7 | .. code-block:: jinja | ||
8 | |||
9 | {{ "I like %s and %s."|format(foo, "bar") }} | ||
10 | |||
11 | {# returns I like foo and bar | ||
12 | if the foo parameter equals to the foo string. #} | ||
13 | |||
14 | .. _`sprintf`: http://www.php.net/sprintf | ||
15 | |||
16 | .. seealso:: :doc:`replace<replace>` | ||
diff --git a/vendor/twig/twig/doc/filters/index.rst b/vendor/twig/twig/doc/filters/index.rst new file mode 100644 index 00000000..b0c6b38d --- /dev/null +++ b/vendor/twig/twig/doc/filters/index.rst | |||
@@ -0,0 +1,36 @@ | |||
1 | Filters | ||
2 | ======= | ||
3 | |||
4 | .. toctree:: | ||
5 | :maxdepth: 1 | ||
6 | |||
7 | abs | ||
8 | batch | ||
9 | capitalize | ||
10 | convert_encoding | ||
11 | date | ||
12 | date_modify | ||
13 | default | ||
14 | escape | ||
15 | first | ||
16 | format | ||
17 | join | ||
18 | json_encode | ||
19 | keys | ||
20 | last | ||
21 | length | ||
22 | lower | ||
23 | nl2br | ||
24 | number_format | ||
25 | merge | ||
26 | upper | ||
27 | raw | ||
28 | replace | ||
29 | reverse | ||
30 | slice | ||
31 | sort | ||
32 | split | ||
33 | striptags | ||
34 | title | ||
35 | trim | ||
36 | url_encode | ||
diff --git a/vendor/twig/twig/doc/filters/join.rst b/vendor/twig/twig/doc/filters/join.rst new file mode 100644 index 00000000..f4952421 --- /dev/null +++ b/vendor/twig/twig/doc/filters/join.rst | |||
@@ -0,0 +1,23 @@ | |||
1 | ``join`` | ||
2 | ======== | ||
3 | |||
4 | The ``join`` filter returns a string which is the concatenation of the items | ||
5 | of a sequence: | ||
6 | |||
7 | .. code-block:: jinja | ||
8 | |||
9 | {{ [1, 2, 3]|join }} | ||
10 | {# returns 123 #} | ||
11 | |||
12 | The separator between elements is an empty string per default, but you can | ||
13 | define it with the optional first parameter: | ||
14 | |||
15 | .. code-block:: jinja | ||
16 | |||
17 | {{ [1, 2, 3]|join('|') }} | ||
18 | {# returns 1|2|3 #} | ||
19 | |||
20 | Arguments | ||
21 | --------- | ||
22 | |||
23 | * ``glue``: The separator | ||
diff --git a/vendor/twig/twig/doc/filters/json_encode.rst b/vendor/twig/twig/doc/filters/json_encode.rst new file mode 100644 index 00000000..a33fef1b --- /dev/null +++ b/vendor/twig/twig/doc/filters/json_encode.rst | |||
@@ -0,0 +1,21 @@ | |||
1 | ``json_encode`` | ||
2 | =============== | ||
3 | |||
4 | The ``json_encode`` filter returns the JSON representation of a string: | ||
5 | |||
6 | .. code-block:: jinja | ||
7 | |||
8 | {{ data|json_encode() }} | ||
9 | |||
10 | .. note:: | ||
11 | |||
12 | Internally, Twig uses the PHP `json_encode`_ function. | ||
13 | |||
14 | Arguments | ||
15 | --------- | ||
16 | |||
17 | * ``options``: A bitmask of `json_encode options`_ (``{{ | ||
18 | data|json_encode(constant(JSON_PRETTY_PRINT)) }}``) | ||
19 | |||
20 | .. _`json_encode`: http://php.net/json_encode | ||
21 | .. _`json_encode options`: http://www.php.net/manual/en/json.constants.php | ||
diff --git a/vendor/twig/twig/doc/filters/keys.rst b/vendor/twig/twig/doc/filters/keys.rst new file mode 100644 index 00000000..e4f090c6 --- /dev/null +++ b/vendor/twig/twig/doc/filters/keys.rst | |||
@@ -0,0 +1,11 @@ | |||
1 | ``keys`` | ||
2 | ======== | ||
3 | |||
4 | The ``keys`` filter returns the keys of an array. It is useful when you want to | ||
5 | iterate over the keys of an array: | ||
6 | |||
7 | .. code-block:: jinja | ||
8 | |||
9 | {% for key in array|keys %} | ||
10 | ... | ||
11 | {% endfor %} | ||
diff --git a/vendor/twig/twig/doc/filters/last.rst b/vendor/twig/twig/doc/filters/last.rst new file mode 100644 index 00000000..723c0b57 --- /dev/null +++ b/vendor/twig/twig/doc/filters/last.rst | |||
@@ -0,0 +1,25 @@ | |||
1 | ``last`` | ||
2 | ======== | ||
3 | |||
4 | .. versionadded:: 1.12.2 | ||
5 | The last filter was added in Twig 1.12.2. | ||
6 | |||
7 | The ``last`` filter returns the last "element" of a sequence, a mapping, or | ||
8 | a string: | ||
9 | |||
10 | .. code-block:: jinja | ||
11 | |||
12 | {{ [1, 2, 3, 4]|last }} | ||
13 | {# outputs 4 #} | ||
14 | |||
15 | {{ { a: 1, b: 2, c: 3, d: 4 }|last }} | ||
16 | {# outputs 4 #} | ||
17 | |||
18 | {{ '1234'|last }} | ||
19 | {# outputs 4 #} | ||
20 | |||
21 | .. note:: | ||
22 | |||
23 | It also works with objects implementing the `Traversable`_ interface. | ||
24 | |||
25 | .. _`Traversable`: http://php.net/manual/en/class.traversable.php | ||
diff --git a/vendor/twig/twig/doc/filters/length.rst b/vendor/twig/twig/doc/filters/length.rst new file mode 100644 index 00000000..f79b9bdf --- /dev/null +++ b/vendor/twig/twig/doc/filters/length.rst | |||
@@ -0,0 +1,12 @@ | |||
1 | ``length`` | ||
2 | ========== | ||
3 | |||
4 | The ``length`` filters returns the number of items of a sequence or mapping, or | ||
5 | the length of a string: | ||
6 | |||
7 | .. code-block:: jinja | ||
8 | |||
9 | {% if users|length > 10 %} | ||
10 | ... | ||
11 | {% endif %} | ||
12 | |||
diff --git a/vendor/twig/twig/doc/filters/lower.rst b/vendor/twig/twig/doc/filters/lower.rst new file mode 100644 index 00000000..ef9faa90 --- /dev/null +++ b/vendor/twig/twig/doc/filters/lower.rst | |||
@@ -0,0 +1,10 @@ | |||
1 | ``lower`` | ||
2 | ========= | ||
3 | |||
4 | The ``lower`` filter converts a value to lowercase: | ||
5 | |||
6 | .. code-block:: jinja | ||
7 | |||
8 | {{ 'WELCOME'|lower }} | ||
9 | |||
10 | {# outputs 'welcome' #} | ||
diff --git a/vendor/twig/twig/doc/filters/merge.rst b/vendor/twig/twig/doc/filters/merge.rst new file mode 100644 index 00000000..05a2ae7d --- /dev/null +++ b/vendor/twig/twig/doc/filters/merge.rst | |||
@@ -0,0 +1,41 @@ | |||
1 | ``merge`` | ||
2 | ========= | ||
3 | |||
4 | The ``merge`` filter merges an array with another array: | ||
5 | |||
6 | .. code-block:: jinja | ||
7 | |||
8 | {% set values = [1, 2] %} | ||
9 | |||
10 | {% set values = values|merge(['apple', 'orange']) %} | ||
11 | |||
12 | {# values now contains [1, 2, 'apple', 'orange'] #} | ||
13 | |||
14 | New values are added at the end of the existing ones. | ||
15 | |||
16 | The ``merge`` filter also works on hashes: | ||
17 | |||
18 | .. code-block:: jinja | ||
19 | |||
20 | {% set items = { 'apple': 'fruit', 'orange': 'fruit', 'peugeot': 'unknown' } %} | ||
21 | |||
22 | {% set items = items|merge({ 'peugeot': 'car', 'renault': 'car' }) %} | ||
23 | |||
24 | {# items now contains { 'apple': 'fruit', 'orange': 'fruit', 'peugeot': 'car', 'renault': 'car' } #} | ||
25 | |||
26 | For hashes, the merging process occurs on the keys: if the key does not | ||
27 | already exist, it is added but if the key already exists, its value is | ||
28 | overridden. | ||
29 | |||
30 | .. tip:: | ||
31 | |||
32 | If you want to ensure that some values are defined in an array (by given | ||
33 | default values), reverse the two elements in the call: | ||
34 | |||
35 | .. code-block:: jinja | ||
36 | |||
37 | {% set items = { 'apple': 'fruit', 'orange': 'fruit' } %} | ||
38 | |||
39 | {% set items = { 'apple': 'unknown' }|merge(items) %} | ||
40 | |||
41 | {# items now contains { 'apple': 'fruit', 'orange': 'fruit' } #} | ||
diff --git a/vendor/twig/twig/doc/filters/nl2br.rst b/vendor/twig/twig/doc/filters/nl2br.rst new file mode 100644 index 00000000..694c6724 --- /dev/null +++ b/vendor/twig/twig/doc/filters/nl2br.rst | |||
@@ -0,0 +1,22 @@ | |||
1 | ``nl2br`` | ||
2 | ========= | ||
3 | |||
4 | .. versionadded:: 1.5 | ||
5 | The nl2br filter was added in Twig 1.5. | ||
6 | |||
7 | The ``nl2br`` filter inserts HTML line breaks before all newlines in a string: | ||
8 | |||
9 | .. code-block:: jinja | ||
10 | |||
11 | {{ "I like Twig.\nYou will like it too."|nl2br }} | ||
12 | {# outputs | ||
13 | |||
14 | I like Twig.<br /> | ||
15 | You will like it too. | ||
16 | |||
17 | #} | ||
18 | |||
19 | .. note:: | ||
20 | |||
21 | The ``nl2br`` filter pre-escapes the input before applying the | ||
22 | transformation. | ||
diff --git a/vendor/twig/twig/doc/filters/number_format.rst b/vendor/twig/twig/doc/filters/number_format.rst new file mode 100644 index 00000000..fedacd9d --- /dev/null +++ b/vendor/twig/twig/doc/filters/number_format.rst | |||
@@ -0,0 +1,45 @@ | |||
1 | ``number_format`` | ||
2 | ================= | ||
3 | |||
4 | .. versionadded:: 1.5 | ||
5 | The number_format filter was added in Twig 1.5 | ||
6 | |||
7 | The ``number_format`` filter formats numbers. It is a wrapper around PHP's | ||
8 | `number_format`_ function: | ||
9 | |||
10 | .. code-block:: jinja | ||
11 | |||
12 | {{ 200.35|number_format }} | ||
13 | |||
14 | You can control the number of decimal places, decimal point, and thousands | ||
15 | separator using the additional arguments: | ||
16 | |||
17 | .. code-block:: jinja | ||
18 | |||
19 | {{ 9800.333|number_format(2, '.', ',') }} | ||
20 | |||
21 | If no formatting options are provided then Twig will use the default formatting | ||
22 | options of: | ||
23 | |||
24 | - 0 decimal places. | ||
25 | - ``.`` as the decimal point. | ||
26 | - ``,`` as the thousands separator. | ||
27 | |||
28 | These defaults can be easily changed through the core extension: | ||
29 | |||
30 | .. code-block:: php | ||
31 | |||
32 | $twig = new Twig_Environment($loader); | ||
33 | $twig->getExtension('core')->setNumberFormat(3, '.', ','); | ||
34 | |||
35 | The defaults set for ``number_format`` can be over-ridden upon each call using the | ||
36 | additional parameters. | ||
37 | |||
38 | Arguments | ||
39 | --------- | ||
40 | |||
41 | * ``decimal``: The number of decimal points to display | ||
42 | * ``decimal_point``: The character(s) to use for the decimal point | ||
43 | * ``decimal_sep``: The character(s) to use for the thousands separator | ||
44 | |||
45 | .. _`number_format`: http://php.net/number_format | ||
diff --git a/vendor/twig/twig/doc/filters/raw.rst b/vendor/twig/twig/doc/filters/raw.rst new file mode 100644 index 00000000..434dd246 --- /dev/null +++ b/vendor/twig/twig/doc/filters/raw.rst | |||
@@ -0,0 +1,12 @@ | |||
1 | ``raw`` | ||
2 | ======= | ||
3 | |||
4 | The ``raw`` filter marks the value as being "safe", which means that in an | ||
5 | environment with automatic escaping enabled this variable will not be escaped | ||
6 | if ``raw`` is the last filter applied to it: | ||
7 | |||
8 | .. code-block:: jinja | ||
9 | |||
10 | {% autoescape true %} | ||
11 | {{ var|raw }} {# var won't be escaped #} | ||
12 | {% endautoescape %} | ||
diff --git a/vendor/twig/twig/doc/filters/replace.rst b/vendor/twig/twig/doc/filters/replace.rst new file mode 100644 index 00000000..e961f23d --- /dev/null +++ b/vendor/twig/twig/doc/filters/replace.rst | |||
@@ -0,0 +1,19 @@ | |||
1 | ``replace`` | ||
2 | =========== | ||
3 | |||
4 | The ``replace`` filter formats a given string by replacing the placeholders | ||
5 | (placeholders are free-form): | ||
6 | |||
7 | .. code-block:: jinja | ||
8 | |||
9 | {{ "I like %this% and %that%."|replace({'%this%': foo, '%that%': "bar"}) }} | ||
10 | |||
11 | {# returns I like foo and bar | ||
12 | if the foo parameter equals to the foo string. #} | ||
13 | |||
14 | Arguments | ||
15 | --------- | ||
16 | |||
17 | * ``replace_pairs``: The placeholder values | ||
18 | |||
19 | .. seealso:: :doc:`format<format>` | ||
diff --git a/vendor/twig/twig/doc/filters/reverse.rst b/vendor/twig/twig/doc/filters/reverse.rst new file mode 100644 index 00000000..752192b8 --- /dev/null +++ b/vendor/twig/twig/doc/filters/reverse.rst | |||
@@ -0,0 +1,47 @@ | |||
1 | ``reverse`` | ||
2 | =========== | ||
3 | |||
4 | .. versionadded:: 1.6 | ||
5 | Support for strings has been added in Twig 1.6. | ||
6 | |||
7 | The ``reverse`` filter reverses a sequence, a mapping, or a string: | ||
8 | |||
9 | .. code-block:: jinja | ||
10 | |||
11 | {% for user in users|reverse %} | ||
12 | ... | ||
13 | {% endfor %} | ||
14 | |||
15 | {{ '1234'|reverse }} | ||
16 | |||
17 | {# outputs 4321 #} | ||
18 | |||
19 | .. tip:: | ||
20 | |||
21 | For sequences and mappings, numeric keys are not preserved. To reverse | ||
22 | them as well, pass ``true`` as an argument to the ``reverse`` filter: | ||
23 | |||
24 | .. code-block:: jinja | ||
25 | |||
26 | {% for key, value in {1: "a", 2: "b", 3: "c"}|reverse %} | ||
27 | {{ key }}: {{ value }} | ||
28 | {%- endfor %} | ||
29 | |||
30 | {# output: 0: c 1: b 2: a #} | ||
31 | |||
32 | {% for key, value in {1: "a", 2: "b", 3: "c"}|reverse(true) %} | ||
33 | {{ key }}: {{ value }} | ||
34 | {%- endfor %} | ||
35 | |||
36 | {# output: 3: c 2: b 1: a #} | ||
37 | |||
38 | .. note:: | ||
39 | |||
40 | It also works with objects implementing the `Traversable`_ interface. | ||
41 | |||
42 | Arguments | ||
43 | --------- | ||
44 | |||
45 | * ``preserve_keys``: Preserve keys when reversing a mapping or a sequence. | ||
46 | |||
47 | .. _`Traversable`: http://php.net/Traversable | ||
diff --git a/vendor/twig/twig/doc/filters/slice.rst b/vendor/twig/twig/doc/filters/slice.rst new file mode 100644 index 00000000..dbd5db37 --- /dev/null +++ b/vendor/twig/twig/doc/filters/slice.rst | |||
@@ -0,0 +1,70 @@ | |||
1 | ``slice`` | ||
2 | =========== | ||
3 | |||
4 | .. versionadded:: 1.6 | ||
5 | The slice filter was added in Twig 1.6. | ||
6 | |||
7 | The ``slice`` filter extracts a slice of a sequence, a mapping, or a string: | ||
8 | |||
9 | .. code-block:: jinja | ||
10 | |||
11 | {% for i in [1, 2, 3, 4, 5]|slice(1, 2) %} | ||
12 | {# will iterate over 2 and 3 #} | ||
13 | {% endfor %} | ||
14 | |||
15 | {{ '12345'|slice(1, 2) }} | ||
16 | |||
17 | {# outputs 23 #} | ||
18 | |||
19 | You can use any valid expression for both the start and the length: | ||
20 | |||
21 | .. code-block:: jinja | ||
22 | |||
23 | {% for i in [1, 2, 3, 4, 5]|slice(start, length) %} | ||
24 | {# ... #} | ||
25 | {% endfor %} | ||
26 | |||
27 | As syntactic sugar, you can also use the ``[]`` notation: | ||
28 | |||
29 | .. code-block:: jinja | ||
30 | |||
31 | {% for i in [1, 2, 3, 4, 5][start:length] %} | ||
32 | {# ... #} | ||
33 | {% endfor %} | ||
34 | |||
35 | {{ '12345'[1:2] }} | ||
36 | |||
37 | {# you can omit the first argument -- which is the same as 0 #} | ||
38 | {{ '12345'[:2] }} {# will display "12" #} | ||
39 | |||
40 | {# you can omit the last argument -- which will select everything till the end #} | ||
41 | {{ '12345'[2:] }} {# will display "345" #} | ||
42 | |||
43 | The ``slice`` filter works as the `array_slice`_ PHP function for arrays and | ||
44 | `substr`_ for strings. | ||
45 | |||
46 | If the start is non-negative, the sequence will start at that start in the | ||
47 | variable. If start is negative, the sequence will start that far from the end | ||
48 | of the variable. | ||
49 | |||
50 | If length is given and is positive, then the sequence will have up to that | ||
51 | many elements in it. If the variable is shorter than the length, then only the | ||
52 | available variable elements will be present. If length is given and is | ||
53 | negative then the sequence will stop that many elements from the end of the | ||
54 | variable. If it is omitted, then the sequence will have everything from offset | ||
55 | up until the end of the variable. | ||
56 | |||
57 | .. note:: | ||
58 | |||
59 | It also works with objects implementing the `Traversable`_ interface. | ||
60 | |||
61 | Arguments | ||
62 | --------- | ||
63 | |||
64 | * ``start``: The start of the slice | ||
65 | * ``length``: The size of the slice | ||
66 | * ``preserve_keys``: Whether to preserve key or not (when the input is an array) | ||
67 | |||
68 | .. _`Traversable`: http://php.net/manual/en/class.traversable.php | ||
69 | .. _`array_slice`: http://php.net/array_slice | ||
70 | .. _`substr`: http://php.net/substr | ||
diff --git a/vendor/twig/twig/doc/filters/sort.rst b/vendor/twig/twig/doc/filters/sort.rst new file mode 100644 index 00000000..33311528 --- /dev/null +++ b/vendor/twig/twig/doc/filters/sort.rst | |||
@@ -0,0 +1,17 @@ | |||
1 | ``sort`` | ||
2 | ======== | ||
3 | |||
4 | The ``sort`` filter sorts an array: | ||
5 | |||
6 | .. code-block:: jinja | ||
7 | |||
8 | {% for user in users|sort %} | ||
9 | ... | ||
10 | {% endfor %} | ||
11 | |||
12 | .. note:: | ||
13 | |||
14 | Internally, Twig uses the PHP `asort`_ function to maintain index | ||
15 | association. | ||
16 | |||
17 | .. _`asort`: http://php.net/asort | ||
diff --git a/vendor/twig/twig/doc/filters/split.rst b/vendor/twig/twig/doc/filters/split.rst new file mode 100644 index 00000000..7cd2ca5b --- /dev/null +++ b/vendor/twig/twig/doc/filters/split.rst | |||
@@ -0,0 +1,53 @@ | |||
1 | ``split`` | ||
2 | ========= | ||
3 | |||
4 | .. versionadded:: 1.10.3 | ||
5 | The split filter was added in Twig 1.10.3. | ||
6 | |||
7 | The ``split`` filter splits a string by the given delimiter and returns a list | ||
8 | of strings: | ||
9 | |||
10 | .. code-block:: jinja | ||
11 | |||
12 | {{ "one,two,three"|split(',') }} | ||
13 | {# returns ['one', 'two', 'three'] #} | ||
14 | |||
15 | You can also pass a ``limit`` argument: | ||
16 | |||
17 | * If ``limit`` is positive, the returned array will contain a maximum of | ||
18 | limit elements with the last element containing the rest of string; | ||
19 | |||
20 | * If ``limit`` is negative, all components except the last -limit are | ||
21 | returned; | ||
22 | |||
23 | * If ``limit`` is zero, then this is treated as 1. | ||
24 | |||
25 | .. code-block:: jinja | ||
26 | |||
27 | {{ "one,two,three,four,five"|split(',', 3) }} | ||
28 | {# returns ['one', 'two', 'three,four,five'] #} | ||
29 | |||
30 | If the ``delimiter`` is an empty string, then value will be split by equal | ||
31 | chunks. Length is set by the ``limit`` argument (one character by default). | ||
32 | |||
33 | .. code-block:: jinja | ||
34 | |||
35 | {{ "123"|split('') }} | ||
36 | {# returns ['1', '2', '3'] #} | ||
37 | |||
38 | {{ "aabbcc"|split('', 2) }} | ||
39 | {# returns ['aa', 'bb', 'cc'] #} | ||
40 | |||
41 | .. note:: | ||
42 | |||
43 | Internally, Twig uses the PHP `explode`_ or `str_split`_ (if delimiter is | ||
44 | empty) functions for string splitting. | ||
45 | |||
46 | Arguments | ||
47 | --------- | ||
48 | |||
49 | * ``delimiter``: The delimiter | ||
50 | * ``limit``: The limit argument | ||
51 | |||
52 | .. _`explode`: http://php.net/explode | ||
53 | .. _`str_split`: http://php.net/str_split | ||
diff --git a/vendor/twig/twig/doc/filters/striptags.rst b/vendor/twig/twig/doc/filters/striptags.rst new file mode 100644 index 00000000..72c6f252 --- /dev/null +++ b/vendor/twig/twig/doc/filters/striptags.rst | |||
@@ -0,0 +1,15 @@ | |||
1 | ``striptags`` | ||
2 | ============= | ||
3 | |||
4 | The ``striptags`` filter strips SGML/XML tags and replace adjacent whitespace | ||
5 | by one space: | ||
6 | |||
7 | .. code-block:: jinja | ||
8 | |||
9 | {{ some_html|striptags }} | ||
10 | |||
11 | .. note:: | ||
12 | |||
13 | Internally, Twig uses the PHP `strip_tags`_ function. | ||
14 | |||
15 | .. _`strip_tags`: http://php.net/strip_tags | ||
diff --git a/vendor/twig/twig/doc/filters/title.rst b/vendor/twig/twig/doc/filters/title.rst new file mode 100644 index 00000000..c5a318e8 --- /dev/null +++ b/vendor/twig/twig/doc/filters/title.rst | |||
@@ -0,0 +1,11 @@ | |||
1 | ``title`` | ||
2 | ========= | ||
3 | |||
4 | The ``title`` filter returns a titlecased version of the value. Words will | ||
5 | start with uppercase letters, all remaining characters are lowercase: | ||
6 | |||
7 | .. code-block:: jinja | ||
8 | |||
9 | {{ 'my first car'|title }} | ||
10 | |||
11 | {# outputs 'My First Car' #} | ||
diff --git a/vendor/twig/twig/doc/filters/trim.rst b/vendor/twig/twig/doc/filters/trim.rst new file mode 100644 index 00000000..f38afd55 --- /dev/null +++ b/vendor/twig/twig/doc/filters/trim.rst | |||
@@ -0,0 +1,29 @@ | |||
1 | ``trim`` | ||
2 | ======== | ||
3 | |||
4 | .. versionadded:: 1.6.2 | ||
5 | The trim filter was added in Twig 1.6.2. | ||
6 | |||
7 | The ``trim`` filter strips whitespace (or other characters) from the beginning | ||
8 | and end of a string: | ||
9 | |||
10 | .. code-block:: jinja | ||
11 | |||
12 | {{ ' I like Twig. '|trim }} | ||
13 | |||
14 | {# outputs 'I like Twig.' #} | ||
15 | |||
16 | {{ ' I like Twig.'|trim('.') }} | ||
17 | |||
18 | {# outputs ' I like Twig' #} | ||
19 | |||
20 | .. note:: | ||
21 | |||
22 | Internally, Twig uses the PHP `trim`_ function. | ||
23 | |||
24 | Arguments | ||
25 | --------- | ||
26 | |||
27 | * ``character_mask``: The characters to strip | ||
28 | |||
29 | .. _`trim`: http://php.net/trim | ||
diff --git a/vendor/twig/twig/doc/filters/upper.rst b/vendor/twig/twig/doc/filters/upper.rst new file mode 100644 index 00000000..561cebe3 --- /dev/null +++ b/vendor/twig/twig/doc/filters/upper.rst | |||
@@ -0,0 +1,10 @@ | |||
1 | ``upper`` | ||
2 | ========= | ||
3 | |||
4 | The ``upper`` filter converts a value to uppercase: | ||
5 | |||
6 | .. code-block:: jinja | ||
7 | |||
8 | {{ 'welcome'|upper }} | ||
9 | |||
10 | {# outputs 'WELCOME' #} | ||
diff --git a/vendor/twig/twig/doc/filters/url_encode.rst b/vendor/twig/twig/doc/filters/url_encode.rst new file mode 100644 index 00000000..b4f9a6ca --- /dev/null +++ b/vendor/twig/twig/doc/filters/url_encode.rst | |||
@@ -0,0 +1,28 @@ | |||
1 | ``url_encode`` | ||
2 | ============== | ||
3 | |||
4 | .. versionadded:: 1.12.3 | ||
5 | Support for encoding an array as query string was added in Twig 1.12.3. | ||
6 | |||
7 | The ``url_encode`` filter percent encodes a given string as URL segment | ||
8 | or an array as query string: | ||
9 | |||
10 | .. code-block:: jinja | ||
11 | |||
12 | {{ "path-seg*ment"|url_encode }} | ||
13 | {# outputs "path-seg%2Ament" #} | ||
14 | |||
15 | {{ "string with spaces"|url_encode(true) }} | ||
16 | {# outputs "string%20with%20spaces" #} | ||
17 | |||
18 | {{ {'param': 'value', 'foo': 'bar'}|url_encode }} | ||
19 | {# outputs "param=value&foo=bar" #} | ||
20 | |||
21 | .. note:: | ||
22 | |||
23 | Internally, Twig uses the PHP `urlencode`_ (or `rawurlencode`_ if you pass | ||
24 | ``true`` as the first parameter) or the `http_build_query`_ function. | ||
25 | |||
26 | .. _`urlencode`: http://php.net/urlencode | ||
27 | .. _`rawurlencode`: http://php.net/rawurlencode | ||
28 | .. _`http_build_query`: http://php.net/http_build_query | ||
diff --git a/vendor/twig/twig/doc/functions/attribute.rst b/vendor/twig/twig/doc/functions/attribute.rst new file mode 100644 index 00000000..3051bdaa --- /dev/null +++ b/vendor/twig/twig/doc/functions/attribute.rst | |||
@@ -0,0 +1,18 @@ | |||
1 | ``attribute`` | ||
2 | ============= | ||
3 | |||
4 | .. versionadded:: 1.2 | ||
5 | The ``attribute`` function was added in Twig 1.2. | ||
6 | |||
7 | ``attribute`` can be used to access a "dynamic" attribute of a variable: | ||
8 | |||
9 | .. code-block:: jinja | ||
10 | |||
11 | {{ attribute(object, method) }} | ||
12 | {{ attribute(object, method, arguments) }} | ||
13 | {{ attribute(array, item) }} | ||
14 | |||
15 | .. note:: | ||
16 | |||
17 | The resolution algorithm is the same as the one used for the ``.`` | ||
18 | notation, except that the item can be any valid expression. | ||
diff --git a/vendor/twig/twig/doc/functions/block.rst b/vendor/twig/twig/doc/functions/block.rst new file mode 100644 index 00000000..fd571efb --- /dev/null +++ b/vendor/twig/twig/doc/functions/block.rst | |||
@@ -0,0 +1,15 @@ | |||
1 | ``block`` | ||
2 | ========= | ||
3 | |||
4 | When a template uses inheritance and if you want to print a block multiple | ||
5 | times, use the ``block`` function: | ||
6 | |||
7 | .. code-block:: jinja | ||
8 | |||
9 | <title>{% block title %}{% endblock %}</title> | ||
10 | |||
11 | <h1>{{ block('title') }}</h1> | ||
12 | |||
13 | {% block body %}{% endblock %} | ||
14 | |||
15 | .. seealso:: :doc:`extends<../tags/extends>`, :doc:`parent<../functions/parent>` | ||
diff --git a/vendor/twig/twig/doc/functions/constant.rst b/vendor/twig/twig/doc/functions/constant.rst new file mode 100644 index 00000000..bea0e9fc --- /dev/null +++ b/vendor/twig/twig/doc/functions/constant.rst | |||
@@ -0,0 +1,18 @@ | |||
1 | ``constant`` | ||
2 | ============ | ||
3 | |||
4 | .. versionadded: 1.12.1 | ||
5 | constant now accepts object instances as the second argument. | ||
6 | |||
7 | ``constant`` returns the constant value for a given string: | ||
8 | |||
9 | .. code-block:: jinja | ||
10 | |||
11 | {{ some_date|date(constant('DATE_W3C')) }} | ||
12 | {{ constant('Namespace\\Classname::CONSTANT_NAME') }} | ||
13 | |||
14 | As of 1.12.1 you can read constants from object instances as well: | ||
15 | |||
16 | .. code-block:: jinja | ||
17 | |||
18 | {{ constant('RSS', date) }} | ||
diff --git a/vendor/twig/twig/doc/functions/cycle.rst b/vendor/twig/twig/doc/functions/cycle.rst new file mode 100644 index 00000000..0015cae1 --- /dev/null +++ b/vendor/twig/twig/doc/functions/cycle.rst | |||
@@ -0,0 +1,25 @@ | |||
1 | ``cycle`` | ||
2 | ========= | ||
3 | |||
4 | The ``cycle`` function cycles on an array of values: | ||
5 | |||
6 | .. code-block:: jinja | ||
7 | |||
8 | {% for i in 0..10 %} | ||
9 | {{ cycle(['odd', 'even'], i) }} | ||
10 | {% endfor %} | ||
11 | |||
12 | The array can contain any number of values: | ||
13 | |||
14 | .. code-block:: jinja | ||
15 | |||
16 | {% set fruits = ['apple', 'orange', 'citrus'] %} | ||
17 | |||
18 | {% for i in 0..10 %} | ||
19 | {{ cycle(fruits, i) }} | ||
20 | {% endfor %} | ||
21 | |||
22 | Arguments | ||
23 | --------- | ||
24 | |||
25 | * ``position``: The cycle position | ||
diff --git a/vendor/twig/twig/doc/functions/date.rst b/vendor/twig/twig/doc/functions/date.rst new file mode 100644 index 00000000..f1c94819 --- /dev/null +++ b/vendor/twig/twig/doc/functions/date.rst | |||
@@ -0,0 +1,52 @@ | |||
1 | ``date`` | ||
2 | ======== | ||
3 | |||
4 | .. versionadded:: 1.6 | ||
5 | The date function has been added in Twig 1.6. | ||
6 | |||
7 | .. versionadded:: 1.6.1 | ||
8 | The default timezone support has been added in Twig 1.6.1. | ||
9 | |||
10 | Converts an argument to a date to allow date comparison: | ||
11 | |||
12 | .. code-block:: jinja | ||
13 | |||
14 | {% if date(user.created_at) < date('-2days') %} | ||
15 | {# do something #} | ||
16 | {% endif %} | ||
17 | |||
18 | The argument must be in a format supported by the `date`_ function. | ||
19 | |||
20 | You can pass a timezone as the second argument: | ||
21 | |||
22 | .. code-block:: jinja | ||
23 | |||
24 | {% if date(user.created_at) < date('-2days', 'Europe/Paris') %} | ||
25 | {# do something #} | ||
26 | {% endif %} | ||
27 | |||
28 | If no argument is passed, the function returns the current date: | ||
29 | |||
30 | .. code-block:: jinja | ||
31 | |||
32 | {% if date(user.created_at) < date() %} | ||
33 | {# always! #} | ||
34 | {% endif %} | ||
35 | |||
36 | .. note:: | ||
37 | |||
38 | You can set the default timezone globally by calling ``setTimezone()`` on | ||
39 | the ``core`` extension instance: | ||
40 | |||
41 | .. code-block:: php | ||
42 | |||
43 | $twig = new Twig_Environment($loader); | ||
44 | $twig->getExtension('core')->setTimezone('Europe/Paris'); | ||
45 | |||
46 | Arguments | ||
47 | --------- | ||
48 | |||
49 | * ``date``: The date | ||
50 | * ``timezone``: The timezone | ||
51 | |||
52 | .. _`date`: http://www.php.net/date | ||
diff --git a/vendor/twig/twig/doc/functions/dump.rst b/vendor/twig/twig/doc/functions/dump.rst new file mode 100644 index 00000000..1500b0f4 --- /dev/null +++ b/vendor/twig/twig/doc/functions/dump.rst | |||
@@ -0,0 +1,69 @@ | |||
1 | ``dump`` | ||
2 | ======== | ||
3 | |||
4 | .. versionadded:: 1.5 | ||
5 | The dump function was added in Twig 1.5. | ||
6 | |||
7 | The ``dump`` function dumps information about a template variable. This is | ||
8 | mostly useful to debug a template that does not behave as expected by | ||
9 | introspecting its variables: | ||
10 | |||
11 | .. code-block:: jinja | ||
12 | |||
13 | {{ dump(user) }} | ||
14 | |||
15 | .. note:: | ||
16 | |||
17 | The ``dump`` function is not available by default. You must add the | ||
18 | ``Twig_Extension_Debug`` extension explicitly when creating your Twig | ||
19 | environment:: | ||
20 | |||
21 | $twig = new Twig_Environment($loader, array( | ||
22 | 'debug' => true, | ||
23 | // ... | ||
24 | )); | ||
25 | $twig->addExtension(new Twig_Extension_Debug()); | ||
26 | |||
27 | Even when enabled, the ``dump`` function won't display anything if the | ||
28 | ``debug`` option on the environment is not enabled (to avoid leaking debug | ||
29 | information on a production server). | ||
30 | |||
31 | In an HTML context, wrap the output with a ``pre`` tag to make it easier to | ||
32 | read: | ||
33 | |||
34 | .. code-block:: jinja | ||
35 | |||
36 | <pre> | ||
37 | {{ dump(user) }} | ||
38 | </pre> | ||
39 | |||
40 | .. tip:: | ||
41 | |||
42 | Using a ``pre`` tag is not needed when `XDebug`_ is enabled and | ||
43 | ``html_errors`` is ``on``; as a bonus, the output is also nicer with | ||
44 | XDebug enabled. | ||
45 | |||
46 | You can debug several variables by passing them as additional arguments: | ||
47 | |||
48 | .. code-block:: jinja | ||
49 | |||
50 | {{ dump(user, categories) }} | ||
51 | |||
52 | If you don't pass any value, all variables from the current context are | ||
53 | dumped: | ||
54 | |||
55 | .. code-block:: jinja | ||
56 | |||
57 | {{ dump() }} | ||
58 | |||
59 | .. note:: | ||
60 | |||
61 | Internally, Twig uses the PHP `var_dump`_ function. | ||
62 | |||
63 | Arguments | ||
64 | --------- | ||
65 | |||
66 | * ``context``: The context to dump | ||
67 | |||
68 | .. _`XDebug`: http://xdebug.org/docs/display | ||
69 | .. _`var_dump`: http://php.net/var_dump | ||
diff --git a/vendor/twig/twig/doc/functions/include.rst b/vendor/twig/twig/doc/functions/include.rst new file mode 100644 index 00000000..eaddfe61 --- /dev/null +++ b/vendor/twig/twig/doc/functions/include.rst | |||
@@ -0,0 +1,80 @@ | |||
1 | ``include`` | ||
2 | =========== | ||
3 | |||
4 | .. versionadded:: 1.12 | ||
5 | The include function was added in Twig 1.12. | ||
6 | |||
7 | The ``include`` function returns the rendered content of a template: | ||
8 | |||
9 | .. code-block:: jinja | ||
10 | |||
11 | {{ include('template.html') }} | ||
12 | {{ include(some_var) }} | ||
13 | |||
14 | Included templates have access to the variables of the active context. | ||
15 | |||
16 | If you are using the filesystem loader, the templates are looked for in the | ||
17 | paths defined by it. | ||
18 | |||
19 | The context is passed by default to the template but you can also pass | ||
20 | additional variables: | ||
21 | |||
22 | .. code-block:: jinja | ||
23 | |||
24 | {# template.html will have access to the variables from the current context and the additional ones provided #} | ||
25 | {{ include('template.html', {foo: 'bar'}) }} | ||
26 | |||
27 | You can disable access to the context by setting ``with_context`` to | ||
28 | ``false``: | ||
29 | |||
30 | .. code-block:: jinja | ||
31 | |||
32 | {# only the foo variable will be accessible #} | ||
33 | {{ include('template.html', {foo: 'bar'}, with_context = false) }} | ||
34 | |||
35 | .. code-block:: jinja | ||
36 | |||
37 | {# no variables will be accessible #} | ||
38 | {{ include('template.html', with_context = false) }} | ||
39 | |||
40 | And if the expression evaluates to a ``Twig_Template`` object, Twig will use it | ||
41 | directly:: | ||
42 | |||
43 | // {{ include(template) }} | ||
44 | |||
45 | $template = $twig->loadTemplate('some_template.twig'); | ||
46 | |||
47 | $twig->loadTemplate('template.twig')->display(array('template' => $template)); | ||
48 | |||
49 | When you set the ``ignore_missing`` flag, Twig will return an empty string if | ||
50 | the template does not exist: | ||
51 | |||
52 | .. code-block:: jinja | ||
53 | |||
54 | {{ include('sidebar.html', ignore_missing = true) }} | ||
55 | |||
56 | You can also provide a list of templates that are checked for existence before | ||
57 | inclusion. The first template that exists will be rendered: | ||
58 | |||
59 | .. code-block:: jinja | ||
60 | |||
61 | {{ include(['page_detailed.html', 'page.html']) }} | ||
62 | |||
63 | If ``ignore_missing`` is set, it will fall back to rendering nothing if none | ||
64 | of the templates exist, otherwise it will throw an exception. | ||
65 | |||
66 | When including a template created by an end user, you should consider | ||
67 | sandboxing it: | ||
68 | |||
69 | .. code-block:: jinja | ||
70 | |||
71 | {{ include('page.html', sandboxed = true) }} | ||
72 | |||
73 | Arguments | ||
74 | --------- | ||
75 | |||
76 | * ``template``: The template to render | ||
77 | * ``variables``: The variables to pass to the template | ||
78 | * ``with_context``: Whether to pass the current context variables or not | ||
79 | * ``ignore_missing``: Whether to ignore missing templates or not | ||
80 | * ``sandboxed``: Whether to sandbox the template or not | ||
diff --git a/vendor/twig/twig/doc/functions/index.rst b/vendor/twig/twig/doc/functions/index.rst new file mode 100644 index 00000000..8650cbdb --- /dev/null +++ b/vendor/twig/twig/doc/functions/index.rst | |||
@@ -0,0 +1,17 @@ | |||
1 | Functions | ||
2 | ========= | ||
3 | |||
4 | .. toctree:: | ||
5 | :maxdepth: 1 | ||
6 | |||
7 | attribute | ||
8 | block | ||
9 | constant | ||
10 | cycle | ||
11 | date | ||
12 | dump | ||
13 | include | ||
14 | parent | ||
15 | random | ||
16 | range | ||
17 | template_from_string | ||
diff --git a/vendor/twig/twig/doc/functions/parent.rst b/vendor/twig/twig/doc/functions/parent.rst new file mode 100644 index 00000000..f5bd2001 --- /dev/null +++ b/vendor/twig/twig/doc/functions/parent.rst | |||
@@ -0,0 +1,20 @@ | |||
1 | ``parent`` | ||
2 | ========== | ||
3 | |||
4 | When a template uses inheritance, it's possible to render the contents of the | ||
5 | parent block when overriding a block by using the ``parent`` function: | ||
6 | |||
7 | .. code-block:: jinja | ||
8 | |||
9 | {% extends "base.html" %} | ||
10 | |||
11 | {% block sidebar %} | ||
12 | <h3>Table Of Contents</h3> | ||
13 | ... | ||
14 | {{ parent() }} | ||
15 | {% endblock %} | ||
16 | |||
17 | The ``parent()`` call will return the content of the ``sidebar`` block as | ||
18 | defined in the ``base.html`` template. | ||
19 | |||
20 | .. seealso:: :doc:`extends<../tags/extends>`, :doc:`block<../functions/block>`, :doc:`block<../tags/block>` | ||
diff --git a/vendor/twig/twig/doc/functions/random.rst b/vendor/twig/twig/doc/functions/random.rst new file mode 100644 index 00000000..a5a916bb --- /dev/null +++ b/vendor/twig/twig/doc/functions/random.rst | |||
@@ -0,0 +1,29 @@ | |||
1 | ``random`` | ||
2 | ========== | ||
3 | |||
4 | .. versionadded:: 1.5 | ||
5 | The random function was added in Twig 1.5. | ||
6 | |||
7 | .. versionadded:: 1.6 | ||
8 | String and integer handling was added in Twig 1.6. | ||
9 | |||
10 | The ``random`` function returns a random value depending on the supplied | ||
11 | parameter type: | ||
12 | |||
13 | * a random item from a sequence; | ||
14 | * a random character from a string; | ||
15 | * a random integer between 0 and the integer parameter (inclusive). | ||
16 | |||
17 | .. code-block:: jinja | ||
18 | |||
19 | {{ random(['apple', 'orange', 'citrus']) }} {# example output: orange #} | ||
20 | {{ random('ABC') }} {# example output: C #} | ||
21 | {{ random() }} {# example output: 15386094 (works as native PHP `mt_rand`_ function) #} | ||
22 | {{ random(5) }} {# example output: 3 #} | ||
23 | |||
24 | Arguments | ||
25 | --------- | ||
26 | |||
27 | * ``values``: The values | ||
28 | |||
29 | .. _`mt_rand`: http://php.net/mt_rand | ||
diff --git a/vendor/twig/twig/doc/functions/range.rst b/vendor/twig/twig/doc/functions/range.rst new file mode 100644 index 00000000..b1fa5471 --- /dev/null +++ b/vendor/twig/twig/doc/functions/range.rst | |||
@@ -0,0 +1,45 @@ | |||
1 | ``range`` | ||
2 | ========= | ||
3 | |||
4 | Returns a list containing an arithmetic progression of integers: | ||
5 | |||
6 | .. code-block:: jinja | ||
7 | |||
8 | {% for i in range(0, 3) %} | ||
9 | {{ i }}, | ||
10 | {% endfor %} | ||
11 | |||
12 | {# returns 0, 1, 2, 3 #} | ||
13 | |||
14 | When step is given (as the third parameter), it specifies the increment (or | ||
15 | decrement): | ||
16 | |||
17 | .. code-block:: jinja | ||
18 | |||
19 | {% for i in range(0, 6, 2) %} | ||
20 | {{ i }}, | ||
21 | {% endfor %} | ||
22 | |||
23 | {# returns 0, 2, 4, 6 #} | ||
24 | |||
25 | The Twig built-in ``..`` operator is just syntactic sugar for the ``range`` | ||
26 | function (with a step of 1): | ||
27 | |||
28 | .. code-block:: jinja | ||
29 | |||
30 | {% for i in 0..3 %} | ||
31 | {{ i }}, | ||
32 | {% endfor %} | ||
33 | |||
34 | .. tip:: | ||
35 | |||
36 | The ``range`` function works as the native PHP `range`_ function. | ||
37 | |||
38 | Arguments | ||
39 | --------- | ||
40 | |||
41 | * ``low``: The first value of the sequence. | ||
42 | * ``high``: The highest possible value of the sequence. | ||
43 | * ``step``: The increment between elements of the sequence. | ||
44 | |||
45 | .. _`range`: http://php.net/range | ||
diff --git a/vendor/twig/twig/doc/functions/template_from_string.rst b/vendor/twig/twig/doc/functions/template_from_string.rst new file mode 100644 index 00000000..bbb06d86 --- /dev/null +++ b/vendor/twig/twig/doc/functions/template_from_string.rst | |||
@@ -0,0 +1,32 @@ | |||
1 | ``template_from_string`` | ||
2 | ======================== | ||
3 | |||
4 | .. versionadded:: 1.11 | ||
5 | The template_from_string function was added in Twig 1.11. | ||
6 | |||
7 | The ``template_from_string`` function loads a template from a string: | ||
8 | |||
9 | .. code-block:: jinja | ||
10 | |||
11 | {{ include(template_from_string("Hello {{ name }}") }} | ||
12 | {{ include(template_from_string(page.template)) }} | ||
13 | |||
14 | .. note:: | ||
15 | |||
16 | The ``template_from_string`` function is not available by default. You | ||
17 | must add the ``Twig_Extension_StringLoader`` extension explicitly when | ||
18 | creating your Twig environment:: | ||
19 | |||
20 | $twig = new Twig_Environment(...); | ||
21 | $twig->addExtension(new Twig_Extension_StringLoader()); | ||
22 | |||
23 | .. note:: | ||
24 | |||
25 | Even if you will probably always use the ``template_from_string`` function | ||
26 | with the ``include`` function, you can use it with any tag or function that | ||
27 | takes a template as an argument (like the ``embed`` or ``extends`` tags). | ||
28 | |||
29 | Arguments | ||
30 | --------- | ||
31 | |||
32 | * ``template``: The template | ||
diff --git a/vendor/twig/twig/doc/index.rst b/vendor/twig/twig/doc/index.rst new file mode 100644 index 00000000..3e5166c6 --- /dev/null +++ b/vendor/twig/twig/doc/index.rst | |||
@@ -0,0 +1,18 @@ | |||
1 | Twig | ||
2 | ==== | ||
3 | |||
4 | .. toctree:: | ||
5 | :maxdepth: 2 | ||
6 | |||
7 | intro | ||
8 | templates | ||
9 | api | ||
10 | advanced | ||
11 | internals | ||
12 | recipes | ||
13 | coding_standards | ||
14 | tags/index | ||
15 | filters/index | ||
16 | functions/index | ||
17 | tests/index | ||
18 | deprecated | ||
diff --git a/vendor/twig/twig/doc/internals.rst b/vendor/twig/twig/doc/internals.rst new file mode 100644 index 00000000..79a3c8d5 --- /dev/null +++ b/vendor/twig/twig/doc/internals.rst | |||
@@ -0,0 +1,140 @@ | |||
1 | Twig Internals | ||
2 | ============== | ||
3 | |||
4 | Twig is very extensible and you can easily hack it. Keep in mind that you | ||
5 | should probably try to create an extension before hacking the core, as most | ||
6 | features and enhancements can be done with extensions. This chapter is also | ||
7 | useful for people who want to understand how Twig works under the hood. | ||
8 | |||
9 | How Twig works? | ||
10 | --------------- | ||
11 | |||
12 | The rendering of a Twig template can be summarized into four key steps: | ||
13 | |||
14 | * **Load** the template: If the template is already compiled, load it and go | ||
15 | to the *evaluation* step, otherwise: | ||
16 | |||
17 | * First, the **lexer** tokenizes the template source code into small pieces | ||
18 | for easier processing; | ||
19 | * Then, the **parser** converts the token stream into a meaningful tree | ||
20 | of nodes (the Abstract Syntax Tree); | ||
21 | * Eventually, the *compiler* transforms the AST into PHP code; | ||
22 | |||
23 | * **Evaluate** the template: It basically means calling the ``display()`` | ||
24 | method of the compiled template and passing it the context. | ||
25 | |||
26 | The Lexer | ||
27 | --------- | ||
28 | |||
29 | The lexer tokenizes a template source code into a token stream (each token is | ||
30 | an instance of ``Twig_Token``, and the stream is an instance of | ||
31 | ``Twig_TokenStream``). The default lexer recognizes 13 different token types: | ||
32 | |||
33 | * ``Twig_Token::BLOCK_START_TYPE``, ``Twig_Token::BLOCK_END_TYPE``: Delimiters for blocks (``{% %}``) | ||
34 | * ``Twig_Token::VAR_START_TYPE``, ``Twig_Token::VAR_END_TYPE``: Delimiters for variables (``{{ }}``) | ||
35 | * ``Twig_Token::TEXT_TYPE``: A text outside an expression; | ||
36 | * ``Twig_Token::NAME_TYPE``: A name in an expression; | ||
37 | * ``Twig_Token::NUMBER_TYPE``: A number in an expression; | ||
38 | * ``Twig_Token::STRING_TYPE``: A string in an expression; | ||
39 | * ``Twig_Token::OPERATOR_TYPE``: An operator; | ||
40 | * ``Twig_Token::PUNCTUATION_TYPE``: A punctuation sign; | ||
41 | * ``Twig_Token::INTERPOLATION_START_TYPE``, ``Twig_Token::INTERPOLATION_END_TYPE`` (as of Twig 1.5): Delimiters for string interpolation; | ||
42 | * ``Twig_Token::EOF_TYPE``: Ends of template. | ||
43 | |||
44 | You can manually convert a source code into a token stream by calling the | ||
45 | ``tokenize()`` of an environment:: | ||
46 | |||
47 | $stream = $twig->tokenize($source, $identifier); | ||
48 | |||
49 | As the stream has a ``__toString()`` method, you can have a textual | ||
50 | representation of it by echoing the object:: | ||
51 | |||
52 | echo $stream."\n"; | ||
53 | |||
54 | Here is the output for the ``Hello {{ name }}`` template: | ||
55 | |||
56 | .. code-block:: text | ||
57 | |||
58 | TEXT_TYPE(Hello ) | ||
59 | VAR_START_TYPE() | ||
60 | NAME_TYPE(name) | ||
61 | VAR_END_TYPE() | ||
62 | EOF_TYPE() | ||
63 | |||
64 | .. note:: | ||
65 | |||
66 | You can change the default lexer use by Twig (``Twig_Lexer``) by calling | ||
67 | the ``setLexer()`` method:: | ||
68 | |||
69 | $twig->setLexer($lexer); | ||
70 | |||
71 | The Parser | ||
72 | ---------- | ||
73 | |||
74 | The parser converts the token stream into an AST (Abstract Syntax Tree), or a | ||
75 | node tree (an instance of ``Twig_Node_Module``). The core extension defines | ||
76 | the basic nodes like: ``for``, ``if``, ... and the expression nodes. | ||
77 | |||
78 | You can manually convert a token stream into a node tree by calling the | ||
79 | ``parse()`` method of an environment:: | ||
80 | |||
81 | $nodes = $twig->parse($stream); | ||
82 | |||
83 | Echoing the node object gives you a nice representation of the tree:: | ||
84 | |||
85 | echo $nodes."\n"; | ||
86 | |||
87 | Here is the output for the ``Hello {{ name }}`` template: | ||
88 | |||
89 | .. code-block:: text | ||
90 | |||
91 | Twig_Node_Module( | ||
92 | Twig_Node_Text(Hello ) | ||
93 | Twig_Node_Print( | ||
94 | Twig_Node_Expression_Name(name) | ||
95 | ) | ||
96 | ) | ||
97 | |||
98 | .. note:: | ||
99 | |||
100 | The default parser (``Twig_TokenParser``) can be also changed by calling the | ||
101 | ``setParser()`` method:: | ||
102 | |||
103 | $twig->setParser($parser); | ||
104 | |||
105 | The Compiler | ||
106 | ------------ | ||
107 | |||
108 | The last step is done by the compiler. It takes a node tree as an input and | ||
109 | generates PHP code usable for runtime execution of the template. | ||
110 | |||
111 | You can call the compiler by hand with the ``compile()`` method of an | ||
112 | environment:: | ||
113 | |||
114 | $php = $twig->compile($nodes); | ||
115 | |||
116 | The ``compile()`` method returns the PHP source code representing the node. | ||
117 | |||
118 | The generated template for a ``Hello {{ name }}`` template reads as follows | ||
119 | (the actual output can differ depending on the version of Twig you are | ||
120 | using):: | ||
121 | |||
122 | /* Hello {{ name }} */ | ||
123 | class __TwigTemplate_1121b6f109fe93ebe8c6e22e3712bceb extends Twig_Template | ||
124 | { | ||
125 | protected function doDisplay(array $context, array $blocks = array()) | ||
126 | { | ||
127 | // line 1 | ||
128 | echo "Hello "; | ||
129 | echo twig_escape_filter($this->env, $this->getContext($context, "name"), "ndex", null, true); | ||
130 | } | ||
131 | |||
132 | // some more code | ||
133 | } | ||
134 | |||
135 | .. note:: | ||
136 | |||
137 | As for the lexer and the parser, the default compiler (``Twig_Compiler``) can | ||
138 | be changed by calling the ``setCompiler()`` method:: | ||
139 | |||
140 | $twig->setCompiler($compiler); | ||
diff --git a/vendor/twig/twig/doc/intro.rst b/vendor/twig/twig/doc/intro.rst new file mode 100644 index 00000000..bdcdb8a0 --- /dev/null +++ b/vendor/twig/twig/doc/intro.rst | |||
@@ -0,0 +1,164 @@ | |||
1 | Introduction | ||
2 | ============ | ||
3 | |||
4 | This is the documentation for Twig, the flexible, fast, and secure template | ||
5 | engine for PHP. | ||
6 | |||
7 | If you have any exposure to other text-based template languages, such as | ||
8 | Smarty, Django, or Jinja, you should feel right at home with Twig. It's both | ||
9 | designer and developer friendly by sticking to PHP's principles and adding | ||
10 | functionality useful for templating environments. | ||
11 | |||
12 | The key-features are... | ||
13 | |||
14 | * *Fast*: Twig compiles templates down to plain optimized PHP code. The | ||
15 | overhead compared to regular PHP code was reduced to the very minimum. | ||
16 | |||
17 | * *Secure*: Twig has a sandbox mode to evaluate untrusted template code. This | ||
18 | allows Twig to be used as a template language for applications where users | ||
19 | may modify the template design. | ||
20 | |||
21 | * *Flexible*: Twig is powered by a flexible lexer and parser. This allows the | ||
22 | developer to define its own custom tags and filters, and create its own DSL. | ||
23 | |||
24 | Prerequisites | ||
25 | ------------- | ||
26 | |||
27 | Twig needs at least **PHP 5.2.4** to run. | ||
28 | |||
29 | Installation | ||
30 | ------------ | ||
31 | |||
32 | You have multiple ways to install Twig. | ||
33 | |||
34 | Installing via Composer (recommended) | ||
35 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
36 | |||
37 | 1. Install composer in your project: | ||
38 | |||
39 | .. code-block:: bash | ||
40 | |||
41 | curl -s http://getcomposer.org/installer | php | ||
42 | |||
43 | 2. Create a ``composer.json`` file in your project root: | ||
44 | |||
45 | .. code-block:: javascript | ||
46 | |||
47 | { | ||
48 | "require": { | ||
49 | "twig/twig": "1.*" | ||
50 | } | ||
51 | } | ||
52 | |||
53 | 3. Install via composer | ||
54 | |||
55 | .. code-block:: bash | ||
56 | |||
57 | php composer.phar install | ||
58 | |||
59 | .. note:: | ||
60 | If you want to learn more about Composer, the ``composer.json`` file syntax | ||
61 | and its usage, you can read the `online documentation`_. | ||
62 | |||
63 | Installing from the tarball release | ||
64 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
65 | |||
66 | 1. Download the most recent tarball from the `download page`_ | ||
67 | 2. Unpack the tarball | ||
68 | 3. Move the files somewhere in your project | ||
69 | |||
70 | Installing the development version | ||
71 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
72 | |||
73 | 1. Install Git | ||
74 | 2. ``git clone git://github.com/fabpot/Twig.git`` | ||
75 | |||
76 | Installing the PEAR package | ||
77 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
78 | |||
79 | 1. Install PEAR | ||
80 | 2. ``pear channel-discover pear.twig-project.org`` | ||
81 | 3. ``pear install twig/Twig`` (or ``pear install twig/Twig-beta``) | ||
82 | |||
83 | |||
84 | Installing the C extension | ||
85 | ~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
86 | |||
87 | .. versionadded:: 1.4 | ||
88 | The C extension was added in Twig 1.4. | ||
89 | |||
90 | Twig comes with a C extension that enhances the performance of the Twig | ||
91 | runtime engine. You can install it like any other PHP extension: | ||
92 | |||
93 | .. code-block:: bash | ||
94 | |||
95 | $ cd ext/twig | ||
96 | $ phpize | ||
97 | $ ./configure | ||
98 | $ make | ||
99 | $ make install | ||
100 | |||
101 | Finally, enable the extension in your ``php.ini`` configuration file: | ||
102 | |||
103 | .. code-block:: ini | ||
104 | |||
105 | extension=twig.so | ||
106 | |||
107 | And from now on, Twig will automatically compile your templates to take | ||
108 | advantage of the C extension. Note that this extension does not replace the | ||
109 | PHP code but only provides an optimized version of the | ||
110 | ``Twig_Template::getAttribute()`` method. | ||
111 | |||
112 | .. tip:: | ||
113 | |||
114 | On Windows, you can also simply download and install a `pre-built DLL`_. | ||
115 | |||
116 | Basic API Usage | ||
117 | --------------- | ||
118 | |||
119 | This section gives you a brief introduction to the PHP API for Twig. | ||
120 | |||
121 | The first step to use Twig is to register its autoloader:: | ||
122 | |||
123 | require_once '/path/to/lib/Twig/Autoloader.php'; | ||
124 | Twig_Autoloader::register(); | ||
125 | |||
126 | Replace the ``/path/to/lib/`` path with the path you used for Twig | ||
127 | installation. | ||
128 | |||
129 | If you have installed Twig via Composer you can take advantage of Composer's | ||
130 | autoload mechanism by replacing the previous snippet for:: | ||
131 | |||
132 | require_once '/path/to/vendor/autoload.php'; | ||
133 | |||
134 | .. note:: | ||
135 | |||
136 | Twig follows the PEAR convention names for its classes, which means you | ||
137 | can easily integrate Twig classes loading in your own autoloader. | ||
138 | |||
139 | .. code-block:: php | ||
140 | |||
141 | $loader = new Twig_Loader_String(); | ||
142 | $twig = new Twig_Environment($loader); | ||
143 | |||
144 | echo $twig->render('Hello {{ name }}!', array('name' => 'Fabien')); | ||
145 | |||
146 | Twig uses a loader (``Twig_Loader_String``) to locate templates, and an | ||
147 | environment (``Twig_Environment``) to store the configuration. | ||
148 | |||
149 | The ``render()`` method loads the template passed as a first argument and | ||
150 | renders it with the variables passed as a second argument. | ||
151 | |||
152 | As templates are generally stored on the filesystem, Twig also comes with a | ||
153 | filesystem loader:: | ||
154 | |||
155 | $loader = new Twig_Loader_Filesystem('/path/to/templates'); | ||
156 | $twig = new Twig_Environment($loader, array( | ||
157 | 'cache' => '/path/to/compilation_cache', | ||
158 | )); | ||
159 | |||
160 | echo $twig->render('index.html', array('name' => 'Fabien')); | ||
161 | |||
162 | .. _`download page`: https://github.com/fabpot/Twig/tags | ||
163 | .. _`online documentation`: http://getcomposer.org/doc | ||
164 | .. _`pre-built DLL`: https://github.com/stealth35/stealth35.github.com/downloads | ||
diff --git a/vendor/twig/twig/doc/recipes.rst b/vendor/twig/twig/doc/recipes.rst new file mode 100644 index 00000000..dfcc9205 --- /dev/null +++ b/vendor/twig/twig/doc/recipes.rst | |||
@@ -0,0 +1,475 @@ | |||
1 | Recipes | ||
2 | ======= | ||
3 | |||
4 | Making a Layout conditional | ||
5 | --------------------------- | ||
6 | |||
7 | Working with Ajax means that the same content is sometimes displayed as is, | ||
8 | and sometimes decorated with a layout. As Twig layout template names can be | ||
9 | any valid expression, you can pass a variable that evaluates to ``true`` when | ||
10 | the request is made via Ajax and choose the layout accordingly: | ||
11 | |||
12 | .. code-block:: jinja | ||
13 | |||
14 | {% extends request.ajax ? "base_ajax.html" : "base.html" %} | ||
15 | |||
16 | {% block content %} | ||
17 | This is the content to be displayed. | ||
18 | {% endblock %} | ||
19 | |||
20 | Making an Include dynamic | ||
21 | ------------------------- | ||
22 | |||
23 | When including a template, its name does not need to be a string. For | ||
24 | instance, the name can depend on the value of a variable: | ||
25 | |||
26 | .. code-block:: jinja | ||
27 | |||
28 | {% include var ~ '_foo.html' %} | ||
29 | |||
30 | If ``var`` evaluates to ``index``, the ``index_foo.html`` template will be | ||
31 | rendered. | ||
32 | |||
33 | As a matter of fact, the template name can be any valid expression, such as | ||
34 | the following: | ||
35 | |||
36 | .. code-block:: jinja | ||
37 | |||
38 | {% include var|default('index') ~ '_foo.html' %} | ||
39 | |||
40 | Overriding a Template that also extends itself | ||
41 | ---------------------------------------------- | ||
42 | |||
43 | A template can be customized in two different ways: | ||
44 | |||
45 | * *Inheritance*: A template *extends* a parent template and overrides some | ||
46 | blocks; | ||
47 | |||
48 | * *Replacement*: If you use the filesystem loader, Twig loads the first | ||
49 | template it finds in a list of configured directories; a template found in a | ||
50 | directory *replaces* another one from a directory further in the list. | ||
51 | |||
52 | But how do you combine both: *replace* a template that also extends itself | ||
53 | (aka a template in a directory further in the list)? | ||
54 | |||
55 | Let's say that your templates are loaded from both ``.../templates/mysite`` | ||
56 | and ``.../templates/default`` in this order. The ``page.twig`` template, | ||
57 | stored in ``.../templates/default`` reads as follows: | ||
58 | |||
59 | .. code-block:: jinja | ||
60 | |||
61 | {# page.twig #} | ||
62 | {% extends "layout.twig" %} | ||
63 | |||
64 | {% block content %} | ||
65 | {% endblock %} | ||
66 | |||
67 | You can replace this template by putting a file with the same name in | ||
68 | ``.../templates/mysite``. And if you want to extend the original template, you | ||
69 | might be tempted to write the following: | ||
70 | |||
71 | .. code-block:: jinja | ||
72 | |||
73 | {# page.twig in .../templates/mysite #} | ||
74 | {% extends "page.twig" %} {# from .../templates/default #} | ||
75 | |||
76 | Of course, this will not work as Twig will always load the template from | ||
77 | ``.../templates/mysite``. | ||
78 | |||
79 | It turns out it is possible to get this to work, by adding a directory right | ||
80 | at the end of your template directories, which is the parent of all of the | ||
81 | other directories: ``.../templates`` in our case. This has the effect of | ||
82 | making every template file within our system uniquely addressable. Most of the | ||
83 | time you will use the "normal" paths, but in the special case of wanting to | ||
84 | extend a template with an overriding version of itself we can reference its | ||
85 | parent's full, unambiguous template path in the extends tag: | ||
86 | |||
87 | .. code-block:: jinja | ||
88 | |||
89 | {# page.twig in .../templates/mysite #} | ||
90 | {% extends "default/page.twig" %} {# from .../templates #} | ||
91 | |||
92 | .. note:: | ||
93 | |||
94 | This recipe was inspired by the following Django wiki page: | ||
95 | http://code.djangoproject.com/wiki/ExtendingTemplates | ||
96 | |||
97 | Customizing the Syntax | ||
98 | ---------------------- | ||
99 | |||
100 | Twig allows some syntax customization for the block delimiters. It's not | ||
101 | recommended to use this feature as templates will be tied with your custom | ||
102 | syntax. But for specific projects, it can make sense to change the defaults. | ||
103 | |||
104 | To change the block delimiters, you need to create your own lexer object:: | ||
105 | |||
106 | $twig = new Twig_Environment(); | ||
107 | |||
108 | $lexer = new Twig_Lexer($twig, array( | ||
109 | 'tag_comment' => array('{#', '#}'), | ||
110 | 'tag_block' => array('{%', '%}'), | ||
111 | 'tag_variable' => array('{{', '}}'), | ||
112 | 'interpolation' => array('#{', '}'), | ||
113 | )); | ||
114 | $twig->setLexer($lexer); | ||
115 | |||
116 | Here are some configuration example that simulates some other template engines | ||
117 | syntax:: | ||
118 | |||
119 | // Ruby erb syntax | ||
120 | $lexer = new Twig_Lexer($twig, array( | ||
121 | 'tag_comment' => array('<%#', '%>'), | ||
122 | 'tag_block' => array('<%', '%>'), | ||
123 | 'tag_variable' => array('<%=', '%>'), | ||
124 | )); | ||
125 | |||
126 | // SGML Comment Syntax | ||
127 | $lexer = new Twig_Lexer($twig, array( | ||
128 | 'tag_comment' => array('<!--#', '-->'), | ||
129 | 'tag_block' => array('<!--', '-->'), | ||
130 | 'tag_variable' => array('${', '}'), | ||
131 | )); | ||
132 | |||
133 | // Smarty like | ||
134 | $lexer = new Twig_Lexer($twig, array( | ||
135 | 'tag_comment' => array('{*', '*}'), | ||
136 | 'tag_block' => array('{', '}'), | ||
137 | 'tag_variable' => array('{$', '}'), | ||
138 | )); | ||
139 | |||
140 | Using dynamic Object Properties | ||
141 | ------------------------------- | ||
142 | |||
143 | When Twig encounters a variable like ``article.title``, it tries to find a | ||
144 | ``title`` public property in the ``article`` object. | ||
145 | |||
146 | It also works if the property does not exist but is rather defined dynamically | ||
147 | thanks to the magic ``__get()`` method; you just need to also implement the | ||
148 | ``__isset()`` magic method like shown in the following snippet of code:: | ||
149 | |||
150 | class Article | ||
151 | { | ||
152 | public function __get($name) | ||
153 | { | ||
154 | if ('title' == $name) { | ||
155 | return 'The title'; | ||
156 | } | ||
157 | |||
158 | // throw some kind of error | ||
159 | } | ||
160 | |||
161 | public function __isset($name) | ||
162 | { | ||
163 | if ('title' == $name) { | ||
164 | return true; | ||
165 | } | ||
166 | |||
167 | return false; | ||
168 | } | ||
169 | } | ||
170 | |||
171 | Accessing the parent Context in Nested Loops | ||
172 | -------------------------------------------- | ||
173 | |||
174 | Sometimes, when using nested loops, you need to access the parent context. The | ||
175 | parent context is always accessible via the ``loop.parent`` variable. For | ||
176 | instance, if you have the following template data:: | ||
177 | |||
178 | $data = array( | ||
179 | 'topics' => array( | ||
180 | 'topic1' => array('Message 1 of topic 1', 'Message 2 of topic 1'), | ||
181 | 'topic2' => array('Message 1 of topic 2', 'Message 2 of topic 2'), | ||
182 | ), | ||
183 | ); | ||
184 | |||
185 | And the following template to display all messages in all topics: | ||
186 | |||
187 | .. code-block:: jinja | ||
188 | |||
189 | {% for topic, messages in topics %} | ||
190 | * {{ loop.index }}: {{ topic }} | ||
191 | {% for message in messages %} | ||
192 | - {{ loop.parent.loop.index }}.{{ loop.index }}: {{ message }} | ||
193 | {% endfor %} | ||
194 | {% endfor %} | ||
195 | |||
196 | The output will be similar to: | ||
197 | |||
198 | .. code-block:: text | ||
199 | |||
200 | * 1: topic1 | ||
201 | - 1.1: The message 1 of topic 1 | ||
202 | - 1.2: The message 2 of topic 1 | ||
203 | * 2: topic2 | ||
204 | - 2.1: The message 1 of topic 2 | ||
205 | - 2.2: The message 2 of topic 2 | ||
206 | |||
207 | In the inner loop, the ``loop.parent`` variable is used to access the outer | ||
208 | context. So, the index of the current ``topic`` defined in the outer for loop | ||
209 | is accessible via the ``loop.parent.loop.index`` variable. | ||
210 | |||
211 | Defining undefined Functions and Filters on the Fly | ||
212 | --------------------------------------------------- | ||
213 | |||
214 | When a function (or a filter) is not defined, Twig defaults to throw a | ||
215 | ``Twig_Error_Syntax`` exception. However, it can also call a `callback`_ (any | ||
216 | valid PHP callable) which should return a function (or a filter). | ||
217 | |||
218 | For filters, register callbacks with ``registerUndefinedFilterCallback()``. | ||
219 | For functions, use ``registerUndefinedFunctionCallback()``:: | ||
220 | |||
221 | // auto-register all native PHP functions as Twig functions | ||
222 | // don't try this at home as it's not secure at all! | ||
223 | $twig->registerUndefinedFunctionCallback(function ($name) { | ||
224 | if (function_exists($name)) { | ||
225 | return new Twig_Function_Function($name); | ||
226 | } | ||
227 | |||
228 | return false; | ||
229 | }); | ||
230 | |||
231 | If the callable is not able to return a valid function (or filter), it must | ||
232 | return ``false``. | ||
233 | |||
234 | If you register more than one callback, Twig will call them in turn until one | ||
235 | does not return ``false``. | ||
236 | |||
237 | .. tip:: | ||
238 | |||
239 | As the resolution of functions and filters is done during compilation, | ||
240 | there is no overhead when registering these callbacks. | ||
241 | |||
242 | Validating the Template Syntax | ||
243 | ------------------------------ | ||
244 | |||
245 | When template code is providing by a third-party (through a web interface for | ||
246 | instance), it might be interesting to validate the template syntax before | ||
247 | saving it. If the template code is stored in a `$template` variable, here is | ||
248 | how you can do it:: | ||
249 | |||
250 | try { | ||
251 | $twig->parse($twig->tokenize($template)); | ||
252 | |||
253 | // the $template is valid | ||
254 | } catch (Twig_Error_Syntax $e) { | ||
255 | // $template contains one or more syntax errors | ||
256 | } | ||
257 | |||
258 | If you iterate over a set of files, you can pass the filename to the | ||
259 | ``tokenize()`` method to get the filename in the exception message:: | ||
260 | |||
261 | foreach ($files as $file) { | ||
262 | try { | ||
263 | $twig->parse($twig->tokenize($template, $file)); | ||
264 | |||
265 | // the $template is valid | ||
266 | } catch (Twig_Error_Syntax $e) { | ||
267 | // $template contains one or more syntax errors | ||
268 | } | ||
269 | } | ||
270 | |||
271 | .. note:: | ||
272 | |||
273 | This method won't catch any sandbox policy violations because the policy | ||
274 | is enforced during template rendering (as Twig needs the context for some | ||
275 | checks like allowed methods on objects). | ||
276 | |||
277 | Refreshing modified Templates when APC is enabled and apc.stat = 0 | ||
278 | ------------------------------------------------------------------ | ||
279 | |||
280 | When using APC with ``apc.stat`` set to ``0`` and Twig cache enabled, clearing | ||
281 | the template cache won't update the APC cache. To get around this, one can | ||
282 | extend ``Twig_Environment`` and force the update of the APC cache when Twig | ||
283 | rewrites the cache:: | ||
284 | |||
285 | class Twig_Environment_APC extends Twig_Environment | ||
286 | { | ||
287 | protected function writeCacheFile($file, $content) | ||
288 | { | ||
289 | parent::writeCacheFile($file, $content); | ||
290 | |||
291 | // Compile cached file into bytecode cache | ||
292 | apc_compile_file($file); | ||
293 | } | ||
294 | } | ||
295 | |||
296 | Reusing a stateful Node Visitor | ||
297 | ------------------------------- | ||
298 | |||
299 | When attaching a visitor to a ``Twig_Environment`` instance, Twig uses it to | ||
300 | visit *all* templates it compiles. If you need to keep some state information | ||
301 | around, you probably want to reset it when visiting a new template. | ||
302 | |||
303 | This can be easily achieved with the following code:: | ||
304 | |||
305 | protected $someTemplateState = array(); | ||
306 | |||
307 | public function enterNode(Twig_NodeInterface $node, Twig_Environment $env) | ||
308 | { | ||
309 | if ($node instanceof Twig_Node_Module) { | ||
310 | // reset the state as we are entering a new template | ||
311 | $this->someTemplateState = array(); | ||
312 | } | ||
313 | |||
314 | // ... | ||
315 | |||
316 | return $node; | ||
317 | } | ||
318 | |||
319 | Using the Template name to set the default Escaping Strategy | ||
320 | ------------------------------------------------------------ | ||
321 | |||
322 | .. versionadded:: 1.8 | ||
323 | This recipe requires Twig 1.8 or later. | ||
324 | |||
325 | The ``autoescape`` option determines the default escaping strategy to use when | ||
326 | no escaping is applied on a variable. When Twig is used to mostly generate | ||
327 | HTML files, you can set it to ``html`` and explicitly change it to ``js`` when | ||
328 | you have some dynamic JavaScript files thanks to the ``autoescape`` tag: | ||
329 | |||
330 | .. code-block:: jinja | ||
331 | |||
332 | {% autoescape 'js' %} | ||
333 | ... some JS ... | ||
334 | {% endautoescape %} | ||
335 | |||
336 | But if you have many HTML and JS files, and if your template names follow some | ||
337 | conventions, you can instead determine the default escaping strategy to use | ||
338 | based on the template name. Let's say that your template names always ends | ||
339 | with ``.html`` for HTML files, ``.js`` for JavaScript ones, and ``.css`` for | ||
340 | stylesheets, here is how you can configure Twig:: | ||
341 | |||
342 | class TwigEscapingGuesser | ||
343 | { | ||
344 | function guess($filename) | ||
345 | { | ||
346 | // get the format | ||
347 | $format = substr($filename, strrpos($filename, '.') + 1); | ||
348 | |||
349 | switch ($format) { | ||
350 | case 'js': | ||
351 | return 'js'; | ||
352 | case 'css': | ||
353 | return 'css'; | ||
354 | case 'html': | ||
355 | default: | ||
356 | return 'html'; | ||
357 | } | ||
358 | } | ||
359 | } | ||
360 | |||
361 | $loader = new Twig_Loader_Filesystem('/path/to/templates'); | ||
362 | $twig = new Twig_Environment($loader, array( | ||
363 | 'autoescape' => array(new TwigEscapingGuesser(), 'guess'), | ||
364 | )); | ||
365 | |||
366 | This dynamic strategy does not incur any overhead at runtime as auto-escaping | ||
367 | is done at compilation time. | ||
368 | |||
369 | Using a Database to store Templates | ||
370 | ----------------------------------- | ||
371 | |||
372 | If you are developing a CMS, templates are usually stored in a database. This | ||
373 | recipe gives you a simple PDO template loader you can use as a starting point | ||
374 | for your own. | ||
375 | |||
376 | First, let's create a temporary in-memory SQLite3 database to work with:: | ||
377 | |||
378 | $dbh = new PDO('sqlite::memory:'); | ||
379 | $dbh->exec('CREATE TABLE templates (name STRING, source STRING, last_modified INTEGER)'); | ||
380 | $base = '{% block content %}{% endblock %}'; | ||
381 | $index = ' | ||
382 | {% extends "base.twig" %} | ||
383 | {% block content %}Hello {{ name }}{% endblock %} | ||
384 | '; | ||
385 | $now = time(); | ||
386 | $dbh->exec("INSERT INTO templates (name, source, last_modified) VALUES ('base.twig', '$base', $now)"); | ||
387 | $dbh->exec("INSERT INTO templates (name, source, last_modified) VALUES ('index.twig', '$index', $now)"); | ||
388 | |||
389 | We have created a simple ``templates`` table that hosts two templates: | ||
390 | ``base.twig`` and ``index.twig``. | ||
391 | |||
392 | Now, let's define a loader able to use this database:: | ||
393 | |||
394 | class DatabaseTwigLoader implements Twig_LoaderInterface, Twig_ExistsLoaderInterface | ||
395 | { | ||
396 | protected $dbh; | ||
397 | |||
398 | public function __construct(PDO $dbh) | ||
399 | { | ||
400 | $this->dbh = $dbh; | ||
401 | } | ||
402 | |||
403 | public function getSource($name) | ||
404 | { | ||
405 | if (false === $source = $this->getValue('source', $name)) { | ||
406 | throw new Twig_Error_Loader(sprintf('Template "%s" does not exist.', $name)); | ||
407 | } | ||
408 | |||
409 | return $source; | ||
410 | } | ||
411 | |||
412 | // Twig_ExistsLoaderInterface as of Twig 1.11 | ||
413 | public function exists($name) | ||
414 | { | ||
415 | return $name === $this->getValue('name', $name); | ||
416 | } | ||
417 | |||
418 | public function getCacheKey($name) | ||
419 | { | ||
420 | return $name; | ||
421 | } | ||
422 | |||
423 | public function isFresh($name, $time) | ||
424 | { | ||
425 | if (false === $lastModified = $this->getValue('last_modified', $name)) { | ||
426 | return false; | ||
427 | } | ||
428 | |||
429 | return $lastModified <= $time; | ||
430 | } | ||
431 | |||
432 | protected function getValue($column, $name) | ||
433 | { | ||
434 | $sth = $this->dbh->prepare('SELECT '.$column.' FROM templates WHERE name = :name'); | ||
435 | $sth->execute(array(':name' => (string) $name)); | ||
436 | |||
437 | return $sth->fetchColumn(); | ||
438 | } | ||
439 | } | ||
440 | |||
441 | Finally, here is an example on how you can use it:: | ||
442 | |||
443 | $loader = new DatabaseTwigLoader($dbh); | ||
444 | $twig = new Twig_Environment($loader); | ||
445 | |||
446 | echo $twig->render('index.twig', array('name' => 'Fabien')); | ||
447 | |||
448 | Using different Template Sources | ||
449 | -------------------------------- | ||
450 | |||
451 | This recipe is the continuation of the previous one. Even if you store the | ||
452 | contributed templates in a database, you might want to keep the original/base | ||
453 | templates on the filesystem. When templates can be loaded from different | ||
454 | sources, you need to use the ``Twig_Loader_Chain`` loader. | ||
455 | |||
456 | As you can see in the previous recipe, we reference the template in the exact | ||
457 | same way as we would have done it with a regular filesystem loader. This is | ||
458 | the key to be able to mix and match templates coming from the database, the | ||
459 | filesystem, or any other loader for that matter: the template name should be a | ||
460 | logical name, and not the path from the filesystem:: | ||
461 | |||
462 | $loader1 = new DatabaseTwigLoader($dbh); | ||
463 | $loader2 = new Twig_Loader_Array(array( | ||
464 | 'base.twig' => '{% block content %}{% endblock %}', | ||
465 | )); | ||
466 | $loader = new Twig_Loader_Chain(array($loader1, $loader2)); | ||
467 | |||
468 | $twig = new Twig_Environment($loader); | ||
469 | |||
470 | echo $twig->render('index.twig', array('name' => 'Fabien')); | ||
471 | |||
472 | Now that the ``base.twig`` templates is defined in an array loader, you can | ||
473 | remove it from the database, and everything else will still work as before. | ||
474 | |||
475 | .. _callback: http://www.php.net/manual/en/function.is-callable.php | ||
diff --git a/vendor/twig/twig/doc/tags/autoescape.rst b/vendor/twig/twig/doc/tags/autoescape.rst new file mode 100644 index 00000000..c5ff0c2c --- /dev/null +++ b/vendor/twig/twig/doc/tags/autoescape.rst | |||
@@ -0,0 +1,71 @@ | |||
1 | ``autoescape`` | ||
2 | ============== | ||
3 | |||
4 | Whether automatic escaping is enabled or not, you can mark a section of a | ||
5 | template to be escaped or not by using the ``autoescape`` tag: | ||
6 | |||
7 | .. code-block:: jinja | ||
8 | |||
9 | {# The following syntax works as of Twig 1.8 -- see the note below for previous versions #} | ||
10 | |||
11 | {% autoescape %} | ||
12 | Everything will be automatically escaped in this block | ||
13 | using the HTML strategy | ||
14 | {% endautoescape %} | ||
15 | |||
16 | {% autoescape 'html' %} | ||
17 | Everything will be automatically escaped in this block | ||
18 | using the HTML strategy | ||
19 | {% endautoescape %} | ||
20 | |||
21 | {% autoescape 'js' %} | ||
22 | Everything will be automatically escaped in this block | ||
23 | using the js escaping strategy | ||
24 | {% endautoescape %} | ||
25 | |||
26 | {% autoescape false %} | ||
27 | Everything will be outputted as is in this block | ||
28 | {% endautoescape %} | ||
29 | |||
30 | .. note:: | ||
31 | |||
32 | Before Twig 1.8, the syntax was different: | ||
33 | |||
34 | .. code-block:: jinja | ||
35 | |||
36 | {% autoescape true %} | ||
37 | Everything will be automatically escaped in this block | ||
38 | using the HTML strategy | ||
39 | {% endautoescape %} | ||
40 | |||
41 | {% autoescape false %} | ||
42 | Everything will be outputted as is in this block | ||
43 | {% endautoescape %} | ||
44 | |||
45 | {% autoescape true js %} | ||
46 | Everything will be automatically escaped in this block | ||
47 | using the js escaping strategy | ||
48 | {% endautoescape %} | ||
49 | |||
50 | When automatic escaping is enabled everything is escaped by default except for | ||
51 | values explicitly marked as safe. Those can be marked in the template by using | ||
52 | the :doc:`raw<../filters/raw>` filter: | ||
53 | |||
54 | .. code-block:: jinja | ||
55 | |||
56 | {% autoescape %} | ||
57 | {{ safe_value|raw }} | ||
58 | {% endautoescape %} | ||
59 | |||
60 | Functions returning template data (like :doc:`macros<macro>` and | ||
61 | :doc:`parent<../functions/parent>`) always return safe markup. | ||
62 | |||
63 | .. note:: | ||
64 | |||
65 | Twig is smart enough to not escape an already escaped value by the | ||
66 | :doc:`escape<../filters/escape>` filter. | ||
67 | |||
68 | .. note:: | ||
69 | |||
70 | The chapter :doc:`Twig for Developers<../api>` gives more information | ||
71 | about when and how automatic escaping is applied. | ||
diff --git a/vendor/twig/twig/doc/tags/block.rst b/vendor/twig/twig/doc/tags/block.rst new file mode 100644 index 00000000..e3804823 --- /dev/null +++ b/vendor/twig/twig/doc/tags/block.rst | |||
@@ -0,0 +1,11 @@ | |||
1 | ``block`` | ||
2 | ========= | ||
3 | |||
4 | Blocks are used for inheritance and act as placeholders and replacements at | ||
5 | the same time. They are documented in detail in the documentation for the | ||
6 | :doc:`extends<../tags/extends>` tag. | ||
7 | |||
8 | Block names should consist of alphanumeric characters, and underscores. Dashes | ||
9 | are not permitted. | ||
10 | |||
11 | .. seealso:: :doc:`block<../functions/block>`, :doc:`parent<../functions/parent>`, :doc:`use<../tags/use>`, :doc:`extends<../tags/extends>` | ||
diff --git a/vendor/twig/twig/doc/tags/do.rst b/vendor/twig/twig/doc/tags/do.rst new file mode 100644 index 00000000..eca63d0a --- /dev/null +++ b/vendor/twig/twig/doc/tags/do.rst | |||
@@ -0,0 +1,12 @@ | |||
1 | ``do`` | ||
2 | ====== | ||
3 | |||
4 | .. versionadded:: 1.5 | ||
5 | The do tag was added in Twig 1.5. | ||
6 | |||
7 | The ``do`` tag works exactly like the regular variable expression (``{{ ... | ||
8 | }}``) just that it doesn't print anything: | ||
9 | |||
10 | .. code-block:: jinja | ||
11 | |||
12 | {% do 1 + 2 %} | ||
diff --git a/vendor/twig/twig/doc/tags/embed.rst b/vendor/twig/twig/doc/tags/embed.rst new file mode 100644 index 00000000..5a6a0299 --- /dev/null +++ b/vendor/twig/twig/doc/tags/embed.rst | |||
@@ -0,0 +1,178 @@ | |||
1 | ``embed`` | ||
2 | ========= | ||
3 | |||
4 | .. versionadded:: 1.8 | ||
5 | The ``embed`` tag was added in Twig 1.8. | ||
6 | |||
7 | The ``embed`` tag combines the behaviour of :doc:`include<include>` and | ||
8 | :doc:`extends<extends>`. | ||
9 | It allows you to include another template's contents, just like ``include`` | ||
10 | does. But it also allows you to override any block defined inside the | ||
11 | included template, like when extending a template. | ||
12 | |||
13 | Think of an embedded template as a "micro layout skeleton". | ||
14 | |||
15 | .. code-block:: jinja | ||
16 | |||
17 | {% embed "teasers_skeleton.twig" %} | ||
18 | {# These blocks are defined in "teasers_skeleton.twig" #} | ||
19 | {# and we override them right here: #} | ||
20 | {% block left_teaser %} | ||
21 | Some content for the left teaser box | ||
22 | {% endblock %} | ||
23 | {% block right_teaser %} | ||
24 | Some content for the right teaser box | ||
25 | {% endblock %} | ||
26 | {% endembed %} | ||
27 | |||
28 | The ``embed`` tag takes the idea of template inheritance to the level of | ||
29 | content fragments. While template inheritance allows for "document skeletons", | ||
30 | which are filled with life by child templates, the ``embed`` tag allows you to | ||
31 | create "skeletons" for smaller units of content and re-use and fill them | ||
32 | anywhere you like. | ||
33 | |||
34 | Since the use case may not be obvious, let's look at a simplified example. | ||
35 | Imagine a base template shared by multiple HTML pages, defining a single block | ||
36 | named "content": | ||
37 | |||
38 | .. code-block:: text | ||
39 | |||
40 | ┌─── page layout ─────────────────────┐ | ||
41 | │ │ | ||
42 | │ ┌── block "content" ──┐ │ | ||
43 | │ │ │ │ | ||
44 | │ │ │ │ | ||
45 | │ │ (child template to │ │ | ||
46 | │ │ put content here) │ │ | ||
47 | │ │ │ │ | ||
48 | │ │ │ │ | ||
49 | │ └─────────────────────┘ │ | ||
50 | │ │ | ||
51 | └─────────────────────────────────────┘ | ||
52 | |||
53 | Some pages ("foo" and "bar") share the same content structure - | ||
54 | two vertically stacked boxes: | ||
55 | |||
56 | .. code-block:: text | ||
57 | |||
58 | ┌─── page layout ─────────────────────┐ | ||
59 | │ │ | ||
60 | │ ┌── block "content" ──┐ │ | ||
61 | │ │ ┌─ block "top" ───┐ │ │ | ||
62 | │ │ │ │ │ │ | ||
63 | │ │ └─────────────────┘ │ │ | ||
64 | │ │ ┌─ block "bottom" ┐ │ │ | ||
65 | │ │ │ │ │ │ | ||
66 | │ │ └─────────────────┘ │ │ | ||
67 | │ └─────────────────────┘ │ | ||
68 | │ │ | ||
69 | └─────────────────────────────────────┘ | ||
70 | |||
71 | While other pages ("boom" and "baz") share a different content structure - | ||
72 | two boxes side by side: | ||
73 | |||
74 | .. code-block:: text | ||
75 | |||
76 | ┌─── page layout ─────────────────────┐ | ||
77 | │ │ | ||
78 | │ ┌── block "content" ──┐ │ | ||
79 | │ │ │ │ | ||
80 | │ │ ┌ block ┐ ┌ block ┐ │ │ | ||
81 | │ │ │"left" │ │"right"│ │ │ | ||
82 | │ │ │ │ │ │ │ │ | ||
83 | │ │ │ │ │ │ │ │ | ||
84 | │ │ └───────┘ └───────┘ │ │ | ||
85 | │ └─────────────────────┘ │ | ||
86 | │ │ | ||
87 | └─────────────────────────────────────┘ | ||
88 | |||
89 | Without the ``embed`` tag, you have two ways to design your templates: | ||
90 | |||
91 | * Create two "intermediate" base templates that extend the master layout | ||
92 | template: one with vertically stacked boxes to be used by the "foo" and | ||
93 | "bar" pages and another one with side-by-side boxes for the "boom" and | ||
94 | "baz" pages. | ||
95 | |||
96 | * Embed the markup for the top/bottom and left/right boxes into each page | ||
97 | template directly. | ||
98 | |||
99 | These two solutions do not scale well because they each have a major drawback: | ||
100 | |||
101 | * The first solution may indeed work for this simplified example. But imagine | ||
102 | we add a sidebar, which may again contain different, recurring structures | ||
103 | of content. Now we would need to create intermediate base templates for | ||
104 | all occurring combinations of content structure and sidebar structure... | ||
105 | and so on. | ||
106 | |||
107 | * The second solution involves duplication of common code with all its negative | ||
108 | consequences: any change involves finding and editing all affected copies | ||
109 | of the structure, correctness has to be verified for each copy, copies may | ||
110 | go out of sync by careless modifications etc. | ||
111 | |||
112 | In such a situation, the ``embed`` tag comes in handy. The common layout | ||
113 | code can live in a single base template, and the two different content structures, | ||
114 | let's call them "micro layouts" go into separate templates which are embedded | ||
115 | as necessary: | ||
116 | |||
117 | Page template ``foo.twig``: | ||
118 | |||
119 | .. code-block:: jinja | ||
120 | |||
121 | {% extends "layout_skeleton.twig" %} | ||
122 | |||
123 | {% block content %} | ||
124 | {% embed "vertical_boxes_skeleton.twig" %} | ||
125 | {% block top %} | ||
126 | Some content for the top box | ||
127 | {% endblock %} | ||
128 | |||
129 | {% block bottom %} | ||
130 | Some content for the bottom box | ||
131 | {% endblock %} | ||
132 | {% endembed %} | ||
133 | {% endblock %} | ||
134 | |||
135 | And here is the code for ``vertical_boxes_skeleton.twig``: | ||
136 | |||
137 | .. code-block:: html+jinja | ||
138 | |||
139 | <div class="top_box"> | ||
140 | {% block top %} | ||
141 | Top box default content | ||
142 | {% endblock %} | ||
143 | </div> | ||
144 | |||
145 | <div class="bottom_box"> | ||
146 | {% block bottom %} | ||
147 | Bottom box default content | ||
148 | {% endblock %} | ||
149 | </div> | ||
150 | |||
151 | The goal of the ``vertical_boxes_skeleton.twig`` template being to factor | ||
152 | out the HTML markup for the boxes. | ||
153 | |||
154 | The ``embed`` tag takes the exact same arguments as the ``include`` tag: | ||
155 | |||
156 | .. code-block:: jinja | ||
157 | |||
158 | {% embed "base" with {'foo': 'bar'} %} | ||
159 | ... | ||
160 | {% endembed %} | ||
161 | |||
162 | {% embed "base" with {'foo': 'bar'} only %} | ||
163 | ... | ||
164 | {% endembed %} | ||
165 | |||
166 | {% embed "base" ignore missing %} | ||
167 | ... | ||
168 | {% endembed %} | ||
169 | |||
170 | .. warning:: | ||
171 | |||
172 | As embedded templates do not have "names", auto-escaping strategies based | ||
173 | on the template "filename" won't work as expected if you change the | ||
174 | context (for instance, if you embed a CSS/JavaScript template into an HTML | ||
175 | one). In that case, explicitly set the default auto-escaping strategy with | ||
176 | the ``autoescape`` tag. | ||
177 | |||
178 | .. seealso:: :doc:`include<../tags/include>` | ||
diff --git a/vendor/twig/twig/doc/tags/extends.rst b/vendor/twig/twig/doc/tags/extends.rst new file mode 100644 index 00000000..f995a5dc --- /dev/null +++ b/vendor/twig/twig/doc/tags/extends.rst | |||
@@ -0,0 +1,268 @@ | |||
1 | ``extends`` | ||
2 | =========== | ||
3 | |||
4 | The ``extends`` tag can be used to extend a template from another one. | ||
5 | |||
6 | .. note:: | ||
7 | |||
8 | Like PHP, Twig does not support multiple inheritance. So you can only have | ||
9 | one extends tag called per rendering. However, Twig supports horizontal | ||
10 | :doc:`reuse<use>`. | ||
11 | |||
12 | Let's define a base template, ``base.html``, which defines a simple HTML | ||
13 | skeleton document: | ||
14 | |||
15 | .. code-block:: html+jinja | ||
16 | |||
17 | <!DOCTYPE html> | ||
18 | <html> | ||
19 | <head> | ||
20 | {% block head %} | ||
21 | <link rel="stylesheet" href="style.css" /> | ||
22 | <title>{% block title %}{% endblock %} - My Webpage</title> | ||
23 | {% endblock %} | ||
24 | </head> | ||
25 | <body> | ||
26 | <div id="content">{% block content %}{% endblock %}</div> | ||
27 | <div id="footer"> | ||
28 | {% block footer %} | ||
29 | © Copyright 2011 by <a href="http://domain.invalid/">you</a>. | ||
30 | {% endblock %} | ||
31 | </div> | ||
32 | </body> | ||
33 | </html> | ||
34 | |||
35 | In this example, the :doc:`block<block>` tags define four blocks that child | ||
36 | templates can fill in. | ||
37 | |||
38 | All the ``block`` tag does is to tell the template engine that a child | ||
39 | template may override those portions of the template. | ||
40 | |||
41 | Child Template | ||
42 | -------------- | ||
43 | |||
44 | A child template might look like this: | ||
45 | |||
46 | .. code-block:: jinja | ||
47 | |||
48 | {% extends "base.html" %} | ||
49 | |||
50 | {% block title %}Index{% endblock %} | ||
51 | {% block head %} | ||
52 | {{ parent() }} | ||
53 | <style type="text/css"> | ||
54 | .important { color: #336699; } | ||
55 | </style> | ||
56 | {% endblock %} | ||
57 | {% block content %} | ||
58 | <h1>Index</h1> | ||
59 | <p class="important"> | ||
60 | Welcome on my awesome homepage. | ||
61 | </p> | ||
62 | {% endblock %} | ||
63 | |||
64 | The ``extends`` tag is the key here. It tells the template engine that this | ||
65 | template "extends" another template. When the template system evaluates this | ||
66 | template, first it locates the parent. The extends tag should be the first tag | ||
67 | in the template. | ||
68 | |||
69 | Note that since the child template doesn't define the ``footer`` block, the | ||
70 | value from the parent template is used instead. | ||
71 | |||
72 | You can't define multiple ``block`` tags with the same name in the same | ||
73 | template. This limitation exists because a block tag works in "both" | ||
74 | directions. That is, a block tag doesn't just provide a hole to fill - it also | ||
75 | defines the content that fills the hole in the *parent*. If there were two | ||
76 | similarly-named ``block`` tags in a template, that template's parent wouldn't | ||
77 | know which one of the blocks' content to use. | ||
78 | |||
79 | If you want to print a block multiple times you can however use the | ||
80 | ``block`` function: | ||
81 | |||
82 | .. code-block:: jinja | ||
83 | |||
84 | <title>{% block title %}{% endblock %}</title> | ||
85 | <h1>{{ block('title') }}</h1> | ||
86 | {% block body %}{% endblock %} | ||
87 | |||
88 | Parent Blocks | ||
89 | ------------- | ||
90 | |||
91 | It's possible to render the contents of the parent block by using the | ||
92 | :doc:`parent<../functions/parent>` function. This gives back the results of | ||
93 | the parent block: | ||
94 | |||
95 | .. code-block:: jinja | ||
96 | |||
97 | {% block sidebar %} | ||
98 | <h3>Table Of Contents</h3> | ||
99 | ... | ||
100 | {{ parent() }} | ||
101 | {% endblock %} | ||
102 | |||
103 | Named Block End-Tags | ||
104 | -------------------- | ||
105 | |||
106 | Twig allows you to put the name of the block after the end tag for better | ||
107 | readability: | ||
108 | |||
109 | .. code-block:: jinja | ||
110 | |||
111 | {% block sidebar %} | ||
112 | {% block inner_sidebar %} | ||
113 | ... | ||
114 | {% endblock inner_sidebar %} | ||
115 | {% endblock sidebar %} | ||
116 | |||
117 | Of course, the name after the ``endblock`` word must match the block name. | ||
118 | |||
119 | Block Nesting and Scope | ||
120 | ----------------------- | ||
121 | |||
122 | Blocks can be nested for more complex layouts. Per default, blocks have access | ||
123 | to variables from outer scopes: | ||
124 | |||
125 | .. code-block:: jinja | ||
126 | |||
127 | {% for item in seq %} | ||
128 | <li>{% block loop_item %}{{ item }}{% endblock %}</li> | ||
129 | {% endfor %} | ||
130 | |||
131 | Block Shortcuts | ||
132 | --------------- | ||
133 | |||
134 | For blocks with few content, it's possible to use a shortcut syntax. The | ||
135 | following constructs do the same: | ||
136 | |||
137 | .. code-block:: jinja | ||
138 | |||
139 | {% block title %} | ||
140 | {{ page_title|title }} | ||
141 | {% endblock %} | ||
142 | |||
143 | .. code-block:: jinja | ||
144 | |||
145 | {% block title page_title|title %} | ||
146 | |||
147 | Dynamic Inheritance | ||
148 | ------------------- | ||
149 | |||
150 | Twig supports dynamic inheritance by using a variable as the base template: | ||
151 | |||
152 | .. code-block:: jinja | ||
153 | |||
154 | {% extends some_var %} | ||
155 | |||
156 | If the variable evaluates to a ``Twig_Template`` object, Twig will use it as | ||
157 | the parent template:: | ||
158 | |||
159 | // {% extends layout %} | ||
160 | |||
161 | $layout = $twig->loadTemplate('some_layout_template.twig'); | ||
162 | |||
163 | $twig->display('template.twig', array('layout' => $layout)); | ||
164 | |||
165 | .. versionadded:: 1.2 | ||
166 | The possibility to pass an array of templates has been added in Twig 1.2. | ||
167 | |||
168 | You can also provide a list of templates that are checked for existence. The | ||
169 | first template that exists will be used as a parent: | ||
170 | |||
171 | .. code-block:: jinja | ||
172 | |||
173 | {% extends ['layout.html', 'base_layout.html'] %} | ||
174 | |||
175 | Conditional Inheritance | ||
176 | ----------------------- | ||
177 | |||
178 | As the template name for the parent can be any valid Twig expression, it's | ||
179 | possible to make the inheritance mechanism conditional: | ||
180 | |||
181 | .. code-block:: jinja | ||
182 | |||
183 | {% extends standalone ? "minimum.html" : "base.html" %} | ||
184 | |||
185 | In this example, the template will extend the "minimum.html" layout template | ||
186 | if the ``standalone`` variable evaluates to ``true``, and "base.html" | ||
187 | otherwise. | ||
188 | |||
189 | How blocks work? | ||
190 | ---------------- | ||
191 | |||
192 | A block provides a way to change how a certain part of a template is rendered | ||
193 | but it does not interfere in any way with the logic around it. | ||
194 | |||
195 | Let's take the following example to illustrate how a block work and more | ||
196 | importantly, how it does not work: | ||
197 | |||
198 | .. code-block:: jinja | ||
199 | |||
200 | {# base.twig #} | ||
201 | |||
202 | {% for post in posts %} | ||
203 | {% block post %} | ||
204 | <h1>{{ post.title }}</h1> | ||
205 | <p>{{ post.body }}</p> | ||
206 | {% endblock %} | ||
207 | {% endfor %} | ||
208 | |||
209 | If you render this template, the result would be exactly the same with or | ||
210 | without the ``block`` tag. The ``block`` inside the ``for`` loop is just a way | ||
211 | to make it overridable by a child template: | ||
212 | |||
213 | .. code-block:: jinja | ||
214 | |||
215 | {# child.twig #} | ||
216 | |||
217 | {% extends "base.twig" %} | ||
218 | |||
219 | {% block post %} | ||
220 | <article> | ||
221 | <header>{{ post.title }}</header> | ||
222 | <section>{{ post.text }}</section> | ||
223 | </article> | ||
224 | {% endblock %} | ||
225 | |||
226 | Now, when rendering the child template, the loop is going to use the block | ||
227 | defined in the child template instead of the one defined in the base one; the | ||
228 | executed template is then equivalent to the following one: | ||
229 | |||
230 | .. code-block:: jinja | ||
231 | |||
232 | {% for post in posts %} | ||
233 | <article> | ||
234 | <header>{{ post.title }}</header> | ||
235 | <section>{{ post.text }}</section> | ||
236 | </article> | ||
237 | {% endfor %} | ||
238 | |||
239 | Let's take another example: a block included within an ``if`` statement: | ||
240 | |||
241 | .. code-block:: jinja | ||
242 | |||
243 | {% if posts is empty %} | ||
244 | {% block head %} | ||
245 | {{ parent() }} | ||
246 | |||
247 | <meta name="robots" content="noindex, follow"> | ||
248 | {% endblock head %} | ||
249 | {% endif %} | ||
250 | |||
251 | Contrary to what you might think, this template does not define a block | ||
252 | conditionally; it just makes overridable by a child template the output of | ||
253 | what will be rendered when the condition is ``true``. | ||
254 | |||
255 | If you want the output to be displayed conditionally, use the following | ||
256 | instead: | ||
257 | |||
258 | .. code-block:: jinja | ||
259 | |||
260 | {% block head %} | ||
261 | {{ parent() }} | ||
262 | |||
263 | {% if posts is empty %} | ||
264 | <meta name="robots" content="noindex, follow"> | ||
265 | {% endif %} | ||
266 | {% endblock head %} | ||
267 | |||
268 | .. seealso:: :doc:`block<../functions/block>`, :doc:`block<../tags/block>`, :doc:`parent<../functions/parent>`, :doc:`use<../tags/use>` | ||
diff --git a/vendor/twig/twig/doc/tags/filter.rst b/vendor/twig/twig/doc/tags/filter.rst new file mode 100644 index 00000000..82ca5c62 --- /dev/null +++ b/vendor/twig/twig/doc/tags/filter.rst | |||
@@ -0,0 +1,21 @@ | |||
1 | ``filter`` | ||
2 | ========== | ||
3 | |||
4 | Filter sections allow you to apply regular Twig filters on a block of template | ||
5 | data. Just wrap the code in the special ``filter`` section: | ||
6 | |||
7 | .. code-block:: jinja | ||
8 | |||
9 | {% filter upper %} | ||
10 | This text becomes uppercase | ||
11 | {% endfilter %} | ||
12 | |||
13 | You can also chain filters: | ||
14 | |||
15 | .. code-block:: jinja | ||
16 | |||
17 | {% filter lower|escape %} | ||
18 | <strong>SOME TEXT</strong> | ||
19 | {% endfilter %} | ||
20 | |||
21 | {# outputs "<strong>some text</strong>" #} | ||
diff --git a/vendor/twig/twig/doc/tags/flush.rst b/vendor/twig/twig/doc/tags/flush.rst new file mode 100644 index 00000000..55ef593a --- /dev/null +++ b/vendor/twig/twig/doc/tags/flush.rst | |||
@@ -0,0 +1,17 @@ | |||
1 | ``flush`` | ||
2 | ========= | ||
3 | |||
4 | .. versionadded:: 1.5 | ||
5 | The flush tag was added in Twig 1.5. | ||
6 | |||
7 | The ``flush`` tag tells Twig to flush the output buffer: | ||
8 | |||
9 | .. code-block:: jinja | ||
10 | |||
11 | {% flush %} | ||
12 | |||
13 | .. note:: | ||
14 | |||
15 | Internally, Twig uses the PHP `flush`_ function. | ||
16 | |||
17 | .. _`flush`: http://php.net/flush | ||
diff --git a/vendor/twig/twig/doc/tags/for.rst b/vendor/twig/twig/doc/tags/for.rst new file mode 100644 index 00000000..0673b551 --- /dev/null +++ b/vendor/twig/twig/doc/tags/for.rst | |||
@@ -0,0 +1,172 @@ | |||
1 | ``for`` | ||
2 | ======= | ||
3 | |||
4 | Loop over each item in a sequence. For example, to display a list of users | ||
5 | provided in a variable called ``users``: | ||
6 | |||
7 | .. code-block:: jinja | ||
8 | |||
9 | <h1>Members</h1> | ||
10 | <ul> | ||
11 | {% for user in users %} | ||
12 | <li>{{ user.username|e }}</li> | ||
13 | {% endfor %} | ||
14 | </ul> | ||
15 | |||
16 | .. note:: | ||
17 | |||
18 | A sequence can be either an array or an object implementing the | ||
19 | ``Traversable`` interface. | ||
20 | |||
21 | If you do need to iterate over a sequence of numbers, you can use the ``..`` | ||
22 | operator: | ||
23 | |||
24 | .. code-block:: jinja | ||
25 | |||
26 | {% for i in 0..10 %} | ||
27 | * {{ i }} | ||
28 | {% endfor %} | ||
29 | |||
30 | The above snippet of code would print all numbers from 0 to 10. | ||
31 | |||
32 | It can be also useful with letters: | ||
33 | |||
34 | .. code-block:: jinja | ||
35 | |||
36 | {% for letter in 'a'..'z' %} | ||
37 | * {{ letter }} | ||
38 | {% endfor %} | ||
39 | |||
40 | The ``..`` operator can take any expression at both sides: | ||
41 | |||
42 | .. code-block:: jinja | ||
43 | |||
44 | {% for letter in 'a'|upper..'z'|upper %} | ||
45 | * {{ letter }} | ||
46 | {% endfor %} | ||
47 | |||
48 | .. tip: | ||
49 | |||
50 | If you need a step different from 1, you can use the ``range`` function | ||
51 | instead. | ||
52 | |||
53 | The `loop` variable | ||
54 | ------------------- | ||
55 | |||
56 | Inside of a ``for`` loop block you can access some special variables: | ||
57 | |||
58 | ===================== ============================================================= | ||
59 | Variable Description | ||
60 | ===================== ============================================================= | ||
61 | ``loop.index`` The current iteration of the loop. (1 indexed) | ||
62 | ``loop.index0`` The current iteration of the loop. (0 indexed) | ||
63 | ``loop.revindex`` The number of iterations from the end of the loop (1 indexed) | ||
64 | ``loop.revindex0`` The number of iterations from the end of the loop (0 indexed) | ||
65 | ``loop.first`` True if first iteration | ||
66 | ``loop.last`` True if last iteration | ||
67 | ``loop.length`` The number of items in the sequence | ||
68 | ``loop.parent`` The parent context | ||
69 | ===================== ============================================================= | ||
70 | |||
71 | .. code-block:: jinja | ||
72 | |||
73 | {% for user in users %} | ||
74 | {{ loop.index }} - {{ user.username }} | ||
75 | {% endfor %} | ||
76 | |||
77 | .. note:: | ||
78 | |||
79 | The ``loop.length``, ``loop.revindex``, ``loop.revindex0``, and | ||
80 | ``loop.last`` variables are only available for PHP arrays, or objects that | ||
81 | implement the ``Countable`` interface. They are also not available when | ||
82 | looping with a condition. | ||
83 | |||
84 | .. versionadded:: 1.2 | ||
85 | The ``if`` modifier support has been added in Twig 1.2. | ||
86 | |||
87 | Adding a condition | ||
88 | ------------------ | ||
89 | |||
90 | Unlike in PHP, it's not possible to ``break`` or ``continue`` in a loop. You | ||
91 | can however filter the sequence during iteration which allows you to skip | ||
92 | items. The following example skips all the users which are not active: | ||
93 | |||
94 | .. code-block:: jinja | ||
95 | |||
96 | <ul> | ||
97 | {% for user in users if user.active %} | ||
98 | <li>{{ user.username|e }}</li> | ||
99 | {% endfor %} | ||
100 | </ul> | ||
101 | |||
102 | The advantage is that the special loop variable will count correctly thus not | ||
103 | counting the users not iterated over. Keep in mind that properties like | ||
104 | ``loop.last`` will not be defined when using loop conditions. | ||
105 | |||
106 | .. note:: | ||
107 | |||
108 | Using the ``loop`` variable within the condition is not recommended as it | ||
109 | will probably not be doing what you expect it to. For instance, adding a | ||
110 | condition like ``loop.index > 4`` won't work as the index is only | ||
111 | incremented when the condition is true (so the condition will never | ||
112 | match). | ||
113 | |||
114 | The `else` Clause | ||
115 | ----------------- | ||
116 | |||
117 | If no iteration took place because the sequence was empty, you can render a | ||
118 | replacement block by using ``else``: | ||
119 | |||
120 | .. code-block:: jinja | ||
121 | |||
122 | <ul> | ||
123 | {% for user in users %} | ||
124 | <li>{{ user.username|e }}</li> | ||
125 | {% else %} | ||
126 | <li><em>no user found</em></li> | ||
127 | {% endfor %} | ||
128 | </ul> | ||
129 | |||
130 | Iterating over Keys | ||
131 | ------------------- | ||
132 | |||
133 | By default, a loop iterates over the values of the sequence. You can iterate | ||
134 | on keys by using the ``keys`` filter: | ||
135 | |||
136 | .. code-block:: jinja | ||
137 | |||
138 | <h1>Members</h1> | ||
139 | <ul> | ||
140 | {% for key in users|keys %} | ||
141 | <li>{{ key }}</li> | ||
142 | {% endfor %} | ||
143 | </ul> | ||
144 | |||
145 | Iterating over Keys and Values | ||
146 | ------------------------------ | ||
147 | |||
148 | You can also access both keys and values: | ||
149 | |||
150 | .. code-block:: jinja | ||
151 | |||
152 | <h1>Members</h1> | ||
153 | <ul> | ||
154 | {% for key, user in users %} | ||
155 | <li>{{ key }}: {{ user.username|e }}</li> | ||
156 | {% endfor %} | ||
157 | </ul> | ||
158 | |||
159 | Iterating over a Subset | ||
160 | ----------------------- | ||
161 | |||
162 | You might want to iterate over a subset of values. This can be achieved using | ||
163 | the :doc:`slice <../filters/slice>` filter: | ||
164 | |||
165 | .. code-block:: jinja | ||
166 | |||
167 | <h1>Top Ten Members</h1> | ||
168 | <ul> | ||
169 | {% for user in users|slice(0, 10) %} | ||
170 | <li>{{ user.username|e }}</li> | ||
171 | {% endfor %} | ||
172 | </ul> | ||
diff --git a/vendor/twig/twig/doc/tags/from.rst b/vendor/twig/twig/doc/tags/from.rst new file mode 100644 index 00000000..5337a235 --- /dev/null +++ b/vendor/twig/twig/doc/tags/from.rst | |||
@@ -0,0 +1,8 @@ | |||
1 | ``from`` | ||
2 | ======== | ||
3 | |||
4 | The ``from`` tags import :doc:`macro<../tags/macro>` names into the current | ||
5 | namespace. The tag is documented in detail in the documentation for the | ||
6 | :doc:`import<../tags/import>` tag. | ||
7 | |||
8 | .. seealso:: :doc:`macro<../tags/macro>`, :doc:`import<../tags/import>` | ||
diff --git a/vendor/twig/twig/doc/tags/if.rst b/vendor/twig/twig/doc/tags/if.rst new file mode 100644 index 00000000..d7a1451c --- /dev/null +++ b/vendor/twig/twig/doc/tags/if.rst | |||
@@ -0,0 +1,43 @@ | |||
1 | ``if`` | ||
2 | ====== | ||
3 | |||
4 | The ``if`` statement in Twig is comparable with the if statements of PHP. | ||
5 | |||
6 | In the simplest form you can use it to test if an expression evaluates to | ||
7 | ``true``: | ||
8 | |||
9 | .. code-block:: jinja | ||
10 | |||
11 | {% if online == false %} | ||
12 | <p>Our website is in maintenance mode. Please, come back later.</p> | ||
13 | {% endif %} | ||
14 | |||
15 | You can also test if an array is not empty: | ||
16 | |||
17 | .. code-block:: jinja | ||
18 | |||
19 | {% if users %} | ||
20 | <ul> | ||
21 | {% for user in users %} | ||
22 | <li>{{ user.username|e }}</li> | ||
23 | {% endfor %} | ||
24 | </ul> | ||
25 | {% endif %} | ||
26 | |||
27 | .. note:: | ||
28 | |||
29 | If you want to test if the variable is defined, use ``if users is | ||
30 | defined`` instead. | ||
31 | |||
32 | For multiple branches ``elseif`` and ``else`` can be used like in PHP. You can use | ||
33 | more complex ``expressions`` there too: | ||
34 | |||
35 | .. code-block:: jinja | ||
36 | |||
37 | {% if kenny.sick %} | ||
38 | Kenny is sick. | ||
39 | {% elseif kenny.dead %} | ||
40 | You killed Kenny! You bastard!!! | ||
41 | {% else %} | ||
42 | Kenny looks okay --- so far | ||
43 | {% endif %} | ||
diff --git a/vendor/twig/twig/doc/tags/import.rst b/vendor/twig/twig/doc/tags/import.rst new file mode 100644 index 00000000..f6bf718e --- /dev/null +++ b/vendor/twig/twig/doc/tags/import.rst | |||
@@ -0,0 +1,57 @@ | |||
1 | ``import`` | ||
2 | ========== | ||
3 | |||
4 | Twig supports putting often used code into :doc:`macros<../tags/macro>`. These | ||
5 | macros can go into different templates and get imported from there. | ||
6 | |||
7 | There are two ways to import templates. You can import the complete template | ||
8 | into a variable or request specific macros from it. | ||
9 | |||
10 | Imagine we have a helper module that renders forms (called ``forms.html``): | ||
11 | |||
12 | .. code-block:: jinja | ||
13 | |||
14 | {% macro input(name, value, type, size) %} | ||
15 | <input type="{{ type|default('text') }}" name="{{ name }}" value="{{ value|e }}" size="{{ size|default(20) }}" /> | ||
16 | {% endmacro %} | ||
17 | |||
18 | {% macro textarea(name, value, rows) %} | ||
19 | <textarea name="{{ name }}" rows="{{ rows|default(10) }}" cols="{{ cols|default(40) }}">{{ value|e }}</textarea> | ||
20 | {% endmacro %} | ||
21 | |||
22 | The easiest and most flexible is importing the whole module into a variable. | ||
23 | That way you can access the attributes: | ||
24 | |||
25 | .. code-block:: jinja | ||
26 | |||
27 | {% import 'forms.html' as forms %} | ||
28 | |||
29 | <dl> | ||
30 | <dt>Username</dt> | ||
31 | <dd>{{ forms.input('username') }}</dd> | ||
32 | <dt>Password</dt> | ||
33 | <dd>{{ forms.input('password', null, 'password') }}</dd> | ||
34 | </dl> | ||
35 | <p>{{ forms.textarea('comment') }}</p> | ||
36 | |||
37 | Alternatively you can import names from the template into the current | ||
38 | namespace: | ||
39 | |||
40 | .. code-block:: jinja | ||
41 | |||
42 | {% from 'forms.html' import input as input_field, textarea %} | ||
43 | |||
44 | <dl> | ||
45 | <dt>Username</dt> | ||
46 | <dd>{{ input_field('username') }}</dd> | ||
47 | <dt>Password</dt> | ||
48 | <dd>{{ input_field('password', '', 'password') }}</dd> | ||
49 | </dl> | ||
50 | <p>{{ textarea('comment') }}</p> | ||
51 | |||
52 | .. tip:: | ||
53 | |||
54 | To import macros from the current file, use the special ``_self`` variable | ||
55 | for the source. | ||
56 | |||
57 | .. seealso:: :doc:`macro<../tags/macro>`, :doc:`from<../tags/from>` | ||
diff --git a/vendor/twig/twig/doc/tags/include.rst b/vendor/twig/twig/doc/tags/include.rst new file mode 100644 index 00000000..10b262de --- /dev/null +++ b/vendor/twig/twig/doc/tags/include.rst | |||
@@ -0,0 +1,86 @@ | |||
1 | ``include`` | ||
2 | =========== | ||
3 | |||
4 | The ``include`` statement includes a template and return the rendered content | ||
5 | of that file into the current namespace: | ||
6 | |||
7 | .. code-block:: jinja | ||
8 | |||
9 | {% include 'header.html' %} | ||
10 | Body | ||
11 | {% include 'footer.html' %} | ||
12 | |||
13 | Included templates have access to the variables of the active context. | ||
14 | |||
15 | If you are using the filesystem loader, the templates are looked for in the | ||
16 | paths defined by it. | ||
17 | |||
18 | You can add additional variables by passing them after the ``with`` keyword: | ||
19 | |||
20 | .. code-block:: jinja | ||
21 | |||
22 | {# template.html will have access to the variables from the current context and the additional ones provided #} | ||
23 | {% include 'template.html' with {'foo': 'bar'} %} | ||
24 | |||
25 | {% set vars = {'foo': 'bar'} %} | ||
26 | {% include 'template.html' with vars %} | ||
27 | |||
28 | You can disable access to the context by appending the ``only`` keyword: | ||
29 | |||
30 | .. code-block:: jinja | ||
31 | |||
32 | {# only the foo variable will be accessible #} | ||
33 | {% include 'template.html' with {'foo': 'bar'} only %} | ||
34 | |||
35 | .. code-block:: jinja | ||
36 | |||
37 | {# no variables will be accessible #} | ||
38 | {% include 'template.html' only %} | ||
39 | |||
40 | .. tip:: | ||
41 | |||
42 | When including a template created by an end user, you should consider | ||
43 | sandboxing it. More information in the :doc:`Twig for Developers<../api>` | ||
44 | chapter and in the :doc:`sandbox<../tags/sandbox>` tag documentation. | ||
45 | |||
46 | The template name can be any valid Twig expression: | ||
47 | |||
48 | .. code-block:: jinja | ||
49 | |||
50 | {% include some_var %} | ||
51 | {% include ajax ? 'ajax.html' : 'not_ajax.html' %} | ||
52 | |||
53 | And if the expression evaluates to a ``Twig_Template`` object, Twig will use it | ||
54 | directly:: | ||
55 | |||
56 | // {% include template %} | ||
57 | |||
58 | $template = $twig->loadTemplate('some_template.twig'); | ||
59 | |||
60 | $twig->loadTemplate('template.twig')->display(array('template' => $template)); | ||
61 | |||
62 | .. versionadded:: 1.2 | ||
63 | The ``ignore missing`` feature has been added in Twig 1.2. | ||
64 | |||
65 | You can mark an include with ``ignore missing`` in which case Twig will ignore | ||
66 | the statement if the template to be included does not exist. It has to be | ||
67 | placed just after the template name. Here some valid examples: | ||
68 | |||
69 | .. code-block:: jinja | ||
70 | |||
71 | {% include 'sidebar.html' ignore missing %} | ||
72 | {% include 'sidebar.html' ignore missing with {'foo': 'bar'} %} | ||
73 | {% include 'sidebar.html' ignore missing only %} | ||
74 | |||
75 | .. versionadded:: 1.2 | ||
76 | The possibility to pass an array of templates has been added in Twig 1.2. | ||
77 | |||
78 | You can also provide a list of templates that are checked for existence before | ||
79 | inclusion. The first template that exists will be included: | ||
80 | |||
81 | .. code-block:: jinja | ||
82 | |||
83 | {% include ['page_detailed.html', 'page.html'] %} | ||
84 | |||
85 | If ``ignore missing`` is given, it will fall back to rendering nothing if none | ||
86 | of the templates exist, otherwise it will throw an exception. | ||
diff --git a/vendor/twig/twig/doc/tags/index.rst b/vendor/twig/twig/doc/tags/index.rst new file mode 100644 index 00000000..64e88644 --- /dev/null +++ b/vendor/twig/twig/doc/tags/index.rst | |||
@@ -0,0 +1,24 @@ | |||
1 | Tags | ||
2 | ==== | ||
3 | |||
4 | .. toctree:: | ||
5 | :maxdepth: 1 | ||
6 | |||
7 | autoescape | ||
8 | block | ||
9 | filter | ||
10 | do | ||
11 | embed | ||
12 | extends | ||
13 | flush | ||
14 | for | ||
15 | from | ||
16 | if | ||
17 | import | ||
18 | include | ||
19 | macro | ||
20 | sandbox | ||
21 | set | ||
22 | spaceless | ||
23 | use | ||
24 | verbatim | ||
diff --git a/vendor/twig/twig/doc/tags/macro.rst b/vendor/twig/twig/doc/tags/macro.rst new file mode 100644 index 00000000..11c115a0 --- /dev/null +++ b/vendor/twig/twig/doc/tags/macro.rst | |||
@@ -0,0 +1,83 @@ | |||
1 | ``macro`` | ||
2 | ========= | ||
3 | |||
4 | Macros are comparable with functions in regular programming languages. They | ||
5 | are useful to put often used HTML idioms into reusable elements to not repeat | ||
6 | yourself. | ||
7 | |||
8 | Here is a small example of a macro that renders a form element: | ||
9 | |||
10 | .. code-block:: jinja | ||
11 | |||
12 | {% macro input(name, value, type, size) %} | ||
13 | <input type="{{ type|default('text') }}" name="{{ name }}" value="{{ value|e }}" size="{{ size|default(20) }}" /> | ||
14 | {% endmacro %} | ||
15 | |||
16 | Macros differs from native PHP functions in a few ways: | ||
17 | |||
18 | * Default argument values are defined by using the ``default`` filter in the | ||
19 | macro body; | ||
20 | |||
21 | * Arguments of a macro are always optional. | ||
22 | |||
23 | But as with PHP functions, macros don't have access to the current template | ||
24 | variables. | ||
25 | |||
26 | .. tip:: | ||
27 | |||
28 | You can pass the whole context as an argument by using the special | ||
29 | ``_context`` variable. | ||
30 | |||
31 | Macros can be defined in any template, and need to be "imported" before being | ||
32 | used (see the documentation for the :doc:`import<../tags/import>` tag for more | ||
33 | information): | ||
34 | |||
35 | .. code-block:: jinja | ||
36 | |||
37 | {% import "forms.html" as forms %} | ||
38 | |||
39 | The above ``import`` call imports the "forms.html" file (which can contain only | ||
40 | macros, or a template and some macros), and import the functions as items of | ||
41 | the ``forms`` variable. | ||
42 | |||
43 | The macro can then be called at will: | ||
44 | |||
45 | .. code-block:: jinja | ||
46 | |||
47 | <p>{{ forms.input('username') }}</p> | ||
48 | <p>{{ forms.input('password', null, 'password') }}</p> | ||
49 | |||
50 | If macros are defined and used in the same template, you can use the | ||
51 | special ``_self`` variable to import them: | ||
52 | |||
53 | .. code-block:: jinja | ||
54 | |||
55 | {% import _self as forms %} | ||
56 | |||
57 | <p>{{ forms.input('username') }}</p> | ||
58 | |||
59 | .. warning:: | ||
60 | |||
61 | When you define a macro in the template where you are going to use it, you | ||
62 | might be tempted to call the macro directly via ``_self.input()`` instead | ||
63 | of importing it; even if seems to work, this is just a side-effect of the | ||
64 | current implementation and it won't work anymore in Twig 2.x. | ||
65 | |||
66 | When you want to use a macro in another macro from the same file, you need to | ||
67 | import it locally: | ||
68 | |||
69 | .. code-block:: jinja | ||
70 | |||
71 | {% macro input(name, value, type, size) %} | ||
72 | <input type="{{ type|default('text') }}" name="{{ name }}" value="{{ value|e }}" size="{{ size|default(20) }}" /> | ||
73 | {% endmacro %} | ||
74 | |||
75 | {% macro wrapped_input(name, value, type, size) %} | ||
76 | {% import _self as forms %} | ||
77 | |||
78 | <div class="field"> | ||
79 | {{ forms.input(name, value, type, size) }} | ||
80 | </div> | ||
81 | {% endmacro %} | ||
82 | |||
83 | .. seealso:: :doc:`from<../tags/from>`, :doc:`import<../tags/import>` | ||
diff --git a/vendor/twig/twig/doc/tags/sandbox.rst b/vendor/twig/twig/doc/tags/sandbox.rst new file mode 100644 index 00000000..e186726c --- /dev/null +++ b/vendor/twig/twig/doc/tags/sandbox.rst | |||
@@ -0,0 +1,30 @@ | |||
1 | ``sandbox`` | ||
2 | =========== | ||
3 | |||
4 | The ``sandbox`` tag can be used to enable the sandboxing mode for an included | ||
5 | template, when sandboxing is not enabled globally for the Twig environment: | ||
6 | |||
7 | .. code-block:: jinja | ||
8 | |||
9 | {% sandbox %} | ||
10 | {% include 'user.html' %} | ||
11 | {% endsandbox %} | ||
12 | |||
13 | .. warning:: | ||
14 | |||
15 | The ``sandbox`` tag is only available when the sandbox extension is | ||
16 | enabled (see the :doc:`Twig for Developers<../api>` chapter). | ||
17 | |||
18 | .. note:: | ||
19 | |||
20 | The ``sandbox`` tag can only be used to sandbox an include tag and it | ||
21 | cannot be used to sandbox a section of a template. The following example | ||
22 | won't work: | ||
23 | |||
24 | .. code-block:: jinja | ||
25 | |||
26 | {% sandbox %} | ||
27 | {% for i in 1..2 %} | ||
28 | {{ i }} | ||
29 | {% endfor %} | ||
30 | {% endsandbox %} | ||
diff --git a/vendor/twig/twig/doc/tags/set.rst b/vendor/twig/twig/doc/tags/set.rst new file mode 100644 index 00000000..3eba239a --- /dev/null +++ b/vendor/twig/twig/doc/tags/set.rst | |||
@@ -0,0 +1,78 @@ | |||
1 | ``set`` | ||
2 | ======= | ||
3 | |||
4 | Inside code blocks you can also assign values to variables. Assignments use | ||
5 | the ``set`` tag and can have multiple targets. | ||
6 | |||
7 | Here is how you can assign the ``bar`` value to the ``foo`` variable: | ||
8 | |||
9 | .. code-block:: jinja | ||
10 | |||
11 | {% set foo = 'bar' %} | ||
12 | |||
13 | After the ``set`` call, the ``foo`` variable is available in the template like | ||
14 | any other ones: | ||
15 | |||
16 | .. code-block:: jinja | ||
17 | |||
18 | {# displays bar #} | ||
19 | {{ foo }} | ||
20 | |||
21 | The assigned value can be any valid :ref:`Twig expressions | ||
22 | <twig-expressions>`: | ||
23 | |||
24 | .. code-block:: jinja | ||
25 | |||
26 | {% set foo = [1, 2] %} | ||
27 | {% set foo = {'foo': 'bar'} %} | ||
28 | {% set foo = 'foo' ~ 'bar' %} | ||
29 | |||
30 | Several variables can be assigned in one block: | ||
31 | |||
32 | .. code-block:: jinja | ||
33 | |||
34 | {% set foo, bar = 'foo', 'bar' %} | ||
35 | |||
36 | {# is equivalent to #} | ||
37 | |||
38 | {% set foo = 'foo' %} | ||
39 | {% set bar = 'bar' %} | ||
40 | |||
41 | The ``set`` tag can also be used to 'capture' chunks of text: | ||
42 | |||
43 | .. code-block:: jinja | ||
44 | |||
45 | {% set foo %} | ||
46 | <div id="pagination"> | ||
47 | ... | ||
48 | </div> | ||
49 | {% endset %} | ||
50 | |||
51 | .. caution:: | ||
52 | |||
53 | If you enable automatic output escaping, Twig will only consider the | ||
54 | content to be safe when capturing chunks of text. | ||
55 | |||
56 | .. note:: | ||
57 | |||
58 | Note that loops are scoped in Twig; therefore a variable declared inside a | ||
59 | ``for`` loop is not accessible outside the loop itself: | ||
60 | |||
61 | .. code-block:: jinja | ||
62 | |||
63 | {% for item in list %} | ||
64 | {% set foo = item %} | ||
65 | {% endfor %} | ||
66 | |||
67 | {# foo is NOT available #} | ||
68 | |||
69 | If you want to access the variable, just declare it before the loop: | ||
70 | |||
71 | .. code-block:: jinja | ||
72 | |||
73 | {% set foo = "" %} | ||
74 | {% for item in list %} | ||
75 | {% set foo = item %} | ||
76 | {% endfor %} | ||
77 | |||
78 | {# foo is available #} | ||
diff --git a/vendor/twig/twig/doc/tags/spaceless.rst b/vendor/twig/twig/doc/tags/spaceless.rst new file mode 100644 index 00000000..12e77b25 --- /dev/null +++ b/vendor/twig/twig/doc/tags/spaceless.rst | |||
@@ -0,0 +1,37 @@ | |||
1 | ``spaceless`` | ||
2 | ============= | ||
3 | |||
4 | Use the ``spaceless`` tag to remove whitespace *between HTML tags*, not | ||
5 | whitespace within HTML tags or whitespace in plain text: | ||
6 | |||
7 | .. code-block:: jinja | ||
8 | |||
9 | {% spaceless %} | ||
10 | <div> | ||
11 | <strong>foo</strong> | ||
12 | </div> | ||
13 | {% endspaceless %} | ||
14 | |||
15 | {# output will be <div><strong>foo</strong></div> #} | ||
16 | |||
17 | This tag is not meant to "optimize" the size of the generated HTML content but | ||
18 | merely to avoid extra whitespace between HTML tags to avoid browser rendering | ||
19 | quirks under some circumstances. | ||
20 | |||
21 | .. tip:: | ||
22 | |||
23 | If you want to optimize the size of the generated HTML content, gzip | ||
24 | compress the output instead. | ||
25 | |||
26 | .. tip:: | ||
27 | |||
28 | If you want to create a tag that actually removes all extra whitespace in | ||
29 | an HTML string, be warned that this is not as easy as it seems to be | ||
30 | (think of ``textarea`` or ``pre`` tags for instance). Using a third-party | ||
31 | library like Tidy is probably a better idea. | ||
32 | |||
33 | .. tip:: | ||
34 | |||
35 | For more information on whitespace control, read the | ||
36 | :doc:`dedicated<../templates>` section of the documentation and learn how | ||
37 | you can also use the whitespace control modifier on your tags. | ||
diff --git a/vendor/twig/twig/doc/tags/use.rst b/vendor/twig/twig/doc/tags/use.rst new file mode 100644 index 00000000..085f9161 --- /dev/null +++ b/vendor/twig/twig/doc/tags/use.rst | |||
@@ -0,0 +1,123 @@ | |||
1 | ``use`` | ||
2 | ======= | ||
3 | |||
4 | .. versionadded:: 1.1 | ||
5 | Horizontal reuse was added in Twig 1.1. | ||
6 | |||
7 | .. note:: | ||
8 | |||
9 | Horizontal reuse is an advanced Twig feature that is hardly ever needed in | ||
10 | regular templates. It is mainly used by projects that need to make | ||
11 | template blocks reusable without using inheritance. | ||
12 | |||
13 | Template inheritance is one of the most powerful Twig's feature but it is | ||
14 | limited to single inheritance; a template can only extend one other template. | ||
15 | This limitation makes template inheritance simple to understand and easy to | ||
16 | debug: | ||
17 | |||
18 | .. code-block:: jinja | ||
19 | |||
20 | {% extends "base.html" %} | ||
21 | |||
22 | {% block title %}{% endblock %} | ||
23 | {% block content %}{% endblock %} | ||
24 | |||
25 | Horizontal reuse is a way to achieve the same goal as multiple inheritance, | ||
26 | but without the associated complexity: | ||
27 | |||
28 | .. code-block:: jinja | ||
29 | |||
30 | {% extends "base.html" %} | ||
31 | |||
32 | {% use "blocks.html" %} | ||
33 | |||
34 | {% block title %}{% endblock %} | ||
35 | {% block content %}{% endblock %} | ||
36 | |||
37 | The ``use`` statement tells Twig to import the blocks defined in | ||
38 | ```blocks.html`` into the current template (it's like macros, but for blocks): | ||
39 | |||
40 | .. code-block:: jinja | ||
41 | |||
42 | # blocks.html | ||
43 | {% block sidebar %}{% endblock %} | ||
44 | |||
45 | In this example, the ``use`` statement imports the ``sidebar`` block into the | ||
46 | main template. The code is mostly equivalent to the following one (the | ||
47 | imported blocks are not outputted automatically): | ||
48 | |||
49 | .. code-block:: jinja | ||
50 | |||
51 | {% extends "base.html" %} | ||
52 | |||
53 | {% block sidebar %}{% endblock %} | ||
54 | {% block title %}{% endblock %} | ||
55 | {% block content %}{% endblock %} | ||
56 | |||
57 | .. note:: | ||
58 | |||
59 | The ``use`` tag only imports a template if it does not extend another | ||
60 | template, if it does not define macros, and if the body is empty. But it | ||
61 | can *use* other templates. | ||
62 | |||
63 | .. note:: | ||
64 | |||
65 | Because ``use`` statements are resolved independently of the context | ||
66 | passed to the template, the template reference cannot be an expression. | ||
67 | |||
68 | The main template can also override any imported block. If the template | ||
69 | already defines the ``sidebar`` block, then the one defined in ``blocks.html`` | ||
70 | is ignored. To avoid name conflicts, you can rename imported blocks: | ||
71 | |||
72 | .. code-block:: jinja | ||
73 | |||
74 | {% extends "base.html" %} | ||
75 | |||
76 | {% use "blocks.html" with sidebar as base_sidebar %} | ||
77 | |||
78 | {% block sidebar %}{% endblock %} | ||
79 | {% block title %}{% endblock %} | ||
80 | {% block content %}{% endblock %} | ||
81 | |||
82 | .. versionadded:: 1.3 | ||
83 | The ``parent()`` support was added in Twig 1.3. | ||
84 | |||
85 | The ``parent()`` function automatically determines the correct inheritance | ||
86 | tree, so it can be used when overriding a block defined in an imported | ||
87 | template: | ||
88 | |||
89 | .. code-block:: jinja | ||
90 | |||
91 | {% extends "base.html" %} | ||
92 | |||
93 | {% use "blocks.html" %} | ||
94 | |||
95 | {% block sidebar %} | ||
96 | {{ parent() }} | ||
97 | {% endblock %} | ||
98 | |||
99 | {% block title %}{% endblock %} | ||
100 | {% block content %}{% endblock %} | ||
101 | |||
102 | In this example, ``parent()`` will correctly call the ``sidebar`` block from | ||
103 | the ``blocks.html`` template. | ||
104 | |||
105 | .. tip:: | ||
106 | |||
107 | In Twig 1.2, renaming allows you to simulate inheritance by calling the | ||
108 | "parent" block: | ||
109 | |||
110 | .. code-block:: jinja | ||
111 | |||
112 | {% extends "base.html" %} | ||
113 | |||
114 | {% use "blocks.html" with sidebar as parent_sidebar %} | ||
115 | |||
116 | {% block sidebar %} | ||
117 | {{ block('parent_sidebar') }} | ||
118 | {% endblock %} | ||
119 | |||
120 | .. note:: | ||
121 | |||
122 | You can use as many ``use`` statements as you want in any given template. | ||
123 | If two imported templates define the same block, the latest one wins. | ||
diff --git a/vendor/twig/twig/doc/tags/verbatim.rst b/vendor/twig/twig/doc/tags/verbatim.rst new file mode 100644 index 00000000..fe61ca1b --- /dev/null +++ b/vendor/twig/twig/doc/tags/verbatim.rst | |||
@@ -0,0 +1,24 @@ | |||
1 | ``verbatim`` | ||
2 | ============ | ||
3 | |||
4 | .. versionadded:: 1.12 | ||
5 | The ``verbatim`` tag was added in Twig 1.12 (it was named ``raw`` before). | ||
6 | |||
7 | The ``verbatim`` tag marks sections as being raw text that should not be | ||
8 | parsed. For example to put Twig syntax as example into a template you can use | ||
9 | this snippet: | ||
10 | |||
11 | .. code-block:: jinja | ||
12 | |||
13 | {% verbatim %} | ||
14 | <ul> | ||
15 | {% for item in seq %} | ||
16 | <li>{{ item }}</li> | ||
17 | {% endfor %} | ||
18 | </ul> | ||
19 | {% endverbatim %} | ||
20 | |||
21 | .. note:: | ||
22 | |||
23 | The ``verbatim`` tag works in the exact same way as the old ``raw`` tag, | ||
24 | but was renamed to avoid confusion with the ``raw`` filter. \ No newline at end of file | ||
diff --git a/vendor/twig/twig/doc/templates.rst b/vendor/twig/twig/doc/templates.rst new file mode 100644 index 00000000..542b8aef --- /dev/null +++ b/vendor/twig/twig/doc/templates.rst | |||
@@ -0,0 +1,851 @@ | |||
1 | Twig for Template Designers | ||
2 | =========================== | ||
3 | |||
4 | This document describes the syntax and semantics of the template engine and | ||
5 | will be most useful as reference to those creating Twig templates. | ||
6 | |||
7 | Synopsis | ||
8 | -------- | ||
9 | |||
10 | A template is simply a text file. It can generate any text-based format (HTML, | ||
11 | XML, CSV, LaTeX, etc.). It doesn't have a specific extension, ``.html`` or | ||
12 | ``.xml`` are just fine. | ||
13 | |||
14 | A template contains **variables** or **expressions**, which get replaced with | ||
15 | values when the template is evaluated, and **tags**, which control the logic | ||
16 | of the template. | ||
17 | |||
18 | Below is a minimal template that illustrates a few basics. We will cover the | ||
19 | details later on: | ||
20 | |||
21 | .. code-block:: html+jinja | ||
22 | |||
23 | <!DOCTYPE html> | ||
24 | <html> | ||
25 | <head> | ||
26 | <title>My Webpage</title> | ||
27 | </head> | ||
28 | <body> | ||
29 | <ul id="navigation"> | ||
30 | {% for item in navigation %} | ||
31 | <li><a href="{{ item.href }}">{{ item.caption }}</a></li> | ||
32 | {% endfor %} | ||
33 | </ul> | ||
34 | |||
35 | <h1>My Webpage</h1> | ||
36 | {{ a_variable }} | ||
37 | </body> | ||
38 | </html> | ||
39 | |||
40 | There are two kinds of delimiters: ``{% ... %}`` and ``{{ ... }}``. The first | ||
41 | one is used to execute statements such as for-loops, the latter prints the | ||
42 | result of an expression to the template. | ||
43 | |||
44 | IDEs Integration | ||
45 | ---------------- | ||
46 | |||
47 | Many IDEs support syntax highlighting and auto-completion for Twig: | ||
48 | |||
49 | * *Textmate* via the `Twig bundle`_ | ||
50 | * *Vim* via the `Jinja syntax plugin`_ | ||
51 | * *Netbeans* via the `Twig syntax plugin`_ (until 7.1, native as of 7.2) | ||
52 | * *PhpStorm* (native as of 2.1) | ||
53 | * *Eclipse* via the `Twig plugin`_ | ||
54 | * *Sublime Text* via the `Twig bundle`_ | ||
55 | * *GtkSourceView* via the `Twig language definition`_ (used by gedit and other projects) | ||
56 | * *Coda* and *SubEthaEdit* via the `Twig syntax mode`_ | ||
57 | * *Coda 2* via the `other Twig syntax mode`_ | ||
58 | * *Komodo* and *Komodo Edit* via the Twig highlight/syntax check mode | ||
59 | * *Notepad++* via the `Notepad++ Twig Highlighter`_ | ||
60 | * *Emacs* via `web-mode.el`_ | ||
61 | |||
62 | Variables | ||
63 | --------- | ||
64 | |||
65 | The application passes variables to the templates you can mess around in the | ||
66 | template. Variables may have attributes or elements on them you can access | ||
67 | too. How a variable looks like heavily depends on the application providing | ||
68 | those. | ||
69 | |||
70 | You can use a dot (``.``) to access attributes of a variable (methods or | ||
71 | properties of a PHP object, or items of a PHP array), or the so-called | ||
72 | "subscript" syntax (``[]``): | ||
73 | |||
74 | .. code-block:: jinja | ||
75 | |||
76 | {{ foo.bar }} | ||
77 | {{ foo['bar'] }} | ||
78 | |||
79 | When the attribute contains special characters (like ``-`` that would be | ||
80 | interpreted as the minus operator), use the ``attribute`` function instead to | ||
81 | access the variable attribute: | ||
82 | |||
83 | .. code-block:: jinja | ||
84 | |||
85 | {# equivalent to the non-working foo.data-foo #} | ||
86 | {{ attribute(foo, 'data-foo') }} | ||
87 | |||
88 | .. note:: | ||
89 | |||
90 | It's important to know that the curly braces are *not* part of the | ||
91 | variable but the print statement. If you access variables inside tags | ||
92 | don't put the braces around. | ||
93 | |||
94 | If a variable or attribute does not exist, you will get back a ``null`` value | ||
95 | when the ``strict_variables`` option is set to ``false``, otherwise Twig will | ||
96 | throw an error (see :ref:`environment options<environment_options>`). | ||
97 | |||
98 | .. sidebar:: Implementation | ||
99 | |||
100 | For convenience sake ``foo.bar`` does the following things on the PHP | ||
101 | layer: | ||
102 | |||
103 | * check if ``foo`` is an array and ``bar`` a valid element; | ||
104 | * if not, and if ``foo`` is an object, check that ``bar`` is a valid property; | ||
105 | * if not, and if ``foo`` is an object, check that ``bar`` is a valid method | ||
106 | (even if ``bar`` is the constructor - use ``__construct()`` instead); | ||
107 | * if not, and if ``foo`` is an object, check that ``getBar`` is a valid method; | ||
108 | * if not, and if ``foo`` is an object, check that ``isBar`` is a valid method; | ||
109 | * if not, return a ``null`` value. | ||
110 | |||
111 | ``foo['bar']`` on the other hand only works with PHP arrays: | ||
112 | |||
113 | * check if ``foo`` is an array and ``bar`` a valid element; | ||
114 | * if not, return a ``null`` value. | ||
115 | |||
116 | .. note:: | ||
117 | |||
118 | If you want to get a dynamic attribute on a variable, use the | ||
119 | :doc:`attribute<functions/attribute>` function instead. | ||
120 | |||
121 | Global Variables | ||
122 | ~~~~~~~~~~~~~~~~ | ||
123 | |||
124 | The following variables are always available in templates: | ||
125 | |||
126 | * ``_self``: references the current template; | ||
127 | * ``_context``: references the current context; | ||
128 | * ``_charset``: references the current charset. | ||
129 | |||
130 | Setting Variables | ||
131 | ~~~~~~~~~~~~~~~~~ | ||
132 | |||
133 | You can assign values to variables inside code blocks. Assignments use the | ||
134 | :doc:`set<tags/set>` tag: | ||
135 | |||
136 | .. code-block:: jinja | ||
137 | |||
138 | {% set foo = 'foo' %} | ||
139 | {% set foo = [1, 2] %} | ||
140 | {% set foo = {'foo': 'bar'} %} | ||
141 | |||
142 | Filters | ||
143 | ------- | ||
144 | |||
145 | Variables can be modified by **filters**. Filters are separated from the | ||
146 | variable by a pipe symbol (``|``) and may have optional arguments in | ||
147 | parentheses. Multiple filters can be chained. The output of one filter is | ||
148 | applied to the next. | ||
149 | |||
150 | The following example removes all HTML tags from the ``name`` and title-cases | ||
151 | it: | ||
152 | |||
153 | .. code-block:: jinja | ||
154 | |||
155 | {{ name|striptags|title }} | ||
156 | |||
157 | Filters that accept arguments have parentheses around the arguments. This | ||
158 | example will join a list by commas: | ||
159 | |||
160 | .. code-block:: jinja | ||
161 | |||
162 | {{ list|join(', ') }} | ||
163 | |||
164 | To apply a filter on a section of code, wrap it with the | ||
165 | :doc:`filter<tags/filter>` tag: | ||
166 | |||
167 | .. code-block:: jinja | ||
168 | |||
169 | {% filter upper %} | ||
170 | This text becomes uppercase | ||
171 | {% endfilter %} | ||
172 | |||
173 | Go to the :doc:`filters<filters/index>` page to learn more about the built-in | ||
174 | filters. | ||
175 | |||
176 | Functions | ||
177 | --------- | ||
178 | |||
179 | Functions can be called to generate content. Functions are called by their | ||
180 | name followed by parentheses (``()``) and may have arguments. | ||
181 | |||
182 | For instance, the ``range`` function returns a list containing an arithmetic | ||
183 | progression of integers: | ||
184 | |||
185 | .. code-block:: jinja | ||
186 | |||
187 | {% for i in range(0, 3) %} | ||
188 | {{ i }}, | ||
189 | {% endfor %} | ||
190 | |||
191 | Go to the :doc:`functions<functions/index>` page to learn more about the | ||
192 | built-in functions. | ||
193 | |||
194 | Named Arguments | ||
195 | --------------- | ||
196 | |||
197 | .. versionadded:: 1.12 | ||
198 | Support for named arguments was added in Twig 1.12. | ||
199 | |||
200 | Arguments for filters and functions can also be passed as *named arguments*: | ||
201 | |||
202 | .. code-block:: jinja | ||
203 | |||
204 | {% for i in range(low=1, high=10, step=2) %} | ||
205 | {{ i }}, | ||
206 | {% endfor %} | ||
207 | |||
208 | Using named arguments makes your templates more explicit about the meaning of | ||
209 | the values you pass as arguments: | ||
210 | |||
211 | .. code-block:: jinja | ||
212 | |||
213 | {{ data|convert_encoding('UTF-8', 'iso-2022-jp') }} | ||
214 | |||
215 | {# versus #} | ||
216 | |||
217 | {{ data|convert_encoding(from='iso-2022-jp', to='UTF-8') }} | ||
218 | |||
219 | Named arguments also allow you to skip some arguments for which you don't want | ||
220 | to change the default value: | ||
221 | |||
222 | .. code-block:: jinja | ||
223 | |||
224 | {# the first argument is the date format, which defaults to the global date format if null is passed #} | ||
225 | {{ "now"|date(null, "Europe/Paris") }} | ||
226 | |||
227 | {# or skip the format value by using a named argument for the timezone #} | ||
228 | {{ "now"|date(timezone="Europe/Paris") }} | ||
229 | |||
230 | You can also use both positional and named arguments in one call, in which | ||
231 | case positional arguments must always come before named arguments: | ||
232 | |||
233 | .. code-block:: jinja | ||
234 | |||
235 | {{ "now"|date('d/m/Y H:i', timezone="Europe/Paris") }} | ||
236 | |||
237 | .. tip:: | ||
238 | |||
239 | Each function and filter documentation page has a section where the names | ||
240 | of all arguments are listed when supported. | ||
241 | |||
242 | Control Structure | ||
243 | ----------------- | ||
244 | |||
245 | A control structure refers to all those things that control the flow of a | ||
246 | program - conditionals (i.e. ``if``/``elseif``/``else``), ``for``-loops, as | ||
247 | well as things like blocks. Control structures appear inside ``{% ... %}`` | ||
248 | blocks. | ||
249 | |||
250 | For example, to display a list of users provided in a variable called | ||
251 | ``users``, use the :doc:`for<tags/for>` tag: | ||
252 | |||
253 | .. code-block:: jinja | ||
254 | |||
255 | <h1>Members</h1> | ||
256 | <ul> | ||
257 | {% for user in users %} | ||
258 | <li>{{ user.username|e }}</li> | ||
259 | {% endfor %} | ||
260 | </ul> | ||
261 | |||
262 | The :doc:`if<tags/if>` tag can be used to test an expression: | ||
263 | |||
264 | .. code-block:: jinja | ||
265 | |||
266 | {% if users|length > 0 %} | ||
267 | <ul> | ||
268 | {% for user in users %} | ||
269 | <li>{{ user.username|e }}</li> | ||
270 | {% endfor %} | ||
271 | </ul> | ||
272 | {% endif %} | ||
273 | |||
274 | Go to the :doc:`tags<tags/index>` page to learn more about the built-in tags. | ||
275 | |||
276 | Comments | ||
277 | -------- | ||
278 | |||
279 | To comment-out part of a line in a template, use the comment syntax ``{# ... | ||
280 | #}``. This is useful for debugging or to add information for other template | ||
281 | designers or yourself: | ||
282 | |||
283 | .. code-block:: jinja | ||
284 | |||
285 | {# note: disabled template because we no longer use this | ||
286 | {% for user in users %} | ||
287 | ... | ||
288 | {% endfor %} | ||
289 | #} | ||
290 | |||
291 | Including other Templates | ||
292 | ------------------------- | ||
293 | |||
294 | The :doc:`include<tags/include>` tag is useful to include a template and | ||
295 | return the rendered content of that template into the current one: | ||
296 | |||
297 | .. code-block:: jinja | ||
298 | |||
299 | {% include 'sidebar.html' %} | ||
300 | |||
301 | Per default included templates are passed the current context. | ||
302 | |||
303 | The context that is passed to the included template includes variables defined | ||
304 | in the template: | ||
305 | |||
306 | .. code-block:: jinja | ||
307 | |||
308 | {% for box in boxes %} | ||
309 | {% include "render_box.html" %} | ||
310 | {% endfor %} | ||
311 | |||
312 | The included template ``render_box.html`` is able to access ``box``. | ||
313 | |||
314 | The filename of the template depends on the template loader. For instance, the | ||
315 | ``Twig_Loader_Filesystem`` allows you to access other templates by giving the | ||
316 | filename. You can access templates in subdirectories with a slash: | ||
317 | |||
318 | .. code-block:: jinja | ||
319 | |||
320 | {% include "sections/articles/sidebar.html" %} | ||
321 | |||
322 | This behavior depends on the application embedding Twig. | ||
323 | |||
324 | Template Inheritance | ||
325 | -------------------- | ||
326 | |||
327 | The most powerful part of Twig is template inheritance. Template inheritance | ||
328 | allows you to build a base "skeleton" template that contains all the common | ||
329 | elements of your site and defines **blocks** that child templates can | ||
330 | override. | ||
331 | |||
332 | Sounds complicated but is very basic. It's easier to understand it by | ||
333 | starting with an example. | ||
334 | |||
335 | Let's define a base template, ``base.html``, which defines a simple HTML | ||
336 | skeleton document that you might use for a simple two-column page: | ||
337 | |||
338 | .. code-block:: html+jinja | ||
339 | |||
340 | <!DOCTYPE html> | ||
341 | <html> | ||
342 | <head> | ||
343 | {% block head %} | ||
344 | <link rel="stylesheet" href="style.css" /> | ||
345 | <title>{% block title %}{% endblock %} - My Webpage</title> | ||
346 | {% endblock %} | ||
347 | </head> | ||
348 | <body> | ||
349 | <div id="content">{% block content %}{% endblock %}</div> | ||
350 | <div id="footer"> | ||
351 | {% block footer %} | ||
352 | © Copyright 2011 by <a href="http://domain.invalid/">you</a>. | ||
353 | {% endblock %} | ||
354 | </div> | ||
355 | </body> | ||
356 | </html> | ||
357 | |||
358 | In this example, the :doc:`block<tags/block>` tags define four blocks that | ||
359 | child templates can fill in. All the ``block`` tag does is to tell the | ||
360 | template engine that a child template may override those portions of the | ||
361 | template. | ||
362 | |||
363 | A child template might look like this: | ||
364 | |||
365 | .. code-block:: jinja | ||
366 | |||
367 | {% extends "base.html" %} | ||
368 | |||
369 | {% block title %}Index{% endblock %} | ||
370 | {% block head %} | ||
371 | {{ parent() }} | ||
372 | <style type="text/css"> | ||
373 | .important { color: #336699; } | ||
374 | </style> | ||
375 | {% endblock %} | ||
376 | {% block content %} | ||
377 | <h1>Index</h1> | ||
378 | <p class="important"> | ||
379 | Welcome to my awesome homepage. | ||
380 | </p> | ||
381 | {% endblock %} | ||
382 | |||
383 | The :doc:`extends<tags/extends>` tag is the key here. It tells the template | ||
384 | engine that this template "extends" another template. When the template system | ||
385 | evaluates this template, first it locates the parent. The extends tag should | ||
386 | be the first tag in the template. | ||
387 | |||
388 | Note that since the child template doesn't define the ``footer`` block, the | ||
389 | value from the parent template is used instead. | ||
390 | |||
391 | It's possible to render the contents of the parent block by using the | ||
392 | :doc:`parent<functions/parent>` function. This gives back the results of the | ||
393 | parent block: | ||
394 | |||
395 | .. code-block:: jinja | ||
396 | |||
397 | {% block sidebar %} | ||
398 | <h3>Table Of Contents</h3> | ||
399 | ... | ||
400 | {{ parent() }} | ||
401 | {% endblock %} | ||
402 | |||
403 | .. tip:: | ||
404 | |||
405 | The documentation page for the :doc:`extends<tags/extends>` tag describes | ||
406 | more advanced features like block nesting, scope, dynamic inheritance, and | ||
407 | conditional inheritance. | ||
408 | |||
409 | .. note:: | ||
410 | |||
411 | Twig also supports multiple inheritance with the so called horizontal reuse | ||
412 | with the help of the :doc:`use<tags/use>` tag. This is an advanced feature | ||
413 | hardly ever needed in regular templates. | ||
414 | |||
415 | HTML Escaping | ||
416 | ------------- | ||
417 | |||
418 | When generating HTML from templates, there's always a risk that a variable | ||
419 | will include characters that affect the resulting HTML. There are two | ||
420 | approaches: manually escaping each variable or automatically escaping | ||
421 | everything by default. | ||
422 | |||
423 | Twig supports both, automatic escaping is enabled by default. | ||
424 | |||
425 | .. note:: | ||
426 | |||
427 | Automatic escaping is only supported if the *escaper* extension has been | ||
428 | enabled (which is the default). | ||
429 | |||
430 | Working with Manual Escaping | ||
431 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
432 | |||
433 | If manual escaping is enabled, it is **your** responsibility to escape | ||
434 | variables if needed. What to escape? Any variable you don't trust. | ||
435 | |||
436 | Escaping works by piping the variable through the | ||
437 | :doc:`escape<filters/escape>` or ``e`` filter: | ||
438 | |||
439 | .. code-block:: jinja | ||
440 | |||
441 | {{ user.username|e }} | ||
442 | |||
443 | By default, the ``escape`` filter uses the ``html`` strategy, but depending on | ||
444 | the escaping context, you might want to explicitly use any other available | ||
445 | strategies: | ||
446 | |||
447 | .. code-block:: jinja | ||
448 | |||
449 | {{ user.username|e('js') }} | ||
450 | {{ user.username|e('css') }} | ||
451 | {{ user.username|e('url') }} | ||
452 | {{ user.username|e('html_attr') }} | ||
453 | |||
454 | Working with Automatic Escaping | ||
455 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
456 | |||
457 | Whether automatic escaping is enabled or not, you can mark a section of a | ||
458 | template to be escaped or not by using the :doc:`autoescape<tags/autoescape>` | ||
459 | tag: | ||
460 | |||
461 | .. code-block:: jinja | ||
462 | |||
463 | {% autoescape %} | ||
464 | Everything will be automatically escaped in this block (using the HTML strategy) | ||
465 | {% endautoescape %} | ||
466 | |||
467 | By default, auto-escaping uses the ``html`` escaping strategy. If you output | ||
468 | variables in other contexts, you need to explicitly escape them with the | ||
469 | appropriate escaping strategy: | ||
470 | |||
471 | .. code-block:: jinja | ||
472 | |||
473 | {% autoescape 'js' %} | ||
474 | Everything will be automatically escaped in this block (using the JS strategy) | ||
475 | {% endautoescape %} | ||
476 | |||
477 | Escaping | ||
478 | -------- | ||
479 | |||
480 | It is sometimes desirable or even necessary to have Twig ignore parts it would | ||
481 | otherwise handle as variables or blocks. For example if the default syntax is | ||
482 | used and you want to use ``{{`` as raw string in the template and not start a | ||
483 | variable you have to use a trick. | ||
484 | |||
485 | The easiest way is to output the variable delimiter (``{{``) by using a variable | ||
486 | expression: | ||
487 | |||
488 | .. code-block:: jinja | ||
489 | |||
490 | {{ '{{' }} | ||
491 | |||
492 | For bigger sections it makes sense to mark a block | ||
493 | :doc:`verbatim<tags/verbatim>`. | ||
494 | |||
495 | Macros | ||
496 | ------ | ||
497 | |||
498 | .. versionadded:: 1.12 | ||
499 | Support for default argument values was added in Twig 1.12. | ||
500 | |||
501 | Macros are comparable with functions in regular programming languages. They | ||
502 | are useful to reuse often used HTML fragments to not repeat yourself. | ||
503 | |||
504 | A macro is defined via the :doc:`macro<tags/macro>` tag. Here is a small example | ||
505 | (subsequently called ``forms.html``) of a macro that renders a form element: | ||
506 | |||
507 | .. code-block:: jinja | ||
508 | |||
509 | {% macro input(name, value, type, size) %} | ||
510 | <input type="{{ type|default('text') }}" name="{{ name }}" value="{{ value|e }}" size="{{ size|default(20) }}" /> | ||
511 | {% endmacro %} | ||
512 | |||
513 | Macros can be defined in any template, and need to be "imported" via the | ||
514 | :doc:`import<tags/import>` tag before being used: | ||
515 | |||
516 | .. code-block:: jinja | ||
517 | |||
518 | {% import "forms.html" as forms %} | ||
519 | |||
520 | <p>{{ forms.input('username') }}</p> | ||
521 | |||
522 | Alternatively, you can import individual macro names from a template into the | ||
523 | current namespace via the :doc:`from<tags/from>` tag and optionally alias them: | ||
524 | |||
525 | .. code-block:: jinja | ||
526 | |||
527 | {% from 'forms.html' import input as input_field %} | ||
528 | |||
529 | <dl> | ||
530 | <dt>Username</dt> | ||
531 | <dd>{{ input_field('username') }}</dd> | ||
532 | <dt>Password</dt> | ||
533 | <dd>{{ input_field('password', '', 'password') }}</dd> | ||
534 | </dl> | ||
535 | |||
536 | A default value can also be defined for macro arguments when not provided in a | ||
537 | macro call: | ||
538 | |||
539 | .. code-block:: jinja | ||
540 | |||
541 | {% macro input(name, value = "", type = "text", size = 20) %} | ||
542 | <input type="{{ type }}" name="{{ name }}" value="{{ value|e }}" size="{{ size }}" /> | ||
543 | {% endmacro %} | ||
544 | |||
545 | .. _twig-expressions: | ||
546 | |||
547 | Expressions | ||
548 | ----------- | ||
549 | |||
550 | Twig allows expressions everywhere. These work very similar to regular PHP and | ||
551 | even if you're not working with PHP you should feel comfortable with it. | ||
552 | |||
553 | .. note:: | ||
554 | |||
555 | The operator precedence is as follows, with the lowest-precedence | ||
556 | operators listed first: ``b-and``, ``b-xor``, ``b-or``, ``or``, ``and``, | ||
557 | ``==``, ``!=``, ``<``, ``>``, ``>=``, ``<=``, ``in``, ``..``, ``+``, | ||
558 | ``-``, ``~``, ``*``, ``/``, ``//``, ``%``, ``is``, ``**``, ``|``, ``[]``, | ||
559 | and ``.``: | ||
560 | |||
561 | .. code-block:: jinja | ||
562 | |||
563 | {% set greeting = 'Hello' %} | ||
564 | {% set name = 'Fabien' %} | ||
565 | |||
566 | {{ greeting ~ name|lower }} {# Hello fabien #} | ||
567 | |||
568 | {# use parenthesis to change precedence #} | ||
569 | {{ (greeting ~ name)|lower }} {# hello fabien #} | ||
570 | |||
571 | Literals | ||
572 | ~~~~~~~~ | ||
573 | |||
574 | .. versionadded:: 1.5 | ||
575 | Support for hash keys as names and expressions was added in Twig 1.5. | ||
576 | |||
577 | The simplest form of expressions are literals. Literals are representations | ||
578 | for PHP types such as strings, numbers, and arrays. The following literals | ||
579 | exist: | ||
580 | |||
581 | * ``"Hello World"``: Everything between two double or single quotes is a | ||
582 | string. They are useful whenever you need a string in the template (for | ||
583 | example as arguments to function calls, filters or just to extend or include | ||
584 | a template). A string can contain a delimiter if it is preceded by a | ||
585 | backslash (``\``) -- like in ``'It\'s good'``. | ||
586 | |||
587 | * ``42`` / ``42.23``: Integers and floating point numbers are created by just | ||
588 | writing the number down. If a dot is present the number is a float, | ||
589 | otherwise an integer. | ||
590 | |||
591 | * ``["foo", "bar"]``: Arrays are defined by a sequence of expressions | ||
592 | separated by a comma (``,``) and wrapped with squared brackets (``[]``). | ||
593 | |||
594 | * ``{"foo": "bar"}``: Hashes are defined by a list of keys and values | ||
595 | separated by a comma (``,``) and wrapped with curly braces (``{}``): | ||
596 | |||
597 | .. code-block:: jinja | ||
598 | |||
599 | {# keys as string #} | ||
600 | { 'foo': 'foo', 'bar': 'bar' } | ||
601 | |||
602 | {# keys as names (equivalent to the previous hash) -- as of Twig 1.5 #} | ||
603 | { foo: 'foo', bar: 'bar' } | ||
604 | |||
605 | {# keys as integer #} | ||
606 | { 2: 'foo', 4: 'bar' } | ||
607 | |||
608 | {# keys as expressions (the expression must be enclosed into parentheses) -- as of Twig 1.5 #} | ||
609 | { (1 + 1): 'foo', (a ~ 'b'): 'bar' } | ||
610 | |||
611 | * ``true`` / ``false``: ``true`` represents the true value, ``false`` | ||
612 | represents the false value. | ||
613 | |||
614 | * ``null``: ``null`` represents no specific value. This is the value returned | ||
615 | when a variable does not exist. ``none`` is an alias for ``null``. | ||
616 | |||
617 | Arrays and hashes can be nested: | ||
618 | |||
619 | .. code-block:: jinja | ||
620 | |||
621 | {% set foo = [1, {"foo": "bar"}] %} | ||
622 | |||
623 | .. tip:: | ||
624 | |||
625 | Using double-quoted or single-quoted strings has no impact on performance | ||
626 | but string interpolation is only supported in double-quoted strings. | ||
627 | |||
628 | Math | ||
629 | ~~~~ | ||
630 | |||
631 | Twig allows you to calculate with values. This is rarely useful in templates | ||
632 | but exists for completeness' sake. The following operators are supported: | ||
633 | |||
634 | * ``+``: Adds two objects together (the operands are casted to numbers). ``{{ | ||
635 | 1 + 1 }}`` is ``2``. | ||
636 | |||
637 | * ``-``: Subtracts the second number from the first one. ``{{ 3 - 2 }}`` is | ||
638 | ``1``. | ||
639 | |||
640 | * ``/``: Divides two numbers. The returned value will be a floating point | ||
641 | number. ``{{ 1 / 2 }}`` is ``{{ 0.5 }}``. | ||
642 | |||
643 | * ``%``: Calculates the remainder of an integer division. ``{{ 11 % 7 }}`` is | ||
644 | ``4``. | ||
645 | |||
646 | * ``//``: Divides two numbers and returns the truncated integer result. ``{{ | ||
647 | 20 // 7 }}`` is ``2``. | ||
648 | |||
649 | * ``*``: Multiplies the left operand with the right one. ``{{ 2 * 2 }}`` would | ||
650 | return ``4``. | ||
651 | |||
652 | * ``**``: Raises the left operand to the power of the right operand. ``{{ 2 ** | ||
653 | 3 }}`` would return ``8``. | ||
654 | |||
655 | Logic | ||
656 | ~~~~~ | ||
657 | |||
658 | You can combine multiple expressions with the following operators: | ||
659 | |||
660 | * ``and``: Returns true if the left and the right operands are both true. | ||
661 | |||
662 | * ``or``: Returns true if the left or the right operand is true. | ||
663 | |||
664 | * ``not``: Negates a statement. | ||
665 | |||
666 | * ``(expr)``: Groups an expression. | ||
667 | |||
668 | .. note:: | ||
669 | |||
670 | Twig also support bitwise operators (``b-and``, ``b-xor``, and ``b-or``). | ||
671 | |||
672 | Comparisons | ||
673 | ~~~~~~~~~~~ | ||
674 | |||
675 | The following comparison operators are supported in any expression: ``==``, | ||
676 | ``!=``, ``<``, ``>``, ``>=``, and ``<=``. | ||
677 | |||
678 | Containment Operator | ||
679 | ~~~~~~~~~~~~~~~~~~~~ | ||
680 | |||
681 | The ``in`` operator performs containment test. | ||
682 | |||
683 | It returns ``true`` if the left operand is contained in the right: | ||
684 | |||
685 | .. code-block:: jinja | ||
686 | |||
687 | {# returns true #} | ||
688 | |||
689 | {{ 1 in [1, 2, 3] }} | ||
690 | |||
691 | {{ 'cd' in 'abcde' }} | ||
692 | |||
693 | .. tip:: | ||
694 | |||
695 | You can use this filter to perform a containment test on strings, arrays, | ||
696 | or objects implementing the ``Traversable`` interface. | ||
697 | |||
698 | To perform a negative test, use the ``not in`` operator: | ||
699 | |||
700 | .. code-block:: jinja | ||
701 | |||
702 | {% if 1 not in [1, 2, 3] %} | ||
703 | |||
704 | {# is equivalent to #} | ||
705 | {% if not (1 in [1, 2, 3]) %} | ||
706 | |||
707 | Test Operator | ||
708 | ~~~~~~~~~~~~~ | ||
709 | |||
710 | The ``is`` operator performs tests. Tests can be used to test a variable against | ||
711 | a common expression. The right operand is name of the test: | ||
712 | |||
713 | .. code-block:: jinja | ||
714 | |||
715 | {# find out if a variable is odd #} | ||
716 | |||
717 | {{ name is odd }} | ||
718 | |||
719 | Tests can accept arguments too: | ||
720 | |||
721 | .. code-block:: jinja | ||
722 | |||
723 | {% if loop.index is divisibleby(3) %} | ||
724 | |||
725 | Tests can be negated by using the ``is not`` operator: | ||
726 | |||
727 | .. code-block:: jinja | ||
728 | |||
729 | {% if loop.index is not divisibleby(3) %} | ||
730 | |||
731 | {# is equivalent to #} | ||
732 | {% if not (loop.index is divisibleby(3)) %} | ||
733 | |||
734 | Go to the :doc:`tests<tests/index>` page to learn more about the built-in | ||
735 | tests. | ||
736 | |||
737 | Other Operators | ||
738 | ~~~~~~~~~~~~~~~ | ||
739 | |||
740 | .. versionadded:: 1.12.0 | ||
741 | Support for the extended ternary operator was added in Twig 1.12.0. | ||
742 | |||
743 | The following operators are very useful but don't fit into any of the other | ||
744 | categories: | ||
745 | |||
746 | * ``..``: Creates a sequence based on the operand before and after the | ||
747 | operator (this is just syntactic sugar for the :doc:`range<functions/range>` | ||
748 | function). | ||
749 | |||
750 | * ``|``: Applies a filter. | ||
751 | |||
752 | * ``~``: Converts all operands into strings and concatenates them. ``{{ "Hello | ||
753 | " ~ name ~ "!" }}`` would return (assuming ``name`` is ``'John'``) ``Hello | ||
754 | John!``. | ||
755 | |||
756 | * ``.``, ``[]``: Gets an attribute of an object. | ||
757 | |||
758 | * ``?:``: The ternary operator: | ||
759 | |||
760 | .. code-block:: jinja | ||
761 | |||
762 | {{ foo ? 'yes' : 'no' }} | ||
763 | |||
764 | {# as of Twig 1.12.0 #} | ||
765 | {{ foo ?: 'no' }} == {{ foo ? foo : 'no' }} | ||
766 | {{ foo ? 'yes' }} == {{ foo ? 'yes' : '' }} | ||
767 | |||
768 | String Interpolation | ||
769 | ~~~~~~~~~~~~~~~~~~~~ | ||
770 | |||
771 | .. versionadded:: 1.5 | ||
772 | String interpolation was added in Twig 1.5. | ||
773 | |||
774 | String interpolation (`#{expression}`) allows any valid expression to appear | ||
775 | within a *double-quoted string*. The result of evaluating that expression is | ||
776 | inserted into the string: | ||
777 | |||
778 | .. code-block:: jinja | ||
779 | |||
780 | {{ "foo #{bar} baz" }} | ||
781 | {{ "foo #{1 + 2} baz" }} | ||
782 | |||
783 | Whitespace Control | ||
784 | ------------------ | ||
785 | |||
786 | .. versionadded:: 1.1 | ||
787 | Tag level whitespace control was added in Twig 1.1. | ||
788 | |||
789 | The first newline after a template tag is removed automatically (like in PHP.) | ||
790 | Whitespace is not further modified by the template engine, so each whitespace | ||
791 | (spaces, tabs, newlines etc.) is returned unchanged. | ||
792 | |||
793 | Use the ``spaceless`` tag to remove whitespace *between HTML tags*: | ||
794 | |||
795 | .. code-block:: jinja | ||
796 | |||
797 | {% spaceless %} | ||
798 | <div> | ||
799 | <strong>foo bar</strong> | ||
800 | </div> | ||
801 | {% endspaceless %} | ||
802 | |||
803 | {# output will be <div><strong>foo bar</strong></div> #} | ||
804 | |||
805 | In addition to the spaceless tag you can also control whitespace on a per tag | ||
806 | level. By using the whitespace control modifier on your tags, you can trim | ||
807 | leading and or trailing whitespace: | ||
808 | |||
809 | .. code-block:: jinja | ||
810 | |||
811 | {% set value = 'no spaces' %} | ||
812 | {#- No leading/trailing whitespace -#} | ||
813 | {%- if true -%} | ||
814 | {{- value -}} | ||
815 | {%- endif -%} | ||
816 | |||
817 | {# output 'no spaces' #} | ||
818 | |||
819 | The above sample shows the default whitespace control modifier, and how you can | ||
820 | use it to remove whitespace around tags. Trimming space will consume all whitespace | ||
821 | for that side of the tag. It is possible to use whitespace trimming on one side | ||
822 | of a tag: | ||
823 | |||
824 | .. code-block:: jinja | ||
825 | |||
826 | {% set value = 'no spaces' %} | ||
827 | <li> {{- value }} </li> | ||
828 | |||
829 | {# outputs '<li>no spaces </li>' #} | ||
830 | |||
831 | Extensions | ||
832 | ---------- | ||
833 | |||
834 | Twig can be easily extended. | ||
835 | |||
836 | If you are looking for new tags, filters, or functions, have a look at the Twig official | ||
837 | `extension repository`_. | ||
838 | |||
839 | If you want to create your own, read the :ref:`Creating an | ||
840 | Extension<creating_extensions>` chapter. | ||
841 | |||
842 | .. _`Twig bundle`: https://github.com/Anomareh/PHP-Twig.tmbundle | ||
843 | .. _`Jinja syntax plugin`: http://jinja.pocoo.org/2/documentation/integration | ||
844 | .. _`Twig syntax plugin`: http://plugins.netbeans.org/plugin/37069/php-twig | ||
845 | .. _`Twig plugin`: https://github.com/pulse00/Twig-Eclipse-Plugin | ||
846 | .. _`Twig language definition`: https://github.com/gabrielcorpse/gedit-twig-template-language | ||
847 | .. _`extension repository`: http://github.com/fabpot/Twig-extensions | ||
848 | .. _`Twig syntax mode`: https://github.com/bobthecow/Twig-HTML.mode | ||
849 | .. _`other Twig syntax mode`: https://github.com/muxx/Twig-HTML.mode | ||
850 | .. _`Notepad++ Twig Highlighter`: https://github.com/Banane9/notepadplusplus-twig | ||
851 | .. _`web-mode.el`: http://web-mode.org/ | ||
diff --git a/vendor/twig/twig/doc/tests/constant.rst b/vendor/twig/twig/doc/tests/constant.rst new file mode 100644 index 00000000..8d0724a8 --- /dev/null +++ b/vendor/twig/twig/doc/tests/constant.rst | |||
@@ -0,0 +1,22 @@ | |||
1 | ``constant`` | ||
2 | ============ | ||
3 | |||
4 | .. versionadded: 1.13.1 | ||
5 | constant now accepts object instances as the second argument. | ||
6 | |||
7 | ``constant`` checks if a variable has the exact same value as a constant. You | ||
8 | can use either global constants or class constants: | ||
9 | |||
10 | .. code-block:: jinja | ||
11 | |||
12 | {% if post.status is constant('Post::PUBLISHED') %} | ||
13 | the status attribute is exactly the same as Post::PUBLISHED | ||
14 | {% endif %} | ||
15 | |||
16 | You can test constants from object instances as well: | ||
17 | |||
18 | .. code-block:: jinja | ||
19 | |||
20 | {% if post.status is constant('PUBLISHED', post) %} | ||
21 | the status attribute is exactly the same as Post::PUBLISHED | ||
22 | {% endif %} | ||
diff --git a/vendor/twig/twig/doc/tests/defined.rst b/vendor/twig/twig/doc/tests/defined.rst new file mode 100644 index 00000000..702ce725 --- /dev/null +++ b/vendor/twig/twig/doc/tests/defined.rst | |||
@@ -0,0 +1,30 @@ | |||
1 | ``defined`` | ||
2 | =========== | ||
3 | |||
4 | ``defined`` checks if a variable is defined in the current context. This is very | ||
5 | useful if you use the ``strict_variables`` option: | ||
6 | |||
7 | .. code-block:: jinja | ||
8 | |||
9 | {# defined works with variable names #} | ||
10 | {% if foo is defined %} | ||
11 | ... | ||
12 | {% endif %} | ||
13 | |||
14 | {# and attributes on variables names #} | ||
15 | {% if foo.bar is defined %} | ||
16 | ... | ||
17 | {% endif %} | ||
18 | |||
19 | {% if foo['bar'] is defined %} | ||
20 | ... | ||
21 | {% endif %} | ||
22 | |||
23 | When using the ``defined`` test on an expression that uses variables in some | ||
24 | method calls, be sure that they are all defined first: | ||
25 | |||
26 | .. code-block:: jinja | ||
27 | |||
28 | {% if var is defined and foo.method(var) is defined %} | ||
29 | ... | ||
30 | {% endif %} | ||
diff --git a/vendor/twig/twig/doc/tests/divisibleby.rst b/vendor/twig/twig/doc/tests/divisibleby.rst new file mode 100644 index 00000000..9b0b9644 --- /dev/null +++ b/vendor/twig/twig/doc/tests/divisibleby.rst | |||
@@ -0,0 +1,10 @@ | |||
1 | ``divisibleby`` | ||
2 | =============== | ||
3 | |||
4 | ``divisibleby`` checks if a variable is divisible by a number: | ||
5 | |||
6 | .. code-block:: jinja | ||
7 | |||
8 | {% if loop.index is divisibleby(3) %} | ||
9 | ... | ||
10 | {% endif %} | ||
diff --git a/vendor/twig/twig/doc/tests/empty.rst b/vendor/twig/twig/doc/tests/empty.rst new file mode 100644 index 00000000..e5b55999 --- /dev/null +++ b/vendor/twig/twig/doc/tests/empty.rst | |||
@@ -0,0 +1,11 @@ | |||
1 | ``empty`` | ||
2 | ========= | ||
3 | |||
4 | ``empty`` checks if a variable is empty: | ||
5 | |||
6 | .. code-block:: jinja | ||
7 | |||
8 | {# evaluates to true if the foo variable is null, false, an empty array, or the empty string #} | ||
9 | {% if foo is empty %} | ||
10 | ... | ||
11 | {% endif %} | ||
diff --git a/vendor/twig/twig/doc/tests/even.rst b/vendor/twig/twig/doc/tests/even.rst new file mode 100644 index 00000000..6ab5cc39 --- /dev/null +++ b/vendor/twig/twig/doc/tests/even.rst | |||
@@ -0,0 +1,10 @@ | |||
1 | ``even`` | ||
2 | ======== | ||
3 | |||
4 | ``even`` returns ``true`` if the given number is even: | ||
5 | |||
6 | .. code-block:: jinja | ||
7 | |||
8 | {{ var is even }} | ||
9 | |||
10 | .. seealso:: :doc:`odd<../tests/odd>` | ||
diff --git a/vendor/twig/twig/doc/tests/index.rst b/vendor/twig/twig/doc/tests/index.rst new file mode 100644 index 00000000..c63208ee --- /dev/null +++ b/vendor/twig/twig/doc/tests/index.rst | |||
@@ -0,0 +1,15 @@ | |||
1 | Tests | ||
2 | ===== | ||
3 | |||
4 | .. toctree:: | ||
5 | :maxdepth: 1 | ||
6 | |||
7 | constant | ||
8 | defined | ||
9 | divisibleby | ||
10 | empty | ||
11 | even | ||
12 | iterable | ||
13 | null | ||
14 | odd | ||
15 | sameas | ||
diff --git a/vendor/twig/twig/doc/tests/iterable.rst b/vendor/twig/twig/doc/tests/iterable.rst new file mode 100644 index 00000000..89a172f7 --- /dev/null +++ b/vendor/twig/twig/doc/tests/iterable.rst | |||
@@ -0,0 +1,19 @@ | |||
1 | ``iterable`` | ||
2 | ============ | ||
3 | |||
4 | .. versionadded:: 1.7 | ||
5 | The iterable test was added in Twig 1.7. | ||
6 | |||
7 | ``iterable`` checks if a variable is an array or a traversable object: | ||
8 | |||
9 | .. code-block:: jinja | ||
10 | |||
11 | {# evaluates to true if the foo variable is iterable #} | ||
12 | {% if users is iterable %} | ||
13 | {% for user in users %} | ||
14 | Hello {{ user }}! | ||
15 | {% endfor %} | ||
16 | {% else %} | ||
17 | {# users is probably a string #} | ||
18 | Hello {{ users }}! | ||
19 | {% endif %} | ||
diff --git a/vendor/twig/twig/doc/tests/null.rst b/vendor/twig/twig/doc/tests/null.rst new file mode 100644 index 00000000..44eec62e --- /dev/null +++ b/vendor/twig/twig/doc/tests/null.rst | |||
@@ -0,0 +1,12 @@ | |||
1 | ``null`` | ||
2 | ======== | ||
3 | |||
4 | ``null`` returns ``true`` if the variable is ``null``: | ||
5 | |||
6 | .. code-block:: jinja | ||
7 | |||
8 | {{ var is null }} | ||
9 | |||
10 | .. note:: | ||
11 | |||
12 | ``none`` is an alias for ``null``. | ||
diff --git a/vendor/twig/twig/doc/tests/odd.rst b/vendor/twig/twig/doc/tests/odd.rst new file mode 100644 index 00000000..9eece777 --- /dev/null +++ b/vendor/twig/twig/doc/tests/odd.rst | |||
@@ -0,0 +1,10 @@ | |||
1 | ``odd`` | ||
2 | ======= | ||
3 | |||
4 | ``odd`` returns ``true`` if the given number is odd: | ||
5 | |||
6 | .. code-block:: jinja | ||
7 | |||
8 | {{ var is odd }} | ||
9 | |||
10 | .. seealso:: :doc:`even<../tests/even>` | ||
diff --git a/vendor/twig/twig/doc/tests/sameas.rst b/vendor/twig/twig/doc/tests/sameas.rst new file mode 100644 index 00000000..efb15c35 --- /dev/null +++ b/vendor/twig/twig/doc/tests/sameas.rst | |||
@@ -0,0 +1,11 @@ | |||
1 | ``sameas`` | ||
2 | ========== | ||
3 | |||
4 | ``sameas`` checks if a variable points to the same memory address than another | ||
5 | variable: | ||
6 | |||
7 | .. code-block:: jinja | ||
8 | |||
9 | {% if foo.attribute is sameas(false) %} | ||
10 | the foo attribute really is the ``false`` PHP value | ||
11 | {% endif %} | ||
diff --git a/vendor/twig/twig/ext/twig/.gitignore b/vendor/twig/twig/ext/twig/.gitignore new file mode 100644 index 00000000..56ea76cc --- /dev/null +++ b/vendor/twig/twig/ext/twig/.gitignore | |||
@@ -0,0 +1,30 @@ | |||
1 | *.sw* | ||
2 | .deps | ||
3 | Makefile | ||
4 | Makefile.fragments | ||
5 | Makefile.global | ||
6 | Makefile.objects | ||
7 | acinclude.m4 | ||
8 | aclocal.m4 | ||
9 | build/ | ||
10 | config.cache | ||
11 | config.guess | ||
12 | config.h | ||
13 | config.h.in | ||
14 | config.log | ||
15 | config.nice | ||
16 | config.status | ||
17 | config.sub | ||
18 | configure | ||
19 | configure.in | ||
20 | install-sh | ||
21 | libtool | ||
22 | ltmain.sh | ||
23 | missing | ||
24 | mkinstalldirs | ||
25 | run-tests.php | ||
26 | twig.loT | ||
27 | .libs/ | ||
28 | modules/ | ||
29 | twig.la | ||
30 | twig.lo | ||
diff --git a/vendor/twig/twig/ext/twig/LICENSE b/vendor/twig/twig/ext/twig/LICENSE new file mode 100644 index 00000000..66b8bb4c --- /dev/null +++ b/vendor/twig/twig/ext/twig/LICENSE | |||
@@ -0,0 +1,22 @@ | |||
1 | Copyright (c) 2011, Derick Rethans <derick@derickrethans.nl> | ||
2 | All rights reserved. | ||
3 | |||
4 | Redistribution and use in source and binary forms, with or without | ||
5 | modification, are permitted provided that the following conditions are met: | ||
6 | |||
7 | * Redistributions of source code must retain the above copyright notice, | ||
8 | this list of conditions and the following disclaimer. | ||
9 | * Redistributions in binary form must reproduce the above copyright | ||
10 | notice, this list of conditions and the following disclaimer in the | ||
11 | documentation and/or other materials provided with the distribution. | ||
12 | |||
13 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | ||
14 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||
15 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
16 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE | ||
17 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | ||
18 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | ||
19 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | ||
20 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | ||
21 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
22 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
diff --git a/vendor/twig/twig/ext/twig/config.m4 b/vendor/twig/twig/ext/twig/config.m4 new file mode 100644 index 00000000..83486be4 --- /dev/null +++ b/vendor/twig/twig/ext/twig/config.m4 | |||
@@ -0,0 +1,8 @@ | |||
1 | dnl config.m4 for extension twig | ||
2 | |||
3 | PHP_ARG_ENABLE(twig, whether to enable twig support, | ||
4 | [ --enable-twig Enable twig support]) | ||
5 | |||
6 | if test "$PHP_TWIG" != "no"; then | ||
7 | PHP_NEW_EXTENSION(twig, twig.c, $ext_shared) | ||
8 | fi | ||
diff --git a/vendor/twig/twig/ext/twig/config.w32 b/vendor/twig/twig/ext/twig/config.w32 new file mode 100644 index 00000000..cb287b99 --- /dev/null +++ b/vendor/twig/twig/ext/twig/config.w32 | |||
@@ -0,0 +1,8 @@ | |||
1 | // vim:ft=javascript | ||
2 | |||
3 | ARG_ENABLE("twig", "Twig support", "no"); | ||
4 | |||
5 | if (PHP_TWIG != "no") { | ||
6 | AC_DEFINE('HAVE_TWIG', 1); | ||
7 | EXTENSION('twig', 'twig.c'); | ||
8 | } | ||
diff --git a/vendor/twig/twig/ext/twig/php_twig.h b/vendor/twig/twig/ext/twig/php_twig.h new file mode 100644 index 00000000..1cf0ad44 --- /dev/null +++ b/vendor/twig/twig/ext/twig/php_twig.h | |||
@@ -0,0 +1,31 @@ | |||
1 | /* | ||
2 | +----------------------------------------------------------------------+ | ||
3 | | Twig Extension | | ||
4 | +----------------------------------------------------------------------+ | ||
5 | | Copyright (c) 2011 Derick Rethans | | ||
6 | +----------------------------------------------------------------------+ | ||
7 | | Redistribution and use in source and binary forms, with or without | | ||
8 | | modification, are permitted provided that the conditions mentioned | | ||
9 | | in the accompanying LICENSE file are met (BSD, revised). | | ||
10 | +----------------------------------------------------------------------+ | ||
11 | | Author: Derick Rethans <derick@derickrethans.nl> | | ||
12 | +----------------------------------------------------------------------+ | ||
13 | */ | ||
14 | |||
15 | #ifndef PHP_TWIG_H | ||
16 | #define PHP_TWIG_H | ||
17 | |||
18 | #define PHP_TWIG_VERSION "1.13.2" | ||
19 | |||
20 | #include "php.h" | ||
21 | |||
22 | extern zend_module_entry twig_module_entry; | ||
23 | #define phpext_twig_ptr &twig_module_entry | ||
24 | |||
25 | #ifdef ZTS | ||
26 | #include "TSRM.h" | ||
27 | #endif | ||
28 | |||
29 | PHP_FUNCTION(twig_template_get_attributes); | ||
30 | |||
31 | #endif | ||
diff --git a/vendor/twig/twig/ext/twig/twig.c b/vendor/twig/twig/ext/twig/twig.c new file mode 100644 index 00000000..3ba9ff2c --- /dev/null +++ b/vendor/twig/twig/ext/twig/twig.c | |||
@@ -0,0 +1,1076 @@ | |||
1 | /* | ||
2 | +----------------------------------------------------------------------+ | ||
3 | | Twig Extension | | ||
4 | +----------------------------------------------------------------------+ | ||
5 | | Copyright (c) 2011 Derick Rethans | | ||
6 | +----------------------------------------------------------------------+ | ||
7 | | Redistribution and use in source and binary forms, with or without | | ||
8 | | modification, are permitted provided that the conditions mentioned | | ||
9 | | in the accompanying LICENSE file are met (BSD, revised). | | ||
10 | +----------------------------------------------------------------------+ | ||
11 | | Author: Derick Rethans <derick@derickrethans.nl> | | ||
12 | +----------------------------------------------------------------------+ | ||
13 | */ | ||
14 | |||
15 | #ifdef HAVE_CONFIG_H | ||
16 | #include "config.h" | ||
17 | #endif | ||
18 | |||
19 | #include "php.h" | ||
20 | #include "php_twig.h" | ||
21 | #include "ext/standard/php_string.h" | ||
22 | #include "ext/standard/php_smart_str.h" | ||
23 | |||
24 | #include "Zend/zend_object_handlers.h" | ||
25 | #include "Zend/zend_interfaces.h" | ||
26 | #include "Zend/zend_exceptions.h" | ||
27 | |||
28 | #ifndef Z_ADDREF_P | ||
29 | #define Z_ADDREF_P(pz) (pz)->refcount++ | ||
30 | #endif | ||
31 | |||
32 | #define FREE_DTOR(z) \ | ||
33 | zval_dtor(z); \ | ||
34 | efree(z); | ||
35 | |||
36 | #if PHP_VERSION_ID >= 50300 | ||
37 | #define APPLY_TSRMLS_DC TSRMLS_DC | ||
38 | #define APPLY_TSRMLS_CC TSRMLS_CC | ||
39 | #define APPLY_TSRMLS_FETCH() | ||
40 | #else | ||
41 | #define APPLY_TSRMLS_DC | ||
42 | #define APPLY_TSRMLS_CC | ||
43 | #define APPLY_TSRMLS_FETCH() TSRMLS_FETCH() | ||
44 | #endif | ||
45 | |||
46 | ZEND_BEGIN_ARG_INFO_EX(twig_template_get_attribute_args, ZEND_SEND_BY_VAL, ZEND_RETURN_VALUE, 6) | ||
47 | ZEND_ARG_INFO(0, template) | ||
48 | ZEND_ARG_INFO(0, object) | ||
49 | ZEND_ARG_INFO(0, item) | ||
50 | ZEND_ARG_INFO(0, arguments) | ||
51 | ZEND_ARG_INFO(0, type) | ||
52 | ZEND_ARG_INFO(0, isDefinedTest) | ||
53 | ZEND_END_ARG_INFO() | ||
54 | |||
55 | zend_function_entry twig_functions[] = { | ||
56 | PHP_FE(twig_template_get_attributes, twig_template_get_attribute_args) | ||
57 | {NULL, NULL, NULL} | ||
58 | }; | ||
59 | |||
60 | |||
61 | zend_module_entry twig_module_entry = { | ||
62 | STANDARD_MODULE_HEADER, | ||
63 | "twig", | ||
64 | twig_functions, | ||
65 | NULL, | ||
66 | NULL, | ||
67 | NULL, | ||
68 | NULL, | ||
69 | NULL, | ||
70 | PHP_TWIG_VERSION, | ||
71 | STANDARD_MODULE_PROPERTIES | ||
72 | }; | ||
73 | |||
74 | |||
75 | #ifdef COMPILE_DL_TWIG | ||
76 | ZEND_GET_MODULE(twig) | ||
77 | #endif | ||
78 | |||
79 | int TWIG_ARRAY_KEY_EXISTS(zval *array, zval *key) | ||
80 | { | ||
81 | zval temp; | ||
82 | int result; | ||
83 | |||
84 | if (Z_TYPE_P(array) != IS_ARRAY) { | ||
85 | return 0; | ||
86 | } | ||
87 | |||
88 | switch (Z_TYPE_P(key)) { | ||
89 | case IS_NULL: | ||
90 | return zend_hash_exists(Z_ARRVAL_P(array), "", 1); | ||
91 | |||
92 | case IS_BOOL: | ||
93 | case IS_DOUBLE: | ||
94 | convert_to_long(key); | ||
95 | case IS_LONG: | ||
96 | return zend_hash_index_exists(Z_ARRVAL_P(array), Z_LVAL_P(key)); | ||
97 | |||
98 | default: | ||
99 | convert_to_string(key); | ||
100 | return zend_symtable_exists(Z_ARRVAL_P(array), Z_STRVAL_P(key), Z_STRLEN_P(key) + 1); | ||
101 | } | ||
102 | } | ||
103 | |||
104 | int TWIG_INSTANCE_OF(zval *object, zend_class_entry *interface TSRMLS_DC) | ||
105 | { | ||
106 | if (Z_TYPE_P(object) != IS_OBJECT) { | ||
107 | return 0; | ||
108 | } | ||
109 | return instanceof_function(Z_OBJCE_P(object), interface TSRMLS_CC); | ||
110 | } | ||
111 | |||
112 | int TWIG_INSTANCE_OF_USERLAND(zval *object, char *interface TSRMLS_DC) | ||
113 | { | ||
114 | zend_class_entry **pce; | ||
115 | if (Z_TYPE_P(object) != IS_OBJECT) { | ||
116 | return 0; | ||
117 | } | ||
118 | if (zend_lookup_class(interface, strlen(interface), &pce TSRMLS_CC) == FAILURE) { | ||
119 | return 0; | ||
120 | } | ||
121 | return instanceof_function(Z_OBJCE_P(object), *pce TSRMLS_CC); | ||
122 | } | ||
123 | |||
124 | zval *TWIG_GET_ARRAYOBJECT_ELEMENT(zval *object, zval *offset TSRMLS_DC) | ||
125 | { | ||
126 | zend_class_entry *ce = Z_OBJCE_P(object); | ||
127 | zval *retval; | ||
128 | |||
129 | if (Z_TYPE_P(object) == IS_OBJECT) { | ||
130 | SEPARATE_ARG_IF_REF(offset); | ||
131 | zend_call_method_with_1_params(&object, ce, NULL, "offsetget", &retval, offset); | ||
132 | |||
133 | zval_ptr_dtor(&offset); | ||
134 | |||
135 | if (!retval) { | ||
136 | if (!EG(exception)) { | ||
137 | zend_error(E_ERROR, "Undefined offset for object of type %s used as array", ce->name); | ||
138 | } | ||
139 | return NULL; | ||
140 | } | ||
141 | |||
142 | return retval; | ||
143 | } | ||
144 | return NULL; | ||
145 | } | ||
146 | |||
147 | int TWIG_ISSET_ARRAYOBJECT_ELEMENT(zval *object, zval *offset TSRMLS_DC) | ||
148 | { | ||
149 | zend_class_entry *ce = Z_OBJCE_P(object); | ||
150 | zval *retval; | ||
151 | |||
152 | if (Z_TYPE_P(object) == IS_OBJECT) { | ||
153 | SEPARATE_ARG_IF_REF(offset); | ||
154 | zend_call_method_with_1_params(&object, ce, NULL, "offsetexists", &retval, offset); | ||
155 | |||
156 | zval_ptr_dtor(&offset); | ||
157 | |||
158 | if (!retval) { | ||
159 | if (!EG(exception)) { | ||
160 | zend_error(E_ERROR, "Undefined offset for object of type %s used as array", ce->name); | ||
161 | } | ||
162 | return 0; | ||
163 | } | ||
164 | |||
165 | return (retval && Z_TYPE_P(retval) == IS_BOOL && Z_LVAL_P(retval)); | ||
166 | } | ||
167 | return 0; | ||
168 | } | ||
169 | |||
170 | char *TWIG_STRTOLOWER(const char *str, int str_len) | ||
171 | { | ||
172 | char *item_dup; | ||
173 | |||
174 | item_dup = estrndup(str, str_len); | ||
175 | php_strtolower(item_dup, str_len); | ||
176 | return item_dup; | ||
177 | } | ||
178 | |||
179 | zval *TWIG_CALL_USER_FUNC_ARRAY(zval *object, char *function, zval *arguments TSRMLS_DC) | ||
180 | { | ||
181 | zend_fcall_info fci; | ||
182 | zval ***args = NULL; | ||
183 | int arg_count = 0; | ||
184 | HashTable *table; | ||
185 | HashPosition pos; | ||
186 | int i = 0; | ||
187 | zval *retval_ptr; | ||
188 | zval *zfunction; | ||
189 | |||
190 | if (arguments) { | ||
191 | table = HASH_OF(arguments); | ||
192 | args = safe_emalloc(sizeof(zval **), table->nNumOfElements, 0); | ||
193 | |||
194 | zend_hash_internal_pointer_reset_ex(table, &pos); | ||
195 | |||
196 | while (zend_hash_get_current_data_ex(table, (void **)&args[i], &pos) == SUCCESS) { | ||
197 | i++; | ||
198 | zend_hash_move_forward_ex(table, &pos); | ||
199 | } | ||
200 | arg_count = table->nNumOfElements; | ||
201 | } | ||
202 | |||
203 | MAKE_STD_ZVAL(zfunction); | ||
204 | ZVAL_STRING(zfunction, function, 1); | ||
205 | fci.size = sizeof(fci); | ||
206 | fci.function_table = EG(function_table); | ||
207 | fci.function_name = zfunction; | ||
208 | fci.symbol_table = NULL; | ||
209 | #if PHP_VERSION_ID >= 50300 | ||
210 | fci.object_ptr = object; | ||
211 | #else | ||
212 | fci.object_pp = &object; | ||
213 | #endif | ||
214 | fci.retval_ptr_ptr = &retval_ptr; | ||
215 | fci.param_count = arg_count; | ||
216 | fci.params = args; | ||
217 | fci.no_separation = 0; | ||
218 | |||
219 | if (zend_call_function(&fci, NULL TSRMLS_CC) == FAILURE) { | ||
220 | ALLOC_INIT_ZVAL(retval_ptr); | ||
221 | ZVAL_BOOL(retval_ptr, 0); | ||
222 | } | ||
223 | |||
224 | if (args) { | ||
225 | efree(fci.params); | ||
226 | } | ||
227 | FREE_DTOR(zfunction); | ||
228 | return retval_ptr; | ||
229 | } | ||
230 | |||
231 | int TWIG_CALL_BOOLEAN(zval *object, char *functionName TSRMLS_DC) | ||
232 | { | ||
233 | zval *ret; | ||
234 | int res; | ||
235 | |||
236 | ret = TWIG_CALL_USER_FUNC_ARRAY(object, functionName, NULL TSRMLS_CC); | ||
237 | res = Z_LVAL_P(ret); | ||
238 | zval_ptr_dtor(&ret); | ||
239 | return res; | ||
240 | } | ||
241 | |||
242 | zval *TWIG_GET_STATIC_PROPERTY(zval *class, char *prop_name TSRMLS_DC) | ||
243 | { | ||
244 | zval **tmp_zval; | ||
245 | zend_class_entry *ce; | ||
246 | |||
247 | if (class == NULL || Z_TYPE_P(class) != IS_OBJECT) { | ||
248 | return NULL; | ||
249 | } | ||
250 | |||
251 | ce = zend_get_class_entry(class TSRMLS_CC); | ||
252 | #if PHP_VERSION_ID >= 50400 | ||
253 | tmp_zval = zend_std_get_static_property(ce, prop_name, strlen(prop_name), 0, NULL TSRMLS_CC); | ||
254 | #else | ||
255 | tmp_zval = zend_std_get_static_property(ce, prop_name, strlen(prop_name), 0 TSRMLS_CC); | ||
256 | #endif | ||
257 | return *tmp_zval; | ||
258 | } | ||
259 | |||
260 | zval *TWIG_GET_ARRAY_ELEMENT_ZVAL(zval *class, zval *prop_name TSRMLS_DC) | ||
261 | { | ||
262 | zval **tmp_zval; | ||
263 | char *tmp_name; | ||
264 | |||
265 | if (class == NULL || Z_TYPE_P(class) != IS_ARRAY) { | ||
266 | if (class != NULL && Z_TYPE_P(class) == IS_OBJECT && TWIG_INSTANCE_OF(class, zend_ce_arrayaccess TSRMLS_CC)) { | ||
267 | // array access object | ||
268 | return TWIG_GET_ARRAYOBJECT_ELEMENT(class, prop_name TSRMLS_CC); | ||
269 | } | ||
270 | return NULL; | ||
271 | } | ||
272 | |||
273 | switch(Z_TYPE_P(prop_name)) { | ||
274 | case IS_NULL: | ||
275 | zend_hash_find(HASH_OF(class), "", 1, (void**) &tmp_zval); | ||
276 | return *tmp_zval; | ||
277 | |||
278 | case IS_BOOL: | ||
279 | case IS_DOUBLE: | ||
280 | convert_to_long(prop_name); | ||
281 | case IS_LONG: | ||
282 | zend_hash_index_find(HASH_OF(class), Z_LVAL_P(prop_name), (void **) &tmp_zval); | ||
283 | return *tmp_zval; | ||
284 | |||
285 | case IS_STRING: | ||
286 | zend_symtable_find(HASH_OF(class), Z_STRVAL_P(prop_name), Z_STRLEN_P(prop_name) + 1, (void**) &tmp_zval); | ||
287 | return *tmp_zval; | ||
288 | } | ||
289 | |||
290 | return NULL; | ||
291 | } | ||
292 | |||
293 | zval *TWIG_GET_ARRAY_ELEMENT(zval *class, char *prop_name, int prop_name_length TSRMLS_DC) | ||
294 | { | ||
295 | zval **tmp_zval; | ||
296 | |||
297 | if (class == NULL/* || Z_TYPE_P(class) != IS_ARRAY*/) { | ||
298 | return NULL; | ||
299 | } | ||
300 | |||
301 | if (class != NULL && Z_TYPE_P(class) == IS_OBJECT && TWIG_INSTANCE_OF(class, zend_ce_arrayaccess TSRMLS_CC)) { | ||
302 | // array access object | ||
303 | zval *tmp_name_zval; | ||
304 | zval *tmp_ret_zval; | ||
305 | |||
306 | ALLOC_INIT_ZVAL(tmp_name_zval); | ||
307 | ZVAL_STRING(tmp_name_zval, prop_name, 1); | ||
308 | tmp_ret_zval = TWIG_GET_ARRAYOBJECT_ELEMENT(class, tmp_name_zval TSRMLS_CC); | ||
309 | FREE_DTOR(tmp_name_zval); | ||
310 | return tmp_ret_zval; | ||
311 | } | ||
312 | |||
313 | if (zend_symtable_find(HASH_OF(class), prop_name, prop_name_length+1, (void**)&tmp_zval) == SUCCESS) { | ||
314 | return *tmp_zval; | ||
315 | } | ||
316 | return NULL; | ||
317 | } | ||
318 | |||
319 | zval *TWIG_PROPERTY(zval *object, zval *propname TSRMLS_DC) | ||
320 | { | ||
321 | zval *tmp = NULL; | ||
322 | |||
323 | if (Z_OBJ_HT_P(object)->read_property) { | ||
324 | #if PHP_VERSION_ID >= 50400 | ||
325 | tmp = Z_OBJ_HT_P(object)->read_property(object, propname, BP_VAR_IS, NULL TSRMLS_CC); | ||
326 | #else | ||
327 | tmp = Z_OBJ_HT_P(object)->read_property(object, propname, BP_VAR_IS TSRMLS_CC); | ||
328 | #endif | ||
329 | if (tmp != EG(uninitialized_zval_ptr)) { | ||
330 | return tmp; | ||
331 | } else { | ||
332 | return NULL; | ||
333 | } | ||
334 | } | ||
335 | return tmp; | ||
336 | } | ||
337 | |||
338 | int TWIG_HAS_PROPERTY(zval *object, zval *propname TSRMLS_DC) | ||
339 | { | ||
340 | if (Z_OBJ_HT_P(object)->has_property) { | ||
341 | #if PHP_VERSION_ID >= 50400 | ||
342 | return Z_OBJ_HT_P(object)->has_property(object, propname, 0, NULL TSRMLS_CC); | ||
343 | #else | ||
344 | return Z_OBJ_HT_P(object)->has_property(object, propname, 0 TSRMLS_CC); | ||
345 | #endif | ||
346 | } | ||
347 | return 0; | ||
348 | } | ||
349 | |||
350 | int TWIG_HAS_DYNAMIC_PROPERTY(zval *object, char *prop, int prop_len TSRMLS_DC) | ||
351 | { | ||
352 | if (Z_OBJ_HT_P(object)->get_properties) { | ||
353 | return zend_hash_quick_exists( | ||
354 | Z_OBJ_HT_P(object)->get_properties(object TSRMLS_CC), // the properties hash | ||
355 | prop, // property name | ||
356 | prop_len + 1, // property length | ||
357 | zend_get_hash_value(prop, prop_len + 1) // hash value | ||
358 | ); | ||
359 | } | ||
360 | return 0; | ||
361 | } | ||
362 | |||
363 | zval *TWIG_PROPERTY_CHAR(zval *object, char *propname TSRMLS_DC) | ||
364 | { | ||
365 | zval *tmp_name_zval, *tmp; | ||
366 | |||
367 | ALLOC_INIT_ZVAL(tmp_name_zval); | ||
368 | ZVAL_STRING(tmp_name_zval, propname, 1); | ||
369 | tmp = TWIG_PROPERTY(object, tmp_name_zval TSRMLS_CC); | ||
370 | FREE_DTOR(tmp_name_zval); | ||
371 | return tmp; | ||
372 | } | ||
373 | |||
374 | int TWIG_CALL_B_0(zval *object, char *method) | ||
375 | { | ||
376 | return 0; | ||
377 | } | ||
378 | |||
379 | zval *TWIG_CALL_S(zval *object, char *method, char *arg0 TSRMLS_DC) | ||
380 | { | ||
381 | zend_fcall_info fci; | ||
382 | zval **args[1]; | ||
383 | zval *argument; | ||
384 | zval *zfunction; | ||
385 | zval *retval_ptr; | ||
386 | |||
387 | MAKE_STD_ZVAL(argument); | ||
388 | ZVAL_STRING(argument, arg0, 1); | ||
389 | args[0] = &argument; | ||
390 | |||
391 | MAKE_STD_ZVAL(zfunction); | ||
392 | ZVAL_STRING(zfunction, method, 1); | ||
393 | fci.size = sizeof(fci); | ||
394 | fci.function_table = EG(function_table); | ||
395 | fci.function_name = zfunction; | ||
396 | fci.symbol_table = NULL; | ||
397 | #if PHP_VERSION_ID >= 50300 | ||
398 | fci.object_ptr = object; | ||
399 | #else | ||
400 | fci.object_pp = &object; | ||
401 | #endif | ||
402 | fci.retval_ptr_ptr = &retval_ptr; | ||
403 | fci.param_count = 1; | ||
404 | fci.params = args; | ||
405 | fci.no_separation = 0; | ||
406 | |||
407 | if (zend_call_function(&fci, NULL TSRMLS_CC) == FAILURE) { | ||
408 | FREE_DTOR(zfunction); | ||
409 | zval_ptr_dtor(&argument); | ||
410 | return 0; | ||
411 | } | ||
412 | FREE_DTOR(zfunction); | ||
413 | zval_ptr_dtor(&argument); | ||
414 | return retval_ptr; | ||
415 | } | ||
416 | |||
417 | int TWIG_CALL_SB(zval *object, char *method, char *arg0 TSRMLS_DC) | ||
418 | { | ||
419 | zval *retval_ptr; | ||
420 | int success; | ||
421 | |||
422 | retval_ptr = TWIG_CALL_S(object, method, arg0 TSRMLS_CC); | ||
423 | success = (retval_ptr && (Z_TYPE_P(retval_ptr) == IS_BOOL) && Z_LVAL_P(retval_ptr)); | ||
424 | |||
425 | if (retval_ptr) { | ||
426 | zval_ptr_dtor(&retval_ptr); | ||
427 | } | ||
428 | |||
429 | return success; | ||
430 | } | ||
431 | |||
432 | int TWIG_CALL_Z(zval *object, char *method, zval *arg1 TSRMLS_DC) | ||
433 | { | ||
434 | zend_fcall_info fci; | ||
435 | zval **args[1]; | ||
436 | zval *zfunction; | ||
437 | zval *retval_ptr; | ||
438 | int success; | ||
439 | |||
440 | args[0] = &arg1; | ||
441 | |||
442 | MAKE_STD_ZVAL(zfunction); | ||
443 | ZVAL_STRING(zfunction, method, 1); | ||
444 | fci.size = sizeof(fci); | ||
445 | fci.function_table = EG(function_table); | ||
446 | fci.function_name = zfunction; | ||
447 | fci.symbol_table = NULL; | ||
448 | #if PHP_VERSION_ID >= 50300 | ||
449 | fci.object_ptr = object; | ||
450 | #else | ||
451 | fci.object_pp = &object; | ||
452 | #endif | ||
453 | fci.retval_ptr_ptr = &retval_ptr; | ||
454 | fci.param_count = 1; | ||
455 | fci.params = args; | ||
456 | fci.no_separation = 0; | ||
457 | |||
458 | if (zend_call_function(&fci, NULL TSRMLS_CC) == FAILURE) { | ||
459 | FREE_DTOR(zfunction); | ||
460 | if (retval_ptr) { | ||
461 | zval_ptr_dtor(&retval_ptr); | ||
462 | } | ||
463 | return 0; | ||
464 | } | ||
465 | |||
466 | FREE_DTOR(zfunction); | ||
467 | |||
468 | success = (retval_ptr && (Z_TYPE_P(retval_ptr) == IS_BOOL) && Z_LVAL_P(retval_ptr)); | ||
469 | if (retval_ptr) { | ||
470 | zval_ptr_dtor(&retval_ptr); | ||
471 | } | ||
472 | |||
473 | return success; | ||
474 | } | ||
475 | |||
476 | int TWIG_CALL_ZZ(zval *object, char *method, zval *arg1, zval *arg2 TSRMLS_DC) | ||
477 | { | ||
478 | zend_fcall_info fci; | ||
479 | zval **args[2]; | ||
480 | zval *zfunction; | ||
481 | zval *retval_ptr; | ||
482 | int success; | ||
483 | |||
484 | args[0] = &arg1; | ||
485 | args[1] = &arg2; | ||
486 | |||
487 | MAKE_STD_ZVAL(zfunction); | ||
488 | ZVAL_STRING(zfunction, method, 1); | ||
489 | fci.size = sizeof(fci); | ||
490 | fci.function_table = EG(function_table); | ||
491 | fci.function_name = zfunction; | ||
492 | fci.symbol_table = NULL; | ||
493 | #if PHP_VERSION_ID >= 50300 | ||
494 | fci.object_ptr = object; | ||
495 | #else | ||
496 | fci.object_pp = &object; | ||
497 | #endif | ||
498 | fci.retval_ptr_ptr = &retval_ptr; | ||
499 | fci.param_count = 2; | ||
500 | fci.params = args; | ||
501 | fci.no_separation = 0; | ||
502 | |||
503 | if (zend_call_function(&fci, NULL TSRMLS_CC) == FAILURE) { | ||
504 | FREE_DTOR(zfunction); | ||
505 | return 0; | ||
506 | } | ||
507 | |||
508 | FREE_DTOR(zfunction); | ||
509 | |||
510 | success = (retval_ptr && (Z_TYPE_P(retval_ptr) == IS_BOOL) && Z_LVAL_P(retval_ptr)); | ||
511 | if (retval_ptr) { | ||
512 | zval_ptr_dtor(&retval_ptr); | ||
513 | } | ||
514 | |||
515 | return success; | ||
516 | } | ||
517 | |||
518 | #ifndef Z_SET_REFCOUNT_P | ||
519 | # define Z_SET_REFCOUNT_P(pz, rc) pz->refcount = rc | ||
520 | # define Z_UNSET_ISREF_P(pz) pz->is_ref = 0 | ||
521 | #endif | ||
522 | |||
523 | void TWIG_NEW(zval *object, char *class, zval *arg0, zval *arg1 TSRMLS_DC) | ||
524 | { | ||
525 | zend_class_entry **pce; | ||
526 | |||
527 | if (zend_lookup_class(class, strlen(class), &pce TSRMLS_CC) == FAILURE) { | ||
528 | return; | ||
529 | } | ||
530 | |||
531 | Z_TYPE_P(object) = IS_OBJECT; | ||
532 | object_init_ex(object, *pce); | ||
533 | Z_SET_REFCOUNT_P(object, 1); | ||
534 | Z_UNSET_ISREF_P(object); | ||
535 | |||
536 | TWIG_CALL_ZZ(object, "__construct", arg0, arg1 TSRMLS_CC); | ||
537 | } | ||
538 | |||
539 | static int twig_add_array_key_to_string(void *pDest APPLY_TSRMLS_DC, int num_args, va_list args, zend_hash_key *hash_key) | ||
540 | { | ||
541 | smart_str *buf; | ||
542 | char *joiner; | ||
543 | APPLY_TSRMLS_FETCH(); | ||
544 | |||
545 | buf = va_arg(args, smart_str*); | ||
546 | joiner = va_arg(args, char*); | ||
547 | |||
548 | if (buf->len != 0) { | ||
549 | smart_str_appends(buf, joiner); | ||
550 | } | ||
551 | |||
552 | if (hash_key->nKeyLength == 0) { | ||
553 | smart_str_append_long(buf, (long) hash_key->h); | ||
554 | } else { | ||
555 | char *key, *tmp_str; | ||
556 | int key_len, tmp_len; | ||
557 | key = php_addcslashes(hash_key->arKey, hash_key->nKeyLength - 1, &key_len, 0, "'\\", 2 TSRMLS_CC); | ||
558 | tmp_str = php_str_to_str_ex(key, key_len, "\0", 1, "' . \"\\0\" . '", 12, &tmp_len, 0, NULL); | ||
559 | |||
560 | smart_str_appendl(buf, tmp_str, tmp_len); | ||
561 | efree(key); | ||
562 | efree(tmp_str); | ||
563 | } | ||
564 | |||
565 | return 0; | ||
566 | } | ||
567 | |||
568 | char *TWIG_IMPLODE_ARRAY_KEYS(char *joiner, zval *array TSRMLS_DC) | ||
569 | { | ||
570 | smart_str collector = { 0, 0, 0 }; | ||
571 | |||
572 | smart_str_appendl(&collector, "", 0); | ||
573 | zend_hash_apply_with_arguments(HASH_OF(array) APPLY_TSRMLS_CC, twig_add_array_key_to_string, 2, &collector, joiner); | ||
574 | smart_str_0(&collector); | ||
575 | |||
576 | return collector.c; | ||
577 | } | ||
578 | |||
579 | static void TWIG_THROW_EXCEPTION(char *exception_name TSRMLS_DC, char *message, ...) | ||
580 | { | ||
581 | char *buffer; | ||
582 | va_list args; | ||
583 | zend_class_entry **pce; | ||
584 | |||
585 | if (zend_lookup_class(exception_name, strlen(exception_name), &pce TSRMLS_CC) == FAILURE) { | ||
586 | return; | ||
587 | } | ||
588 | |||
589 | va_start(args, message); | ||
590 | vspprintf(&buffer, 0, message, args); | ||
591 | va_end(args); | ||
592 | |||
593 | zend_throw_exception_ex(*pce, 0 TSRMLS_CC, buffer); | ||
594 | efree(buffer); | ||
595 | } | ||
596 | |||
597 | static void TWIG_RUNTIME_ERROR(zval *template TSRMLS_DC, char *message, ...) | ||
598 | { | ||
599 | char *buffer; | ||
600 | va_list args; | ||
601 | zend_class_entry **pce; | ||
602 | zval *ex; | ||
603 | zval *constructor; | ||
604 | zval *zmessage; | ||
605 | zval *lineno; | ||
606 | zval *filename_func; | ||
607 | zval *filename; | ||
608 | zval *constructor_args[3]; | ||
609 | zval *constructor_retval; | ||
610 | |||
611 | if (zend_lookup_class("Twig_Error_Runtime", strlen("Twig_Error_Runtime"), &pce TSRMLS_CC) == FAILURE) { | ||
612 | return; | ||
613 | } | ||
614 | |||
615 | va_start(args, message); | ||
616 | vspprintf(&buffer, 0, message, args); | ||
617 | va_end(args); | ||
618 | |||
619 | MAKE_STD_ZVAL(ex); | ||
620 | object_init_ex(ex, *pce); | ||
621 | |||
622 | // Call Twig_Error constructor | ||
623 | MAKE_STD_ZVAL(constructor); | ||
624 | MAKE_STD_ZVAL(zmessage); | ||
625 | MAKE_STD_ZVAL(lineno); | ||
626 | MAKE_STD_ZVAL(filename); | ||
627 | MAKE_STD_ZVAL(filename_func); | ||
628 | MAKE_STD_ZVAL(constructor_retval); | ||
629 | |||
630 | ZVAL_STRINGL(constructor, "__construct", sizeof("__construct")-1, 1); | ||
631 | ZVAL_STRING(zmessage, buffer, 1); | ||
632 | ZVAL_LONG(lineno, -1); | ||
633 | |||
634 | // Get template filename | ||
635 | ZVAL_STRINGL(filename_func, "getTemplateName", sizeof("getTemplateName")-1, 1); | ||
636 | call_user_function(EG(function_table), &template, filename_func, filename, 0, 0 TSRMLS_CC); | ||
637 | |||
638 | constructor_args[0] = zmessage; | ||
639 | constructor_args[1] = lineno; | ||
640 | constructor_args[2] = filename; | ||
641 | call_user_function(EG(function_table), &ex, constructor, constructor_retval, 3, constructor_args TSRMLS_CC); | ||
642 | |||
643 | zval_ptr_dtor(&constructor_retval); | ||
644 | zval_ptr_dtor(&zmessage); | ||
645 | zval_ptr_dtor(&lineno); | ||
646 | zval_ptr_dtor(&filename); | ||
647 | FREE_DTOR(constructor); | ||
648 | FREE_DTOR(filename_func); | ||
649 | efree(buffer); | ||
650 | |||
651 | zend_throw_exception_object(ex TSRMLS_CC); | ||
652 | } | ||
653 | |||
654 | static char *TWIG_GET_CLASS_NAME(zval *object TSRMLS_DC) | ||
655 | { | ||
656 | char *class_name; | ||
657 | zend_uint class_name_len; | ||
658 | |||
659 | if (Z_TYPE_P(object) != IS_OBJECT) { | ||
660 | return ""; | ||
661 | } | ||
662 | #if PHP_API_VERSION >= 20100412 | ||
663 | zend_get_object_classname(object, (const char **) &class_name, &class_name_len TSRMLS_CC); | ||
664 | #else | ||
665 | zend_get_object_classname(object, &class_name, &class_name_len TSRMLS_CC); | ||
666 | #endif | ||
667 | return class_name; | ||
668 | } | ||
669 | |||
670 | static int twig_add_method_to_class(void *pDest APPLY_TSRMLS_DC, int num_args, va_list args, zend_hash_key *hash_key) | ||
671 | { | ||
672 | zval *retval; | ||
673 | char *item; | ||
674 | size_t item_len; | ||
675 | zend_function *mptr = (zend_function *) pDest; | ||
676 | APPLY_TSRMLS_FETCH(); | ||
677 | |||
678 | if (!(mptr->common.fn_flags & ZEND_ACC_PUBLIC)) { | ||
679 | return 0; | ||
680 | } | ||
681 | |||
682 | retval = va_arg(args, zval*); | ||
683 | |||
684 | item_len = strlen(mptr->common.function_name); | ||
685 | item = estrndup(mptr->common.function_name, item_len); | ||
686 | php_strtolower(item, item_len); | ||
687 | |||
688 | add_assoc_stringl_ex(retval, item, item_len+1, item, item_len, 0); | ||
689 | |||
690 | return 0; | ||
691 | } | ||
692 | |||
693 | static int twig_add_property_to_class(void *pDest APPLY_TSRMLS_DC, int num_args, va_list args, zend_hash_key *hash_key) | ||
694 | { | ||
695 | zend_class_entry *ce; | ||
696 | zval *retval; | ||
697 | char *class_name, *prop_name; | ||
698 | zend_property_info *pptr = (zend_property_info *) pDest; | ||
699 | APPLY_TSRMLS_FETCH(); | ||
700 | |||
701 | if (!(pptr->flags & ZEND_ACC_PUBLIC)) { | ||
702 | return 0; | ||
703 | } | ||
704 | |||
705 | ce = *va_arg(args, zend_class_entry**); | ||
706 | retval = va_arg(args, zval*); | ||
707 | |||
708 | #if PHP_API_VERSION >= 20100412 | ||
709 | zend_unmangle_property_name(pptr->name, pptr->name_length, (const char **) &class_name, (const char **) &prop_name); | ||
710 | #else | ||
711 | zend_unmangle_property_name(pptr->name, pptr->name_length, &class_name, &prop_name); | ||
712 | #endif | ||
713 | |||
714 | add_assoc_string(retval, prop_name, prop_name, 1); | ||
715 | |||
716 | return 0; | ||
717 | } | ||
718 | |||
719 | static void twig_add_class_to_cache(zval *cache, zval *object, char *class_name TSRMLS_DC) | ||
720 | { | ||
721 | zval *class_info, *class_methods, *class_properties; | ||
722 | zend_class_entry *class_ce; | ||
723 | |||
724 | class_ce = zend_get_class_entry(object TSRMLS_CC); | ||
725 | |||
726 | ALLOC_INIT_ZVAL(class_info); | ||
727 | ALLOC_INIT_ZVAL(class_methods); | ||
728 | ALLOC_INIT_ZVAL(class_properties); | ||
729 | array_init(class_info); | ||
730 | array_init(class_methods); | ||
731 | array_init(class_properties); | ||
732 | // add all methods to self::cache[$class]['methods'] | ||
733 | zend_hash_apply_with_arguments(&class_ce->function_table APPLY_TSRMLS_CC, twig_add_method_to_class, 1, class_methods); | ||
734 | zend_hash_apply_with_arguments(&class_ce->properties_info APPLY_TSRMLS_CC, twig_add_property_to_class, 2, &class_ce, class_properties); | ||
735 | |||
736 | add_assoc_zval(class_info, "methods", class_methods); | ||
737 | add_assoc_zval(class_info, "properties", class_properties); | ||
738 | add_assoc_zval(cache, class_name, class_info); | ||
739 | } | ||
740 | |||
741 | /* {{{ proto mixed twig_template_get_attributes(TwigTemplate template, mixed object, mixed item, array arguments, string type, boolean isDefinedTest, boolean ignoreStrictCheck) | ||
742 | A C implementation of TwigTemplate::getAttribute() */ | ||
743 | PHP_FUNCTION(twig_template_get_attributes) | ||
744 | { | ||
745 | zval *template; | ||
746 | zval *object; | ||
747 | char *item; | ||
748 | int item_len; | ||
749 | zval *zitem, ztmpitem; | ||
750 | zval *arguments = NULL; | ||
751 | zval *ret = NULL; | ||
752 | char *type = NULL; | ||
753 | int type_len = 0; | ||
754 | zend_bool isDefinedTest = 0; | ||
755 | zend_bool ignoreStrictCheck = 0; | ||
756 | int free_ret = 0; | ||
757 | zval *tmp_self_cache; | ||
758 | |||
759 | |||
760 | if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ozz|asbb", &template, &object, &zitem, &arguments, &type, &type_len, &isDefinedTest, &ignoreStrictCheck) == FAILURE) { | ||
761 | return; | ||
762 | } | ||
763 | |||
764 | // convert the item to a string | ||
765 | ztmpitem = *zitem; | ||
766 | zval_copy_ctor(&ztmpitem); | ||
767 | convert_to_string(&ztmpitem); | ||
768 | item_len = Z_STRLEN(ztmpitem); | ||
769 | item = estrndup(Z_STRVAL(ztmpitem), item_len); | ||
770 | zval_dtor(&ztmpitem); | ||
771 | |||
772 | if (!type) { | ||
773 | type = "any"; | ||
774 | } | ||
775 | |||
776 | /* | ||
777 | // array | ||
778 | if (Twig_TemplateInterface::METHOD_CALL !== $type) { | ||
779 | $arrayItem = is_bool($item) || is_float($item) ? (int) $item : $item; | ||
780 | |||
781 | if ((is_array($object) && array_key_exists($arrayItem, $object)) | ||
782 | || ($object instanceof ArrayAccess && isset($object[$arrayItem])) | ||
783 | ) { | ||
784 | if ($isDefinedTest) { | ||
785 | return true; | ||
786 | } | ||
787 | |||
788 | return $object[$arrayItem]; | ||
789 | } | ||
790 | */ | ||
791 | |||
792 | |||
793 | if (strcmp("method", type) != 0) { | ||
794 | if ((TWIG_ARRAY_KEY_EXISTS(object, zitem)) | ||
795 | || (TWIG_INSTANCE_OF(object, zend_ce_arrayaccess TSRMLS_CC) && TWIG_ISSET_ARRAYOBJECT_ELEMENT(object, zitem TSRMLS_CC)) | ||
796 | ) { | ||
797 | |||
798 | if (isDefinedTest) { | ||
799 | RETURN_TRUE; | ||
800 | } | ||
801 | |||
802 | ret = TWIG_GET_ARRAY_ELEMENT_ZVAL(object, zitem TSRMLS_CC); | ||
803 | |||
804 | if (!ret) { | ||
805 | ret = &EG(uninitialized_zval); | ||
806 | } | ||
807 | RETVAL_ZVAL(ret, 1, 0); | ||
808 | if (free_ret) { | ||
809 | zval_ptr_dtor(&ret); | ||
810 | } | ||
811 | return; | ||
812 | } | ||
813 | /* | ||
814 | if (Twig_TemplateInterface::ARRAY_CALL === $type) { | ||
815 | if ($isDefinedTest) { | ||
816 | return false; | ||
817 | } | ||
818 | if ($ignoreStrictCheck || !$this->env->isStrictVariables()) { | ||
819 | return null; | ||
820 | } | ||
821 | */ | ||
822 | if (strcmp("array", type) == 0 || Z_TYPE_P(object) != IS_OBJECT) { | ||
823 | if (isDefinedTest) { | ||
824 | RETURN_FALSE; | ||
825 | } | ||
826 | if (ignoreStrictCheck || !TWIG_CALL_BOOLEAN(TWIG_PROPERTY_CHAR(template, "env" TSRMLS_CC), "isStrictVariables" TSRMLS_CC)) { | ||
827 | return; | ||
828 | } | ||
829 | /* | ||
830 | if (is_object($object)) { | ||
831 | throw new Twig_Error_Runtime(sprintf('Key "%s" in object (with ArrayAccess) of type "%s" does not exist', $arrayItem, get_class($object)), -1, $this->getTemplateName()); | ||
832 | } elseif (is_array($object)) { | ||
833 | throw new Twig_Error_Runtime(sprintf('Key "%s" for array with keys "%s" does not exist', $arrayItem, implode(', ', array_keys($object))), -1, $this->getTemplateName()); | ||
834 | } elseif (Twig_TemplateInterface::ARRAY_CALL === $type) { | ||
835 | throw new Twig_Error_Runtime(sprintf('Impossible to access a key ("%s") on a %s variable ("%s")', $item, gettype($object), $object), -1, $this->getTemplateName()); | ||
836 | } else { | ||
837 | throw new Twig_Error_Runtime(sprintf('Impossible to access an attribute ("%s") on a %s variable ("%s")', $item, gettype($object), $object), -1, $this->getTemplateName()); | ||
838 | } | ||
839 | } | ||
840 | } | ||
841 | */ | ||
842 | if (Z_TYPE_P(object) == IS_OBJECT) { | ||
843 | TWIG_RUNTIME_ERROR(template TSRMLS_CC, "Key \"%s\" in object (with ArrayAccess) of type \"%s\" does not exist", item, TWIG_GET_CLASS_NAME(object TSRMLS_CC)); | ||
844 | } else if (Z_TYPE_P(object) == IS_ARRAY) { | ||
845 | TWIG_RUNTIME_ERROR(template TSRMLS_CC, "Key \"%s\" for array with keys \"%s\" does not exist", item, TWIG_IMPLODE_ARRAY_KEYS(", ", object TSRMLS_CC)); | ||
846 | } else { | ||
847 | char *type_name = zend_zval_type_name(object); | ||
848 | Z_ADDREF_P(object); | ||
849 | convert_to_string(object); | ||
850 | TWIG_RUNTIME_ERROR(template TSRMLS_CC, | ||
851 | (strcmp("array", type) == 0) | ||
852 | ? "Impossible to access a key (\"%s\") on a %s variable (\"%s\")" | ||
853 | : "Impossible to access an attribute (\"%s\") on a %s variable (\"%s\")", | ||
854 | item, type_name, Z_STRVAL_P(object)); | ||
855 | zval_ptr_dtor(&object); | ||
856 | } | ||
857 | return; | ||
858 | } | ||
859 | } | ||
860 | |||
861 | /* | ||
862 | if (!is_object($object)) { | ||
863 | if ($isDefinedTest) { | ||
864 | return false; | ||
865 | } | ||
866 | */ | ||
867 | |||
868 | if (Z_TYPE_P(object) != IS_OBJECT) { | ||
869 | if (isDefinedTest) { | ||
870 | RETURN_FALSE; | ||
871 | } | ||
872 | /* | ||
873 | if ($ignoreStrictCheck || !$this->env->isStrictVariables()) { | ||
874 | return null; | ||
875 | } | ||
876 | throw new Twig_Error_Runtime(sprintf('Impossible to invoke a method ("%s") on a %s variable ("%s")', $item, gettype($object), $object), -1, $this->getTemplateName()); | ||
877 | } | ||
878 | */ | ||
879 | if (ignoreStrictCheck || !TWIG_CALL_BOOLEAN(TWIG_PROPERTY_CHAR(template, "env" TSRMLS_CC), "isStrictVariables" TSRMLS_CC)) { | ||
880 | return; | ||
881 | } | ||
882 | |||
883 | char *type_name = zend_zval_type_name(object); | ||
884 | Z_ADDREF_P(object); | ||
885 | convert_to_string_ex(&object); | ||
886 | |||
887 | TWIG_RUNTIME_ERROR(template TSRMLS_CC, "Impossible to invoke a method (\"%s\") on a %s variable (\"%s\")", item, type_name, Z_STRVAL_P(object)); | ||
888 | |||
889 | zval_ptr_dtor(&object); | ||
890 | |||
891 | return; | ||
892 | } | ||
893 | /* | ||
894 | $class = get_class($object); | ||
895 | */ | ||
896 | char *class_name = NULL; | ||
897 | zval *tmp_class; | ||
898 | |||
899 | class_name = TWIG_GET_CLASS_NAME(object TSRMLS_CC); | ||
900 | tmp_self_cache = TWIG_GET_STATIC_PROPERTY(template, "cache" TSRMLS_CC); | ||
901 | tmp_class = TWIG_GET_ARRAY_ELEMENT(tmp_self_cache, class_name, strlen(class_name) TSRMLS_CC); | ||
902 | |||
903 | if (!tmp_class) { | ||
904 | twig_add_class_to_cache(tmp_self_cache, object, class_name TSRMLS_CC); | ||
905 | tmp_class = TWIG_GET_ARRAY_ELEMENT(tmp_self_cache, class_name, strlen(class_name) TSRMLS_CC); | ||
906 | } | ||
907 | efree(class_name); | ||
908 | |||
909 | /* | ||
910 | // object property | ||
911 | if (Twig_TemplateInterface::METHOD_CALL !== $type) { | ||
912 | if (isset($object->$item) || array_key_exists((string) $item, $object)) { | ||
913 | if ($isDefinedTest) { | ||
914 | return true; | ||
915 | } | ||
916 | |||
917 | if ($this->env->hasExtension('sandbox')) { | ||
918 | $this->env->getExtension('sandbox')->checkPropertyAllowed($object, $item); | ||
919 | } | ||
920 | |||
921 | return $object->$item; | ||
922 | } | ||
923 | } | ||
924 | */ | ||
925 | if (strcmp("method", type) != 0) { | ||
926 | zval *tmp_properties, *tmp_item; | ||
927 | |||
928 | tmp_properties = TWIG_GET_ARRAY_ELEMENT(tmp_class, "properties", strlen("properties") TSRMLS_CC); | ||
929 | tmp_item = TWIG_GET_ARRAY_ELEMENT(tmp_properties, item, item_len TSRMLS_CC); | ||
930 | |||
931 | if (tmp_item || TWIG_HAS_PROPERTY(object, zitem TSRMLS_CC) || TWIG_HAS_DYNAMIC_PROPERTY(object, item, item_len TSRMLS_CC)) { | ||
932 | if (isDefinedTest) { | ||
933 | RETURN_TRUE; | ||
934 | } | ||
935 | if (TWIG_CALL_SB(TWIG_PROPERTY_CHAR(template, "env" TSRMLS_CC), "hasExtension", "sandbox" TSRMLS_CC)) { | ||
936 | TWIG_CALL_ZZ(TWIG_CALL_S(TWIG_PROPERTY_CHAR(template, "env" TSRMLS_CC), "getExtension", "sandbox" TSRMLS_CC), "checkPropertyAllowed", object, zitem TSRMLS_CC); | ||
937 | } | ||
938 | if (EG(exception)) { | ||
939 | return; | ||
940 | } | ||
941 | |||
942 | ret = TWIG_PROPERTY(object, zitem TSRMLS_CC); | ||
943 | RETURN_ZVAL(ret, 1, 0); | ||
944 | } | ||
945 | } | ||
946 | /* | ||
947 | // object method | ||
948 | if (!isset(self::$cache[$class]['methods'])) { | ||
949 | self::$cache[$class]['methods'] = array_change_key_case(array_flip(get_class_methods($object))); | ||
950 | } | ||
951 | |||
952 | $lcItem = strtolower($item); | ||
953 | if (isset(self::$cache[$class]['methods'][$lcItem])) { | ||
954 | $method = (string) $item; | ||
955 | } elseif (isset(self::$cache[$class]['methods']['get'.$lcItem])) { | ||
956 | $method = 'get'.$item; | ||
957 | } elseif (isset(self::$cache[$class]['methods']['is'.$lcItem])) { | ||
958 | $method = 'is'.$item; | ||
959 | } elseif (isset(self::$cache[$class]['methods']['__call'])) { | ||
960 | $method = (string) $item; | ||
961 | */ | ||
962 | { | ||
963 | char *lcItem = TWIG_STRTOLOWER(item, item_len); | ||
964 | int lcItem_length; | ||
965 | char *method = NULL; | ||
966 | char *tmp_method_name_get; | ||
967 | char *tmp_method_name_is; | ||
968 | zval *tmp_methods; | ||
969 | |||
970 | lcItem_length = strlen(lcItem); | ||
971 | tmp_method_name_get = emalloc(4 + lcItem_length); | ||
972 | tmp_method_name_is = emalloc(3 + lcItem_length); | ||
973 | |||
974 | sprintf(tmp_method_name_get, "get%s", lcItem); | ||
975 | sprintf(tmp_method_name_is, "is%s", lcItem); | ||
976 | |||
977 | tmp_methods = TWIG_GET_ARRAY_ELEMENT(tmp_class, "methods", strlen("methods") TSRMLS_CC); | ||
978 | |||
979 | if (TWIG_GET_ARRAY_ELEMENT(tmp_methods, lcItem, lcItem_length TSRMLS_CC)) { | ||
980 | method = item; | ||
981 | } else if (TWIG_GET_ARRAY_ELEMENT(tmp_methods, tmp_method_name_get, lcItem_length + 3 TSRMLS_CC)) { | ||
982 | method = tmp_method_name_get; | ||
983 | } else if (TWIG_GET_ARRAY_ELEMENT(tmp_methods, tmp_method_name_is, lcItem_length + 2 TSRMLS_CC)) { | ||
984 | method = tmp_method_name_is; | ||
985 | } else if (TWIG_GET_ARRAY_ELEMENT(tmp_methods, "__call", 6 TSRMLS_CC)) { | ||
986 | method = item; | ||
987 | /* | ||
988 | } else { | ||
989 | if ($isDefinedTest) { | ||
990 | return false; | ||
991 | } | ||
992 | |||
993 | if ($ignoreStrictCheck || !$this->env->isStrictVariables()) { | ||
994 | return null; | ||
995 | } | ||
996 | |||
997 | throw new Twig_Error_Runtime(sprintf('Method "%s" for object "%s" does not exist', $item, get_class($object)), -1, $this->getTemplateName()); | ||
998 | } | ||
999 | |||
1000 | if ($isDefinedTest) { | ||
1001 | return true; | ||
1002 | } | ||
1003 | */ | ||
1004 | } else { | ||
1005 | efree(tmp_method_name_get); | ||
1006 | efree(tmp_method_name_is); | ||
1007 | efree(lcItem); | ||
1008 | |||
1009 | if (isDefinedTest) { | ||
1010 | RETURN_FALSE; | ||
1011 | } | ||
1012 | if (ignoreStrictCheck || !TWIG_CALL_BOOLEAN(TWIG_PROPERTY_CHAR(template, "env" TSRMLS_CC), "isStrictVariables" TSRMLS_CC)) { | ||
1013 | return; | ||
1014 | } | ||
1015 | TWIG_RUNTIME_ERROR(template TSRMLS_CC, "Method \"%s\" for object \"%s\" does not exist", item, TWIG_GET_CLASS_NAME(object TSRMLS_CC)); | ||
1016 | return; | ||
1017 | } | ||
1018 | |||
1019 | if (isDefinedTest) { | ||
1020 | efree(tmp_method_name_get); | ||
1021 | efree(tmp_method_name_is); | ||
1022 | efree(lcItem); | ||
1023 | RETURN_TRUE; | ||
1024 | } | ||
1025 | /* | ||
1026 | if ($this->env->hasExtension('sandbox')) { | ||
1027 | $this->env->getExtension('sandbox')->checkMethodAllowed($object, $method); | ||
1028 | } | ||
1029 | */ | ||
1030 | if (TWIG_CALL_SB(TWIG_PROPERTY_CHAR(template, "env" TSRMLS_CC), "hasExtension", "sandbox" TSRMLS_CC)) { | ||
1031 | TWIG_CALL_ZZ(TWIG_CALL_S(TWIG_PROPERTY_CHAR(template, "env" TSRMLS_CC), "getExtension", "sandbox" TSRMLS_CC), "checkMethodAllowed", object, zitem TSRMLS_CC); | ||
1032 | } | ||
1033 | if (EG(exception)) { | ||
1034 | efree(tmp_method_name_get); | ||
1035 | efree(tmp_method_name_is); | ||
1036 | efree(lcItem); | ||
1037 | return; | ||
1038 | } | ||
1039 | /* | ||
1040 | $ret = call_user_func_array(array($object, $method), $arguments); | ||
1041 | */ | ||
1042 | ret = TWIG_CALL_USER_FUNC_ARRAY(object, method, arguments TSRMLS_CC); | ||
1043 | free_ret = 1; | ||
1044 | efree(tmp_method_name_get); | ||
1045 | efree(tmp_method_name_is); | ||
1046 | efree(lcItem); | ||
1047 | } | ||
1048 | /* | ||
1049 | // useful when calling a template method from a template | ||
1050 | // this is not supported but unfortunately heavily used in the Symfony profiler | ||
1051 | if ($object instanceof Twig_TemplateInterface) { | ||
1052 | return $ret === '' ? '' : new Twig_Markup($ret, $this->env->getCharset()); | ||
1053 | } | ||
1054 | |||
1055 | return $ret; | ||
1056 | */ | ||
1057 | // ret can be null, if e.g. the called method throws an exception | ||
1058 | if (ret) { | ||
1059 | if (TWIG_INSTANCE_OF_USERLAND(object, "Twig_TemplateInterface" TSRMLS_CC)) { | ||
1060 | if (Z_STRLEN_P(ret) != 0) { | ||
1061 | zval *charset = TWIG_CALL_USER_FUNC_ARRAY(TWIG_PROPERTY_CHAR(template, "env" TSRMLS_CC), "getCharset", NULL TSRMLS_CC); | ||
1062 | TWIG_NEW(return_value, "Twig_Markup", ret, charset TSRMLS_CC); | ||
1063 | zval_ptr_dtor(&charset); | ||
1064 | if (ret) { | ||
1065 | zval_ptr_dtor(&ret); | ||
1066 | } | ||
1067 | return; | ||
1068 | } | ||
1069 | } | ||
1070 | |||
1071 | RETVAL_ZVAL(ret, 1, 0); | ||
1072 | if (free_ret) { | ||
1073 | zval_ptr_dtor(&ret); | ||
1074 | } | ||
1075 | } | ||
1076 | } | ||
diff --git a/vendor/twig/twig/lib/Twig/Autoloader.php b/vendor/twig/twig/lib/Twig/Autoloader.php new file mode 100644 index 00000000..7007d315 --- /dev/null +++ b/vendor/twig/twig/lib/Twig/Autoloader.php | |||
@@ -0,0 +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 Boolean $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(new self, 'autoload'), true, $prepend); | ||
28 | } else { | ||
29 | spl_autoload_register(array(new self, '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 | } | ||
diff --git a/vendor/twig/twig/lib/Twig/Compiler.php b/vendor/twig/twig/lib/Twig/Compiler.php new file mode 100644 index 00000000..99aecbcc --- /dev/null +++ b/vendor/twig/twig/lib/Twig/Compiler.php | |||
@@ -0,0 +1,267 @@ | |||
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 integer $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 | $i = 0; | ||
184 | foreach ($value as $key => $value) { | ||
185 | if ($i++) { | ||
186 | $this->raw(', '); | ||
187 | } | ||
188 | $this->repr($key); | ||
189 | $this->raw(' => '); | ||
190 | $this->repr($value); | ||
191 | } | ||
192 | $this->raw(')'); | ||
193 | } else { | ||
194 | $this->string($value); | ||
195 | } | ||
196 | |||
197 | return $this; | ||
198 | } | ||
199 | |||
200 | /** | ||
201 | * Adds debugging information. | ||
202 | * | ||
203 | * @param Twig_NodeInterface $node The related twig node | ||
204 | * | ||
205 | * @return Twig_Compiler The current compiler instance | ||
206 | */ | ||
207 | public function addDebugInfo(Twig_NodeInterface $node) | ||
208 | { | ||
209 | if ($node->getLine() != $this->lastLine) { | ||
210 | $this->write("// line {$node->getLine()}\n"); | ||
211 | |||
212 | // when mbstring.func_overload is set to 2 | ||
213 | // mb_substr_count() replaces substr_count() | ||
214 | // but they have different signatures! | ||
215 | if (((int) ini_get('mbstring.func_overload')) & 2) { | ||
216 | // this is much slower than the "right" version | ||
217 | $this->sourceLine += mb_substr_count(mb_substr($this->source, $this->sourceOffset), "\n"); | ||
218 | } else { | ||
219 | $this->sourceLine += substr_count($this->source, "\n", $this->sourceOffset); | ||
220 | } | ||
221 | $this->sourceOffset = strlen($this->source); | ||
222 | $this->debugInfo[$this->sourceLine] = $node->getLine(); | ||
223 | |||
224 | $this->lastLine = $node->getLine(); | ||
225 | } | ||
226 | |||
227 | return $this; | ||
228 | } | ||
229 | |||
230 | public function getDebugInfo() | ||
231 | { | ||
232 | return $this->debugInfo; | ||
233 | } | ||
234 | |||
235 | /** | ||
236 | * Indents the generated code. | ||
237 | * | ||
238 | * @param integer $step The number of indentation to add | ||
239 | * | ||
240 | * @return Twig_Compiler The current compiler instance | ||
241 | */ | ||
242 | public function indent($step = 1) | ||
243 | { | ||
244 | $this->indentation += $step; | ||
245 | |||
246 | return $this; | ||
247 | } | ||
248 | |||
249 | /** | ||
250 | * Outdents the generated code. | ||
251 | * | ||
252 | * @param integer $step The number of indentation to remove | ||
253 | * | ||
254 | * @return Twig_Compiler The current compiler instance | ||
255 | */ | ||
256 | public function outdent($step = 1) | ||
257 | { | ||
258 | // can't outdent by more steps than the current indentation level | ||
259 | if ($this->indentation < $step) { | ||
260 | throw new LogicException('Unable to call outdent() as the indentation would become negative'); | ||
261 | } | ||
262 | |||
263 | $this->indentation -= $step; | ||
264 | |||
265 | return $this; | ||
266 | } | ||
267 | } | ||
diff --git a/vendor/twig/twig/lib/Twig/CompilerInterface.php b/vendor/twig/twig/lib/Twig/CompilerInterface.php new file mode 100644 index 00000000..e293ec91 --- /dev/null +++ b/vendor/twig/twig/lib/Twig/CompilerInterface.php | |||
@@ -0,0 +1,35 @@ | |||
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 | * @deprecated since 1.12 (to be removed in 2.0) | ||
17 | */ | ||
18 | interface Twig_CompilerInterface | ||
19 | { | ||
20 | /** | ||
21 | * Compiles a node. | ||
22 | * | ||
23 | * @param Twig_NodeInterface $node The node to compile | ||
24 | * | ||
25 | * @return Twig_CompilerInterface The current compiler instance | ||
26 | */ | ||
27 | public function compile(Twig_NodeInterface $node); | ||
28 | |||
29 | /** | ||
30 | * Gets the current PHP code after compilation. | ||
31 | * | ||
32 | * @return string The PHP code | ||
33 | */ | ||
34 | public function getSource(); | ||
35 | } | ||
diff --git a/vendor/twig/twig/lib/Twig/Environment.php b/vendor/twig/twig/lib/Twig/Environment.php new file mode 100644 index 00000000..6d4c5c57 --- /dev/null +++ b/vendor/twig/twig/lib/Twig/Environment.php | |||
@@ -0,0 +1,1224 @@ | |||
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.13.2'; | ||
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 is the original source changed. | ||
65 | * If you don't provide the auto_reload option, it will be | ||
66 | * determined automatically base 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 Boolean 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 Boolean 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 Boolean 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 The cache file name | ||
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 integer $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.md5($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 | public function render($name, array $context = array()) | ||
287 | { | ||
288 | return $this->loadTemplate($name)->render($context); | ||
289 | } | ||
290 | |||
291 | /** | ||
292 | * Displays a template. | ||
293 | * | ||
294 | * @param string $name The template name | ||
295 | * @param array $context An array of parameters to pass to the template | ||
296 | */ | ||
297 | public function display($name, array $context = array()) | ||
298 | { | ||
299 | $this->loadTemplate($name)->display($context); | ||
300 | } | ||
301 | |||
302 | /** | ||
303 | * Loads a template by name. | ||
304 | * | ||
305 | * @param string $name The template name | ||
306 | * @param integer $index The index if it is an embedded template | ||
307 | * | ||
308 | * @return Twig_TemplateInterface A template instance representing the given template name | ||
309 | */ | ||
310 | public function loadTemplate($name, $index = null) | ||
311 | { | ||
312 | $cls = $this->getTemplateClass($name, $index); | ||
313 | |||
314 | if (isset($this->loadedTemplates[$cls])) { | ||
315 | return $this->loadedTemplates[$cls]; | ||
316 | } | ||
317 | |||
318 | if (!class_exists($cls, false)) { | ||
319 | if (false === $cache = $this->getCacheFilename($name)) { | ||
320 | eval('?>'.$this->compileSource($this->getLoader()->getSource($name), $name)); | ||
321 | } else { | ||
322 | if (!is_file($cache) || ($this->isAutoReload() && !$this->isTemplateFresh($name, filemtime($cache)))) { | ||
323 | $this->writeCacheFile($cache, $this->compileSource($this->getLoader()->getSource($name), $name)); | ||
324 | } | ||
325 | |||
326 | require_once $cache; | ||
327 | } | ||
328 | } | ||
329 | |||
330 | if (!$this->runtimeInitialized) { | ||
331 | $this->initRuntime(); | ||
332 | } | ||
333 | |||
334 | return $this->loadedTemplates[$cls] = new $cls($this); | ||
335 | } | ||
336 | |||
337 | /** | ||
338 | * Returns true if the template is still fresh. | ||
339 | * | ||
340 | * Besides checking the loader for freshness information, | ||
341 | * this method also checks if the enabled extensions have | ||
342 | * not changed. | ||
343 | * | ||
344 | * @param string $name The template name | ||
345 | * @param timestamp $time The last modification time of the cached template | ||
346 | * | ||
347 | * @return Boolean true if the template is fresh, false otherwise | ||
348 | */ | ||
349 | public function isTemplateFresh($name, $time) | ||
350 | { | ||
351 | foreach ($this->extensions as $extension) { | ||
352 | $r = new ReflectionObject($extension); | ||
353 | if (filemtime($r->getFileName()) > $time) { | ||
354 | return false; | ||
355 | } | ||
356 | } | ||
357 | |||
358 | return $this->getLoader()->isFresh($name, $time); | ||
359 | } | ||
360 | |||
361 | public function resolveTemplate($names) | ||
362 | { | ||
363 | if (!is_array($names)) { | ||
364 | $names = array($names); | ||
365 | } | ||
366 | |||
367 | foreach ($names as $name) { | ||
368 | if ($name instanceof Twig_Template) { | ||
369 | return $name; | ||
370 | } | ||
371 | |||
372 | try { | ||
373 | return $this->loadTemplate($name); | ||
374 | } catch (Twig_Error_Loader $e) { | ||
375 | } | ||
376 | } | ||
377 | |||
378 | if (1 === count($names)) { | ||
379 | throw $e; | ||
380 | } | ||
381 | |||
382 | throw new Twig_Error_Loader(sprintf('Unable to find one of the following templates: "%s".', implode('", "', $names))); | ||
383 | } | ||
384 | |||
385 | /** | ||
386 | * Clears the internal template cache. | ||
387 | */ | ||
388 | public function clearTemplateCache() | ||
389 | { | ||
390 | $this->loadedTemplates = array(); | ||
391 | } | ||
392 | |||
393 | /** | ||
394 | * Clears the template cache files on the filesystem. | ||
395 | */ | ||
396 | public function clearCacheFiles() | ||
397 | { | ||
398 | if (false === $this->cache) { | ||
399 | return; | ||
400 | } | ||
401 | |||
402 | foreach (new RecursiveIteratorIterator(new RecursiveDirectoryIterator($this->cache), RecursiveIteratorIterator::LEAVES_ONLY) as $file) { | ||
403 | if ($file->isFile()) { | ||
404 | @unlink($file->getPathname()); | ||
405 | } | ||
406 | } | ||
407 | } | ||
408 | |||
409 | /** | ||
410 | * Gets the Lexer instance. | ||
411 | * | ||
412 | * @return Twig_LexerInterface A Twig_LexerInterface instance | ||
413 | */ | ||
414 | public function getLexer() | ||
415 | { | ||
416 | if (null === $this->lexer) { | ||
417 | $this->lexer = new Twig_Lexer($this); | ||
418 | } | ||
419 | |||
420 | return $this->lexer; | ||
421 | } | ||
422 | |||
423 | /** | ||
424 | * Sets the Lexer instance. | ||
425 | * | ||
426 | * @param Twig_LexerInterface A Twig_LexerInterface instance | ||
427 | */ | ||
428 | public function setLexer(Twig_LexerInterface $lexer) | ||
429 | { | ||
430 | $this->lexer = $lexer; | ||
431 | } | ||
432 | |||
433 | /** | ||
434 | * Tokenizes a source code. | ||
435 | * | ||
436 | * @param string $source The template source code | ||
437 | * @param string $name The template name | ||
438 | * | ||
439 | * @return Twig_TokenStream A Twig_TokenStream instance | ||
440 | */ | ||
441 | public function tokenize($source, $name = null) | ||
442 | { | ||
443 | return $this->getLexer()->tokenize($source, $name); | ||
444 | } | ||
445 | |||
446 | /** | ||
447 | * Gets the Parser instance. | ||
448 | * | ||
449 | * @return Twig_ParserInterface A Twig_ParserInterface instance | ||
450 | */ | ||
451 | public function getParser() | ||
452 | { | ||
453 | if (null === $this->parser) { | ||
454 | $this->parser = new Twig_Parser($this); | ||
455 | } | ||
456 | |||
457 | return $this->parser; | ||
458 | } | ||
459 | |||
460 | /** | ||
461 | * Sets the Parser instance. | ||
462 | * | ||
463 | * @param Twig_ParserInterface A Twig_ParserInterface instance | ||
464 | */ | ||
465 | public function setParser(Twig_ParserInterface $parser) | ||
466 | { | ||
467 | $this->parser = $parser; | ||
468 | } | ||
469 | |||
470 | /** | ||
471 | * Parses a token stream. | ||
472 | * | ||
473 | * @param Twig_TokenStream $tokens A Twig_TokenStream instance | ||
474 | * | ||
475 | * @return Twig_Node_Module A Node tree | ||
476 | */ | ||
477 | public function parse(Twig_TokenStream $tokens) | ||
478 | { | ||
479 | return $this->getParser()->parse($tokens); | ||
480 | } | ||
481 | |||
482 | /** | ||
483 | * Gets the Compiler instance. | ||
484 | * | ||
485 | * @return Twig_CompilerInterface A Twig_CompilerInterface instance | ||
486 | */ | ||
487 | public function getCompiler() | ||
488 | { | ||
489 | if (null === $this->compiler) { | ||
490 | $this->compiler = new Twig_Compiler($this); | ||
491 | } | ||
492 | |||
493 | return $this->compiler; | ||
494 | } | ||
495 | |||
496 | /** | ||
497 | * Sets the Compiler instance. | ||
498 | * | ||
499 | * @param Twig_CompilerInterface $compiler A Twig_CompilerInterface instance | ||
500 | */ | ||
501 | public function setCompiler(Twig_CompilerInterface $compiler) | ||
502 | { | ||
503 | $this->compiler = $compiler; | ||
504 | } | ||
505 | |||
506 | /** | ||
507 | * Compiles a Node. | ||
508 | * | ||
509 | * @param Twig_NodeInterface $node A Twig_NodeInterface instance | ||
510 | * | ||
511 | * @return string The compiled PHP source code | ||
512 | */ | ||
513 | public function compile(Twig_NodeInterface $node) | ||
514 | { | ||
515 | return $this->getCompiler()->compile($node)->getSource(); | ||
516 | } | ||
517 | |||
518 | /** | ||
519 | * Compiles a template source code. | ||
520 | * | ||
521 | * @param string $source The template source code | ||
522 | * @param string $name The template name | ||
523 | * | ||
524 | * @return string The compiled PHP source code | ||
525 | */ | ||
526 | public function compileSource($source, $name = null) | ||
527 | { | ||
528 | try { | ||
529 | return $this->compile($this->parse($this->tokenize($source, $name))); | ||
530 | } catch (Twig_Error $e) { | ||
531 | $e->setTemplateFile($name); | ||
532 | throw $e; | ||
533 | } catch (Exception $e) { | ||
534 | throw new Twig_Error_Runtime(sprintf('An exception has been thrown during the compilation of a template ("%s").', $e->getMessage()), -1, $name, $e); | ||
535 | } | ||
536 | } | ||
537 | |||
538 | /** | ||
539 | * Sets the Loader instance. | ||
540 | * | ||
541 | * @param Twig_LoaderInterface $loader A Twig_LoaderInterface instance | ||
542 | */ | ||
543 | public function setLoader(Twig_LoaderInterface $loader) | ||
544 | { | ||
545 | $this->loader = $loader; | ||
546 | } | ||
547 | |||
548 | /** | ||
549 | * Gets the Loader instance. | ||
550 | * | ||
551 | * @return Twig_LoaderInterface A Twig_LoaderInterface instance | ||
552 | */ | ||
553 | public function getLoader() | ||
554 | { | ||
555 | if (null === $this->loader) { | ||
556 | throw new LogicException('You must set a loader first.'); | ||
557 | } | ||
558 | |||
559 | return $this->loader; | ||
560 | } | ||
561 | |||
562 | /** | ||
563 | * Sets the default template charset. | ||
564 | * | ||
565 | * @param string $charset The default charset | ||
566 | */ | ||
567 | public function setCharset($charset) | ||
568 | { | ||
569 | $this->charset = strtoupper($charset); | ||
570 | } | ||
571 | |||
572 | /** | ||
573 | * Gets the default template charset. | ||
574 | * | ||
575 | * @return string The default charset | ||
576 | */ | ||
577 | public function getCharset() | ||
578 | { | ||
579 | return $this->charset; | ||
580 | } | ||
581 | |||
582 | /** | ||
583 | * Initializes the runtime environment. | ||
584 | */ | ||
585 | public function initRuntime() | ||
586 | { | ||
587 | $this->runtimeInitialized = true; | ||
588 | |||
589 | foreach ($this->getExtensions() as $extension) { | ||
590 | $extension->initRuntime($this); | ||
591 | } | ||
592 | } | ||
593 | |||
594 | /** | ||
595 | * Returns true if the given extension is registered. | ||
596 | * | ||
597 | * @param string $name The extension name | ||
598 | * | ||
599 | * @return Boolean Whether the extension is registered or not | ||
600 | */ | ||
601 | public function hasExtension($name) | ||
602 | { | ||
603 | return isset($this->extensions[$name]); | ||
604 | } | ||
605 | |||
606 | /** | ||
607 | * Gets an extension by name. | ||
608 | * | ||
609 | * @param string $name The extension name | ||
610 | * | ||
611 | * @return Twig_ExtensionInterface A Twig_ExtensionInterface instance | ||
612 | */ | ||
613 | public function getExtension($name) | ||
614 | { | ||
615 | if (!isset($this->extensions[$name])) { | ||
616 | throw new Twig_Error_Runtime(sprintf('The "%s" extension is not enabled.', $name)); | ||
617 | } | ||
618 | |||
619 | return $this->extensions[$name]; | ||
620 | } | ||
621 | |||
622 | /** | ||
623 | * Registers an extension. | ||
624 | * | ||
625 | * @param Twig_ExtensionInterface $extension A Twig_ExtensionInterface instance | ||
626 | */ | ||
627 | public function addExtension(Twig_ExtensionInterface $extension) | ||
628 | { | ||
629 | if ($this->extensionInitialized) { | ||
630 | throw new LogicException(sprintf('Unable to register extension "%s" as extensions have already been initialized.', $extension->getName())); | ||
631 | } | ||
632 | |||
633 | $this->extensions[$extension->getName()] = $extension; | ||
634 | } | ||
635 | |||
636 | /** | ||
637 | * Removes an extension by name. | ||
638 | * | ||
639 | * This method is deprecated and you should not use it. | ||
640 | * | ||
641 | * @param string $name The extension name | ||
642 | * | ||
643 | * @deprecated since 1.12 (to be removed in 2.0) | ||
644 | */ | ||
645 | public function removeExtension($name) | ||
646 | { | ||
647 | if ($this->extensionInitialized) { | ||
648 | throw new LogicException(sprintf('Unable to remove extension "%s" as extensions have already been initialized.', $name)); | ||
649 | } | ||
650 | |||
651 | unset($this->extensions[$name]); | ||
652 | } | ||
653 | |||
654 | /** | ||
655 | * Registers an array of extensions. | ||
656 | * | ||
657 | * @param array $extensions An array of extensions | ||
658 | */ | ||
659 | public function setExtensions(array $extensions) | ||
660 | { | ||
661 | foreach ($extensions as $extension) { | ||
662 | $this->addExtension($extension); | ||
663 | } | ||
664 | } | ||
665 | |||
666 | /** | ||
667 | * Returns all registered extensions. | ||
668 | * | ||
669 | * @return array An array of extensions | ||
670 | */ | ||
671 | public function getExtensions() | ||
672 | { | ||
673 | return $this->extensions; | ||
674 | } | ||
675 | |||
676 | /** | ||
677 | * Registers a Token Parser. | ||
678 | * | ||
679 | * @param Twig_TokenParserInterface $parser A Twig_TokenParserInterface instance | ||
680 | */ | ||
681 | public function addTokenParser(Twig_TokenParserInterface $parser) | ||
682 | { | ||
683 | if ($this->extensionInitialized) { | ||
684 | throw new LogicException('Unable to add a token parser as extensions have already been initialized.'); | ||
685 | } | ||
686 | |||
687 | $this->staging->addTokenParser($parser); | ||
688 | } | ||
689 | |||
690 | /** | ||
691 | * Gets the registered Token Parsers. | ||
692 | * | ||
693 | * @return Twig_TokenParserBrokerInterface A broker containing token parsers | ||
694 | */ | ||
695 | public function getTokenParsers() | ||
696 | { | ||
697 | if (!$this->extensionInitialized) { | ||
698 | $this->initExtensions(); | ||
699 | } | ||
700 | |||
701 | return $this->parsers; | ||
702 | } | ||
703 | |||
704 | /** | ||
705 | * Gets registered tags. | ||
706 | * | ||
707 | * Be warned that this method cannot return tags defined by Twig_TokenParserBrokerInterface classes. | ||
708 | * | ||
709 | * @return Twig_TokenParserInterface[] An array of Twig_TokenParserInterface instances | ||
710 | */ | ||
711 | public function getTags() | ||
712 | { | ||
713 | $tags = array(); | ||
714 | foreach ($this->getTokenParsers()->getParsers() as $parser) { | ||
715 | if ($parser instanceof Twig_TokenParserInterface) { | ||
716 | $tags[$parser->getTag()] = $parser; | ||
717 | } | ||
718 | } | ||
719 | |||
720 | return $tags; | ||
721 | } | ||
722 | |||
723 | /** | ||
724 | * Registers a Node Visitor. | ||
725 | * | ||
726 | * @param Twig_NodeVisitorInterface $visitor A Twig_NodeVisitorInterface instance | ||
727 | */ | ||
728 | public function addNodeVisitor(Twig_NodeVisitorInterface $visitor) | ||
729 | { | ||
730 | if ($this->extensionInitialized) { | ||
731 | throw new LogicException('Unable to add a node visitor as extensions have already been initialized.'); | ||
732 | } | ||
733 | |||
734 | $this->staging->addNodeVisitor($visitor); | ||
735 | } | ||
736 | |||
737 | /** | ||
738 | * Gets the registered Node Visitors. | ||
739 | * | ||
740 | * @return Twig_NodeVisitorInterface[] An array of Twig_NodeVisitorInterface instances | ||
741 | */ | ||
742 | public function getNodeVisitors() | ||
743 | { | ||
744 | if (!$this->extensionInitialized) { | ||
745 | $this->initExtensions(); | ||
746 | } | ||
747 | |||
748 | return $this->visitors; | ||
749 | } | ||
750 | |||
751 | /** | ||
752 | * Registers a Filter. | ||
753 | * | ||
754 | * @param string|Twig_SimpleFilter $name The filter name or a Twig_SimpleFilter instance | ||
755 | * @param Twig_FilterInterface|Twig_SimpleFilter $filter A Twig_FilterInterface instance or a Twig_SimpleFilter instance | ||
756 | */ | ||
757 | public function addFilter($name, $filter = null) | ||
758 | { | ||
759 | if (!$name instanceof Twig_SimpleFilter && !($filter instanceof Twig_SimpleFilter || $filter instanceof Twig_FilterInterface)) { | ||
760 | throw new LogicException('A filter must be an instance of Twig_FilterInterface or Twig_SimpleFilter'); | ||
761 | } | ||
762 | |||
763 | if ($name instanceof Twig_SimpleFilter) { | ||
764 | $filter = $name; | ||
765 | $name = $filter->getName(); | ||
766 | } | ||
767 | |||
768 | if ($this->extensionInitialized) { | ||
769 | throw new LogicException(sprintf('Unable to add filter "%s" as extensions have already been initialized.', $name)); | ||
770 | } | ||
771 | |||
772 | $this->staging->addFilter($name, $filter); | ||
773 | } | ||
774 | |||
775 | /** | ||
776 | * Get a filter by name. | ||
777 | * | ||
778 | * Subclasses may override this method and load filters differently; | ||
779 | * so no list of filters is available. | ||
780 | * | ||
781 | * @param string $name The filter name | ||
782 | * | ||
783 | * @return Twig_Filter|false A Twig_Filter instance or false if the filter does not exist | ||
784 | */ | ||
785 | public function getFilter($name) | ||
786 | { | ||
787 | if (!$this->extensionInitialized) { | ||
788 | $this->initExtensions(); | ||
789 | } | ||
790 | |||
791 | if (isset($this->filters[$name])) { | ||
792 | return $this->filters[$name]; | ||
793 | } | ||
794 | |||
795 | foreach ($this->filters as $pattern => $filter) { | ||
796 | $pattern = str_replace('\\*', '(.*?)', preg_quote($pattern, '#'), $count); | ||
797 | |||
798 | if ($count) { | ||
799 | if (preg_match('#^'.$pattern.'$#', $name, $matches)) { | ||
800 | array_shift($matches); | ||
801 | $filter->setArguments($matches); | ||
802 | |||
803 | return $filter; | ||
804 | } | ||
805 | } | ||
806 | } | ||
807 | |||
808 | foreach ($this->filterCallbacks as $callback) { | ||
809 | if (false !== $filter = call_user_func($callback, $name)) { | ||
810 | return $filter; | ||
811 | } | ||
812 | } | ||
813 | |||
814 | return false; | ||
815 | } | ||
816 | |||
817 | public function registerUndefinedFilterCallback($callable) | ||
818 | { | ||
819 | $this->filterCallbacks[] = $callable; | ||
820 | } | ||
821 | |||
822 | /** | ||
823 | * Gets the registered Filters. | ||
824 | * | ||
825 | * Be warned that this method cannot return filters defined with registerUndefinedFunctionCallback. | ||
826 | * | ||
827 | * @return Twig_FilterInterface[] An array of Twig_FilterInterface instances | ||
828 | * | ||
829 | * @see registerUndefinedFilterCallback | ||
830 | */ | ||
831 | public function getFilters() | ||
832 | { | ||
833 | if (!$this->extensionInitialized) { | ||
834 | $this->initExtensions(); | ||
835 | } | ||
836 | |||
837 | return $this->filters; | ||
838 | } | ||
839 | |||
840 | /** | ||
841 | * Registers a Test. | ||
842 | * | ||
843 | * @param string|Twig_SimpleTest $name The test name or a Twig_SimpleTest instance | ||
844 | * @param Twig_TestInterface|Twig_SimpleTest $test A Twig_TestInterface instance or a Twig_SimpleTest instance | ||
845 | */ | ||
846 | public function addTest($name, $test = null) | ||
847 | { | ||
848 | if (!$name instanceof Twig_SimpleTest && !($test instanceof Twig_SimpleTest || $test instanceof Twig_TestInterface)) { | ||
849 | throw new LogicException('A test must be an instance of Twig_TestInterface or Twig_SimpleTest'); | ||
850 | } | ||
851 | |||
852 | if ($name instanceof Twig_SimpleTest) { | ||
853 | $test = $name; | ||
854 | $name = $test->getName(); | ||
855 | } | ||
856 | |||
857 | if ($this->extensionInitialized) { | ||
858 | throw new LogicException(sprintf('Unable to add test "%s" as extensions have already been initialized.', $name)); | ||
859 | } | ||
860 | |||
861 | $this->staging->addTest($name, $test); | ||
862 | } | ||
863 | |||
864 | /** | ||
865 | * Gets the registered Tests. | ||
866 | * | ||
867 | * @return Twig_TestInterface[] An array of Twig_TestInterface instances | ||
868 | */ | ||
869 | public function getTests() | ||
870 | { | ||
871 | if (!$this->extensionInitialized) { | ||
872 | $this->initExtensions(); | ||
873 | } | ||
874 | |||
875 | return $this->tests; | ||
876 | } | ||
877 | |||
878 | /** | ||
879 | * Gets a test by name. | ||
880 | * | ||
881 | * @param string $name The test name | ||
882 | * | ||
883 | * @return Twig_Test|false A Twig_Test instance or false if the test does not exist | ||
884 | */ | ||
885 | public function getTest($name) | ||
886 | { | ||
887 | if (!$this->extensionInitialized) { | ||
888 | $this->initExtensions(); | ||
889 | } | ||
890 | |||
891 | if (isset($this->tests[$name])) { | ||
892 | return $this->tests[$name]; | ||
893 | } | ||
894 | |||
895 | return false; | ||
896 | } | ||
897 | |||
898 | /** | ||
899 | * Registers a Function. | ||
900 | * | ||
901 | * @param string|Twig_SimpleFunction $name The function name or a Twig_SimpleFunction instance | ||
902 | * @param Twig_FunctionInterface|Twig_SimpleFunction $function A Twig_FunctionInterface instance or a Twig_SimpleFunction instance | ||
903 | */ | ||
904 | public function addFunction($name, $function = null) | ||
905 | { | ||
906 | if (!$name instanceof Twig_SimpleFunction && !($function instanceof Twig_SimpleFunction || $function instanceof Twig_FunctionInterface)) { | ||
907 | throw new LogicException('A function must be an instance of Twig_FunctionInterface or Twig_SimpleFunction'); | ||
908 | } | ||
909 | |||
910 | if ($name instanceof Twig_SimpleFunction) { | ||
911 | $function = $name; | ||
912 | $name = $function->getName(); | ||
913 | } | ||
914 | |||
915 | if ($this->extensionInitialized) { | ||
916 | throw new LogicException(sprintf('Unable to add function "%s" as extensions have already been initialized.', $name)); | ||
917 | } | ||
918 | |||
919 | $this->staging->addFunction($name, $function); | ||
920 | } | ||
921 | |||
922 | /** | ||
923 | * Get a function by name. | ||
924 | * | ||
925 | * Subclasses may override this method and load functions differently; | ||
926 | * so no list of functions is available. | ||
927 | * | ||
928 | * @param string $name function name | ||
929 | * | ||
930 | * @return Twig_Function|false A Twig_Function instance or false if the function does not exist | ||
931 | */ | ||
932 | public function getFunction($name) | ||
933 | { | ||
934 | if (!$this->extensionInitialized) { | ||
935 | $this->initExtensions(); | ||
936 | } | ||
937 | |||
938 | if (isset($this->functions[$name])) { | ||
939 | return $this->functions[$name]; | ||
940 | } | ||
941 | |||
942 | foreach ($this->functions as $pattern => $function) { | ||
943 | $pattern = str_replace('\\*', '(.*?)', preg_quote($pattern, '#'), $count); | ||
944 | |||
945 | if ($count) { | ||
946 | if (preg_match('#^'.$pattern.'$#', $name, $matches)) { | ||
947 | array_shift($matches); | ||
948 | $function->setArguments($matches); | ||
949 | |||
950 | return $function; | ||
951 | } | ||
952 | } | ||
953 | } | ||
954 | |||
955 | foreach ($this->functionCallbacks as $callback) { | ||
956 | if (false !== $function = call_user_func($callback, $name)) { | ||
957 | return $function; | ||
958 | } | ||
959 | } | ||
960 | |||
961 | return false; | ||
962 | } | ||
963 | |||
964 | public function registerUndefinedFunctionCallback($callable) | ||
965 | { | ||
966 | $this->functionCallbacks[] = $callable; | ||
967 | } | ||
968 | |||
969 | /** | ||
970 | * Gets registered functions. | ||
971 | * | ||
972 | * Be warned that this method cannot return functions defined with registerUndefinedFunctionCallback. | ||
973 | * | ||
974 | * @return Twig_FunctionInterface[] An array of Twig_FunctionInterface instances | ||
975 | * | ||
976 | * @see registerUndefinedFunctionCallback | ||
977 | */ | ||
978 | public function getFunctions() | ||
979 | { | ||
980 | if (!$this->extensionInitialized) { | ||
981 | $this->initExtensions(); | ||
982 | } | ||
983 | |||
984 | return $this->functions; | ||
985 | } | ||
986 | |||
987 | /** | ||
988 | * Registers a Global. | ||
989 | * | ||
990 | * New globals can be added before compiling or rendering a template; | ||
991 | * but after, you can only update existing globals. | ||
992 | * | ||
993 | * @param string $name The global name | ||
994 | * @param mixed $value The global value | ||
995 | */ | ||
996 | public function addGlobal($name, $value) | ||
997 | { | ||
998 | if ($this->extensionInitialized || $this->runtimeInitialized) { | ||
999 | if (null === $this->globals) { | ||
1000 | $this->globals = $this->initGlobals(); | ||
1001 | } | ||
1002 | |||
1003 | /* This condition must be uncommented in Twig 2.0 | ||
1004 | if (!array_key_exists($name, $this->globals)) { | ||
1005 | throw new LogicException(sprintf('Unable to add global "%s" as the runtime or the extensions have already been initialized.', $name)); | ||
1006 | } | ||
1007 | */ | ||
1008 | } | ||
1009 | |||
1010 | if ($this->extensionInitialized || $this->runtimeInitialized) { | ||
1011 | // update the value | ||
1012 | $this->globals[$name] = $value; | ||
1013 | } else { | ||
1014 | $this->staging->addGlobal($name, $value); | ||
1015 | } | ||
1016 | } | ||
1017 | |||
1018 | /** | ||
1019 | * Gets the registered Globals. | ||
1020 | * | ||
1021 | * @return array An array of globals | ||
1022 | */ | ||
1023 | public function getGlobals() | ||
1024 | { | ||
1025 | if (!$this->runtimeInitialized && !$this->extensionInitialized) { | ||
1026 | return $this->initGlobals(); | ||
1027 | } | ||
1028 | |||
1029 | if (null === $this->globals) { | ||
1030 | $this->globals = $this->initGlobals(); | ||
1031 | } | ||
1032 | |||
1033 | return $this->globals; | ||
1034 | } | ||
1035 | |||
1036 | /** | ||
1037 | * Merges a context with the defined globals. | ||
1038 | * | ||
1039 | * @param array $context An array representing the context | ||
1040 | * | ||
1041 | * @return array The context merged with the globals | ||
1042 | */ | ||
1043 | public function mergeGlobals(array $context) | ||
1044 | { | ||
1045 | // we don't use array_merge as the context being generally | ||
1046 | // bigger than globals, this code is faster. | ||
1047 | foreach ($this->getGlobals() as $key => $value) { | ||
1048 | if (!array_key_exists($key, $context)) { | ||
1049 | $context[$key] = $value; | ||
1050 | } | ||
1051 | } | ||
1052 | |||
1053 | return $context; | ||
1054 | } | ||
1055 | |||
1056 | /** | ||
1057 | * Gets the registered unary Operators. | ||
1058 | * | ||
1059 | * @return array An array of unary operators | ||
1060 | */ | ||
1061 | public function getUnaryOperators() | ||
1062 | { | ||
1063 | if (!$this->extensionInitialized) { | ||
1064 | $this->initExtensions(); | ||
1065 | } | ||
1066 | |||
1067 | return $this->unaryOperators; | ||
1068 | } | ||
1069 | |||
1070 | /** | ||
1071 | * Gets the registered binary Operators. | ||
1072 | * | ||
1073 | * @return array An array of binary operators | ||
1074 | */ | ||
1075 | public function getBinaryOperators() | ||
1076 | { | ||
1077 | if (!$this->extensionInitialized) { | ||
1078 | $this->initExtensions(); | ||
1079 | } | ||
1080 | |||
1081 | return $this->binaryOperators; | ||
1082 | } | ||
1083 | |||
1084 | public function computeAlternatives($name, $items) | ||
1085 | { | ||
1086 | $alternatives = array(); | ||
1087 | foreach ($items as $item) { | ||
1088 | $lev = levenshtein($name, $item); | ||
1089 | if ($lev <= strlen($name) / 3 || false !== strpos($item, $name)) { | ||
1090 | $alternatives[$item] = $lev; | ||
1091 | } | ||
1092 | } | ||
1093 | asort($alternatives); | ||
1094 | |||
1095 | return array_keys($alternatives); | ||
1096 | } | ||
1097 | |||
1098 | protected function initGlobals() | ||
1099 | { | ||
1100 | $globals = array(); | ||
1101 | foreach ($this->extensions as $extension) { | ||
1102 | $extGlob = $extension->getGlobals(); | ||
1103 | if (!is_array($extGlob)) { | ||
1104 | throw new UnexpectedValueException(sprintf('"%s::getGlobals()" must return an array of globals.', get_class($extension))); | ||
1105 | } | ||
1106 | |||
1107 | $globals[] = $extGlob; | ||
1108 | } | ||
1109 | |||
1110 | $globals[] = $this->staging->getGlobals(); | ||
1111 | |||
1112 | return call_user_func_array('array_merge', $globals); | ||
1113 | } | ||
1114 | |||
1115 | protected function initExtensions() | ||
1116 | { | ||
1117 | if ($this->extensionInitialized) { | ||
1118 | return; | ||
1119 | } | ||
1120 | |||
1121 | $this->extensionInitialized = true; | ||
1122 | $this->parsers = new Twig_TokenParserBroker(); | ||
1123 | $this->filters = array(); | ||
1124 | $this->functions = array(); | ||
1125 | $this->tests = array(); | ||
1126 | $this->visitors = array(); | ||
1127 | $this->unaryOperators = array(); | ||
1128 | $this->binaryOperators = array(); | ||
1129 | |||
1130 | foreach ($this->extensions as $extension) { | ||
1131 | $this->initExtension($extension); | ||
1132 | } | ||
1133 | $this->initExtension($this->staging); | ||
1134 | } | ||
1135 | |||
1136 | protected function initExtension(Twig_ExtensionInterface $extension) | ||
1137 | { | ||
1138 | // filters | ||
1139 | foreach ($extension->getFilters() as $name => $filter) { | ||
1140 | if ($name instanceof Twig_SimpleFilter) { | ||
1141 | $filter = $name; | ||
1142 | $name = $filter->getName(); | ||
1143 | } elseif ($filter instanceof Twig_SimpleFilter) { | ||
1144 | $name = $filter->getName(); | ||
1145 | } | ||
1146 | |||
1147 | $this->filters[$name] = $filter; | ||
1148 | } | ||
1149 | |||
1150 | // functions | ||
1151 | foreach ($extension->getFunctions() as $name => $function) { | ||
1152 | if ($name instanceof Twig_SimpleFunction) { | ||
1153 | $function = $name; | ||
1154 | $name = $function->getName(); | ||
1155 | } elseif ($function instanceof Twig_SimpleFunction) { | ||
1156 | $name = $function->getName(); | ||
1157 | } | ||
1158 | |||
1159 | $this->functions[$name] = $function; | ||
1160 | } | ||
1161 | |||
1162 | // tests | ||
1163 | foreach ($extension->getTests() as $name => $test) { | ||
1164 | if ($name instanceof Twig_SimpleTest) { | ||
1165 | $test = $name; | ||
1166 | $name = $test->getName(); | ||
1167 | } elseif ($test instanceof Twig_SimpleTest) { | ||
1168 | $name = $test->getName(); | ||
1169 | } | ||
1170 | |||
1171 | $this->tests[$name] = $test; | ||
1172 | } | ||
1173 | |||
1174 | // token parsers | ||
1175 | foreach ($extension->getTokenParsers() as $parser) { | ||
1176 | if ($parser instanceof Twig_TokenParserInterface) { | ||
1177 | $this->parsers->addTokenParser($parser); | ||
1178 | } elseif ($parser instanceof Twig_TokenParserBrokerInterface) { | ||
1179 | $this->parsers->addTokenParserBroker($parser); | ||
1180 | } else { | ||
1181 | throw new LogicException('getTokenParsers() must return an array of Twig_TokenParserInterface or Twig_TokenParserBrokerInterface instances'); | ||
1182 | } | ||
1183 | } | ||
1184 | |||
1185 | // node visitors | ||
1186 | foreach ($extension->getNodeVisitors() as $visitor) { | ||
1187 | $this->visitors[] = $visitor; | ||
1188 | } | ||
1189 | |||
1190 | // operators | ||
1191 | if ($operators = $extension->getOperators()) { | ||
1192 | if (2 !== count($operators)) { | ||
1193 | throw new InvalidArgumentException(sprintf('"%s::getOperators()" does not return a valid operators array.', get_class($extension))); | ||
1194 | } | ||
1195 | |||
1196 | $this->unaryOperators = array_merge($this->unaryOperators, $operators[0]); | ||
1197 | $this->binaryOperators = array_merge($this->binaryOperators, $operators[1]); | ||
1198 | } | ||
1199 | } | ||
1200 | |||
1201 | protected function writeCacheFile($file, $content) | ||
1202 | { | ||
1203 | $dir = dirname($file); | ||
1204 | if (!is_dir($dir)) { | ||
1205 | if (false === @mkdir($dir, 0777, true) && !is_dir($dir)) { | ||
1206 | throw new RuntimeException(sprintf("Unable to create the cache directory (%s).", $dir)); | ||
1207 | } | ||
1208 | } elseif (!is_writable($dir)) { | ||
1209 | throw new RuntimeException(sprintf("Unable to write in the cache directory (%s).", $dir)); | ||
1210 | } | ||
1211 | |||
1212 | $tmpFile = tempnam(dirname($file), basename($file)); | ||
1213 | if (false !== @file_put_contents($tmpFile, $content)) { | ||
1214 | // rename does not work on Win32 before 5.2.6 | ||
1215 | if (@rename($tmpFile, $file) || (@copy($tmpFile, $file) && unlink($tmpFile))) { | ||
1216 | @chmod($file, 0666 & ~umask()); | ||
1217 | |||
1218 | return; | ||
1219 | } | ||
1220 | } | ||
1221 | |||
1222 | throw new RuntimeException(sprintf('Failed to write cache file "%s".', $file)); | ||
1223 | } | ||
1224 | } | ||
diff --git a/vendor/twig/twig/lib/Twig/Error.php b/vendor/twig/twig/lib/Twig/Error.php new file mode 100644 index 00000000..61a4cfa0 --- /dev/null +++ b/vendor/twig/twig/lib/Twig/Error.php | |||
@@ -0,0 +1,243 @@ | |||
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 integer $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 integer 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 integer $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 | $exceptions = array($e = $this); | ||
221 | while (($e instanceof self || method_exists($e, 'getPrevious')) && $e = $e->getPrevious()) { | ||
222 | $exceptions[] = $e; | ||
223 | } | ||
224 | |||
225 | while ($e = array_pop($exceptions)) { | ||
226 | $traces = $e->getTrace(); | ||
227 | while ($trace = array_shift($traces)) { | ||
228 | if (!isset($trace['file']) || !isset($trace['line']) || $file != $trace['file']) { | ||
229 | continue; | ||
230 | } | ||
231 | |||
232 | foreach ($template->getDebugInfo() as $codeLine => $templateLine) { | ||
233 | if ($codeLine <= $trace['line']) { | ||
234 | // update template line | ||
235 | $this->lineno = $templateLine; | ||
236 | |||
237 | return; | ||
238 | } | ||
239 | } | ||
240 | } | ||
241 | } | ||
242 | } | ||
243 | } | ||
diff --git a/vendor/twig/twig/lib/Twig/Error/Loader.php b/vendor/twig/twig/lib/Twig/Error/Loader.php new file mode 100644 index 00000000..68efb574 --- /dev/null +++ b/vendor/twig/twig/lib/Twig/Error/Loader.php | |||
@@ -0,0 +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 | } | ||
diff --git a/vendor/twig/twig/lib/Twig/Error/Runtime.php b/vendor/twig/twig/lib/Twig/Error/Runtime.php new file mode 100644 index 00000000..8b6ceddb --- /dev/null +++ b/vendor/twig/twig/lib/Twig/Error/Runtime.php | |||
@@ -0,0 +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 | } | ||
diff --git a/vendor/twig/twig/lib/Twig/Error/Syntax.php b/vendor/twig/twig/lib/Twig/Error/Syntax.php new file mode 100644 index 00000000..0f5c5792 --- /dev/null +++ b/vendor/twig/twig/lib/Twig/Error/Syntax.php | |||
@@ -0,0 +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 | } | ||
diff --git a/vendor/twig/twig/lib/Twig/ExistsLoaderInterface.php b/vendor/twig/twig/lib/Twig/ExistsLoaderInterface.php new file mode 100644 index 00000000..ce434765 --- /dev/null +++ b/vendor/twig/twig/lib/Twig/ExistsLoaderInterface.php | |||
@@ -0,0 +1,28 @@ | |||
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 | * @deprecated since 1.12 (to be removed in 2.0) | ||
17 | */ | ||
18 | interface Twig_ExistsLoaderInterface | ||
19 | { | ||
20 | /** | ||
21 | * Check if we have the source code of a template, given its name. | ||
22 | * | ||
23 | * @param string $name The name of the template to check if we can load | ||
24 | * | ||
25 | * @return boolean If the template source code is handled by this loader or not | ||
26 | */ | ||
27 | public function exists($name); | ||
28 | } | ||
diff --git a/vendor/twig/twig/lib/Twig/ExpressionParser.php b/vendor/twig/twig/lib/Twig/ExpressionParser.php new file mode 100644 index 00000000..9cf19344 --- /dev/null +++ b/vendor/twig/twig/lib/Twig/ExpressionParser.php | |||
@@ -0,0 +1,600 @@ | |||
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()->test(Twig_Token::PUNCTUATION_TYPE, '?')) { | ||
90 | $this->parser->getStream()->next(); | ||
91 | if (!$this->parser->getStream()->test(Twig_Token::PUNCTUATION_TYPE, ':')) { | ||
92 | $expr2 = $this->parseExpression(); | ||
93 | if ($this->parser->getStream()->test(Twig_Token::PUNCTUATION_TYPE, ':')) { | ||
94 | $this->parser->getStream()->next(); | ||
95 | $expr3 = $this->parseExpression(); | ||
96 | } else { | ||
97 | $expr3 = new Twig_Node_Expression_Constant('', $this->parser->getCurrentToken()->getLine()); | ||
98 | } | ||
99 | } else { | ||
100 | $this->parser->getStream()->next(); | ||
101 | $expr2 = $expr; | ||
102 | $expr3 = $this->parseExpression(); | ||
103 | } | ||
104 | |||
105 | $expr = new Twig_Node_Expression_Conditional($expr, $expr2, $expr3, $this->parser->getCurrentToken()->getLine()); | ||
106 | } | ||
107 | |||
108 | return $expr; | ||
109 | } | ||
110 | |||
111 | protected function isUnary(Twig_Token $token) | ||
112 | { | ||
113 | return $token->test(Twig_Token::OPERATOR_TYPE) && isset($this->unaryOperators[$token->getValue()]); | ||
114 | } | ||
115 | |||
116 | protected function isBinary(Twig_Token $token) | ||
117 | { | ||
118 | return $token->test(Twig_Token::OPERATOR_TYPE) && isset($this->binaryOperators[$token->getValue()]); | ||
119 | } | ||
120 | |||
121 | public function parsePrimaryExpression() | ||
122 | { | ||
123 | $token = $this->parser->getCurrentToken(); | ||
124 | switch ($token->getType()) { | ||
125 | case Twig_Token::NAME_TYPE: | ||
126 | $this->parser->getStream()->next(); | ||
127 | switch ($token->getValue()) { | ||
128 | case 'true': | ||
129 | case 'TRUE': | ||
130 | $node = new Twig_Node_Expression_Constant(true, $token->getLine()); | ||
131 | break; | ||
132 | |||
133 | case 'false': | ||
134 | case 'FALSE': | ||
135 | $node = new Twig_Node_Expression_Constant(false, $token->getLine()); | ||
136 | break; | ||
137 | |||
138 | case 'none': | ||
139 | case 'NONE': | ||
140 | case 'null': | ||
141 | case 'NULL': | ||
142 | $node = new Twig_Node_Expression_Constant(null, $token->getLine()); | ||
143 | break; | ||
144 | |||
145 | default: | ||
146 | if ('(' === $this->parser->getCurrentToken()->getValue()) { | ||
147 | $node = $this->getFunctionNode($token->getValue(), $token->getLine()); | ||
148 | } else { | ||
149 | $node = new Twig_Node_Expression_Name($token->getValue(), $token->getLine()); | ||
150 | } | ||
151 | } | ||
152 | break; | ||
153 | |||
154 | case Twig_Token::NUMBER_TYPE: | ||
155 | $this->parser->getStream()->next(); | ||
156 | $node = new Twig_Node_Expression_Constant($token->getValue(), $token->getLine()); | ||
157 | break; | ||
158 | |||
159 | case Twig_Token::STRING_TYPE: | ||
160 | case Twig_Token::INTERPOLATION_START_TYPE: | ||
161 | $node = $this->parseStringExpression(); | ||
162 | break; | ||
163 | |||
164 | default: | ||
165 | if ($token->test(Twig_Token::PUNCTUATION_TYPE, '[')) { | ||
166 | $node = $this->parseArrayExpression(); | ||
167 | } elseif ($token->test(Twig_Token::PUNCTUATION_TYPE, '{')) { | ||
168 | $node = $this->parseHashExpression(); | ||
169 | } else { | ||
170 | throw new Twig_Error_Syntax(sprintf('Unexpected token "%s" of value "%s"', Twig_Token::typeToEnglish($token->getType(), $token->getLine()), $token->getValue()), $token->getLine(), $this->parser->getFilename()); | ||
171 | } | ||
172 | } | ||
173 | |||
174 | return $this->parsePostfixExpression($node); | ||
175 | } | ||
176 | |||
177 | public function parseStringExpression() | ||
178 | { | ||
179 | $stream = $this->parser->getStream(); | ||
180 | |||
181 | $nodes = array(); | ||
182 | // a string cannot be followed by another string in a single expression | ||
183 | $nextCanBeString = true; | ||
184 | while (true) { | ||
185 | if ($stream->test(Twig_Token::STRING_TYPE) && $nextCanBeString) { | ||
186 | $token = $stream->next(); | ||
187 | $nodes[] = new Twig_Node_Expression_Constant($token->getValue(), $token->getLine()); | ||
188 | $nextCanBeString = false; | ||
189 | } elseif ($stream->test(Twig_Token::INTERPOLATION_START_TYPE)) { | ||
190 | $stream->next(); | ||
191 | $nodes[] = $this->parseExpression(); | ||
192 | $stream->expect(Twig_Token::INTERPOLATION_END_TYPE); | ||
193 | $nextCanBeString = true; | ||
194 | } else { | ||
195 | break; | ||
196 | } | ||
197 | } | ||
198 | |||
199 | $expr = array_shift($nodes); | ||
200 | foreach ($nodes as $node) { | ||
201 | $expr = new Twig_Node_Expression_Binary_Concat($expr, $node, $node->getLine()); | ||
202 | } | ||
203 | |||
204 | return $expr; | ||
205 | } | ||
206 | |||
207 | public function parseArrayExpression() | ||
208 | { | ||
209 | $stream = $this->parser->getStream(); | ||
210 | $stream->expect(Twig_Token::PUNCTUATION_TYPE, '[', 'An array element was expected'); | ||
211 | |||
212 | $node = new Twig_Node_Expression_Array(array(), $stream->getCurrent()->getLine()); | ||
213 | $first = true; | ||
214 | while (!$stream->test(Twig_Token::PUNCTUATION_TYPE, ']')) { | ||
215 | if (!$first) { | ||
216 | $stream->expect(Twig_Token::PUNCTUATION_TYPE, ',', 'An array element must be followed by a comma'); | ||
217 | |||
218 | // trailing ,? | ||
219 | if ($stream->test(Twig_Token::PUNCTUATION_TYPE, ']')) { | ||
220 | break; | ||
221 | } | ||
222 | } | ||
223 | $first = false; | ||
224 | |||
225 | $node->addElement($this->parseExpression()); | ||
226 | } | ||
227 | $stream->expect(Twig_Token::PUNCTUATION_TYPE, ']', 'An opened array is not properly closed'); | ||
228 | |||
229 | return $node; | ||
230 | } | ||
231 | |||
232 | public function parseHashExpression() | ||
233 | { | ||
234 | $stream = $this->parser->getStream(); | ||
235 | $stream->expect(Twig_Token::PUNCTUATION_TYPE, '{', 'A hash element was expected'); | ||
236 | |||
237 | $node = new Twig_Node_Expression_Array(array(), $stream->getCurrent()->getLine()); | ||
238 | $first = true; | ||
239 | while (!$stream->test(Twig_Token::PUNCTUATION_TYPE, '}')) { | ||
240 | if (!$first) { | ||
241 | $stream->expect(Twig_Token::PUNCTUATION_TYPE, ',', 'A hash value must be followed by a comma'); | ||
242 | |||
243 | // trailing ,? | ||
244 | if ($stream->test(Twig_Token::PUNCTUATION_TYPE, '}')) { | ||
245 | break; | ||
246 | } | ||
247 | } | ||
248 | $first = false; | ||
249 | |||
250 | // a hash key can be: | ||
251 | // | ||
252 | // * a number -- 12 | ||
253 | // * a string -- 'a' | ||
254 | // * a name, which is equivalent to a string -- a | ||
255 | // * an expression, which must be enclosed in parentheses -- (1 + 2) | ||
256 | if ($stream->test(Twig_Token::STRING_TYPE) || $stream->test(Twig_Token::NAME_TYPE) || $stream->test(Twig_Token::NUMBER_TYPE)) { | ||
257 | $token = $stream->next(); | ||
258 | $key = new Twig_Node_Expression_Constant($token->getValue(), $token->getLine()); | ||
259 | } elseif ($stream->test(Twig_Token::PUNCTUATION_TYPE, '(')) { | ||
260 | $key = $this->parseExpression(); | ||
261 | } else { | ||
262 | $current = $stream->getCurrent(); | ||
263 | |||
264 | 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->getLine()), $current->getValue()), $current->getLine(), $this->parser->getFilename()); | ||
265 | } | ||
266 | |||
267 | $stream->expect(Twig_Token::PUNCTUATION_TYPE, ':', 'A hash key must be followed by a colon (:)'); | ||
268 | $value = $this->parseExpression(); | ||
269 | |||
270 | $node->addElement($value, $key); | ||
271 | } | ||
272 | $stream->expect(Twig_Token::PUNCTUATION_TYPE, '}', 'An opened hash is not properly closed'); | ||
273 | |||
274 | return $node; | ||
275 | } | ||
276 | |||
277 | public function parsePostfixExpression($node) | ||
278 | { | ||
279 | while (true) { | ||
280 | $token = $this->parser->getCurrentToken(); | ||
281 | if ($token->getType() == Twig_Token::PUNCTUATION_TYPE) { | ||
282 | if ('.' == $token->getValue() || '[' == $token->getValue()) { | ||
283 | $node = $this->parseSubscriptExpression($node); | ||
284 | } elseif ('|' == $token->getValue()) { | ||
285 | $node = $this->parseFilterExpression($node); | ||
286 | } else { | ||
287 | break; | ||
288 | } | ||
289 | } else { | ||
290 | break; | ||
291 | } | ||
292 | } | ||
293 | |||
294 | return $node; | ||
295 | } | ||
296 | |||
297 | public function getFunctionNode($name, $line) | ||
298 | { | ||
299 | switch ($name) { | ||
300 | case 'parent': | ||
301 | $args = $this->parseArguments(); | ||
302 | if (!count($this->parser->getBlockStack())) { | ||
303 | throw new Twig_Error_Syntax('Calling "parent" outside a block is forbidden', $line, $this->parser->getFilename()); | ||
304 | } | ||
305 | |||
306 | if (!$this->parser->getParent() && !$this->parser->hasTraits()) { | ||
307 | throw new Twig_Error_Syntax('Calling "parent" on a template that does not extend nor "use" another template is forbidden', $line, $this->parser->getFilename()); | ||
308 | } | ||
309 | |||
310 | return new Twig_Node_Expression_Parent($this->parser->peekBlockStack(), $line); | ||
311 | case 'block': | ||
312 | return new Twig_Node_Expression_BlockReference($this->parseArguments()->getNode(0), false, $line); | ||
313 | case 'attribute': | ||
314 | $args = $this->parseArguments(); | ||
315 | if (count($args) < 2) { | ||
316 | throw new Twig_Error_Syntax('The "attribute" function takes at least two arguments (the variable and the attributes)', $line, $this->parser->getFilename()); | ||
317 | } | ||
318 | |||
319 | 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_TemplateInterface::ANY_CALL, $line); | ||
320 | default: | ||
321 | if (null !== $alias = $this->parser->getImportedSymbol('function', $name)) { | ||
322 | $arguments = new Twig_Node_Expression_Array(array(), $line); | ||
323 | foreach ($this->parseArguments() as $n) { | ||
324 | $arguments->addElement($n); | ||
325 | } | ||
326 | |||
327 | $node = new Twig_Node_Expression_MethodCall($alias['node'], $alias['name'], $arguments, $line); | ||
328 | $node->setAttribute('safe', true); | ||
329 | |||
330 | return $node; | ||
331 | } | ||
332 | |||
333 | $args = $this->parseArguments(true); | ||
334 | $class = $this->getFunctionNodeClass($name, $line); | ||
335 | |||
336 | return new $class($name, $args, $line); | ||
337 | } | ||
338 | } | ||
339 | |||
340 | public function parseSubscriptExpression($node) | ||
341 | { | ||
342 | $stream = $this->parser->getStream(); | ||
343 | $token = $stream->next(); | ||
344 | $lineno = $token->getLine(); | ||
345 | $arguments = new Twig_Node_Expression_Array(array(), $lineno); | ||
346 | $type = Twig_TemplateInterface::ANY_CALL; | ||
347 | if ($token->getValue() == '.') { | ||
348 | $token = $stream->next(); | ||
349 | if ( | ||
350 | $token->getType() == Twig_Token::NAME_TYPE | ||
351 | || | ||
352 | $token->getType() == Twig_Token::NUMBER_TYPE | ||
353 | || | ||
354 | ($token->getType() == Twig_Token::OPERATOR_TYPE && preg_match(Twig_Lexer::REGEX_NAME, $token->getValue())) | ||
355 | ) { | ||
356 | $arg = new Twig_Node_Expression_Constant($token->getValue(), $lineno); | ||
357 | |||
358 | if ($stream->test(Twig_Token::PUNCTUATION_TYPE, '(')) { | ||
359 | $type = Twig_TemplateInterface::METHOD_CALL; | ||
360 | foreach ($this->parseArguments() as $n) { | ||
361 | $arguments->addElement($n); | ||
362 | } | ||
363 | } | ||
364 | } else { | ||
365 | throw new Twig_Error_Syntax('Expected name or number', $lineno, $this->parser->getFilename()); | ||
366 | } | ||
367 | |||
368 | if ($node instanceof Twig_Node_Expression_Name && null !== $this->parser->getImportedSymbol('template', $node->getAttribute('name'))) { | ||
369 | if (!$arg instanceof Twig_Node_Expression_Constant) { | ||
370 | throw new Twig_Error_Syntax(sprintf('Dynamic macro names are not supported (called on "%s")', $node->getAttribute('name')), $token->getLine(), $this->parser->getFilename()); | ||
371 | } | ||
372 | |||
373 | $node = new Twig_Node_Expression_MethodCall($node, 'get'.$arg->getAttribute('value'), $arguments, $lineno); | ||
374 | $node->setAttribute('safe', true); | ||
375 | |||
376 | return $node; | ||
377 | } | ||
378 | } else { | ||
379 | $type = Twig_TemplateInterface::ARRAY_CALL; | ||
380 | |||
381 | // slice? | ||
382 | $slice = false; | ||
383 | if ($stream->test(Twig_Token::PUNCTUATION_TYPE, ':')) { | ||
384 | $slice = true; | ||
385 | $arg = new Twig_Node_Expression_Constant(0, $token->getLine()); | ||
386 | } else { | ||
387 | $arg = $this->parseExpression(); | ||
388 | } | ||
389 | |||
390 | if ($stream->test(Twig_Token::PUNCTUATION_TYPE, ':')) { | ||
391 | $slice = true; | ||
392 | $stream->next(); | ||
393 | } | ||
394 | |||
395 | if ($slice) { | ||
396 | if ($stream->test(Twig_Token::PUNCTUATION_TYPE, ']')) { | ||
397 | $length = new Twig_Node_Expression_Constant(null, $token->getLine()); | ||
398 | } else { | ||
399 | $length = $this->parseExpression(); | ||
400 | } | ||
401 | |||
402 | $class = $this->getFilterNodeClass('slice', $token->getLine()); | ||
403 | $arguments = new Twig_Node(array($arg, $length)); | ||
404 | $filter = new $class($node, new Twig_Node_Expression_Constant('slice', $token->getLine()), $arguments, $token->getLine()); | ||
405 | |||
406 | $stream->expect(Twig_Token::PUNCTUATION_TYPE, ']'); | ||
407 | |||
408 | return $filter; | ||
409 | } | ||
410 | |||
411 | $stream->expect(Twig_Token::PUNCTUATION_TYPE, ']'); | ||
412 | } | ||
413 | |||
414 | return new Twig_Node_Expression_GetAttr($node, $arg, $arguments, $type, $lineno); | ||
415 | } | ||
416 | |||
417 | public function parseFilterExpression($node) | ||
418 | { | ||
419 | $this->parser->getStream()->next(); | ||
420 | |||
421 | return $this->parseFilterExpressionRaw($node); | ||
422 | } | ||
423 | |||
424 | public function parseFilterExpressionRaw($node, $tag = null) | ||
425 | { | ||
426 | while (true) { | ||
427 | $token = $this->parser->getStream()->expect(Twig_Token::NAME_TYPE); | ||
428 | |||
429 | $name = new Twig_Node_Expression_Constant($token->getValue(), $token->getLine()); | ||
430 | if (!$this->parser->getStream()->test(Twig_Token::PUNCTUATION_TYPE, '(')) { | ||
431 | $arguments = new Twig_Node(); | ||
432 | } else { | ||
433 | $arguments = $this->parseArguments(true); | ||
434 | } | ||
435 | |||
436 | $class = $this->getFilterNodeClass($name->getAttribute('value'), $token->getLine()); | ||
437 | |||
438 | $node = new $class($node, $name, $arguments, $token->getLine(), $tag); | ||
439 | |||
440 | if (!$this->parser->getStream()->test(Twig_Token::PUNCTUATION_TYPE, '|')) { | ||
441 | break; | ||
442 | } | ||
443 | |||
444 | $this->parser->getStream()->next(); | ||
445 | } | ||
446 | |||
447 | return $node; | ||
448 | } | ||
449 | |||
450 | /** | ||
451 | * Parses arguments. | ||
452 | * | ||
453 | * @param Boolean $namedArguments Whether to allow named arguments or not | ||
454 | * @param Boolean $definition Whether we are parsing arguments for a function definition | ||
455 | */ | ||
456 | public function parseArguments($namedArguments = false, $definition = false) | ||
457 | { | ||
458 | $args = array(); | ||
459 | $stream = $this->parser->getStream(); | ||
460 | |||
461 | $stream->expect(Twig_Token::PUNCTUATION_TYPE, '(', 'A list of arguments must begin with an opening parenthesis'); | ||
462 | while (!$stream->test(Twig_Token::PUNCTUATION_TYPE, ')')) { | ||
463 | if (!empty($args)) { | ||
464 | $stream->expect(Twig_Token::PUNCTUATION_TYPE, ',', 'Arguments must be separated by a comma'); | ||
465 | } | ||
466 | |||
467 | if ($definition) { | ||
468 | $token = $stream->expect(Twig_Token::NAME_TYPE, null, 'An argument must be a name'); | ||
469 | $value = new Twig_Node_Expression_Name($token->getValue(), $this->parser->getCurrentToken()->getLine()); | ||
470 | } else { | ||
471 | $value = $this->parseExpression(); | ||
472 | } | ||
473 | |||
474 | $name = null; | ||
475 | if ($namedArguments && $stream->test(Twig_Token::OPERATOR_TYPE, '=')) { | ||
476 | $token = $stream->next(); | ||
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()->test(Twig_Token::PUNCTUATION_TYPE, ',')) { | ||
523 | break; | ||
524 | } | ||
525 | $this->parser->getStream()->next(); | ||
526 | } | ||
527 | |||
528 | return new Twig_Node($targets); | ||
529 | } | ||
530 | |||
531 | public function parseMultitargetExpression() | ||
532 | { | ||
533 | $targets = array(); | ||
534 | while (true) { | ||
535 | $targets[] = $this->parseExpression(); | ||
536 | if (!$this->parser->getStream()->test(Twig_Token::PUNCTUATION_TYPE, ',')) { | ||
537 | break; | ||
538 | } | ||
539 | $this->parser->getStream()->next(); | ||
540 | } | ||
541 | |||
542 | return new Twig_Node($targets); | ||
543 | } | ||
544 | |||
545 | protected function getFunctionNodeClass($name, $line) | ||
546 | { | ||
547 | $env = $this->parser->getEnvironment(); | ||
548 | |||
549 | if (false === $function = $env->getFunction($name)) { | ||
550 | $message = sprintf('The function "%s" does not exist', $name); | ||
551 | if ($alternatives = $env->computeAlternatives($name, array_keys($env->getFunctions()))) { | ||
552 | $message = sprintf('%s. Did you mean "%s"', $message, implode('", "', $alternatives)); | ||
553 | } | ||
554 | |||
555 | throw new Twig_Error_Syntax($message, $line, $this->parser->getFilename()); | ||
556 | } | ||
557 | |||
558 | if ($function instanceof Twig_SimpleFunction) { | ||
559 | return $function->getNodeClass(); | ||
560 | } | ||
561 | |||
562 | return $function instanceof Twig_Function_Node ? $function->getClass() : 'Twig_Node_Expression_Function'; | ||
563 | } | ||
564 | |||
565 | protected function getFilterNodeClass($name, $line) | ||
566 | { | ||
567 | $env = $this->parser->getEnvironment(); | ||
568 | |||
569 | if (false === $filter = $env->getFilter($name)) { | ||
570 | $message = sprintf('The filter "%s" does not exist', $name); | ||
571 | if ($alternatives = $env->computeAlternatives($name, array_keys($env->getFilters()))) { | ||
572 | $message = sprintf('%s. Did you mean "%s"', $message, implode('", "', $alternatives)); | ||
573 | } | ||
574 | |||
575 | throw new Twig_Error_Syntax($message, $line, $this->parser->getFilename()); | ||
576 | } | ||
577 | |||
578 | if ($filter instanceof Twig_SimpleFilter) { | ||
579 | return $filter->getNodeClass(); | ||
580 | } | ||
581 | |||
582 | return $filter instanceof Twig_Filter_Node ? $filter->getClass() : 'Twig_Node_Expression_Filter'; | ||
583 | } | ||
584 | |||
585 | // checks that the node only contains "constant" elements | ||
586 | protected function checkConstantExpression(Twig_NodeInterface $node) | ||
587 | { | ||
588 | if (!($node instanceof Twig_Node_Expression_Constant || $node instanceof Twig_Node_Expression_Array)) { | ||
589 | return false; | ||
590 | } | ||
591 | |||
592 | foreach ($node as $n) { | ||
593 | if (!$this->checkConstantExpression($n)) { | ||
594 | return false; | ||
595 | } | ||
596 | } | ||
597 | |||
598 | return true; | ||
599 | } | ||
600 | } | ||
diff --git a/vendor/twig/twig/lib/Twig/Extension.php b/vendor/twig/twig/lib/Twig/Extension.php new file mode 100644 index 00000000..931fc033 --- /dev/null +++ b/vendor/twig/twig/lib/Twig/Extension.php | |||
@@ -0,0 +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 array 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 | } | ||
diff --git a/vendor/twig/twig/lib/Twig/Extension/Core.php b/vendor/twig/twig/lib/Twig/Extension/Core.php new file mode 100644 index 00000000..e68687b4 --- /dev/null +++ b/vendor/twig/twig/lib/Twig/Extension/Core.php | |||
@@ -0,0 +1,1355 @@ | |||
1 | <?php | ||
2 | |||
3 | if (!defined('ENT_SUBSTITUTE')) { | ||
4 | define('ENT_SUBSTITUTE', 8); | ||
5 | } | ||
6 | |||
7 | /* | ||
8 | * This file is part of Twig. | ||
9 | * | ||
10 | * (c) 2009 Fabien Potencier | ||
11 | * | ||
12 | * For the full copyright and license information, please view the LICENSE | ||
13 | * file that was distributed with this source code. | ||
14 | */ | ||
15 | class Twig_Extension_Core extends Twig_Extension | ||
16 | { | ||
17 | protected $dateFormats = array('F j, Y H:i', '%d days'); | ||
18 | protected $numberFormat = array(0, '.', ','); | ||
19 | protected $timezone = null; | ||
20 | |||
21 | /** | ||
22 | * Sets the default format to be used by the date filter. | ||
23 | * | ||
24 | * @param string $format The default date format string | ||
25 | * @param string $dateIntervalFormat The default date interval format string | ||
26 | */ | ||
27 | public function setDateFormat($format = null, $dateIntervalFormat = null) | ||
28 | { | ||
29 | if (null !== $format) { | ||
30 | $this->dateFormats[0] = $format; | ||
31 | } | ||
32 | |||
33 | if (null !== $dateIntervalFormat) { | ||
34 | $this->dateFormats[1] = $dateIntervalFormat; | ||
35 | } | ||
36 | } | ||
37 | |||
38 | /** | ||
39 | * Gets the default format to be used by the date filter. | ||
40 | * | ||
41 | * @return array The default date format string and the default date interval format string | ||
42 | */ | ||
43 | public function getDateFormat() | ||
44 | { | ||
45 | return $this->dateFormats; | ||
46 | } | ||
47 | |||
48 | /** | ||
49 | * Sets the default timezone to be used by the date filter. | ||
50 | * | ||
51 | * @param DateTimeZone|string $timezone The default timezone string or a DateTimeZone object | ||
52 | */ | ||
53 | public function setTimezone($timezone) | ||
54 | { | ||
55 | $this->timezone = $timezone instanceof DateTimeZone ? $timezone : new DateTimeZone($timezone); | ||
56 | } | ||
57 | |||
58 | /** | ||
59 | * Gets the default timezone to be used by the date filter. | ||
60 | * | ||
61 | * @return DateTimeZone The default timezone currently in use | ||
62 | */ | ||
63 | public function getTimezone() | ||
64 | { | ||
65 | if (null === $this->timezone) { | ||
66 | $this->timezone = new DateTimeZone(date_default_timezone_get()); | ||
67 | } | ||
68 | |||
69 | return $this->timezone; | ||
70 | } | ||
71 | |||
72 | /** | ||
73 | * Sets the default format to be used by the number_format filter. | ||
74 | * | ||
75 | * @param integer $decimal The number of decimal places to use. | ||
76 | * @param string $decimalPoint The character(s) to use for the decimal point. | ||
77 | * @param string $thousandSep The character(s) to use for the thousands separator. | ||
78 | */ | ||
79 | public function setNumberFormat($decimal, $decimalPoint, $thousandSep) | ||
80 | { | ||
81 | $this->numberFormat = array($decimal, $decimalPoint, $thousandSep); | ||
82 | } | ||
83 | |||
84 | /** | ||
85 | * Get the default format used by the number_format filter. | ||
86 | * | ||
87 | * @return array The arguments for number_format() | ||
88 | */ | ||
89 | public function getNumberFormat() | ||
90 | { | ||
91 | return $this->numberFormat; | ||
92 | } | ||
93 | |||
94 | /** | ||
95 | * Returns the token parser instance to add to the existing list. | ||
96 | * | ||
97 | * @return array An array of Twig_TokenParser instances | ||
98 | */ | ||
99 | public function getTokenParsers() | ||
100 | { | ||
101 | return array( | ||
102 | new Twig_TokenParser_For(), | ||
103 | new Twig_TokenParser_If(), | ||
104 | new Twig_TokenParser_Extends(), | ||
105 | new Twig_TokenParser_Include(), | ||
106 | new Twig_TokenParser_Block(), | ||
107 | new Twig_TokenParser_Use(), | ||
108 | new Twig_TokenParser_Filter(), | ||
109 | new Twig_TokenParser_Macro(), | ||
110 | new Twig_TokenParser_Import(), | ||
111 | new Twig_TokenParser_From(), | ||
112 | new Twig_TokenParser_Set(), | ||
113 | new Twig_TokenParser_Spaceless(), | ||
114 | new Twig_TokenParser_Flush(), | ||
115 | new Twig_TokenParser_Do(), | ||
116 | new Twig_TokenParser_Embed(), | ||
117 | ); | ||
118 | } | ||
119 | |||
120 | /** | ||
121 | * Returns a list of filters to add to the existing list. | ||
122 | * | ||
123 | * @return array An array of filters | ||
124 | */ | ||
125 | public function getFilters() | ||
126 | { | ||
127 | $filters = array( | ||
128 | // formatting filters | ||
129 | new Twig_SimpleFilter('date', 'twig_date_format_filter', array('needs_environment' => true)), | ||
130 | new Twig_SimpleFilter('date_modify', 'twig_date_modify_filter', array('needs_environment' => true)), | ||
131 | new Twig_SimpleFilter('format', 'sprintf'), | ||
132 | new Twig_SimpleFilter('replace', 'strtr'), | ||
133 | new Twig_SimpleFilter('number_format', 'twig_number_format_filter', array('needs_environment' => true)), | ||
134 | new Twig_SimpleFilter('abs', 'abs'), | ||
135 | |||
136 | // encoding | ||
137 | new Twig_SimpleFilter('url_encode', 'twig_urlencode_filter'), | ||
138 | new Twig_SimpleFilter('json_encode', 'twig_jsonencode_filter'), | ||
139 | new Twig_SimpleFilter('convert_encoding', 'twig_convert_encoding'), | ||
140 | |||
141 | // string filters | ||
142 | new Twig_SimpleFilter('title', 'twig_title_string_filter', array('needs_environment' => true)), | ||
143 | new Twig_SimpleFilter('capitalize', 'twig_capitalize_string_filter', array('needs_environment' => true)), | ||
144 | new Twig_SimpleFilter('upper', 'strtoupper'), | ||
145 | new Twig_SimpleFilter('lower', 'strtolower'), | ||
146 | new Twig_SimpleFilter('striptags', 'strip_tags'), | ||
147 | new Twig_SimpleFilter('trim', 'trim'), | ||
148 | new Twig_SimpleFilter('nl2br', 'nl2br', array('pre_escape' => 'html', 'is_safe' => array('html'))), | ||
149 | |||
150 | // array helpers | ||
151 | new Twig_SimpleFilter('join', 'twig_join_filter'), | ||
152 | new Twig_SimpleFilter('split', 'twig_split_filter'), | ||
153 | new Twig_SimpleFilter('sort', 'twig_sort_filter'), | ||
154 | new Twig_SimpleFilter('merge', 'twig_array_merge'), | ||
155 | new Twig_SimpleFilter('batch', 'twig_array_batch'), | ||
156 | |||
157 | // string/array filters | ||
158 | new Twig_SimpleFilter('reverse', 'twig_reverse_filter', array('needs_environment' => true)), | ||
159 | new Twig_SimpleFilter('length', 'twig_length_filter', array('needs_environment' => true)), | ||
160 | new Twig_SimpleFilter('slice', 'twig_slice', array('needs_environment' => true)), | ||
161 | new Twig_SimpleFilter('first', 'twig_first', array('needs_environment' => true)), | ||
162 | new Twig_SimpleFilter('last', 'twig_last', array('needs_environment' => true)), | ||
163 | |||
164 | // iteration and runtime | ||
165 | new Twig_SimpleFilter('default', '_twig_default_filter', array('node_class' => 'Twig_Node_Expression_Filter_Default')), | ||
166 | new Twig_SimpleFilter('keys', 'twig_get_array_keys_filter'), | ||
167 | |||
168 | // escaping | ||
169 | new Twig_SimpleFilter('escape', 'twig_escape_filter', array('needs_environment' => true, 'is_safe_callback' => 'twig_escape_filter_is_safe')), | ||
170 | new Twig_SimpleFilter('e', 'twig_escape_filter', array('needs_environment' => true, 'is_safe_callback' => 'twig_escape_filter_is_safe')), | ||
171 | ); | ||
172 | |||
173 | if (function_exists('mb_get_info')) { | ||
174 | $filters[] = new Twig_SimpleFilter('upper', 'twig_upper_filter', array('needs_environment' => true)); | ||
175 | $filters[] = new Twig_SimpleFilter('lower', 'twig_lower_filter', array('needs_environment' => true)); | ||
176 | } | ||
177 | |||
178 | return $filters; | ||
179 | } | ||
180 | |||
181 | /** | ||
182 | * Returns a list of global functions to add to the existing list. | ||
183 | * | ||
184 | * @return array An array of global functions | ||
185 | */ | ||
186 | public function getFunctions() | ||
187 | { | ||
188 | return array( | ||
189 | new Twig_SimpleFunction('range', 'range'), | ||
190 | new Twig_SimpleFunction('constant', 'twig_constant'), | ||
191 | new Twig_SimpleFunction('cycle', 'twig_cycle'), | ||
192 | new Twig_SimpleFunction('random', 'twig_random', array('needs_environment' => true)), | ||
193 | new Twig_SimpleFunction('date', 'twig_date_converter', array('needs_environment' => true)), | ||
194 | new Twig_SimpleFunction('include', 'twig_include', array('needs_environment' => true, 'needs_context' => true, 'is_safe' => array('all'))), | ||
195 | ); | ||
196 | } | ||
197 | |||
198 | /** | ||
199 | * Returns a list of tests to add to the existing list. | ||
200 | * | ||
201 | * @return array An array of tests | ||
202 | */ | ||
203 | public function getTests() | ||
204 | { | ||
205 | return array( | ||
206 | new Twig_SimpleTest('even', null, array('node_class' => 'Twig_Node_Expression_Test_Even')), | ||
207 | new Twig_SimpleTest('odd', null, array('node_class' => 'Twig_Node_Expression_Test_Odd')), | ||
208 | new Twig_SimpleTest('defined', null, array('node_class' => 'Twig_Node_Expression_Test_Defined')), | ||
209 | new Twig_SimpleTest('sameas', null, array('node_class' => 'Twig_Node_Expression_Test_Sameas')), | ||
210 | new Twig_SimpleTest('none', null, array('node_class' => 'Twig_Node_Expression_Test_Null')), | ||
211 | new Twig_SimpleTest('null', null, array('node_class' => 'Twig_Node_Expression_Test_Null')), | ||
212 | new Twig_SimpleTest('divisibleby', null, array('node_class' => 'Twig_Node_Expression_Test_Divisibleby')), | ||
213 | new Twig_SimpleTest('constant', null, array('node_class' => 'Twig_Node_Expression_Test_Constant')), | ||
214 | new Twig_SimpleTest('empty', 'twig_test_empty'), | ||
215 | new Twig_SimpleTest('iterable', 'twig_test_iterable'), | ||
216 | ); | ||
217 | } | ||
218 | |||
219 | /** | ||
220 | * Returns a list of operators to add to the existing list. | ||
221 | * | ||
222 | * @return array An array of operators | ||
223 | */ | ||
224 | public function getOperators() | ||
225 | { | ||
226 | return array( | ||
227 | array( | ||
228 | 'not' => array('precedence' => 50, 'class' => 'Twig_Node_Expression_Unary_Not'), | ||
229 | '-' => array('precedence' => 500, 'class' => 'Twig_Node_Expression_Unary_Neg'), | ||
230 | '+' => array('precedence' => 500, 'class' => 'Twig_Node_Expression_Unary_Pos'), | ||
231 | ), | ||
232 | array( | ||
233 | 'or' => array('precedence' => 10, 'class' => 'Twig_Node_Expression_Binary_Or', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT), | ||
234 | 'and' => array('precedence' => 15, 'class' => 'Twig_Node_Expression_Binary_And', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT), | ||
235 | 'b-or' => array('precedence' => 16, 'class' => 'Twig_Node_Expression_Binary_BitwiseOr', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT), | ||
236 | 'b-xor' => array('precedence' => 17, 'class' => 'Twig_Node_Expression_Binary_BitwiseXor', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT), | ||
237 | 'b-and' => array('precedence' => 18, 'class' => 'Twig_Node_Expression_Binary_BitwiseAnd', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT), | ||
238 | '==' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_Equal', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT), | ||
239 | '!=' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_NotEqual', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT), | ||
240 | '<' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_Less', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT), | ||
241 | '>' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_Greater', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT), | ||
242 | '>=' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_GreaterEqual', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT), | ||
243 | '<=' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_LessEqual', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT), | ||
244 | 'not in' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_NotIn', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT), | ||
245 | 'in' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_In', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT), | ||
246 | '..' => array('precedence' => 25, 'class' => 'Twig_Node_Expression_Binary_Range', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT), | ||
247 | '+' => array('precedence' => 30, 'class' => 'Twig_Node_Expression_Binary_Add', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT), | ||
248 | '-' => array('precedence' => 30, 'class' => 'Twig_Node_Expression_Binary_Sub', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT), | ||
249 | '~' => array('precedence' => 40, 'class' => 'Twig_Node_Expression_Binary_Concat', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT), | ||
250 | '*' => array('precedence' => 60, 'class' => 'Twig_Node_Expression_Binary_Mul', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT), | ||
251 | '/' => array('precedence' => 60, 'class' => 'Twig_Node_Expression_Binary_Div', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT), | ||
252 | '//' => array('precedence' => 60, 'class' => 'Twig_Node_Expression_Binary_FloorDiv', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT), | ||
253 | '%' => array('precedence' => 60, 'class' => 'Twig_Node_Expression_Binary_Mod', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT), | ||
254 | 'is' => array('precedence' => 100, 'callable' => array($this, 'parseTestExpression'), 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT), | ||
255 | 'is not' => array('precedence' => 100, 'callable' => array($this, 'parseNotTestExpression'), 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT), | ||
256 | '**' => array('precedence' => 200, 'class' => 'Twig_Node_Expression_Binary_Power', 'associativity' => Twig_ExpressionParser::OPERATOR_RIGHT), | ||
257 | ), | ||
258 | ); | ||
259 | } | ||
260 | |||
261 | public function parseNotTestExpression(Twig_Parser $parser, $node) | ||
262 | { | ||
263 | return new Twig_Node_Expression_Unary_Not($this->parseTestExpression($parser, $node), $parser->getCurrentToken()->getLine()); | ||
264 | } | ||
265 | |||
266 | public function parseTestExpression(Twig_Parser $parser, $node) | ||
267 | { | ||
268 | $stream = $parser->getStream(); | ||
269 | $name = $stream->expect(Twig_Token::NAME_TYPE)->getValue(); | ||
270 | $arguments = null; | ||
271 | if ($stream->test(Twig_Token::PUNCTUATION_TYPE, '(')) { | ||
272 | $arguments = $parser->getExpressionParser()->parseArguments(true); | ||
273 | } | ||
274 | |||
275 | $class = $this->getTestNodeClass($parser, $name, $node->getLine()); | ||
276 | |||
277 | return new $class($node, $name, $arguments, $parser->getCurrentToken()->getLine()); | ||
278 | } | ||
279 | |||
280 | protected function getTestNodeClass(Twig_Parser $parser, $name, $line) | ||
281 | { | ||
282 | $env = $parser->getEnvironment(); | ||
283 | $testMap = $env->getTests(); | ||
284 | if (!isset($testMap[$name])) { | ||
285 | $message = sprintf('The test "%s" does not exist', $name); | ||
286 | if ($alternatives = $env->computeAlternatives($name, array_keys($env->getTests()))) { | ||
287 | $message = sprintf('%s. Did you mean "%s"', $message, implode('", "', $alternatives)); | ||
288 | } | ||
289 | |||
290 | throw new Twig_Error_Syntax($message, $line, $parser->getFilename()); | ||
291 | } | ||
292 | |||
293 | if ($testMap[$name] instanceof Twig_SimpleTest) { | ||
294 | return $testMap[$name]->getNodeClass(); | ||
295 | } | ||
296 | |||
297 | return $testMap[$name] instanceof Twig_Test_Node ? $testMap[$name]->getClass() : 'Twig_Node_Expression_Test'; | ||
298 | } | ||
299 | |||
300 | /** | ||
301 | * Returns the name of the extension. | ||
302 | * | ||
303 | * @return string The extension name | ||
304 | */ | ||
305 | public function getName() | ||
306 | { | ||
307 | return 'core'; | ||
308 | } | ||
309 | } | ||
310 | |||
311 | /** | ||
312 | * Cycles over a value. | ||
313 | * | ||
314 | * @param ArrayAccess|array $values An array or an ArrayAccess instance | ||
315 | * @param integer $position The cycle position | ||
316 | * | ||
317 | * @return string The next value in the cycle | ||
318 | */ | ||
319 | function twig_cycle($values, $position) | ||
320 | { | ||
321 | if (!is_array($values) && !$values instanceof ArrayAccess) { | ||
322 | return $values; | ||
323 | } | ||
324 | |||
325 | return $values[$position % count($values)]; | ||
326 | } | ||
327 | |||
328 | /** | ||
329 | * Returns a random value depending on the supplied parameter type: | ||
330 | * - a random item from a Traversable or array | ||
331 | * - a random character from a string | ||
332 | * - a random integer between 0 and the integer parameter | ||
333 | * | ||
334 | * @param Twig_Environment $env A Twig_Environment instance | ||
335 | * @param Traversable|array|integer|string $values The values to pick a random item from | ||
336 | * | ||
337 | * @throws Twig_Error_Runtime When $values is an empty array (does not apply to an empty string which is returned as is). | ||
338 | * | ||
339 | * @return mixed A random value from the given sequence | ||
340 | */ | ||
341 | function twig_random(Twig_Environment $env, $values = null) | ||
342 | { | ||
343 | if (null === $values) { | ||
344 | return mt_rand(); | ||
345 | } | ||
346 | |||
347 | if (is_int($values) || is_float($values)) { | ||
348 | return $values < 0 ? mt_rand($values, 0) : mt_rand(0, $values); | ||
349 | } | ||
350 | |||
351 | if ($values instanceof Traversable) { | ||
352 | $values = iterator_to_array($values); | ||
353 | } elseif (is_string($values)) { | ||
354 | if ('' === $values) { | ||
355 | return ''; | ||
356 | } | ||
357 | if (null !== $charset = $env->getCharset()) { | ||
358 | if ('UTF-8' != $charset) { | ||
359 | $values = twig_convert_encoding($values, 'UTF-8', $charset); | ||
360 | } | ||
361 | |||
362 | // unicode version of str_split() | ||
363 | // split at all positions, but not after the start and not before the end | ||
364 | $values = preg_split('/(?<!^)(?!$)/u', $values); | ||
365 | |||
366 | if ('UTF-8' != $charset) { | ||
367 | foreach ($values as $i => $value) { | ||
368 | $values[$i] = twig_convert_encoding($value, $charset, 'UTF-8'); | ||
369 | } | ||
370 | } | ||
371 | } else { | ||
372 | return $values[mt_rand(0, strlen($values) - 1)]; | ||
373 | } | ||
374 | } | ||
375 | |||
376 | if (!is_array($values)) { | ||
377 | return $values; | ||
378 | } | ||
379 | |||
380 | if (0 === count($values)) { | ||
381 | throw new Twig_Error_Runtime('The random function cannot pick from an empty array.'); | ||
382 | } | ||
383 | |||
384 | return $values[array_rand($values, 1)]; | ||
385 | } | ||
386 | |||
387 | /** | ||
388 | * Converts a date to the given format. | ||
389 | * | ||
390 | * <pre> | ||
391 | * {{ post.published_at|date("m/d/Y") }} | ||
392 | * </pre> | ||
393 | * | ||
394 | * @param Twig_Environment $env A Twig_Environment instance | ||
395 | * @param DateTime|DateInterval|string $date A date | ||
396 | * @param string $format A format | ||
397 | * @param DateTimeZone|string $timezone A timezone | ||
398 | * | ||
399 | * @return string The formatted date | ||
400 | */ | ||
401 | function twig_date_format_filter(Twig_Environment $env, $date, $format = null, $timezone = null) | ||
402 | { | ||
403 | if (null === $format) { | ||
404 | $formats = $env->getExtension('core')->getDateFormat(); | ||
405 | $format = $date instanceof DateInterval ? $formats[1] : $formats[0]; | ||
406 | } | ||
407 | |||
408 | if ($date instanceof DateInterval) { | ||
409 | return $date->format($format); | ||
410 | } | ||
411 | |||
412 | return twig_date_converter($env, $date, $timezone)->format($format); | ||
413 | } | ||
414 | |||
415 | /** | ||
416 | * Returns a new date object modified | ||
417 | * | ||
418 | * <pre> | ||
419 | * {{ post.published_at|date_modify("-1day")|date("m/d/Y") }} | ||
420 | * </pre> | ||
421 | * | ||
422 | * @param Twig_Environment $env A Twig_Environment instance | ||
423 | * @param DateTime|string $date A date | ||
424 | * @param string $modifier A modifier string | ||
425 | * | ||
426 | * @return DateTime A new date object | ||
427 | */ | ||
428 | function twig_date_modify_filter(Twig_Environment $env, $date, $modifier) | ||
429 | { | ||
430 | $date = twig_date_converter($env, $date, false); | ||
431 | $date->modify($modifier); | ||
432 | |||
433 | return $date; | ||
434 | } | ||
435 | |||
436 | /** | ||
437 | * Converts an input to a DateTime instance. | ||
438 | * | ||
439 | * <pre> | ||
440 | * {% if date(user.created_at) < date('+2days') %} | ||
441 | * {# do something #} | ||
442 | * {% endif %} | ||
443 | * </pre> | ||
444 | * | ||
445 | * @param Twig_Environment $env A Twig_Environment instance | ||
446 | * @param DateTime|string $date A date | ||
447 | * @param DateTimeZone|string $timezone A timezone | ||
448 | * | ||
449 | * @return DateTime A DateTime instance | ||
450 | */ | ||
451 | function twig_date_converter(Twig_Environment $env, $date = null, $timezone = null) | ||
452 | { | ||
453 | // determine the timezone | ||
454 | if (!$timezone) { | ||
455 | $defaultTimezone = $env->getExtension('core')->getTimezone(); | ||
456 | } elseif (!$timezone instanceof DateTimeZone) { | ||
457 | $defaultTimezone = new DateTimeZone($timezone); | ||
458 | } else { | ||
459 | $defaultTimezone = $timezone; | ||
460 | } | ||
461 | |||
462 | if ($date instanceof DateTime) { | ||
463 | $date = clone $date; | ||
464 | if (false !== $timezone) { | ||
465 | $date->setTimezone($defaultTimezone); | ||
466 | } | ||
467 | |||
468 | return $date; | ||
469 | } | ||
470 | |||
471 | $asString = (string) $date; | ||
472 | if (ctype_digit($asString) || (!empty($asString) && '-' === $asString[0] && ctype_digit(substr($asString, 1)))) { | ||
473 | $date = '@'.$date; | ||
474 | } | ||
475 | |||
476 | $date = new DateTime($date, $defaultTimezone); | ||
477 | if (false !== $timezone) { | ||
478 | $date->setTimezone($defaultTimezone); | ||
479 | } | ||
480 | |||
481 | return $date; | ||
482 | } | ||
483 | |||
484 | /** | ||
485 | * Number format filter. | ||
486 | * | ||
487 | * All of the formatting options can be left null, in that case the defaults will | ||
488 | * be used. Supplying any of the parameters will override the defaults set in the | ||
489 | * environment object. | ||
490 | * | ||
491 | * @param Twig_Environment $env A Twig_Environment instance | ||
492 | * @param mixed $number A float/int/string of the number to format | ||
493 | * @param integer $decimal The number of decimal points to display. | ||
494 | * @param string $decimalPoint The character(s) to use for the decimal point. | ||
495 | * @param string $thousandSep The character(s) to use for the thousands separator. | ||
496 | * | ||
497 | * @return string The formatted number | ||
498 | */ | ||
499 | function twig_number_format_filter(Twig_Environment $env, $number, $decimal = null, $decimalPoint = null, $thousandSep = null) | ||
500 | { | ||
501 | $defaults = $env->getExtension('core')->getNumberFormat(); | ||
502 | if (null === $decimal) { | ||
503 | $decimal = $defaults[0]; | ||
504 | } | ||
505 | |||
506 | if (null === $decimalPoint) { | ||
507 | $decimalPoint = $defaults[1]; | ||
508 | } | ||
509 | |||
510 | if (null === $thousandSep) { | ||
511 | $thousandSep = $defaults[2]; | ||
512 | } | ||
513 | |||
514 | return number_format((float) $number, $decimal, $decimalPoint, $thousandSep); | ||
515 | } | ||
516 | |||
517 | /** | ||
518 | * URL encodes a string as a path segment or an array as a query string. | ||
519 | * | ||
520 | * @param string|array $url A URL or an array of query parameters | ||
521 | * @param bool $raw true to use rawurlencode() instead of urlencode | ||
522 | * | ||
523 | * @return string The URL encoded value | ||
524 | */ | ||
525 | function twig_urlencode_filter($url, $raw = false) | ||
526 | { | ||
527 | if (is_array($url)) { | ||
528 | return http_build_query($url, '', '&'); | ||
529 | } | ||
530 | |||
531 | if ($raw) { | ||
532 | return rawurlencode($url); | ||
533 | } | ||
534 | |||
535 | return urlencode($url); | ||
536 | } | ||
537 | |||
538 | if (version_compare(PHP_VERSION, '5.3.0', '<')) { | ||
539 | /** | ||
540 | * JSON encodes a variable. | ||
541 | * | ||
542 | * @param mixed $value The value to encode. | ||
543 | * @param integer $options Not used on PHP 5.2.x | ||
544 | * | ||
545 | * @return mixed The JSON encoded value | ||
546 | */ | ||
547 | function twig_jsonencode_filter($value, $options = 0) | ||
548 | { | ||
549 | if ($value instanceof Twig_Markup) { | ||
550 | $value = (string) $value; | ||
551 | } elseif (is_array($value)) { | ||
552 | array_walk_recursive($value, '_twig_markup2string'); | ||
553 | } | ||
554 | |||
555 | return json_encode($value); | ||
556 | } | ||
557 | } else { | ||
558 | /** | ||
559 | * JSON encodes a variable. | ||
560 | * | ||
561 | * @param mixed $value The value to encode. | ||
562 | * @param integer $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 | ||
563 | * | ||
564 | * @return mixed The JSON encoded value | ||
565 | */ | ||
566 | function twig_jsonencode_filter($value, $options = 0) | ||
567 | { | ||
568 | if ($value instanceof Twig_Markup) { | ||
569 | $value = (string) $value; | ||
570 | } elseif (is_array($value)) { | ||
571 | array_walk_recursive($value, '_twig_markup2string'); | ||
572 | } | ||
573 | |||
574 | return json_encode($value, $options); | ||
575 | } | ||
576 | } | ||
577 | |||
578 | function _twig_markup2string(&$value) | ||
579 | { | ||
580 | if ($value instanceof Twig_Markup) { | ||
581 | $value = (string) $value; | ||
582 | } | ||
583 | } | ||
584 | |||
585 | /** | ||
586 | * Merges an array with another one. | ||
587 | * | ||
588 | * <pre> | ||
589 | * {% set items = { 'apple': 'fruit', 'orange': 'fruit' } %} | ||
590 | * | ||
591 | * {% set items = items|merge({ 'peugeot': 'car' }) %} | ||
592 | * | ||
593 | * {# items now contains { 'apple': 'fruit', 'orange': 'fruit', 'peugeot': 'car' } #} | ||
594 | * </pre> | ||
595 | * | ||
596 | * @param array $arr1 An array | ||
597 | * @param array $arr2 An array | ||
598 | * | ||
599 | * @return array The merged array | ||
600 | */ | ||
601 | function twig_array_merge($arr1, $arr2) | ||
602 | { | ||
603 | if (!is_array($arr1) || !is_array($arr2)) { | ||
604 | throw new Twig_Error_Runtime('The merge filter only works with arrays or hashes.'); | ||
605 | } | ||
606 | |||
607 | return array_merge($arr1, $arr2); | ||
608 | } | ||
609 | |||
610 | /** | ||
611 | * Slices a variable. | ||
612 | * | ||
613 | * @param Twig_Environment $env A Twig_Environment instance | ||
614 | * @param mixed $item A variable | ||
615 | * @param integer $start Start of the slice | ||
616 | * @param integer $length Size of the slice | ||
617 | * @param Boolean $preserveKeys Whether to preserve key or not (when the input is an array) | ||
618 | * | ||
619 | * @return mixed The sliced variable | ||
620 | */ | ||
621 | function twig_slice(Twig_Environment $env, $item, $start, $length = null, $preserveKeys = false) | ||
622 | { | ||
623 | if ($item instanceof Traversable) { | ||
624 | $item = iterator_to_array($item, false); | ||
625 | } | ||
626 | |||
627 | if (is_array($item)) { | ||
628 | return array_slice($item, $start, $length, $preserveKeys); | ||
629 | } | ||
630 | |||
631 | $item = (string) $item; | ||
632 | |||
633 | if (function_exists('mb_get_info') && null !== $charset = $env->getCharset()) { | ||
634 | return mb_substr($item, $start, null === $length ? mb_strlen($item, $charset) - $start : $length, $charset); | ||
635 | } | ||
636 | |||
637 | return null === $length ? substr($item, $start) : substr($item, $start, $length); | ||
638 | } | ||
639 | |||
640 | /** | ||
641 | * Returns the first element of the item. | ||
642 | * | ||
643 | * @param Twig_Environment $env A Twig_Environment instance | ||
644 | * @param mixed $item A variable | ||
645 | * | ||
646 | * @return mixed The first element of the item | ||
647 | */ | ||
648 | function twig_first(Twig_Environment $env, $item) | ||
649 | { | ||
650 | $elements = twig_slice($env, $item, 0, 1, false); | ||
651 | |||
652 | return is_string($elements) ? $elements[0] : current($elements); | ||
653 | } | ||
654 | |||
655 | /** | ||
656 | * Returns the last element of the item. | ||
657 | * | ||
658 | * @param Twig_Environment $env A Twig_Environment instance | ||
659 | * @param mixed $item A variable | ||
660 | * | ||
661 | * @return mixed The last element of the item | ||
662 | */ | ||
663 | function twig_last(Twig_Environment $env, $item) | ||
664 | { | ||
665 | $elements = twig_slice($env, $item, -1, 1, false); | ||
666 | |||
667 | return is_string($elements) ? $elements[0] : current($elements); | ||
668 | } | ||
669 | |||
670 | /** | ||
671 | * Joins the values to a string. | ||
672 | * | ||
673 | * The separator between elements is an empty string per default, you can define it with the optional parameter. | ||
674 | * | ||
675 | * <pre> | ||
676 | * {{ [1, 2, 3]|join('|') }} | ||
677 | * {# returns 1|2|3 #} | ||
678 | * | ||
679 | * {{ [1, 2, 3]|join }} | ||
680 | * {# returns 123 #} | ||
681 | * </pre> | ||
682 | * | ||
683 | * @param array $value An array | ||
684 | * @param string $glue The separator | ||
685 | * | ||
686 | * @return string The concatenated string | ||
687 | */ | ||
688 | function twig_join_filter($value, $glue = '') | ||
689 | { | ||
690 | if ($value instanceof Traversable) { | ||
691 | $value = iterator_to_array($value, false); | ||
692 | } | ||
693 | |||
694 | return implode($glue, (array) $value); | ||
695 | } | ||
696 | |||
697 | /** | ||
698 | * Splits the string into an array. | ||
699 | * | ||
700 | * <pre> | ||
701 | * {{ "one,two,three"|split(',') }} | ||
702 | * {# returns [one, two, three] #} | ||
703 | * | ||
704 | * {{ "one,two,three,four,five"|split(',', 3) }} | ||
705 | * {# returns [one, two, "three,four,five"] #} | ||
706 | * | ||
707 | * {{ "123"|split('') }} | ||
708 | * {# returns [1, 2, 3] #} | ||
709 | * | ||
710 | * {{ "aabbcc"|split('', 2) }} | ||
711 | * {# returns [aa, bb, cc] #} | ||
712 | * </pre> | ||
713 | * | ||
714 | * @param string $value A string | ||
715 | * @param string $delimiter The delimiter | ||
716 | * @param integer $limit The limit | ||
717 | * | ||
718 | * @return array The split string as an array | ||
719 | */ | ||
720 | function twig_split_filter($value, $delimiter, $limit = null) | ||
721 | { | ||
722 | if (empty($delimiter)) { | ||
723 | return str_split($value, null === $limit ? 1 : $limit); | ||
724 | } | ||
725 | |||
726 | return null === $limit ? explode($delimiter, $value) : explode($delimiter, $value, $limit); | ||
727 | } | ||
728 | |||
729 | // The '_default' filter is used internally to avoid using the ternary operator | ||
730 | // which costs a lot for big contexts (before PHP 5.4). So, on average, | ||
731 | // a function call is cheaper. | ||
732 | function _twig_default_filter($value, $default = '') | ||
733 | { | ||
734 | if (twig_test_empty($value)) { | ||
735 | return $default; | ||
736 | } | ||
737 | |||
738 | return $value; | ||
739 | } | ||
740 | |||
741 | /** | ||
742 | * Returns the keys for the given array. | ||
743 | * | ||
744 | * It is useful when you want to iterate over the keys of an array: | ||
745 | * | ||
746 | * <pre> | ||
747 | * {% for key in array|keys %} | ||
748 | * {# ... #} | ||
749 | * {% endfor %} | ||
750 | * </pre> | ||
751 | * | ||
752 | * @param array $array An array | ||
753 | * | ||
754 | * @return array The keys | ||
755 | */ | ||
756 | function twig_get_array_keys_filter($array) | ||
757 | { | ||
758 | if (is_object($array) && $array instanceof Traversable) { | ||
759 | return array_keys(iterator_to_array($array)); | ||
760 | } | ||
761 | |||
762 | if (!is_array($array)) { | ||
763 | return array(); | ||
764 | } | ||
765 | |||
766 | return array_keys($array); | ||
767 | } | ||
768 | |||
769 | /** | ||
770 | * Reverses a variable. | ||
771 | * | ||
772 | * @param Twig_Environment $env A Twig_Environment instance | ||
773 | * @param array|Traversable|string $item An array, a Traversable instance, or a string | ||
774 | * @param Boolean $preserveKeys Whether to preserve key or not | ||
775 | * | ||
776 | * @return mixed The reversed input | ||
777 | */ | ||
778 | function twig_reverse_filter(Twig_Environment $env, $item, $preserveKeys = false) | ||
779 | { | ||
780 | if (is_object($item) && $item instanceof Traversable) { | ||
781 | return array_reverse(iterator_to_array($item), $preserveKeys); | ||
782 | } | ||
783 | |||
784 | if (is_array($item)) { | ||
785 | return array_reverse($item, $preserveKeys); | ||
786 | } | ||
787 | |||
788 | if (null !== $charset = $env->getCharset()) { | ||
789 | $string = (string) $item; | ||
790 | |||
791 | if ('UTF-8' != $charset) { | ||
792 | $item = twig_convert_encoding($string, 'UTF-8', $charset); | ||
793 | } | ||
794 | |||
795 | preg_match_all('/./us', $item, $matches); | ||
796 | |||
797 | $string = implode('', array_reverse($matches[0])); | ||
798 | |||
799 | if ('UTF-8' != $charset) { | ||
800 | $string = twig_convert_encoding($string, $charset, 'UTF-8'); | ||
801 | } | ||
802 | |||
803 | return $string; | ||
804 | } | ||
805 | |||
806 | return strrev((string) $item); | ||
807 | } | ||
808 | |||
809 | /** | ||
810 | * Sorts an array. | ||
811 | * | ||
812 | * @param array $array An array | ||
813 | */ | ||
814 | function twig_sort_filter($array) | ||
815 | { | ||
816 | asort($array); | ||
817 | |||
818 | return $array; | ||
819 | } | ||
820 | |||
821 | /* used internally */ | ||
822 | function twig_in_filter($value, $compare) | ||
823 | { | ||
824 | if (is_array($compare)) { | ||
825 | return in_array($value, $compare, is_object($value)); | ||
826 | } elseif (is_string($compare)) { | ||
827 | if (!strlen($value)) { | ||
828 | return empty($compare); | ||
829 | } | ||
830 | |||
831 | return false !== strpos($compare, (string) $value); | ||
832 | } elseif ($compare instanceof Traversable) { | ||
833 | return in_array($value, iterator_to_array($compare, false), is_object($value)); | ||
834 | } | ||
835 | |||
836 | return false; | ||
837 | } | ||
838 | |||
839 | /** | ||
840 | * Escapes a string. | ||
841 | * | ||
842 | * @param Twig_Environment $env A Twig_Environment instance | ||
843 | * @param string $string The value to be escaped | ||
844 | * @param string $strategy The escaping strategy | ||
845 | * @param string $charset The charset | ||
846 | * @param Boolean $autoescape Whether the function is called by the auto-escaping feature (true) or by the developer (false) | ||
847 | */ | ||
848 | function twig_escape_filter(Twig_Environment $env, $string, $strategy = 'html', $charset = null, $autoescape = false) | ||
849 | { | ||
850 | if ($autoescape && $string instanceof Twig_Markup) { | ||
851 | return $string; | ||
852 | } | ||
853 | |||
854 | if (!is_string($string)) { | ||
855 | if (is_object($string) && method_exists($string, '__toString')) { | ||
856 | $string = (string) $string; | ||
857 | } else { | ||
858 | return $string; | ||
859 | } | ||
860 | } | ||
861 | |||
862 | if (null === $charset) { | ||
863 | $charset = $env->getCharset(); | ||
864 | } | ||
865 | |||
866 | switch ($strategy) { | ||
867 | case 'html': | ||
868 | // see http://php.net/htmlspecialchars | ||
869 | |||
870 | // Using a static variable to avoid initializing the array | ||
871 | // each time the function is called. Moving the declaration on the | ||
872 | // top of the function slow downs other escaping strategies. | ||
873 | static $htmlspecialcharsCharsets = array( | ||
874 | 'ISO-8859-1' => true, 'ISO8859-1' => true, | ||
875 | 'ISO-8859-15' => true, 'ISO8859-15' => true, | ||
876 | 'utf-8' => true, 'UTF-8' => true, | ||
877 | 'CP866' => true, 'IBM866' => true, '866' => true, | ||
878 | 'CP1251' => true, 'WINDOWS-1251' => true, 'WIN-1251' => true, | ||
879 | '1251' => true, | ||
880 | 'CP1252' => true, 'WINDOWS-1252' => true, '1252' => true, | ||
881 | 'KOI8-R' => true, 'KOI8-RU' => true, 'KOI8R' => true, | ||
882 | 'BIG5' => true, '950' => true, | ||
883 | 'GB2312' => true, '936' => true, | ||
884 | 'BIG5-HKSCS' => true, | ||
885 | 'SHIFT_JIS' => true, 'SJIS' => true, '932' => true, | ||
886 | 'EUC-JP' => true, 'EUCJP' => true, | ||
887 | 'ISO8859-5' => true, 'ISO-8859-5' => true, 'MACROMAN' => true, | ||
888 | ); | ||
889 | |||
890 | if (isset($htmlspecialcharsCharsets[$charset])) { | ||
891 | return htmlspecialchars($string, ENT_QUOTES | ENT_SUBSTITUTE, $charset); | ||
892 | } | ||
893 | |||
894 | if (isset($htmlspecialcharsCharsets[strtoupper($charset)])) { | ||
895 | // cache the lowercase variant for future iterations | ||
896 | $htmlspecialcharsCharsets[$charset] = true; | ||
897 | |||
898 | return htmlspecialchars($string, ENT_QUOTES | ENT_SUBSTITUTE, $charset); | ||
899 | } | ||
900 | |||
901 | $string = twig_convert_encoding($string, 'UTF-8', $charset); | ||
902 | $string = htmlspecialchars($string, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8'); | ||
903 | |||
904 | return twig_convert_encoding($string, $charset, 'UTF-8'); | ||
905 | |||
906 | case 'js': | ||
907 | // escape all non-alphanumeric characters | ||
908 | // into their \xHH or \uHHHH representations | ||
909 | if ('UTF-8' != $charset) { | ||
910 | $string = twig_convert_encoding($string, 'UTF-8', $charset); | ||
911 | } | ||
912 | |||
913 | if (0 == strlen($string) ? false : (1 == preg_match('/^./su', $string) ? false : true)) { | ||
914 | throw new Twig_Error_Runtime('The string to escape is not a valid UTF-8 string.'); | ||
915 | } | ||
916 | |||
917 | $string = preg_replace_callback('#[^a-zA-Z0-9,\._]#Su', '_twig_escape_js_callback', $string); | ||
918 | |||
919 | if ('UTF-8' != $charset) { | ||
920 | $string = twig_convert_encoding($string, $charset, 'UTF-8'); | ||
921 | } | ||
922 | |||
923 | return $string; | ||
924 | |||
925 | case 'css': | ||
926 | if ('UTF-8' != $charset) { | ||
927 | $string = twig_convert_encoding($string, 'UTF-8', $charset); | ||
928 | } | ||
929 | |||
930 | if (0 == strlen($string) ? false : (1 == preg_match('/^./su', $string) ? false : true)) { | ||
931 | throw new Twig_Error_Runtime('The string to escape is not a valid UTF-8 string.'); | ||
932 | } | ||
933 | |||
934 | $string = preg_replace_callback('#[^a-zA-Z0-9]#Su', '_twig_escape_css_callback', $string); | ||
935 | |||
936 | if ('UTF-8' != $charset) { | ||
937 | $string = twig_convert_encoding($string, $charset, 'UTF-8'); | ||
938 | } | ||
939 | |||
940 | return $string; | ||
941 | |||
942 | case 'html_attr': | ||
943 | if ('UTF-8' != $charset) { | ||
944 | $string = twig_convert_encoding($string, 'UTF-8', $charset); | ||
945 | } | ||
946 | |||
947 | if (0 == strlen($string) ? false : (1 == preg_match('/^./su', $string) ? false : true)) { | ||
948 | throw new Twig_Error_Runtime('The string to escape is not a valid UTF-8 string.'); | ||
949 | } | ||
950 | |||
951 | $string = preg_replace_callback('#[^a-zA-Z0-9,\.\-_]#Su', '_twig_escape_html_attr_callback', $string); | ||
952 | |||
953 | if ('UTF-8' != $charset) { | ||
954 | $string = twig_convert_encoding($string, $charset, 'UTF-8'); | ||
955 | } | ||
956 | |||
957 | return $string; | ||
958 | |||
959 | case 'url': | ||
960 | // hackish test to avoid version_compare that is much slower, this works unless PHP releases a 5.10.* | ||
961 | // at that point however PHP 5.2.* support can be removed | ||
962 | if (PHP_VERSION < '5.3.0') { | ||
963 | return str_replace('%7E', '~', rawurlencode($string)); | ||
964 | } | ||
965 | |||
966 | return rawurlencode($string); | ||
967 | |||
968 | default: | ||
969 | throw new Twig_Error_Runtime(sprintf('Invalid escaping strategy "%s" (valid ones: html, js, url, css, and html_attr).', $strategy)); | ||
970 | } | ||
971 | } | ||
972 | |||
973 | /* used internally */ | ||
974 | function twig_escape_filter_is_safe(Twig_Node $filterArgs) | ||
975 | { | ||
976 | foreach ($filterArgs as $arg) { | ||
977 | if ($arg instanceof Twig_Node_Expression_Constant) { | ||
978 | return array($arg->getAttribute('value')); | ||
979 | } | ||
980 | |||
981 | return array(); | ||
982 | } | ||
983 | |||
984 | return array('html'); | ||
985 | } | ||
986 | |||
987 | if (function_exists('mb_convert_encoding')) { | ||
988 | function twig_convert_encoding($string, $to, $from) | ||
989 | { | ||
990 | return mb_convert_encoding($string, $to, $from); | ||
991 | } | ||
992 | } elseif (function_exists('iconv')) { | ||
993 | function twig_convert_encoding($string, $to, $from) | ||
994 | { | ||
995 | return iconv($from, $to, $string); | ||
996 | } | ||
997 | } else { | ||
998 | function twig_convert_encoding($string, $to, $from) | ||
999 | { | ||
1000 | throw new Twig_Error_Runtime('No suitable convert encoding function (use UTF-8 as your encoding or install the iconv or mbstring extension).'); | ||
1001 | } | ||
1002 | } | ||
1003 | |||
1004 | function _twig_escape_js_callback($matches) | ||
1005 | { | ||
1006 | $char = $matches[0]; | ||
1007 | |||
1008 | // \xHH | ||
1009 | if (!isset($char[1])) { | ||
1010 | return '\\x'.strtoupper(substr('00'.bin2hex($char), -2)); | ||
1011 | } | ||
1012 | |||
1013 | // \uHHHH | ||
1014 | $char = twig_convert_encoding($char, 'UTF-16BE', 'UTF-8'); | ||
1015 | |||
1016 | return '\\u'.strtoupper(substr('0000'.bin2hex($char), -4)); | ||
1017 | } | ||
1018 | |||
1019 | function _twig_escape_css_callback($matches) | ||
1020 | { | ||
1021 | $char = $matches[0]; | ||
1022 | |||
1023 | // \xHH | ||
1024 | if (!isset($char[1])) { | ||
1025 | $hex = ltrim(strtoupper(bin2hex($char)), '0'); | ||
1026 | if (0 === strlen($hex)) { | ||
1027 | $hex = '0'; | ||
1028 | } | ||
1029 | |||
1030 | return '\\'.$hex.' '; | ||
1031 | } | ||
1032 | |||
1033 | // \uHHHH | ||
1034 | $char = twig_convert_encoding($char, 'UTF-16BE', 'UTF-8'); | ||
1035 | |||
1036 | return '\\'.ltrim(strtoupper(bin2hex($char)), '0').' '; | ||
1037 | } | ||
1038 | |||
1039 | /** | ||
1040 | * This function is adapted from code coming from Zend Framework. | ||
1041 | * | ||
1042 | * @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com) | ||
1043 | * @license http://framework.zend.com/license/new-bsd New BSD License | ||
1044 | */ | ||
1045 | function _twig_escape_html_attr_callback($matches) | ||
1046 | { | ||
1047 | /* | ||
1048 | * While HTML supports far more named entities, the lowest common denominator | ||
1049 | * has become HTML5's XML Serialisation which is restricted to the those named | ||
1050 | * entities that XML supports. Using HTML entities would result in this error: | ||
1051 | * XML Parsing Error: undefined entity | ||
1052 | */ | ||
1053 | static $entityMap = array( | ||
1054 | 34 => 'quot', /* quotation mark */ | ||
1055 | 38 => 'amp', /* ampersand */ | ||
1056 | 60 => 'lt', /* less-than sign */ | ||
1057 | 62 => 'gt', /* greater-than sign */ | ||
1058 | ); | ||
1059 | |||
1060 | $chr = $matches[0]; | ||
1061 | $ord = ord($chr); | ||
1062 | |||
1063 | /** | ||
1064 | * The following replaces characters undefined in HTML with the | ||
1065 | * hex entity for the Unicode replacement character. | ||
1066 | */ | ||
1067 | if (($ord <= 0x1f && $chr != "\t" && $chr != "\n" && $chr != "\r") || ($ord >= 0x7f && $ord <= 0x9f)) { | ||
1068 | return '�'; | ||
1069 | } | ||
1070 | |||
1071 | /** | ||
1072 | * Check if the current character to escape has a name entity we should | ||
1073 | * replace it with while grabbing the hex value of the character. | ||
1074 | */ | ||
1075 | if (strlen($chr) == 1) { | ||
1076 | $hex = strtoupper(substr('00'.bin2hex($chr), -2)); | ||
1077 | } else { | ||
1078 | $chr = twig_convert_encoding($chr, 'UTF-16BE', 'UTF-8'); | ||
1079 | $hex = strtoupper(substr('0000'.bin2hex($chr), -4)); | ||
1080 | } | ||
1081 | |||
1082 | $int = hexdec($hex); | ||
1083 | if (array_key_exists($int, $entityMap)) { | ||
1084 | return sprintf('&%s;', $entityMap[$int]); | ||
1085 | } | ||
1086 | |||
1087 | /** | ||
1088 | * Per OWASP recommendations, we'll use hex entities for any other | ||
1089 | * characters where a named entity does not exist. | ||
1090 | */ | ||
1091 | |||
1092 | return sprintf('&#x%s;', $hex); | ||
1093 | } | ||
1094 | |||
1095 | // add multibyte extensions if possible | ||
1096 | if (function_exists('mb_get_info')) { | ||
1097 | /** | ||
1098 | * Returns the length of a variable. | ||
1099 | * | ||
1100 | * @param Twig_Environment $env A Twig_Environment instance | ||
1101 | * @param mixed $thing A variable | ||
1102 | * | ||
1103 | * @return integer The length of the value | ||
1104 | */ | ||
1105 | function twig_length_filter(Twig_Environment $env, $thing) | ||
1106 | { | ||
1107 | return is_scalar($thing) ? mb_strlen($thing, $env->getCharset()) : count($thing); | ||
1108 | } | ||
1109 | |||
1110 | /** | ||
1111 | * Converts a string to uppercase. | ||
1112 | * | ||
1113 | * @param Twig_Environment $env A Twig_Environment instance | ||
1114 | * @param string $string A string | ||
1115 | * | ||
1116 | * @return string The uppercased string | ||
1117 | */ | ||
1118 | function twig_upper_filter(Twig_Environment $env, $string) | ||
1119 | { | ||
1120 | if (null !== ($charset = $env->getCharset())) { | ||
1121 | return mb_strtoupper($string, $charset); | ||
1122 | } | ||
1123 | |||
1124 | return strtoupper($string); | ||
1125 | } | ||
1126 | |||
1127 | /** | ||
1128 | * Converts a string to lowercase. | ||
1129 | * | ||
1130 | * @param Twig_Environment $env A Twig_Environment instance | ||
1131 | * @param string $string A string | ||
1132 | * | ||
1133 | * @return string The lowercased string | ||
1134 | */ | ||
1135 | function twig_lower_filter(Twig_Environment $env, $string) | ||
1136 | { | ||
1137 | if (null !== ($charset = $env->getCharset())) { | ||
1138 | return mb_strtolower($string, $charset); | ||
1139 | } | ||
1140 | |||
1141 | return strtolower($string); | ||
1142 | } | ||
1143 | |||
1144 | /** | ||
1145 | * Returns a titlecased string. | ||
1146 | * | ||
1147 | * @param Twig_Environment $env A Twig_Environment instance | ||
1148 | * @param string $string A string | ||
1149 | * | ||
1150 | * @return string The titlecased string | ||
1151 | */ | ||
1152 | function twig_title_string_filter(Twig_Environment $env, $string) | ||
1153 | { | ||
1154 | if (null !== ($charset = $env->getCharset())) { | ||
1155 | return mb_convert_case($string, MB_CASE_TITLE, $charset); | ||
1156 | } | ||
1157 | |||
1158 | return ucwords(strtolower($string)); | ||
1159 | } | ||
1160 | |||
1161 | /** | ||
1162 | * Returns a capitalized string. | ||
1163 | * | ||
1164 | * @param Twig_Environment $env A Twig_Environment instance | ||
1165 | * @param string $string A string | ||
1166 | * | ||
1167 | * @return string The capitalized string | ||
1168 | */ | ||
1169 | function twig_capitalize_string_filter(Twig_Environment $env, $string) | ||
1170 | { | ||
1171 | if (null !== ($charset = $env->getCharset())) { | ||
1172 | return mb_strtoupper(mb_substr($string, 0, 1, $charset), $charset). | ||
1173 | mb_strtolower(mb_substr($string, 1, mb_strlen($string, $charset), $charset), $charset); | ||
1174 | } | ||
1175 | |||
1176 | return ucfirst(strtolower($string)); | ||
1177 | } | ||
1178 | } | ||
1179 | // and byte fallback | ||
1180 | else { | ||
1181 | /** | ||
1182 | * Returns the length of a variable. | ||
1183 | * | ||
1184 | * @param Twig_Environment $env A Twig_Environment instance | ||
1185 | * @param mixed $thing A variable | ||
1186 | * | ||
1187 | * @return integer The length of the value | ||
1188 | */ | ||
1189 | function twig_length_filter(Twig_Environment $env, $thing) | ||
1190 | { | ||
1191 | return is_scalar($thing) ? strlen($thing) : count($thing); | ||
1192 | } | ||
1193 | |||
1194 | /** | ||
1195 | * Returns a titlecased string. | ||
1196 | * | ||
1197 | * @param Twig_Environment $env A Twig_Environment instance | ||
1198 | * @param string $string A string | ||
1199 | * | ||
1200 | * @return string The titlecased string | ||
1201 | */ | ||
1202 | function twig_title_string_filter(Twig_Environment $env, $string) | ||
1203 | { | ||
1204 | return ucwords(strtolower($string)); | ||
1205 | } | ||
1206 | |||
1207 | /** | ||
1208 | * Returns a capitalized string. | ||
1209 | * | ||
1210 | * @param Twig_Environment $env A Twig_Environment instance | ||
1211 | * @param string $string A string | ||
1212 | * | ||
1213 | * @return string The capitalized string | ||
1214 | */ | ||
1215 | function twig_capitalize_string_filter(Twig_Environment $env, $string) | ||
1216 | { | ||
1217 | return ucfirst(strtolower($string)); | ||
1218 | } | ||
1219 | } | ||
1220 | |||
1221 | /* used internally */ | ||
1222 | function twig_ensure_traversable($seq) | ||
1223 | { | ||
1224 | if ($seq instanceof Traversable || is_array($seq)) { | ||
1225 | return $seq; | ||
1226 | } | ||
1227 | |||
1228 | return array(); | ||
1229 | } | ||
1230 | |||
1231 | /** | ||
1232 | * Checks if a variable is empty. | ||
1233 | * | ||
1234 | * <pre> | ||
1235 | * {# evaluates to true if the foo variable is null, false, or the empty string #} | ||
1236 | * {% if foo is empty %} | ||
1237 | * {# ... #} | ||
1238 | * {% endif %} | ||
1239 | * </pre> | ||
1240 | * | ||
1241 | * @param mixed $value A variable | ||
1242 | * | ||
1243 | * @return Boolean true if the value is empty, false otherwise | ||
1244 | */ | ||
1245 | function twig_test_empty($value) | ||
1246 | { | ||
1247 | if ($value instanceof Countable) { | ||
1248 | return 0 == count($value); | ||
1249 | } | ||
1250 | |||
1251 | return '' === $value || false === $value || null === $value || array() === $value; | ||
1252 | } | ||
1253 | |||
1254 | /** | ||
1255 | * Checks if a variable is traversable. | ||
1256 | * | ||
1257 | * <pre> | ||
1258 | * {# evaluates to true if the foo variable is an array or a traversable object #} | ||
1259 | * {% if foo is traversable %} | ||
1260 | * {# ... #} | ||
1261 | * {% endif %} | ||
1262 | * </pre> | ||
1263 | * | ||
1264 | * @param mixed $value A variable | ||
1265 | * | ||
1266 | * @return Boolean true if the value is traversable | ||
1267 | */ | ||
1268 | function twig_test_iterable($value) | ||
1269 | { | ||
1270 | return $value instanceof Traversable || is_array($value); | ||
1271 | } | ||
1272 | |||
1273 | /** | ||
1274 | * Renders a template. | ||
1275 | * | ||
1276 | * @param string $template The template to render | ||
1277 | * @param array $variables The variables to pass to the template | ||
1278 | * @param Boolean $with_context Whether to pass the current context variables or not | ||
1279 | * @param Boolean $ignore_missing Whether to ignore missing templates or not | ||
1280 | * @param Boolean $sandboxed Whether to sandbox the template or not | ||
1281 | * | ||
1282 | * @return string The rendered template | ||
1283 | */ | ||
1284 | function twig_include(Twig_Environment $env, $context, $template, $variables = array(), $withContext = true, $ignoreMissing = false, $sandboxed = false) | ||
1285 | { | ||
1286 | if ($withContext) { | ||
1287 | $variables = array_merge($context, $variables); | ||
1288 | } | ||
1289 | |||
1290 | if ($isSandboxed = $sandboxed && $env->hasExtension('sandbox')) { | ||
1291 | $sandbox = $env->getExtension('sandbox'); | ||
1292 | if (!$alreadySandboxed = $sandbox->isSandboxed()) { | ||
1293 | $sandbox->enableSandbox(); | ||
1294 | } | ||
1295 | } | ||
1296 | |||
1297 | try { | ||
1298 | return $env->resolveTemplate($template)->render($variables); | ||
1299 | } catch (Twig_Error_Loader $e) { | ||
1300 | if (!$ignoreMissing) { | ||
1301 | throw $e; | ||
1302 | } | ||
1303 | } | ||
1304 | |||
1305 | if ($isSandboxed && !$alreadySandboxed) { | ||
1306 | $sandbox->disableSandbox(); | ||
1307 | } | ||
1308 | } | ||
1309 | |||
1310 | /** | ||
1311 | * Provides the ability to get constants from instances as well as class/global constants. | ||
1312 | * | ||
1313 | * @param string $constant The name of the constant | ||
1314 | * @param null|object $object The object to get the constant from | ||
1315 | * | ||
1316 | * @return string | ||
1317 | */ | ||
1318 | function twig_constant($constant, $object = null) | ||
1319 | { | ||
1320 | if (null !== $object) { | ||
1321 | $constant = get_class($object).'::'.$constant; | ||
1322 | } | ||
1323 | |||
1324 | return constant($constant); | ||
1325 | } | ||
1326 | |||
1327 | /** | ||
1328 | * Batches item. | ||
1329 | * | ||
1330 | * @param array $items An array of items | ||
1331 | * @param integer $size The size of the batch | ||
1332 | * @param string $fill A string to fill missing items | ||
1333 | * | ||
1334 | * @return array | ||
1335 | */ | ||
1336 | function twig_array_batch($items, $size, $fill = null) | ||
1337 | { | ||
1338 | if ($items instanceof Traversable) { | ||
1339 | $items = iterator_to_array($items, false); | ||
1340 | } | ||
1341 | |||
1342 | $size = ceil($size); | ||
1343 | |||
1344 | $result = array_chunk($items, $size, true); | ||
1345 | |||
1346 | if (null !== $fill) { | ||
1347 | $last = count($result) - 1; | ||
1348 | $result[$last] = array_merge( | ||
1349 | $result[$last], | ||
1350 | array_fill(0, $size - count($result[$last]), $fill) | ||
1351 | ); | ||
1352 | } | ||
1353 | |||
1354 | return $result; | ||
1355 | } | ||
diff --git a/vendor/twig/twig/lib/Twig/Extension/Debug.php b/vendor/twig/twig/lib/Twig/Extension/Debug.php new file mode 100644 index 00000000..e3a85bfe --- /dev/null +++ b/vendor/twig/twig/lib/Twig/Extension/Debug.php | |||
@@ -0,0 +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 | } | ||
diff --git a/vendor/twig/twig/lib/Twig/Extension/Escaper.php b/vendor/twig/twig/lib/Twig/Extension/Escaper.php new file mode 100644 index 00000000..c9a7f68e --- /dev/null +++ b/vendor/twig/twig/lib/Twig/Extension/Escaper.php | |||
@@ -0,0 +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 array 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 | } | ||
diff --git a/vendor/twig/twig/lib/Twig/Extension/Optimizer.php b/vendor/twig/twig/lib/Twig/Extension/Optimizer.php new file mode 100644 index 00000000..013fcb62 --- /dev/null +++ b/vendor/twig/twig/lib/Twig/Extension/Optimizer.php | |||
@@ -0,0 +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 | } | ||
diff --git a/vendor/twig/twig/lib/Twig/Extension/Sandbox.php b/vendor/twig/twig/lib/Twig/Extension/Sandbox.php new file mode 100644 index 00000000..bf76c11a --- /dev/null +++ b/vendor/twig/twig/lib/Twig/Extension/Sandbox.php | |||
@@ -0,0 +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 array 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 (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 | } | ||
diff --git a/vendor/twig/twig/lib/Twig/Extension/Staging.php b/vendor/twig/twig/lib/Twig/Extension/Staging.php new file mode 100644 index 00000000..8ab0f459 --- /dev/null +++ b/vendor/twig/twig/lib/Twig/Extension/Staging.php | |||
@@ -0,0 +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 | } | ||
diff --git a/vendor/twig/twig/lib/Twig/Extension/StringLoader.php b/vendor/twig/twig/lib/Twig/Extension/StringLoader.php new file mode 100644 index 00000000..20f3f994 --- /dev/null +++ b/vendor/twig/twig/lib/Twig/Extension/StringLoader.php | |||
@@ -0,0 +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 | static $loader; | ||
47 | |||
48 | if (null === $loader) { | ||
49 | $loader = new Twig_Loader_String(); | ||
50 | } | ||
51 | |||
52 | $current = $env->getLoader(); | ||
53 | $env->setLoader($loader); | ||
54 | try { | ||
55 | $template = $env->loadTemplate($template); | ||
56 | } catch (Exception $e) { | ||
57 | $env->setLoader($current); | ||
58 | |||
59 | throw $e; | ||
60 | } | ||
61 | $env->setLoader($current); | ||
62 | |||
63 | return $template; | ||
64 | } | ||
diff --git a/vendor/twig/twig/lib/Twig/ExtensionInterface.php b/vendor/twig/twig/lib/Twig/ExtensionInterface.php new file mode 100644 index 00000000..f189e9d9 --- /dev/null +++ b/vendor/twig/twig/lib/Twig/ExtensionInterface.php | |||
@@ -0,0 +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 array 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 | } | ||
diff --git a/vendor/twig/twig/lib/Twig/Filter.php b/vendor/twig/twig/lib/Twig/Filter.php new file mode 100644 index 00000000..5cfbb662 --- /dev/null +++ b/vendor/twig/twig/lib/Twig/Filter.php | |||
@@ -0,0 +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 | } | ||
diff --git a/vendor/twig/twig/lib/Twig/Filter/Function.php b/vendor/twig/twig/lib/Twig/Filter/Function.php new file mode 100644 index 00000000..ad374a55 --- /dev/null +++ b/vendor/twig/twig/lib/Twig/Filter/Function.php | |||
@@ -0,0 +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 | } | ||
diff --git a/vendor/twig/twig/lib/Twig/Filter/Method.php b/vendor/twig/twig/lib/Twig/Filter/Method.php new file mode 100644 index 00000000..63c8c3be --- /dev/null +++ b/vendor/twig/twig/lib/Twig/Filter/Method.php | |||
@@ -0,0 +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 | } | ||
diff --git a/vendor/twig/twig/lib/Twig/Filter/Node.php b/vendor/twig/twig/lib/Twig/Filter/Node.php new file mode 100644 index 00000000..8744c5e0 --- /dev/null +++ b/vendor/twig/twig/lib/Twig/Filter/Node.php | |||
@@ -0,0 +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 | } | ||
diff --git a/vendor/twig/twig/lib/Twig/FilterCallableInterface.php b/vendor/twig/twig/lib/Twig/FilterCallableInterface.php new file mode 100644 index 00000000..145534df --- /dev/null +++ b/vendor/twig/twig/lib/Twig/FilterCallableInterface.php | |||
@@ -0,0 +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 | } | ||
diff --git a/vendor/twig/twig/lib/Twig/FilterInterface.php b/vendor/twig/twig/lib/Twig/FilterInterface.php new file mode 100644 index 00000000..5319ecc9 --- /dev/null +++ b/vendor/twig/twig/lib/Twig/FilterInterface.php | |||
@@ -0,0 +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 | } | ||
diff --git a/vendor/twig/twig/lib/Twig/Function.php b/vendor/twig/twig/lib/Twig/Function.php new file mode 100644 index 00000000..b5ffb2b0 --- /dev/null +++ b/vendor/twig/twig/lib/Twig/Function.php | |||
@@ -0,0 +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 | } | ||
diff --git a/vendor/twig/twig/lib/Twig/Function/Function.php b/vendor/twig/twig/lib/Twig/Function/Function.php new file mode 100644 index 00000000..d1e1b96a --- /dev/null +++ b/vendor/twig/twig/lib/Twig/Function/Function.php | |||
@@ -0,0 +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 | } | ||
diff --git a/vendor/twig/twig/lib/Twig/Function/Method.php b/vendor/twig/twig/lib/Twig/Function/Method.php new file mode 100644 index 00000000..67039a95 --- /dev/null +++ b/vendor/twig/twig/lib/Twig/Function/Method.php | |||
@@ -0,0 +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 | } | ||
diff --git a/vendor/twig/twig/lib/Twig/Function/Node.php b/vendor/twig/twig/lib/Twig/Function/Node.php new file mode 100644 index 00000000..06a0d0db --- /dev/null +++ b/vendor/twig/twig/lib/Twig/Function/Node.php | |||
@@ -0,0 +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 | } | ||
diff --git a/vendor/twig/twig/lib/Twig/FunctionCallableInterface.php b/vendor/twig/twig/lib/Twig/FunctionCallableInterface.php new file mode 100644 index 00000000..0aab4f5e --- /dev/null +++ b/vendor/twig/twig/lib/Twig/FunctionCallableInterface.php | |||
@@ -0,0 +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 | } | ||
diff --git a/vendor/twig/twig/lib/Twig/FunctionInterface.php b/vendor/twig/twig/lib/Twig/FunctionInterface.php new file mode 100644 index 00000000..67f4f89c --- /dev/null +++ b/vendor/twig/twig/lib/Twig/FunctionInterface.php | |||
@@ -0,0 +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 | } | ||
diff --git a/vendor/twig/twig/lib/Twig/Lexer.php b/vendor/twig/twig/lib/Twig/Lexer.php new file mode 100644 index 00000000..000b038e --- /dev/null +++ b/vendor/twig/twig/lib/Twig/Lexer.php | |||
@@ -0,0 +1,408 @@ | |||
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 | * Tokenizes a source code. | ||
77 | * | ||
78 | * @param string $code The source code | ||
79 | * @param string $filename A unique identifier for the source code | ||
80 | * | ||
81 | * @return Twig_TokenStream A token stream instance | ||
82 | */ | ||
83 | public function tokenize($code, $filename = null) | ||
84 | { | ||
85 | if (function_exists('mb_internal_encoding') && ((int) ini_get('mbstring.func_overload')) & 2) { | ||
86 | $mbEncoding = mb_internal_encoding(); | ||
87 | mb_internal_encoding('ASCII'); | ||
88 | } | ||
89 | |||
90 | $this->code = str_replace(array("\r\n", "\r"), "\n", $code); | ||
91 | $this->filename = $filename; | ||
92 | $this->cursor = 0; | ||
93 | $this->lineno = 1; | ||
94 | $this->end = strlen($this->code); | ||
95 | $this->tokens = array(); | ||
96 | $this->state = self::STATE_DATA; | ||
97 | $this->states = array(); | ||
98 | $this->brackets = array(); | ||
99 | $this->position = -1; | ||
100 | |||
101 | // find all token starts in one go | ||
102 | preg_match_all($this->regexes['lex_tokens_start'], $this->code, $matches, PREG_OFFSET_CAPTURE); | ||
103 | $this->positions = $matches; | ||
104 | |||
105 | while ($this->cursor < $this->end) { | ||
106 | // dispatch to the lexing functions depending | ||
107 | // on the current state | ||
108 | switch ($this->state) { | ||
109 | case self::STATE_DATA: | ||
110 | $this->lexData(); | ||
111 | break; | ||
112 | |||
113 | case self::STATE_BLOCK: | ||
114 | $this->lexBlock(); | ||
115 | break; | ||
116 | |||
117 | case self::STATE_VAR: | ||
118 | $this->lexVar(); | ||
119 | break; | ||
120 | |||
121 | case self::STATE_STRING: | ||
122 | $this->lexString(); | ||
123 | break; | ||
124 | |||
125 | case self::STATE_INTERPOLATION: | ||
126 | $this->lexInterpolation(); | ||
127 | break; | ||
128 | } | ||
129 | } | ||
130 | |||
131 | $this->pushToken(Twig_Token::EOF_TYPE); | ||
132 | |||
133 | if (!empty($this->brackets)) { | ||
134 | list($expect, $lineno) = array_pop($this->brackets); | ||
135 | throw new Twig_Error_Syntax(sprintf('Unclosed "%s"', $expect), $lineno, $this->filename); | ||
136 | } | ||
137 | |||
138 | if (isset($mbEncoding)) { | ||
139 | mb_internal_encoding($mbEncoding); | ||
140 | } | ||
141 | |||
142 | return new Twig_TokenStream($this->tokens, $this->filename); | ||
143 | } | ||
144 | |||
145 | protected function lexData() | ||
146 | { | ||
147 | // if no matches are left we return the rest of the template as simple text token | ||
148 | if ($this->position == count($this->positions[0]) - 1) { | ||
149 | $this->pushToken(Twig_Token::TEXT_TYPE, substr($this->code, $this->cursor)); | ||
150 | $this->cursor = $this->end; | ||
151 | |||
152 | return; | ||
153 | } | ||
154 | |||
155 | // Find the first token after the current cursor | ||
156 | $position = $this->positions[0][++$this->position]; | ||
157 | while ($position[1] < $this->cursor) { | ||
158 | if ($this->position == count($this->positions[0]) - 1) { | ||
159 | return; | ||
160 | } | ||
161 | $position = $this->positions[0][++$this->position]; | ||
162 | } | ||
163 | |||
164 | // push the template text first | ||
165 | $text = $textContent = substr($this->code, $this->cursor, $position[1] - $this->cursor); | ||
166 | if (isset($this->positions[2][$this->position][0])) { | ||
167 | $text = rtrim($text); | ||
168 | } | ||
169 | $this->pushToken(Twig_Token::TEXT_TYPE, $text); | ||
170 | $this->moveCursor($textContent.$position[0]); | ||
171 | |||
172 | switch ($this->positions[1][$this->position][0]) { | ||
173 | case $this->options['tag_comment'][0]: | ||
174 | $this->lexComment(); | ||
175 | break; | ||
176 | |||
177 | case $this->options['tag_block'][0]: | ||
178 | // raw data? | ||
179 | if (preg_match($this->regexes['lex_block_raw'], $this->code, $match, null, $this->cursor)) { | ||
180 | $this->moveCursor($match[0]); | ||
181 | $this->lexRawData($match[1]); | ||
182 | // {% line \d+ %} | ||
183 | } elseif (preg_match($this->regexes['lex_block_line'], $this->code, $match, null, $this->cursor)) { | ||
184 | $this->moveCursor($match[0]); | ||
185 | $this->lineno = (int) $match[1]; | ||
186 | } else { | ||
187 | $this->pushToken(Twig_Token::BLOCK_START_TYPE); | ||
188 | $this->pushState(self::STATE_BLOCK); | ||
189 | $this->currentVarBlockLine = $this->lineno; | ||
190 | } | ||
191 | break; | ||
192 | |||
193 | case $this->options['tag_variable'][0]: | ||
194 | $this->pushToken(Twig_Token::VAR_START_TYPE); | ||
195 | $this->pushState(self::STATE_VAR); | ||
196 | $this->currentVarBlockLine = $this->lineno; | ||
197 | break; | ||
198 | } | ||
199 | } | ||
200 | |||
201 | protected function lexBlock() | ||
202 | { | ||
203 | if (empty($this->brackets) && preg_match($this->regexes['lex_block'], $this->code, $match, null, $this->cursor)) { | ||
204 | $this->pushToken(Twig_Token::BLOCK_END_TYPE); | ||
205 | $this->moveCursor($match[0]); | ||
206 | $this->popState(); | ||
207 | } else { | ||
208 | $this->lexExpression(); | ||
209 | } | ||
210 | } | ||
211 | |||
212 | protected function lexVar() | ||
213 | { | ||
214 | if (empty($this->brackets) && preg_match($this->regexes['lex_var'], $this->code, $match, null, $this->cursor)) { | ||
215 | $this->pushToken(Twig_Token::VAR_END_TYPE); | ||
216 | $this->moveCursor($match[0]); | ||
217 | $this->popState(); | ||
218 | } else { | ||
219 | $this->lexExpression(); | ||
220 | } | ||
221 | } | ||
222 | |||
223 | protected function lexExpression() | ||
224 | { | ||
225 | // whitespace | ||
226 | if (preg_match('/\s+/A', $this->code, $match, null, $this->cursor)) { | ||
227 | $this->moveCursor($match[0]); | ||
228 | |||
229 | if ($this->cursor >= $this->end) { | ||
230 | throw new Twig_Error_Syntax(sprintf('Unclosed "%s"', $this->state === self::STATE_BLOCK ? 'block' : 'variable'), $this->currentVarBlockLine, $this->filename); | ||
231 | } | ||
232 | } | ||
233 | |||
234 | // operators | ||
235 | if (preg_match($this->regexes['operator'], $this->code, $match, null, $this->cursor)) { | ||
236 | $this->pushToken(Twig_Token::OPERATOR_TYPE, $match[0]); | ||
237 | $this->moveCursor($match[0]); | ||
238 | } | ||
239 | // names | ||
240 | elseif (preg_match(self::REGEX_NAME, $this->code, $match, null, $this->cursor)) { | ||
241 | $this->pushToken(Twig_Token::NAME_TYPE, $match[0]); | ||
242 | $this->moveCursor($match[0]); | ||
243 | } | ||
244 | // numbers | ||
245 | elseif (preg_match(self::REGEX_NUMBER, $this->code, $match, null, $this->cursor)) { | ||
246 | $number = (float) $match[0]; // floats | ||
247 | if (ctype_digit($match[0]) && $number <= PHP_INT_MAX) { | ||
248 | $number = (int) $match[0]; // integers lower than the maximum | ||
249 | } | ||
250 | $this->pushToken(Twig_Token::NUMBER_TYPE, $number); | ||
251 | $this->moveCursor($match[0]); | ||
252 | } | ||
253 | // punctuation | ||
254 | elseif (false !== strpos(self::PUNCTUATION, $this->code[$this->cursor])) { | ||
255 | // opening bracket | ||
256 | if (false !== strpos('([{', $this->code[$this->cursor])) { | ||
257 | $this->brackets[] = array($this->code[$this->cursor], $this->lineno); | ||
258 | } | ||
259 | // closing bracket | ||
260 | elseif (false !== strpos(')]}', $this->code[$this->cursor])) { | ||
261 | if (empty($this->brackets)) { | ||
262 | throw new Twig_Error_Syntax(sprintf('Unexpected "%s"', $this->code[$this->cursor]), $this->lineno, $this->filename); | ||
263 | } | ||
264 | |||
265 | list($expect, $lineno) = array_pop($this->brackets); | ||
266 | if ($this->code[$this->cursor] != strtr($expect, '([{', ')]}')) { | ||
267 | throw new Twig_Error_Syntax(sprintf('Unclosed "%s"', $expect), $lineno, $this->filename); | ||
268 | } | ||
269 | } | ||
270 | |||
271 | $this->pushToken(Twig_Token::PUNCTUATION_TYPE, $this->code[$this->cursor]); | ||
272 | ++$this->cursor; | ||
273 | } | ||
274 | // strings | ||
275 | elseif (preg_match(self::REGEX_STRING, $this->code, $match, null, $this->cursor)) { | ||
276 | $this->pushToken(Twig_Token::STRING_TYPE, stripcslashes(substr($match[0], 1, -1))); | ||
277 | $this->moveCursor($match[0]); | ||
278 | } | ||
279 | // opening double quoted string | ||
280 | elseif (preg_match(self::REGEX_DQ_STRING_DELIM, $this->code, $match, null, $this->cursor)) { | ||
281 | $this->brackets[] = array('"', $this->lineno); | ||
282 | $this->pushState(self::STATE_STRING); | ||
283 | $this->moveCursor($match[0]); | ||
284 | } | ||
285 | // unlexable | ||
286 | else { | ||
287 | throw new Twig_Error_Syntax(sprintf('Unexpected character "%s"', $this->code[$this->cursor]), $this->lineno, $this->filename); | ||
288 | } | ||
289 | } | ||
290 | |||
291 | protected function lexRawData($tag) | ||
292 | { | ||
293 | if (!preg_match(str_replace('%s', $tag, $this->regexes['lex_raw_data']), $this->code, $match, PREG_OFFSET_CAPTURE, $this->cursor)) { | ||
294 | throw new Twig_Error_Syntax(sprintf('Unexpected end of file: Unclosed "%s" block', $tag), $this->lineno, $this->filename); | ||
295 | } | ||
296 | |||
297 | $text = substr($this->code, $this->cursor, $match[0][1] - $this->cursor); | ||
298 | $this->moveCursor($text.$match[0][0]); | ||
299 | |||
300 | if (false !== strpos($match[1][0], $this->options['whitespace_trim'])) { | ||
301 | $text = rtrim($text); | ||
302 | } | ||
303 | |||
304 | $this->pushToken(Twig_Token::TEXT_TYPE, $text); | ||
305 | } | ||
306 | |||
307 | protected function lexComment() | ||
308 | { | ||
309 | if (!preg_match($this->regexes['lex_comment'], $this->code, $match, PREG_OFFSET_CAPTURE, $this->cursor)) { | ||
310 | throw new Twig_Error_Syntax('Unclosed comment', $this->lineno, $this->filename); | ||
311 | } | ||
312 | |||
313 | $this->moveCursor(substr($this->code, $this->cursor, $match[0][1] - $this->cursor).$match[0][0]); | ||
314 | } | ||
315 | |||
316 | protected function lexString() | ||
317 | { | ||
318 | if (preg_match($this->regexes['interpolation_start'], $this->code, $match, null, $this->cursor)) { | ||
319 | $this->brackets[] = array($this->options['interpolation'][0], $this->lineno); | ||
320 | $this->pushToken(Twig_Token::INTERPOLATION_START_TYPE); | ||
321 | $this->moveCursor($match[0]); | ||
322 | $this->pushState(self::STATE_INTERPOLATION); | ||
323 | |||
324 | } elseif (preg_match(self::REGEX_DQ_STRING_PART, $this->code, $match, null, $this->cursor) && strlen($match[0]) > 0) { | ||
325 | $this->pushToken(Twig_Token::STRING_TYPE, stripcslashes($match[0])); | ||
326 | $this->moveCursor($match[0]); | ||
327 | |||
328 | } elseif (preg_match(self::REGEX_DQ_STRING_DELIM, $this->code, $match, null, $this->cursor)) { | ||
329 | |||
330 | list($expect, $lineno) = array_pop($this->brackets); | ||
331 | if ($this->code[$this->cursor] != '"') { | ||
332 | throw new Twig_Error_Syntax(sprintf('Unclosed "%s"', $expect), $lineno, $this->filename); | ||
333 | } | ||
334 | |||
335 | $this->popState(); | ||
336 | ++$this->cursor; | ||
337 | } | ||
338 | } | ||
339 | |||
340 | protected function lexInterpolation() | ||
341 | { | ||
342 | $bracket = end($this->brackets); | ||
343 | if ($this->options['interpolation'][0] === $bracket[0] && preg_match($this->regexes['interpolation_end'], $this->code, $match, null, $this->cursor)) { | ||
344 | array_pop($this->brackets); | ||
345 | $this->pushToken(Twig_Token::INTERPOLATION_END_TYPE); | ||
346 | $this->moveCursor($match[0]); | ||
347 | $this->popState(); | ||
348 | } else { | ||
349 | $this->lexExpression(); | ||
350 | } | ||
351 | } | ||
352 | |||
353 | protected function pushToken($type, $value = '') | ||
354 | { | ||
355 | // do not push empty text tokens | ||
356 | if (Twig_Token::TEXT_TYPE === $type && '' === $value) { | ||
357 | return; | ||
358 | } | ||
359 | |||
360 | $this->tokens[] = new Twig_Token($type, $value, $this->lineno); | ||
361 | } | ||
362 | |||
363 | protected function moveCursor($text) | ||
364 | { | ||
365 | $this->cursor += strlen($text); | ||
366 | $this->lineno += substr_count($text, "\n"); | ||
367 | } | ||
368 | |||
369 | protected function getOperatorRegex() | ||
370 | { | ||
371 | $operators = array_merge( | ||
372 | array('='), | ||
373 | array_keys($this->env->getUnaryOperators()), | ||
374 | array_keys($this->env->getBinaryOperators()) | ||
375 | ); | ||
376 | |||
377 | $operators = array_combine($operators, array_map('strlen', $operators)); | ||
378 | arsort($operators); | ||
379 | |||
380 | $regex = array(); | ||
381 | foreach ($operators as $operator => $length) { | ||
382 | // an operator that ends with a character must be followed by | ||
383 | // a whitespace or a parenthesis | ||
384 | if (ctype_alpha($operator[$length - 1])) { | ||
385 | $regex[] = preg_quote($operator, '/').'(?=[\s()])'; | ||
386 | } else { | ||
387 | $regex[] = preg_quote($operator, '/'); | ||
388 | } | ||
389 | } | ||
390 | |||
391 | return '/'.implode('|', $regex).'/A'; | ||
392 | } | ||
393 | |||
394 | protected function pushState($state) | ||
395 | { | ||
396 | $this->states[] = $this->state; | ||
397 | $this->state = $state; | ||
398 | } | ||
399 | |||
400 | protected function popState() | ||
401 | { | ||
402 | if (0 === count($this->states)) { | ||
403 | throw new Exception('Cannot pop state without a previous state'); | ||
404 | } | ||
405 | |||
406 | $this->state = array_pop($this->states); | ||
407 | } | ||
408 | } | ||
diff --git a/vendor/twig/twig/lib/Twig/LexerInterface.php b/vendor/twig/twig/lib/Twig/LexerInterface.php new file mode 100644 index 00000000..4b83f81b --- /dev/null +++ b/vendor/twig/twig/lib/Twig/LexerInterface.php | |||
@@ -0,0 +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 | * Interface implemented by lexer classes. | ||
14 | * | ||
15 | * @author Fabien Potencier <fabien@symfony.com> | ||
16 | * @deprecated since 1.12 (to be removed in 2.0) | ||
17 | */ | ||
18 | interface Twig_LexerInterface | ||
19 | { | ||
20 | /** | ||
21 | * Tokenizes a source code. | ||
22 | * | ||
23 | * @param string $code The source code | ||
24 | * @param string $filename A unique identifier for the source code | ||
25 | * | ||
26 | * @return Twig_TokenStream A token stream instance | ||
27 | */ | ||
28 | public function tokenize($code, $filename = null); | ||
29 | } | ||
diff --git a/vendor/twig/twig/lib/Twig/Loader/Array.php b/vendor/twig/twig/lib/Twig/Loader/Array.php new file mode 100644 index 00000000..89087aea --- /dev/null +++ b/vendor/twig/twig/lib/Twig/Loader/Array.php | |||
@@ -0,0 +1,98 @@ | |||
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; | ||
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 = array(); | ||
36 | foreach ($templates as $name => $template) { | ||
37 | $this->templates[$name] = $template; | ||
38 | } | ||
39 | } | ||
40 | |||
41 | /** | ||
42 | * Adds or overrides a template. | ||
43 | * | ||
44 | * @param string $name The template name | ||
45 | * @param string $template The template source | ||
46 | */ | ||
47 | public function setTemplate($name, $template) | ||
48 | { | ||
49 | $this->templates[(string) $name] = $template; | ||
50 | } | ||
51 | |||
52 | /** | ||
53 | * {@inheritdoc} | ||
54 | */ | ||
55 | public function getSource($name) | ||
56 | { | ||
57 | $name = (string) $name; | ||
58 | if (!isset($this->templates[$name])) { | ||
59 | throw new Twig_Error_Loader(sprintf('Template "%s" is not defined.', $name)); | ||
60 | } | ||
61 | |||
62 | return $this->templates[$name]; | ||
63 | } | ||
64 | |||
65 | /** | ||
66 | * {@inheritdoc} | ||
67 | */ | ||
68 | public function exists($name) | ||
69 | { | ||
70 | return isset($this->templates[(string) $name]); | ||
71 | } | ||
72 | |||
73 | /** | ||
74 | * {@inheritdoc} | ||
75 | */ | ||
76 | public function getCacheKey($name) | ||
77 | { | ||
78 | $name = (string) $name; | ||
79 | if (!isset($this->templates[$name])) { | ||
80 | throw new Twig_Error_Loader(sprintf('Template "%s" is not defined.', $name)); | ||
81 | } | ||
82 | |||
83 | return $this->templates[$name]; | ||
84 | } | ||
85 | |||
86 | /** | ||
87 | * {@inheritdoc} | ||
88 | */ | ||
89 | public function isFresh($name, $time) | ||
90 | { | ||
91 | $name = (string) $name; | ||
92 | if (!isset($this->templates[$name])) { | ||
93 | throw new Twig_Error_Loader(sprintf('Template "%s" is not defined.', $name)); | ||
94 | } | ||
95 | |||
96 | return true; | ||
97 | } | ||
98 | } | ||
diff --git a/vendor/twig/twig/lib/Twig/Loader/Chain.php b/vendor/twig/twig/lib/Twig/Loader/Chain.php new file mode 100644 index 00000000..1f1cf065 --- /dev/null +++ b/vendor/twig/twig/lib/Twig/Loader/Chain.php | |||
@@ -0,0 +1,139 @@ | |||
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; | ||
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 | $this->loaders = array(); | ||
30 | foreach ($loaders as $loader) { | ||
31 | $this->addLoader($loader); | ||
32 | } | ||
33 | } | ||
34 | |||
35 | /** | ||
36 | * Adds a loader instance. | ||
37 | * | ||
38 | * @param Twig_LoaderInterface $loader A Loader instance | ||
39 | */ | ||
40 | public function addLoader(Twig_LoaderInterface $loader) | ||
41 | { | ||
42 | $this->loaders[] = $loader; | ||
43 | $this->hasSourceCache = array(); | ||
44 | } | ||
45 | |||
46 | /** | ||
47 | * {@inheritdoc} | ||
48 | */ | ||
49 | public function getSource($name) | ||
50 | { | ||
51 | $exceptions = array(); | ||
52 | foreach ($this->loaders as $loader) { | ||
53 | if ($loader instanceof Twig_ExistsLoaderInterface && !$loader->exists($name)) { | ||
54 | continue; | ||
55 | } | ||
56 | |||
57 | try { | ||
58 | return $loader->getSource($name); | ||
59 | } catch (Twig_Error_Loader $e) { | ||
60 | $exceptions[] = $e->getMessage(); | ||
61 | } | ||
62 | } | ||
63 | |||
64 | throw new Twig_Error_Loader(sprintf('Template "%s" is not defined (%s).', $name, implode(', ', $exceptions))); | ||
65 | } | ||
66 | |||
67 | /** | ||
68 | * {@inheritdoc} | ||
69 | */ | ||
70 | public function exists($name) | ||
71 | { | ||
72 | $name = (string) $name; | ||
73 | |||
74 | if (isset($this->hasSourceCache[$name])) { | ||
75 | return $this->hasSourceCache[$name]; | ||
76 | } | ||
77 | |||
78 | foreach ($this->loaders as $loader) { | ||
79 | if ($loader instanceof Twig_ExistsLoaderInterface) { | ||
80 | if ($loader->exists($name)) { | ||
81 | return $this->hasSourceCache[$name] = true; | ||
82 | } | ||
83 | |||
84 | continue; | ||
85 | } | ||
86 | |||
87 | try { | ||
88 | $loader->getSource($name); | ||
89 | |||
90 | return $this->hasSourceCache[$name] = true; | ||
91 | } catch (Twig_Error_Loader $e) { | ||
92 | } | ||
93 | } | ||
94 | |||
95 | return $this->hasSourceCache[$name] = false; | ||
96 | } | ||
97 | |||
98 | /** | ||
99 | * {@inheritdoc} | ||
100 | */ | ||
101 | public function getCacheKey($name) | ||
102 | { | ||
103 | $exceptions = array(); | ||
104 | foreach ($this->loaders as $loader) { | ||
105 | if ($loader instanceof Twig_ExistsLoaderInterface && !$loader->exists($name)) { | ||
106 | continue; | ||
107 | } | ||
108 | |||
109 | try { | ||
110 | return $loader->getCacheKey($name); | ||
111 | } catch (Twig_Error_Loader $e) { | ||
112 | $exceptions[] = get_class($loader).': '.$e->getMessage(); | ||
113 | } | ||
114 | } | ||
115 | |||
116 | throw new Twig_Error_Loader(sprintf('Template "%s" is not defined (%s).', $name, implode(' ', $exceptions))); | ||
117 | } | ||
118 | |||
119 | /** | ||
120 | * {@inheritdoc} | ||
121 | */ | ||
122 | public function isFresh($name, $time) | ||
123 | { | ||
124 | $exceptions = array(); | ||
125 | foreach ($this->loaders as $loader) { | ||
126 | if ($loader instanceof Twig_ExistsLoaderInterface && !$loader->exists($name)) { | ||
127 | continue; | ||
128 | } | ||
129 | |||
130 | try { | ||
131 | return $loader->isFresh($name, $time); | ||
132 | } catch (Twig_Error_Loader $e) { | ||
133 | $exceptions[] = get_class($loader).': '.$e->getMessage(); | ||
134 | } | ||
135 | } | ||
136 | |||
137 | throw new Twig_Error_Loader(sprintf('Template "%s" is not defined (%s).', $name, implode(' ', $exceptions))); | ||
138 | } | ||
139 | } | ||
diff --git a/vendor/twig/twig/lib/Twig/Loader/Filesystem.php b/vendor/twig/twig/lib/Twig/Loader/Filesystem.php new file mode 100644 index 00000000..d47781ab --- /dev/null +++ b/vendor/twig/twig/lib/Twig/Loader/Filesystem.php | |||
@@ -0,0 +1,226 @@ | |||
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; | ||
23 | protected $cache; | ||
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 = (string) $name; | ||
147 | if (isset($this->cache[$name])) { | ||
148 | return true; | ||
149 | } | ||
150 | |||
151 | try { | ||
152 | $this->findTemplate($name); | ||
153 | |||
154 | return true; | ||
155 | } catch (Twig_Error_Loader $exception) { | ||
156 | return false; | ||
157 | } | ||
158 | } | ||
159 | |||
160 | /** | ||
161 | * {@inheritdoc} | ||
162 | */ | ||
163 | public function isFresh($name, $time) | ||
164 | { | ||
165 | return filemtime($this->findTemplate($name)) <= $time; | ||
166 | } | ||
167 | |||
168 | protected function findTemplate($name) | ||
169 | { | ||
170 | $name = (string) $name; | ||
171 | |||
172 | // normalize name | ||
173 | $name = preg_replace('#/{2,}#', '/', strtr($name, '\\', '/')); | ||
174 | |||
175 | if (isset($this->cache[$name])) { | ||
176 | return $this->cache[$name]; | ||
177 | } | ||
178 | |||
179 | $this->validateName($name); | ||
180 | |||
181 | $namespace = self::MAIN_NAMESPACE; | ||
182 | if (isset($name[0]) && '@' == $name[0]) { | ||
183 | if (false === $pos = strpos($name, '/')) { | ||
184 | throw new Twig_Error_Loader(sprintf('Malformed namespaced template name "%s" (expecting "@namespace/template_name").', $name)); | ||
185 | } | ||
186 | |||
187 | $namespace = substr($name, 1, $pos - 1); | ||
188 | |||
189 | $name = substr($name, $pos + 1); | ||
190 | } | ||
191 | |||
192 | if (!isset($this->paths[$namespace])) { | ||
193 | throw new Twig_Error_Loader(sprintf('There are no registered paths for namespace "%s".', $namespace)); | ||
194 | } | ||
195 | |||
196 | foreach ($this->paths[$namespace] as $path) { | ||
197 | if (is_file($path.'/'.$name)) { | ||
198 | return $this->cache[$name] = $path.'/'.$name; | ||
199 | } | ||
200 | } | ||
201 | |||
202 | throw new Twig_Error_Loader(sprintf('Unable to find template "%s" (looked into: %s).', $name, implode(', ', $this->paths[$namespace]))); | ||
203 | } | ||
204 | |||
205 | protected function validateName($name) | ||
206 | { | ||
207 | if (false !== strpos($name, "\0")) { | ||
208 | throw new Twig_Error_Loader('A template name cannot contain NUL bytes.'); | ||
209 | } | ||
210 | |||
211 | $name = ltrim($name, '/'); | ||
212 | $parts = explode('/', $name); | ||
213 | $level = 0; | ||
214 | foreach ($parts as $part) { | ||
215 | if ('..' === $part) { | ||
216 | --$level; | ||
217 | } elseif ('.' !== $part) { | ||
218 | ++$level; | ||
219 | } | ||
220 | |||
221 | if ($level < 0) { | ||
222 | throw new Twig_Error_Loader(sprintf('Looks like you try to load a template outside configured directories (%s).', $name)); | ||
223 | } | ||
224 | } | ||
225 | } | ||
226 | } | ||
diff --git a/vendor/twig/twig/lib/Twig/Loader/String.php b/vendor/twig/twig/lib/Twig/Loader/String.php new file mode 100644 index 00000000..8ad9856c --- /dev/null +++ b/vendor/twig/twig/lib/Twig/Loader/String.php | |||
@@ -0,0 +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 | } | ||
diff --git a/vendor/twig/twig/lib/Twig/LoaderInterface.php b/vendor/twig/twig/lib/Twig/LoaderInterface.php new file mode 100644 index 00000000..927786d1 --- /dev/null +++ b/vendor/twig/twig/lib/Twig/LoaderInterface.php | |||
@@ -0,0 +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 Boolean 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 | } | ||
diff --git a/vendor/twig/twig/lib/Twig/Markup.php b/vendor/twig/twig/lib/Twig/Markup.php new file mode 100644 index 00000000..69871fcb --- /dev/null +++ b/vendor/twig/twig/lib/Twig/Markup.php | |||
@@ -0,0 +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 | } | ||
diff --git a/vendor/twig/twig/lib/Twig/Node.php b/vendor/twig/twig/lib/Twig/Node.php new file mode 100644 index 00000000..931b4635 --- /dev/null +++ b/vendor/twig/twig/lib/Twig/Node.php | |||
@@ -0,0 +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 integer $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 Boolean 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 Boolean 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 | } | ||
diff --git a/vendor/twig/twig/lib/Twig/Node/AutoEscape.php b/vendor/twig/twig/lib/Twig/Node/AutoEscape.php new file mode 100644 index 00000000..8f190e0b --- /dev/null +++ b/vendor/twig/twig/lib/Twig/Node/AutoEscape.php | |||
@@ -0,0 +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 | } | ||
diff --git a/vendor/twig/twig/lib/Twig/Node/Block.php b/vendor/twig/twig/lib/Twig/Node/Block.php new file mode 100644 index 00000000..50eb67ed --- /dev/null +++ b/vendor/twig/twig/lib/Twig/Node/Block.php | |||
@@ -0,0 +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 | } | ||
diff --git a/vendor/twig/twig/lib/Twig/Node/BlockReference.php b/vendor/twig/twig/lib/Twig/Node/BlockReference.php new file mode 100644 index 00000000..013e369e --- /dev/null +++ b/vendor/twig/twig/lib/Twig/Node/BlockReference.php | |||
@@ -0,0 +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 | } | ||
diff --git a/vendor/twig/twig/lib/Twig/Node/Body.php b/vendor/twig/twig/lib/Twig/Node/Body.php new file mode 100644 index 00000000..3ffb1342 --- /dev/null +++ b/vendor/twig/twig/lib/Twig/Node/Body.php | |||
@@ -0,0 +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 | } | ||
diff --git a/vendor/twig/twig/lib/Twig/Node/Do.php b/vendor/twig/twig/lib/Twig/Node/Do.php new file mode 100644 index 00000000..c528066b --- /dev/null +++ b/vendor/twig/twig/lib/Twig/Node/Do.php | |||
@@ -0,0 +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 | } | ||
diff --git a/vendor/twig/twig/lib/Twig/Node/Embed.php b/vendor/twig/twig/lib/Twig/Node/Embed.php new file mode 100644 index 00000000..4c9456dc --- /dev/null +++ b/vendor/twig/twig/lib/Twig/Node/Embed.php | |||
@@ -0,0 +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 | } | ||
diff --git a/vendor/twig/twig/lib/Twig/Node/Expression.php b/vendor/twig/twig/lib/Twig/Node/Expression.php new file mode 100644 index 00000000..a7382e7d --- /dev/null +++ b/vendor/twig/twig/lib/Twig/Node/Expression.php | |||
@@ -0,0 +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 | } | ||
diff --git a/vendor/twig/twig/lib/Twig/Node/Expression/Array.php b/vendor/twig/twig/lib/Twig/Node/Expression/Array.php new file mode 100644 index 00000000..1da785fe --- /dev/null +++ b/vendor/twig/twig/lib/Twig/Node/Expression/Array.php | |||
@@ -0,0 +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 | } | ||
diff --git a/vendor/twig/twig/lib/Twig/Node/Expression/AssignName.php b/vendor/twig/twig/lib/Twig/Node/Expression/AssignName.php new file mode 100644 index 00000000..2ddea78c --- /dev/null +++ b/vendor/twig/twig/lib/Twig/Node/Expression/AssignName.php | |||
@@ -0,0 +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 | } | ||
diff --git a/vendor/twig/twig/lib/Twig/Node/Expression/Binary.php b/vendor/twig/twig/lib/Twig/Node/Expression/Binary.php new file mode 100644 index 00000000..9dd5de2c --- /dev/null +++ b/vendor/twig/twig/lib/Twig/Node/Expression/Binary.php | |||
@@ -0,0 +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 | } | ||
diff --git a/vendor/twig/twig/lib/Twig/Node/Expression/Binary/Add.php b/vendor/twig/twig/lib/Twig/Node/Expression/Binary/Add.php new file mode 100644 index 00000000..0ef8e117 --- /dev/null +++ b/vendor/twig/twig/lib/Twig/Node/Expression/Binary/Add.php | |||
@@ -0,0 +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 | } | ||
diff --git a/vendor/twig/twig/lib/Twig/Node/Expression/Binary/And.php b/vendor/twig/twig/lib/Twig/Node/Expression/Binary/And.php new file mode 100644 index 00000000..d5752ebb --- /dev/null +++ b/vendor/twig/twig/lib/Twig/Node/Expression/Binary/And.php | |||
@@ -0,0 +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 | } | ||
diff --git a/vendor/twig/twig/lib/Twig/Node/Expression/Binary/BitwiseAnd.php b/vendor/twig/twig/lib/Twig/Node/Expression/Binary/BitwiseAnd.php new file mode 100644 index 00000000..9a46d845 --- /dev/null +++ b/vendor/twig/twig/lib/Twig/Node/Expression/Binary/BitwiseAnd.php | |||
@@ -0,0 +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 | } | ||
diff --git a/vendor/twig/twig/lib/Twig/Node/Expression/Binary/BitwiseOr.php b/vendor/twig/twig/lib/Twig/Node/Expression/Binary/BitwiseOr.php new file mode 100644 index 00000000..058a20bf --- /dev/null +++ b/vendor/twig/twig/lib/Twig/Node/Expression/Binary/BitwiseOr.php | |||
@@ -0,0 +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 | } | ||
diff --git a/vendor/twig/twig/lib/Twig/Node/Expression/Binary/BitwiseXor.php b/vendor/twig/twig/lib/Twig/Node/Expression/Binary/BitwiseXor.php new file mode 100644 index 00000000..f4da73d4 --- /dev/null +++ b/vendor/twig/twig/lib/Twig/Node/Expression/Binary/BitwiseXor.php | |||
@@ -0,0 +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 | } | ||
diff --git a/vendor/twig/twig/lib/Twig/Node/Expression/Binary/Concat.php b/vendor/twig/twig/lib/Twig/Node/Expression/Binary/Concat.php new file mode 100644 index 00000000..f9a64627 --- /dev/null +++ b/vendor/twig/twig/lib/Twig/Node/Expression/Binary/Concat.php | |||
@@ -0,0 +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 | } | ||
diff --git a/vendor/twig/twig/lib/Twig/Node/Expression/Binary/Div.php b/vendor/twig/twig/lib/Twig/Node/Expression/Binary/Div.php new file mode 100644 index 00000000..e0797a61 --- /dev/null +++ b/vendor/twig/twig/lib/Twig/Node/Expression/Binary/Div.php | |||
@@ -0,0 +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 | } | ||
diff --git a/vendor/twig/twig/lib/Twig/Node/Expression/Binary/Equal.php b/vendor/twig/twig/lib/Twig/Node/Expression/Binary/Equal.php new file mode 100644 index 00000000..7b1236d0 --- /dev/null +++ b/vendor/twig/twig/lib/Twig/Node/Expression/Binary/Equal.php | |||
@@ -0,0 +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 | } | ||
diff --git a/vendor/twig/twig/lib/Twig/Node/Expression/Binary/FloorDiv.php b/vendor/twig/twig/lib/Twig/Node/Expression/Binary/FloorDiv.php new file mode 100644 index 00000000..7fbd0556 --- /dev/null +++ b/vendor/twig/twig/lib/Twig/Node/Expression/Binary/FloorDiv.php | |||
@@ -0,0 +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 | } | ||
diff --git a/vendor/twig/twig/lib/Twig/Node/Expression/Binary/Greater.php b/vendor/twig/twig/lib/Twig/Node/Expression/Binary/Greater.php new file mode 100644 index 00000000..a110bd92 --- /dev/null +++ b/vendor/twig/twig/lib/Twig/Node/Expression/Binary/Greater.php | |||
@@ -0,0 +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 | } | ||
diff --git a/vendor/twig/twig/lib/Twig/Node/Expression/Binary/GreaterEqual.php b/vendor/twig/twig/lib/Twig/Node/Expression/Binary/GreaterEqual.php new file mode 100644 index 00000000..3754fed2 --- /dev/null +++ b/vendor/twig/twig/lib/Twig/Node/Expression/Binary/GreaterEqual.php | |||
@@ -0,0 +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 | } | ||
diff --git a/vendor/twig/twig/lib/Twig/Node/Expression/Binary/In.php b/vendor/twig/twig/lib/Twig/Node/Expression/Binary/In.php new file mode 100644 index 00000000..788f9377 --- /dev/null +++ b/vendor/twig/twig/lib/Twig/Node/Expression/Binary/In.php | |||
@@ -0,0 +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 | } | ||
diff --git a/vendor/twig/twig/lib/Twig/Node/Expression/Binary/Less.php b/vendor/twig/twig/lib/Twig/Node/Expression/Binary/Less.php new file mode 100644 index 00000000..45fd3004 --- /dev/null +++ b/vendor/twig/twig/lib/Twig/Node/Expression/Binary/Less.php | |||
@@ -0,0 +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 | } | ||
diff --git a/vendor/twig/twig/lib/Twig/Node/Expression/Binary/LessEqual.php b/vendor/twig/twig/lib/Twig/Node/Expression/Binary/LessEqual.php new file mode 100644 index 00000000..e38e257c --- /dev/null +++ b/vendor/twig/twig/lib/Twig/Node/Expression/Binary/LessEqual.php | |||
@@ -0,0 +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 | } | ||
diff --git a/vendor/twig/twig/lib/Twig/Node/Expression/Binary/Mod.php b/vendor/twig/twig/lib/Twig/Node/Expression/Binary/Mod.php new file mode 100644 index 00000000..9924114f --- /dev/null +++ b/vendor/twig/twig/lib/Twig/Node/Expression/Binary/Mod.php | |||
@@ -0,0 +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 | } | ||
diff --git a/vendor/twig/twig/lib/Twig/Node/Expression/Binary/Mul.php b/vendor/twig/twig/lib/Twig/Node/Expression/Binary/Mul.php new file mode 100644 index 00000000..c91529ca --- /dev/null +++ b/vendor/twig/twig/lib/Twig/Node/Expression/Binary/Mul.php | |||
@@ -0,0 +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 | } | ||
diff --git a/vendor/twig/twig/lib/Twig/Node/Expression/Binary/NotEqual.php b/vendor/twig/twig/lib/Twig/Node/Expression/Binary/NotEqual.php new file mode 100644 index 00000000..26867ba2 --- /dev/null +++ b/vendor/twig/twig/lib/Twig/Node/Expression/Binary/NotEqual.php | |||
@@ -0,0 +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 | } | ||
diff --git a/vendor/twig/twig/lib/Twig/Node/Expression/Binary/NotIn.php b/vendor/twig/twig/lib/Twig/Node/Expression/Binary/NotIn.php new file mode 100644 index 00000000..f347b7b6 --- /dev/null +++ b/vendor/twig/twig/lib/Twig/Node/Expression/Binary/NotIn.php | |||
@@ -0,0 +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 | } | ||
diff --git a/vendor/twig/twig/lib/Twig/Node/Expression/Binary/Or.php b/vendor/twig/twig/lib/Twig/Node/Expression/Binary/Or.php new file mode 100644 index 00000000..adba49c6 --- /dev/null +++ b/vendor/twig/twig/lib/Twig/Node/Expression/Binary/Or.php | |||
@@ -0,0 +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 | } | ||
diff --git a/vendor/twig/twig/lib/Twig/Node/Expression/Binary/Power.php b/vendor/twig/twig/lib/Twig/Node/Expression/Binary/Power.php new file mode 100644 index 00000000..b2c59040 --- /dev/null +++ b/vendor/twig/twig/lib/Twig/Node/Expression/Binary/Power.php | |||
@@ -0,0 +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 | } | ||
diff --git a/vendor/twig/twig/lib/Twig/Node/Expression/Binary/Range.php b/vendor/twig/twig/lib/Twig/Node/Expression/Binary/Range.php new file mode 100644 index 00000000..bea4f2a6 --- /dev/null +++ b/vendor/twig/twig/lib/Twig/Node/Expression/Binary/Range.php | |||
@@ -0,0 +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 | } | ||
diff --git a/vendor/twig/twig/lib/Twig/Node/Expression/Binary/Sub.php b/vendor/twig/twig/lib/Twig/Node/Expression/Binary/Sub.php new file mode 100644 index 00000000..d4463991 --- /dev/null +++ b/vendor/twig/twig/lib/Twig/Node/Expression/Binary/Sub.php | |||
@@ -0,0 +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 | } | ||
diff --git a/vendor/twig/twig/lib/Twig/Node/Expression/BlockReference.php b/vendor/twig/twig/lib/Twig/Node/Expression/BlockReference.php new file mode 100644 index 00000000..647196eb --- /dev/null +++ b/vendor/twig/twig/lib/Twig/Node/Expression/BlockReference.php | |||
@@ -0,0 +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 | } | ||
diff --git a/vendor/twig/twig/lib/Twig/Node/Expression/Call.php b/vendor/twig/twig/lib/Twig/Node/Expression/Call.php new file mode 100644 index 00000000..dba9b0e6 --- /dev/null +++ b/vendor/twig/twig/lib/Twig/Node/Expression/Call.php | |||
@@ -0,0 +1,178 @@ | |||
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 | $callable = $this->getAttribute('callable'); | ||
16 | |||
17 | $closingParenthesis = false; | ||
18 | if ($callable) { | ||
19 | if (is_string($callable)) { | ||
20 | $compiler->raw($callable); | ||
21 | } elseif (is_array($callable) && $callable[0] instanceof Twig_ExtensionInterface) { | ||
22 | $compiler->raw(sprintf('$this->env->getExtension(\'%s\')->%s', $callable[0]->getName(), $callable[1])); | ||
23 | } else { | ||
24 | $type = ucfirst($this->getAttribute('type')); | ||
25 | $compiler->raw(sprintf('call_user_func_array($this->env->get%s(\'%s\')->getCallable(), array', $type, $this->getAttribute('name'))); | ||
26 | $closingParenthesis = true; | ||
27 | } | ||
28 | } else { | ||
29 | $compiler->raw($this->getAttribute('thing')->compile()); | ||
30 | } | ||
31 | |||
32 | $this->compileArguments($compiler); | ||
33 | |||
34 | if ($closingParenthesis) { | ||
35 | $compiler->raw(')'); | ||
36 | } | ||
37 | } | ||
38 | |||
39 | protected function compileArguments(Twig_Compiler $compiler) | ||
40 | { | ||
41 | $compiler->raw('('); | ||
42 | |||
43 | $first = true; | ||
44 | |||
45 | if ($this->hasAttribute('needs_environment') && $this->getAttribute('needs_environment')) { | ||
46 | $compiler->raw('$this->env'); | ||
47 | $first = false; | ||
48 | } | ||
49 | |||
50 | if ($this->hasAttribute('needs_context') && $this->getAttribute('needs_context')) { | ||
51 | if (!$first) { | ||
52 | $compiler->raw(', '); | ||
53 | } | ||
54 | $compiler->raw('$context'); | ||
55 | $first = false; | ||
56 | } | ||
57 | |||
58 | if ($this->hasAttribute('arguments')) { | ||
59 | foreach ($this->getAttribute('arguments') as $argument) { | ||
60 | if (!$first) { | ||
61 | $compiler->raw(', '); | ||
62 | } | ||
63 | $compiler->string($argument); | ||
64 | $first = false; | ||
65 | } | ||
66 | } | ||
67 | |||
68 | if ($this->hasNode('node')) { | ||
69 | if (!$first) { | ||
70 | $compiler->raw(', '); | ||
71 | } | ||
72 | $compiler->subcompile($this->getNode('node')); | ||
73 | $first = false; | ||
74 | } | ||
75 | |||
76 | if ($this->hasNode('arguments') && null !== $this->getNode('arguments')) { | ||
77 | $callable = $this->hasAttribute('callable') ? $this->getAttribute('callable') : null; | ||
78 | |||
79 | $arguments = $this->getArguments($callable, $this->getNode('arguments')); | ||
80 | |||
81 | foreach ($arguments as $node) { | ||
82 | if (!$first) { | ||
83 | $compiler->raw(', '); | ||
84 | } | ||
85 | $compiler->subcompile($node); | ||
86 | $first = false; | ||
87 | } | ||
88 | } | ||
89 | |||
90 | $compiler->raw(')'); | ||
91 | } | ||
92 | |||
93 | protected function getArguments($callable, $arguments) | ||
94 | { | ||
95 | $parameters = array(); | ||
96 | $named = false; | ||
97 | foreach ($arguments as $name => $node) { | ||
98 | if (!is_int($name)) { | ||
99 | $named = true; | ||
100 | $name = $this->normalizeName($name); | ||
101 | } elseif ($named) { | ||
102 | throw new Twig_Error_Syntax(sprintf('Positional arguments cannot be used after named arguments for %s "%s".', $this->getAttribute('type'), $this->getAttribute('name'))); | ||
103 | } | ||
104 | |||
105 | $parameters[$name] = $node; | ||
106 | } | ||
107 | |||
108 | if (!$named) { | ||
109 | return $parameters; | ||
110 | } | ||
111 | |||
112 | if (!$callable) { | ||
113 | throw new LogicException(sprintf('Named arguments are not supported for %s "%s".', $this->getAttribute('type'), $this->getAttribute('name'))); | ||
114 | } | ||
115 | |||
116 | // manage named arguments | ||
117 | if (is_array($callable)) { | ||
118 | $r = new ReflectionMethod($callable[0], $callable[1]); | ||
119 | } elseif (is_object($callable) && !$callable instanceof Closure) { | ||
120 | $r = new ReflectionObject($callable); | ||
121 | $r = $r->getMethod('__invoke'); | ||
122 | } else { | ||
123 | $r = new ReflectionFunction($callable); | ||
124 | } | ||
125 | |||
126 | $definition = $r->getParameters(); | ||
127 | if ($this->hasNode('node')) { | ||
128 | array_shift($definition); | ||
129 | } | ||
130 | if ($this->hasAttribute('needs_environment') && $this->getAttribute('needs_environment')) { | ||
131 | array_shift($definition); | ||
132 | } | ||
133 | if ($this->hasAttribute('needs_context') && $this->getAttribute('needs_context')) { | ||
134 | array_shift($definition); | ||
135 | } | ||
136 | if ($this->hasAttribute('arguments') && null !== $this->getAttribute('arguments')) { | ||
137 | foreach ($this->getAttribute('arguments') as $argument) { | ||
138 | array_shift($definition); | ||
139 | } | ||
140 | } | ||
141 | |||
142 | $arguments = array(); | ||
143 | $pos = 0; | ||
144 | foreach ($definition as $param) { | ||
145 | $name = $this->normalizeName($param->name); | ||
146 | |||
147 | if (array_key_exists($name, $parameters)) { | ||
148 | if (array_key_exists($pos, $parameters)) { | ||
149 | throw new Twig_Error_Syntax(sprintf('Argument "%s" is defined twice for %s "%s".', $name, $this->getAttribute('type'), $this->getAttribute('name'))); | ||
150 | } | ||
151 | |||
152 | $arguments[] = $parameters[$name]; | ||
153 | unset($parameters[$name]); | ||
154 | } elseif (array_key_exists($pos, $parameters)) { | ||
155 | $arguments[] = $parameters[$pos]; | ||
156 | unset($parameters[$pos]); | ||
157 | ++$pos; | ||
158 | } elseif ($param->isDefaultValueAvailable()) { | ||
159 | $arguments[] = new Twig_Node_Expression_Constant($param->getDefaultValue(), -1); | ||
160 | } elseif ($param->isOptional()) { | ||
161 | break; | ||
162 | } else { | ||
163 | throw new Twig_Error_Syntax(sprintf('Value for argument "%s" is required for %s "%s".', $name, $this->getAttribute('type'), $this->getAttribute('name'))); | ||
164 | } | ||
165 | } | ||
166 | |||
167 | if (!empty($parameters)) { | ||
168 | 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'))); | ||
169 | } | ||
170 | |||
171 | return $arguments; | ||
172 | } | ||
173 | |||
174 | protected function normalizeName($name) | ||
175 | { | ||
176 | return strtolower(preg_replace(array('/([A-Z]+)([A-Z][a-z])/', '/([a-z\d])([A-Z])/'), array('\\1_\\2', '\\1_\\2'), $name)); | ||
177 | } | ||
178 | } | ||
diff --git a/vendor/twig/twig/lib/Twig/Node/Expression/Conditional.php b/vendor/twig/twig/lib/Twig/Node/Expression/Conditional.php new file mode 100644 index 00000000..edcb1e2d --- /dev/null +++ b/vendor/twig/twig/lib/Twig/Node/Expression/Conditional.php | |||
@@ -0,0 +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 | } | ||
diff --git a/vendor/twig/twig/lib/Twig/Node/Expression/Constant.php b/vendor/twig/twig/lib/Twig/Node/Expression/Constant.php new file mode 100644 index 00000000..a91dc698 --- /dev/null +++ b/vendor/twig/twig/lib/Twig/Node/Expression/Constant.php | |||
@@ -0,0 +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 | } | ||
diff --git a/vendor/twig/twig/lib/Twig/Node/Expression/ExtensionReference.php b/vendor/twig/twig/lib/Twig/Node/Expression/ExtensionReference.php new file mode 100644 index 00000000..00ac6701 --- /dev/null +++ b/vendor/twig/twig/lib/Twig/Node/Expression/ExtensionReference.php | |||
@@ -0,0 +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 | } | ||
diff --git a/vendor/twig/twig/lib/Twig/Node/Expression/Filter.php b/vendor/twig/twig/lib/Twig/Node/Expression/Filter.php new file mode 100644 index 00000000..207b062a --- /dev/null +++ b/vendor/twig/twig/lib/Twig/Node/Expression/Filter.php | |||
@@ -0,0 +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 | } | ||
diff --git a/vendor/twig/twig/lib/Twig/Node/Expression/Filter/Default.php b/vendor/twig/twig/lib/Twig/Node/Expression/Filter/Default.php new file mode 100644 index 00000000..1827c888 --- /dev/null +++ b/vendor/twig/twig/lib/Twig/Node/Expression/Filter/Default.php | |||
@@ -0,0 +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 | } | ||
diff --git a/vendor/twig/twig/lib/Twig/Node/Expression/Function.php b/vendor/twig/twig/lib/Twig/Node/Expression/Function.php new file mode 100644 index 00000000..3e1f6b55 --- /dev/null +++ b/vendor/twig/twig/lib/Twig/Node/Expression/Function.php | |||
@@ -0,0 +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 | } | ||
diff --git a/vendor/twig/twig/lib/Twig/Node/Expression/GetAttr.php b/vendor/twig/twig/lib/Twig/Node/Expression/GetAttr.php new file mode 100644 index 00000000..81a9b137 --- /dev/null +++ b/vendor/twig/twig/lib/Twig/Node/Expression/GetAttr.php | |||
@@ -0,0 +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_TemplateInterface::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_TemplateInterface::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 | } | ||
diff --git a/vendor/twig/twig/lib/Twig/Node/Expression/MethodCall.php b/vendor/twig/twig/lib/Twig/Node/Expression/MethodCall.php new file mode 100644 index 00000000..620b02bf --- /dev/null +++ b/vendor/twig/twig/lib/Twig/Node/Expression/MethodCall.php | |||
@@ -0,0 +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 | } | ||
diff --git a/vendor/twig/twig/lib/Twig/Node/Expression/Name.php b/vendor/twig/twig/lib/Twig/Node/Expression/Name.php new file mode 100644 index 00000000..3b8fae01 --- /dev/null +++ b/vendor/twig/twig/lib/Twig/Node/Expression/Name.php | |||
@@ -0,0 +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 | } | ||
diff --git a/vendor/twig/twig/lib/Twig/Node/Expression/Parent.php b/vendor/twig/twig/lib/Twig/Node/Expression/Parent.php new file mode 100644 index 00000000..dcf618c0 --- /dev/null +++ b/vendor/twig/twig/lib/Twig/Node/Expression/Parent.php | |||
@@ -0,0 +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 | } | ||
diff --git a/vendor/twig/twig/lib/Twig/Node/Expression/TempName.php b/vendor/twig/twig/lib/Twig/Node/Expression/TempName.php new file mode 100644 index 00000000..e6b058e8 --- /dev/null +++ b/vendor/twig/twig/lib/Twig/Node/Expression/TempName.php | |||
@@ -0,0 +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 | } | ||
diff --git a/vendor/twig/twig/lib/Twig/Node/Expression/Test.php b/vendor/twig/twig/lib/Twig/Node/Expression/Test.php new file mode 100644 index 00000000..639f501a --- /dev/null +++ b/vendor/twig/twig/lib/Twig/Node/Expression/Test.php | |||
@@ -0,0 +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 | } | ||
diff --git a/vendor/twig/twig/lib/Twig/Node/Expression/Test/Constant.php b/vendor/twig/twig/lib/Twig/Node/Expression/Test/Constant.php new file mode 100644 index 00000000..de55f5f5 --- /dev/null +++ b/vendor/twig/twig/lib/Twig/Node/Expression/Test/Constant.php | |||
@@ -0,0 +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 | } | ||
diff --git a/vendor/twig/twig/lib/Twig/Node/Expression/Test/Defined.php b/vendor/twig/twig/lib/Twig/Node/Expression/Test/Defined.php new file mode 100644 index 00000000..247b2e23 --- /dev/null +++ b/vendor/twig/twig/lib/Twig/Node/Expression/Test/Defined.php | |||
@@ -0,0 +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 | } | ||
diff --git a/vendor/twig/twig/lib/Twig/Node/Expression/Test/Divisibleby.php b/vendor/twig/twig/lib/Twig/Node/Expression/Test/Divisibleby.php new file mode 100644 index 00000000..0aceb530 --- /dev/null +++ b/vendor/twig/twig/lib/Twig/Node/Expression/Test/Divisibleby.php | |||
@@ -0,0 +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 divisibleby(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 | } | ||
diff --git a/vendor/twig/twig/lib/Twig/Node/Expression/Test/Even.php b/vendor/twig/twig/lib/Twig/Node/Expression/Test/Even.php new file mode 100644 index 00000000..d7853e89 --- /dev/null +++ b/vendor/twig/twig/lib/Twig/Node/Expression/Test/Even.php | |||
@@ -0,0 +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 | } | ||
diff --git a/vendor/twig/twig/lib/Twig/Node/Expression/Test/Null.php b/vendor/twig/twig/lib/Twig/Node/Expression/Test/Null.php new file mode 100644 index 00000000..1c83825a --- /dev/null +++ b/vendor/twig/twig/lib/Twig/Node/Expression/Test/Null.php | |||
@@ -0,0 +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 | } | ||
diff --git a/vendor/twig/twig/lib/Twig/Node/Expression/Test/Odd.php b/vendor/twig/twig/lib/Twig/Node/Expression/Test/Odd.php new file mode 100644 index 00000000..421c19e8 --- /dev/null +++ b/vendor/twig/twig/lib/Twig/Node/Expression/Test/Odd.php | |||
@@ -0,0 +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 | } | ||
diff --git a/vendor/twig/twig/lib/Twig/Node/Expression/Test/Sameas.php b/vendor/twig/twig/lib/Twig/Node/Expression/Test/Sameas.php new file mode 100644 index 00000000..b48905ee --- /dev/null +++ b/vendor/twig/twig/lib/Twig/Node/Expression/Test/Sameas.php | |||
@@ -0,0 +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 | } | ||
diff --git a/vendor/twig/twig/lib/Twig/Node/Expression/Unary.php b/vendor/twig/twig/lib/Twig/Node/Expression/Unary.php new file mode 100644 index 00000000..c514388e --- /dev/null +++ b/vendor/twig/twig/lib/Twig/Node/Expression/Unary.php | |||
@@ -0,0 +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 | } | ||
diff --git a/vendor/twig/twig/lib/Twig/Node/Expression/Unary/Neg.php b/vendor/twig/twig/lib/Twig/Node/Expression/Unary/Neg.php new file mode 100644 index 00000000..2a3937ec --- /dev/null +++ b/vendor/twig/twig/lib/Twig/Node/Expression/Unary/Neg.php | |||
@@ -0,0 +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 | } | ||
diff --git a/vendor/twig/twig/lib/Twig/Node/Expression/Unary/Not.php b/vendor/twig/twig/lib/Twig/Node/Expression/Unary/Not.php new file mode 100644 index 00000000..f94073cf --- /dev/null +++ b/vendor/twig/twig/lib/Twig/Node/Expression/Unary/Not.php | |||
@@ -0,0 +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 | } | ||
diff --git a/vendor/twig/twig/lib/Twig/Node/Expression/Unary/Pos.php b/vendor/twig/twig/lib/Twig/Node/Expression/Unary/Pos.php new file mode 100644 index 00000000..04edb52a --- /dev/null +++ b/vendor/twig/twig/lib/Twig/Node/Expression/Unary/Pos.php | |||
@@ -0,0 +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 | } | ||
diff --git a/vendor/twig/twig/lib/Twig/Node/Flush.php b/vendor/twig/twig/lib/Twig/Node/Flush.php new file mode 100644 index 00000000..0467ddce --- /dev/null +++ b/vendor/twig/twig/lib/Twig/Node/Flush.php | |||
@@ -0,0 +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 | } | ||
diff --git a/vendor/twig/twig/lib/Twig/Node/For.php b/vendor/twig/twig/lib/Twig/Node/For.php new file mode 100644 index 00000000..d1ff371d --- /dev/null +++ b/vendor/twig/twig/lib/Twig/Node/For.php | |||
@@ -0,0 +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 | } | ||
diff --git a/vendor/twig/twig/lib/Twig/Node/ForLoop.php b/vendor/twig/twig/lib/Twig/Node/ForLoop.php new file mode 100644 index 00000000..b8841583 --- /dev/null +++ b/vendor/twig/twig/lib/Twig/Node/ForLoop.php | |||
@@ -0,0 +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 | } | ||
diff --git a/vendor/twig/twig/lib/Twig/Node/If.php b/vendor/twig/twig/lib/Twig/Node/If.php new file mode 100644 index 00000000..4296a8d6 --- /dev/null +++ b/vendor/twig/twig/lib/Twig/Node/If.php | |||
@@ -0,0 +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; $i < count($this->getNode('tests')); $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 | } | ||
diff --git a/vendor/twig/twig/lib/Twig/Node/Import.php b/vendor/twig/twig/lib/Twig/Node/Import.php new file mode 100644 index 00000000..99efc091 --- /dev/null +++ b/vendor/twig/twig/lib/Twig/Node/Import.php | |||
@@ -0,0 +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 | } | ||
diff --git a/vendor/twig/twig/lib/Twig/Node/Include.php b/vendor/twig/twig/lib/Twig/Node/Include.php new file mode 100644 index 00000000..ed4a3751 --- /dev/null +++ b/vendor/twig/twig/lib/Twig/Node/Include.php | |||
@@ -0,0 +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' => (Boolean) $only, 'ignore_missing' => (Boolean) $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 | } | ||
diff --git a/vendor/twig/twig/lib/Twig/Node/Macro.php b/vendor/twig/twig/lib/Twig/Node/Macro.php new file mode 100644 index 00000000..89910618 --- /dev/null +++ b/vendor/twig/twig/lib/Twig/Node/Macro.php | |||
@@ -0,0 +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 | } | ||
diff --git a/vendor/twig/twig/lib/Twig/Node/Module.php b/vendor/twig/twig/lib/Twig/Node/Module.php new file mode 100644 index 00000000..585048b8 --- /dev/null +++ b/vendor/twig/twig/lib/Twig/Node/Module.php | |||
@@ -0,0 +1,371 @@ | |||
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("\$_trait_%s_blocks[", $i)) | ||
174 | ->subcompile($value) | ||
175 | ->raw(sprintf("] = \$_trait_%s_blocks[", $i)) | ||
176 | ->string($key) | ||
177 | ->raw(sprintf("]; unset(\$_trait_%s_blocks[", $i)) | ||
178 | ->string($key) | ||
179 | ->raw("]);\n\n") | ||
180 | ; | ||
181 | } | ||
182 | } | ||
183 | |||
184 | if ($countTraits > 1) { | ||
185 | $compiler | ||
186 | ->write("\$this->traits = array_merge(\n") | ||
187 | ->indent() | ||
188 | ; | ||
189 | |||
190 | for ($i = 0; $i < $countTraits; $i++) { | ||
191 | $compiler | ||
192 | ->write(sprintf("\$_trait_%s_blocks".($i == $countTraits - 1 ? '' : ',')."\n", $i)) | ||
193 | ; | ||
194 | } | ||
195 | |||
196 | $compiler | ||
197 | ->outdent() | ||
198 | ->write(");\n\n") | ||
199 | ; | ||
200 | } else { | ||
201 | $compiler | ||
202 | ->write("\$this->traits = \$_trait_0_blocks;\n\n") | ||
203 | ; | ||
204 | } | ||
205 | |||
206 | $compiler | ||
207 | ->write("\$this->blocks = array_merge(\n") | ||
208 | ->indent() | ||
209 | ->write("\$this->traits,\n") | ||
210 | ->write("array(\n") | ||
211 | ; | ||
212 | } else { | ||
213 | $compiler | ||
214 | ->write("\$this->blocks = array(\n") | ||
215 | ; | ||
216 | } | ||
217 | |||
218 | // blocks | ||
219 | $compiler | ||
220 | ->indent() | ||
221 | ; | ||
222 | |||
223 | foreach ($this->getNode('blocks') as $name => $node) { | ||
224 | $compiler | ||
225 | ->write(sprintf("'%s' => array(\$this, 'block_%s'),\n", $name, $name)) | ||
226 | ; | ||
227 | } | ||
228 | |||
229 | if ($countTraits) { | ||
230 | $compiler | ||
231 | ->outdent() | ||
232 | ->write(")\n") | ||
233 | ; | ||
234 | } | ||
235 | |||
236 | $compiler | ||
237 | ->outdent() | ||
238 | ->write(");\n") | ||
239 | ->outdent() | ||
240 | ->write("}\n\n"); | ||
241 | ; | ||
242 | } | ||
243 | |||
244 | protected function compileDisplayHeader(Twig_Compiler $compiler) | ||
245 | { | ||
246 | $compiler | ||
247 | ->write("protected function doDisplay(array \$context, array \$blocks = array())\n", "{\n") | ||
248 | ->indent() | ||
249 | ; | ||
250 | } | ||
251 | |||
252 | protected function compileDisplayFooter(Twig_Compiler $compiler) | ||
253 | { | ||
254 | $compiler | ||
255 | ->outdent() | ||
256 | ->write("}\n\n") | ||
257 | ; | ||
258 | } | ||
259 | |||
260 | protected function compileClassFooter(Twig_Compiler $compiler) | ||
261 | { | ||
262 | $compiler | ||
263 | ->outdent() | ||
264 | ->write("}\n") | ||
265 | ; | ||
266 | } | ||
267 | |||
268 | protected function compileMacros(Twig_Compiler $compiler) | ||
269 | { | ||
270 | $compiler->subcompile($this->getNode('macros')); | ||
271 | } | ||
272 | |||
273 | protected function compileGetTemplateName(Twig_Compiler $compiler) | ||
274 | { | ||
275 | $compiler | ||
276 | ->write("public function getTemplateName()\n", "{\n") | ||
277 | ->indent() | ||
278 | ->write('return ') | ||
279 | ->repr($this->getAttribute('filename')) | ||
280 | ->raw(";\n") | ||
281 | ->outdent() | ||
282 | ->write("}\n\n") | ||
283 | ; | ||
284 | } | ||
285 | |||
286 | protected function compileIsTraitable(Twig_Compiler $compiler) | ||
287 | { | ||
288 | // A template can be used as a trait if: | ||
289 | // * it has no parent | ||
290 | // * it has no macros | ||
291 | // * it has no body | ||
292 | // | ||
293 | // Put another way, a template can be used as a trait if it | ||
294 | // only contains blocks and use statements. | ||
295 | $traitable = null === $this->getNode('parent') && 0 === count($this->getNode('macros')); | ||
296 | if ($traitable) { | ||
297 | if ($this->getNode('body') instanceof Twig_Node_Body) { | ||
298 | $nodes = $this->getNode('body')->getNode(0); | ||
299 | } else { | ||
300 | $nodes = $this->getNode('body'); | ||
301 | } | ||
302 | |||
303 | if (!count($nodes)) { | ||
304 | $nodes = new Twig_Node(array($nodes)); | ||
305 | } | ||
306 | |||
307 | foreach ($nodes as $node) { | ||
308 | if (!count($node)) { | ||
309 | continue; | ||
310 | } | ||
311 | |||
312 | if ($node instanceof Twig_Node_Text && ctype_space($node->getAttribute('data'))) { | ||
313 | continue; | ||
314 | } | ||
315 | |||
316 | if ($node instanceof Twig_Node_BlockReference) { | ||
317 | continue; | ||
318 | } | ||
319 | |||
320 | $traitable = false; | ||
321 | break; | ||
322 | } | ||
323 | } | ||
324 | |||
325 | if ($traitable) { | ||
326 | return; | ||
327 | } | ||
328 | |||
329 | $compiler | ||
330 | ->write("public function isTraitable()\n", "{\n") | ||
331 | ->indent() | ||
332 | ->write(sprintf("return %s;\n", $traitable ? 'true' : 'false')) | ||
333 | ->outdent() | ||
334 | ->write("}\n\n") | ||
335 | ; | ||
336 | } | ||
337 | |||
338 | protected function compileDebugInfo(Twig_Compiler $compiler) | ||
339 | { | ||
340 | $compiler | ||
341 | ->write("public function getDebugInfo()\n", "{\n") | ||
342 | ->indent() | ||
343 | ->write(sprintf("return %s;\n", str_replace("\n", '', var_export(array_reverse($compiler->getDebugInfo(), true), true)))) | ||
344 | ->outdent() | ||
345 | ->write("}\n") | ||
346 | ; | ||
347 | } | ||
348 | |||
349 | protected function compileLoadTemplate(Twig_Compiler $compiler, $node, $var) | ||
350 | { | ||
351 | if ($node instanceof Twig_Node_Expression_Constant) { | ||
352 | $compiler | ||
353 | ->write(sprintf("%s = \$this->env->loadTemplate(", $var)) | ||
354 | ->subcompile($node) | ||
355 | ->raw(");\n") | ||
356 | ; | ||
357 | } else { | ||
358 | $compiler | ||
359 | ->write(sprintf("%s = ", $var)) | ||
360 | ->subcompile($node) | ||
361 | ->raw(";\n") | ||
362 | ->write(sprintf("if (!%s", $var)) | ||
363 | ->raw(" instanceof Twig_Template) {\n") | ||
364 | ->indent() | ||
365 | ->write(sprintf("%s = \$this->env->loadTemplate(%s);\n", $var, $var)) | ||
366 | ->outdent() | ||
367 | ->write("}\n") | ||
368 | ; | ||
369 | } | ||
370 | } | ||
371 | } | ||
diff --git a/vendor/twig/twig/lib/Twig/Node/Print.php b/vendor/twig/twig/lib/Twig/Node/Print.php new file mode 100644 index 00000000..b0c41d1d --- /dev/null +++ b/vendor/twig/twig/lib/Twig/Node/Print.php | |||
@@ -0,0 +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 | } | ||
diff --git a/vendor/twig/twig/lib/Twig/Node/Sandbox.php b/vendor/twig/twig/lib/Twig/Node/Sandbox.php new file mode 100644 index 00000000..8cf3ed44 --- /dev/null +++ b/vendor/twig/twig/lib/Twig/Node/Sandbox.php | |||
@@ -0,0 +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 | } | ||
diff --git a/vendor/twig/twig/lib/Twig/Node/SandboxedModule.php b/vendor/twig/twig/lib/Twig/Node/SandboxedModule.php new file mode 100644 index 00000000..be1f5daa --- /dev/null +++ b/vendor/twig/twig/lib/Twig/Node/SandboxedModule.php | |||
@@ -0,0 +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'), $node->getLine(), $node->getNodeTag()); | ||
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 | } | ||
diff --git a/vendor/twig/twig/lib/Twig/Node/SandboxedPrint.php b/vendor/twig/twig/lib/Twig/Node/SandboxedPrint.php new file mode 100644 index 00000000..73dfaa96 --- /dev/null +++ b/vendor/twig/twig/lib/Twig/Node/SandboxedPrint.php | |||
@@ -0,0 +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 | } | ||
diff --git a/vendor/twig/twig/lib/Twig/Node/Set.php b/vendor/twig/twig/lib/Twig/Node/Set.php new file mode 100644 index 00000000..4c9c16ce --- /dev/null +++ b/vendor/twig/twig/lib/Twig/Node/Set.php | |||
@@ -0,0 +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 | } | ||
diff --git a/vendor/twig/twig/lib/Twig/Node/SetTemp.php b/vendor/twig/twig/lib/Twig/Node/SetTemp.php new file mode 100644 index 00000000..3bdd1cb7 --- /dev/null +++ b/vendor/twig/twig/lib/Twig/Node/SetTemp.php | |||
@@ -0,0 +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 | } | ||
diff --git a/vendor/twig/twig/lib/Twig/Node/Spaceless.php b/vendor/twig/twig/lib/Twig/Node/Spaceless.php new file mode 100644 index 00000000..7555fa0f --- /dev/null +++ b/vendor/twig/twig/lib/Twig/Node/Spaceless.php | |||
@@ -0,0 +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 | } | ||
diff --git a/vendor/twig/twig/lib/Twig/Node/Text.php b/vendor/twig/twig/lib/Twig/Node/Text.php new file mode 100644 index 00000000..21bdcea1 --- /dev/null +++ b/vendor/twig/twig/lib/Twig/Node/Text.php | |||
@@ -0,0 +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 | } | ||
diff --git a/vendor/twig/twig/lib/Twig/NodeInterface.php b/vendor/twig/twig/lib/Twig/NodeInterface.php new file mode 100644 index 00000000..f0ef7258 --- /dev/null +++ b/vendor/twig/twig/lib/Twig/NodeInterface.php | |||
@@ -0,0 +1,30 @@ | |||
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 | * @deprecated since 1.12 (to be removed in 2.0) | ||
17 | */ | ||
18 | interface Twig_NodeInterface extends Countable, IteratorAggregate | ||
19 | { | ||
20 | /** | ||
21 | * Compiles the node to PHP. | ||
22 | * | ||
23 | * @param Twig_Compiler A Twig_Compiler instance | ||
24 | */ | ||
25 | public function compile(Twig_Compiler $compiler); | ||
26 | |||
27 | public function getLine(); | ||
28 | |||
29 | public function getNodeTag(); | ||
30 | } | ||
diff --git a/vendor/twig/twig/lib/Twig/NodeOutputInterface.php b/vendor/twig/twig/lib/Twig/NodeOutputInterface.php new file mode 100644 index 00000000..22172c09 --- /dev/null +++ b/vendor/twig/twig/lib/Twig/NodeOutputInterface.php | |||
@@ -0,0 +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 | } | ||
diff --git a/vendor/twig/twig/lib/Twig/NodeTraverser.php b/vendor/twig/twig/lib/Twig/NodeTraverser.php new file mode 100644 index 00000000..28cba1ad --- /dev/null +++ b/vendor/twig/twig/lib/Twig/NodeTraverser.php | |||
@@ -0,0 +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 call 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 array $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 null; | ||
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 | } | ||
diff --git a/vendor/twig/twig/lib/Twig/NodeVisitor/Escaper.php b/vendor/twig/twig/lib/Twig/NodeVisitor/Escaper.php new file mode 100644 index 00000000..cc4b3d71 --- /dev/null +++ b/vendor/twig/twig/lib/Twig/NodeVisitor/Escaper.php | |||
@@ -0,0 +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 | } | ||
diff --git a/vendor/twig/twig/lib/Twig/NodeVisitor/Optimizer.php b/vendor/twig/twig/lib/Twig/NodeVisitor/Optimizer.php new file mode 100644 index 00000000..a254def7 --- /dev/null +++ b/vendor/twig/twig/lib/Twig/NodeVisitor/Optimizer.php | |||
@@ -0,0 +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 integer $optimizers The optimizer mode | ||
39 | */ | ||
40 | public function __construct($optimizers = -1) | ||
41 | { | ||
42 | if (!is_int($optimizers) || $optimizers > 2) { | ||
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($node, $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($node, $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($node, $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($node, $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($node, $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 | } | ||
diff --git a/vendor/twig/twig/lib/Twig/NodeVisitor/SafeAnalysis.php b/vendor/twig/twig/lib/Twig/NodeVisitor/SafeAnalysis.php new file mode 100644 index 00000000..c4bbd812 --- /dev/null +++ b/vendor/twig/twig/lib/Twig/NodeVisitor/SafeAnalysis.php | |||
@@ -0,0 +1,131 @@ | |||
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 | foreach ($this->data[$hash] as $bucket) { | ||
18 | if ($bucket['key'] === $node) { | ||
19 | return $bucket['value']; | ||
20 | } | ||
21 | } | ||
22 | } | ||
23 | } | ||
24 | |||
25 | protected function setSafe(Twig_NodeInterface $node, array $safe) | ||
26 | { | ||
27 | $hash = spl_object_hash($node); | ||
28 | if (isset($this->data[$hash])) { | ||
29 | foreach ($this->data[$hash] as &$bucket) { | ||
30 | if ($bucket['key'] === $node) { | ||
31 | $bucket['value'] = $safe; | ||
32 | |||
33 | return; | ||
34 | } | ||
35 | } | ||
36 | } | ||
37 | $this->data[$hash][] = array( | ||
38 | 'key' => $node, | ||
39 | 'value' => $safe, | ||
40 | ); | ||
41 | } | ||
42 | |||
43 | public function enterNode(Twig_NodeInterface $node, Twig_Environment $env) | ||
44 | { | ||
45 | return $node; | ||
46 | } | ||
47 | |||
48 | public function leaveNode(Twig_NodeInterface $node, Twig_Environment $env) | ||
49 | { | ||
50 | if ($node instanceof Twig_Node_Expression_Constant) { | ||
51 | // constants are marked safe for all | ||
52 | $this->setSafe($node, array('all')); | ||
53 | } elseif ($node instanceof Twig_Node_Expression_BlockReference) { | ||
54 | // blocks are safe by definition | ||
55 | $this->setSafe($node, array('all')); | ||
56 | } elseif ($node instanceof Twig_Node_Expression_Parent) { | ||
57 | // parent block is safe by definition | ||
58 | $this->setSafe($node, array('all')); | ||
59 | } elseif ($node instanceof Twig_Node_Expression_Conditional) { | ||
60 | // intersect safeness of both operands | ||
61 | $safe = $this->intersectSafe($this->getSafe($node->getNode('expr2')), $this->getSafe($node->getNode('expr3'))); | ||
62 | $this->setSafe($node, $safe); | ||
63 | } elseif ($node instanceof Twig_Node_Expression_Filter) { | ||
64 | // filter expression is safe when the filter is safe | ||
65 | $name = $node->getNode('filter')->getAttribute('value'); | ||
66 | $args = $node->getNode('arguments'); | ||
67 | if (false !== $filter = $env->getFilter($name)) { | ||
68 | $safe = $filter->getSafe($args); | ||
69 | if (null === $safe) { | ||
70 | $safe = $this->intersectSafe($this->getSafe($node->getNode('node')), $filter->getPreservesSafety()); | ||
71 | } | ||
72 | $this->setSafe($node, $safe); | ||
73 | } else { | ||
74 | $this->setSafe($node, array()); | ||
75 | } | ||
76 | } elseif ($node instanceof Twig_Node_Expression_Function) { | ||
77 | // function expression is safe when the function is safe | ||
78 | $name = $node->getAttribute('name'); | ||
79 | $args = $node->getNode('arguments'); | ||
80 | $function = $env->getFunction($name); | ||
81 | if (false !== $function) { | ||
82 | $this->setSafe($node, $function->getSafe($args)); | ||
83 | } else { | ||
84 | $this->setSafe($node, array()); | ||
85 | } | ||
86 | } elseif ($node instanceof Twig_Node_Expression_MethodCall) { | ||
87 | if ($node->getAttribute('safe')) { | ||
88 | $this->setSafe($node, array('all')); | ||
89 | } else { | ||
90 | $this->setSafe($node, array()); | ||
91 | } | ||
92 | } elseif ($node instanceof Twig_Node_Expression_GetAttr && $node->getNode('node') instanceof Twig_Node_Expression_Name) { | ||
93 | $name = $node->getNode('node')->getAttribute('name'); | ||
94 | // attributes on template instances are safe | ||
95 | if ('_self' == $name || in_array($name, $this->safeVars)) { | ||
96 | $this->setSafe($node, array('all')); | ||
97 | } else { | ||
98 | $this->setSafe($node, array()); | ||
99 | } | ||
100 | } else { | ||
101 | $this->setSafe($node, array()); | ||
102 | } | ||
103 | |||
104 | return $node; | ||
105 | } | ||
106 | |||
107 | protected function intersectSafe(array $a = null, array $b = null) | ||
108 | { | ||
109 | if (null === $a || null === $b) { | ||
110 | return array(); | ||
111 | } | ||
112 | |||
113 | if (in_array('all', $a)) { | ||
114 | return $b; | ||
115 | } | ||
116 | |||
117 | if (in_array('all', $b)) { | ||
118 | return $a; | ||
119 | } | ||
120 | |||
121 | return array_intersect($a, $b); | ||
122 | } | ||
123 | |||
124 | /** | ||
125 | * {@inheritdoc} | ||
126 | */ | ||
127 | public function getPriority() | ||
128 | { | ||
129 | return 0; | ||
130 | } | ||
131 | } | ||
diff --git a/vendor/twig/twig/lib/Twig/NodeVisitor/Sandbox.php b/vendor/twig/twig/lib/Twig/NodeVisitor/Sandbox.php new file mode 100644 index 00000000..fb27045b --- /dev/null +++ b/vendor/twig/twig/lib/Twig/NodeVisitor/Sandbox.php | |||
@@ -0,0 +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 | } | ||
diff --git a/vendor/twig/twig/lib/Twig/NodeVisitorInterface.php b/vendor/twig/twig/lib/Twig/NodeVisitorInterface.php new file mode 100644 index 00000000..f33c13fc --- /dev/null +++ b/vendor/twig/twig/lib/Twig/NodeVisitorInterface.php | |||
@@ -0,0 +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 integer The priority level | ||
45 | */ | ||
46 | public function getPriority(); | ||
47 | } | ||
diff --git a/vendor/twig/twig/lib/Twig/Parser.php b/vendor/twig/twig/lib/Twig/Parser.php new file mode 100644 index 00000000..958e46b3 --- /dev/null +++ b/vendor/twig/twig/lib/Twig/Parser.php | |||
@@ -0,0 +1,394 @@ | |||
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('sha1', uniqid(mt_rand(), true), false)); | ||
53 | } | ||
54 | |||
55 | public function getFilename() | ||
56 | { | ||
57 | return $this->stream->getFilename(); | ||
58 | } | ||
59 | |||
60 | /** | ||
61 | * Converts a token stream to a node tree. | ||
62 | * | ||
63 | * @param Twig_TokenStream $stream A token stream instance | ||
64 | * | ||
65 | * @return Twig_Node_Module A node tree | ||
66 | */ | ||
67 | public function parse(Twig_TokenStream $stream, $test = null, $dropNeedle = false) | ||
68 | { | ||
69 | // push all variables into the stack to keep the current state of the parser | ||
70 | $vars = get_object_vars($this); | ||
71 | unset($vars['stack'], $vars['env'], $vars['handlers'], $vars['visitors'], $vars['expressionParser']); | ||
72 | $this->stack[] = $vars; | ||
73 | |||
74 | // tag handlers | ||
75 | if (null === $this->handlers) { | ||
76 | $this->handlers = $this->env->getTokenParsers(); | ||
77 | $this->handlers->setParser($this); | ||
78 | } | ||
79 | |||
80 | // node visitors | ||
81 | if (null === $this->visitors) { | ||
82 | $this->visitors = $this->env->getNodeVisitors(); | ||
83 | } | ||
84 | |||
85 | if (null === $this->expressionParser) { | ||
86 | $this->expressionParser = new Twig_ExpressionParser($this, $this->env->getUnaryOperators(), $this->env->getBinaryOperators()); | ||
87 | } | ||
88 | |||
89 | $this->stream = $stream; | ||
90 | $this->parent = null; | ||
91 | $this->blocks = array(); | ||
92 | $this->macros = array(); | ||
93 | $this->traits = array(); | ||
94 | $this->blockStack = array(); | ||
95 | $this->importedSymbols = array(array()); | ||
96 | $this->embeddedTemplates = array(); | ||
97 | |||
98 | try { | ||
99 | $body = $this->subparse($test, $dropNeedle); | ||
100 | |||
101 | if (null !== $this->parent) { | ||
102 | if (null === $body = $this->filterBodyNodes($body)) { | ||
103 | $body = new Twig_Node(); | ||
104 | } | ||
105 | } | ||
106 | } catch (Twig_Error_Syntax $e) { | ||
107 | if (!$e->getTemplateFile()) { | ||
108 | $e->setTemplateFile($this->getFilename()); | ||
109 | } | ||
110 | |||
111 | if (!$e->getTemplateLine()) { | ||
112 | $e->setTemplateLine($this->stream->getCurrent()->getLine()); | ||
113 | } | ||
114 | |||
115 | throw $e; | ||
116 | } | ||
117 | |||
118 | $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()); | ||
119 | |||
120 | $traverser = new Twig_NodeTraverser($this->env, $this->visitors); | ||
121 | |||
122 | $node = $traverser->traverse($node); | ||
123 | |||
124 | // restore previous stack so previous parse() call can resume working | ||
125 | foreach (array_pop($this->stack) as $key => $val) { | ||
126 | $this->$key = $val; | ||
127 | } | ||
128 | |||
129 | return $node; | ||
130 | } | ||
131 | |||
132 | public function subparse($test, $dropNeedle = false) | ||
133 | { | ||
134 | $lineno = $this->getCurrentToken()->getLine(); | ||
135 | $rv = array(); | ||
136 | while (!$this->stream->isEOF()) { | ||
137 | switch ($this->getCurrentToken()->getType()) { | ||
138 | case Twig_Token::TEXT_TYPE: | ||
139 | $token = $this->stream->next(); | ||
140 | $rv[] = new Twig_Node_Text($token->getValue(), $token->getLine()); | ||
141 | break; | ||
142 | |||
143 | case Twig_Token::VAR_START_TYPE: | ||
144 | $token = $this->stream->next(); | ||
145 | $expr = $this->expressionParser->parseExpression(); | ||
146 | $this->stream->expect(Twig_Token::VAR_END_TYPE); | ||
147 | $rv[] = new Twig_Node_Print($expr, $token->getLine()); | ||
148 | break; | ||
149 | |||
150 | case Twig_Token::BLOCK_START_TYPE: | ||
151 | $this->stream->next(); | ||
152 | $token = $this->getCurrentToken(); | ||
153 | |||
154 | if ($token->getType() !== Twig_Token::NAME_TYPE) { | ||
155 | throw new Twig_Error_Syntax('A block must start with a tag name', $token->getLine(), $this->getFilename()); | ||
156 | } | ||
157 | |||
158 | if (null !== $test && call_user_func($test, $token)) { | ||
159 | if ($dropNeedle) { | ||
160 | $this->stream->next(); | ||
161 | } | ||
162 | |||
163 | if (1 === count($rv)) { | ||
164 | return $rv[0]; | ||
165 | } | ||
166 | |||
167 | return new Twig_Node($rv, array(), $lineno); | ||
168 | } | ||
169 | |||
170 | $subparser = $this->handlers->getTokenParser($token->getValue()); | ||
171 | if (null === $subparser) { | ||
172 | if (null !== $test) { | ||
173 | $error = sprintf('Unexpected tag name "%s"', $token->getValue()); | ||
174 | if (is_array($test) && isset($test[0]) && $test[0] instanceof Twig_TokenParserInterface) { | ||
175 | $error .= sprintf(' (expecting closing tag for the "%s" tag defined near line %s)', $test[0]->getTag(), $lineno); | ||
176 | } | ||
177 | |||
178 | throw new Twig_Error_Syntax($error, $token->getLine(), $this->getFilename()); | ||
179 | } | ||
180 | |||
181 | $message = sprintf('Unknown tag name "%s"', $token->getValue()); | ||
182 | if ($alternatives = $this->env->computeAlternatives($token->getValue(), array_keys($this->env->getTags()))) { | ||
183 | $message = sprintf('%s. Did you mean "%s"', $message, implode('", "', $alternatives)); | ||
184 | } | ||
185 | |||
186 | throw new Twig_Error_Syntax($message, $token->getLine(), $this->getFilename()); | ||
187 | } | ||
188 | |||
189 | $this->stream->next(); | ||
190 | |||
191 | $node = $subparser->parse($token); | ||
192 | if (null !== $node) { | ||
193 | $rv[] = $node; | ||
194 | } | ||
195 | break; | ||
196 | |||
197 | default: | ||
198 | throw new Twig_Error_Syntax('Lexer or parser ended up in unsupported state.', 0, $this->getFilename()); | ||
199 | } | ||
200 | } | ||
201 | |||
202 | if (1 === count($rv)) { | ||
203 | return $rv[0]; | ||
204 | } | ||
205 | |||
206 | return new Twig_Node($rv, array(), $lineno); | ||
207 | } | ||
208 | |||
209 | public function addHandler($name, $class) | ||
210 | { | ||
211 | $this->handlers[$name] = $class; | ||
212 | } | ||
213 | |||
214 | public function addNodeVisitor(Twig_NodeVisitorInterface $visitor) | ||
215 | { | ||
216 | $this->visitors[] = $visitor; | ||
217 | } | ||
218 | |||
219 | public function getBlockStack() | ||
220 | { | ||
221 | return $this->blockStack; | ||
222 | } | ||
223 | |||
224 | public function peekBlockStack() | ||
225 | { | ||
226 | return $this->blockStack[count($this->blockStack) - 1]; | ||
227 | } | ||
228 | |||
229 | public function popBlockStack() | ||
230 | { | ||
231 | array_pop($this->blockStack); | ||
232 | } | ||
233 | |||
234 | public function pushBlockStack($name) | ||
235 | { | ||
236 | $this->blockStack[] = $name; | ||
237 | } | ||
238 | |||
239 | public function hasBlock($name) | ||
240 | { | ||
241 | return isset($this->blocks[$name]); | ||
242 | } | ||
243 | |||
244 | public function getBlock($name) | ||
245 | { | ||
246 | return $this->blocks[$name]; | ||
247 | } | ||
248 | |||
249 | public function setBlock($name, $value) | ||
250 | { | ||
251 | $this->blocks[$name] = new Twig_Node_Body(array($value), array(), $value->getLine()); | ||
252 | } | ||
253 | |||
254 | public function hasMacro($name) | ||
255 | { | ||
256 | return isset($this->macros[$name]); | ||
257 | } | ||
258 | |||
259 | public function setMacro($name, Twig_Node_Macro $node) | ||
260 | { | ||
261 | if (null === $this->reservedMacroNames) { | ||
262 | $this->reservedMacroNames = array(); | ||
263 | $r = new ReflectionClass($this->env->getBaseTemplateClass()); | ||
264 | foreach ($r->getMethods() as $method) { | ||
265 | $this->reservedMacroNames[] = $method->getName(); | ||
266 | } | ||
267 | } | ||
268 | |||
269 | if (in_array($name, $this->reservedMacroNames)) { | ||
270 | 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()); | ||
271 | } | ||
272 | |||
273 | $this->macros[$name] = $node; | ||
274 | } | ||
275 | |||
276 | public function addTrait($trait) | ||
277 | { | ||
278 | $this->traits[] = $trait; | ||
279 | } | ||
280 | |||
281 | public function hasTraits() | ||
282 | { | ||
283 | return count($this->traits) > 0; | ||
284 | } | ||
285 | |||
286 | public function embedTemplate(Twig_Node_Module $template) | ||
287 | { | ||
288 | $template->setIndex(mt_rand()); | ||
289 | |||
290 | $this->embeddedTemplates[] = $template; | ||
291 | } | ||
292 | |||
293 | public function addImportedSymbol($type, $alias, $name = null, Twig_Node_Expression $node = null) | ||
294 | { | ||
295 | $this->importedSymbols[0][$type][$alias] = array('name' => $name, 'node' => $node); | ||
296 | } | ||
297 | |||
298 | public function getImportedSymbol($type, $alias) | ||
299 | { | ||
300 | foreach ($this->importedSymbols as $functions) { | ||
301 | if (isset($functions[$type][$alias])) { | ||
302 | return $functions[$type][$alias]; | ||
303 | } | ||
304 | } | ||
305 | } | ||
306 | |||
307 | public function isMainScope() | ||
308 | { | ||
309 | return 1 === count($this->importedSymbols); | ||
310 | } | ||
311 | |||
312 | public function pushLocalScope() | ||
313 | { | ||
314 | array_unshift($this->importedSymbols, array()); | ||
315 | } | ||
316 | |||
317 | public function popLocalScope() | ||
318 | { | ||
319 | array_shift($this->importedSymbols); | ||
320 | } | ||
321 | |||
322 | /** | ||
323 | * Gets the expression parser. | ||
324 | * | ||
325 | * @return Twig_ExpressionParser The expression parser | ||
326 | */ | ||
327 | public function getExpressionParser() | ||
328 | { | ||
329 | return $this->expressionParser; | ||
330 | } | ||
331 | |||
332 | public function getParent() | ||
333 | { | ||
334 | return $this->parent; | ||
335 | } | ||
336 | |||
337 | public function setParent($parent) | ||
338 | { | ||
339 | $this->parent = $parent; | ||
340 | } | ||
341 | |||
342 | /** | ||
343 | * Gets the token stream. | ||
344 | * | ||
345 | * @return Twig_TokenStream The token stream | ||
346 | */ | ||
347 | public function getStream() | ||
348 | { | ||
349 | return $this->stream; | ||
350 | } | ||
351 | |||
352 | /** | ||
353 | * Gets the current token. | ||
354 | * | ||
355 | * @return Twig_Token The current token | ||
356 | */ | ||
357 | public function getCurrentToken() | ||
358 | { | ||
359 | return $this->stream->getCurrent(); | ||
360 | } | ||
361 | |||
362 | protected function filterBodyNodes(Twig_NodeInterface $node) | ||
363 | { | ||
364 | // check that the body does not contain non-empty output nodes | ||
365 | if ( | ||
366 | ($node instanceof Twig_Node_Text && !ctype_space($node->getAttribute('data'))) | ||
367 | || | ||
368 | (!$node instanceof Twig_Node_Text && !$node instanceof Twig_Node_BlockReference && $node instanceof Twig_NodeOutputInterface) | ||
369 | ) { | ||
370 | if (false !== strpos((string) $node, chr(0xEF).chr(0xBB).chr(0xBF))) { | ||
371 | 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()); | ||
372 | } | ||
373 | |||
374 | throw new Twig_Error_Syntax('A template that extends another one cannot have a body.', $node->getLine(), $this->getFilename()); | ||
375 | } | ||
376 | |||
377 | // bypass "set" nodes as they "capture" the output | ||
378 | if ($node instanceof Twig_Node_Set) { | ||
379 | return $node; | ||
380 | } | ||
381 | |||
382 | if ($node instanceof Twig_NodeOutputInterface) { | ||
383 | return; | ||
384 | } | ||
385 | |||
386 | foreach ($node as $k => $n) { | ||
387 | if (null !== $n && null === $n = $this->filterBodyNodes($n)) { | ||
388 | $node->removeNode($k); | ||
389 | } | ||
390 | } | ||
391 | |||
392 | return $node; | ||
393 | } | ||
394 | } | ||
diff --git a/vendor/twig/twig/lib/Twig/ParserInterface.php b/vendor/twig/twig/lib/Twig/ParserInterface.php new file mode 100644 index 00000000..f0d79009 --- /dev/null +++ b/vendor/twig/twig/lib/Twig/ParserInterface.php | |||
@@ -0,0 +1,28 @@ | |||
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 | * @deprecated since 1.12 (to be removed in 2.0) | ||
17 | */ | ||
18 | interface Twig_ParserInterface | ||
19 | { | ||
20 | /** | ||
21 | * Converts a token stream to a node tree. | ||
22 | * | ||
23 | * @param Twig_TokenStream $stream A token stream instance | ||
24 | * | ||
25 | * @return Twig_Node_Module A node tree | ||
26 | */ | ||
27 | public function parse(Twig_TokenStream $stream); | ||
28 | } | ||
diff --git a/vendor/twig/twig/lib/Twig/Sandbox/SecurityError.php b/vendor/twig/twig/lib/Twig/Sandbox/SecurityError.php new file mode 100644 index 00000000..015bfaea --- /dev/null +++ b/vendor/twig/twig/lib/Twig/Sandbox/SecurityError.php | |||
@@ -0,0 +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 | } | ||
diff --git a/vendor/twig/twig/lib/Twig/Sandbox/SecurityPolicy.php b/vendor/twig/twig/lib/Twig/Sandbox/SecurityPolicy.php new file mode 100644 index 00000000..66ee2332 --- /dev/null +++ b/vendor/twig/twig/lib/Twig/Sandbox/SecurityPolicy.php | |||
@@ -0,0 +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 | } | ||
diff --git a/vendor/twig/twig/lib/Twig/Sandbox/SecurityPolicyInterface.php b/vendor/twig/twig/lib/Twig/Sandbox/SecurityPolicyInterface.php new file mode 100644 index 00000000..6ab48e3c --- /dev/null +++ b/vendor/twig/twig/lib/Twig/Sandbox/SecurityPolicyInterface.php | |||
@@ -0,0 +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 | } | ||
diff --git a/vendor/twig/twig/lib/Twig/SimpleFilter.php b/vendor/twig/twig/lib/Twig/SimpleFilter.php new file mode 100644 index 00000000..d35c5633 --- /dev/null +++ b/vendor/twig/twig/lib/Twig/SimpleFilter.php | |||
@@ -0,0 +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 | } | ||
diff --git a/vendor/twig/twig/lib/Twig/SimpleFunction.php b/vendor/twig/twig/lib/Twig/SimpleFunction.php new file mode 100644 index 00000000..8ef6aca2 --- /dev/null +++ b/vendor/twig/twig/lib/Twig/SimpleFunction.php | |||
@@ -0,0 +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 | } | ||
diff --git a/vendor/twig/twig/lib/Twig/SimpleTest.php b/vendor/twig/twig/lib/Twig/SimpleTest.php new file mode 100644 index 00000000..225459c9 --- /dev/null +++ b/vendor/twig/twig/lib/Twig/SimpleTest.php | |||
@@ -0,0 +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 | } | ||
diff --git a/vendor/twig/twig/lib/Twig/Template.php b/vendor/twig/twig/lib/Twig/Template.php new file mode 100644 index 00000000..a001ca03 --- /dev/null +++ b/vendor/twig/twig/lib/Twig/Template.php | |||
@@ -0,0 +1,455 @@ | |||
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); | ||
109 | } elseif (false !== $parent = $this->getParent($context)) { | ||
110 | $parent->displayBlock($name, $context, $blocks); | ||
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 | */ | ||
126 | public function displayBlock($name, array $context, array $blocks = array()) | ||
127 | { | ||
128 | $name = (string) $name; | ||
129 | |||
130 | if (isset($blocks[$name])) { | ||
131 | $b = $blocks; | ||
132 | unset($b[$name]); | ||
133 | call_user_func($blocks[$name], $context, $b); | ||
134 | } elseif (isset($this->blocks[$name])) { | ||
135 | call_user_func($this->blocks[$name], $context, $blocks); | ||
136 | } elseif (false !== $parent = $this->getParent($context)) { | ||
137 | $parent->displayBlock($name, $context, array_merge($this->blocks, $blocks)); | ||
138 | } | ||
139 | } | ||
140 | |||
141 | /** | ||
142 | * Renders a parent block. | ||
143 | * | ||
144 | * This method is for internal use only and should never be called | ||
145 | * directly. | ||
146 | * | ||
147 | * @param string $name The block name to render from the parent | ||
148 | * @param array $context The context | ||
149 | * @param array $blocks The current set of blocks | ||
150 | * | ||
151 | * @return string The rendered block | ||
152 | */ | ||
153 | public function renderParentBlock($name, array $context, array $blocks = array()) | ||
154 | { | ||
155 | ob_start(); | ||
156 | $this->displayParentBlock($name, $context, $blocks); | ||
157 | |||
158 | return ob_get_clean(); | ||
159 | } | ||
160 | |||
161 | /** | ||
162 | * Renders a block. | ||
163 | * | ||
164 | * This method is for internal use only and should never be called | ||
165 | * directly. | ||
166 | * | ||
167 | * @param string $name The block name to render | ||
168 | * @param array $context The context | ||
169 | * @param array $blocks The current set of blocks | ||
170 | * | ||
171 | * @return string The rendered block | ||
172 | */ | ||
173 | public function renderBlock($name, array $context, array $blocks = array()) | ||
174 | { | ||
175 | ob_start(); | ||
176 | $this->displayBlock($name, $context, $blocks); | ||
177 | |||
178 | return ob_get_clean(); | ||
179 | } | ||
180 | |||
181 | /** | ||
182 | * Returns whether a block exists or not. | ||
183 | * | ||
184 | * This method is for internal use only and should never be called | ||
185 | * directly. | ||
186 | * | ||
187 | * This method does only return blocks defined in the current template | ||
188 | * or defined in "used" traits. | ||
189 | * | ||
190 | * It does not return blocks from parent templates as the parent | ||
191 | * template name can be dynamic, which is only known based on the | ||
192 | * current context. | ||
193 | * | ||
194 | * @param string $name The block name | ||
195 | * | ||
196 | * @return Boolean true if the block exists, false otherwise | ||
197 | */ | ||
198 | public function hasBlock($name) | ||
199 | { | ||
200 | return isset($this->blocks[(string) $name]); | ||
201 | } | ||
202 | |||
203 | /** | ||
204 | * Returns all block names. | ||
205 | * | ||
206 | * This method is for internal use only and should never be called | ||
207 | * directly. | ||
208 | * | ||
209 | * @return array An array of block names | ||
210 | * | ||
211 | * @see hasBlock | ||
212 | */ | ||
213 | public function getBlockNames() | ||
214 | { | ||
215 | return array_keys($this->blocks); | ||
216 | } | ||
217 | |||
218 | /** | ||
219 | * Returns all blocks. | ||
220 | * | ||
221 | * This method is for internal use only and should never be called | ||
222 | * directly. | ||
223 | * | ||
224 | * @return array An array of blocks | ||
225 | * | ||
226 | * @see hasBlock | ||
227 | */ | ||
228 | public function getBlocks() | ||
229 | { | ||
230 | return $this->blocks; | ||
231 | } | ||
232 | |||
233 | /** | ||
234 | * {@inheritdoc} | ||
235 | */ | ||
236 | public function display(array $context, array $blocks = array()) | ||
237 | { | ||
238 | $this->displayWithErrorHandling($this->env->mergeGlobals($context), $blocks); | ||
239 | } | ||
240 | |||
241 | /** | ||
242 | * {@inheritdoc} | ||
243 | */ | ||
244 | public function render(array $context) | ||
245 | { | ||
246 | $level = ob_get_level(); | ||
247 | ob_start(); | ||
248 | try { | ||
249 | $this->display($context); | ||
250 | } catch (Exception $e) { | ||
251 | while (ob_get_level() > $level) { | ||
252 | ob_end_clean(); | ||
253 | } | ||
254 | |||
255 | throw $e; | ||
256 | } | ||
257 | |||
258 | return ob_get_clean(); | ||
259 | } | ||
260 | |||
261 | protected function displayWithErrorHandling(array $context, array $blocks = array()) | ||
262 | { | ||
263 | try { | ||
264 | $this->doDisplay($context, $blocks); | ||
265 | } catch (Twig_Error $e) { | ||
266 | if (!$e->getTemplateFile()) { | ||
267 | $e->setTemplateFile($this->getTemplateName()); | ||
268 | } | ||
269 | |||
270 | // this is mostly useful for Twig_Error_Loader exceptions | ||
271 | // see Twig_Error_Loader | ||
272 | if (false === $e->getTemplateLine()) { | ||
273 | $e->setTemplateLine(-1); | ||
274 | $e->guess(); | ||
275 | } | ||
276 | |||
277 | throw $e; | ||
278 | } catch (Exception $e) { | ||
279 | throw new Twig_Error_Runtime(sprintf('An exception has been thrown during the rendering of a template ("%s").', $e->getMessage()), -1, null, $e); | ||
280 | } | ||
281 | } | ||
282 | |||
283 | /** | ||
284 | * Auto-generated method to display the template with the given context. | ||
285 | * | ||
286 | * @param array $context An array of parameters to pass to the template | ||
287 | * @param array $blocks An array of blocks to pass to the template | ||
288 | */ | ||
289 | abstract protected function doDisplay(array $context, array $blocks = array()); | ||
290 | |||
291 | /** | ||
292 | * Returns a variable from the context. | ||
293 | * | ||
294 | * This method is for internal use only and should never be called | ||
295 | * directly. | ||
296 | * | ||
297 | * This method should not be overridden in a sub-class as this is an | ||
298 | * implementation detail that has been introduced to optimize variable | ||
299 | * access for versions of PHP before 5.4. This is not a way to override | ||
300 | * the way to get a variable value. | ||
301 | * | ||
302 | * @param array $context The context | ||
303 | * @param string $item The variable to return from the context | ||
304 | * @param Boolean $ignoreStrictCheck Whether to ignore the strict variable check or not | ||
305 | * | ||
306 | * @return The content of the context variable | ||
307 | * | ||
308 | * @throws Twig_Error_Runtime if the variable does not exist and Twig is running in strict mode | ||
309 | */ | ||
310 | final protected function getContext($context, $item, $ignoreStrictCheck = false) | ||
311 | { | ||
312 | if (!array_key_exists($item, $context)) { | ||
313 | if ($ignoreStrictCheck || !$this->env->isStrictVariables()) { | ||
314 | return null; | ||
315 | } | ||
316 | |||
317 | throw new Twig_Error_Runtime(sprintf('Variable "%s" does not exist', $item), -1, $this->getTemplateName()); | ||
318 | } | ||
319 | |||
320 | return $context[$item]; | ||
321 | } | ||
322 | |||
323 | /** | ||
324 | * Returns the attribute value for a given array/object. | ||
325 | * | ||
326 | * @param mixed $object The object or array from where to get the item | ||
327 | * @param mixed $item The item to get from the array or object | ||
328 | * @param array $arguments An array of arguments to pass if the item is an object method | ||
329 | * @param string $type The type of attribute (@see Twig_TemplateInterface) | ||
330 | * @param Boolean $isDefinedTest Whether this is only a defined check | ||
331 | * @param Boolean $ignoreStrictCheck Whether to ignore the strict attribute check or not | ||
332 | * | ||
333 | * @return mixed The attribute value, or a Boolean when $isDefinedTest is true, or null when the attribute is not set and $ignoreStrictCheck is true | ||
334 | * | ||
335 | * @throws Twig_Error_Runtime if the attribute does not exist and Twig is running in strict mode and $isDefinedTest is false | ||
336 | */ | ||
337 | protected function getAttribute($object, $item, array $arguments = array(), $type = Twig_TemplateInterface::ANY_CALL, $isDefinedTest = false, $ignoreStrictCheck = false) | ||
338 | { | ||
339 | // array | ||
340 | if (Twig_TemplateInterface::METHOD_CALL !== $type) { | ||
341 | $arrayItem = is_bool($item) || is_float($item) ? (int) $item : $item; | ||
342 | |||
343 | if ((is_array($object) && array_key_exists($arrayItem, $object)) | ||
344 | || ($object instanceof ArrayAccess && isset($object[$arrayItem])) | ||
345 | ) { | ||
346 | if ($isDefinedTest) { | ||
347 | return true; | ||
348 | } | ||
349 | |||
350 | return $object[$arrayItem]; | ||
351 | } | ||
352 | |||
353 | if (Twig_TemplateInterface::ARRAY_CALL === $type || !is_object($object)) { | ||
354 | if ($isDefinedTest) { | ||
355 | return false; | ||
356 | } | ||
357 | |||
358 | if ($ignoreStrictCheck || !$this->env->isStrictVariables()) { | ||
359 | return null; | ||
360 | } | ||
361 | |||
362 | if (is_object($object)) { | ||
363 | throw new Twig_Error_Runtime(sprintf('Key "%s" in object (with ArrayAccess) of type "%s" does not exist', $arrayItem, get_class($object)), -1, $this->getTemplateName()); | ||
364 | } elseif (is_array($object)) { | ||
365 | throw new Twig_Error_Runtime(sprintf('Key "%s" for array with keys "%s" does not exist', $arrayItem, implode(', ', array_keys($object))), -1, $this->getTemplateName()); | ||
366 | } elseif (Twig_TemplateInterface::ARRAY_CALL === $type) { | ||
367 | throw new Twig_Error_Runtime(sprintf('Impossible to access a key ("%s") on a %s variable ("%s")', $item, gettype($object), $object), -1, $this->getTemplateName()); | ||
368 | } else { | ||
369 | throw new Twig_Error_Runtime(sprintf('Impossible to access an attribute ("%s") on a %s variable ("%s")', $item, gettype($object), $object), -1, $this->getTemplateName()); | ||
370 | } | ||
371 | } | ||
372 | } | ||
373 | |||
374 | if (!is_object($object)) { | ||
375 | if ($isDefinedTest) { | ||
376 | return false; | ||
377 | } | ||
378 | |||
379 | if ($ignoreStrictCheck || !$this->env->isStrictVariables()) { | ||
380 | return null; | ||
381 | } | ||
382 | |||
383 | throw new Twig_Error_Runtime(sprintf('Impossible to invoke a method ("%s") on a %s variable ("%s")', $item, gettype($object), $object), -1, $this->getTemplateName()); | ||
384 | } | ||
385 | |||
386 | $class = get_class($object); | ||
387 | |||
388 | // object property | ||
389 | if (Twig_TemplateInterface::METHOD_CALL !== $type) { | ||
390 | if (isset($object->$item) || array_key_exists((string) $item, $object)) { | ||
391 | if ($isDefinedTest) { | ||
392 | return true; | ||
393 | } | ||
394 | |||
395 | if ($this->env->hasExtension('sandbox')) { | ||
396 | $this->env->getExtension('sandbox')->checkPropertyAllowed($object, $item); | ||
397 | } | ||
398 | |||
399 | return $object->$item; | ||
400 | } | ||
401 | } | ||
402 | |||
403 | // object method | ||
404 | if (!isset(self::$cache[$class]['methods'])) { | ||
405 | self::$cache[$class]['methods'] = array_change_key_case(array_flip(get_class_methods($object))); | ||
406 | } | ||
407 | |||
408 | $lcItem = strtolower($item); | ||
409 | if (isset(self::$cache[$class]['methods'][$lcItem])) { | ||
410 | $method = (string) $item; | ||
411 | } elseif (isset(self::$cache[$class]['methods']['get'.$lcItem])) { | ||
412 | $method = 'get'.$item; | ||
413 | } elseif (isset(self::$cache[$class]['methods']['is'.$lcItem])) { | ||
414 | $method = 'is'.$item; | ||
415 | } elseif (isset(self::$cache[$class]['methods']['__call'])) { | ||
416 | $method = (string) $item; | ||
417 | } else { | ||
418 | if ($isDefinedTest) { | ||
419 | return false; | ||
420 | } | ||
421 | |||
422 | if ($ignoreStrictCheck || !$this->env->isStrictVariables()) { | ||
423 | return null; | ||
424 | } | ||
425 | |||
426 | throw new Twig_Error_Runtime(sprintf('Method "%s" for object "%s" does not exist', $item, get_class($object)), -1, $this->getTemplateName()); | ||
427 | } | ||
428 | |||
429 | if ($isDefinedTest) { | ||
430 | return true; | ||
431 | } | ||
432 | |||
433 | if ($this->env->hasExtension('sandbox')) { | ||
434 | $this->env->getExtension('sandbox')->checkMethodAllowed($object, $method); | ||
435 | } | ||
436 | |||
437 | $ret = call_user_func_array(array($object, $method), $arguments); | ||
438 | |||
439 | // useful when calling a template method from a template | ||
440 | // this is not supported but unfortunately heavily used in the Symfony profiler | ||
441 | if ($object instanceof Twig_TemplateInterface) { | ||
442 | return $ret === '' ? '' : new Twig_Markup($ret, $this->env->getCharset()); | ||
443 | } | ||
444 | |||
445 | return $ret; | ||
446 | } | ||
447 | |||
448 | /** | ||
449 | * This method is only useful when testing Twig. Do not use it. | ||
450 | */ | ||
451 | public static function clearCache() | ||
452 | { | ||
453 | self::$cache = array(); | ||
454 | } | ||
455 | } | ||
diff --git a/vendor/twig/twig/lib/Twig/TemplateInterface.php b/vendor/twig/twig/lib/Twig/TemplateInterface.php new file mode 100644 index 00000000..879f503e --- /dev/null +++ b/vendor/twig/twig/lib/Twig/TemplateInterface.php | |||
@@ -0,0 +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 | * Interface implemented by all compiled templates. | ||
14 | * | ||
15 | * @author Fabien Potencier <fabien@symfony.com> | ||
16 | * @deprecated since 1.12 (to be removed in 2.0) | ||
17 | */ | ||
18 | interface Twig_TemplateInterface | ||
19 | { | ||
20 | const ANY_CALL = 'any'; | ||
21 | const ARRAY_CALL = 'array'; | ||
22 | const METHOD_CALL = 'method'; | ||
23 | |||
24 | /** | ||
25 | * Renders the template with the given context and returns it as string. | ||
26 | * | ||
27 | * @param array $context An array of parameters to pass to the template | ||
28 | * | ||
29 | * @return string The rendered template | ||
30 | */ | ||
31 | public function render(array $context); | ||
32 | |||
33 | /** | ||
34 | * Displays the template with the given context. | ||
35 | * | ||
36 | * @param array $context An array of parameters to pass to the template | ||
37 | * @param array $blocks An array of blocks to pass to the template | ||
38 | */ | ||
39 | public function display(array $context, array $blocks = array()); | ||
40 | |||
41 | /** | ||
42 | * Returns the bound environment for this template. | ||
43 | * | ||
44 | * @return Twig_Environment The current environment | ||
45 | */ | ||
46 | public function getEnvironment(); | ||
47 | } | ||
diff --git a/vendor/twig/twig/lib/Twig/Test.php b/vendor/twig/twig/lib/Twig/Test.php new file mode 100644 index 00000000..3baff885 --- /dev/null +++ b/vendor/twig/twig/lib/Twig/Test.php | |||
@@ -0,0 +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 | } | ||
diff --git a/vendor/twig/twig/lib/Twig/Test/Function.php b/vendor/twig/twig/lib/Twig/Test/Function.php new file mode 100644 index 00000000..4be6b9b9 --- /dev/null +++ b/vendor/twig/twig/lib/Twig/Test/Function.php | |||
@@ -0,0 +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 | |||
12 | /** | ||
13 | * Represents a function template test. | ||
14 | * | ||
15 | * @author Fabien Potencier <fabien@symfony.com> | ||
16 | * @deprecated since 1.12 (to be removed in 2.0) | ||
17 | */ | ||
18 | class Twig_Test_Function extends Twig_Test | ||
19 | { | ||
20 | protected $function; | ||
21 | |||
22 | public function __construct($function, array $options = array()) | ||
23 | { | ||
24 | $options['callable'] = $function; | ||
25 | |||
26 | parent::__construct($options); | ||
27 | |||
28 | $this->function = $function; | ||
29 | } | ||
30 | |||
31 | public function compile() | ||
32 | { | ||
33 | return $this->function; | ||
34 | } | ||
35 | } | ||
diff --git a/vendor/twig/twig/lib/Twig/Test/IntegrationTestCase.php b/vendor/twig/twig/lib/Twig/Test/IntegrationTestCase.php new file mode 100644 index 00000000..724f0941 --- /dev/null +++ b/vendor/twig/twig/lib/Twig/Test/IntegrationTestCase.php | |||
@@ -0,0 +1,154 @@ | |||
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 | * Integration test helper | ||
14 | * | ||
15 | * @author Fabien Potencier <fabien@symfony.com> | ||
16 | * @author Karma Dordrak <drak@zikula.org> | ||
17 | */ | ||
18 | abstract class Twig_Test_IntegrationTestCase extends PHPUnit_Framework_TestCase | ||
19 | { | ||
20 | abstract protected function getExtensions(); | ||
21 | abstract protected function getFixturesDir(); | ||
22 | |||
23 | /** | ||
24 | * @dataProvider getTests | ||
25 | */ | ||
26 | public function testIntegration($file, $message, $condition, $templates, $exception, $outputs) | ||
27 | { | ||
28 | $this->doIntegrationTest($file, $message, $condition, $templates, $exception, $outputs); | ||
29 | } | ||
30 | |||
31 | public function getTests() | ||
32 | { | ||
33 | $fixturesDir = realpath($this->getFixturesDir()); | ||
34 | $tests = array(); | ||
35 | |||
36 | foreach (new RecursiveIteratorIterator(new RecursiveDirectoryIterator($fixturesDir), RecursiveIteratorIterator::LEAVES_ONLY) as $file) { | ||
37 | if (!preg_match('/\.test$/', $file)) { | ||
38 | continue; | ||
39 | } | ||
40 | |||
41 | $test = file_get_contents($file->getRealpath()); | ||
42 | |||
43 | if (preg_match('/ | ||
44 | --TEST--\s*(.*?)\s*(?:--CONDITION--\s*(.*))?\s*((?:--TEMPLATE(?:\(.*?\))?--(?:.*?))+)\s*(?:--DATA--\s*(.*))?\s*--EXCEPTION--\s*(.*)/sx', $test, $match)) { | ||
45 | $message = $match[1]; | ||
46 | $condition = $match[2]; | ||
47 | $templates = $this->parseTemplates($match[3]); | ||
48 | $exception = $match[5]; | ||
49 | $outputs = array(array(null, $match[4], null, '')); | ||
50 | } elseif (preg_match('/--TEST--\s*(.*?)\s*(?:--CONDITION--\s*(.*))?\s*((?:--TEMPLATE(?:\(.*?\))?--(?:.*?))+)--DATA--.*?--EXPECT--.*/s', $test, $match)) { | ||
51 | $message = $match[1]; | ||
52 | $condition = $match[2]; | ||
53 | $templates = $this->parseTemplates($match[3]); | ||
54 | $exception = false; | ||
55 | preg_match_all('/--DATA--(.*?)(?:--CONFIG--(.*?))?--EXPECT--(.*?)(?=\-\-DATA\-\-|$)/s', $test, $outputs, PREG_SET_ORDER); | ||
56 | } else { | ||
57 | throw new InvalidArgumentException(sprintf('Test "%s" is not valid.', str_replace($fixturesDir.'/', '', $file))); | ||
58 | } | ||
59 | |||
60 | $tests[] = array(str_replace($fixturesDir.'/', '', $file), $message, $condition, $templates, $exception, $outputs); | ||
61 | } | ||
62 | |||
63 | return $tests; | ||
64 | } | ||
65 | |||
66 | protected function doIntegrationTest($file, $message, $condition, $templates, $exception, $outputs) | ||
67 | { | ||
68 | if ($condition) { | ||
69 | eval('$ret = '.$condition.';'); | ||
70 | if (!$ret) { | ||
71 | $this->markTestSkipped($condition); | ||
72 | } | ||
73 | } | ||
74 | |||
75 | $loader = new Twig_Loader_Array($templates); | ||
76 | |||
77 | foreach ($outputs as $match) { | ||
78 | $config = array_merge(array( | ||
79 | 'cache' => false, | ||
80 | 'strict_variables' => true, | ||
81 | ), $match[2] ? eval($match[2].';') : array()); | ||
82 | $twig = new Twig_Environment($loader, $config); | ||
83 | $twig->addGlobal('global', 'global'); | ||
84 | foreach ($this->getExtensions() as $extension) { | ||
85 | $twig->addExtension($extension); | ||
86 | } | ||
87 | |||
88 | try { | ||
89 | $template = $twig->loadTemplate('index.twig'); | ||
90 | } catch (Exception $e) { | ||
91 | if (false !== $exception) { | ||
92 | $this->assertEquals(trim($exception), trim(sprintf('%s: %s', get_class($e), $e->getMessage()))); | ||
93 | |||
94 | return; | ||
95 | } | ||
96 | |||
97 | if ($e instanceof Twig_Error_Syntax) { | ||
98 | $e->setTemplateFile($file); | ||
99 | |||
100 | throw $e; | ||
101 | } | ||
102 | |||
103 | throw new Twig_Error(sprintf('%s: %s', get_class($e), $e->getMessage()), -1, $file, $e); | ||
104 | } | ||
105 | |||
106 | try { | ||
107 | $output = trim($template->render(eval($match[1].';')), "\n "); | ||
108 | } catch (Exception $e) { | ||
109 | if (false !== $exception) { | ||
110 | $this->assertEquals(trim($exception), trim(sprintf('%s: %s', get_class($e), $e->getMessage()))); | ||
111 | |||
112 | return; | ||
113 | } | ||
114 | |||
115 | if ($e instanceof Twig_Error_Syntax) { | ||
116 | $e->setTemplateFile($file); | ||
117 | } else { | ||
118 | $e = new Twig_Error(sprintf('%s: %s', get_class($e), $e->getMessage()), -1, $file, $e); | ||
119 | } | ||
120 | |||
121 | $output = trim(sprintf('%s: %s', get_class($e), $e->getMessage())); | ||
122 | } | ||
123 | |||
124 | if (false !== $exception) { | ||
125 | list($class, ) = explode(':', $exception); | ||
126 | $this->assertThat(NULL, new PHPUnit_Framework_Constraint_Exception($class)); | ||
127 | } | ||
128 | |||
129 | $expected = trim($match[3], "\n "); | ||
130 | |||
131 | if ($expected != $output) { | ||
132 | echo 'Compiled template that failed:'; | ||
133 | |||
134 | foreach (array_keys($templates) as $name) { | ||
135 | echo "Template: $name\n"; | ||
136 | $source = $loader->getSource($name); | ||
137 | echo $twig->compile($twig->parse($twig->tokenize($source, $name))); | ||
138 | } | ||
139 | } | ||
140 | $this->assertEquals($expected, $output, $message.' (in '.$file.')'); | ||
141 | } | ||
142 | } | ||
143 | |||
144 | protected static function parseTemplates($test) | ||
145 | { | ||
146 | $templates = array(); | ||
147 | preg_match_all('/--TEMPLATE(?:\((.*?)\))?--(.*?)(?=\-\-TEMPLATE|$)/s', $test, $matches, PREG_SET_ORDER); | ||
148 | foreach ($matches as $match) { | ||
149 | $templates[($match[1] ? $match[1] : 'index.twig')] = $match[2]; | ||
150 | } | ||
151 | |||
152 | return $templates; | ||
153 | } | ||
154 | } | ||
diff --git a/vendor/twig/twig/lib/Twig/Test/Method.php b/vendor/twig/twig/lib/Twig/Test/Method.php new file mode 100644 index 00000000..17c6c041 --- /dev/null +++ b/vendor/twig/twig/lib/Twig/Test/Method.php | |||
@@ -0,0 +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 | * Represents a method template test. | ||
14 | * | ||
15 | * @author Fabien Potencier <fabien@symfony.com> | ||
16 | * @deprecated since 1.12 (to be removed in 2.0) | ||
17 | */ | ||
18 | class Twig_Test_Method extends Twig_Test | ||
19 | { | ||
20 | protected $extension; | ||
21 | protected $method; | ||
22 | |||
23 | public function __construct(Twig_ExtensionInterface $extension, $method, array $options = array()) | ||
24 | { | ||
25 | $options['callable'] = array($extension, $method); | ||
26 | |||
27 | parent::__construct($options); | ||
28 | |||
29 | $this->extension = $extension; | ||
30 | $this->method = $method; | ||
31 | } | ||
32 | |||
33 | public function compile() | ||
34 | { | ||
35 | return sprintf('$this->env->getExtension(\'%s\')->%s', $this->extension->getName(), $this->method); | ||
36 | } | ||
37 | } | ||
diff --git a/vendor/twig/twig/lib/Twig/Test/Node.php b/vendor/twig/twig/lib/Twig/Test/Node.php new file mode 100644 index 00000000..c832a57b --- /dev/null +++ b/vendor/twig/twig/lib/Twig/Test/Node.php | |||
@@ -0,0 +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 | * Represents a template test as a Node. | ||
14 | * | ||
15 | * @author Fabien Potencier <fabien@symfony.com> | ||
16 | * @deprecated since 1.12 (to be removed in 2.0) | ||
17 | */ | ||
18 | class Twig_Test_Node extends Twig_Test | ||
19 | { | ||
20 | protected $class; | ||
21 | |||
22 | public function __construct($class, array $options = array()) | ||
23 | { | ||
24 | parent::__construct($options); | ||
25 | |||
26 | $this->class = $class; | ||
27 | } | ||
28 | |||
29 | public function getClass() | ||
30 | { | ||
31 | return $this->class; | ||
32 | } | ||
33 | |||
34 | public function compile() | ||
35 | { | ||
36 | } | ||
37 | } | ||
diff --git a/vendor/twig/twig/lib/Twig/Test/NodeTestCase.php b/vendor/twig/twig/lib/Twig/Test/NodeTestCase.php new file mode 100644 index 00000000..b15c85ff --- /dev/null +++ b/vendor/twig/twig/lib/Twig/Test/NodeTestCase.php | |||
@@ -0,0 +1,58 @@ | |||
1 | <?php | ||
2 | |||
3 | /* | ||
4 | * This file is part of Twig. | ||
5 | * | ||
6 | * (c) 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_Test_NodeTestCase extends PHPUnit_Framework_TestCase | ||
12 | { | ||
13 | abstract public function getTests(); | ||
14 | |||
15 | /** | ||
16 | * @dataProvider getTests | ||
17 | */ | ||
18 | public function testCompile($node, $source, $environment = null) | ||
19 | { | ||
20 | $this->assertNodeCompilation($source, $node, $environment); | ||
21 | } | ||
22 | |||
23 | public function assertNodeCompilation($source, Twig_Node $node, Twig_Environment $environment = null) | ||
24 | { | ||
25 | $compiler = $this->getCompiler($environment); | ||
26 | $compiler->compile($node); | ||
27 | |||
28 | $this->assertEquals($source, trim($compiler->getSource())); | ||
29 | } | ||
30 | |||
31 | protected function getCompiler(Twig_Environment $environment = null) | ||
32 | { | ||
33 | return new Twig_Compiler(null === $environment ? $this->getEnvironment() : $environment); | ||
34 | } | ||
35 | |||
36 | protected function getEnvironment() | ||
37 | { | ||
38 | return new Twig_Environment(); | ||
39 | } | ||
40 | |||
41 | protected function getVariableGetter($name) | ||
42 | { | ||
43 | if (version_compare(phpversion(), '5.4.0RC1', '>=')) { | ||
44 | return sprintf('(isset($context["%s"]) ? $context["%s"] : null)', $name, $name); | ||
45 | } | ||
46 | |||
47 | return sprintf('$this->getContext($context, "%s")', $name); | ||
48 | } | ||
49 | |||
50 | protected function getAttributeGetter() | ||
51 | { | ||
52 | if (function_exists('twig_template_get_attributes')) { | ||
53 | return 'twig_template_get_attributes($this, '; | ||
54 | } | ||
55 | |||
56 | return '$this->getAttribute('; | ||
57 | } | ||
58 | } | ||
diff --git a/vendor/twig/twig/lib/Twig/TestCallableInterface.php b/vendor/twig/twig/lib/Twig/TestCallableInterface.php new file mode 100644 index 00000000..0db43682 --- /dev/null +++ b/vendor/twig/twig/lib/Twig/TestCallableInterface.php | |||
@@ -0,0 +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 | } | ||
diff --git a/vendor/twig/twig/lib/Twig/TestInterface.php b/vendor/twig/twig/lib/Twig/TestInterface.php new file mode 100644 index 00000000..30d8a2c4 --- /dev/null +++ b/vendor/twig/twig/lib/Twig/TestInterface.php | |||
@@ -0,0 +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 | } | ||
diff --git a/vendor/twig/twig/lib/Twig/Token.php b/vendor/twig/twig/lib/Twig/Token.php new file mode 100644 index 00000000..bbca90db --- /dev/null +++ b/vendor/twig/twig/lib/Twig/Token.php | |||
@@ -0,0 +1,218 @@ | |||
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 integer $type The type of the token | ||
42 | * @param string $value The token value | ||
43 | * @param integer $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->lineno), $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|integer $type The type to test | ||
71 | * @param array|string|null $values The token value | ||
72 | * | ||
73 | * @return Boolean | ||
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 integer The source line | ||
93 | */ | ||
94 | public function getLine() | ||
95 | { | ||
96 | return $this->lineno; | ||
97 | } | ||
98 | |||
99 | /** | ||
100 | * Gets the token type. | ||
101 | * | ||
102 | * @return integer 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 integer $type The type as an integer | ||
123 | * @param Boolean $short Whether to return a short representation or not | ||
124 | * @param integer $line The code line | ||
125 | * | ||
126 | * @return string The string representation | ||
127 | */ | ||
128 | public static function typeToString($type, $short = false, $line = -1) | ||
129 | { | ||
130 | switch ($type) { | ||
131 | case self::EOF_TYPE: | ||
132 | $name = 'EOF_TYPE'; | ||
133 | break; | ||
134 | case self::TEXT_TYPE: | ||
135 | $name = 'TEXT_TYPE'; | ||
136 | break; | ||
137 | case self::BLOCK_START_TYPE: | ||
138 | $name = 'BLOCK_START_TYPE'; | ||
139 | break; | ||
140 | case self::VAR_START_TYPE: | ||
141 | $name = 'VAR_START_TYPE'; | ||
142 | break; | ||
143 | case self::BLOCK_END_TYPE: | ||
144 | $name = 'BLOCK_END_TYPE'; | ||
145 | break; | ||
146 | case self::VAR_END_TYPE: | ||
147 | $name = 'VAR_END_TYPE'; | ||
148 | break; | ||
149 | case self::NAME_TYPE: | ||
150 | $name = 'NAME_TYPE'; | ||
151 | break; | ||
152 | case self::NUMBER_TYPE: | ||
153 | $name = 'NUMBER_TYPE'; | ||
154 | break; | ||
155 | case self::STRING_TYPE: | ||
156 | $name = 'STRING_TYPE'; | ||
157 | break; | ||
158 | case self::OPERATOR_TYPE: | ||
159 | $name = 'OPERATOR_TYPE'; | ||
160 | break; | ||
161 | case self::PUNCTUATION_TYPE: | ||
162 | $name = 'PUNCTUATION_TYPE'; | ||
163 | break; | ||
164 | case self::INTERPOLATION_START_TYPE: | ||
165 | $name = 'INTERPOLATION_START_TYPE'; | ||
166 | break; | ||
167 | case self::INTERPOLATION_END_TYPE: | ||
168 | $name = 'INTERPOLATION_END_TYPE'; | ||
169 | break; | ||
170 | default: | ||
171 | throw new LogicException(sprintf('Token of type "%s" does not exist.', $type)); | ||
172 | } | ||
173 | |||
174 | return $short ? $name : 'Twig_Token::'.$name; | ||
175 | } | ||
176 | |||
177 | /** | ||
178 | * Returns the english representation of a given type. | ||
179 | * | ||
180 | * @param integer $type The type as an integer | ||
181 | * @param integer $line The code line | ||
182 | * | ||
183 | * @return string The string representation | ||
184 | */ | ||
185 | public static function typeToEnglish($type, $line = -1) | ||
186 | { | ||
187 | switch ($type) { | ||
188 | case self::EOF_TYPE: | ||
189 | return 'end of template'; | ||
190 | case self::TEXT_TYPE: | ||
191 | return 'text'; | ||
192 | case self::BLOCK_START_TYPE: | ||
193 | return 'begin of statement block'; | ||
194 | case self::VAR_START_TYPE: | ||
195 | return 'begin of print statement'; | ||
196 | case self::BLOCK_END_TYPE: | ||
197 | return 'end of statement block'; | ||
198 | case self::VAR_END_TYPE: | ||
199 | return 'end of print statement'; | ||
200 | case self::NAME_TYPE: | ||
201 | return 'name'; | ||
202 | case self::NUMBER_TYPE: | ||
203 | return 'number'; | ||
204 | case self::STRING_TYPE: | ||
205 | return 'string'; | ||
206 | case self::OPERATOR_TYPE: | ||
207 | return 'operator'; | ||
208 | case self::PUNCTUATION_TYPE: | ||
209 | return 'punctuation'; | ||
210 | case self::INTERPOLATION_START_TYPE: | ||
211 | return 'begin of string interpolation'; | ||
212 | case self::INTERPOLATION_END_TYPE: | ||
213 | return 'end of string interpolation'; | ||
214 | default: | ||
215 | throw new LogicException(sprintf('Token of type "%s" does not exist.', $type)); | ||
216 | } | ||
217 | } | ||
218 | } | ||
diff --git a/vendor/twig/twig/lib/Twig/TokenParser.php b/vendor/twig/twig/lib/Twig/TokenParser.php new file mode 100644 index 00000000..decebd5e --- /dev/null +++ b/vendor/twig/twig/lib/Twig/TokenParser.php | |||
@@ -0,0 +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 | } | ||
diff --git a/vendor/twig/twig/lib/Twig/TokenParser/AutoEscape.php b/vendor/twig/twig/lib/Twig/TokenParser/AutoEscape.php new file mode 100644 index 00000000..27560288 --- /dev/null +++ b/vendor/twig/twig/lib/Twig/TokenParser/AutoEscape.php | |||
@@ -0,0 +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 | } | ||
diff --git a/vendor/twig/twig/lib/Twig/TokenParser/Block.php b/vendor/twig/twig/lib/Twig/TokenParser/Block.php new file mode 100644 index 00000000..a2e017f3 --- /dev/null +++ b/vendor/twig/twig/lib/Twig/TokenParser/Block.php | |||
@@ -0,0 +1,83 @@ | |||
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->test(Twig_Token::BLOCK_END_TYPE)) { | ||
45 | $stream->next(); | ||
46 | |||
47 | $body = $this->parser->subparse(array($this, 'decideBlockEnd'), true); | ||
48 | if ($stream->test(Twig_Token::NAME_TYPE)) { | ||
49 | $value = $stream->next()->getValue(); | ||
50 | |||
51 | if ($value != $name) { | ||
52 | throw new Twig_Error_Syntax(sprintf("Expected endblock for block '$name' (but %s given)", $value), $stream->getCurrent()->getLine(), $stream->getFilename()); | ||
53 | } | ||
54 | } | ||
55 | } else { | ||
56 | $body = new Twig_Node(array( | ||
57 | new Twig_Node_Print($this->parser->getExpressionParser()->parseExpression(), $lineno), | ||
58 | )); | ||
59 | } | ||
60 | $stream->expect(Twig_Token::BLOCK_END_TYPE); | ||
61 | |||
62 | $block->setNode('body', $body); | ||
63 | $this->parser->popBlockStack(); | ||
64 | $this->parser->popLocalScope(); | ||
65 | |||
66 | return new Twig_Node_BlockReference($name, $lineno, $this->getTag()); | ||
67 | } | ||
68 | |||
69 | public function decideBlockEnd(Twig_Token $token) | ||
70 | { | ||
71 | return $token->test('endblock'); | ||
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 'block'; | ||
82 | } | ||
83 | } | ||
diff --git a/vendor/twig/twig/lib/Twig/TokenParser/Do.php b/vendor/twig/twig/lib/Twig/TokenParser/Do.php new file mode 100644 index 00000000..f50939dd --- /dev/null +++ b/vendor/twig/twig/lib/Twig/TokenParser/Do.php | |||
@@ -0,0 +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 | } | ||
diff --git a/vendor/twig/twig/lib/Twig/TokenParser/Embed.php b/vendor/twig/twig/lib/Twig/TokenParser/Embed.php new file mode 100644 index 00000000..69cb5f35 --- /dev/null +++ b/vendor/twig/twig/lib/Twig/TokenParser/Embed.php | |||
@@ -0,0 +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 | } | ||
diff --git a/vendor/twig/twig/lib/Twig/TokenParser/Extends.php b/vendor/twig/twig/lib/Twig/TokenParser/Extends.php new file mode 100644 index 00000000..f5ecee21 --- /dev/null +++ b/vendor/twig/twig/lib/Twig/TokenParser/Extends.php | |||
@@ -0,0 +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 | } | ||
diff --git a/vendor/twig/twig/lib/Twig/TokenParser/Filter.php b/vendor/twig/twig/lib/Twig/TokenParser/Filter.php new file mode 100644 index 00000000..2b97475a --- /dev/null +++ b/vendor/twig/twig/lib/Twig/TokenParser/Filter.php | |||
@@ -0,0 +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 | } | ||
diff --git a/vendor/twig/twig/lib/Twig/TokenParser/Flush.php b/vendor/twig/twig/lib/Twig/TokenParser/Flush.php new file mode 100644 index 00000000..4e15e785 --- /dev/null +++ b/vendor/twig/twig/lib/Twig/TokenParser/Flush.php | |||
@@ -0,0 +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 | } | ||
diff --git a/vendor/twig/twig/lib/Twig/TokenParser/For.php b/vendor/twig/twig/lib/Twig/TokenParser/For.php new file mode 100644 index 00000000..98a6d079 --- /dev/null +++ b/vendor/twig/twig/lib/Twig/TokenParser/For.php | |||
@@ -0,0 +1,136 @@ | |||
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->test(Twig_Token::NAME_TYPE, 'if')) { | ||
43 | $stream->next(); | ||
44 | $ifexpr = $this->parser->getExpressionParser()->parseExpression(); | ||
45 | } | ||
46 | |||
47 | $stream->expect(Twig_Token::BLOCK_END_TYPE); | ||
48 | $body = $this->parser->subparse(array($this, 'decideForFork')); | ||
49 | if ($stream->next()->getValue() == 'else') { | ||
50 | $stream->expect(Twig_Token::BLOCK_END_TYPE); | ||
51 | $else = $this->parser->subparse(array($this, 'decideForEnd'), true); | ||
52 | } else { | ||
53 | $else = null; | ||
54 | } | ||
55 | $stream->expect(Twig_Token::BLOCK_END_TYPE); | ||
56 | |||
57 | if (count($targets) > 1) { | ||
58 | $keyTarget = $targets->getNode(0); | ||
59 | $keyTarget = new Twig_Node_Expression_AssignName($keyTarget->getAttribute('name'), $keyTarget->getLine()); | ||
60 | $valueTarget = $targets->getNode(1); | ||
61 | $valueTarget = new Twig_Node_Expression_AssignName($valueTarget->getAttribute('name'), $valueTarget->getLine()); | ||
62 | } else { | ||
63 | $keyTarget = new Twig_Node_Expression_AssignName('_key', $lineno); | ||
64 | $valueTarget = $targets->getNode(0); | ||
65 | $valueTarget = new Twig_Node_Expression_AssignName($valueTarget->getAttribute('name'), $valueTarget->getLine()); | ||
66 | } | ||
67 | |||
68 | if ($ifexpr) { | ||
69 | $this->checkLoopUsageCondition($stream, $ifexpr); | ||
70 | $this->checkLoopUsageBody($stream, $body); | ||
71 | } | ||
72 | |||
73 | return new Twig_Node_For($keyTarget, $valueTarget, $seq, $ifexpr, $body, $else, $lineno, $this->getTag()); | ||
74 | } | ||
75 | |||
76 | public function decideForFork(Twig_Token $token) | ||
77 | { | ||
78 | return $token->test(array('else', 'endfor')); | ||
79 | } | ||
80 | |||
81 | public function decideForEnd(Twig_Token $token) | ||
82 | { | ||
83 | return $token->test('endfor'); | ||
84 | } | ||
85 | |||
86 | // the loop variable cannot be used in the condition | ||
87 | protected function checkLoopUsageCondition(Twig_TokenStream $stream, Twig_NodeInterface $node) | ||
88 | { | ||
89 | if ($node instanceof Twig_Node_Expression_GetAttr && $node->getNode('node') instanceof Twig_Node_Expression_Name && 'loop' == $node->getNode('node')->getAttribute('name')) { | ||
90 | throw new Twig_Error_Syntax('The "loop" variable cannot be used in a looping condition', $node->getLine(), $stream->getFilename()); | ||
91 | } | ||
92 | |||
93 | foreach ($node as $n) { | ||
94 | if (!$n) { | ||
95 | continue; | ||
96 | } | ||
97 | |||
98 | $this->checkLoopUsageCondition($stream, $n); | ||
99 | } | ||
100 | } | ||
101 | |||
102 | // check usage of non-defined loop-items | ||
103 | // it does not catch all problems (for instance when a for is included into another or when the variable is used in an include) | ||
104 | protected function checkLoopUsageBody(Twig_TokenStream $stream, Twig_NodeInterface $node) | ||
105 | { | ||
106 | if ($node instanceof Twig_Node_Expression_GetAttr && $node->getNode('node') instanceof Twig_Node_Expression_Name && 'loop' == $node->getNode('node')->getAttribute('name')) { | ||
107 | $attribute = $node->getNode('attribute'); | ||
108 | if ($attribute instanceof Twig_Node_Expression_Constant && in_array($attribute->getAttribute('value'), array('length', 'revindex0', 'revindex', 'last'))) { | ||
109 | 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()); | ||
110 | } | ||
111 | } | ||
112 | |||
113 | // should check for parent.loop.XXX usage | ||
114 | if ($node instanceof Twig_Node_For) { | ||
115 | return; | ||
116 | } | ||
117 | |||
118 | foreach ($node as $n) { | ||
119 | if (!$n) { | ||
120 | continue; | ||
121 | } | ||
122 | |||
123 | $this->checkLoopUsageBody($stream, $n); | ||
124 | } | ||
125 | } | ||
126 | |||
127 | /** | ||
128 | * Gets the tag name associated with this token parser. | ||
129 | * | ||
130 | * @return string The tag name | ||
131 | */ | ||
132 | public function getTag() | ||
133 | { | ||
134 | return 'for'; | ||
135 | } | ||
136 | } | ||
diff --git a/vendor/twig/twig/lib/Twig/TokenParser/From.php b/vendor/twig/twig/lib/Twig/TokenParser/From.php new file mode 100644 index 00000000..a54054db --- /dev/null +++ b/vendor/twig/twig/lib/Twig/TokenParser/From.php | |||
@@ -0,0 +1,74 @@ | |||
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->test('as')) { | ||
40 | $stream->next(); | ||
41 | |||
42 | $alias = $stream->expect(Twig_Token::NAME_TYPE)->getValue(); | ||
43 | } | ||
44 | |||
45 | $targets[$name] = $alias; | ||
46 | |||
47 | if (!$stream->test(Twig_Token::PUNCTUATION_TYPE, ',')) { | ||
48 | break; | ||
49 | } | ||
50 | |||
51 | $stream->next(); | ||
52 | } while (true); | ||
53 | |||
54 | $stream->expect(Twig_Token::BLOCK_END_TYPE); | ||
55 | |||
56 | $node = new Twig_Node_Import($macro, new Twig_Node_Expression_AssignName($this->parser->getVarName(), $token->getLine()), $token->getLine(), $this->getTag()); | ||
57 | |||
58 | foreach ($targets as $name => $alias) { | ||
59 | $this->parser->addImportedSymbol('function', $alias, 'get'.$name, $node->getNode('var')); | ||
60 | } | ||
61 | |||
62 | return $node; | ||
63 | } | ||
64 | |||
65 | /** | ||
66 | * Gets the tag name associated with this token parser. | ||
67 | * | ||
68 | * @return string The tag name | ||
69 | */ | ||
70 | public function getTag() | ||
71 | { | ||
72 | return 'from'; | ||
73 | } | ||
74 | } | ||
diff --git a/vendor/twig/twig/lib/Twig/TokenParser/If.php b/vendor/twig/twig/lib/Twig/TokenParser/If.php new file mode 100644 index 00000000..3d7d1f51 --- /dev/null +++ b/vendor/twig/twig/lib/Twig/TokenParser/If.php | |||
@@ -0,0 +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 | } | ||
diff --git a/vendor/twig/twig/lib/Twig/TokenParser/Import.php b/vendor/twig/twig/lib/Twig/TokenParser/Import.php new file mode 100644 index 00000000..e7050c70 --- /dev/null +++ b/vendor/twig/twig/lib/Twig/TokenParser/Import.php | |||
@@ -0,0 +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 | } | ||
diff --git a/vendor/twig/twig/lib/Twig/TokenParser/Include.php b/vendor/twig/twig/lib/Twig/TokenParser/Include.php new file mode 100644 index 00000000..4a317868 --- /dev/null +++ b/vendor/twig/twig/lib/Twig/TokenParser/Include.php | |||
@@ -0,0 +1,80 @@ | |||
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->test(Twig_Token::NAME_TYPE, 'ignore')) { | ||
46 | $stream->next(); | ||
47 | $stream->expect(Twig_Token::NAME_TYPE, 'missing'); | ||
48 | |||
49 | $ignoreMissing = true; | ||
50 | } | ||
51 | |||
52 | $variables = null; | ||
53 | if ($stream->test(Twig_Token::NAME_TYPE, 'with')) { | ||
54 | $stream->next(); | ||
55 | |||
56 | $variables = $this->parser->getExpressionParser()->parseExpression(); | ||
57 | } | ||
58 | |||
59 | $only = false; | ||
60 | if ($stream->test(Twig_Token::NAME_TYPE, 'only')) { | ||
61 | $stream->next(); | ||
62 | |||
63 | $only = true; | ||
64 | } | ||
65 | |||
66 | $stream->expect(Twig_Token::BLOCK_END_TYPE); | ||
67 | |||
68 | return array($variables, $only, $ignoreMissing); | ||
69 | } | ||
70 | |||
71 | /** | ||
72 | * Gets the tag name associated with this token parser. | ||
73 | * | ||
74 | * @return string The tag name | ||
75 | */ | ||
76 | public function getTag() | ||
77 | { | ||
78 | return 'include'; | ||
79 | } | ||
80 | } | ||
diff --git a/vendor/twig/twig/lib/Twig/TokenParser/Macro.php b/vendor/twig/twig/lib/Twig/TokenParser/Macro.php new file mode 100644 index 00000000..82b4fa6d --- /dev/null +++ b/vendor/twig/twig/lib/Twig/TokenParser/Macro.php | |||
@@ -0,0 +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 ($stream->test(Twig_Token::NAME_TYPE)) { | ||
42 | $value = $stream->next()->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 | } | ||
diff --git a/vendor/twig/twig/lib/Twig/TokenParser/Sandbox.php b/vendor/twig/twig/lib/Twig/TokenParser/Sandbox.php new file mode 100644 index 00000000..9457325a --- /dev/null +++ b/vendor/twig/twig/lib/Twig/TokenParser/Sandbox.php | |||
@@ -0,0 +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 | } | ||
diff --git a/vendor/twig/twig/lib/Twig/TokenParser/Set.php b/vendor/twig/twig/lib/Twig/TokenParser/Set.php new file mode 100644 index 00000000..70e0b41b --- /dev/null +++ b/vendor/twig/twig/lib/Twig/TokenParser/Set.php | |||
@@ -0,0 +1,84 @@ | |||
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->test(Twig_Token::OPERATOR_TYPE, '=')) { | ||
46 | $stream->next(); | ||
47 | $values = $this->parser->getExpressionParser()->parseMultitargetExpression(); | ||
48 | |||
49 | $stream->expect(Twig_Token::BLOCK_END_TYPE); | ||
50 | |||
51 | if (count($names) !== count($values)) { | ||
52 | throw new Twig_Error_Syntax("When using set, you must have the same number of variables and assignments.", $stream->getCurrent()->getLine(), $stream->getFilename()); | ||
53 | } | ||
54 | } else { | ||
55 | $capture = true; | ||
56 | |||
57 | if (count($names) > 1) { | ||
58 | throw new Twig_Error_Syntax("When using set with a block, you cannot have a multi-target.", $stream->getCurrent()->getLine(), $stream->getFilename()); | ||
59 | } | ||
60 | |||
61 | $stream->expect(Twig_Token::BLOCK_END_TYPE); | ||
62 | |||
63 | $values = $this->parser->subparse(array($this, 'decideBlockEnd'), true); | ||
64 | $stream->expect(Twig_Token::BLOCK_END_TYPE); | ||
65 | } | ||
66 | |||
67 | return new Twig_Node_Set($capture, $names, $values, $lineno, $this->getTag()); | ||
68 | } | ||
69 | |||
70 | public function decideBlockEnd(Twig_Token $token) | ||
71 | { | ||
72 | return $token->test('endset'); | ||
73 | } | ||
74 | |||
75 | /** | ||
76 | * Gets the tag name associated with this token parser. | ||
77 | * | ||
78 | * @return string The tag name | ||
79 | */ | ||
80 | public function getTag() | ||
81 | { | ||
82 | return 'set'; | ||
83 | } | ||
84 | } | ||
diff --git a/vendor/twig/twig/lib/Twig/TokenParser/Spaceless.php b/vendor/twig/twig/lib/Twig/TokenParser/Spaceless.php new file mode 100644 index 00000000..1e3fa8f3 --- /dev/null +++ b/vendor/twig/twig/lib/Twig/TokenParser/Spaceless.php | |||
@@ -0,0 +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 | } | ||
diff --git a/vendor/twig/twig/lib/Twig/TokenParser/Use.php b/vendor/twig/twig/lib/Twig/TokenParser/Use.php new file mode 100644 index 00000000..bc0e09ef --- /dev/null +++ b/vendor/twig/twig/lib/Twig/TokenParser/Use.php | |||
@@ -0,0 +1,82 @@ | |||
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->test('with')) { | ||
46 | $stream->next(); | ||
47 | |||
48 | do { | ||
49 | $name = $stream->expect(Twig_Token::NAME_TYPE)->getValue(); | ||
50 | |||
51 | $alias = $name; | ||
52 | if ($stream->test('as')) { | ||
53 | $stream->next(); | ||
54 | |||
55 | $alias = $stream->expect(Twig_Token::NAME_TYPE)->getValue(); | ||
56 | } | ||
57 | |||
58 | $targets[$name] = new Twig_Node_Expression_Constant($alias, -1); | ||
59 | |||
60 | if (!$stream->test(Twig_Token::PUNCTUATION_TYPE, ',')) { | ||
61 | break; | ||
62 | } | ||
63 | |||
64 | $stream->next(); | ||
65 | } while (true); | ||
66 | } | ||
67 | |||
68 | $stream->expect(Twig_Token::BLOCK_END_TYPE); | ||
69 | |||
70 | $this->parser->addTrait(new Twig_Node(array('template' => $template, 'targets' => new Twig_Node($targets)))); | ||
71 | } | ||
72 | |||
73 | /** | ||
74 | * Gets the tag name associated with this token parser. | ||
75 | * | ||
76 | * @return string The tag name | ||
77 | */ | ||
78 | public function getTag() | ||
79 | { | ||
80 | return 'use'; | ||
81 | } | ||
82 | } | ||
diff --git a/vendor/twig/twig/lib/Twig/TokenParserBroker.php b/vendor/twig/twig/lib/Twig/TokenParserBroker.php new file mode 100644 index 00000000..ec3fba67 --- /dev/null +++ b/vendor/twig/twig/lib/Twig/TokenParserBroker.php | |||
@@ -0,0 +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 | } | ||
diff --git a/vendor/twig/twig/lib/Twig/TokenParserBrokerInterface.php b/vendor/twig/twig/lib/Twig/TokenParserBrokerInterface.php new file mode 100644 index 00000000..3f006e33 --- /dev/null +++ b/vendor/twig/twig/lib/Twig/TokenParserBrokerInterface.php | |||
@@ -0,0 +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 | } | ||
diff --git a/vendor/twig/twig/lib/Twig/TokenParserInterface.php b/vendor/twig/twig/lib/Twig/TokenParserInterface.php new file mode 100644 index 00000000..bbde7714 --- /dev/null +++ b/vendor/twig/twig/lib/Twig/TokenParserInterface.php | |||
@@ -0,0 +1,41 @@ | |||
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 | public function parse(Twig_Token $token); | ||
34 | |||
35 | /** | ||
36 | * Gets the tag name associated with this token parser. | ||
37 | * | ||
38 | * @return string The tag name | ||
39 | */ | ||
40 | public function getTag(); | ||
41 | } | ||
diff --git a/vendor/twig/twig/lib/Twig/TokenStream.php b/vendor/twig/twig/lib/Twig/TokenStream.php new file mode 100644 index 00000000..a78189f6 --- /dev/null +++ b/vendor/twig/twig/lib/Twig/TokenStream.php | |||
@@ -0,0 +1,144 @@ | |||
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 and returns it or throws a syntax error. | ||
68 | * | ||
69 | * @return Twig_Token | ||
70 | */ | ||
71 | public function expect($type, $value = null, $message = null) | ||
72 | { | ||
73 | $token = $this->tokens[$this->current]; | ||
74 | if (!$token->test($type, $value)) { | ||
75 | $line = $token->getLine(); | ||
76 | throw new Twig_Error_Syntax(sprintf('%sUnexpected token "%s" of value "%s" ("%s" expected%s)', | ||
77 | $message ? $message.'. ' : '', | ||
78 | Twig_Token::typeToEnglish($token->getType(), $line), $token->getValue(), | ||
79 | Twig_Token::typeToEnglish($type, $line), $value ? sprintf(' with value "%s"', $value) : ''), | ||
80 | $line, | ||
81 | $this->filename | ||
82 | ); | ||
83 | } | ||
84 | $this->next(); | ||
85 | |||
86 | return $token; | ||
87 | } | ||
88 | |||
89 | /** | ||
90 | * Looks at the next token. | ||
91 | * | ||
92 | * @param integer $number | ||
93 | * | ||
94 | * @return Twig_Token | ||
95 | */ | ||
96 | public function look($number = 1) | ||
97 | { | ||
98 | if (!isset($this->tokens[$this->current + $number])) { | ||
99 | throw new Twig_Error_Syntax('Unexpected end of template', $this->tokens[$this->current + $number - 1]->getLine(), $this->filename); | ||
100 | } | ||
101 | |||
102 | return $this->tokens[$this->current + $number]; | ||
103 | } | ||
104 | |||
105 | /** | ||
106 | * Tests the current token | ||
107 | * | ||
108 | * @return bool | ||
109 | */ | ||
110 | public function test($primary, $secondary = null) | ||
111 | { | ||
112 | return $this->tokens[$this->current]->test($primary, $secondary); | ||
113 | } | ||
114 | |||
115 | /** | ||
116 | * Checks if end of stream was reached | ||
117 | * | ||
118 | * @return bool | ||
119 | */ | ||
120 | public function isEOF() | ||
121 | { | ||
122 | return $this->tokens[$this->current]->getType() === Twig_Token::EOF_TYPE; | ||
123 | } | ||
124 | |||
125 | /** | ||
126 | * Gets the current token | ||
127 | * | ||
128 | * @return Twig_Token | ||
129 | */ | ||
130 | public function getCurrent() | ||
131 | { | ||
132 | return $this->tokens[$this->current]; | ||
133 | } | ||
134 | |||
135 | /** | ||
136 | * Gets the filename associated with this stream | ||
137 | * | ||
138 | * @return string | ||
139 | */ | ||
140 | public function getFilename() | ||
141 | { | ||
142 | return $this->filename; | ||
143 | } | ||
144 | } | ||
diff --git a/vendor/twig/twig/phpunit.xml.dist b/vendor/twig/twig/phpunit.xml.dist new file mode 100644 index 00000000..6c5046f1 --- /dev/null +++ b/vendor/twig/twig/phpunit.xml.dist | |||
@@ -0,0 +1,25 @@ | |||
1 | <?xml version="1.0" encoding="UTF-8"?> | ||
2 | |||
3 | <phpunit backupGlobals="false" | ||
4 | backupStaticAttributes="false" | ||
5 | colors="true" | ||
6 | convertErrorsToExceptions="true" | ||
7 | convertNoticesToExceptions="true" | ||
8 | convertWarningsToExceptions="true" | ||
9 | processIsolation="false" | ||
10 | stopOnFailure="false" | ||
11 | syntaxCheck="false" | ||
12 | bootstrap="test/bootstrap.php" | ||
13 | > | ||
14 | <testsuites> | ||
15 | <testsuite name="Twig Test Suite"> | ||
16 | <directory>./test/Twig/</directory> | ||
17 | </testsuite> | ||
18 | </testsuites> | ||
19 | |||
20 | <filter> | ||
21 | <whitelist> | ||
22 | <directory suffix=".php">./lib/Twig/</directory> | ||
23 | </whitelist> | ||
24 | </filter> | ||
25 | </phpunit> | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/AutoloaderTest.php b/vendor/twig/twig/test/Twig/Tests/AutoloaderTest.php new file mode 100644 index 00000000..c8b7999a --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/AutoloaderTest.php | |||
@@ -0,0 +1,21 @@ | |||
1 | <?php | ||
2 | |||
3 | /* | ||
4 | * This file is part of Twig. | ||
5 | * | ||
6 | * (c) 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_Tests_AutoloaderTest extends PHPUnit_Framework_TestCase | ||
13 | { | ||
14 | public function testAutoload() | ||
15 | { | ||
16 | $this->assertFalse(class_exists('FooBarFoo'), '->autoload() does not try to load classes that does not begin with Twig'); | ||
17 | |||
18 | $autoloader = new Twig_Autoloader(); | ||
19 | $this->assertNull($autoloader->autoload('Foo'), '->autoload() returns false if it is not able to load a class'); | ||
20 | } | ||
21 | } | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/CompilerTest.php b/vendor/twig/twig/test/Twig/Tests/CompilerTest.php new file mode 100644 index 00000000..ebe79aef --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/CompilerTest.php | |||
@@ -0,0 +1,33 @@ | |||
1 | <?php | ||
2 | |||
3 | /* | ||
4 | * This file is part of Twig. | ||
5 | * | ||
6 | * (c) 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_Tests_CompilerTest extends PHPUnit_Framework_TestCase | ||
13 | { | ||
14 | public function testReprNumericValueWithLocale() | ||
15 | { | ||
16 | $compiler = new Twig_Compiler(new Twig_Environment()); | ||
17 | |||
18 | $locale = setlocale(LC_NUMERIC, 0); | ||
19 | if (false === $locale) { | ||
20 | $this->markTestSkipped('Your platform does not support locales.'); | ||
21 | } | ||
22 | |||
23 | $required_locales = array('fr_FR.UTF-8', 'fr_FR.UTF8', 'fr_FR.utf-8', 'fr_FR.utf8', 'French_France.1252'); | ||
24 | if (false === setlocale(LC_ALL, $required_locales)) { | ||
25 | $this->markTestSkipped('Could not set any of required locales: ' . implode(", ", $required_locales)); | ||
26 | } | ||
27 | |||
28 | $this->assertEquals('1.2', $compiler->repr(1.2)->getSource()); | ||
29 | $this->assertContains('fr', strtolower(setlocale(LC_NUMERIC, 0))); | ||
30 | |||
31 | setlocale(LC_ALL, $locale); | ||
32 | } | ||
33 | } | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/EnvironmentTest.php b/vendor/twig/twig/test/Twig/Tests/EnvironmentTest.php new file mode 100644 index 00000000..22461b5d --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/EnvironmentTest.php | |||
@@ -0,0 +1,288 @@ | |||
1 | <?php | ||
2 | |||
3 | /* | ||
4 | * This file is part of Twig. | ||
5 | * | ||
6 | * (c) 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_Tests_EnvironmentTest extends PHPUnit_Framework_TestCase | ||
13 | { | ||
14 | /** | ||
15 | * @expectedException LogicException | ||
16 | * @expectedExceptionMessage You must set a loader first. | ||
17 | */ | ||
18 | public function testRenderNoLoader() | ||
19 | { | ||
20 | $env = new Twig_Environment(); | ||
21 | $env->render('test'); | ||
22 | } | ||
23 | |||
24 | public function testAutoescapeOption() | ||
25 | { | ||
26 | $loader = new Twig_Loader_Array(array( | ||
27 | 'html' => '{{ foo }} {{ foo }}', | ||
28 | 'js' => '{{ bar }} {{ bar }}', | ||
29 | )); | ||
30 | |||
31 | $twig = new Twig_Environment($loader, array( | ||
32 | 'debug' => true, | ||
33 | 'cache' => false, | ||
34 | 'autoescape' => array($this, 'escapingStrategyCallback'), | ||
35 | )); | ||
36 | |||
37 | $this->assertEquals('foo<br/ > foo<br/ >', $twig->render('html', array('foo' => 'foo<br/ >'))); | ||
38 | $this->assertEquals('foo\x3Cbr\x2F\x20\x3E foo\x3Cbr\x2F\x20\x3E', $twig->render('js', array('bar' => 'foo<br/ >'))); | ||
39 | } | ||
40 | |||
41 | public function escapingStrategyCallback($filename) | ||
42 | { | ||
43 | return $filename; | ||
44 | } | ||
45 | |||
46 | public function testGlobals() | ||
47 | { | ||
48 | // globals can be added after calling getGlobals | ||
49 | $twig = new Twig_Environment(new Twig_Loader_String()); | ||
50 | $twig->addGlobal('foo', 'foo'); | ||
51 | $globals = $twig->getGlobals(); | ||
52 | $twig->addGlobal('foo', 'bar'); | ||
53 | $globals = $twig->getGlobals(); | ||
54 | $this->assertEquals('bar', $globals['foo']); | ||
55 | |||
56 | // globals can be modified after runtime init | ||
57 | $twig = new Twig_Environment(new Twig_Loader_String()); | ||
58 | $twig->addGlobal('foo', 'foo'); | ||
59 | $globals = $twig->getGlobals(); | ||
60 | $twig->initRuntime(); | ||
61 | $twig->addGlobal('foo', 'bar'); | ||
62 | $globals = $twig->getGlobals(); | ||
63 | $this->assertEquals('bar', $globals['foo']); | ||
64 | |||
65 | // globals can be modified after extensions init | ||
66 | $twig = new Twig_Environment(new Twig_Loader_String()); | ||
67 | $twig->addGlobal('foo', 'foo'); | ||
68 | $globals = $twig->getGlobals(); | ||
69 | $twig->getFunctions(); | ||
70 | $twig->addGlobal('foo', 'bar'); | ||
71 | $globals = $twig->getGlobals(); | ||
72 | $this->assertEquals('bar', $globals['foo']); | ||
73 | |||
74 | // globals can be modified after extensions and runtime init | ||
75 | $twig = new Twig_Environment(new Twig_Loader_String()); | ||
76 | $twig->addGlobal('foo', 'foo'); | ||
77 | $globals = $twig->getGlobals(); | ||
78 | $twig->getFunctions(); | ||
79 | $twig->initRuntime(); | ||
80 | $twig->addGlobal('foo', 'bar'); | ||
81 | $globals = $twig->getGlobals(); | ||
82 | $this->assertEquals('bar', $globals['foo']); | ||
83 | |||
84 | $twig = new Twig_Environment(new Twig_Loader_String()); | ||
85 | $twig->getGlobals(); | ||
86 | $twig->addGlobal('foo', 'bar'); | ||
87 | $template = $twig->loadTemplate('{{foo}}'); | ||
88 | $this->assertEquals('bar', $template->render(array())); | ||
89 | |||
90 | /* to be uncomment in Twig 2.0 | ||
91 | // globals cannot be added after runtime init | ||
92 | $twig = new Twig_Environment(new Twig_Loader_String()); | ||
93 | $twig->addGlobal('foo', 'foo'); | ||
94 | $globals = $twig->getGlobals(); | ||
95 | $twig->initRuntime(); | ||
96 | try { | ||
97 | $twig->addGlobal('bar', 'bar'); | ||
98 | $this->fail(); | ||
99 | } catch (LogicException $e) { | ||
100 | $this->assertFalse(array_key_exists('bar', $twig->getGlobals())); | ||
101 | } | ||
102 | |||
103 | // globals cannot be added after extensions init | ||
104 | $twig = new Twig_Environment(new Twig_Loader_String()); | ||
105 | $twig->addGlobal('foo', 'foo'); | ||
106 | $globals = $twig->getGlobals(); | ||
107 | $twig->getFunctions(); | ||
108 | try { | ||
109 | $twig->addGlobal('bar', 'bar'); | ||
110 | $this->fail(); | ||
111 | } catch (LogicException $e) { | ||
112 | $this->assertFalse(array_key_exists('bar', $twig->getGlobals())); | ||
113 | } | ||
114 | |||
115 | // globals cannot be added after extensions and runtime init | ||
116 | $twig = new Twig_Environment(new Twig_Loader_String()); | ||
117 | $twig->addGlobal('foo', 'foo'); | ||
118 | $globals = $twig->getGlobals(); | ||
119 | $twig->getFunctions(); | ||
120 | $twig->initRuntime(); | ||
121 | try { | ||
122 | $twig->addGlobal('bar', 'bar'); | ||
123 | $this->fail(); | ||
124 | } catch (LogicException $e) { | ||
125 | $this->assertFalse(array_key_exists('bar', $twig->getGlobals())); | ||
126 | } | ||
127 | |||
128 | // test adding globals after initRuntime without call to getGlobals | ||
129 | $twig = new Twig_Environment(new Twig_Loader_String()); | ||
130 | $twig->initRuntime(); | ||
131 | try { | ||
132 | $twig->addGlobal('bar', 'bar'); | ||
133 | $this->fail(); | ||
134 | } catch (LogicException $e) { | ||
135 | $this->assertFalse(array_key_exists('bar', $twig->getGlobals())); | ||
136 | } | ||
137 | */ | ||
138 | } | ||
139 | |||
140 | public function testExtensionsAreNotInitializedWhenRenderingACompiledTemplate() | ||
141 | { | ||
142 | $options = array('cache' => sys_get_temp_dir().'/twig', 'auto_reload' => false, 'debug' => false); | ||
143 | |||
144 | // force compilation | ||
145 | $twig = new Twig_Environment(new Twig_Loader_String(), $options); | ||
146 | $cache = $twig->getCacheFilename('{{ foo }}'); | ||
147 | if (!is_dir(dirname($cache))) { | ||
148 | mkdir(dirname($cache), 0777, true); | ||
149 | } | ||
150 | file_put_contents($cache, $twig->compileSource('{{ foo }}', '{{ foo }}')); | ||
151 | |||
152 | // check that extensions won't be initialized when rendering a template that is already in the cache | ||
153 | $twig = $this | ||
154 | ->getMockBuilder('Twig_Environment') | ||
155 | ->setConstructorArgs(array(new Twig_Loader_String(), $options)) | ||
156 | ->setMethods(array('initExtensions')) | ||
157 | ->getMock() | ||
158 | ; | ||
159 | |||
160 | $twig->expects($this->never())->method('initExtensions'); | ||
161 | |||
162 | // render template | ||
163 | $output = $twig->render('{{ foo }}', array('foo' => 'bar')); | ||
164 | $this->assertEquals('bar', $output); | ||
165 | |||
166 | unlink($cache); | ||
167 | } | ||
168 | |||
169 | public function testAddExtension() | ||
170 | { | ||
171 | $twig = new Twig_Environment(new Twig_Loader_String()); | ||
172 | $twig->addExtension(new Twig_Tests_EnvironmentTest_Extension()); | ||
173 | |||
174 | $this->assertArrayHasKey('test', $twig->getTags()); | ||
175 | $this->assertArrayHasKey('foo_filter', $twig->getFilters()); | ||
176 | $this->assertArrayHasKey('foo_function', $twig->getFunctions()); | ||
177 | $this->assertArrayHasKey('foo_test', $twig->getTests()); | ||
178 | $this->assertArrayHasKey('foo_unary', $twig->getUnaryOperators()); | ||
179 | $this->assertArrayHasKey('foo_binary', $twig->getBinaryOperators()); | ||
180 | $this->assertArrayHasKey('foo_global', $twig->getGlobals()); | ||
181 | $visitors = $twig->getNodeVisitors(); | ||
182 | $this->assertEquals('Twig_Tests_EnvironmentTest_NodeVisitor', get_class($visitors[2])); | ||
183 | } | ||
184 | |||
185 | public function testRemoveExtension() | ||
186 | { | ||
187 | $twig = new Twig_Environment(new Twig_Loader_String()); | ||
188 | $twig->addExtension(new Twig_Tests_EnvironmentTest_Extension()); | ||
189 | $twig->removeExtension('environment_test'); | ||
190 | |||
191 | $this->assertFalse(array_key_exists('test', $twig->getTags())); | ||
192 | $this->assertFalse(array_key_exists('foo_filter', $twig->getFilters())); | ||
193 | $this->assertFalse(array_key_exists('foo_function', $twig->getFunctions())); | ||
194 | $this->assertFalse(array_key_exists('foo_test', $twig->getTests())); | ||
195 | $this->assertFalse(array_key_exists('foo_unary', $twig->getUnaryOperators())); | ||
196 | $this->assertFalse(array_key_exists('foo_binary', $twig->getBinaryOperators())); | ||
197 | $this->assertFalse(array_key_exists('foo_global', $twig->getGlobals())); | ||
198 | $this->assertCount(2, $twig->getNodeVisitors()); | ||
199 | } | ||
200 | } | ||
201 | |||
202 | class Twig_Tests_EnvironmentTest_Extension extends Twig_Extension | ||
203 | { | ||
204 | public function getTokenParsers() | ||
205 | { | ||
206 | return array( | ||
207 | new Twig_Tests_EnvironmentTest_TokenParser(), | ||
208 | ); | ||
209 | } | ||
210 | |||
211 | public function getNodeVisitors() | ||
212 | { | ||
213 | return array( | ||
214 | new Twig_Tests_EnvironmentTest_NodeVisitor(), | ||
215 | ); | ||
216 | } | ||
217 | |||
218 | public function getFilters() | ||
219 | { | ||
220 | return array( | ||
221 | 'foo_filter' => new Twig_Filter_Function('foo_filter'), | ||
222 | ); | ||
223 | } | ||
224 | |||
225 | public function getTests() | ||
226 | { | ||
227 | return array( | ||
228 | 'foo_test' => new Twig_Test_Function('foo_test'), | ||
229 | ); | ||
230 | } | ||
231 | |||
232 | public function getFunctions() | ||
233 | { | ||
234 | return array( | ||
235 | 'foo_function' => new Twig_Function_Function('foo_function'), | ||
236 | ); | ||
237 | } | ||
238 | |||
239 | public function getOperators() | ||
240 | { | ||
241 | return array( | ||
242 | array('foo_unary' => array()), | ||
243 | array('foo_binary' => array()), | ||
244 | ); | ||
245 | } | ||
246 | |||
247 | public function getGlobals() | ||
248 | { | ||
249 | return array( | ||
250 | 'foo_global' => 'foo_global', | ||
251 | ); | ||
252 | } | ||
253 | |||
254 | public function getName() | ||
255 | { | ||
256 | return 'environment_test'; | ||
257 | } | ||
258 | } | ||
259 | |||
260 | class Twig_Tests_EnvironmentTest_TokenParser extends Twig_TokenParser | ||
261 | { | ||
262 | public function parse(Twig_Token $token) | ||
263 | { | ||
264 | } | ||
265 | |||
266 | public function getTag() | ||
267 | { | ||
268 | return 'test'; | ||
269 | } | ||
270 | } | ||
271 | |||
272 | class Twig_Tests_EnvironmentTest_NodeVisitor implements Twig_NodeVisitorInterface | ||
273 | { | ||
274 | public function enterNode(Twig_NodeInterface $node, Twig_Environment $env) | ||
275 | { | ||
276 | return $node; | ||
277 | } | ||
278 | |||
279 | public function leaveNode(Twig_NodeInterface $node, Twig_Environment $env) | ||
280 | { | ||
281 | return $node; | ||
282 | } | ||
283 | |||
284 | public function getPriority() | ||
285 | { | ||
286 | return 0; | ||
287 | } | ||
288 | } | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/ErrorTest.php b/vendor/twig/twig/test/Twig/Tests/ErrorTest.php new file mode 100644 index 00000000..9b286974 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/ErrorTest.php | |||
@@ -0,0 +1,159 @@ | |||
1 | <?php | ||
2 | |||
3 | /* | ||
4 | * This file is part of Twig. | ||
5 | * | ||
6 | * (c) 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_Tests_ErrorTest extends PHPUnit_Framework_TestCase | ||
13 | { | ||
14 | public function testErrorWithObjectFilename() | ||
15 | { | ||
16 | $error = new Twig_Error('foo'); | ||
17 | $error->setTemplateFile(new SplFileInfo(__FILE__)); | ||
18 | |||
19 | $this->assertContains('test'.DIRECTORY_SEPARATOR.'Twig'.DIRECTORY_SEPARATOR.'Tests'.DIRECTORY_SEPARATOR.'ErrorTest.php', $error->getMessage()); | ||
20 | } | ||
21 | |||
22 | public function testErrorWithArrayFilename() | ||
23 | { | ||
24 | $error = new Twig_Error('foo'); | ||
25 | $error->setTemplateFile(array('foo' => 'bar')); | ||
26 | |||
27 | $this->assertEquals('foo in {"foo":"bar"}', $error->getMessage()); | ||
28 | } | ||
29 | |||
30 | public function testTwigExceptionAddsFileAndLineWhenMissing() | ||
31 | { | ||
32 | $loader = new Twig_Loader_Array(array('index' => "\n\n{{ foo.bar }}\n\n\n{{ 'foo' }}")); | ||
33 | $twig = new Twig_Environment($loader, array('strict_variables' => true, 'debug' => true, 'cache' => false)); | ||
34 | |||
35 | $template = $twig->loadTemplate('index'); | ||
36 | |||
37 | try { | ||
38 | $template->render(array()); | ||
39 | |||
40 | $this->fail(); | ||
41 | } catch (Twig_Error_Runtime $e) { | ||
42 | $this->assertEquals('Variable "foo" does not exist in "index" at line 3', $e->getMessage()); | ||
43 | $this->assertEquals(3, $e->getTemplateLine()); | ||
44 | $this->assertEquals('index', $e->getTemplateFile()); | ||
45 | } | ||
46 | } | ||
47 | |||
48 | public function testRenderWrapsExceptions() | ||
49 | { | ||
50 | $loader = new Twig_Loader_Array(array('index' => "\n\n\n{{ foo.bar }}\n\n\n\n{{ 'foo' }}")); | ||
51 | $twig = new Twig_Environment($loader, array('strict_variables' => true, 'debug' => true, 'cache' => false)); | ||
52 | |||
53 | $template = $twig->loadTemplate('index'); | ||
54 | |||
55 | try { | ||
56 | $template->render(array('foo' => new Twig_Tests_ErrorTest_Foo())); | ||
57 | |||
58 | $this->fail(); | ||
59 | } catch (Twig_Error_Runtime $e) { | ||
60 | $this->assertEquals('An exception has been thrown during the rendering of a template ("Runtime error...") in "index" at line 4.', $e->getMessage()); | ||
61 | $this->assertEquals(4, $e->getTemplateLine()); | ||
62 | $this->assertEquals('index', $e->getTemplateFile()); | ||
63 | } | ||
64 | } | ||
65 | |||
66 | public function testTwigExceptionAddsFileAndLineWhenMissingWithInheritance() | ||
67 | { | ||
68 | $loader = new Twig_Loader_Array(array( | ||
69 | 'index' => "{% extends 'base' %} | ||
70 | {% block content %} | ||
71 | {{ foo.bar }} | ||
72 | {% endblock %} | ||
73 | {% block foo %} | ||
74 | {{ foo.bar }} | ||
75 | {% endblock %}", | ||
76 | 'base' => '{% block content %}{% endblock %}' | ||
77 | )); | ||
78 | $twig = new Twig_Environment($loader, array('strict_variables' => true, 'debug' => true, 'cache' => false)); | ||
79 | |||
80 | $template = $twig->loadTemplate('index'); | ||
81 | try { | ||
82 | $template->render(array()); | ||
83 | |||
84 | $this->fail(); | ||
85 | } catch (Twig_Error_Runtime $e) { | ||
86 | $this->assertEquals('Variable "foo" does not exist in "index" at line 3', $e->getMessage()); | ||
87 | $this->assertEquals(3, $e->getTemplateLine()); | ||
88 | $this->assertEquals('index', $e->getTemplateFile()); | ||
89 | } | ||
90 | |||
91 | try { | ||
92 | $template->render(array('foo' => new Twig_Tests_ErrorTest_Foo())); | ||
93 | |||
94 | $this->fail(); | ||
95 | } catch (Twig_Error_Runtime $e) { | ||
96 | $this->assertEquals('An exception has been thrown during the rendering of a template ("Runtime error...") in "index" at line 3.', $e->getMessage()); | ||
97 | $this->assertEquals(3, $e->getTemplateLine()); | ||
98 | $this->assertEquals('index', $e->getTemplateFile()); | ||
99 | } | ||
100 | } | ||
101 | |||
102 | public function testTwigExceptionAddsFileAndLineWhenMissingWithInheritanceAgain() | ||
103 | { | ||
104 | $loader = new Twig_Loader_Array(array( | ||
105 | 'index' => "{% extends 'base' %} | ||
106 | {% block content %} | ||
107 | {{ parent() }} | ||
108 | {% endblock %}", | ||
109 | 'base' => '{% block content %}{{ foo }}{% endblock %}' | ||
110 | )); | ||
111 | $twig = new Twig_Environment($loader, array('strict_variables' => true, 'debug' => true, 'cache' => false)); | ||
112 | |||
113 | $template = $twig->loadTemplate('index'); | ||
114 | try { | ||
115 | $template->render(array()); | ||
116 | |||
117 | $this->fail(); | ||
118 | } catch (Twig_Error_Runtime $e) { | ||
119 | $this->assertEquals('Variable "foo" does not exist in "base" at line 1', $e->getMessage()); | ||
120 | $this->assertEquals(1, $e->getTemplateLine()); | ||
121 | $this->assertEquals('base', $e->getTemplateFile()); | ||
122 | } | ||
123 | } | ||
124 | |||
125 | public function testTwigExceptionAddsFileAndLineWhenMissingWithInheritanceOnDisk() | ||
126 | { | ||
127 | $loader = new Twig_Loader_Filesystem(dirname(__FILE__).'/Fixtures/errors'); | ||
128 | $twig = new Twig_Environment($loader, array('strict_variables' => true, 'debug' => true, 'cache' => false)); | ||
129 | |||
130 | $template = $twig->loadTemplate('index.html'); | ||
131 | try { | ||
132 | $template->render(array()); | ||
133 | |||
134 | $this->fail(); | ||
135 | } catch (Twig_Error_Runtime $e) { | ||
136 | $this->assertEquals('Variable "foo" does not exist in "index.html" at line 3', $e->getMessage()); | ||
137 | $this->assertEquals(3, $e->getTemplateLine()); | ||
138 | $this->assertEquals('index.html', $e->getTemplateFile()); | ||
139 | } | ||
140 | |||
141 | try { | ||
142 | $template->render(array('foo' => new Twig_Tests_ErrorTest_Foo())); | ||
143 | |||
144 | $this->fail(); | ||
145 | } catch (Twig_Error_Runtime $e) { | ||
146 | $this->assertEquals('An exception has been thrown during the rendering of a template ("Runtime error...") in "index.html" at line 3.', $e->getMessage()); | ||
147 | $this->assertEquals(3, $e->getTemplateLine()); | ||
148 | $this->assertEquals('index.html', $e->getTemplateFile()); | ||
149 | } | ||
150 | } | ||
151 | } | ||
152 | |||
153 | class Twig_Tests_ErrorTest_Foo | ||
154 | { | ||
155 | public function bar() | ||
156 | { | ||
157 | throw new Exception('Runtime error...'); | ||
158 | } | ||
159 | } | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/ExpressionParserTest.php b/vendor/twig/twig/test/Twig/Tests/ExpressionParserTest.php new file mode 100644 index 00000000..8ec6537a --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/ExpressionParserTest.php | |||
@@ -0,0 +1,332 @@ | |||
1 | <?php | ||
2 | |||
3 | /* | ||
4 | * This file is part of Twig. | ||
5 | * | ||
6 | * (c) 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_Tests_ExpressionParserTest extends PHPUnit_Framework_TestCase | ||
13 | { | ||
14 | /** | ||
15 | * @expectedException Twig_Error_Syntax | ||
16 | * @dataProvider getFailingTestsForAssignment | ||
17 | */ | ||
18 | public function testCanOnlyAssignToNames($template) | ||
19 | { | ||
20 | $env = new Twig_Environment(new Twig_Loader_String(), array('cache' => false, 'autoescape' => false)); | ||
21 | $parser = new Twig_Parser($env); | ||
22 | |||
23 | $parser->parse($env->tokenize($template, 'index')); | ||
24 | } | ||
25 | |||
26 | public function getFailingTestsForAssignment() | ||
27 | { | ||
28 | return array( | ||
29 | array('{% set false = "foo" %}'), | ||
30 | array('{% set true = "foo" %}'), | ||
31 | array('{% set none = "foo" %}'), | ||
32 | array('{% set 3 = "foo" %}'), | ||
33 | array('{% set 1 + 2 = "foo" %}'), | ||
34 | array('{% set "bar" = "foo" %}'), | ||
35 | array('{% set %}{% endset %}') | ||
36 | ); | ||
37 | } | ||
38 | |||
39 | /** | ||
40 | * @dataProvider getTestsForArray | ||
41 | */ | ||
42 | public function testArrayExpression($template, $expected) | ||
43 | { | ||
44 | $env = new Twig_Environment(new Twig_Loader_String(), array('cache' => false, 'autoescape' => false)); | ||
45 | $stream = $env->tokenize($template, 'index'); | ||
46 | $parser = new Twig_Parser($env); | ||
47 | |||
48 | $this->assertEquals($expected, $parser->parse($stream)->getNode('body')->getNode(0)->getNode('expr')); | ||
49 | } | ||
50 | |||
51 | /** | ||
52 | * @expectedException Twig_Error_Syntax | ||
53 | * @dataProvider getFailingTestsForArray | ||
54 | */ | ||
55 | public function testArraySyntaxError($template) | ||
56 | { | ||
57 | $env = new Twig_Environment(new Twig_Loader_String(), array('cache' => false, 'autoescape' => false)); | ||
58 | $parser = new Twig_Parser($env); | ||
59 | |||
60 | $parser->parse($env->tokenize($template, 'index')); | ||
61 | } | ||
62 | |||
63 | public function getFailingTestsForArray() | ||
64 | { | ||
65 | return array( | ||
66 | array('{{ [1, "a": "b"] }}'), | ||
67 | array('{{ {"a": "b", 2} }}'), | ||
68 | ); | ||
69 | } | ||
70 | |||
71 | public function getTestsForArray() | ||
72 | { | ||
73 | return array( | ||
74 | // simple array | ||
75 | array('{{ [1, 2] }}', new Twig_Node_Expression_Array(array( | ||
76 | new Twig_Node_Expression_Constant(0, 1), | ||
77 | new Twig_Node_Expression_Constant(1, 1), | ||
78 | |||
79 | new Twig_Node_Expression_Constant(1, 1), | ||
80 | new Twig_Node_Expression_Constant(2, 1), | ||
81 | ), 1), | ||
82 | ), | ||
83 | |||
84 | // array with trailing , | ||
85 | array('{{ [1, 2, ] }}', new Twig_Node_Expression_Array(array( | ||
86 | new Twig_Node_Expression_Constant(0, 1), | ||
87 | new Twig_Node_Expression_Constant(1, 1), | ||
88 | |||
89 | new Twig_Node_Expression_Constant(1, 1), | ||
90 | new Twig_Node_Expression_Constant(2, 1), | ||
91 | ), 1), | ||
92 | ), | ||
93 | |||
94 | // simple hash | ||
95 | array('{{ {"a": "b", "b": "c"} }}', new Twig_Node_Expression_Array(array( | ||
96 | new Twig_Node_Expression_Constant('a', 1), | ||
97 | new Twig_Node_Expression_Constant('b', 1), | ||
98 | |||
99 | new Twig_Node_Expression_Constant('b', 1), | ||
100 | new Twig_Node_Expression_Constant('c', 1), | ||
101 | ), 1), | ||
102 | ), | ||
103 | |||
104 | // hash with trailing , | ||
105 | array('{{ {"a": "b", "b": "c", } }}', new Twig_Node_Expression_Array(array( | ||
106 | new Twig_Node_Expression_Constant('a', 1), | ||
107 | new Twig_Node_Expression_Constant('b', 1), | ||
108 | |||
109 | new Twig_Node_Expression_Constant('b', 1), | ||
110 | new Twig_Node_Expression_Constant('c', 1), | ||
111 | ), 1), | ||
112 | ), | ||
113 | |||
114 | // hash in an array | ||
115 | array('{{ [1, {"a": "b", "b": "c"}] }}', new Twig_Node_Expression_Array(array( | ||
116 | new Twig_Node_Expression_Constant(0, 1), | ||
117 | new Twig_Node_Expression_Constant(1, 1), | ||
118 | |||
119 | new Twig_Node_Expression_Constant(1, 1), | ||
120 | new Twig_Node_Expression_Array(array( | ||
121 | new Twig_Node_Expression_Constant('a', 1), | ||
122 | new Twig_Node_Expression_Constant('b', 1), | ||
123 | |||
124 | new Twig_Node_Expression_Constant('b', 1), | ||
125 | new Twig_Node_Expression_Constant('c', 1), | ||
126 | ), 1), | ||
127 | ), 1), | ||
128 | ), | ||
129 | |||
130 | // array in a hash | ||
131 | array('{{ {"a": [1, 2], "b": "c"} }}', new Twig_Node_Expression_Array(array( | ||
132 | new Twig_Node_Expression_Constant('a', 1), | ||
133 | new Twig_Node_Expression_Array(array( | ||
134 | new Twig_Node_Expression_Constant(0, 1), | ||
135 | new Twig_Node_Expression_Constant(1, 1), | ||
136 | |||
137 | new Twig_Node_Expression_Constant(1, 1), | ||
138 | new Twig_Node_Expression_Constant(2, 1), | ||
139 | ), 1), | ||
140 | new Twig_Node_Expression_Constant('b', 1), | ||
141 | new Twig_Node_Expression_Constant('c', 1), | ||
142 | ), 1), | ||
143 | ), | ||
144 | ); | ||
145 | } | ||
146 | |||
147 | /** | ||
148 | * @expectedException Twig_Error_Syntax | ||
149 | */ | ||
150 | public function testStringExpressionDoesNotConcatenateTwoConsecutiveStrings() | ||
151 | { | ||
152 | $env = new Twig_Environment(new Twig_Loader_String(), array('cache' => false, 'autoescape' => false, 'optimizations' => 0)); | ||
153 | $stream = $env->tokenize('{{ "a" "b" }}', 'index'); | ||
154 | $parser = new Twig_Parser($env); | ||
155 | |||
156 | $parser->parse($stream); | ||
157 | } | ||
158 | |||
159 | /** | ||
160 | * @dataProvider getTestsForString | ||
161 | */ | ||
162 | public function testStringExpression($template, $expected) | ||
163 | { | ||
164 | $env = new Twig_Environment(new Twig_Loader_String(), array('cache' => false, 'autoescape' => false, 'optimizations' => 0)); | ||
165 | $stream = $env->tokenize($template, 'index'); | ||
166 | $parser = new Twig_Parser($env); | ||
167 | |||
168 | $this->assertEquals($expected, $parser->parse($stream)->getNode('body')->getNode(0)->getNode('expr')); | ||
169 | } | ||
170 | |||
171 | public function getTestsForString() | ||
172 | { | ||
173 | return array( | ||
174 | array( | ||
175 | '{{ "foo" }}', new Twig_Node_Expression_Constant('foo', 1), | ||
176 | ), | ||
177 | array( | ||
178 | '{{ "foo #{bar}" }}', new Twig_Node_Expression_Binary_Concat( | ||
179 | new Twig_Node_Expression_Constant('foo ', 1), | ||
180 | new Twig_Node_Expression_Name('bar', 1), | ||
181 | 1 | ||
182 | ), | ||
183 | ), | ||
184 | array( | ||
185 | '{{ "foo #{bar} baz" }}', new Twig_Node_Expression_Binary_Concat( | ||
186 | new Twig_Node_Expression_Binary_Concat( | ||
187 | new Twig_Node_Expression_Constant('foo ', 1), | ||
188 | new Twig_Node_Expression_Name('bar', 1), | ||
189 | 1 | ||
190 | ), | ||
191 | new Twig_Node_Expression_Constant(' baz', 1), | ||
192 | 1 | ||
193 | ) | ||
194 | ), | ||
195 | |||
196 | array( | ||
197 | '{{ "foo #{"foo #{bar} baz"} baz" }}', new Twig_Node_Expression_Binary_Concat( | ||
198 | new Twig_Node_Expression_Binary_Concat( | ||
199 | new Twig_Node_Expression_Constant('foo ', 1), | ||
200 | new Twig_Node_Expression_Binary_Concat( | ||
201 | new Twig_Node_Expression_Binary_Concat( | ||
202 | new Twig_Node_Expression_Constant('foo ', 1), | ||
203 | new Twig_Node_Expression_Name('bar', 1), | ||
204 | 1 | ||
205 | ), | ||
206 | new Twig_Node_Expression_Constant(' baz', 1), | ||
207 | 1 | ||
208 | ), | ||
209 | 1 | ||
210 | ), | ||
211 | new Twig_Node_Expression_Constant(' baz', 1), | ||
212 | 1 | ||
213 | ), | ||
214 | ), | ||
215 | ); | ||
216 | } | ||
217 | |||
218 | /** | ||
219 | * @expectedException Twig_Error_Syntax | ||
220 | */ | ||
221 | public function testAttributeCallDoesNotSupportNamedArguments() | ||
222 | { | ||
223 | $env = new Twig_Environment(new Twig_Loader_String(), array('cache' => false, 'autoescape' => false)); | ||
224 | $parser = new Twig_Parser($env); | ||
225 | |||
226 | $parser->parse($env->tokenize('{{ foo.bar(name="Foo") }}', 'index')); | ||
227 | } | ||
228 | |||
229 | /** | ||
230 | * @expectedException Twig_Error_Syntax | ||
231 | */ | ||
232 | public function testMacroCallDoesNotSupportNamedArguments() | ||
233 | { | ||
234 | $env = new Twig_Environment(new Twig_Loader_String(), array('cache' => false, 'autoescape' => false)); | ||
235 | $parser = new Twig_Parser($env); | ||
236 | |||
237 | $parser->parse($env->tokenize('{% from _self import foo %}{% macro foo() %}{% endmacro %}{{ foo(name="Foo") }}', 'index')); | ||
238 | } | ||
239 | |||
240 | /** | ||
241 | * @expectedException Twig_Error_Syntax | ||
242 | * @expectedExceptionMessage An argument must be a name. Unexpected token "string" of value "a" ("name" expected) in "index" at line 1 | ||
243 | */ | ||
244 | public function testMacroDefinitionDoesNotSupportNonNameVariableName() | ||
245 | { | ||
246 | $env = new Twig_Environment(new Twig_Loader_String(), array('cache' => false, 'autoescape' => false)); | ||
247 | $parser = new Twig_Parser($env); | ||
248 | |||
249 | $parser->parse($env->tokenize('{% macro foo("a") %}{% endmacro %}', 'index')); | ||
250 | } | ||
251 | |||
252 | /** | ||
253 | * @expectedException Twig_Error_Syntax | ||
254 | * @expectedExceptionMessage A default value for an argument must be a constant (a boolean, a string, a number, or an array) in "index" at line 1 | ||
255 | * @dataProvider getMacroDefinitionDoesNotSupportNonConstantDefaultValues | ||
256 | */ | ||
257 | public function testMacroDefinitionDoesNotSupportNonConstantDefaultValues($template) | ||
258 | { | ||
259 | $env = new Twig_Environment(new Twig_Loader_String(), array('cache' => false, 'autoescape' => false)); | ||
260 | $parser = new Twig_Parser($env); | ||
261 | |||
262 | $parser->parse($env->tokenize($template, 'index')); | ||
263 | } | ||
264 | |||
265 | public function getMacroDefinitionDoesNotSupportNonConstantDefaultValues() | ||
266 | { | ||
267 | return array( | ||
268 | array('{% macro foo(name = "a #{foo} a") %}{% endmacro %}'), | ||
269 | array('{% macro foo(name = [["b", "a #{foo} a"]]) %}{% endmacro %}'), | ||
270 | ); | ||
271 | } | ||
272 | |||
273 | /** | ||
274 | * @dataProvider getMacroDefinitionSupportsConstantDefaultValues | ||
275 | */ | ||
276 | public function testMacroDefinitionSupportsConstantDefaultValues($template) | ||
277 | { | ||
278 | $env = new Twig_Environment(new Twig_Loader_String(), array('cache' => false, 'autoescape' => false)); | ||
279 | $parser = new Twig_Parser($env); | ||
280 | |||
281 | $parser->parse($env->tokenize($template, 'index')); | ||
282 | } | ||
283 | |||
284 | public function getMacroDefinitionSupportsConstantDefaultValues() | ||
285 | { | ||
286 | return array( | ||
287 | array('{% macro foo(name = "aa") %}{% endmacro %}'), | ||
288 | array('{% macro foo(name = 12) %}{% endmacro %}'), | ||
289 | array('{% macro foo(name = true) %}{% endmacro %}'), | ||
290 | array('{% macro foo(name = ["a"]) %}{% endmacro %}'), | ||
291 | array('{% macro foo(name = [["a"]]) %}{% endmacro %}'), | ||
292 | array('{% macro foo(name = {a: "a"}) %}{% endmacro %}'), | ||
293 | array('{% macro foo(name = {a: {b: "a"}}) %}{% endmacro %}'), | ||
294 | ); | ||
295 | } | ||
296 | |||
297 | /** | ||
298 | * @expectedException Twig_Error_Syntax | ||
299 | * @expectedExceptionMessage The function "cycl" does not exist. Did you mean "cycle" in "index" at line 1 | ||
300 | */ | ||
301 | public function testUnknownFunction() | ||
302 | { | ||
303 | $env = new Twig_Environment(new Twig_Loader_String(), array('cache' => false, 'autoescape' => false)); | ||
304 | $parser = new Twig_Parser($env); | ||
305 | |||
306 | $parser->parse($env->tokenize('{{ cycl() }}', 'index')); | ||
307 | } | ||
308 | |||
309 | /** | ||
310 | * @expectedException Twig_Error_Syntax | ||
311 | * @expectedExceptionMessage The filter "lowe" does not exist. Did you mean "lower" in "index" at line 1 | ||
312 | */ | ||
313 | public function testUnknownFilter() | ||
314 | { | ||
315 | $env = new Twig_Environment(new Twig_Loader_String(), array('cache' => false, 'autoescape' => false)); | ||
316 | $parser = new Twig_Parser($env); | ||
317 | |||
318 | $parser->parse($env->tokenize('{{ 1|lowe }}', 'index')); | ||
319 | } | ||
320 | |||
321 | /** | ||
322 | * @expectedException Twig_Error_Syntax | ||
323 | * @expectedExceptionMessage The test "nul" does not exist. Did you mean "null" in "index" at line 1 | ||
324 | */ | ||
325 | public function testUnknownTest() | ||
326 | { | ||
327 | $env = new Twig_Environment(new Twig_Loader_String(), array('cache' => false, 'autoescape' => false)); | ||
328 | $parser = new Twig_Parser($env); | ||
329 | |||
330 | $parser->parse($env->tokenize('{{ 1 is nul }}', 'index')); | ||
331 | } | ||
332 | } | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Extension/CoreTest.php b/vendor/twig/twig/test/Twig/Tests/Extension/CoreTest.php new file mode 100644 index 00000000..5743e343 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Extension/CoreTest.php | |||
@@ -0,0 +1,117 @@ | |||
1 | <?php | ||
2 | |||
3 | /* | ||
4 | * This file is part of Twig. | ||
5 | * | ||
6 | * (c) 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_Tests_Extension_CoreTest extends PHPUnit_Framework_TestCase | ||
13 | { | ||
14 | /** | ||
15 | * @dataProvider getRandomFunctionTestData | ||
16 | */ | ||
17 | public function testRandomFunction($value, $expectedInArray) | ||
18 | { | ||
19 | $env = new Twig_Environment(); | ||
20 | |||
21 | for ($i = 0; $i < 100; $i++) { | ||
22 | $this->assertTrue(in_array(twig_random($env, $value), $expectedInArray, true)); // assertContains() would not consider the type | ||
23 | } | ||
24 | } | ||
25 | |||
26 | public function getRandomFunctionTestData() | ||
27 | { | ||
28 | return array( | ||
29 | array( // array | ||
30 | array('apple', 'orange', 'citrus'), | ||
31 | array('apple', 'orange', 'citrus'), | ||
32 | ), | ||
33 | array( // Traversable | ||
34 | new ArrayObject(array('apple', 'orange', 'citrus')), | ||
35 | array('apple', 'orange', 'citrus'), | ||
36 | ), | ||
37 | array( // unicode string | ||
38 | 'Ä€é', | ||
39 | array('Ä', '€', 'é'), | ||
40 | ), | ||
41 | array( // numeric but string | ||
42 | '123', | ||
43 | array('1', '2', '3'), | ||
44 | ), | ||
45 | array( // integer | ||
46 | 5, | ||
47 | range(0, 5, 1), | ||
48 | ), | ||
49 | array( // float | ||
50 | 5.9, | ||
51 | range(0, 5, 1), | ||
52 | ), | ||
53 | array( // negative | ||
54 | -2, | ||
55 | array(0, -1, -2), | ||
56 | ), | ||
57 | ); | ||
58 | } | ||
59 | |||
60 | public function testRandomFunctionWithoutParameter() | ||
61 | { | ||
62 | $max = mt_getrandmax(); | ||
63 | |||
64 | for ($i = 0; $i < 100; $i++) { | ||
65 | $val = twig_random(new Twig_Environment()); | ||
66 | $this->assertTrue(is_int($val) && $val >= 0 && $val <= $max); | ||
67 | } | ||
68 | } | ||
69 | |||
70 | public function testRandomFunctionReturnsAsIs() | ||
71 | { | ||
72 | $this->assertSame('', twig_random(new Twig_Environment(), '')); | ||
73 | $this->assertSame('', twig_random(new Twig_Environment(null, array('charset' => null)), '')); | ||
74 | |||
75 | $instance = new stdClass(); | ||
76 | $this->assertSame($instance, twig_random(new Twig_Environment(), $instance)); | ||
77 | } | ||
78 | |||
79 | /** | ||
80 | * @expectedException Twig_Error_Runtime | ||
81 | */ | ||
82 | public function testRandomFunctionOfEmptyArrayThrowsException() | ||
83 | { | ||
84 | twig_random(new Twig_Environment(), array()); | ||
85 | } | ||
86 | |||
87 | public function testRandomFunctionOnNonUTF8String() | ||
88 | { | ||
89 | if (!function_exists('iconv') && !function_exists('mb_convert_encoding')) { | ||
90 | $this->markTestSkipped('needs iconv or mbstring'); | ||
91 | } | ||
92 | |||
93 | $twig = new Twig_Environment(); | ||
94 | $twig->setCharset('ISO-8859-1'); | ||
95 | |||
96 | $text = twig_convert_encoding('Äé', 'ISO-8859-1', 'UTF-8'); | ||
97 | for ($i = 0; $i < 30; $i++) { | ||
98 | $rand = twig_random($twig, $text); | ||
99 | $this->assertTrue(in_array(twig_convert_encoding($rand, 'UTF-8', 'ISO-8859-1'), array('Ä', 'é'), true)); | ||
100 | } | ||
101 | } | ||
102 | |||
103 | public function testReverseFilterOnNonUTF8String() | ||
104 | { | ||
105 | if (!function_exists('iconv') && !function_exists('mb_convert_encoding')) { | ||
106 | $this->markTestSkipped('needs iconv or mbstring'); | ||
107 | } | ||
108 | |||
109 | $twig = new Twig_Environment(); | ||
110 | $twig->setCharset('ISO-8859-1'); | ||
111 | |||
112 | $input = twig_convert_encoding('Äé', 'ISO-8859-1', 'UTF-8'); | ||
113 | $output = twig_convert_encoding(twig_reverse_filter($twig, $input), 'UTF-8', 'ISO-8859-1'); | ||
114 | |||
115 | $this->assertEquals($output, 'éÄ'); | ||
116 | } | ||
117 | } | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Extension/SandboxTest.php b/vendor/twig/twig/test/Twig/Tests/Extension/SandboxTest.php new file mode 100644 index 00000000..72253c88 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Extension/SandboxTest.php | |||
@@ -0,0 +1,212 @@ | |||
1 | <?php | ||
2 | |||
3 | /* | ||
4 | * This file is part of Twig. | ||
5 | * | ||
6 | * (c) 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_Tests_Extension_SandboxTest extends PHPUnit_Framework_TestCase | ||
13 | { | ||
14 | protected static $params, $templates; | ||
15 | |||
16 | public function setUp() | ||
17 | { | ||
18 | self::$params = array( | ||
19 | 'name' => 'Fabien', | ||
20 | 'obj' => new FooObject(), | ||
21 | 'arr' => array('obj' => new FooObject()), | ||
22 | ); | ||
23 | |||
24 | self::$templates = array( | ||
25 | '1_basic1' => '{{ obj.foo }}', | ||
26 | '1_basic2' => '{{ name|upper }}', | ||
27 | '1_basic3' => '{% if name %}foo{% endif %}', | ||
28 | '1_basic4' => '{{ obj.bar }}', | ||
29 | '1_basic5' => '{{ obj }}', | ||
30 | '1_basic6' => '{{ arr.obj }}', | ||
31 | '1_basic7' => '{{ cycle(["foo","bar"], 1) }}', | ||
32 | '1_basic8' => '{{ obj.getfoobar }}{{ obj.getFooBar }}', | ||
33 | '1_basic' => '{% if obj.foo %}{{ obj.foo|upper }}{% endif %}', | ||
34 | '1_layout' => '{% block content %}{% endblock %}', | ||
35 | '1_child' => '{% extends "1_layout" %}{% block content %}{{ "a"|json_encode }}{% endblock %}', | ||
36 | ); | ||
37 | } | ||
38 | |||
39 | /** | ||
40 | * @expectedException Twig_Sandbox_SecurityError | ||
41 | * @expectedExceptionMessage Filter "json_encode" is not allowed in "1_child". | ||
42 | */ | ||
43 | public function testSandboxWithInheritance() | ||
44 | { | ||
45 | $twig = $this->getEnvironment(true, array(), self::$templates, array('block')); | ||
46 | $twig->loadTemplate('1_child')->render(array()); | ||
47 | } | ||
48 | |||
49 | public function testSandboxGloballySet() | ||
50 | { | ||
51 | $twig = $this->getEnvironment(false, array(), self::$templates); | ||
52 | $this->assertEquals('FOO', $twig->loadTemplate('1_basic')->render(self::$params), 'Sandbox does nothing if it is disabled globally'); | ||
53 | |||
54 | $twig = $this->getEnvironment(true, array(), self::$templates); | ||
55 | try { | ||
56 | $twig->loadTemplate('1_basic1')->render(self::$params); | ||
57 | $this->fail('Sandbox throws a SecurityError exception if an unallowed method is called'); | ||
58 | } catch (Twig_Sandbox_SecurityError $e) { | ||
59 | } | ||
60 | |||
61 | $twig = $this->getEnvironment(true, array(), self::$templates); | ||
62 | try { | ||
63 | $twig->loadTemplate('1_basic2')->render(self::$params); | ||
64 | $this->fail('Sandbox throws a SecurityError exception if an unallowed filter is called'); | ||
65 | } catch (Twig_Sandbox_SecurityError $e) { | ||
66 | } | ||
67 | |||
68 | $twig = $this->getEnvironment(true, array(), self::$templates); | ||
69 | try { | ||
70 | $twig->loadTemplate('1_basic3')->render(self::$params); | ||
71 | $this->fail('Sandbox throws a SecurityError exception if an unallowed tag is used in the template'); | ||
72 | } catch (Twig_Sandbox_SecurityError $e) { | ||
73 | } | ||
74 | |||
75 | $twig = $this->getEnvironment(true, array(), self::$templates); | ||
76 | try { | ||
77 | $twig->loadTemplate('1_basic4')->render(self::$params); | ||
78 | $this->fail('Sandbox throws a SecurityError exception if an unallowed property is called in the template'); | ||
79 | } catch (Twig_Sandbox_SecurityError $e) { | ||
80 | } | ||
81 | |||
82 | $twig = $this->getEnvironment(true, array(), self::$templates); | ||
83 | try { | ||
84 | $twig->loadTemplate('1_basic5')->render(self::$params); | ||
85 | $this->fail('Sandbox throws a SecurityError exception if an unallowed method (__toString()) is called in the template'); | ||
86 | } catch (Twig_Sandbox_SecurityError $e) { | ||
87 | } | ||
88 | |||
89 | $twig = $this->getEnvironment(true, array(), self::$templates); | ||
90 | try { | ||
91 | $twig->loadTemplate('1_basic6')->render(self::$params); | ||
92 | $this->fail('Sandbox throws a SecurityError exception if an unallowed method (__toString()) is called in the template'); | ||
93 | } catch (Twig_Sandbox_SecurityError $e) { | ||
94 | } | ||
95 | |||
96 | $twig = $this->getEnvironment(true, array(), self::$templates); | ||
97 | try { | ||
98 | $twig->loadTemplate('1_basic7')->render(self::$params); | ||
99 | $this->fail('Sandbox throws a SecurityError exception if an unallowed function is called in the template'); | ||
100 | } catch (Twig_Sandbox_SecurityError $e) { | ||
101 | } | ||
102 | |||
103 | $twig = $this->getEnvironment(true, array(), self::$templates, array(), array(), array('FooObject' => 'foo')); | ||
104 | FooObject::reset(); | ||
105 | $this->assertEquals('foo', $twig->loadTemplate('1_basic1')->render(self::$params), 'Sandbox allow some methods'); | ||
106 | $this->assertEquals(1, FooObject::$called['foo'], 'Sandbox only calls method once'); | ||
107 | |||
108 | $twig = $this->getEnvironment(true, array(), self::$templates, array(), array(), array('FooObject' => '__toString')); | ||
109 | FooObject::reset(); | ||
110 | $this->assertEquals('foo', $twig->loadTemplate('1_basic5')->render(self::$params), 'Sandbox allow some methods'); | ||
111 | $this->assertEquals(1, FooObject::$called['__toString'], 'Sandbox only calls method once'); | ||
112 | |||
113 | $twig = $this->getEnvironment(true, array(), self::$templates, array(), array('upper')); | ||
114 | $this->assertEquals('FABIEN', $twig->loadTemplate('1_basic2')->render(self::$params), 'Sandbox allow some filters'); | ||
115 | |||
116 | $twig = $this->getEnvironment(true, array(), self::$templates, array('if')); | ||
117 | $this->assertEquals('foo', $twig->loadTemplate('1_basic3')->render(self::$params), 'Sandbox allow some tags'); | ||
118 | |||
119 | $twig = $this->getEnvironment(true, array(), self::$templates, array(), array(), array(), array('FooObject' => 'bar')); | ||
120 | $this->assertEquals('bar', $twig->loadTemplate('1_basic4')->render(self::$params), 'Sandbox allow some properties'); | ||
121 | |||
122 | $twig = $this->getEnvironment(true, array(), self::$templates, array(), array(), array(), array(), array('cycle')); | ||
123 | $this->assertEquals('bar', $twig->loadTemplate('1_basic7')->render(self::$params), 'Sandbox allow some functions'); | ||
124 | |||
125 | foreach (array('getfoobar', 'getFoobar', 'getFooBar') as $name) { | ||
126 | $twig = $this->getEnvironment(true, array(), self::$templates, array(), array(), array('FooObject' => $name)); | ||
127 | FooObject::reset(); | ||
128 | $this->assertEquals('foobarfoobar', $twig->loadTemplate('1_basic8')->render(self::$params), 'Sandbox allow methods in a case-insensitive way'); | ||
129 | $this->assertEquals(2, FooObject::$called['getFooBar'], 'Sandbox only calls method once'); | ||
130 | } | ||
131 | } | ||
132 | |||
133 | public function testSandboxLocallySetForAnInclude() | ||
134 | { | ||
135 | self::$templates = array( | ||
136 | '2_basic' => '{{ obj.foo }}{% include "2_included" %}{{ obj.foo }}', | ||
137 | '2_included' => '{% if obj.foo %}{{ obj.foo|upper }}{% endif %}', | ||
138 | ); | ||
139 | |||
140 | $twig = $this->getEnvironment(false, array(), self::$templates); | ||
141 | $this->assertEquals('fooFOOfoo', $twig->loadTemplate('2_basic')->render(self::$params), 'Sandbox does nothing if disabled globally and sandboxed not used for the include'); | ||
142 | |||
143 | self::$templates = array( | ||
144 | '3_basic' => '{{ obj.foo }}{% sandbox %}{% include "3_included" %}{% endsandbox %}{{ obj.foo }}', | ||
145 | '3_included' => '{% if obj.foo %}{{ obj.foo|upper }}{% endif %}', | ||
146 | ); | ||
147 | |||
148 | $twig = $this->getEnvironment(true, array(), self::$templates); | ||
149 | try { | ||
150 | $twig->loadTemplate('3_basic')->render(self::$params); | ||
151 | $this->fail('Sandbox throws a SecurityError exception when the included file is sandboxed'); | ||
152 | } catch (Twig_Sandbox_SecurityError $e) { | ||
153 | } | ||
154 | } | ||
155 | |||
156 | public function testMacrosInASandbox() | ||
157 | { | ||
158 | $twig = $this->getEnvironment(true, array('autoescape' => true), array('index' => <<<EOF | ||
159 | {%- import _self as macros %} | ||
160 | |||
161 | {%- macro test(text) %}<p>{{ text }}</p>{% endmacro %} | ||
162 | |||
163 | {{- macros.test('username') }} | ||
164 | EOF | ||
165 | ), array('macro', 'import'), array('escape')); | ||
166 | |||
167 | $this->assertEquals('<p>username</p>', $twig->loadTemplate('index')->render(array())); | ||
168 | } | ||
169 | |||
170 | protected function getEnvironment($sandboxed, $options, $templates, $tags = array(), $filters = array(), $methods = array(), $properties = array(), $functions = array()) | ||
171 | { | ||
172 | $loader = new Twig_Loader_Array($templates); | ||
173 | $twig = new Twig_Environment($loader, array_merge(array('debug' => true, 'cache' => false, 'autoescape' => false), $options)); | ||
174 | $policy = new Twig_Sandbox_SecurityPolicy($tags, $filters, $methods, $properties, $functions); | ||
175 | $twig->addExtension(new Twig_Extension_Sandbox($policy, $sandboxed)); | ||
176 | |||
177 | return $twig; | ||
178 | } | ||
179 | } | ||
180 | |||
181 | class FooObject | ||
182 | { | ||
183 | public static $called = array('__toString' => 0, 'foo' => 0, 'getFooBar' => 0); | ||
184 | |||
185 | public $bar = 'bar'; | ||
186 | |||
187 | public static function reset() | ||
188 | { | ||
189 | self::$called = array('__toString' => 0, 'foo' => 0, 'getFooBar' => 0); | ||
190 | } | ||
191 | |||
192 | public function __toString() | ||
193 | { | ||
194 | ++self::$called['__toString']; | ||
195 | |||
196 | return 'foo'; | ||
197 | } | ||
198 | |||
199 | public function foo() | ||
200 | { | ||
201 | ++self::$called['foo']; | ||
202 | |||
203 | return 'foo'; | ||
204 | } | ||
205 | |||
206 | public function getFooBar() | ||
207 | { | ||
208 | ++self::$called['getFooBar']; | ||
209 | |||
210 | return 'foobar'; | ||
211 | } | ||
212 | } | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/FileCachingTest.php b/vendor/twig/twig/test/Twig/Tests/FileCachingTest.php new file mode 100644 index 00000000..8efc948f --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/FileCachingTest.php | |||
@@ -0,0 +1,70 @@ | |||
1 | <?php | ||
2 | |||
3 | class Twig_Tests_FileCachingTest extends PHPUnit_Framework_TestCase | ||
4 | { | ||
5 | protected $fileName; | ||
6 | protected $env; | ||
7 | protected $tmpDir; | ||
8 | |||
9 | public function setUp() | ||
10 | { | ||
11 | $this->tmpDir = sys_get_temp_dir().'/TwigTests'; | ||
12 | if (!file_exists($this->tmpDir)) { | ||
13 | @mkdir($this->tmpDir, 0777, true); | ||
14 | } | ||
15 | |||
16 | if (!is_writable($this->tmpDir)) { | ||
17 | $this->markTestSkipped(sprintf('Unable to run the tests as "%s" is not writable.', $this->tmpDir)); | ||
18 | } | ||
19 | |||
20 | $this->env = new Twig_Environment(new Twig_Loader_String(), array('cache' => $this->tmpDir)); | ||
21 | } | ||
22 | |||
23 | public function tearDown() | ||
24 | { | ||
25 | if ($this->fileName) { | ||
26 | unlink($this->fileName); | ||
27 | } | ||
28 | |||
29 | $this->removeDir($this->tmpDir); | ||
30 | } | ||
31 | |||
32 | public function testWritingCacheFiles() | ||
33 | { | ||
34 | $name = 'This is just text.'; | ||
35 | $template = $this->env->loadTemplate($name); | ||
36 | $cacheFileName = $this->env->getCacheFilename($name); | ||
37 | |||
38 | $this->assertTrue(file_exists($cacheFileName), 'Cache file does not exist.'); | ||
39 | $this->fileName = $cacheFileName; | ||
40 | } | ||
41 | |||
42 | public function testClearingCacheFiles() | ||
43 | { | ||
44 | $name = 'I will be deleted.'; | ||
45 | $template = $this->env->loadTemplate($name); | ||
46 | $cacheFileName = $this->env->getCacheFilename($name); | ||
47 | |||
48 | $this->assertTrue(file_exists($cacheFileName), 'Cache file does not exist.'); | ||
49 | $this->env->clearCacheFiles(); | ||
50 | $this->assertFalse(file_exists($cacheFileName), 'Cache file was not cleared.'); | ||
51 | } | ||
52 | |||
53 | private function removeDir($target) | ||
54 | { | ||
55 | $fp = opendir($target); | ||
56 | while (false !== $file = readdir($fp)) { | ||
57 | if (in_array($file, array('.', '..'))) { | ||
58 | continue; | ||
59 | } | ||
60 | |||
61 | if (is_dir($target.'/'.$file)) { | ||
62 | self::removeDir($target.'/'.$file); | ||
63 | } else { | ||
64 | unlink($target.'/'.$file); | ||
65 | } | ||
66 | } | ||
67 | closedir($fp); | ||
68 | rmdir($target); | ||
69 | } | ||
70 | } | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/errors/base.html b/vendor/twig/twig/test/Twig/Tests/Fixtures/errors/base.html new file mode 100644 index 00000000..cb0dbe44 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/errors/base.html | |||
@@ -0,0 +1 @@ | |||
{% block content %}{% endblock %} | |||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/errors/index.html b/vendor/twig/twig/test/Twig/Tests/Fixtures/errors/index.html new file mode 100644 index 00000000..df57c822 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/errors/index.html | |||
@@ -0,0 +1,7 @@ | |||
1 | {% extends 'base.html' %} | ||
2 | {% block content %} | ||
3 | {{ foo.bar }} | ||
4 | {% endblock %} | ||
5 | {% block foo %} | ||
6 | {{ foo.bar }} | ||
7 | {% endblock %} | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/exceptions/unclosed_tag.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/exceptions/unclosed_tag.test new file mode 100644 index 00000000..02245e93 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/exceptions/unclosed_tag.test | |||
@@ -0,0 +1,20 @@ | |||
1 | --TEST-- | ||
2 | Exception for an unclosed tag | ||
3 | --TEMPLATE-- | ||
4 | {% block foo %} | ||
5 | {% if foo %} | ||
6 | |||
7 | |||
8 | |||
9 | |||
10 | {% for i in fo %} | ||
11 | |||
12 | |||
13 | |||
14 | {% endfor %} | ||
15 | |||
16 | |||
17 | |||
18 | {% endblock %} | ||
19 | --EXCEPTION-- | ||
20 | Twig_Error_Syntax: Unexpected tag name "endblock" (expecting closing tag for the "if" tag defined near line 4) in "index.twig" at line 16 | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/expressions/array.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/expressions/array.test new file mode 100644 index 00000000..c69b1192 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/expressions/array.test | |||
@@ -0,0 +1,61 @@ | |||
1 | --TEST-- | ||
2 | Twig supports array notation | ||
3 | --TEMPLATE-- | ||
4 | {# empty array #} | ||
5 | {{ []|join(',') }} | ||
6 | |||
7 | {{ [1, 2]|join(',') }} | ||
8 | {{ ['foo', "bar"]|join(',') }} | ||
9 | {{ {0: 1, 'foo': 'bar'}|join(',') }} | ||
10 | {{ {0: 1, 'foo': 'bar'}|keys|join(',') }} | ||
11 | |||
12 | {{ {0: 1, foo: 'bar'}|join(',') }} | ||
13 | {{ {0: 1, foo: 'bar'}|keys|join(',') }} | ||
14 | |||
15 | {# nested arrays #} | ||
16 | {% set a = [1, 2, [1, 2], {'foo': {'foo': 'bar'}}] %} | ||
17 | {{ a[2]|join(',') }} | ||
18 | {{ a[3]["foo"]|join(',') }} | ||
19 | |||
20 | {# works even if [] is used inside the array #} | ||
21 | {{ [foo[bar]]|join(',') }} | ||
22 | |||
23 | {# elements can be any expression #} | ||
24 | {{ ['foo'|upper, bar|upper, bar == foo]|join(',') }} | ||
25 | |||
26 | {# arrays can have a trailing , like in PHP #} | ||
27 | {{ | ||
28 | [ | ||
29 | 1, | ||
30 | 2, | ||
31 | ]|join(',') | ||
32 | }} | ||
33 | |||
34 | {# keys can be any expression #} | ||
35 | {% set a = 1 %} | ||
36 | {% set b = "foo" %} | ||
37 | {% set ary = { (a): 'a', (b): 'b', 'c': 'c', (a ~ b): 'd' } %} | ||
38 | {{ ary|keys|join(',') }} | ||
39 | {{ ary|join(',') }} | ||
40 | --DATA-- | ||
41 | return array('bar' => 'bar', 'foo' => array('bar' => 'bar')) | ||
42 | --EXPECT-- | ||
43 | 1,2 | ||
44 | foo,bar | ||
45 | 1,bar | ||
46 | 0,foo | ||
47 | |||
48 | 1,bar | ||
49 | 0,foo | ||
50 | |||
51 | 1,2 | ||
52 | bar | ||
53 | |||
54 | bar | ||
55 | |||
56 | FOO,BAR, | ||
57 | |||
58 | 1,2 | ||
59 | |||
60 | 1,foo,c,1foo | ||
61 | a,b,c,d | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/expressions/array_call.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/expressions/array_call.test new file mode 100644 index 00000000..f3df328f --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/expressions/array_call.test | |||
@@ -0,0 +1,14 @@ | |||
1 | --TEST-- | ||
2 | Twig supports method calls | ||
3 | --TEMPLATE-- | ||
4 | {{ items.foo }} | ||
5 | {{ items['foo'] }} | ||
6 | {{ items[foo] }} | ||
7 | {{ items[items[foo]] }} | ||
8 | --DATA-- | ||
9 | return array('foo' => 'bar', 'items' => array('foo' => 'bar', 'bar' => 'foo')) | ||
10 | --EXPECT-- | ||
11 | bar | ||
12 | bar | ||
13 | foo | ||
14 | bar | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/expressions/binary.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/expressions/binary.test new file mode 100644 index 00000000..f5e68456 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/expressions/binary.test | |||
@@ -0,0 +1,46 @@ | |||
1 | --TEST-- | ||
2 | Twig supports binary operations (+, -, *, /, ~, %, and, or) | ||
3 | --TEMPLATE-- | ||
4 | {{ 1 + 1 }} | ||
5 | {{ 2 - 1 }} | ||
6 | {{ 2 * 2 }} | ||
7 | {{ 2 / 2 }} | ||
8 | {{ 3 % 2 }} | ||
9 | {{ 1 and 1 }} | ||
10 | {{ 1 and 0 }} | ||
11 | {{ 0 and 1 }} | ||
12 | {{ 0 and 0 }} | ||
13 | {{ 1 or 1 }} | ||
14 | {{ 1 or 0 }} | ||
15 | {{ 0 or 1 }} | ||
16 | {{ 0 or 0 }} | ||
17 | {{ 0 or 1 and 0 }} | ||
18 | {{ 1 or 0 and 1 }} | ||
19 | {{ "foo" ~ "bar" }} | ||
20 | {{ foo ~ "bar" }} | ||
21 | {{ "foo" ~ bar }} | ||
22 | {{ foo ~ bar }} | ||
23 | {{ 20 // 7 }} | ||
24 | --DATA-- | ||
25 | return array('foo' => 'bar', 'bar' => 'foo') | ||
26 | --EXPECT-- | ||
27 | 2 | ||
28 | 1 | ||
29 | 4 | ||
30 | 1 | ||
31 | 1 | ||
32 | 1 | ||
33 | |||
34 | |||
35 | |||
36 | 1 | ||
37 | 1 | ||
38 | 1 | ||
39 | |||
40 | |||
41 | 1 | ||
42 | foobar | ||
43 | barbar | ||
44 | foofoo | ||
45 | barfoo | ||
46 | 2 | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/expressions/bitwise.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/expressions/bitwise.test new file mode 100644 index 00000000..7b56b761 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/expressions/bitwise.test | |||
@@ -0,0 +1,14 @@ | |||
1 | --TEST-- | ||
2 | Twig supports bitwise operations | ||
3 | --TEMPLATE-- | ||
4 | {{ 1 b-and 5 }} | ||
5 | {{ 1 b-or 5 }} | ||
6 | {{ 1 b-xor 5 }} | ||
7 | {{ (1 and 0 b-or 0) is sameas(1 and (0 b-or 0)) ? 'ok' : 'ko' }} | ||
8 | --DATA-- | ||
9 | return array() | ||
10 | --EXPECT-- | ||
11 | 1 | ||
12 | 5 | ||
13 | 4 | ||
14 | ok | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/expressions/comparison.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/expressions/comparison.test new file mode 100644 index 00000000..726b8507 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/expressions/comparison.test | |||
@@ -0,0 +1,14 @@ | |||
1 | --TEST-- | ||
2 | Twig supports comparison operators (==, !=, <, >, >=, <=) | ||
3 | --TEMPLATE-- | ||
4 | {{ 1 > 2 }}/{{ 1 > 1 }}/{{ 1 >= 2 }}/{{ 1 >= 1 }} | ||
5 | {{ 1 < 2 }}/{{ 1 < 1 }}/{{ 1 <= 2 }}/{{ 1 <= 1 }} | ||
6 | {{ 1 == 1 }}/{{ 1 == 2 }} | ||
7 | {{ 1 != 1 }}/{{ 1 != 2 }} | ||
8 | --DATA-- | ||
9 | return array() | ||
10 | --EXPECT-- | ||
11 | ///1 | ||
12 | 1//1/1 | ||
13 | 1/ | ||
14 | /1 | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/expressions/dotdot.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/expressions/dotdot.test new file mode 100644 index 00000000..9cd0676c --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/expressions/dotdot.test | |||
@@ -0,0 +1,20 @@ | |||
1 | --TEST-- | ||
2 | Twig supports the .. operator | ||
3 | --TEMPLATE-- | ||
4 | {% for i in 0..10 %}{{ i }} {% endfor %} | ||
5 | |||
6 | {% for letter in 'a'..'z' %}{{ letter }} {% endfor %} | ||
7 | |||
8 | {% for letter in 'a'|upper..'z'|upper %}{{ letter }} {% endfor %} | ||
9 | |||
10 | {% for i in foo[0]..foo[1] %}{{ i }} {% endfor %} | ||
11 | |||
12 | {% for i in 0 + 1 .. 10 - 1 %}{{ i }} {% endfor %} | ||
13 | --DATA-- | ||
14 | return array('foo' => array(1, 10)) | ||
15 | --EXPECT-- | ||
16 | 0 1 2 3 4 5 6 7 8 9 10 | ||
17 | a b c d e f g h i j k l m n o p q r s t u v w x y z | ||
18 | A B C D E F G H I J K L M N O P Q R S T U V W X Y Z | ||
19 | 1 2 3 4 5 6 7 8 9 10 | ||
20 | 1 2 3 4 5 6 7 8 9 | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/expressions/grouping.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/expressions/grouping.test new file mode 100644 index 00000000..79f8e0b0 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/expressions/grouping.test | |||
@@ -0,0 +1,8 @@ | |||
1 | --TEST-- | ||
2 | Twig supports grouping of expressions | ||
3 | --TEMPLATE-- | ||
4 | {{ (2 + 2) / 2 }} | ||
5 | --DATA-- | ||
6 | return array() | ||
7 | --EXPECT-- | ||
8 | 2 | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/expressions/literals.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/expressions/literals.test new file mode 100644 index 00000000..7ae3bae9 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/expressions/literals.test | |||
@@ -0,0 +1,22 @@ | |||
1 | --TEST-- | ||
2 | Twig supports literals | ||
3 | --TEMPLATE-- | ||
4 | 1 {{ true }} | ||
5 | 2 {{ TRUE }} | ||
6 | 3 {{ false }} | ||
7 | 4 {{ FALSE }} | ||
8 | 5 {{ none }} | ||
9 | 6 {{ NONE }} | ||
10 | 7 {{ null }} | ||
11 | 8 {{ NULL }} | ||
12 | --DATA-- | ||
13 | return array() | ||
14 | --EXPECT-- | ||
15 | 1 1 | ||
16 | 2 1 | ||
17 | 3 | ||
18 | 4 | ||
19 | 5 | ||
20 | 6 | ||
21 | 7 | ||
22 | 8 | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/expressions/magic_call.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/expressions/magic_call.test new file mode 100644 index 00000000..159db96f --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/expressions/magic_call.test | |||
@@ -0,0 +1,27 @@ | |||
1 | --TEST-- | ||
2 | Twig supports __call() for attributes | ||
3 | --TEMPLATE-- | ||
4 | {{ foo.foo }} | ||
5 | {{ foo.bar }} | ||
6 | --DATA-- | ||
7 | class TestClassForMagicCallAttributes | ||
8 | { | ||
9 | public function getBar() | ||
10 | { | ||
11 | return 'bar_from_getbar'; | ||
12 | } | ||
13 | |||
14 | public function __call($method, $arguments) | ||
15 | { | ||
16 | if ('foo' === $method) | ||
17 | { | ||
18 | return 'foo_from_call'; | ||
19 | } | ||
20 | |||
21 | return false; | ||
22 | } | ||
23 | } | ||
24 | return array('foo' => new TestClassForMagicCallAttributes()) | ||
25 | --EXPECT-- | ||
26 | foo_from_call | ||
27 | bar_from_getbar | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/expressions/method_call.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/expressions/method_call.test new file mode 100644 index 00000000..5f801e63 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/expressions/method_call.test | |||
@@ -0,0 +1,28 @@ | |||
1 | --TEST-- | ||
2 | Twig supports method calls | ||
3 | --TEMPLATE-- | ||
4 | {{ items.foo.foo }} | ||
5 | {{ items.foo.getFoo() }} | ||
6 | {{ items.foo.bar }} | ||
7 | {{ items.foo['bar'] }} | ||
8 | {{ items.foo.bar('a', 43) }} | ||
9 | {{ items.foo.bar(foo) }} | ||
10 | {{ items.foo.self.foo() }} | ||
11 | {{ items.foo.is }} | ||
12 | {{ items.foo.in }} | ||
13 | {{ items.foo.not }} | ||
14 | --DATA-- | ||
15 | return array('foo' => 'bar', 'items' => array('foo' => new TwigTestFoo(), 'bar' => 'foo')) | ||
16 | --CONFIG-- | ||
17 | return array('strict_variables' => false) | ||
18 | --EXPECT-- | ||
19 | foo | ||
20 | foo | ||
21 | bar | ||
22 | |||
23 | bar_a-43 | ||
24 | bar_bar | ||
25 | foo | ||
26 | is | ||
27 | in | ||
28 | not | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/expressions/postfix.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/expressions/postfix.test new file mode 100644 index 00000000..542c3504 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/expressions/postfix.test | |||
@@ -0,0 +1,22 @@ | |||
1 | --TEST-- | ||
2 | Twig parses postfix expressions | ||
3 | --TEMPLATE-- | ||
4 | {% import _self as macros %} | ||
5 | |||
6 | {% macro foo() %}foo{% endmacro %} | ||
7 | |||
8 | {{ 'a' }} | ||
9 | {{ 'a'|upper }} | ||
10 | {{ ('a')|upper }} | ||
11 | {{ -1|upper }} | ||
12 | {{ macros.foo() }} | ||
13 | {{ (macros).foo() }} | ||
14 | --DATA-- | ||
15 | return array(); | ||
16 | --EXPECT-- | ||
17 | a | ||
18 | A | ||
19 | A | ||
20 | -1 | ||
21 | foo | ||
22 | foo | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/expressions/strings.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/expressions/strings.test new file mode 100644 index 00000000..a9116613 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/expressions/strings.test | |||
@@ -0,0 +1,10 @@ | |||
1 | --TEST-- | ||
2 | Twig supports string interpolation | ||
3 | --TEMPLATE-- | ||
4 | {{ "foo #{"foo #{bar} baz"} baz" }} | ||
5 | {{ "foo #{bar}#{bar} baz" }} | ||
6 | --DATA-- | ||
7 | return array('bar' => 'BAR'); | ||
8 | --EXPECT-- | ||
9 | foo foo BAR baz baz | ||
10 | foo BARBAR baz | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/expressions/ternary_operator.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/expressions/ternary_operator.test new file mode 100644 index 00000000..0e6fa96e --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/expressions/ternary_operator.test | |||
@@ -0,0 +1,18 @@ | |||
1 | --TEST-- | ||
2 | Twig supports the ternary operator | ||
3 | --TEMPLATE-- | ||
4 | {{ 1 ? 'YES' : 'NO' }} | ||
5 | {{ 0 ? 'YES' : 'NO' }} | ||
6 | {{ 0 ? 'YES' : (1 ? 'YES1' : 'NO1') }} | ||
7 | {{ 0 ? 'YES' : (0 ? 'YES1' : 'NO1') }} | ||
8 | {{ 1 == 1 ? 'foo<br />':'' }} | ||
9 | {{ foo ~ (bar ? ('-' ~ bar) : '') }} | ||
10 | --DATA-- | ||
11 | return array('foo' => 'foo', 'bar' => 'bar') | ||
12 | --EXPECT-- | ||
13 | YES | ||
14 | NO | ||
15 | YES1 | ||
16 | NO1 | ||
17 | foo<br /> | ||
18 | foo-bar | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/expressions/ternary_operator_noelse.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/expressions/ternary_operator_noelse.test new file mode 100644 index 00000000..fdc660fc --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/expressions/ternary_operator_noelse.test | |||
@@ -0,0 +1,10 @@ | |||
1 | --TEST-- | ||
2 | Twig supports the ternary operator | ||
3 | --TEMPLATE-- | ||
4 | {{ 1 ? 'YES' }} | ||
5 | {{ 0 ? 'YES' }} | ||
6 | --DATA-- | ||
7 | return array() | ||
8 | --EXPECT-- | ||
9 | YES | ||
10 | |||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/expressions/ternary_operator_nothen.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/expressions/ternary_operator_nothen.test new file mode 100644 index 00000000..9057e837 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/expressions/ternary_operator_nothen.test | |||
@@ -0,0 +1,10 @@ | |||
1 | --TEST-- | ||
2 | Twig supports the ternary operator | ||
3 | --TEMPLATE-- | ||
4 | {{ 'YES' ?: 'NO' }} | ||
5 | {{ 0 ?: 'NO' }} | ||
6 | --DATA-- | ||
7 | return array() | ||
8 | --EXPECT-- | ||
9 | YES | ||
10 | NO | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/expressions/unary.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/expressions/unary.test new file mode 100644 index 00000000..b79219a2 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/expressions/unary.test | |||
@@ -0,0 +1,12 @@ | |||
1 | --TEST-- | ||
2 | Twig supports unary operators (not, -, +) | ||
3 | --TEMPLATE-- | ||
4 | {{ not 1 }}/{{ not 0 }} | ||
5 | {{ +1 + 1 }}/{{ -1 - 1 }} | ||
6 | {{ not (false or true) }} | ||
7 | --DATA-- | ||
8 | return array() | ||
9 | --EXPECT-- | ||
10 | /1 | ||
11 | 2/-2 | ||
12 | |||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/expressions/unary_precedence.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/expressions/unary_precedence.test new file mode 100644 index 00000000..cc6eef8d --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/expressions/unary_precedence.test | |||
@@ -0,0 +1,14 @@ | |||
1 | --TEST-- | ||
2 | Twig unary operators precedence | ||
3 | --TEMPLATE-- | ||
4 | {{ -1 - 1 }} | ||
5 | {{ -1 - -1 }} | ||
6 | {{ -1 * -1 }} | ||
7 | {{ 4 / -1 * 5 }} | ||
8 | --DATA-- | ||
9 | return array() | ||
10 | --EXPECT-- | ||
11 | -2 | ||
12 | 0 | ||
13 | 1 | ||
14 | -20 | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/abs.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/abs.test new file mode 100644 index 00000000..27e93fd6 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/abs.test | |||
@@ -0,0 +1,30 @@ | |||
1 | --TEST-- | ||
2 | "abs" filter | ||
3 | --TEMPLATE-- | ||
4 | {{ (-5.5)|abs }} | ||
5 | {{ (-5)|abs }} | ||
6 | {{ (-0)|abs }} | ||
7 | {{ 0|abs }} | ||
8 | {{ 5|abs }} | ||
9 | {{ 5.5|abs }} | ||
10 | {{ number1|abs }} | ||
11 | {{ number2|abs }} | ||
12 | {{ number3|abs }} | ||
13 | {{ number4|abs }} | ||
14 | {{ number5|abs }} | ||
15 | {{ number6|abs }} | ||
16 | --DATA-- | ||
17 | return array('number1' => -5.5, 'number2' => -5, 'number3' => -0, 'number4' => 0, 'number5' => 5, 'number6' => 5.5) | ||
18 | --EXPECT-- | ||
19 | 5.5 | ||
20 | 5 | ||
21 | 0 | ||
22 | 0 | ||
23 | 5 | ||
24 | 5.5 | ||
25 | 5.5 | ||
26 | 5 | ||
27 | 0 | ||
28 | 0 | ||
29 | 5 | ||
30 | 5.5 | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/batch.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/batch.test new file mode 100644 index 00000000..cb6de7f9 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/batch.test | |||
@@ -0,0 +1,31 @@ | |||
1 | --TEST-- | ||
2 | "batch" filter | ||
3 | --TEMPLATE-- | ||
4 | {% for row in items|batch(3) %} | ||
5 | <div class=row> | ||
6 | {% for column in row %} | ||
7 | <div class=item>{{ column }}</div> | ||
8 | {% endfor %} | ||
9 | </div> | ||
10 | {% endfor %} | ||
11 | --DATA-- | ||
12 | return array('items' => array('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j')) | ||
13 | --EXPECT-- | ||
14 | <div class=row> | ||
15 | <div class=item>a</div> | ||
16 | <div class=item>b</div> | ||
17 | <div class=item>c</div> | ||
18 | </div> | ||
19 | <div class=row> | ||
20 | <div class=item>d</div> | ||
21 | <div class=item>e</div> | ||
22 | <div class=item>f</div> | ||
23 | </div> | ||
24 | <div class=row> | ||
25 | <div class=item>g</div> | ||
26 | <div class=item>h</div> | ||
27 | <div class=item>i</div> | ||
28 | </div> | ||
29 | <div class=row> | ||
30 | <div class=item>j</div> | ||
31 | </div> | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/batch_float.php b/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/batch_float.php new file mode 100644 index 00000000..52de39cb --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/batch_float.php | |||
@@ -0,0 +1,31 @@ | |||
1 | --TEST-- | ||
2 | "batch" filter | ||
3 | --TEMPLATE-- | ||
4 | {% for row in items|batch(3.1) %} | ||
5 | <div class=row> | ||
6 | {% for column in row %} | ||
7 | <div class=item>{{ column }}</div> | ||
8 | {% endfor %} | ||
9 | </div> | ||
10 | {% endfor %} | ||
11 | --DATA-- | ||
12 | return array('items' => array('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j')) | ||
13 | --EXPECT-- | ||
14 | <div class=row> | ||
15 | <div class=item>a</div> | ||
16 | <div class=item>b</div> | ||
17 | <div class=item>c</div> | ||
18 | </div> | ||
19 | <div class=row> | ||
20 | <div class=item>d</div> | ||
21 | <div class=item>e</div> | ||
22 | <div class=item>f</div> | ||
23 | </div> | ||
24 | <div class=row> | ||
25 | <div class=item>g</div> | ||
26 | <div class=item>h</div> | ||
27 | <div class=item>i</div> | ||
28 | </div> | ||
29 | <div class=row> | ||
30 | <div class=item>j</div> | ||
31 | </div> | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/batch_with_empty_fill.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/batch_with_empty_fill.test new file mode 100644 index 00000000..af996f24 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/batch_with_empty_fill.test | |||
@@ -0,0 +1,37 @@ | |||
1 | --TEST-- | ||
2 | "batch" filter | ||
3 | --TEMPLATE-- | ||
4 | <table> | ||
5 | {% for row in items|batch(3, '') %} | ||
6 | <tr> | ||
7 | {% for column in row %} | ||
8 | <td>{{ column }}</td> | ||
9 | {% endfor %} | ||
10 | </tr> | ||
11 | {% endfor %} | ||
12 | </table> | ||
13 | --DATA-- | ||
14 | return array('items' => array('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j')) | ||
15 | --EXPECT-- | ||
16 | <table> | ||
17 | <tr> | ||
18 | <td>a</td> | ||
19 | <td>b</td> | ||
20 | <td>c</td> | ||
21 | </tr> | ||
22 | <tr> | ||
23 | <td>d</td> | ||
24 | <td>e</td> | ||
25 | <td>f</td> | ||
26 | </tr> | ||
27 | <tr> | ||
28 | <td>g</td> | ||
29 | <td>h</td> | ||
30 | <td>i</td> | ||
31 | </tr> | ||
32 | <tr> | ||
33 | <td>j</td> | ||
34 | <td></td> | ||
35 | <td></td> | ||
36 | </tr> | ||
37 | </table> | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/batch_with_fill.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/batch_with_fill.test new file mode 100644 index 00000000..746295f1 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/batch_with_fill.test | |||
@@ -0,0 +1,37 @@ | |||
1 | --TEST-- | ||
2 | "batch" filter | ||
3 | --TEMPLATE-- | ||
4 | <table> | ||
5 | {% for row in items|batch(3, 'fill') %} | ||
6 | <tr> | ||
7 | {% for column in row %} | ||
8 | <td>{{ column }}</td> | ||
9 | {% endfor %} | ||
10 | </tr> | ||
11 | {% endfor %} | ||
12 | </table> | ||
13 | --DATA-- | ||
14 | return array('items' => array('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j')) | ||
15 | --EXPECT-- | ||
16 | <table> | ||
17 | <tr> | ||
18 | <td>a</td> | ||
19 | <td>b</td> | ||
20 | <td>c</td> | ||
21 | </tr> | ||
22 | <tr> | ||
23 | <td>d</td> | ||
24 | <td>e</td> | ||
25 | <td>f</td> | ||
26 | </tr> | ||
27 | <tr> | ||
28 | <td>g</td> | ||
29 | <td>h</td> | ||
30 | <td>i</td> | ||
31 | </tr> | ||
32 | <tr> | ||
33 | <td>j</td> | ||
34 | <td>fill</td> | ||
35 | <td>fill</td> | ||
36 | </tr> | ||
37 | </table> | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/convert_encoding.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/convert_encoding.test new file mode 100644 index 00000000..380b04bb --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/convert_encoding.test | |||
@@ -0,0 +1,10 @@ | |||
1 | --TEST-- | ||
2 | "convert_encoding" filter | ||
3 | --CONDITION-- | ||
4 | function_exists('iconv') || function_exists('mb_convert_encoding') | ||
5 | --TEMPLATE-- | ||
6 | {{ "愛していますか?"|convert_encoding('ISO-2022-JP', 'UTF-8')|convert_encoding('UTF-8', 'ISO-2022-JP') }} | ||
7 | --DATA-- | ||
8 | return array() | ||
9 | --EXPECT-- | ||
10 | 愛していますか? | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/date.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/date.test new file mode 100644 index 00000000..d40bb04a --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/date.test | |||
@@ -0,0 +1,76 @@ | |||
1 | --TEST-- | ||
2 | "date" filter | ||
3 | --TEMPLATE-- | ||
4 | {{ date1|date }} | ||
5 | {{ date1|date('d/m/Y') }} | ||
6 | {{ date1|date('d/m/Y H:i:s', 'Asia/Hong_Kong') }} | ||
7 | {{ date1|date('d/m/Y H:i:s P', 'Asia/Hong_Kong') }} | ||
8 | {{ date1|date('d/m/Y H:i:s P', 'America/Chicago') }} | ||
9 | {{ date1|date('e') }} | ||
10 | {{ date1|date('d/m/Y H:i:s') }} | ||
11 | |||
12 | {{ date2|date }} | ||
13 | {{ date2|date('d/m/Y') }} | ||
14 | {{ date2|date('d/m/Y H:i:s', 'Asia/Hong_Kong') }} | ||
15 | {{ date2|date('d/m/Y H:i:s', timezone1) }} | ||
16 | {{ date2|date('d/m/Y H:i:s') }} | ||
17 | |||
18 | {{ date3|date }} | ||
19 | {{ date3|date('d/m/Y') }} | ||
20 | |||
21 | {{ date4|date }} | ||
22 | {{ date4|date('d/m/Y') }} | ||
23 | |||
24 | {{ date5|date }} | ||
25 | {{ date5|date('d/m/Y') }} | ||
26 | |||
27 | {{ date6|date('d/m/Y H:i:s P', 'Europe/Paris') }} | ||
28 | {{ date6|date('d/m/Y H:i:s P', 'Asia/Hong_Kong') }} | ||
29 | {{ date6|date('d/m/Y H:i:s P', false) }} | ||
30 | {{ date6|date('e', 'Europe/Paris') }} | ||
31 | {{ date6|date('e', false) }} | ||
32 | |||
33 | {{ date7|date }} | ||
34 | --DATA-- | ||
35 | date_default_timezone_set('Europe/Paris'); | ||
36 | return array( | ||
37 | 'date1' => mktime(13, 45, 0, 10, 4, 2010), | ||
38 | 'date2' => new DateTime('2010-10-04 13:45'), | ||
39 | 'date3' => '2010-10-04 13:45', | ||
40 | 'date4' => 1286199900, // DateTime::createFromFormat('Y-m-d H:i', '2010-10-04 13:45', new DateTimeZone('UTC'))->getTimestamp() -- A unixtimestamp is always GMT | ||
41 | 'date5' => -189291360, // DateTime::createFromFormat('Y-m-d H:i', '1964-01-02 03:04', new DateTimeZone('UTC'))->getTimestamp(), | ||
42 | 'date6' => new DateTime('2010-10-04 13:45', new DateTimeZone('America/New_York')), | ||
43 | 'date7' => '2010-01-28T15:00:00+05:00', | ||
44 | 'timezone1' => new DateTimeZone('America/New_York'), | ||
45 | ) | ||
46 | --EXPECT-- | ||
47 | October 4, 2010 13:45 | ||
48 | 04/10/2010 | ||
49 | 04/10/2010 19:45:00 | ||
50 | 04/10/2010 19:45:00 +08:00 | ||
51 | 04/10/2010 06:45:00 -05:00 | ||
52 | Europe/Paris | ||
53 | 04/10/2010 13:45:00 | ||
54 | |||
55 | October 4, 2010 13:45 | ||
56 | 04/10/2010 | ||
57 | 04/10/2010 19:45:00 | ||
58 | 04/10/2010 07:45:00 | ||
59 | 04/10/2010 13:45:00 | ||
60 | |||
61 | October 4, 2010 13:45 | ||
62 | 04/10/2010 | ||
63 | |||
64 | October 4, 2010 15:45 | ||
65 | 04/10/2010 | ||
66 | |||
67 | January 2, 1964 04:04 | ||
68 | 02/01/1964 | ||
69 | |||
70 | 04/10/2010 19:45:00 +02:00 | ||
71 | 05/10/2010 01:45:00 +08:00 | ||
72 | 04/10/2010 13:45:00 -04:00 | ||
73 | Europe/Paris | ||
74 | America/New_York | ||
75 | |||
76 | January 28, 2010 11:00 | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/date_default_format.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/date_default_format.test new file mode 100644 index 00000000..11a1ef4b --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/date_default_format.test | |||
@@ -0,0 +1,14 @@ | |||
1 | --TEST-- | ||
2 | "date" filter | ||
3 | --TEMPLATE-- | ||
4 | {{ date1|date }} | ||
5 | {{ date1|date('d/m/Y') }} | ||
6 | --DATA-- | ||
7 | date_default_timezone_set('UTC'); | ||
8 | $twig->getExtension('core')->setDateFormat('Y-m-d', '%d days %h hours'); | ||
9 | return array( | ||
10 | 'date1' => mktime(13, 45, 0, 10, 4, 2010), | ||
11 | ) | ||
12 | --EXPECT-- | ||
13 | 2010-10-04 | ||
14 | 04/10/2010 | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/date_default_format_interval.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/date_default_format_interval.test new file mode 100644 index 00000000..e6d3707d --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/date_default_format_interval.test | |||
@@ -0,0 +1,16 @@ | |||
1 | --TEST-- | ||
2 | "date" filter (interval support as of PHP 5.3) | ||
3 | --CONDITION-- | ||
4 | version_compare(phpversion(), '5.3.0', '>=') | ||
5 | --TEMPLATE-- | ||
6 | {{ date2|date }} | ||
7 | {{ date2|date('%d days') }} | ||
8 | --DATA-- | ||
9 | date_default_timezone_set('UTC'); | ||
10 | $twig->getExtension('core')->setDateFormat('Y-m-d', '%d days %h hours'); | ||
11 | return array( | ||
12 | 'date2' => new DateInterval('P2D'), | ||
13 | ) | ||
14 | --EXPECT-- | ||
15 | 2 days 0 hours | ||
16 | 2 days | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/date_interval.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/date_interval.test new file mode 100644 index 00000000..0c8c6f1a --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/date_interval.test | |||
@@ -0,0 +1,19 @@ | |||
1 | --TEST-- | ||
2 | "date" filter (interval support as of PHP 5.3) | ||
3 | --CONDITION-- | ||
4 | version_compare(phpversion(), '5.3.0', '>=') | ||
5 | --TEMPLATE-- | ||
6 | {{ date1|date }} | ||
7 | {{ date1|date('%d days %h hours') }} | ||
8 | {{ date1|date('%d days %h hours', timezone1) }} | ||
9 | --DATA-- | ||
10 | date_default_timezone_set('UTC'); | ||
11 | return array( | ||
12 | 'date1' => new DateInterval('P2D'), | ||
13 | // This should have no effect on DateInterval formatting | ||
14 | 'timezone1' => new DateTimeZone('America/New_York'), | ||
15 | ) | ||
16 | --EXPECT-- | ||
17 | 2 days | ||
18 | 2 days 0 hours | ||
19 | 2 days 0 hours | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/date_modify.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/date_modify.test new file mode 100644 index 00000000..53d3a69c --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/date_modify.test | |||
@@ -0,0 +1,14 @@ | |||
1 | --TEST-- | ||
2 | "date_modify" filter | ||
3 | --TEMPLATE-- | ||
4 | {{ date1|date_modify('-1day')|date('Y-m-d H:i:s') }} | ||
5 | {{ date2|date_modify('-1day')|date('Y-m-d H:i:s') }} | ||
6 | --DATA-- | ||
7 | date_default_timezone_set('UTC'); | ||
8 | return array( | ||
9 | 'date1' => '2010-10-04 13:45', | ||
10 | 'date2' => new DateTime('2010-10-04 13:45'), | ||
11 | ) | ||
12 | --EXPECT-- | ||
13 | 2010-10-03 13:45:00 | ||
14 | 2010-10-03 13:45:00 | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/date_namedargs.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/date_namedargs.test new file mode 100644 index 00000000..4ecde8a1 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/date_namedargs.test | |||
@@ -0,0 +1,13 @@ | |||
1 | --TEST-- | ||
2 | "date" filter | ||
3 | --TEMPLATE-- | ||
4 | {{ date|date(format='d/m/Y H:i:s P', timezone='America/Chicago') }} | ||
5 | {{ date|date(timezone='America/Chicago', format='d/m/Y H:i:s P') }} | ||
6 | {{ date|date('d/m/Y H:i:s P', timezone='America/Chicago') }} | ||
7 | --DATA-- | ||
8 | date_default_timezone_set('UTC'); | ||
9 | return array('date' => mktime(13, 45, 0, 10, 4, 2010)) | ||
10 | --EXPECT-- | ||
11 | 04/10/2010 08:45:00 -05:00 | ||
12 | 04/10/2010 08:45:00 -05:00 | ||
13 | 04/10/2010 08:45:00 -05:00 | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/default.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/default.test new file mode 100644 index 00000000..0e4404b1 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/default.test | |||
@@ -0,0 +1,150 @@ | |||
1 | --TEST-- | ||
2 | "default" filter | ||
3 | --TEMPLATE-- | ||
4 | Variable: | ||
5 | {{ definedVar |default('default') is sameas('default') ? 'ko' : 'ok' }} | ||
6 | {{ zeroVar |default('default') is sameas('default') ? 'ko' : 'ok' }} | ||
7 | {{ emptyVar |default('default') is sameas('default') ? 'ok' : 'ko' }} | ||
8 | {{ nullVar |default('default') is sameas('default') ? 'ok' : 'ko' }} | ||
9 | {{ undefinedVar |default('default') is sameas('default') ? 'ok' : 'ko' }} | ||
10 | Array access: | ||
11 | {{ nested.definedVar |default('default') is sameas('default') ? 'ko' : 'ok' }} | ||
12 | {{ nested['definedVar'] |default('default') is sameas('default') ? 'ko' : 'ok' }} | ||
13 | {{ nested.zeroVar |default('default') is sameas('default') ? 'ko' : 'ok' }} | ||
14 | {{ nested.emptyVar |default('default') is sameas('default') ? 'ok' : 'ko' }} | ||
15 | {{ nested.nullVar |default('default') is sameas('default') ? 'ok' : 'ko' }} | ||
16 | {{ nested.undefinedVar |default('default') is sameas('default') ? 'ok' : 'ko' }} | ||
17 | {{ nested['undefinedVar'] |default('default') is sameas('default') ? 'ok' : 'ko' }} | ||
18 | {{ undefinedVar.foo |default('default') is sameas('default') ? 'ok' : 'ko' }} | ||
19 | Plain values: | ||
20 | {{ 'defined' |default('default') is sameas('default') ? 'ko' : 'ok' }} | ||
21 | {{ 0 |default('default') is sameas('default') ? 'ko' : 'ok' }} | ||
22 | {{ '' |default('default') is sameas('default') ? 'ok' : 'ko' }} | ||
23 | {{ null |default('default') is sameas('default') ? 'ok' : 'ko' }} | ||
24 | Precedence: | ||
25 | {{ 'o' ~ nullVar |default('k') }} | ||
26 | {{ 'o' ~ nested.nullVar |default('k') }} | ||
27 | Object methods: | ||
28 | {{ object.foo |default('default') is sameas('default') ? 'ko' : 'ok' }} | ||
29 | {{ object.undefinedMethod |default('default') is sameas('default') ? 'ok' : 'ko' }} | ||
30 | {{ object.getFoo() |default('default') is sameas('default') ? 'ko' : 'ok' }} | ||
31 | {{ object.getFoo('a') |default('default') is sameas('default') ? 'ko' : 'ok' }} | ||
32 | {{ object.undefinedMethod() |default('default') is sameas('default') ? 'ok' : 'ko' }} | ||
33 | {{ object.undefinedMethod('a') |default('default') is sameas('default') ? 'ok' : 'ko' }} | ||
34 | Deep nested: | ||
35 | {{ nested.undefinedVar.foo.bar |default('default') is sameas('default') ? 'ok' : 'ko' }} | ||
36 | {{ nested.definedArray.0 |default('default') is sameas('default') ? 'ko' : 'ok' }} | ||
37 | {{ nested['definedArray'][0] |default('default') is sameas('default') ? 'ko' : 'ok' }} | ||
38 | {{ object.self.foo |default('default') is sameas('default') ? 'ko' : 'ok' }} | ||
39 | {{ object.self.undefinedMethod |default('default') is sameas('default') ? 'ok' : 'ko' }} | ||
40 | {{ object.undefinedMethod.self |default('default') is sameas('default') ? 'ok' : 'ko' }} | ||
41 | --DATA-- | ||
42 | return array( | ||
43 | 'definedVar' => 'defined', | ||
44 | 'zeroVar' => 0, | ||
45 | 'emptyVar' => '', | ||
46 | 'nullVar' => null, | ||
47 | 'nested' => array( | ||
48 | 'definedVar' => 'defined', | ||
49 | 'zeroVar' => 0, | ||
50 | 'emptyVar' => '', | ||
51 | 'nullVar' => null, | ||
52 | 'definedArray' => array(0), | ||
53 | ), | ||
54 | 'object' => new TwigTestFoo(), | ||
55 | ) | ||
56 | --CONFIG-- | ||
57 | return array('strict_variables' => false) | ||
58 | --EXPECT-- | ||
59 | Variable: | ||
60 | ok | ||
61 | ok | ||
62 | ok | ||
63 | ok | ||
64 | ok | ||
65 | Array access: | ||
66 | ok | ||
67 | ok | ||
68 | ok | ||
69 | ok | ||
70 | ok | ||
71 | ok | ||
72 | ok | ||
73 | ok | ||
74 | Plain values: | ||
75 | ok | ||
76 | ok | ||
77 | ok | ||
78 | ok | ||
79 | Precedence: | ||
80 | ok | ||
81 | ok | ||
82 | Object methods: | ||
83 | ok | ||
84 | ok | ||
85 | ok | ||
86 | ok | ||
87 | ok | ||
88 | ok | ||
89 | Deep nested: | ||
90 | ok | ||
91 | ok | ||
92 | ok | ||
93 | ok | ||
94 | ok | ||
95 | ok | ||
96 | --DATA-- | ||
97 | return array( | ||
98 | 'definedVar' => 'defined', | ||
99 | 'zeroVar' => 0, | ||
100 | 'emptyVar' => '', | ||
101 | 'nullVar' => null, | ||
102 | 'nested' => array( | ||
103 | 'definedVar' => 'defined', | ||
104 | 'zeroVar' => 0, | ||
105 | 'emptyVar' => '', | ||
106 | 'nullVar' => null, | ||
107 | 'definedArray' => array(0), | ||
108 | ), | ||
109 | 'object' => new TwigTestFoo(), | ||
110 | ) | ||
111 | --CONFIG-- | ||
112 | return array('strict_variables' => true) | ||
113 | --EXPECT-- | ||
114 | Variable: | ||
115 | ok | ||
116 | ok | ||
117 | ok | ||
118 | ok | ||
119 | ok | ||
120 | Array access: | ||
121 | ok | ||
122 | ok | ||
123 | ok | ||
124 | ok | ||
125 | ok | ||
126 | ok | ||
127 | ok | ||
128 | ok | ||
129 | Plain values: | ||
130 | ok | ||
131 | ok | ||
132 | ok | ||
133 | ok | ||
134 | Precedence: | ||
135 | ok | ||
136 | ok | ||
137 | Object methods: | ||
138 | ok | ||
139 | ok | ||
140 | ok | ||
141 | ok | ||
142 | ok | ||
143 | ok | ||
144 | Deep nested: | ||
145 | ok | ||
146 | ok | ||
147 | ok | ||
148 | ok | ||
149 | ok | ||
150 | ok | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/dynamic_filter.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/dynamic_filter.test new file mode 100644 index 00000000..93c5913f --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/dynamic_filter.test | |||
@@ -0,0 +1,10 @@ | |||
1 | --TEST-- | ||
2 | dynamic filter | ||
3 | --TEMPLATE-- | ||
4 | {{ 'bar'|foo_path }} | ||
5 | {{ 'bar'|a_foo_b_bar }} | ||
6 | --DATA-- | ||
7 | return array() | ||
8 | --EXPECT-- | ||
9 | foo/bar | ||
10 | a/b/bar | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/escape.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/escape.test new file mode 100644 index 00000000..a606c106 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/escape.test | |||
@@ -0,0 +1,8 @@ | |||
1 | --TEST-- | ||
2 | "escape" filter | ||
3 | --TEMPLATE-- | ||
4 | {{ "foo <br />"|e }} | ||
5 | --DATA-- | ||
6 | return array() | ||
7 | --EXPECT-- | ||
8 | foo <br /> | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/escape_non_supported_charset.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/escape_non_supported_charset.test new file mode 100644 index 00000000..bba26a0d --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/escape_non_supported_charset.test | |||
@@ -0,0 +1,8 @@ | |||
1 | --TEST-- | ||
2 | "escape" filter | ||
3 | --TEMPLATE-- | ||
4 | {{ "愛していますか? <br />"|e }} | ||
5 | --DATA-- | ||
6 | return array() | ||
7 | --EXPECT-- | ||
8 | 愛していますか? <br /> | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/first.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/first.test new file mode 100644 index 00000000..853465b6 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/first.test | |||
@@ -0,0 +1,14 @@ | |||
1 | --TEST-- | ||
2 | "first" filter | ||
3 | --TEMPLATE-- | ||
4 | {{ [1, 2, 3, 4]|first }} | ||
5 | {{ {a: 1, b: 2, c: 3, d: 4}|first }} | ||
6 | {{ '1234'|first }} | ||
7 | {{ arr|first }} | ||
8 | --DATA-- | ||
9 | return array('arr' => new ArrayObject(array(1, 2, 3, 4))) | ||
10 | --EXPECT-- | ||
11 | 1 | ||
12 | 1 | ||
13 | 1 | ||
14 | 1 | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/force_escape.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/force_escape.test new file mode 100644 index 00000000..85a9b717 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/force_escape.test | |||
@@ -0,0 +1,18 @@ | |||
1 | --TEST-- | ||
2 | "escape" filter | ||
3 | --TEMPLATE-- | ||
4 | {% set foo %} | ||
5 | foo<br /> | ||
6 | {% endset %} | ||
7 | |||
8 | {{ foo|e('html') -}} | ||
9 | {{ foo|e('js') }} | ||
10 | {% autoescape true %} | ||
11 | {{ foo }} | ||
12 | {% endautoescape %} | ||
13 | --DATA-- | ||
14 | return array() | ||
15 | --EXPECT-- | ||
16 | foo<br /> | ||
17 | \x20\x20\x20\x20foo\x3Cbr\x20\x2F\x3E\x0A | ||
18 | foo<br /> | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/format.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/format.test new file mode 100644 index 00000000..97221ff8 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/format.test | |||
@@ -0,0 +1,8 @@ | |||
1 | --TEST-- | ||
2 | "format" filter | ||
3 | --TEMPLATE-- | ||
4 | {{ string|format(foo, 3) }} | ||
5 | --DATA-- | ||
6 | return array('string' => '%s/%d', 'foo' => 'bar') | ||
7 | --EXPECT-- | ||
8 | bar/3 | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/join.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/join.test new file mode 100644 index 00000000..b342c174 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/join.test | |||
@@ -0,0 +1,12 @@ | |||
1 | --TEST-- | ||
2 | "join" filter | ||
3 | --TEMPLATE-- | ||
4 | {{ ["foo", "bar"]|join(', ') }} | ||
5 | {{ foo|join(', ') }} | ||
6 | {{ bar|join(', ') }} | ||
7 | --DATA-- | ||
8 | return array('foo' => new TwigTestFoo(), 'bar' => new ArrayObject(array(3, 4))) | ||
9 | --EXPECT-- | ||
10 | foo, bar | ||
11 | 1, 2 | ||
12 | 3, 4 | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/json_encode.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/json_encode.test new file mode 100644 index 00000000..1738d40c --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/json_encode.test | |||
@@ -0,0 +1,12 @@ | |||
1 | --TEST-- | ||
2 | "json_encode" filter | ||
3 | --TEMPLATE-- | ||
4 | {{ "foo"|json_encode|raw }} | ||
5 | {{ foo|json_encode|raw }} | ||
6 | {{ [foo, "foo"]|json_encode|raw }} | ||
7 | --DATA-- | ||
8 | return array('foo' => new Twig_Markup('foo', 'UTF-8')) | ||
9 | --EXPECT-- | ||
10 | "foo" | ||
11 | "foo" | ||
12 | ["foo","foo"] | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/last.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/last.test new file mode 100644 index 00000000..ca3ac0cf --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/last.test | |||
@@ -0,0 +1,14 @@ | |||
1 | --TEST-- | ||
2 | "last" filter | ||
3 | --TEMPLATE-- | ||
4 | {{ [1, 2, 3, 4]|last }} | ||
5 | {{ {a: 1, b: 2, c: 3, d: 4}|last }} | ||
6 | {{ '1234'|last }} | ||
7 | {{ arr|last }} | ||
8 | --DATA-- | ||
9 | return array('arr' => new ArrayObject(array(1, 2, 3, 4))) | ||
10 | --EXPECT-- | ||
11 | 4 | ||
12 | 4 | ||
13 | 4 | ||
14 | 4 | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/length.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/length.test new file mode 100644 index 00000000..3347474d --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/length.test | |||
@@ -0,0 +1,14 @@ | |||
1 | --TEST-- | ||
2 | "length" filter | ||
3 | --TEMPLATE-- | ||
4 | {{ array|length }} | ||
5 | {{ string|length }} | ||
6 | {{ number|length }} | ||
7 | {{ markup|length }} | ||
8 | --DATA-- | ||
9 | return array('array' => array(1, 4), 'string' => 'foo', 'number' => 1000, 'markup' => new Twig_Markup('foo', 'UTF-8')) | ||
10 | --EXPECT-- | ||
11 | 2 | ||
12 | 3 | ||
13 | 4 | ||
14 | 3 | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/length_utf8.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/length_utf8.test new file mode 100644 index 00000000..5d5e2436 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/length_utf8.test | |||
@@ -0,0 +1,12 @@ | |||
1 | --TEST-- | ||
2 | "length" filter | ||
3 | --CONDITION-- | ||
4 | function_exists('mb_get_info') | ||
5 | --TEMPLATE-- | ||
6 | {{ string|length }} | ||
7 | {{ markup|length }} | ||
8 | --DATA-- | ||
9 | return array('string' => 'été', 'markup' => new Twig_Markup('foo', 'UTF-8')) | ||
10 | --EXPECT-- | ||
11 | 3 | ||
12 | 3 | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/merge.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/merge.test new file mode 100644 index 00000000..2bd3d4c0 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/merge.test | |||
@@ -0,0 +1,16 @@ | |||
1 | --TEST-- | ||
2 | "merge" filter | ||
3 | --TEMPLATE-- | ||
4 | {{ items|merge({'bar': 'foo'})|join }} | ||
5 | {{ items|merge({'bar': 'foo'})|keys|join }} | ||
6 | {{ {'bar': 'foo'}|merge(items)|join }} | ||
7 | {{ {'bar': 'foo'}|merge(items)|keys|join }} | ||
8 | {{ numerics|merge([4, 5, 6])|join }} | ||
9 | --DATA-- | ||
10 | return array('items' => array('foo' => 'bar'), 'numerics' => array(1, 2, 3)) | ||
11 | --EXPECT-- | ||
12 | barfoo | ||
13 | foobar | ||
14 | foobar | ||
15 | barfoo | ||
16 | 123456 | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/nl2br.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/nl2br.test new file mode 100644 index 00000000..6545a9bb --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/nl2br.test | |||
@@ -0,0 +1,14 @@ | |||
1 | --TEST-- | ||
2 | "nl2br" filter | ||
3 | --TEMPLATE-- | ||
4 | {{ "I like Twig.\nYou will like it too.\n\nEverybody like it!"|nl2br }} | ||
5 | {{ text|nl2br }} | ||
6 | --DATA-- | ||
7 | return array('text' => "If you have some <strong>HTML</strong>\nit will be escaped.") | ||
8 | --EXPECT-- | ||
9 | I like Twig.<br /> | ||
10 | You will like it too.<br /> | ||
11 | <br /> | ||
12 | Everybody like it! | ||
13 | If you have some <strong>HTML</strong><br /> | ||
14 | it will be escaped. | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/number_format.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/number_format.test new file mode 100644 index 00000000..639a8659 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/number_format.test | |||
@@ -0,0 +1,18 @@ | |||
1 | --TEST-- | ||
2 | "number_format" filter | ||
3 | --TEMPLATE-- | ||
4 | {{ 20|number_format }} | ||
5 | {{ 20.25|number_format }} | ||
6 | {{ 20.25|number_format(2) }} | ||
7 | {{ 20.25|number_format(2, ',') }} | ||
8 | {{ 1020.25|number_format(2, ',') }} | ||
9 | {{ 1020.25|number_format(2, ',', '.') }} | ||
10 | --DATA-- | ||
11 | return array(); | ||
12 | --EXPECT-- | ||
13 | 20 | ||
14 | 20 | ||
15 | 20.25 | ||
16 | 20,25 | ||
17 | 1,020,25 | ||
18 | 1.020,25 | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/number_format_default.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/number_format_default.test new file mode 100644 index 00000000..c6903cc7 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/number_format_default.test | |||
@@ -0,0 +1,21 @@ | |||
1 | --TEST-- | ||
2 | "number_format" filter with defaults. | ||
3 | --TEMPLATE-- | ||
4 | {{ 20|number_format }} | ||
5 | {{ 20.25|number_format }} | ||
6 | {{ 20.25|number_format(1) }} | ||
7 | {{ 20.25|number_format(2, ',') }} | ||
8 | {{ 1020.25|number_format }} | ||
9 | {{ 1020.25|number_format(2, ',') }} | ||
10 | {{ 1020.25|number_format(2, ',', '.') }} | ||
11 | --DATA-- | ||
12 | $twig->getExtension('core')->setNumberFormat(2, '!', '='); | ||
13 | return array(); | ||
14 | --EXPECT-- | ||
15 | 20!00 | ||
16 | 20!25 | ||
17 | 20!3 | ||
18 | 20,25 | ||
19 | 1=020!25 | ||
20 | 1=020,25 | ||
21 | 1.020,25 | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/replace.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/replace.test new file mode 100644 index 00000000..4021660b --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/replace.test | |||
@@ -0,0 +1,8 @@ | |||
1 | --TEST-- | ||
2 | "replace" filter | ||
3 | --TEMPLATE-- | ||
4 | {{ "I like %this% and %that%."|replace({'%this%': "foo", '%that%': "bar"}) }} | ||
5 | --DATA-- | ||
6 | return array() | ||
7 | --EXPECT-- | ||
8 | I like foo and bar. | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/reverse.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/reverse.test new file mode 100644 index 00000000..7948ac45 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/reverse.test | |||
@@ -0,0 +1,18 @@ | |||
1 | --TEST-- | ||
2 | "reverse" filter | ||
3 | --TEMPLATE-- | ||
4 | {{ [1, 2, 3, 4]|reverse|join('') }} | ||
5 | {{ '1234évènement'|reverse }} | ||
6 | {{ arr|reverse|join('') }} | ||
7 | {{ {'a': 'c', 'b': 'a'}|reverse()|join(',') }} | ||
8 | {{ {'a': 'c', 'b': 'a'}|reverse(preserveKeys=true)|join(glue=',') }} | ||
9 | {{ {'a': 'c', 'b': 'a'}|reverse(preserve_keys=true)|join(glue=',') }} | ||
10 | --DATA-- | ||
11 | return array('arr' => new ArrayObject(array(1, 2, 3, 4))) | ||
12 | --EXPECT-- | ||
13 | 4321 | ||
14 | tnemenèvé4321 | ||
15 | 4321 | ||
16 | a,c | ||
17 | a,c | ||
18 | a,c | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/slice.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/slice.test new file mode 100644 index 00000000..b37ad651 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/slice.test | |||
@@ -0,0 +1,42 @@ | |||
1 | --TEST-- | ||
2 | "slice" filter | ||
3 | --TEMPLATE-- | ||
4 | {{ [1, 2, 3, 4][1:2]|join('') }} | ||
5 | {{ {a: 1, b: 2, c: 3, d: 4}[1:2]|join('') }} | ||
6 | {{ [1, 2, 3, 4][start:length]|join('') }} | ||
7 | {{ [1, 2, 3, 4]|slice(1, 2)|join('') }} | ||
8 | {{ [1, 2, 3, 4]|slice(1, 2)|keys|join('') }} | ||
9 | {{ [1, 2, 3, 4]|slice(1, 2, true)|keys|join('') }} | ||
10 | {{ {a: 1, b: 2, c: 3, d: 4}|slice(1, 2)|join('') }} | ||
11 | {{ {a: 1, b: 2, c: 3, d: 4}|slice(1, 2)|keys|join('') }} | ||
12 | {{ '1234'|slice(1, 2) }} | ||
13 | {{ '1234'[1:2] }} | ||
14 | {{ arr|slice(1, 2)|join('') }} | ||
15 | {{ arr[1:2]|join('') }} | ||
16 | |||
17 | {{ [1, 2, 3, 4]|slice(1)|join('') }} | ||
18 | {{ [1, 2, 3, 4][1:]|join('') }} | ||
19 | {{ '1234'|slice(1) }} | ||
20 | {{ '1234'[1:] }} | ||
21 | {{ '1234'[:1] }} | ||
22 | --DATA-- | ||
23 | return array('start' => 1, 'length' => 2, 'arr' => new ArrayObject(array(1, 2, 3, 4))) | ||
24 | --EXPECT-- | ||
25 | 23 | ||
26 | 23 | ||
27 | 23 | ||
28 | 23 | ||
29 | 01 | ||
30 | 12 | ||
31 | 23 | ||
32 | bc | ||
33 | 23 | ||
34 | 23 | ||
35 | 23 | ||
36 | 23 | ||
37 | |||
38 | 234 | ||
39 | 234 | ||
40 | 234 | ||
41 | 234 | ||
42 | 1 | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/sort.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/sort.test new file mode 100644 index 00000000..21d575f1 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/sort.test | |||
@@ -0,0 +1,10 @@ | |||
1 | --TEST-- | ||
2 | "sort" filter | ||
3 | --TEMPLATE-- | ||
4 | {{ array1|sort|join }} | ||
5 | {{ array2|sort|join }} | ||
6 | --DATA-- | ||
7 | return array('array1' => array(4, 1), 'array2' => array('foo', 'bar')) | ||
8 | --EXPECT-- | ||
9 | 14 | ||
10 | barfoo | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/special_chars.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/special_chars.test new file mode 100644 index 00000000..dbaf7dc9 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/special_chars.test | |||
@@ -0,0 +1,8 @@ | |||
1 | --TEST-- | ||
2 | "§" custom filter | ||
3 | --TEMPLATE-- | ||
4 | {{ 'foo'|§ }} | ||
5 | --DATA-- | ||
6 | return array() | ||
7 | --EXPECT-- | ||
8 | §foo§ | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/split.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/split.test new file mode 100644 index 00000000..ce8ec9ce --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/split.test | |||
@@ -0,0 +1,18 @@ | |||
1 | --TEST-- | ||
2 | "split" filter | ||
3 | --TEMPLATE-- | ||
4 | {{ "one,two,three,four,five"|split(',')|join('-') }} | ||
5 | {{ foo|split(',')|join('-') }} | ||
6 | {{ foo|split(',', 3)|join('-') }} | ||
7 | {{ baz|split('')|join('-') }} | ||
8 | {{ baz|split('', 2)|join('-') }} | ||
9 | {{ foo|split(',', -2)|join('-') }} | ||
10 | --DATA-- | ||
11 | return array('foo' => "one,two,three,four,five", 'baz' => '12345',) | ||
12 | --EXPECT-- | ||
13 | one-two-three-four-five | ||
14 | one-two-three-four-five | ||
15 | one-two-three,four,five | ||
16 | 1-2-3-4-5 | ||
17 | 12-34-5 | ||
18 | one-two-three \ No newline at end of file | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/trim.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/trim.test new file mode 100644 index 00000000..31920625 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/trim.test | |||
@@ -0,0 +1,12 @@ | |||
1 | --TEST-- | ||
2 | "trim" filter | ||
3 | --TEMPLATE-- | ||
4 | {{ " I like Twig. "|trim }} | ||
5 | {{ text|trim }} | ||
6 | {{ " foo/"|trim("/") }} | ||
7 | --DATA-- | ||
8 | return array('text' => " If you have some <strong>HTML</strong> it will be escaped. ") | ||
9 | --EXPECT-- | ||
10 | I like Twig. | ||
11 | If you have some <strong>HTML</strong> it will be escaped. | ||
12 | foo | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/urlencode.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/urlencode.test new file mode 100644 index 00000000..de956e7a --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/urlencode.test | |||
@@ -0,0 +1,12 @@ | |||
1 | --TEST-- | ||
2 | "url_encode" filter | ||
3 | --TEMPLATE-- | ||
4 | {{ {foo: "bar", number: 3, "spéßi%l": "e%c0d@d", "spa ce": ""}|url_encode }} | ||
5 | {{ {foo: "bar", number: 3, "spéßi%l": "e%c0d@d", "spa ce": ""}|url_encode|raw }} | ||
6 | {{ {}|url_encode|default("default") }} | ||
7 | --DATA-- | ||
8 | return array() | ||
9 | --EXPECT-- | ||
10 | foo=bar&number=3&sp%C3%A9%C3%9Fi%25l=e%25c0d%40d&spa+ce= | ||
11 | foo=bar&number=3&sp%C3%A9%C3%9Fi%25l=e%25c0d%40d&spa+ce= | ||
12 | default | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/attribute.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/attribute.test new file mode 100644 index 00000000..16ae1e8b --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/attribute.test | |||
@@ -0,0 +1,12 @@ | |||
1 | --TEST-- | ||
2 | "attribute" function | ||
3 | --TEMPLATE-- | ||
4 | {{ attribute(obj, method) }} | ||
5 | {{ attribute(array, item) }} | ||
6 | {{ attribute(obj, "bar", ["a", "b"]) }} | ||
7 | --DATA-- | ||
8 | return array('obj' => new TwigTestFoo(), 'method' => 'foo', 'array' => array('foo' => 'bar'), 'item' => 'foo') | ||
9 | --EXPECT-- | ||
10 | foo | ||
11 | bar | ||
12 | bar_a-b | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/block.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/block.test new file mode 100644 index 00000000..8e54059a --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/block.test | |||
@@ -0,0 +1,12 @@ | |||
1 | --TEST-- | ||
2 | "block" function | ||
3 | --TEMPLATE-- | ||
4 | {% extends 'base.twig' %} | ||
5 | {% block bar %}BAR{% endblock %} | ||
6 | --TEMPLATE(base.twig)-- | ||
7 | {% block foo %}{{ block('bar') }}{% endblock %} | ||
8 | {% block bar %}BAR_BASE{% endblock %} | ||
9 | --DATA-- | ||
10 | return array() | ||
11 | --EXPECT-- | ||
12 | BARBAR | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/constant.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/constant.test new file mode 100644 index 00000000..63128791 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/constant.test | |||
@@ -0,0 +1,10 @@ | |||
1 | --TEST-- | ||
2 | "constant" function | ||
3 | --TEMPLATE-- | ||
4 | {{ constant('DATE_W3C') == expect ? 'true' : 'false' }} | ||
5 | {{ constant('ARRAY_AS_PROPS', object) }} | ||
6 | --DATA-- | ||
7 | return array('expect' => DATE_W3C, 'object' => new ArrayObject(array('hi'))); | ||
8 | --EXPECT-- | ||
9 | true | ||
10 | 2 | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/cycle.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/cycle.test new file mode 100644 index 00000000..522a63b8 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/cycle.test | |||
@@ -0,0 +1,16 @@ | |||
1 | --TEST-- | ||
2 | "cycle" function | ||
3 | --TEMPLATE-- | ||
4 | {% for i in 0..6 %} | ||
5 | {{ cycle(array1, i) }}-{{ cycle(array2, i) }} | ||
6 | {% endfor %} | ||
7 | --DATA-- | ||
8 | return array('array1' => array('odd', 'even'), 'array2' => array('apple', 'orange', 'citrus')) | ||
9 | --EXPECT-- | ||
10 | odd-apple | ||
11 | even-orange | ||
12 | odd-citrus | ||
13 | even-apple | ||
14 | odd-orange | ||
15 | even-citrus | ||
16 | odd-apple | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/date.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/date.test new file mode 100644 index 00000000..a4c97167 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/date.test | |||
@@ -0,0 +1,27 @@ | |||
1 | --TEST-- | ||
2 | "date" function | ||
3 | --TEMPLATE-- | ||
4 | {{ date() == date('now') ? 'OK' : 'KO' }} | ||
5 | {{ date() > date('-1day') ? 'OK' : 'KO' }} | ||
6 | {{ date(date1) == date('2010-10-04 13:45') ? 'OK' : 'KO' }} | ||
7 | {{ date(date2) == date('2010-10-04 13:45') ? 'OK' : 'KO' }} | ||
8 | {{ date(date3) == date('2010-10-04 13:45') ? 'OK' : 'KO' }} | ||
9 | {{ date(date4) == date('2010-10-04 13:45') ? 'OK' : 'KO' }} | ||
10 | {{ date(date5) == date('1964-01-02 03:04') ? 'OK' : 'KO' }} | ||
11 | --DATA-- | ||
12 | date_default_timezone_set('UTC'); | ||
13 | return array( | ||
14 | 'date1' => mktime(13, 45, 0, 10, 4, 2010), | ||
15 | 'date2' => new DateTime('2010-10-04 13:45'), | ||
16 | 'date3' => '2010-10-04 13:45', | ||
17 | 'date4' => 1286199900, // DateTime::createFromFormat('Y-m-d H:i', '2010-10-04 13:45', new DateTimeZone('UTC'))->getTimestamp() -- A unixtimestamp is always GMT | ||
18 | 'date5' => -189291360, // DateTime::createFromFormat('Y-m-d H:i', '1964-01-02 03:04', new DateTimeZone('UTC'))->getTimestamp(), | ||
19 | ) | ||
20 | --EXPECT-- | ||
21 | OK | ||
22 | OK | ||
23 | OK | ||
24 | OK | ||
25 | OK | ||
26 | OK | ||
27 | OK | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/date_namedargs.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/date_namedargs.test new file mode 100644 index 00000000..b9dd9e38 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/date_namedargs.test | |||
@@ -0,0 +1,11 @@ | |||
1 | --TEST-- | ||
2 | "date" function | ||
3 | --TEMPLATE-- | ||
4 | {{ date(date, "America/New_York")|date('d/m/Y H:i:s P', false) }} | ||
5 | {{ date(timezone="America/New_York", date=date)|date('d/m/Y H:i:s P', false) }} | ||
6 | --DATA-- | ||
7 | date_default_timezone_set('UTC'); | ||
8 | return array('date' => mktime(13, 45, 0, 10, 4, 2010)) | ||
9 | --EXPECT-- | ||
10 | 04/10/2010 09:45:00 -04:00 | ||
11 | 04/10/2010 09:45:00 -04:00 | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/dump.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/dump.test new file mode 100644 index 00000000..f4072375 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/dump.test | |||
@@ -0,0 +1,16 @@ | |||
1 | --TEST-- | ||
2 | "dump" function | ||
3 | --CONDITION-- | ||
4 | !extension_loaded('xdebug') | ||
5 | --TEMPLATE-- | ||
6 | {{ dump('foo') }} | ||
7 | {{ dump('foo', 'bar') }} | ||
8 | --DATA-- | ||
9 | return array('foo' => 'foo', 'bar' => 'bar') | ||
10 | --CONFIG-- | ||
11 | return array('debug' => true, 'autoescape' => false); | ||
12 | --EXPECT-- | ||
13 | string(3) "foo" | ||
14 | |||
15 | string(3) "foo" | ||
16 | string(3) "bar" | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/dump_array.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/dump_array.test new file mode 100644 index 00000000..889b7a92 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/dump_array.test | |||
@@ -0,0 +1,19 @@ | |||
1 | --TEST-- | ||
2 | "dump" function, xdebug is not loaded or xdebug <2.2-dev is loaded | ||
3 | --CONDITION-- | ||
4 | !extension_loaded('xdebug') || (($r = new ReflectionExtension('xdebug')) && version_compare($r->getVersion(), '2.2-dev', '<')) | ||
5 | --TEMPLATE-- | ||
6 | {{ dump() }} | ||
7 | --DATA-- | ||
8 | return array('foo' => 'foo', 'bar' => 'bar') | ||
9 | --CONFIG-- | ||
10 | return array('debug' => true, 'autoescape' => false); | ||
11 | --EXPECT-- | ||
12 | array(3) { | ||
13 | ["foo"]=> | ||
14 | string(3) "foo" | ||
15 | ["bar"]=> | ||
16 | string(3) "bar" | ||
17 | ["global"]=> | ||
18 | string(6) "global" | ||
19 | } | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/dynamic_function.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/dynamic_function.test new file mode 100644 index 00000000..913fbc99 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/dynamic_function.test | |||
@@ -0,0 +1,10 @@ | |||
1 | --TEST-- | ||
2 | dynamic function | ||
3 | --TEMPLATE-- | ||
4 | {{ foo_path('bar') }} | ||
5 | {{ a_foo_b_bar('bar') }} | ||
6 | --DATA-- | ||
7 | return array() | ||
8 | --EXPECT-- | ||
9 | foo/bar | ||
10 | a/b/bar | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/include/assignment.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/include/assignment.test new file mode 100644 index 00000000..b7653b4e --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/include/assignment.test | |||
@@ -0,0 +1,13 @@ | |||
1 | --TEST-- | ||
2 | "include" function | ||
3 | --TEMPLATE-- | ||
4 | {% set tmp = include("foo.twig") %} | ||
5 | |||
6 | FOO{{ tmp }}BAR | ||
7 | --TEMPLATE(foo.twig)-- | ||
8 | FOOBAR | ||
9 | --DATA-- | ||
10 | return array() | ||
11 | --EXPECT-- | ||
12 | FOO | ||
13 | FOOBARBAR | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/include/autoescaping.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/include/autoescaping.test new file mode 100644 index 00000000..56f8f3b5 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/include/autoescaping.test | |||
@@ -0,0 +1,10 @@ | |||
1 | --TEST-- | ||
2 | "include" function is safe for auto-escaping | ||
3 | --TEMPLATE-- | ||
4 | {{ include("foo.twig") }} | ||
5 | --TEMPLATE(foo.twig)-- | ||
6 | <p>Test</p> | ||
7 | --DATA-- | ||
8 | return array() | ||
9 | --EXPECT-- | ||
10 | <p>Test</p> | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/include/basic.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/include/basic.test new file mode 100644 index 00000000..a434182a --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/include/basic.test | |||
@@ -0,0 +1,17 @@ | |||
1 | --TEST-- | ||
2 | "include" function | ||
3 | --TEMPLATE-- | ||
4 | FOO | ||
5 | {{ include("foo.twig") }} | ||
6 | |||
7 | BAR | ||
8 | --TEMPLATE(foo.twig)-- | ||
9 | FOOBAR | ||
10 | --DATA-- | ||
11 | return array() | ||
12 | --EXPECT-- | ||
13 | FOO | ||
14 | |||
15 | FOOBAR | ||
16 | |||
17 | BAR | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/include/expression.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/include/expression.test new file mode 100644 index 00000000..aba30ce3 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/include/expression.test | |||
@@ -0,0 +1,17 @@ | |||
1 | --TEST-- | ||
2 | "include" function allows expressions for the template to include | ||
3 | --TEMPLATE-- | ||
4 | FOO | ||
5 | {{ include(foo) }} | ||
6 | |||
7 | BAR | ||
8 | --TEMPLATE(foo.twig)-- | ||
9 | FOOBAR | ||
10 | --DATA-- | ||
11 | return array('foo' => 'foo.twig') | ||
12 | --EXPECT-- | ||
13 | FOO | ||
14 | |||
15 | FOOBAR | ||
16 | |||
17 | BAR | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/include/ignore_missing.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/include/ignore_missing.test new file mode 100644 index 00000000..43a2ccc2 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/include/ignore_missing.test | |||
@@ -0,0 +1,10 @@ | |||
1 | --TEST-- | ||
2 | "include" function | ||
3 | --TEMPLATE-- | ||
4 | {{ include(["foo.twig", "bar.twig"], ignore_missing = true) }} | ||
5 | {{ include("foo.twig", ignore_missing = true) }} | ||
6 | {{ include("foo.twig", ignore_missing = true, variables = {}) }} | ||
7 | {{ include("foo.twig", ignore_missing = true, variables = {}, with_context = true) }} | ||
8 | --DATA-- | ||
9 | return array() | ||
10 | --EXPECT-- | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/include/missing.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/include/missing.test new file mode 100644 index 00000000..4d2f6cf1 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/include/missing.test | |||
@@ -0,0 +1,8 @@ | |||
1 | --TEST-- | ||
2 | "include" function | ||
3 | --TEMPLATE-- | ||
4 | {{ include("foo.twig") }} | ||
5 | --DATA-- | ||
6 | return array(); | ||
7 | --EXCEPTION-- | ||
8 | Twig_Error_Loader: Template "foo.twig" is not defined in "index.twig" at line 2. | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/include/missing_nested.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/include/missing_nested.test new file mode 100644 index 00000000..78fddc7a --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/include/missing_nested.test | |||
@@ -0,0 +1,16 @@ | |||
1 | --TEST-- | ||
2 | "include" function | ||
3 | --TEMPLATE-- | ||
4 | {% extends "base.twig" %} | ||
5 | |||
6 | {% block content %} | ||
7 | {{ parent() }} | ||
8 | {% endblock %} | ||
9 | --TEMPLATE(base.twig)-- | ||
10 | {% block content %} | ||
11 | {{ include("foo.twig") }} | ||
12 | {% endblock %} | ||
13 | --DATA-- | ||
14 | return array(); | ||
15 | --EXCEPTION-- | ||
16 | Twig_Error_Loader: Template "foo.twig" is not defined in "base.twig" at line 3. | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/include/sandbox.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/include/sandbox.test new file mode 100644 index 00000000..788a2ab0 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/include/sandbox.test | |||
@@ -0,0 +1,10 @@ | |||
1 | --TEST-- | ||
2 | "include" tag sandboxed | ||
3 | --TEMPLATE-- | ||
4 | {{ include("foo.twig", sandboxed = true) }} | ||
5 | --TEMPLATE(foo.twig)-- | ||
6 | {{ foo|e }} | ||
7 | --DATA-- | ||
8 | return array() | ||
9 | --EXCEPTION-- | ||
10 | Twig_Sandbox_SecurityError: Filter "e" is not allowed in "index.twig" at line 2. | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/include/template_instance.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/include/template_instance.test new file mode 100644 index 00000000..18d405a0 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/include/template_instance.test | |||
@@ -0,0 +1,10 @@ | |||
1 | --TEST-- | ||
2 | "include" function accepts Twig_Template instance | ||
3 | --TEMPLATE-- | ||
4 | {{ include(foo) }} FOO | ||
5 | --TEMPLATE(foo.twig)-- | ||
6 | BAR | ||
7 | --DATA-- | ||
8 | return array('foo' => $twig->loadTemplate('foo.twig')) | ||
9 | --EXPECT-- | ||
10 | BAR FOO | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/include/templates_as_array.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/include/templates_as_array.test new file mode 100644 index 00000000..1a810068 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/include/templates_as_array.test | |||
@@ -0,0 +1,12 @@ | |||
1 | --TEST-- | ||
2 | "include" function | ||
3 | --TEMPLATE-- | ||
4 | {{ include(["foo.twig", "bar.twig"]) }} | ||
5 | {{- include(["bar.twig", "foo.twig"]) }} | ||
6 | --TEMPLATE(foo.twig)-- | ||
7 | foo | ||
8 | --DATA-- | ||
9 | return array() | ||
10 | --EXPECT-- | ||
11 | foo | ||
12 | foo | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/include/with_context.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/include/with_context.test new file mode 100644 index 00000000..35611fbb --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/include/with_context.test | |||
@@ -0,0 +1,16 @@ | |||
1 | --TEST-- | ||
2 | "include" function accept variables and with_context | ||
3 | --TEMPLATE-- | ||
4 | {{ include("foo.twig") }} | ||
5 | {{- include("foo.twig", with_context = false) }} | ||
6 | {{- include("foo.twig", {'foo1': 'bar'}) }} | ||
7 | {{- include("foo.twig", {'foo1': 'bar'}, with_context = false) }} | ||
8 | --TEMPLATE(foo.twig)-- | ||
9 | {% for k, v in _context %}{{ k }},{% endfor %} | ||
10 | --DATA-- | ||
11 | return array('foo' => 'bar') | ||
12 | --EXPECT-- | ||
13 | foo,global,_parent, | ||
14 | global,_parent, | ||
15 | foo,global,foo1,_parent, | ||
16 | foo1,global,_parent, | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/include/with_variables.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/include/with_variables.test new file mode 100644 index 00000000..b2ace940 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/include/with_variables.test | |||
@@ -0,0 +1,12 @@ | |||
1 | --TEST-- | ||
2 | "include" function accept variables | ||
3 | --TEMPLATE-- | ||
4 | {{ include("foo.twig", {'foo': 'bar'}) }} | ||
5 | {{- include("foo.twig", vars) }} | ||
6 | --TEMPLATE(foo.twig)-- | ||
7 | {{ foo }} | ||
8 | --DATA-- | ||
9 | return array('vars' => array('foo' => 'bar')) | ||
10 | --EXPECT-- | ||
11 | bar | ||
12 | bar | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/range.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/range.test new file mode 100644 index 00000000..e0377c8d --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/range.test | |||
@@ -0,0 +1,8 @@ | |||
1 | --TEST-- | ||
2 | "range" function | ||
3 | --TEMPLATE-- | ||
4 | {{ range(low=0+1, high=10+0, step=2)|join(',') }} | ||
5 | --DATA-- | ||
6 | return array() | ||
7 | --EXPECT-- | ||
8 | 1,3,5,7,9 | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/special_chars.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/special_chars.test new file mode 100644 index 00000000..30c3df51 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/special_chars.test | |||
@@ -0,0 +1,8 @@ | |||
1 | --TEST-- | ||
2 | "§" custom function | ||
3 | --TEMPLATE-- | ||
4 | {{ §('foo') }} | ||
5 | --DATA-- | ||
6 | return array() | ||
7 | --EXPECT-- | ||
8 | §foo§ | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/template_from_string.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/template_from_string.test new file mode 100644 index 00000000..41428da1 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/template_from_string.test | |||
@@ -0,0 +1,11 @@ | |||
1 | --TEST-- | ||
2 | "template_from_string" function | ||
3 | --TEMPLATE-- | ||
4 | {% include template_from_string(template) %} | ||
5 | |||
6 | {% include template_from_string("Hello {{ name }}") %} | ||
7 | --DATA-- | ||
8 | return array('name' => 'Fabien', 'template' => "Hello {{ name }}") | ||
9 | --EXPECT-- | ||
10 | Hello Fabien | ||
11 | Hello Fabien | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/macros/default_values.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/macros/default_values.test new file mode 100644 index 00000000..4ccff7b6 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/macros/default_values.test | |||
@@ -0,0 +1,16 @@ | |||
1 | --TEST-- | ||
2 | macro | ||
3 | --TEMPLATE-- | ||
4 | {% from _self import test %} | ||
5 | |||
6 | {% macro test(a, b = 'bar') -%} | ||
7 | {{ a }}{{ b }} | ||
8 | {%- endmacro %} | ||
9 | |||
10 | {{ test('foo') }} | ||
11 | {{ test('bar', 'foo') }} | ||
12 | --DATA-- | ||
13 | return array(); | ||
14 | --EXPECT-- | ||
15 | foobar | ||
16 | barfoo | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/macros/nested_calls.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/macros/nested_calls.test new file mode 100644 index 00000000..cd254281 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/macros/nested_calls.test | |||
@@ -0,0 +1,18 @@ | |||
1 | --TEST-- | ||
2 | macro | ||
3 | --TEMPLATE-- | ||
4 | {% import _self as macros %} | ||
5 | |||
6 | {% macro foo(data) %} | ||
7 | {{ data }} | ||
8 | {% endmacro %} | ||
9 | |||
10 | {% macro bar() %} | ||
11 | <br /> | ||
12 | {% endmacro %} | ||
13 | |||
14 | {{ macros.foo(macros.bar()) }} | ||
15 | --DATA-- | ||
16 | return array(); | ||
17 | --EXPECT-- | ||
18 | <br /> | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/macros/reserved_variables.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/macros/reserved_variables.test new file mode 100644 index 00000000..cbfb921b --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/macros/reserved_variables.test | |||
@@ -0,0 +1,14 @@ | |||
1 | --TEST-- | ||
2 | macro | ||
3 | --TEMPLATE-- | ||
4 | {% from _self import test %} | ||
5 | |||
6 | {% macro test(this) -%} | ||
7 | {{ this }} | ||
8 | {%- endmacro %} | ||
9 | |||
10 | {{ test(this) }} | ||
11 | --DATA-- | ||
12 | return array('this' => 'foo'); | ||
13 | --EXPECT-- | ||
14 | foo | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/macros/simple.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/macros/simple.test new file mode 100644 index 00000000..6a366cdf --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/macros/simple.test | |||
@@ -0,0 +1,22 @@ | |||
1 | --TEST-- | ||
2 | macro | ||
3 | --TEMPLATE-- | ||
4 | {% import _self as test %} | ||
5 | {% from _self import test %} | ||
6 | |||
7 | {% macro test(a, b) -%} | ||
8 | {{ a|default('a') }}<br /> | ||
9 | {{- b|default('b') }}<br /> | ||
10 | {%- endmacro %} | ||
11 | |||
12 | {{ test.test() }} | ||
13 | {{ test() }} | ||
14 | {{ test.test(1, "c") }} | ||
15 | {{ test(1, "c") }} | ||
16 | --DATA-- | ||
17 | return array(); | ||
18 | --EXPECT-- | ||
19 | a<br />b<br /> | ||
20 | a<br />b<br /> | ||
21 | 1<br />c<br /> | ||
22 | 1<br />c<br /> | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/macros/with_filters.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/macros/with_filters.test new file mode 100644 index 00000000..685626f2 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/macros/with_filters.test | |||
@@ -0,0 +1,14 @@ | |||
1 | --TEST-- | ||
2 | macro with a filter | ||
3 | --TEMPLATE-- | ||
4 | {% import _self as test %} | ||
5 | |||
6 | {% macro test() %} | ||
7 | {% filter escape %}foo<br />{% endfilter %} | ||
8 | {% endmacro %} | ||
9 | |||
10 | {{ test.test() }} | ||
11 | --DATA-- | ||
12 | return array(); | ||
13 | --EXPECT-- | ||
14 | foo<br /> | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/regression/empty_token.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/regression/empty_token.test new file mode 100644 index 00000000..65f6cd2b --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/regression/empty_token.test | |||
@@ -0,0 +1,8 @@ | |||
1 | --TEST-- | ||
2 | Twig outputs 0 nodes correctly | ||
3 | --TEMPLATE-- | ||
4 | {{ foo }}0{{ foo }} | ||
5 | --DATA-- | ||
6 | return array('foo' => 'foo') | ||
7 | --EXPECT-- | ||
8 | foo0foo | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/regression/simple_xml_element.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/regression/simple_xml_element.test new file mode 100644 index 00000000..110aef82 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/regression/simple_xml_element.test | |||
@@ -0,0 +1,17 @@ | |||
1 | --TEST-- | ||
2 | Twig is able to deal with SimpleXMLElement instances as variables | ||
3 | --CONDITION-- | ||
4 | version_compare(phpversion(), '5.3.0', '>=') | ||
5 | --TEMPLATE-- | ||
6 | Hello '{{ images.image.0.group }}'! | ||
7 | {{ images.children().count() }} | ||
8 | {% for image in images %} | ||
9 | - {{ image.group }} | ||
10 | {% endfor %} | ||
11 | --DATA-- | ||
12 | return array('images' => new SimpleXMLElement('<images><image><group>foo</group></image><image><group>bar</group></image></images>')) | ||
13 | --EXPECT-- | ||
14 | Hello 'foo'! | ||
15 | 2 | ||
16 | - foo | ||
17 | - bar | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/regression/strings_like_numbers.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/regression/strings_like_numbers.test new file mode 100644 index 00000000..e18e1107 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/regression/strings_like_numbers.test | |||
@@ -0,0 +1,8 @@ | |||
1 | --TEST-- | ||
2 | Twig does not confuse strings with integers in getAttribute() | ||
3 | --TEMPLATE-- | ||
4 | {{ hash['2e2'] }} | ||
5 | --DATA-- | ||
6 | return array('hash' => array('2e2' => 'works')) | ||
7 | --EXPECT-- | ||
8 | works | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/autoescape/basic.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/autoescape/basic.test new file mode 100644 index 00000000..2f6a3e1a --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/autoescape/basic.test | |||
@@ -0,0 +1,26 @@ | |||
1 | --TEST-- | ||
2 | "autoescape" tag applies escaping on its children | ||
3 | --TEMPLATE-- | ||
4 | {% autoescape %} | ||
5 | {{ var }}<br /> | ||
6 | {% endautoescape %} | ||
7 | {% autoescape 'html' %} | ||
8 | {{ var }}<br /> | ||
9 | {% endautoescape %} | ||
10 | {% autoescape false %} | ||
11 | {{ var }}<br /> | ||
12 | {% endautoescape %} | ||
13 | {% autoescape true %} | ||
14 | {{ var }}<br /> | ||
15 | {% endautoescape %} | ||
16 | {% autoescape false %} | ||
17 | {{ var }}<br /> | ||
18 | {% endautoescape %} | ||
19 | --DATA-- | ||
20 | return array('var' => '<br />') | ||
21 | --EXPECT-- | ||
22 | <br /><br /> | ||
23 | <br /><br /> | ||
24 | <br /><br /> | ||
25 | <br /><br /> | ||
26 | <br /><br /> | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/autoescape/blocks.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/autoescape/blocks.test new file mode 100644 index 00000000..05ab83ce --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/autoescape/blocks.test | |||
@@ -0,0 +1,12 @@ | |||
1 | --TEST-- | ||
2 | "autoescape" tag applies escaping on embedded blocks | ||
3 | --TEMPLATE-- | ||
4 | {% autoescape 'html' %} | ||
5 | {% block foo %} | ||
6 | {{ var }} | ||
7 | {% endblock %} | ||
8 | {% endautoescape %} | ||
9 | --DATA-- | ||
10 | return array('var' => '<br />') | ||
11 | --EXPECT-- | ||
12 | <br /> | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/autoescape/double_escaping.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/autoescape/double_escaping.test new file mode 100644 index 00000000..9c097246 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/autoescape/double_escaping.test | |||
@@ -0,0 +1,10 @@ | |||
1 | --TEST-- | ||
2 | "autoescape" tag does not double-escape | ||
3 | --TEMPLATE-- | ||
4 | {% autoescape 'html' %} | ||
5 | {{ var|escape }} | ||
6 | {% endautoescape %} | ||
7 | --DATA-- | ||
8 | return array('var' => '<br />') | ||
9 | --EXPECT-- | ||
10 | <br /> | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/autoescape/functions.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/autoescape/functions.test new file mode 100644 index 00000000..ce7ea789 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/autoescape/functions.test | |||
@@ -0,0 +1,83 @@ | |||
1 | --TEST-- | ||
2 | "autoescape" tag applies escaping after calling functions | ||
3 | --TEMPLATE-- | ||
4 | |||
5 | autoescape false | ||
6 | {% autoescape false %} | ||
7 | |||
8 | safe_br | ||
9 | {{ safe_br() }} | ||
10 | |||
11 | unsafe_br | ||
12 | {{ unsafe_br() }} | ||
13 | |||
14 | {% endautoescape %} | ||
15 | |||
16 | autoescape 'html' | ||
17 | {% autoescape 'html' %} | ||
18 | |||
19 | safe_br | ||
20 | {{ safe_br() }} | ||
21 | |||
22 | unsafe_br | ||
23 | {{ unsafe_br() }} | ||
24 | |||
25 | unsafe_br()|raw | ||
26 | {{ (unsafe_br())|raw }} | ||
27 | |||
28 | safe_br()|escape | ||
29 | {{ (safe_br())|escape }} | ||
30 | |||
31 | safe_br()|raw | ||
32 | {{ (safe_br())|raw }} | ||
33 | |||
34 | unsafe_br()|escape | ||
35 | {{ (unsafe_br())|escape }} | ||
36 | |||
37 | {% endautoescape %} | ||
38 | |||
39 | autoescape js | ||
40 | {% autoescape 'js' %} | ||
41 | |||
42 | safe_br | ||
43 | {{ safe_br() }} | ||
44 | |||
45 | {% endautoescape %} | ||
46 | --DATA-- | ||
47 | return array() | ||
48 | --EXPECT-- | ||
49 | |||
50 | autoescape false | ||
51 | |||
52 | safe_br | ||
53 | <br /> | ||
54 | |||
55 | unsafe_br | ||
56 | <br /> | ||
57 | |||
58 | |||
59 | autoescape 'html' | ||
60 | |||
61 | safe_br | ||
62 | <br /> | ||
63 | |||
64 | unsafe_br | ||
65 | <br /> | ||
66 | |||
67 | unsafe_br()|raw | ||
68 | <br /> | ||
69 | |||
70 | safe_br()|escape | ||
71 | <br /> | ||
72 | |||
73 | safe_br()|raw | ||
74 | <br /> | ||
75 | |||
76 | unsafe_br()|escape | ||
77 | <br /> | ||
78 | |||
79 | |||
80 | autoescape js | ||
81 | |||
82 | safe_br | ||
83 | \x3Cbr\x20\x2F\x3E | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/autoescape/literal.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/autoescape/literal.test new file mode 100644 index 00000000..e389d4dd --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/autoescape/literal.test | |||
@@ -0,0 +1,45 @@ | |||
1 | --TEST-- | ||
2 | "autoescape" tag does not apply escaping on literals | ||
3 | --TEMPLATE-- | ||
4 | {% autoescape 'html' %} | ||
5 | |||
6 | 1. Simple literal | ||
7 | {{ "<br />" }} | ||
8 | |||
9 | 2. Conditional expression with only literals | ||
10 | {{ true ? "<br />" : "<br>" }} | ||
11 | |||
12 | 3. Conditional expression with a variable | ||
13 | {{ true ? "<br />" : someVar }} | ||
14 | |||
15 | 4. Nested conditionals with only literals | ||
16 | {{ true ? (true ? "<br />" : "<br>") : "\n" }} | ||
17 | |||
18 | 5. Nested conditionals with a variable | ||
19 | {{ true ? (true ? "<br />" : someVar) : "\n" }} | ||
20 | |||
21 | 6. Nested conditionals with a variable marked safe | ||
22 | {{ true ? (true ? "<br />" : someVar|raw) : "\n" }} | ||
23 | |||
24 | {% endautoescape %} | ||
25 | --DATA-- | ||
26 | return array() | ||
27 | --EXPECT-- | ||
28 | |||
29 | 1. Simple literal | ||
30 | <br /> | ||
31 | |||
32 | 2. Conditional expression with only literals | ||
33 | <br /> | ||
34 | |||
35 | 3. Conditional expression with a variable | ||
36 | <br /> | ||
37 | |||
38 | 4. Nested conditionals with only literals | ||
39 | <br /> | ||
40 | |||
41 | 5. Nested conditionals with a variable | ||
42 | <br /> | ||
43 | |||
44 | 6. Nested conditionals with a variable marked safe | ||
45 | <br /> | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/autoescape/nested.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/autoescape/nested.test new file mode 100644 index 00000000..798e6fea --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/autoescape/nested.test | |||
@@ -0,0 +1,26 @@ | |||
1 | --TEST-- | ||
2 | "autoescape" tags can be nested at will | ||
3 | --TEMPLATE-- | ||
4 | {{ var }} | ||
5 | {% autoescape 'html' %} | ||
6 | {{ var }} | ||
7 | {% autoescape false %} | ||
8 | {{ var }} | ||
9 | {% autoescape 'html' %} | ||
10 | {{ var }} | ||
11 | {% endautoescape %} | ||
12 | {{ var }} | ||
13 | {% endautoescape %} | ||
14 | {{ var }} | ||
15 | {% endautoescape %} | ||
16 | {{ var }} | ||
17 | --DATA-- | ||
18 | return array('var' => '<br />') | ||
19 | --EXPECT-- | ||
20 | <br /> | ||
21 | <br /> | ||
22 | <br /> | ||
23 | <br /> | ||
24 | <br /> | ||
25 | <br /> | ||
26 | <br /> | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/autoescape/objects.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/autoescape/objects.test new file mode 100644 index 00000000..e896aa41 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/autoescape/objects.test | |||
@@ -0,0 +1,26 @@ | |||
1 | --TEST-- | ||
2 | "autoescape" tag applies escaping to object method calls | ||
3 | --TEMPLATE-- | ||
4 | {% autoescape 'html' %} | ||
5 | {{ user.name }} | ||
6 | {{ user.name|lower }} | ||
7 | {{ user }} | ||
8 | {% endautoescape %} | ||
9 | --DATA-- | ||
10 | class UserForAutoEscapeTest | ||
11 | { | ||
12 | public function getName() | ||
13 | { | ||
14 | return 'Fabien<br />'; | ||
15 | } | ||
16 | |||
17 | public function __toString() | ||
18 | { | ||
19 | return 'Fabien<br />'; | ||
20 | } | ||
21 | } | ||
22 | return array('user' => new UserForAutoEscapeTest()) | ||
23 | --EXPECT-- | ||
24 | Fabien<br /> | ||
25 | fabien<br /> | ||
26 | Fabien<br /> | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/autoescape/raw.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/autoescape/raw.test new file mode 100644 index 00000000..9f1cedd3 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/autoescape/raw.test | |||
@@ -0,0 +1,10 @@ | |||
1 | --TEST-- | ||
2 | "autoescape" tag does not escape when raw is used as a filter | ||
3 | --TEMPLATE-- | ||
4 | {% autoescape 'html' %} | ||
5 | {{ var|raw }} | ||
6 | {% endautoescape %} | ||
7 | --DATA-- | ||
8 | return array('var' => '<br />') | ||
9 | --EXPECT-- | ||
10 | <br /> | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/autoescape/strategy.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/autoescape/strategy.test new file mode 100644 index 00000000..cf8cceef --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/autoescape/strategy.test | |||
@@ -0,0 +1,17 @@ | |||
1 | --TEST-- | ||
2 | "autoescape" tag accepts an escaping strategy | ||
3 | --TEMPLATE-- | ||
4 | {% autoescape true js %}{{ var }}{% endautoescape %} | ||
5 | |||
6 | {% autoescape true html %}{{ var }}{% endautoescape %} | ||
7 | |||
8 | {% autoescape 'js' %}{{ var }}{% endautoescape %} | ||
9 | |||
10 | {% autoescape 'html' %}{{ var }}{% endautoescape %} | ||
11 | --DATA-- | ||
12 | return array('var' => '<br />"') | ||
13 | --EXPECT-- | ||
14 | \x3Cbr\x20\x2F\x3E\x22 | ||
15 | <br />" | ||
16 | \x3Cbr\x20\x2F\x3E\x22 | ||
17 | <br />" | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/autoescape/type.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/autoescape/type.test new file mode 100644 index 00000000..4f415201 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/autoescape/type.test | |||
@@ -0,0 +1,69 @@ | |||
1 | --TEST-- | ||
2 | escape types | ||
3 | --TEMPLATE-- | ||
4 | |||
5 | 1. autoescape 'html' |escape('js') | ||
6 | |||
7 | {% autoescape 'html' %} | ||
8 | <a onclick="alert("{{ msg|escape('js') }}")"></a> | ||
9 | {% endautoescape %} | ||
10 | |||
11 | 2. autoescape 'html' |escape('js') | ||
12 | |||
13 | {% autoescape 'html' %} | ||
14 | <a onclick="alert("{{ msg|escape('js') }}")"></a> | ||
15 | {% endautoescape %} | ||
16 | |||
17 | 3. autoescape 'js' |escape('js') | ||
18 | |||
19 | {% autoescape 'js' %} | ||
20 | <a onclick="alert("{{ msg|escape('js') }}")"></a> | ||
21 | {% endautoescape %} | ||
22 | |||
23 | 4. no escape | ||
24 | |||
25 | {% autoescape false %} | ||
26 | <a onclick="alert("{{ msg }}")"></a> | ||
27 | {% endautoescape %} | ||
28 | |||
29 | 5. |escape('js')|escape('html') | ||
30 | |||
31 | {% autoescape false %} | ||
32 | <a onclick="alert("{{ msg|escape('js')|escape('html') }}")"></a> | ||
33 | {% endautoescape %} | ||
34 | |||
35 | 6. autoescape 'html' |escape('js')|escape('html') | ||
36 | |||
37 | {% autoescape 'html' %} | ||
38 | <a onclick="alert("{{ msg|escape('js')|escape('html') }}")"></a> | ||
39 | {% endautoescape %} | ||
40 | |||
41 | --DATA-- | ||
42 | return array('msg' => "<>\n'\"") | ||
43 | --EXPECT-- | ||
44 | |||
45 | 1. autoescape 'html' |escape('js') | ||
46 | |||
47 | <a onclick="alert("\x3C\x3E\x0A\x27\x22")"></a> | ||
48 | |||
49 | 2. autoescape 'html' |escape('js') | ||
50 | |||
51 | <a onclick="alert("\x3C\x3E\x0A\x27\x22")"></a> | ||
52 | |||
53 | 3. autoescape 'js' |escape('js') | ||
54 | |||
55 | <a onclick="alert("\x3C\x3E\x0A\x27\x22")"></a> | ||
56 | |||
57 | 4. no escape | ||
58 | |||
59 | <a onclick="alert("<> | ||
60 | '"")"></a> | ||
61 | |||
62 | 5. |escape('js')|escape('html') | ||
63 | |||
64 | <a onclick="alert("\x3C\x3E\x0A\x27\x22")"></a> | ||
65 | |||
66 | 6. autoescape 'html' |escape('js')|escape('html') | ||
67 | |||
68 | <a onclick="alert("\x3C\x3E\x0A\x27\x22")"></a> | ||
69 | |||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/autoescape/with_filters.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/autoescape/with_filters.test new file mode 100644 index 00000000..7821a9aa --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/autoescape/with_filters.test | |||
@@ -0,0 +1,131 @@ | |||
1 | --TEST-- | ||
2 | "autoescape" tag applies escaping after calling filters | ||
3 | --TEMPLATE-- | ||
4 | {% autoescape 'html' %} | ||
5 | |||
6 | (escape_and_nl2br is an escaper filter) | ||
7 | |||
8 | 1. Don't escape escaper filter output | ||
9 | ( var is escaped by |escape_and_nl2br, line-breaks are added, | ||
10 | the output is not escaped ) | ||
11 | {{ var|escape_and_nl2br }} | ||
12 | |||
13 | 2. Don't escape escaper filter output | ||
14 | ( var is escaped by |escape_and_nl2br, line-breaks are added, | ||
15 | the output is not escaped, |raw is redundant ) | ||
16 | {{ var|escape_and_nl2br|raw }} | ||
17 | |||
18 | 3. Explicit escape | ||
19 | ( var is escaped by |escape_and_nl2br, line-breaks are added, | ||
20 | the output is explicitly escaped by |escape ) | ||
21 | {{ var|escape_and_nl2br|escape }} | ||
22 | |||
23 | 4. Escape non-escaper filter output | ||
24 | ( var is upper-cased by |upper, | ||
25 | the output is auto-escaped ) | ||
26 | {{ var|upper }} | ||
27 | |||
28 | 5. Escape if last filter is not an escaper | ||
29 | ( var is escaped by |escape_and_nl2br, line-breaks are added, | ||
30 | the output is upper-cased by |upper, | ||
31 | the output is auto-escaped as |upper is not an escaper ) | ||
32 | {{ var|escape_and_nl2br|upper }} | ||
33 | |||
34 | 6. Don't escape escaper filter output | ||
35 | ( var is upper cased by upper, | ||
36 | the output is escaped by |escape_and_nl2br, line-breaks are added, | ||
37 | the output is not escaped as |escape_and_nl2br is an escaper ) | ||
38 | {{ var|upper|escape_and_nl2br }} | ||
39 | |||
40 | 7. Escape if last filter is not an escaper | ||
41 | ( the output of |format is "<b>" ~ var ~ "</b>", | ||
42 | the output is auto-escaped ) | ||
43 | {{ "<b>%s</b>"|format(var) }} | ||
44 | |||
45 | 8. Escape if last filter is not an escaper | ||
46 | ( the output of |format is "<b>" ~ var ~ "</b>", | ||
47 | |raw is redundant, | ||
48 | the output is auto-escaped ) | ||
49 | {{ "<b>%s</b>"|raw|format(var) }} | ||
50 | |||
51 | 9. Don't escape escaper filter output | ||
52 | ( the output of |format is "<b>" ~ var ~ "</b>", | ||
53 | the output is not escaped due to |raw filter at the end ) | ||
54 | {{ "<b>%s</b>"|format(var)|raw }} | ||
55 | |||
56 | 10. Don't escape escaper filter output | ||
57 | ( the output of |format is "<b>" ~ var ~ "</b>", | ||
58 | the output is not escaped due to |raw filter at the end, | ||
59 | the |raw filter on var is redundant ) | ||
60 | {{ "<b>%s</b>"|format(var|raw)|raw }} | ||
61 | |||
62 | {% endautoescape %} | ||
63 | --DATA-- | ||
64 | return array('var' => "<Fabien>\nTwig") | ||
65 | --EXPECT-- | ||
66 | |||
67 | (escape_and_nl2br is an escaper filter) | ||
68 | |||
69 | 1. Don't escape escaper filter output | ||
70 | ( var is escaped by |escape_and_nl2br, line-breaks are added, | ||
71 | the output is not escaped ) | ||
72 | <Fabien><br /> | ||
73 | Twig | ||
74 | |||
75 | 2. Don't escape escaper filter output | ||
76 | ( var is escaped by |escape_and_nl2br, line-breaks are added, | ||
77 | the output is not escaped, |raw is redundant ) | ||
78 | <Fabien><br /> | ||
79 | Twig | ||
80 | |||
81 | 3. Explicit escape | ||
82 | ( var is escaped by |escape_and_nl2br, line-breaks are added, | ||
83 | the output is explicitly escaped by |escape ) | ||
84 | &lt;Fabien&gt;<br /> | ||
85 | Twig | ||
86 | |||
87 | 4. Escape non-escaper filter output | ||
88 | ( var is upper-cased by |upper, | ||
89 | the output is auto-escaped ) | ||
90 | <FABIEN> | ||
91 | TWIG | ||
92 | |||
93 | 5. Escape if last filter is not an escaper | ||
94 | ( var is escaped by |escape_and_nl2br, line-breaks are added, | ||
95 | the output is upper-cased by |upper, | ||
96 | the output is auto-escaped as |upper is not an escaper ) | ||
97 | &LT;FABIEN&GT;<BR /> | ||
98 | TWIG | ||
99 | |||
100 | 6. Don't escape escaper filter output | ||
101 | ( var is upper cased by upper, | ||
102 | the output is escaped by |escape_and_nl2br, line-breaks are added, | ||
103 | the output is not escaped as |escape_and_nl2br is an escaper ) | ||
104 | <FABIEN><br /> | ||
105 | TWIG | ||
106 | |||
107 | 7. Escape if last filter is not an escaper | ||
108 | ( the output of |format is "<b>" ~ var ~ "</b>", | ||
109 | the output is auto-escaped ) | ||
110 | <b><Fabien> | ||
111 | Twig</b> | ||
112 | |||
113 | 8. Escape if last filter is not an escaper | ||
114 | ( the output of |format is "<b>" ~ var ~ "</b>", | ||
115 | |raw is redundant, | ||
116 | the output is auto-escaped ) | ||
117 | <b><Fabien> | ||
118 | Twig</b> | ||
119 | |||
120 | 9. Don't escape escaper filter output | ||
121 | ( the output of |format is "<b>" ~ var ~ "</b>", | ||
122 | the output is not escaped due to |raw filter at the end ) | ||
123 | <b><Fabien> | ||
124 | Twig</b> | ||
125 | |||
126 | 10. Don't escape escaper filter output | ||
127 | ( the output of |format is "<b>" ~ var ~ "</b>", | ||
128 | the output is not escaped due to |raw filter at the end, | ||
129 | the |raw filter on var is redundant ) | ||
130 | <b><Fabien> | ||
131 | Twig</b> | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/autoescape/with_filters_arguments.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/autoescape/with_filters_arguments.test new file mode 100644 index 00000000..f58a1e09 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/autoescape/with_filters_arguments.test | |||
@@ -0,0 +1,23 @@ | |||
1 | --TEST-- | ||
2 | "autoescape" tag do not applies escaping on filter arguments | ||
3 | --TEMPLATE-- | ||
4 | {% autoescape 'html' %} | ||
5 | {{ var|nl2br("<br />") }} | ||
6 | {{ var|nl2br("<br />"|escape) }} | ||
7 | {{ var|nl2br(sep) }} | ||
8 | {{ var|nl2br(sep|raw) }} | ||
9 | {{ var|nl2br(sep|escape) }} | ||
10 | {% endautoescape %} | ||
11 | --DATA-- | ||
12 | return array('var' => "<Fabien>\nTwig", 'sep' => '<br />') | ||
13 | --EXPECT-- | ||
14 | <Fabien><br /> | ||
15 | Twig | ||
16 | <Fabien><br /> | ||
17 | Twig | ||
18 | <Fabien><br /> | ||
19 | Twig | ||
20 | <Fabien><br /> | ||
21 | Twig | ||
22 | <Fabien><br /> | ||
23 | Twig | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/autoescape/with_pre_escape_filters.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/autoescape/with_pre_escape_filters.test new file mode 100644 index 00000000..134c77ea --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/autoescape/with_pre_escape_filters.test | |||
@@ -0,0 +1,68 @@ | |||
1 | --TEST-- | ||
2 | "autoescape" tag applies escaping after calling filters, and before calling pre_escape filters | ||
3 | --TEMPLATE-- | ||
4 | {% autoescape 'html' %} | ||
5 | |||
6 | (nl2br is pre_escaped for "html" and declared safe for "html") | ||
7 | |||
8 | 1. Pre-escape and don't post-escape | ||
9 | ( var|escape|nl2br ) | ||
10 | {{ var|nl2br }} | ||
11 | |||
12 | 2. Don't double-pre-escape | ||
13 | ( var|escape|nl2br ) | ||
14 | {{ var|escape|nl2br }} | ||
15 | |||
16 | 3. Don't escape safe values | ||
17 | ( var|raw|nl2br ) | ||
18 | {{ var|raw|nl2br }} | ||
19 | |||
20 | 4. Don't escape safe values | ||
21 | ( var|escape|nl2br|nl2br ) | ||
22 | {{ var|nl2br|nl2br }} | ||
23 | |||
24 | 5. Re-escape values that are escaped for an other contexts | ||
25 | ( var|escape_something|escape|nl2br ) | ||
26 | {{ var|escape_something|nl2br }} | ||
27 | |||
28 | 6. Still escape when using filters not declared safe | ||
29 | ( var|escape|nl2br|upper|escape ) | ||
30 | {{ var|nl2br|upper }} | ||
31 | |||
32 | {% endautoescape %} | ||
33 | --DATA-- | ||
34 | return array('var' => "<Fabien>\nTwig") | ||
35 | --EXPECT-- | ||
36 | |||
37 | (nl2br is pre_escaped for "html" and declared safe for "html") | ||
38 | |||
39 | 1. Pre-escape and don't post-escape | ||
40 | ( var|escape|nl2br ) | ||
41 | <Fabien><br /> | ||
42 | Twig | ||
43 | |||
44 | 2. Don't double-pre-escape | ||
45 | ( var|escape|nl2br ) | ||
46 | <Fabien><br /> | ||
47 | Twig | ||
48 | |||
49 | 3. Don't escape safe values | ||
50 | ( var|raw|nl2br ) | ||
51 | <Fabien><br /> | ||
52 | Twig | ||
53 | |||
54 | 4. Don't escape safe values | ||
55 | ( var|escape|nl2br|nl2br ) | ||
56 | <Fabien><br /><br /> | ||
57 | Twig | ||
58 | |||
59 | 5. Re-escape values that are escaped for an other contexts | ||
60 | ( var|escape_something|escape|nl2br ) | ||
61 | <FABIEN><br /> | ||
62 | TWIG | ||
63 | |||
64 | 6. Still escape when using filters not declared safe | ||
65 | ( var|escape|nl2br|upper|escape ) | ||
66 | &LT;FABIEN&GT;<BR /> | ||
67 | TWIG | ||
68 | |||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/autoescape/with_preserves_safety_filters.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/autoescape/with_preserves_safety_filters.test new file mode 100644 index 00000000..32d3943b --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/autoescape/with_preserves_safety_filters.test | |||
@@ -0,0 +1,50 @@ | |||
1 | --TEST-- | ||
2 | "autoescape" tag handles filters preserving the safety | ||
3 | --TEMPLATE-- | ||
4 | {% autoescape 'html' %} | ||
5 | |||
6 | (preserves_safety is preserving safety for "html") | ||
7 | |||
8 | 1. Unsafe values are still unsafe | ||
9 | ( var|preserves_safety|escape ) | ||
10 | {{ var|preserves_safety }} | ||
11 | |||
12 | 2. Safe values are still safe | ||
13 | ( var|escape|preserves_safety ) | ||
14 | {{ var|escape|preserves_safety }} | ||
15 | |||
16 | 3. Re-escape values that are escaped for an other contexts | ||
17 | ( var|escape_something|preserves_safety|escape ) | ||
18 | {{ var|escape_something|preserves_safety }} | ||
19 | |||
20 | 4. Still escape when using filters not declared safe | ||
21 | ( var|escape|preserves_safety|replace({'FABIEN': 'FABPOT'})|escape ) | ||
22 | {{ var|escape|preserves_safety|replace({'FABIEN': 'FABPOT'}) }} | ||
23 | |||
24 | {% endautoescape %} | ||
25 | --DATA-- | ||
26 | return array('var' => "<Fabien>\nTwig") | ||
27 | --EXPECT-- | ||
28 | |||
29 | (preserves_safety is preserving safety for "html") | ||
30 | |||
31 | 1. Unsafe values are still unsafe | ||
32 | ( var|preserves_safety|escape ) | ||
33 | <FABIEN> | ||
34 | TWIG | ||
35 | |||
36 | 2. Safe values are still safe | ||
37 | ( var|escape|preserves_safety ) | ||
38 | <FABIEN> | ||
39 | TWIG | ||
40 | |||
41 | 3. Re-escape values that are escaped for an other contexts | ||
42 | ( var|escape_something|preserves_safety|escape ) | ||
43 | <FABIEN> | ||
44 | TWIG | ||
45 | |||
46 | 4. Still escape when using filters not declared safe | ||
47 | ( var|escape|preserves_safety|replace({'FABIEN': 'FABPOT'})|escape ) | ||
48 | &LT;FABPOT&GT; | ||
49 | TWIG | ||
50 | |||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/block/basic.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/block/basic.test new file mode 100644 index 00000000..360dcf03 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/block/basic.test | |||
@@ -0,0 +1,11 @@ | |||
1 | --TEST-- | ||
2 | "block" tag | ||
3 | --TEMPLATE-- | ||
4 | {% block title1 %}FOO{% endblock %} | ||
5 | {% block title2 foo|lower %} | ||
6 | --TEMPLATE(foo.twig)-- | ||
7 | {% block content %}{% endblock %} | ||
8 | --DATA-- | ||
9 | return array('foo' => 'bar') | ||
10 | --EXPECT-- | ||
11 | FOObar | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/block/block_unique_name.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/block/block_unique_name.test new file mode 100644 index 00000000..5c205c0a --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/block/block_unique_name.test | |||
@@ -0,0 +1,11 @@ | |||
1 | --TEST-- | ||
2 | "block" tag | ||
3 | --TEMPLATE-- | ||
4 | {% block content %} | ||
5 | {% block content %} | ||
6 | {% endblock %} | ||
7 | {% endblock %} | ||
8 | --DATA-- | ||
9 | return array() | ||
10 | --EXCEPTION-- | ||
11 | Twig_Error_Syntax: The block 'content' has already been defined line 2 in "index.twig" at line 3 | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/block/special_chars.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/block/special_chars.test new file mode 100644 index 00000000..be17fedf --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/block/special_chars.test | |||
@@ -0,0 +1,10 @@ | |||
1 | --TEST-- | ||
2 | "§" special chars in a block name | ||
3 | --TEMPLATE-- | ||
4 | {% block § %} | ||
5 | § | ||
6 | {% endblock § %} | ||
7 | --DATA-- | ||
8 | return array() | ||
9 | --EXPECT-- | ||
10 | § | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/embed/basic.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/embed/basic.test new file mode 100644 index 00000000..f44296ea --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/embed/basic.test | |||
@@ -0,0 +1,35 @@ | |||
1 | --TEST-- | ||
2 | "embed" tag | ||
3 | --TEMPLATE-- | ||
4 | FOO | ||
5 | {% embed "foo.twig" %} | ||
6 | {% block c1 %} | ||
7 | {{ parent() }} | ||
8 | block1extended | ||
9 | {% endblock %} | ||
10 | {% endembed %} | ||
11 | |||
12 | BAR | ||
13 | --TEMPLATE(foo.twig)-- | ||
14 | A | ||
15 | {% block c1 %} | ||
16 | block1 | ||
17 | {% endblock %} | ||
18 | B | ||
19 | {% block c2 %} | ||
20 | block2 | ||
21 | {% endblock %} | ||
22 | C | ||
23 | --DATA-- | ||
24 | return array() | ||
25 | --EXPECT-- | ||
26 | FOO | ||
27 | |||
28 | A | ||
29 | block1 | ||
30 | |||
31 | block1extended | ||
32 | B | ||
33 | block2 | ||
34 | C | ||
35 | BAR | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/embed/error_line.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/embed/error_line.test new file mode 100644 index 00000000..71ab2e01 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/embed/error_line.test | |||
@@ -0,0 +1,16 @@ | |||
1 | --TEST-- | ||
2 | "embed" tag | ||
3 | --TEMPLATE(index.twig)-- | ||
4 | FOO | ||
5 | {% embed "foo.twig" %} | ||
6 | {% block c1 %} | ||
7 | {{ nothing }} | ||
8 | {% endblock %} | ||
9 | {% endembed %} | ||
10 | BAR | ||
11 | --TEMPLATE(foo.twig)-- | ||
12 | {% block c1 %}{% endblock %} | ||
13 | --DATA-- | ||
14 | return array() | ||
15 | --EXCEPTION-- | ||
16 | Twig_Error_Runtime: Variable "nothing" does not exist in "index.twig" at line 5 | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/embed/multiple.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/embed/multiple.test new file mode 100644 index 00000000..da161e6d --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/embed/multiple.test | |||
@@ -0,0 +1,50 @@ | |||
1 | --TEST-- | ||
2 | "embed" tag | ||
3 | --TEMPLATE-- | ||
4 | FOO | ||
5 | {% embed "foo.twig" %} | ||
6 | {% block c1 %} | ||
7 | {{ parent() }} | ||
8 | block1extended | ||
9 | {% endblock %} | ||
10 | {% endembed %} | ||
11 | |||
12 | {% embed "foo.twig" %} | ||
13 | {% block c1 %} | ||
14 | {{ parent() }} | ||
15 | block1extended | ||
16 | {% endblock %} | ||
17 | {% endembed %} | ||
18 | |||
19 | BAR | ||
20 | --TEMPLATE(foo.twig)-- | ||
21 | A | ||
22 | {% block c1 %} | ||
23 | block1 | ||
24 | {% endblock %} | ||
25 | B | ||
26 | {% block c2 %} | ||
27 | block2 | ||
28 | {% endblock %} | ||
29 | C | ||
30 | --DATA-- | ||
31 | return array() | ||
32 | --EXPECT-- | ||
33 | FOO | ||
34 | |||
35 | A | ||
36 | block1 | ||
37 | |||
38 | block1extended | ||
39 | B | ||
40 | block2 | ||
41 | C | ||
42 | |||
43 | A | ||
44 | block1 | ||
45 | |||
46 | block1extended | ||
47 | B | ||
48 | block2 | ||
49 | C | ||
50 | BAR | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/embed/nested.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/embed/nested.test new file mode 100644 index 00000000..81563dce --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/embed/nested.test | |||
@@ -0,0 +1,42 @@ | |||
1 | --TEST-- | ||
2 | "embed" tag | ||
3 | --TEMPLATE-- | ||
4 | {% embed "foo.twig" %} | ||
5 | {% block c1 %} | ||
6 | {{ parent() }} | ||
7 | {% embed "foo.twig" %} | ||
8 | {% block c1 %} | ||
9 | {{ parent() }} | ||
10 | block1extended | ||
11 | {% endblock %} | ||
12 | {% endembed %} | ||
13 | |||
14 | {% endblock %} | ||
15 | {% endembed %} | ||
16 | --TEMPLATE(foo.twig)-- | ||
17 | A | ||
18 | {% block c1 %} | ||
19 | block1 | ||
20 | {% endblock %} | ||
21 | B | ||
22 | {% block c2 %} | ||
23 | block2 | ||
24 | {% endblock %} | ||
25 | C | ||
26 | --DATA-- | ||
27 | return array() | ||
28 | --EXPECT-- | ||
29 | A | ||
30 | block1 | ||
31 | |||
32 | |||
33 | A | ||
34 | block1 | ||
35 | |||
36 | block1extended | ||
37 | B | ||
38 | block2 | ||
39 | C | ||
40 | B | ||
41 | block2 | ||
42 | C | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/embed/with_extends.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/embed/with_extends.test new file mode 100644 index 00000000..cf7953d3 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/embed/with_extends.test | |||
@@ -0,0 +1,57 @@ | |||
1 | --TEST-- | ||
2 | "embed" tag | ||
3 | --TEMPLATE-- | ||
4 | {% extends "base.twig" %} | ||
5 | |||
6 | {% block c1 %} | ||
7 | {{ parent() }} | ||
8 | blockc1baseextended | ||
9 | {% endblock %} | ||
10 | |||
11 | {% block c2 %} | ||
12 | {{ parent() }} | ||
13 | |||
14 | {% embed "foo.twig" %} | ||
15 | {% block c1 %} | ||
16 | {{ parent() }} | ||
17 | block1extended | ||
18 | {% endblock %} | ||
19 | {% endembed %} | ||
20 | {% endblock %} | ||
21 | --TEMPLATE(base.twig)-- | ||
22 | A | ||
23 | {% block c1 %} | ||
24 | blockc1base | ||
25 | {% endblock %} | ||
26 | {% block c2 %} | ||
27 | blockc2base | ||
28 | {% endblock %} | ||
29 | B | ||
30 | --TEMPLATE(foo.twig)-- | ||
31 | A | ||
32 | {% block c1 %} | ||
33 | block1 | ||
34 | {% endblock %} | ||
35 | B | ||
36 | {% block c2 %} | ||
37 | block2 | ||
38 | {% endblock %} | ||
39 | C | ||
40 | --DATA-- | ||
41 | return array() | ||
42 | --EXPECT-- | ||
43 | A | ||
44 | blockc1base | ||
45 | |||
46 | blockc1baseextended | ||
47 | blockc2base | ||
48 | |||
49 | |||
50 | |||
51 | A | ||
52 | block1 | ||
53 | |||
54 | block1extended | ||
55 | B | ||
56 | block2 | ||
57 | CB \ No newline at end of file | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/filter/basic.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/filter/basic.test new file mode 100644 index 00000000..82094f2f --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/filter/basic.test | |||
@@ -0,0 +1,10 @@ | |||
1 | --TEST-- | ||
2 | "filter" tag applies a filter on its children | ||
3 | --TEMPLATE-- | ||
4 | {% filter upper %} | ||
5 | Some text with a {{ var }} | ||
6 | {% endfilter %} | ||
7 | --DATA-- | ||
8 | return array('var' => 'var') | ||
9 | --EXPECT-- | ||
10 | SOME TEXT WITH A VAR | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/filter/json_encode.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/filter/json_encode.test new file mode 100644 index 00000000..3e7148bf --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/filter/json_encode.test | |||
@@ -0,0 +1,8 @@ | |||
1 | --TEST-- | ||
2 | "filter" tag applies a filter on its children | ||
3 | --TEMPLATE-- | ||
4 | {% filter json_encode|raw %}test{% endfilter %} | ||
5 | --DATA-- | ||
6 | return array() | ||
7 | --EXPECT-- | ||
8 | "test" | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/filter/multiple.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/filter/multiple.test new file mode 100644 index 00000000..75512ef9 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/filter/multiple.test | |||
@@ -0,0 +1,10 @@ | |||
1 | --TEST-- | ||
2 | "filter" tags accept multiple chained filters | ||
3 | --TEMPLATE-- | ||
4 | {% filter lower|title %} | ||
5 | {{ var }} | ||
6 | {% endfilter %} | ||
7 | --DATA-- | ||
8 | return array('var' => 'VAR') | ||
9 | --EXPECT-- | ||
10 | Var | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/filter/nested.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/filter/nested.test new file mode 100644 index 00000000..7e4e4eb3 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/filter/nested.test | |||
@@ -0,0 +1,16 @@ | |||
1 | --TEST-- | ||
2 | "filter" tags can be nested at will | ||
3 | --TEMPLATE-- | ||
4 | {% filter lower|title %} | ||
5 | {{ var }} | ||
6 | {% filter upper %} | ||
7 | {{ var }} | ||
8 | {% endfilter %} | ||
9 | {{ var }} | ||
10 | {% endfilter %} | ||
11 | --DATA-- | ||
12 | return array('var' => 'var') | ||
13 | --EXPECT-- | ||
14 | Var | ||
15 | Var | ||
16 | Var | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/filter/with_for_tag.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/filter/with_for_tag.test new file mode 100644 index 00000000..22745ead --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/filter/with_for_tag.test | |||
@@ -0,0 +1,13 @@ | |||
1 | --TEST-- | ||
2 | "filter" tag applies the filter on "for" tags | ||
3 | --TEMPLATE-- | ||
4 | {% filter upper %} | ||
5 | {% for item in items %} | ||
6 | {{ item }} | ||
7 | {% endfor %} | ||
8 | {% endfilter %} | ||
9 | --DATA-- | ||
10 | return array('items' => array('a', 'b')) | ||
11 | --EXPECT-- | ||
12 | A | ||
13 | B | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/filter/with_if_tag.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/filter/with_if_tag.test new file mode 100644 index 00000000..afd95b29 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/filter/with_if_tag.test | |||
@@ -0,0 +1,29 @@ | |||
1 | --TEST-- | ||
2 | "filter" tag applies the filter on "if" tags | ||
3 | --TEMPLATE-- | ||
4 | {% filter upper %} | ||
5 | {% if items %} | ||
6 | {{ items|join(', ') }} | ||
7 | {% endif %} | ||
8 | |||
9 | {% if items.3 is defined %} | ||
10 | FOO | ||
11 | {% else %} | ||
12 | {{ items.1 }} | ||
13 | {% endif %} | ||
14 | |||
15 | {% if items.3 is defined %} | ||
16 | FOO | ||
17 | {% elseif items.1 %} | ||
18 | {{ items.0 }} | ||
19 | {% endif %} | ||
20 | |||
21 | {% endfilter %} | ||
22 | --DATA-- | ||
23 | return array('items' => array('a', 'b')) | ||
24 | --EXPECT-- | ||
25 | A, B | ||
26 | |||
27 | B | ||
28 | |||
29 | A | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/for/condition.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/for/condition.test new file mode 100644 index 00000000..380531f7 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/for/condition.test | |||
@@ -0,0 +1,14 @@ | |||
1 | --TEST-- | ||
2 | "for" tag takes a condition | ||
3 | --TEMPLATE-- | ||
4 | {% for i in 1..5 if i is odd -%} | ||
5 | {{ loop.index }}.{{ i }}{{ foo.bar }} | ||
6 | {% endfor %} | ||
7 | --DATA-- | ||
8 | return array('foo' => array('bar' => 'X')) | ||
9 | --CONFIG-- | ||
10 | return array('strict_variables' => false) | ||
11 | --EXPECT-- | ||
12 | 1.1X | ||
13 | 2.3X | ||
14 | 3.5X | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/for/context.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/for/context.test new file mode 100644 index 00000000..ddc69307 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/for/context.test | |||
@@ -0,0 +1,18 @@ | |||
1 | --TEST-- | ||
2 | "for" tag keeps the context safe | ||
3 | --TEMPLATE-- | ||
4 | {% for item in items %} | ||
5 | {% for item in items %} | ||
6 | * {{ item }} | ||
7 | {% endfor %} | ||
8 | * {{ item }} | ||
9 | {% endfor %} | ||
10 | --DATA-- | ||
11 | return array('items' => array('a', 'b')) | ||
12 | --EXPECT-- | ||
13 | * a | ||
14 | * b | ||
15 | * a | ||
16 | * a | ||
17 | * b | ||
18 | * b | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/for/else.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/for/else.test new file mode 100644 index 00000000..20ccc880 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/for/else.test | |||
@@ -0,0 +1,23 @@ | |||
1 | --TEST-- | ||
2 | "for" tag can use an "else" clause | ||
3 | --TEMPLATE-- | ||
4 | {% for item in items %} | ||
5 | * {{ item }} | ||
6 | {% else %} | ||
7 | no item | ||
8 | {% endfor %} | ||
9 | --DATA-- | ||
10 | return array('items' => array('a', 'b')) | ||
11 | --EXPECT-- | ||
12 | * a | ||
13 | * b | ||
14 | --DATA-- | ||
15 | return array('items' => array()) | ||
16 | --EXPECT-- | ||
17 | no item | ||
18 | --DATA-- | ||
19 | return array() | ||
20 | --CONFIG-- | ||
21 | return array('strict_variables' => false) | ||
22 | --EXPECT-- | ||
23 | no item | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/for/inner_variables.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/for/inner_variables.test new file mode 100644 index 00000000..49fb9ca6 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/for/inner_variables.test | |||
@@ -0,0 +1,17 @@ | |||
1 | --TEST-- | ||
2 | "for" tag does not reset inner variables | ||
3 | --TEMPLATE-- | ||
4 | {% for i in 1..2 %} | ||
5 | {% for j in 0..2 %} | ||
6 | {{k}}{% set k = k+1 %} {{ loop.parent.loop.index }} | ||
7 | {% endfor %} | ||
8 | {% endfor %} | ||
9 | --DATA-- | ||
10 | return array('k' => 0) | ||
11 | --EXPECT-- | ||
12 | 0 1 | ||
13 | 1 1 | ||
14 | 2 1 | ||
15 | 3 2 | ||
16 | 4 2 | ||
17 | 5 2 | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/for/keys.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/for/keys.test new file mode 100644 index 00000000..4e22cb47 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/for/keys.test | |||
@@ -0,0 +1,11 @@ | |||
1 | --TEST-- | ||
2 | "for" tag can iterate over keys | ||
3 | --TEMPLATE-- | ||
4 | {% for key in items|keys %} | ||
5 | * {{ key }} | ||
6 | {% endfor %} | ||
7 | --DATA-- | ||
8 | return array('items' => array('a', 'b')) | ||
9 | --EXPECT-- | ||
10 | * 0 | ||
11 | * 1 | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/for/keys_and_values.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/for/keys_and_values.test new file mode 100644 index 00000000..4c211689 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/for/keys_and_values.test | |||
@@ -0,0 +1,11 @@ | |||
1 | --TEST-- | ||
2 | "for" tag can iterate over keys and values | ||
3 | --TEMPLATE-- | ||
4 | {% for key, item in items %} | ||
5 | * {{ key }}/{{ item }} | ||
6 | {% endfor %} | ||
7 | --DATA-- | ||
8 | return array('items' => array('a', 'b')) | ||
9 | --EXPECT-- | ||
10 | * 0/a | ||
11 | * 1/b | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/for/loop_context.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/for/loop_context.test new file mode 100644 index 00000000..93bc76a1 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/for/loop_context.test | |||
@@ -0,0 +1,19 @@ | |||
1 | --TEST-- | ||
2 | "for" tag adds a loop variable to the context | ||
3 | --TEMPLATE-- | ||
4 | {% for item in items %} | ||
5 | * {{ loop.index }}/{{ loop.index0 }} | ||
6 | * {{ loop.revindex }}/{{ loop.revindex0 }} | ||
7 | * {{ loop.first }}/{{ loop.last }}/{{ loop.length }} | ||
8 | |||
9 | {% endfor %} | ||
10 | --DATA-- | ||
11 | return array('items' => array('a', 'b')) | ||
12 | --EXPECT-- | ||
13 | * 1/0 | ||
14 | * 2/1 | ||
15 | * 1//2 | ||
16 | |||
17 | * 2/1 | ||
18 | * 1/0 | ||
19 | * /1/2 | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/for/loop_context_local.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/for/loop_context_local.test new file mode 100644 index 00000000..58af2c32 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/for/loop_context_local.test | |||
@@ -0,0 +1,10 @@ | |||
1 | --TEST-- | ||
2 | "for" tag adds a loop variable to the context locally | ||
3 | --TEMPLATE-- | ||
4 | {% for item in items %} | ||
5 | {% endfor %} | ||
6 | {% if loop is not defined %}WORKS{% endif %} | ||
7 | --DATA-- | ||
8 | return array('items' => array()) | ||
9 | --EXPECT-- | ||
10 | WORKS | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/for/loop_not_defined.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/for/loop_not_defined.test new file mode 100644 index 00000000..4301ef2f --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/for/loop_not_defined.test | |||
@@ -0,0 +1,10 @@ | |||
1 | --TEST-- | ||
2 | "for" tag | ||
3 | --TEMPLATE-- | ||
4 | {% for i, item in items if i > 0 %} | ||
5 | {{ loop.last }} | ||
6 | {% endfor %} | ||
7 | --DATA-- | ||
8 | return array('items' => array('a', 'b')) | ||
9 | --EXCEPTION-- | ||
10 | Twig_Error_Syntax: The "loop.last" variable is not defined when looping with a condition in "index.twig" at line 3 | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/for/loop_not_defined_cond.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/for/loop_not_defined_cond.test new file mode 100644 index 00000000..c7e723a5 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/for/loop_not_defined_cond.test | |||
@@ -0,0 +1,9 @@ | |||
1 | --TEST-- | ||
2 | "for" tag | ||
3 | --TEMPLATE-- | ||
4 | {% for i, item in items if loop.last > 0 %} | ||
5 | {% endfor %} | ||
6 | --DATA-- | ||
7 | return array('items' => array('a', 'b')) | ||
8 | --EXCEPTION-- | ||
9 | Twig_Error_Syntax: The "loop" variable cannot be used in a looping condition in "index.twig" at line 2 | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/for/nested_else.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/for/nested_else.test new file mode 100644 index 00000000..f8b9f6bc --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/for/nested_else.test | |||
@@ -0,0 +1,17 @@ | |||
1 | --TEST-- | ||
2 | "for" tag can use an "else" clause | ||
3 | --TEMPLATE-- | ||
4 | {% for item in items %} | ||
5 | {% for item in items1 %} | ||
6 | * {{ item }} | ||
7 | {% else %} | ||
8 | no {{ item }} | ||
9 | {% endfor %} | ||
10 | {% else %} | ||
11 | no item1 | ||
12 | {% endfor %} | ||
13 | --DATA-- | ||
14 | return array('items' => array('a', 'b'), 'items1' => array()) | ||
15 | --EXPECT-- | ||
16 | no a | ||
17 | no b | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/for/objects.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/for/objects.test new file mode 100644 index 00000000..50344379 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/for/objects.test | |||
@@ -0,0 +1,43 @@ | |||
1 | --TEST-- | ||
2 | "for" tag iterates over iterable objects | ||
3 | --TEMPLATE-- | ||
4 | {% for item in items %} | ||
5 | * {{ item }} | ||
6 | * {{ loop.index }}/{{ loop.index0 }} | ||
7 | * {{ loop.first }} | ||
8 | |||
9 | {% endfor %} | ||
10 | |||
11 | {% for key, value in items %} | ||
12 | * {{ key }}/{{ value }} | ||
13 | {% endfor %} | ||
14 | |||
15 | {% for key in items|keys %} | ||
16 | * {{ key }} | ||
17 | {% endfor %} | ||
18 | --DATA-- | ||
19 | class ItemsIterator implements Iterator | ||
20 | { | ||
21 | protected $values = array('foo' => 'bar', 'bar' => 'foo'); | ||
22 | public function current() { return current($this->values); } | ||
23 | public function key() { return key($this->values); } | ||
24 | public function next() { return next($this->values); } | ||
25 | public function rewind() { return reset($this->values); } | ||
26 | public function valid() { return false !== current($this->values); } | ||
27 | } | ||
28 | return array('items' => new ItemsIterator()) | ||
29 | --EXPECT-- | ||
30 | * bar | ||
31 | * 1/0 | ||
32 | * 1 | ||
33 | |||
34 | * foo | ||
35 | * 2/1 | ||
36 | * | ||
37 | |||
38 | |||
39 | * foo/bar | ||
40 | * bar/foo | ||
41 | |||
42 | * foo | ||
43 | * bar | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/for/objects_countable.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/for/objects_countable.test new file mode 100644 index 00000000..4a1ff611 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/for/objects_countable.test | |||
@@ -0,0 +1,47 @@ | |||
1 | --TEST-- | ||
2 | "for" tag iterates over iterable and countable objects | ||
3 | --TEMPLATE-- | ||
4 | {% for item in items %} | ||
5 | * {{ item }} | ||
6 | * {{ loop.index }}/{{ loop.index0 }} | ||
7 | * {{ loop.revindex }}/{{ loop.revindex0 }} | ||
8 | * {{ loop.first }}/{{ loop.last }}/{{ loop.length }} | ||
9 | |||
10 | {% endfor %} | ||
11 | |||
12 | {% for key, value in items %} | ||
13 | * {{ key }}/{{ value }} | ||
14 | {% endfor %} | ||
15 | |||
16 | {% for key in items|keys %} | ||
17 | * {{ key }} | ||
18 | {% endfor %} | ||
19 | --DATA-- | ||
20 | class ItemsIteratorCountable implements Iterator, Countable | ||
21 | { | ||
22 | protected $values = array('foo' => 'bar', 'bar' => 'foo'); | ||
23 | public function current() { return current($this->values); } | ||
24 | public function key() { return key($this->values); } | ||
25 | public function next() { return next($this->values); } | ||
26 | public function rewind() { return reset($this->values); } | ||
27 | public function valid() { return false !== current($this->values); } | ||
28 | public function count() { return count($this->values); } | ||
29 | } | ||
30 | return array('items' => new ItemsIteratorCountable()) | ||
31 | --EXPECT-- | ||
32 | * bar | ||
33 | * 1/0 | ||
34 | * 2/1 | ||
35 | * 1//2 | ||
36 | |||
37 | * foo | ||
38 | * 2/1 | ||
39 | * 1/0 | ||
40 | * /1/2 | ||
41 | |||
42 | |||
43 | * foo/bar | ||
44 | * bar/foo | ||
45 | |||
46 | * foo | ||
47 | * bar | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/for/recursive.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/for/recursive.test new file mode 100644 index 00000000..17b2e222 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/for/recursive.test | |||
@@ -0,0 +1,18 @@ | |||
1 | --TEST-- | ||
2 | "for" tags can be nested | ||
3 | --TEMPLATE-- | ||
4 | {% for key, item in items %} | ||
5 | * {{ key }} ({{ loop.length }}): | ||
6 | {% for value in item %} | ||
7 | * {{ value }} ({{ loop.length }}) | ||
8 | {% endfor %} | ||
9 | {% endfor %} | ||
10 | --DATA-- | ||
11 | return array('items' => array('a' => array('a1', 'a2', 'a3'), 'b' => array('b1'))) | ||
12 | --EXPECT-- | ||
13 | * a (2): | ||
14 | * a1 (3) | ||
15 | * a2 (3) | ||
16 | * a3 (3) | ||
17 | * b (2): | ||
18 | * b1 (1) | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/for/values.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/for/values.test new file mode 100644 index 00000000..82f2ae8a --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/for/values.test | |||
@@ -0,0 +1,11 @@ | |||
1 | --TEST-- | ||
2 | "for" tag iterates over item values | ||
3 | --TEMPLATE-- | ||
4 | {% for item in items %} | ||
5 | * {{ item }} | ||
6 | {% endfor %} | ||
7 | --DATA-- | ||
8 | return array('items' => array('a', 'b')) | ||
9 | --EXPECT-- | ||
10 | * a | ||
11 | * b | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/from.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/from.test new file mode 100644 index 00000000..5f5da0ec --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/from.test | |||
@@ -0,0 +1,14 @@ | |||
1 | --TEST-- | ||
2 | global variables | ||
3 | --TEMPLATE-- | ||
4 | {% include "included.twig" %} | ||
5 | {% from "included.twig" import foobar %} | ||
6 | {{ foobar() }} | ||
7 | --TEMPLATE(included.twig)-- | ||
8 | {% macro foobar() %} | ||
9 | called foobar | ||
10 | {% endmacro %} | ||
11 | --DATA-- | ||
12 | return array(); | ||
13 | --EXPECT-- | ||
14 | called foobar | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/if/basic.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/if/basic.test new file mode 100644 index 00000000..c1c3d276 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/if/basic.test | |||
@@ -0,0 +1,22 @@ | |||
1 | --TEST-- | ||
2 | "if" creates a condition | ||
3 | --TEMPLATE-- | ||
4 | {% if a is defined %} | ||
5 | {{ a }} | ||
6 | {% elseif b is defined %} | ||
7 | {{ b }} | ||
8 | {% else %} | ||
9 | NOTHING | ||
10 | {% endif %} | ||
11 | --DATA-- | ||
12 | return array('a' => 'a') | ||
13 | --EXPECT-- | ||
14 | a | ||
15 | --DATA-- | ||
16 | return array('b' => 'b') | ||
17 | --EXPECT-- | ||
18 | b | ||
19 | --DATA-- | ||
20 | return array() | ||
21 | --EXPECT-- | ||
22 | NOTHING | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/if/expression.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/if/expression.test new file mode 100644 index 00000000..edfb73df --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/if/expression.test | |||
@@ -0,0 +1,22 @@ | |||
1 | --TEST-- | ||
2 | "if" takes an expression as a test | ||
3 | --TEMPLATE-- | ||
4 | {% if a < 2 %} | ||
5 | A1 | ||
6 | {% elseif a > 10 %} | ||
7 | A2 | ||
8 | {% else %} | ||
9 | A3 | ||
10 | {% endif %} | ||
11 | --DATA-- | ||
12 | return array('a' => 1) | ||
13 | --EXPECT-- | ||
14 | A1 | ||
15 | --DATA-- | ||
16 | return array('a' => 12) | ||
17 | --EXPECT-- | ||
18 | A2 | ||
19 | --DATA-- | ||
20 | return array('a' => 7) | ||
21 | --EXPECT-- | ||
22 | A3 | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/include/basic.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/include/basic.test new file mode 100644 index 00000000..8fe1a6c1 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/include/basic.test | |||
@@ -0,0 +1,16 @@ | |||
1 | --TEST-- | ||
2 | "include" tag | ||
3 | --TEMPLATE-- | ||
4 | FOO | ||
5 | {% include "foo.twig" %} | ||
6 | |||
7 | BAR | ||
8 | --TEMPLATE(foo.twig)-- | ||
9 | FOOBAR | ||
10 | --DATA-- | ||
11 | return array() | ||
12 | --EXPECT-- | ||
13 | FOO | ||
14 | |||
15 | FOOBAR | ||
16 | BAR | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/include/expression.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/include/expression.test new file mode 100644 index 00000000..eaeeb112 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/include/expression.test | |||
@@ -0,0 +1,16 @@ | |||
1 | --TEST-- | ||
2 | "include" tag allows expressions for the template to include | ||
3 | --TEMPLATE-- | ||
4 | FOO | ||
5 | {% include foo %} | ||
6 | |||
7 | BAR | ||
8 | --TEMPLATE(foo.twig)-- | ||
9 | FOOBAR | ||
10 | --DATA-- | ||
11 | return array('foo' => 'foo.twig') | ||
12 | --EXPECT-- | ||
13 | FOO | ||
14 | |||
15 | FOOBAR | ||
16 | BAR | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/include/ignore_missing.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/include/ignore_missing.test new file mode 100644 index 00000000..24aed06d --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/include/ignore_missing.test | |||
@@ -0,0 +1,10 @@ | |||
1 | --TEST-- | ||
2 | "include" tag | ||
3 | --TEMPLATE-- | ||
4 | {% include ["foo.twig", "bar.twig"] ignore missing %} | ||
5 | {% include "foo.twig" ignore missing %} | ||
6 | {% include "foo.twig" ignore missing with {} %} | ||
7 | {% include "foo.twig" ignore missing with {} only %} | ||
8 | --DATA-- | ||
9 | return array() | ||
10 | --EXPECT-- | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/include/missing.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/include/missing.test new file mode 100644 index 00000000..f25e8715 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/include/missing.test | |||
@@ -0,0 +1,8 @@ | |||
1 | --TEST-- | ||
2 | "include" tag | ||
3 | --TEMPLATE-- | ||
4 | {% include "foo.twig" %} | ||
5 | --DATA-- | ||
6 | return array(); | ||
7 | --EXCEPTION-- | ||
8 | Twig_Error_Loader: Template "foo.twig" is not defined in "index.twig" at line 2. | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/include/missing_nested.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/include/missing_nested.test new file mode 100644 index 00000000..86c18644 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/include/missing_nested.test | |||
@@ -0,0 +1,16 @@ | |||
1 | --TEST-- | ||
2 | "include" tag | ||
3 | --TEMPLATE-- | ||
4 | {% extends "base.twig" %} | ||
5 | |||
6 | {% block content %} | ||
7 | {{ parent() }} | ||
8 | {% endblock %} | ||
9 | --TEMPLATE(base.twig)-- | ||
10 | {% block content %} | ||
11 | {% include "foo.twig" %} | ||
12 | {% endblock %} | ||
13 | --DATA-- | ||
14 | return array(); | ||
15 | --EXCEPTION-- | ||
16 | Twig_Error_Loader: Template "foo.twig" is not defined in "base.twig" at line 3. | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/include/only.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/include/only.test new file mode 100644 index 00000000..77760a09 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/include/only.test | |||
@@ -0,0 +1,16 @@ | |||
1 | --TEST-- | ||
2 | "include" tag accept variables and only | ||
3 | --TEMPLATE-- | ||
4 | {% include "foo.twig" %} | ||
5 | {% include "foo.twig" only %} | ||
6 | {% include "foo.twig" with {'foo1': 'bar'} %} | ||
7 | {% include "foo.twig" with {'foo1': 'bar'} only %} | ||
8 | --TEMPLATE(foo.twig)-- | ||
9 | {% for k, v in _context %}{{ k }},{% endfor %} | ||
10 | --DATA-- | ||
11 | return array('foo' => 'bar') | ||
12 | --EXPECT-- | ||
13 | foo,global,_parent, | ||
14 | global,_parent, | ||
15 | foo,global,foo1,_parent, | ||
16 | foo1,global,_parent, | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/include/template_instance.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/include/template_instance.test new file mode 100644 index 00000000..6ba064a3 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/include/template_instance.test | |||
@@ -0,0 +1,10 @@ | |||
1 | --TEST-- | ||
2 | "include" tag accepts Twig_Template instance | ||
3 | --TEMPLATE-- | ||
4 | {% include foo %} FOO | ||
5 | --TEMPLATE(foo.twig)-- | ||
6 | BAR | ||
7 | --DATA-- | ||
8 | return array('foo' => $twig->loadTemplate('foo.twig')) | ||
9 | --EXPECT-- | ||
10 | BAR FOO | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/include/templates_as_array.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/include/templates_as_array.test new file mode 100644 index 00000000..ab670ee0 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/include/templates_as_array.test | |||
@@ -0,0 +1,12 @@ | |||
1 | --TEST-- | ||
2 | "include" tag | ||
3 | --TEMPLATE-- | ||
4 | {% include ["foo.twig", "bar.twig"] %} | ||
5 | {% include ["bar.twig", "foo.twig"] %} | ||
6 | --TEMPLATE(foo.twig)-- | ||
7 | foo | ||
8 | --DATA-- | ||
9 | return array() | ||
10 | --EXPECT-- | ||
11 | foo | ||
12 | foo | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/include/with_variables.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/include/with_variables.test new file mode 100644 index 00000000..41384ac7 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/include/with_variables.test | |||
@@ -0,0 +1,12 @@ | |||
1 | --TEST-- | ||
2 | "include" tag accept variables | ||
3 | --TEMPLATE-- | ||
4 | {% include "foo.twig" with {'foo': 'bar'} %} | ||
5 | {% include "foo.twig" with vars %} | ||
6 | --TEMPLATE(foo.twig)-- | ||
7 | {{ foo }} | ||
8 | --DATA-- | ||
9 | return array('vars' => array('foo' => 'bar')) | ||
10 | --EXPECT-- | ||
11 | bar | ||
12 | bar | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/basic.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/basic.test new file mode 100644 index 00000000..0778a4b4 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/basic.test | |||
@@ -0,0 +1,14 @@ | |||
1 | --TEST-- | ||
2 | "extends" tag | ||
3 | --TEMPLATE-- | ||
4 | {% extends "foo.twig" %} | ||
5 | |||
6 | {% block content %} | ||
7 | FOO | ||
8 | {% endblock %} | ||
9 | --TEMPLATE(foo.twig)-- | ||
10 | {% block content %}{% endblock %} | ||
11 | --DATA-- | ||
12 | return array() | ||
13 | --EXPECT-- | ||
14 | FOO | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/conditional.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/conditional.test new file mode 100644 index 00000000..8576e773 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/conditional.test | |||
@@ -0,0 +1,14 @@ | |||
1 | --TEST-- | ||
2 | "extends" tag | ||
3 | --TEMPLATE-- | ||
4 | {% extends standalone ? foo : 'bar.twig' %} | ||
5 | |||
6 | {% block content %}{{ parent() }}FOO{% endblock %} | ||
7 | --TEMPLATE(foo.twig)-- | ||
8 | {% block content %}FOO{% endblock %} | ||
9 | --TEMPLATE(bar.twig)-- | ||
10 | {% block content %}BAR{% endblock %} | ||
11 | --DATA-- | ||
12 | return array('foo' => 'foo.twig', 'standalone' => true) | ||
13 | --EXPECT-- | ||
14 | FOOFOO | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/dynamic.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/dynamic.test new file mode 100644 index 00000000..ee06ddce --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/dynamic.test | |||
@@ -0,0 +1,14 @@ | |||
1 | --TEST-- | ||
2 | "extends" tag | ||
3 | --TEMPLATE-- | ||
4 | {% extends foo %} | ||
5 | |||
6 | {% block content %} | ||
7 | FOO | ||
8 | {% endblock %} | ||
9 | --TEMPLATE(foo.twig)-- | ||
10 | {% block content %}{% endblock %} | ||
11 | --DATA-- | ||
12 | return array('foo' => 'foo.twig') | ||
13 | --EXPECT-- | ||
14 | FOO | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/empty.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/empty.test new file mode 100644 index 00000000..784f3571 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/empty.test | |||
@@ -0,0 +1,10 @@ | |||
1 | --TEST-- | ||
2 | "extends" tag | ||
3 | --TEMPLATE-- | ||
4 | {% extends "foo.twig" %} | ||
5 | --TEMPLATE(foo.twig)-- | ||
6 | {% block content %}FOO{% endblock %} | ||
7 | --DATA-- | ||
8 | return array() | ||
9 | --EXPECT-- | ||
10 | FOO | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/extends_as_array.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/extends_as_array.test new file mode 100644 index 00000000..a1cb1ce8 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/extends_as_array.test | |||
@@ -0,0 +1,12 @@ | |||
1 | --TEST-- | ||
2 | "extends" tag | ||
3 | --TEMPLATE-- | ||
4 | {% extends ["foo.twig", "bar.twig"] %} | ||
5 | --TEMPLATE(bar.twig)-- | ||
6 | {% block content %} | ||
7 | foo | ||
8 | {% endblock %} | ||
9 | --DATA-- | ||
10 | return array() | ||
11 | --EXPECT-- | ||
12 | foo | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/multiple.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/multiple.test new file mode 100644 index 00000000..dfc2b6c4 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/multiple.test | |||
@@ -0,0 +1,12 @@ | |||
1 | --TEST-- | ||
2 | "extends" tag | ||
3 | --TEMPLATE-- | ||
4 | {% extends "layout.twig" %}{% block content %}{{ parent() }}index {% endblock %} | ||
5 | --TEMPLATE(layout.twig)-- | ||
6 | {% extends "base.twig" %}{% block content %}{{ parent() }}layout {% endblock %} | ||
7 | --TEMPLATE(base.twig)-- | ||
8 | {% block content %}base {% endblock %} | ||
9 | --DATA-- | ||
10 | return array() | ||
11 | --EXPECT-- | ||
12 | base layout index | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/nested_blocks.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/nested_blocks.test new file mode 100644 index 00000000..faca9259 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/nested_blocks.test | |||
@@ -0,0 +1,22 @@ | |||
1 | --TEST-- | ||
2 | "block" tag | ||
3 | --TEMPLATE-- | ||
4 | {% extends "foo.twig" %} | ||
5 | |||
6 | {% block content %} | ||
7 | {% block subcontent %} | ||
8 | {% block subsubcontent %} | ||
9 | SUBSUBCONTENT | ||
10 | {% endblock %} | ||
11 | {% endblock %} | ||
12 | {% endblock %} | ||
13 | --TEMPLATE(foo.twig)-- | ||
14 | {% block content %} | ||
15 | {% block subcontent %} | ||
16 | SUBCONTENT | ||
17 | {% endblock %} | ||
18 | {% endblock %} | ||
19 | --DATA-- | ||
20 | return array() | ||
21 | --EXPECT-- | ||
22 | SUBSUBCONTENT | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/nested_blocks_parent_only.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/nested_blocks_parent_only.test new file mode 100644 index 00000000..0ad11d0c --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/nested_blocks_parent_only.test | |||
@@ -0,0 +1,15 @@ | |||
1 | --TEST-- | ||
2 | "block" tag | ||
3 | --TEMPLATE-- | ||
4 | {% block content %} | ||
5 | CONTENT | ||
6 | {%- block subcontent -%} | ||
7 | SUBCONTENT | ||
8 | {%- endblock -%} | ||
9 | ENDCONTENT | ||
10 | {% endblock %} | ||
11 | --TEMPLATE(foo.twig)-- | ||
12 | --DATA-- | ||
13 | return array() | ||
14 | --EXPECT-- | ||
15 | CONTENTSUBCONTENTENDCONTENT | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/nested_inheritance.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/nested_inheritance.test new file mode 100644 index 00000000..71e3cdfd --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/nested_inheritance.test | |||
@@ -0,0 +1,16 @@ | |||
1 | --TEST-- | ||
2 | "extends" tag | ||
3 | --TEMPLATE-- | ||
4 | {% extends "layout.twig" %} | ||
5 | {% block inside %}INSIDE{% endblock inside %} | ||
6 | --TEMPLATE(layout.twig)-- | ||
7 | {% extends "base.twig" %} | ||
8 | {% block body %} | ||
9 | {% block inside '' %} | ||
10 | {% endblock body %} | ||
11 | --TEMPLATE(base.twig)-- | ||
12 | {% block body '' %} | ||
13 | --DATA-- | ||
14 | return array() | ||
15 | --EXPECT-- | ||
16 | INSIDE | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/parent.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/parent.test new file mode 100644 index 00000000..4f975db8 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/parent.test | |||
@@ -0,0 +1,12 @@ | |||
1 | --TEST-- | ||
2 | "extends" tag | ||
3 | --TEMPLATE-- | ||
4 | {% extends "foo.twig" %} | ||
5 | |||
6 | {% block content %}{{ parent() }}FOO{{ parent() }}{% endblock %} | ||
7 | --TEMPLATE(foo.twig)-- | ||
8 | {% block content %}BAR{% endblock %} | ||
9 | --DATA-- | ||
10 | return array() | ||
11 | --EXPECT-- | ||
12 | BARFOOBAR | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/parent_change.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/parent_change.test new file mode 100644 index 00000000..a8bc90ce --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/parent_change.test | |||
@@ -0,0 +1,16 @@ | |||
1 | --TEST-- | ||
2 | "extends" tag | ||
3 | --TEMPLATE-- | ||
4 | {% extends foo ? 'foo.twig' : 'bar.twig' %} | ||
5 | --TEMPLATE(foo.twig)-- | ||
6 | FOO | ||
7 | --TEMPLATE(bar.twig)-- | ||
8 | BAR | ||
9 | --DATA-- | ||
10 | return array('foo' => true) | ||
11 | --EXPECT-- | ||
12 | FOO | ||
13 | --DATA-- | ||
14 | return array('foo' => false) | ||
15 | --EXPECT-- | ||
16 | BAR | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/parent_in_a_block.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/parent_in_a_block.test new file mode 100644 index 00000000..c9e86b1a --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/parent_in_a_block.test | |||
@@ -0,0 +1,8 @@ | |||
1 | --TEST-- | ||
2 | "extends" tag | ||
3 | --TEMPLATE-- | ||
4 | {% block content %} | ||
5 | {% extends "foo.twig" %} | ||
6 | {% endblock %} | ||
7 | --EXCEPTION-- | ||
8 | Twig_Error_Syntax: Cannot extend from a block in "index.twig" at line 3 | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/parent_isolation.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/parent_isolation.test new file mode 100644 index 00000000..62816713 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/parent_isolation.test | |||
@@ -0,0 +1,20 @@ | |||
1 | --TEST-- | ||
2 | "extends" tag | ||
3 | --TEMPLATE-- | ||
4 | {% extends "base.twig" %} | ||
5 | {% block content %}{% include "included.twig" %}{% endblock %} | ||
6 | |||
7 | {% block footer %}Footer{% endblock %} | ||
8 | --TEMPLATE(included.twig)-- | ||
9 | {% extends "base.twig" %} | ||
10 | {% block content %}Included Content{% endblock %} | ||
11 | --TEMPLATE(base.twig)-- | ||
12 | {% block content %}Default Content{% endblock %} | ||
13 | |||
14 | {% block footer %}Default Footer{% endblock %} | ||
15 | --DATA-- | ||
16 | return array() | ||
17 | --EXPECT-- | ||
18 | Included Content | ||
19 | Default Footer | ||
20 | Footer | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/parent_nested.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/parent_nested.test new file mode 100644 index 00000000..71e7c208 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/parent_nested.test | |||
@@ -0,0 +1,28 @@ | |||
1 | --TEST-- | ||
2 | "extends" tag | ||
3 | --TEMPLATE-- | ||
4 | {% extends "foo.twig" %} | ||
5 | |||
6 | {% block content %} | ||
7 | {% block inside %} | ||
8 | INSIDE OVERRIDDEN | ||
9 | {% endblock %} | ||
10 | |||
11 | BEFORE | ||
12 | {{ parent() }} | ||
13 | AFTER | ||
14 | {% endblock %} | ||
15 | --TEMPLATE(foo.twig)-- | ||
16 | {% block content %} | ||
17 | BAR | ||
18 | {% endblock %} | ||
19 | --DATA-- | ||
20 | return array() | ||
21 | --EXPECT-- | ||
22 | |||
23 | INSIDE OVERRIDDEN | ||
24 | |||
25 | BEFORE | ||
26 | BAR | ||
27 | |||
28 | AFTER | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/parent_without_extends.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/parent_without_extends.test new file mode 100644 index 00000000..a9eaa4c1 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/parent_without_extends.test | |||
@@ -0,0 +1,8 @@ | |||
1 | --TEST-- | ||
2 | "parent" tag | ||
3 | --TEMPLATE-- | ||
4 | {% block content %} | ||
5 | {{ parent() }} | ||
6 | {% endblock %} | ||
7 | --EXCEPTION-- | ||
8 | Twig_Error_Syntax: Calling "parent" on a template that does not extend nor "use" another template is forbidden in "index.twig" at line 3 | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/parent_without_extends_but_traits.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/parent_without_extends_but_traits.test new file mode 100644 index 00000000..63c73055 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/parent_without_extends_but_traits.test | |||
@@ -0,0 +1,14 @@ | |||
1 | --TEST-- | ||
2 | "parent" tag | ||
3 | --TEMPLATE-- | ||
4 | {% use 'foo.twig' %} | ||
5 | |||
6 | {% block content %} | ||
7 | {{ parent() }} | ||
8 | {% endblock %} | ||
9 | --TEMPLATE(foo.twig)-- | ||
10 | {% block content %}BAR{% endblock %} | ||
11 | --DATA-- | ||
12 | return array() | ||
13 | --EXPECT-- | ||
14 | BAR | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/template_instance.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/template_instance.test new file mode 100644 index 00000000..d1876a52 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/template_instance.test | |||
@@ -0,0 +1,14 @@ | |||
1 | --TEST-- | ||
2 | "extends" tag accepts Twig_Template instance | ||
3 | --TEMPLATE-- | ||
4 | {% extends foo %} | ||
5 | |||
6 | {% block content %} | ||
7 | {{ parent() }}FOO | ||
8 | {% endblock %} | ||
9 | --TEMPLATE(foo.twig)-- | ||
10 | {% block content %}BAR{% endblock %} | ||
11 | --DATA-- | ||
12 | return array('foo' => $twig->loadTemplate('foo.twig')) | ||
13 | --EXPECT-- | ||
14 | BARFOO | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/use.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/use.test new file mode 100644 index 00000000..8f9ece7c --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/use.test | |||
@@ -0,0 +1,44 @@ | |||
1 | --TEST-- | ||
2 | "parent" function | ||
3 | --TEMPLATE-- | ||
4 | {% extends "parent.twig" %} | ||
5 | |||
6 | {% use "use1.twig" %} | ||
7 | {% use "use2.twig" %} | ||
8 | |||
9 | {% block content_parent %} | ||
10 | {{ parent() }} | ||
11 | {% endblock %} | ||
12 | |||
13 | {% block content_use1 %} | ||
14 | {{ parent() }} | ||
15 | {% endblock %} | ||
16 | |||
17 | {% block content_use2 %} | ||
18 | {{ parent() }} | ||
19 | {% endblock %} | ||
20 | |||
21 | {% block content %} | ||
22 | {{ block('content_use1_only') }} | ||
23 | {{ block('content_use2_only') }} | ||
24 | {% endblock %} | ||
25 | --TEMPLATE(parent.twig)-- | ||
26 | {% block content_parent 'content_parent' %} | ||
27 | {% block content_use1 'content_parent' %} | ||
28 | {% block content_use2 'content_parent' %} | ||
29 | {% block content '' %} | ||
30 | --TEMPLATE(use1.twig)-- | ||
31 | {% block content_use1 'content_use1' %} | ||
32 | {% block content_use2 'content_use1' %} | ||
33 | {% block content_use1_only 'content_use1_only' %} | ||
34 | --TEMPLATE(use2.twig)-- | ||
35 | {% block content_use2 'content_use2' %} | ||
36 | {% block content_use2_only 'content_use2_only' %} | ||
37 | --DATA-- | ||
38 | return array() | ||
39 | --EXPECT-- | ||
40 | content_parent | ||
41 | content_use1 | ||
42 | content_use2 | ||
43 | content_use1_only | ||
44 | content_use2_only | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/macro/basic.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/macro/basic.test new file mode 100644 index 00000000..eef0c10d --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/macro/basic.test | |||
@@ -0,0 +1,17 @@ | |||
1 | --TEST-- | ||
2 | "macro" tag | ||
3 | --TEMPLATE-- | ||
4 | {% import _self as macros %} | ||
5 | |||
6 | {{ macros.input('username') }} | ||
7 | {{ macros.input('password', null, 'password', 1) }} | ||
8 | |||
9 | {% macro input(name, value, type, size) %} | ||
10 | <input type="{{ type|default("text") }}" name="{{ name }}" value="{{ value|e|default('') }}" size="{{ size|default(20) }}"> | ||
11 | {% endmacro %} | ||
12 | --DATA-- | ||
13 | return array() | ||
14 | --EXPECT-- | ||
15 | <input type="text" name="username" value="" size="20"> | ||
16 | |||
17 | <input type="password" name="password" value="" size="1"> | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/macro/endmacro_name.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/macro/endmacro_name.test new file mode 100644 index 00000000..ae6203bb --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/macro/endmacro_name.test | |||
@@ -0,0 +1,16 @@ | |||
1 | --TEST-- | ||
2 | "macro" tag supports name for endmacro | ||
3 | --TEMPLATE-- | ||
4 | {% import _self as macros %} | ||
5 | |||
6 | {{ macros.foo() }} | ||
7 | {{ macros.bar() }} | ||
8 | |||
9 | {% macro foo() %}foo{% endmacro %} | ||
10 | {% macro bar() %}bar{% endmacro bar %} | ||
11 | --DATA-- | ||
12 | return array() | ||
13 | --EXPECT-- | ||
14 | foo | ||
15 | bar | ||
16 | |||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/macro/external.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/macro/external.test new file mode 100644 index 00000000..5cd3dae6 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/macro/external.test | |||
@@ -0,0 +1,17 @@ | |||
1 | --TEST-- | ||
2 | "macro" tag | ||
3 | --TEMPLATE-- | ||
4 | {% import 'forms.twig' as forms %} | ||
5 | |||
6 | {{ forms.input('username') }} | ||
7 | {{ forms.input('password', null, 'password', 1) }} | ||
8 | --TEMPLATE(forms.twig)-- | ||
9 | {% macro input(name, value, type, size) %} | ||
10 | <input type="{{ type|default("text") }}" name="{{ name }}" value="{{ value|e|default('') }}" size="{{ size|default(20) }}"> | ||
11 | {% endmacro %} | ||
12 | --DATA-- | ||
13 | return array() | ||
14 | --EXPECT-- | ||
15 | <input type="text" name="username" value="" size="20"> | ||
16 | |||
17 | <input type="password" name="password" value="" size="1"> | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/macro/from.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/macro/from.test new file mode 100644 index 00000000..205f5918 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/macro/from.test | |||
@@ -0,0 +1,18 @@ | |||
1 | --TEST-- | ||
2 | "macro" tag | ||
3 | --TEMPLATE-- | ||
4 | {% from 'forms.twig' import foo %} | ||
5 | {% from 'forms.twig' import foo as foobar, bar %} | ||
6 | |||
7 | {{ foo('foo') }} | ||
8 | {{ foobar('foo') }} | ||
9 | {{ bar('foo') }} | ||
10 | --TEMPLATE(forms.twig)-- | ||
11 | {% macro foo(name) %}foo{{ name }}{% endmacro %} | ||
12 | {% macro bar(name) %}bar{{ name }}{% endmacro %} | ||
13 | --DATA-- | ||
14 | return array() | ||
15 | --EXPECT-- | ||
16 | foofoo | ||
17 | foofoo | ||
18 | barfoo | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/macro/global.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/macro/global.test new file mode 100644 index 00000000..6b371768 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/macro/global.test | |||
@@ -0,0 +1,14 @@ | |||
1 | --TEST-- | ||
2 | "macro" tag | ||
3 | --TEMPLATE-- | ||
4 | {% from 'forms.twig' import foo %} | ||
5 | |||
6 | {{ foo('foo') }} | ||
7 | {{ foo() }} | ||
8 | --TEMPLATE(forms.twig)-- | ||
9 | {% macro foo(name) %}{{ name|default('foo') }}{{ global }}{% endmacro %} | ||
10 | --DATA-- | ||
11 | return array() | ||
12 | --EXPECT-- | ||
13 | fooglobal | ||
14 | fooglobal | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/macro/self_import.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/macro/self_import.test new file mode 100644 index 00000000..17756cb6 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/macro/self_import.test | |||
@@ -0,0 +1,17 @@ | |||
1 | --TEST-- | ||
2 | "macro" tag | ||
3 | --TEMPLATE-- | ||
4 | {% import _self as forms %} | ||
5 | |||
6 | {{ forms.input('username') }} | ||
7 | {{ forms.input('password', null, 'password', 1) }} | ||
8 | |||
9 | {% macro input(name, value, type, size) %} | ||
10 | <input type="{{ type|default("text") }}" name="{{ name }}" value="{{ value|e|default('') }}" size="{{ size|default(20) }}"> | ||
11 | {% endmacro %} | ||
12 | --DATA-- | ||
13 | return array() | ||
14 | --EXPECT-- | ||
15 | <input type="text" name="username" value="" size="20"> | ||
16 | |||
17 | <input type="password" name="password" value="" size="1"> | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/macro/special_chars.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/macro/special_chars.test new file mode 100644 index 00000000..37217707 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/macro/special_chars.test | |||
@@ -0,0 +1,14 @@ | |||
1 | --TEST-- | ||
2 | "§" as a macro name | ||
3 | --TEMPLATE-- | ||
4 | {% import _self as macros %} | ||
5 | |||
6 | {{ macros.§('foo') }} | ||
7 | |||
8 | {% macro §(foo) %} | ||
9 | §{{ foo }}§ | ||
10 | {% endmacro %} | ||
11 | --DATA-- | ||
12 | return array() | ||
13 | --EXPECT-- | ||
14 | §foo§ | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/raw/basic.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/raw/basic.test new file mode 100644 index 00000000..0445e853 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/raw/basic.test | |||
@@ -0,0 +1,10 @@ | |||
1 | --TEST-- | ||
2 | "raw" tag | ||
3 | --TEMPLATE-- | ||
4 | {% raw %} | ||
5 | {{ foo }} | ||
6 | {% endraw %} | ||
7 | --DATA-- | ||
8 | return array() | ||
9 | --EXPECT-- | ||
10 | {{ foo }} | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/raw/mixed_usage_with_raw.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/raw/mixed_usage_with_raw.test new file mode 100644 index 00000000..2fd9fb26 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/raw/mixed_usage_with_raw.test | |||
@@ -0,0 +1,10 @@ | |||
1 | --TEST-- | ||
2 | "raw" tag | ||
3 | --TEMPLATE-- | ||
4 | {% raw %} | ||
5 | {{ foo }} | ||
6 | {% endverbatim %} | ||
7 | --DATA-- | ||
8 | return array() | ||
9 | --EXCEPTION-- | ||
10 | Twig_Error_Syntax: Unexpected end of file: Unclosed "raw" block in "index.twig" at line 2 | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/raw/whitespace_control.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/raw/whitespace_control.test new file mode 100644 index 00000000..352bb187 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/raw/whitespace_control.test | |||
@@ -0,0 +1,56 @@ | |||
1 | --TEST-- | ||
2 | "raw" tag | ||
3 | --TEMPLATE-- | ||
4 | 1*** | ||
5 | |||
6 | {%- raw %} | ||
7 | {{ 'bla' }} | ||
8 | {% endraw %} | ||
9 | |||
10 | 1*** | ||
11 | 2*** | ||
12 | |||
13 | {%- raw -%} | ||
14 | {{ 'bla' }} | ||
15 | {% endraw %} | ||
16 | |||
17 | 2*** | ||
18 | 3*** | ||
19 | |||
20 | {%- raw -%} | ||
21 | {{ 'bla' }} | ||
22 | {% endraw -%} | ||
23 | |||
24 | 3*** | ||
25 | 4*** | ||
26 | |||
27 | {%- raw -%} | ||
28 | {{ 'bla' }} | ||
29 | {%- endraw %} | ||
30 | |||
31 | 4*** | ||
32 | 5*** | ||
33 | |||
34 | {%- raw -%} | ||
35 | {{ 'bla' }} | ||
36 | {%- endraw -%} | ||
37 | |||
38 | 5*** | ||
39 | --DATA-- | ||
40 | return array() | ||
41 | --EXPECT-- | ||
42 | 1*** | ||
43 | {{ 'bla' }} | ||
44 | |||
45 | |||
46 | 1*** | ||
47 | 2***{{ 'bla' }} | ||
48 | |||
49 | |||
50 | 2*** | ||
51 | 3***{{ 'bla' }} | ||
52 | 3*** | ||
53 | 4***{{ 'bla' }} | ||
54 | |||
55 | 4*** | ||
56 | 5***{{ 'bla' }}5*** | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/sandbox/not_valid1.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/sandbox/not_valid1.test new file mode 100644 index 00000000..683c59a0 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/sandbox/not_valid1.test | |||
@@ -0,0 +1,11 @@ | |||
1 | --TEST-- | ||
2 | sandbox tag | ||
3 | --TEMPLATE-- | ||
4 | {%- sandbox %} | ||
5 | {%- include "foo.twig" %} | ||
6 | a | ||
7 | {%- endsandbox %} | ||
8 | --TEMPLATE(foo.twig)-- | ||
9 | foo | ||
10 | --EXCEPTION-- | ||
11 | Twig_Error_Syntax: Only "include" tags are allowed within a "sandbox" section in "index.twig" at line 4 | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/sandbox/not_valid2.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/sandbox/not_valid2.test new file mode 100644 index 00000000..3dcfa88c --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/sandbox/not_valid2.test | |||
@@ -0,0 +1,14 @@ | |||
1 | --TEST-- | ||
2 | sandbox tag | ||
3 | --TEMPLATE-- | ||
4 | {%- sandbox %} | ||
5 | {%- include "foo.twig" %} | ||
6 | |||
7 | {% if 1 %} | ||
8 | {%- include "foo.twig" %} | ||
9 | {% endif %} | ||
10 | {%- endsandbox %} | ||
11 | --TEMPLATE(foo.twig)-- | ||
12 | foo | ||
13 | --EXCEPTION-- | ||
14 | Twig_Error_Syntax: Only "include" tags are allowed within a "sandbox" section in "index.twig" at line 5 | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/sandbox/simple.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/sandbox/simple.test new file mode 100644 index 00000000..de20f3db --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/sandbox/simple.test | |||
@@ -0,0 +1,22 @@ | |||
1 | --TEST-- | ||
2 | sandbox tag | ||
3 | --TEMPLATE-- | ||
4 | {%- sandbox %} | ||
5 | {%- include "foo.twig" %} | ||
6 | {%- endsandbox %} | ||
7 | |||
8 | {%- sandbox %} | ||
9 | {%- include "foo.twig" %} | ||
10 | {%- include "foo.twig" %} | ||
11 | {%- endsandbox %} | ||
12 | |||
13 | {%- sandbox %}{% include "foo.twig" %}{% endsandbox %} | ||
14 | --TEMPLATE(foo.twig)-- | ||
15 | foo | ||
16 | --DATA-- | ||
17 | return array() | ||
18 | --EXPECT-- | ||
19 | foo | ||
20 | foo | ||
21 | foo | ||
22 | foo | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/set/basic.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/set/basic.test new file mode 100644 index 00000000..a5a9f830 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/set/basic.test | |||
@@ -0,0 +1,20 @@ | |||
1 | --TEST-- | ||
2 | "set" tag | ||
3 | --TEMPLATE-- | ||
4 | {% set foo = 'foo' %} | ||
5 | {% set bar = 'foo<br />' %} | ||
6 | |||
7 | {{ foo }} | ||
8 | {{ bar }} | ||
9 | |||
10 | {% set foo, bar = 'foo', 'bar' %} | ||
11 | |||
12 | {{ foo }}{{ bar }} | ||
13 | --DATA-- | ||
14 | return array() | ||
15 | --EXPECT-- | ||
16 | foo | ||
17 | foo<br /> | ||
18 | |||
19 | |||
20 | foobar | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/set/capture-empty.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/set/capture-empty.test new file mode 100644 index 00000000..ec657f00 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/set/capture-empty.test | |||
@@ -0,0 +1,9 @@ | |||
1 | --TEST-- | ||
2 | "set" tag block empty capture | ||
3 | --TEMPLATE-- | ||
4 | {% set foo %}{% endset %} | ||
5 | |||
6 | {% if foo %}FAIL{% endif %} | ||
7 | --DATA-- | ||
8 | return array() | ||
9 | --EXPECT-- | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/set/capture.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/set/capture.test new file mode 100644 index 00000000..f156a1a7 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/set/capture.test | |||
@@ -0,0 +1,10 @@ | |||
1 | --TEST-- | ||
2 | "set" tag block capture | ||
3 | --TEMPLATE-- | ||
4 | {% set foo %}f<br />o<br />o{% endset %} | ||
5 | |||
6 | {{ foo }} | ||
7 | --DATA-- | ||
8 | return array() | ||
9 | --EXPECT-- | ||
10 | f<br />o<br />o | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/set/expression.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/set/expression.test new file mode 100644 index 00000000..8ff434a0 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/set/expression.test | |||
@@ -0,0 +1,12 @@ | |||
1 | --TEST-- | ||
2 | "set" tag | ||
3 | --TEMPLATE-- | ||
4 | {% set foo, bar = 'foo' ~ 'bar', 'bar' ~ 'foo' %} | ||
5 | |||
6 | {{ foo }} | ||
7 | {{ bar }} | ||
8 | --DATA-- | ||
9 | return array() | ||
10 | --EXPECT-- | ||
11 | foobar | ||
12 | barfoo | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/spaceless/simple.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/spaceless/simple.test new file mode 100644 index 00000000..dd06dec2 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/spaceless/simple.test | |||
@@ -0,0 +1,12 @@ | |||
1 | --TEST-- | ||
2 | "spaceless" tag removes whites between HTML tags | ||
3 | --TEMPLATE-- | ||
4 | {% spaceless %} | ||
5 | |||
6 | <div> <div> foo </div> </div> | ||
7 | |||
8 | {% endspaceless %} | ||
9 | --DATA-- | ||
10 | return array() | ||
11 | --EXPECT-- | ||
12 | <div><div> foo </div></div> | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/special_chars.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/special_chars.test new file mode 100644 index 00000000..789b4ba8 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/special_chars.test | |||
@@ -0,0 +1,8 @@ | |||
1 | --TEST-- | ||
2 | "§" custom tag | ||
3 | --TEMPLATE-- | ||
4 | {% § %} | ||
5 | --DATA-- | ||
6 | return array() | ||
7 | --EXPECT-- | ||
8 | § | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/trim_block.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/trim_block.test new file mode 100644 index 00000000..1d2273f8 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/trim_block.test | |||
@@ -0,0 +1,74 @@ | |||
1 | --TEST-- | ||
2 | Whitespace trimming on tags. | ||
3 | --TEMPLATE-- | ||
4 | {{ 5 * '{#-'|length }} | ||
5 | {{ '{{-'|length * 5 + '{%-'|length }} | ||
6 | |||
7 | Trim on control tag: | ||
8 | {% for i in range(1, 9) -%} | ||
9 | {{ i }} | ||
10 | {%- endfor %} | ||
11 | |||
12 | |||
13 | Trim on output tag: | ||
14 | {% for i in range(1, 9) %} | ||
15 | {{- i -}} | ||
16 | {% endfor %} | ||
17 | |||
18 | |||
19 | Trim comments: | ||
20 | |||
21 | {#- Invisible -#} | ||
22 | |||
23 | After the comment. | ||
24 | |||
25 | Trim leading space: | ||
26 | {% if leading %} | ||
27 | |||
28 | {{- leading }} | ||
29 | {% endif %} | ||
30 | |||
31 | {%- if leading %} | ||
32 | {{- leading }} | ||
33 | |||
34 | {%- endif %} | ||
35 | |||
36 | |||
37 | Trim trailing space: | ||
38 | {% if trailing -%} | ||
39 | {{ trailing -}} | ||
40 | |||
41 | {% endif -%} | ||
42 | |||
43 | Combined: | ||
44 | |||
45 | {%- if both -%} | ||
46 | <ul> | ||
47 | <li> {{- both -}} </li> | ||
48 | </ul> | ||
49 | |||
50 | {%- endif -%} | ||
51 | |||
52 | end | ||
53 | --DATA-- | ||
54 | return array('leading' => 'leading space', 'trailing' => 'trailing space', 'both' => 'both') | ||
55 | --EXPECT-- | ||
56 | 15 | ||
57 | 18 | ||
58 | |||
59 | Trim on control tag: | ||
60 | 123456789 | ||
61 | |||
62 | Trim on output tag: | ||
63 | 123456789 | ||
64 | |||
65 | Trim comments:After the comment. | ||
66 | |||
67 | Trim leading space: | ||
68 | leading space | ||
69 | leading space | ||
70 | |||
71 | Trim trailing space: | ||
72 | trailing spaceCombined:<ul> | ||
73 | <li>both</li> | ||
74 | </ul>end | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/use/aliases.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/use/aliases.test new file mode 100644 index 00000000..f887006f --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/use/aliases.test | |||
@@ -0,0 +1,12 @@ | |||
1 | --TEST-- | ||
2 | "use" tag | ||
3 | --TEMPLATE-- | ||
4 | {% use "blocks.twig" with content as foo %} | ||
5 | |||
6 | {{ block('foo') }} | ||
7 | --TEMPLATE(blocks.twig)-- | ||
8 | {% block content 'foo' %} | ||
9 | --DATA-- | ||
10 | return array() | ||
11 | --EXPECT-- | ||
12 | foo | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/use/basic.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/use/basic.test new file mode 100644 index 00000000..7364d76d --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/use/basic.test | |||
@@ -0,0 +1,12 @@ | |||
1 | --TEST-- | ||
2 | "use" tag | ||
3 | --TEMPLATE-- | ||
4 | {% use "blocks.twig" %} | ||
5 | |||
6 | {{ block('content') }} | ||
7 | --TEMPLATE(blocks.twig)-- | ||
8 | {% block content 'foo' %} | ||
9 | --DATA-- | ||
10 | return array() | ||
11 | --EXPECT-- | ||
12 | foo | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/use/deep.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/use/deep.test new file mode 100644 index 00000000..b551a1e6 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/use/deep.test | |||
@@ -0,0 +1,22 @@ | |||
1 | --TEST-- | ||
2 | "use" tag | ||
3 | --TEMPLATE-- | ||
4 | {% use "foo.twig" %} | ||
5 | |||
6 | {{ block('content') }} | ||
7 | {{ block('foo') }} | ||
8 | {{ block('bar') }} | ||
9 | --TEMPLATE(foo.twig)-- | ||
10 | {% use "bar.twig" %} | ||
11 | |||
12 | {% block content 'foo' %} | ||
13 | {% block foo 'foo' %} | ||
14 | --TEMPLATE(bar.twig)-- | ||
15 | {% block content 'bar' %} | ||
16 | {% block bar 'bar' %} | ||
17 | --DATA-- | ||
18 | return array() | ||
19 | --EXPECT-- | ||
20 | foo | ||
21 | foo | ||
22 | bar | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/use/deep_empty.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/use/deep_empty.test new file mode 100644 index 00000000..05cca682 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/use/deep_empty.test | |||
@@ -0,0 +1,10 @@ | |||
1 | --TEST-- | ||
2 | "use" tag | ||
3 | --TEMPLATE-- | ||
4 | {% use "foo.twig" %} | ||
5 | --TEMPLATE(foo.twig)-- | ||
6 | {% use "bar.twig" %} | ||
7 | --TEMPLATE(bar.twig)-- | ||
8 | --DATA-- | ||
9 | return array() | ||
10 | --EXPECT-- | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/use/multiple.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/use/multiple.test new file mode 100644 index 00000000..198be0c5 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/use/multiple.test | |||
@@ -0,0 +1,21 @@ | |||
1 | --TEST-- | ||
2 | "use" tag | ||
3 | --TEMPLATE-- | ||
4 | {% use "foo.twig" %} | ||
5 | {% use "bar.twig" %} | ||
6 | |||
7 | {{ block('content') }} | ||
8 | {{ block('foo') }} | ||
9 | {{ block('bar') }} | ||
10 | --TEMPLATE(foo.twig)-- | ||
11 | {% block content 'foo' %} | ||
12 | {% block foo 'foo' %} | ||
13 | --TEMPLATE(bar.twig)-- | ||
14 | {% block content 'bar' %} | ||
15 | {% block bar 'bar' %} | ||
16 | --DATA-- | ||
17 | return array() | ||
18 | --EXPECT-- | ||
19 | bar | ||
20 | foo | ||
21 | bar | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/use/multiple_aliases.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/use/multiple_aliases.test new file mode 100644 index 00000000..8de871a8 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/use/multiple_aliases.test | |||
@@ -0,0 +1,23 @@ | |||
1 | --TEST-- | ||
2 | "use" tag | ||
3 | --TEMPLATE-- | ||
4 | {% use "foo.twig" with content as foo_content %} | ||
5 | {% use "bar.twig" %} | ||
6 | |||
7 | {{ block('content') }} | ||
8 | {{ block('foo') }} | ||
9 | {{ block('bar') }} | ||
10 | {{ block('foo_content') }} | ||
11 | --TEMPLATE(foo.twig)-- | ||
12 | {% block content 'foo' %} | ||
13 | {% block foo 'foo' %} | ||
14 | --TEMPLATE(bar.twig)-- | ||
15 | {% block content 'bar' %} | ||
16 | {% block bar 'bar' %} | ||
17 | --DATA-- | ||
18 | return array() | ||
19 | --EXPECT-- | ||
20 | bar | ||
21 | foo | ||
22 | bar | ||
23 | foo | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/verbatim/basic.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/verbatim/basic.test new file mode 100644 index 00000000..a95be557 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/verbatim/basic.test | |||
@@ -0,0 +1,10 @@ | |||
1 | --TEST-- | ||
2 | "verbatim" tag | ||
3 | --TEMPLATE-- | ||
4 | {% verbatim %} | ||
5 | {{ foo }} | ||
6 | {% endverbatim %} | ||
7 | --DATA-- | ||
8 | return array() | ||
9 | --EXPECT-- | ||
10 | {{ foo }} | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/verbatim/mixed_usage_with_raw.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/verbatim/mixed_usage_with_raw.test new file mode 100644 index 00000000..941dddcc --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/verbatim/mixed_usage_with_raw.test | |||
@@ -0,0 +1,10 @@ | |||
1 | --TEST-- | ||
2 | "verbatim" tag | ||
3 | --TEMPLATE-- | ||
4 | {% verbatim %} | ||
5 | {{ foo }} | ||
6 | {% endraw %} | ||
7 | --DATA-- | ||
8 | return array() | ||
9 | --EXCEPTION-- | ||
10 | Twig_Error_Syntax: Unexpected end of file: Unclosed "verbatim" block in "index.twig" at line 2 | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/verbatim/whitespace_control.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/verbatim/whitespace_control.test new file mode 100644 index 00000000..eb610444 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/verbatim/whitespace_control.test | |||
@@ -0,0 +1,56 @@ | |||
1 | --TEST-- | ||
2 | "verbatim" tag | ||
3 | --TEMPLATE-- | ||
4 | 1*** | ||
5 | |||
6 | {%- verbatim %} | ||
7 | {{ 'bla' }} | ||
8 | {% endverbatim %} | ||
9 | |||
10 | 1*** | ||
11 | 2*** | ||
12 | |||
13 | {%- verbatim -%} | ||
14 | {{ 'bla' }} | ||
15 | {% endverbatim %} | ||
16 | |||
17 | 2*** | ||
18 | 3*** | ||
19 | |||
20 | {%- verbatim -%} | ||
21 | {{ 'bla' }} | ||
22 | {% endverbatim -%} | ||
23 | |||
24 | 3*** | ||
25 | 4*** | ||
26 | |||
27 | {%- verbatim -%} | ||
28 | {{ 'bla' }} | ||
29 | {%- endverbatim %} | ||
30 | |||
31 | 4*** | ||
32 | 5*** | ||
33 | |||
34 | {%- verbatim -%} | ||
35 | {{ 'bla' }} | ||
36 | {%- endverbatim -%} | ||
37 | |||
38 | 5*** | ||
39 | --DATA-- | ||
40 | return array() | ||
41 | --EXPECT-- | ||
42 | 1*** | ||
43 | {{ 'bla' }} | ||
44 | |||
45 | |||
46 | 1*** | ||
47 | 2***{{ 'bla' }} | ||
48 | |||
49 | |||
50 | 2*** | ||
51 | 3***{{ 'bla' }} | ||
52 | 3*** | ||
53 | 4***{{ 'bla' }} | ||
54 | |||
55 | 4*** | ||
56 | 5***{{ 'bla' }}5*** | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tests/array.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tests/array.test new file mode 100644 index 00000000..1429d375 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tests/array.test | |||
@@ -0,0 +1,24 @@ | |||
1 | --TEST-- | ||
2 | array index test | ||
3 | --TEMPLATE-- | ||
4 | {% for key, value in days %} | ||
5 | {{ key }} | ||
6 | {% endfor %} | ||
7 | --DATA-- | ||
8 | return array('days' => array( | ||
9 | 1 => array('money' => 9), | ||
10 | 2 => array('money' => 21), | ||
11 | 3 => array('money' => 38), | ||
12 | 4 => array('money' => 6), | ||
13 | 18 => array('money' => 6), | ||
14 | 19 => array('money' => 3), | ||
15 | 31 => array('money' => 11), | ||
16 | )); | ||
17 | --EXPECT-- | ||
18 | 1 | ||
19 | 2 | ||
20 | 3 | ||
21 | 4 | ||
22 | 18 | ||
23 | 19 | ||
24 | 31 | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tests/constant.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tests/constant.test new file mode 100644 index 00000000..60218ac0 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tests/constant.test | |||
@@ -0,0 +1,14 @@ | |||
1 | --TEST-- | ||
2 | "const" test | ||
3 | --TEMPLATE-- | ||
4 | {{ 8 is constant('E_NOTICE') ? 'ok' : 'no' }} | ||
5 | {{ 'bar' is constant('TwigTestFoo::BAR_NAME') ? 'ok' : 'no' }} | ||
6 | {{ value is constant('TwigTestFoo::BAR_NAME') ? 'ok' : 'no' }} | ||
7 | {{ 2 is constant('ARRAY_AS_PROPS', object) ? 'ok' : 'no' }} | ||
8 | --DATA-- | ||
9 | return array('value' => 'bar', 'object' => new ArrayObject(array('hi'))); | ||
10 | --EXPECT-- | ||
11 | ok | ||
12 | ok | ||
13 | ok | ||
14 | ok \ No newline at end of file | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tests/defined.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tests/defined.test new file mode 100644 index 00000000..cbfe03de --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tests/defined.test | |||
@@ -0,0 +1,108 @@ | |||
1 | --TEST-- | ||
2 | "defined" test | ||
3 | --TEMPLATE-- | ||
4 | {{ definedVar is defined ? 'ok' : 'ko' }} | ||
5 | {{ definedVar is not defined ? 'ko' : 'ok' }} | ||
6 | {{ undefinedVar is defined ? 'ko' : 'ok' }} | ||
7 | {{ undefinedVar is not defined ? 'ok' : 'ko' }} | ||
8 | {{ zeroVar is defined ? 'ok' : 'ko' }} | ||
9 | {{ nullVar is defined ? 'ok' : 'ko' }} | ||
10 | {{ nested.definedVar is defined ? 'ok' : 'ko' }} | ||
11 | {{ nested['definedVar'] is defined ? 'ok' : 'ko' }} | ||
12 | {{ nested.definedVar is not defined ? 'ko' : 'ok' }} | ||
13 | {{ nested.undefinedVar is defined ? 'ko' : 'ok' }} | ||
14 | {{ nested['undefinedVar'] is defined ? 'ko' : 'ok' }} | ||
15 | {{ nested.undefinedVar is not defined ? 'ok' : 'ko' }} | ||
16 | {{ nested.zeroVar is defined ? 'ok' : 'ko' }} | ||
17 | {{ nested.nullVar is defined ? 'ok' : 'ko' }} | ||
18 | {{ nested.definedArray.0 is defined ? 'ok' : 'ko' }} | ||
19 | {{ nested['definedArray'][0] is defined ? 'ok' : 'ko' }} | ||
20 | {{ object.foo is defined ? 'ok' : 'ko' }} | ||
21 | {{ object.undefinedMethod is defined ? 'ko' : 'ok' }} | ||
22 | {{ object.getFoo() is defined ? 'ok' : 'ko' }} | ||
23 | {{ object.getFoo('a') is defined ? 'ok' : 'ko' }} | ||
24 | {{ object.undefinedMethod() is defined ? 'ko' : 'ok' }} | ||
25 | {{ object.undefinedMethod('a') is defined ? 'ko' : 'ok' }} | ||
26 | {{ object.self.foo is defined ? 'ok' : 'ko' }} | ||
27 | {{ object.self.undefinedMethod is defined ? 'ko' : 'ok' }} | ||
28 | {{ object.undefinedMethod.self is defined ? 'ko' : 'ok' }} | ||
29 | --DATA-- | ||
30 | return array( | ||
31 | 'definedVar' => 'defined', | ||
32 | 'zeroVar' => 0, | ||
33 | 'nullVar' => null, | ||
34 | 'nested' => array( | ||
35 | 'definedVar' => 'defined', | ||
36 | 'zeroVar' => 0, | ||
37 | 'nullVar' => null, | ||
38 | 'definedArray' => array(0), | ||
39 | ), | ||
40 | 'object' => new TwigTestFoo(), | ||
41 | ); | ||
42 | --EXPECT-- | ||
43 | ok | ||
44 | ok | ||
45 | ok | ||
46 | ok | ||
47 | ok | ||
48 | ok | ||
49 | ok | ||
50 | ok | ||
51 | ok | ||
52 | ok | ||
53 | ok | ||
54 | ok | ||
55 | ok | ||
56 | ok | ||
57 | ok | ||
58 | ok | ||
59 | ok | ||
60 | ok | ||
61 | ok | ||
62 | ok | ||
63 | ok | ||
64 | ok | ||
65 | ok | ||
66 | ok | ||
67 | ok | ||
68 | --DATA-- | ||
69 | return array( | ||
70 | 'definedVar' => 'defined', | ||
71 | 'zeroVar' => 0, | ||
72 | 'nullVar' => null, | ||
73 | 'nested' => array( | ||
74 | 'definedVar' => 'defined', | ||
75 | 'zeroVar' => 0, | ||
76 | 'nullVar' => null, | ||
77 | 'definedArray' => array(0), | ||
78 | ), | ||
79 | 'object' => new TwigTestFoo(), | ||
80 | ); | ||
81 | --CONFIG-- | ||
82 | return array('strict_variables' => false) | ||
83 | --EXPECT-- | ||
84 | ok | ||
85 | ok | ||
86 | ok | ||
87 | ok | ||
88 | ok | ||
89 | ok | ||
90 | ok | ||
91 | ok | ||
92 | ok | ||
93 | ok | ||
94 | ok | ||
95 | ok | ||
96 | ok | ||
97 | ok | ||
98 | ok | ||
99 | ok | ||
100 | ok | ||
101 | ok | ||
102 | ok | ||
103 | ok | ||
104 | ok | ||
105 | ok | ||
106 | ok | ||
107 | ok | ||
108 | ok | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tests/empty.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tests/empty.test new file mode 100644 index 00000000..a776d032 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tests/empty.test | |||
@@ -0,0 +1,45 @@ | |||
1 | --TEST-- | ||
2 | "empty" test | ||
3 | --TEMPLATE-- | ||
4 | {{ foo is empty ? 'ok' : 'ko' }} | ||
5 | {{ bar is empty ? 'ok' : 'ko' }} | ||
6 | {{ foobar is empty ? 'ok' : 'ko' }} | ||
7 | {{ array is empty ? 'ok' : 'ko' }} | ||
8 | {{ zero is empty ? 'ok' : 'ko' }} | ||
9 | {{ string is empty ? 'ok' : 'ko' }} | ||
10 | {{ countable_empty is empty ? 'ok' : 'ko' }} | ||
11 | {{ countable_not_empty is empty ? 'ok' : 'ko' }} | ||
12 | {{ markup_empty is empty ? 'ok' : 'ko' }} | ||
13 | {{ markup_not_empty is empty ? 'ok' : 'ko' }} | ||
14 | --DATA-- | ||
15 | |||
16 | class CountableStub implements Countable | ||
17 | { | ||
18 | private $items; | ||
19 | |||
20 | public function __construct(array $items) | ||
21 | { | ||
22 | $this->items = $items; | ||
23 | } | ||
24 | |||
25 | public function count() | ||
26 | { | ||
27 | return count($this->items); | ||
28 | } | ||
29 | } | ||
30 | return array( | ||
31 | 'foo' => '', 'bar' => null, 'foobar' => false, 'array' => array(), 'zero' => 0, 'string' => '0', | ||
32 | 'countable_empty' => new CountableStub(array()), 'countable_not_empty' => new CountableStub(array(1, 2)), | ||
33 | 'markup_empty' => new Twig_Markup('', 'UTF-8'), 'markup_not_empty' => new Twig_Markup('test', 'UTF-8'), | ||
34 | ); | ||
35 | --EXPECT-- | ||
36 | ok | ||
37 | ok | ||
38 | ok | ||
39 | ok | ||
40 | ko | ||
41 | ko | ||
42 | ok | ||
43 | ko | ||
44 | ok | ||
45 | ko | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tests/even.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tests/even.test new file mode 100644 index 00000000..695b4c2f --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tests/even.test | |||
@@ -0,0 +1,14 @@ | |||
1 | --TEST-- | ||
2 | "even" test | ||
3 | --TEMPLATE-- | ||
4 | {{ 1 is even ? 'ko' : 'ok' }} | ||
5 | {{ 2 is even ? 'ok' : 'ko' }} | ||
6 | {{ 1 is not even ? 'ok' : 'ko' }} | ||
7 | {{ 2 is not even ? 'ko' : 'ok' }} | ||
8 | --DATA-- | ||
9 | return array() | ||
10 | --EXPECT-- | ||
11 | ok | ||
12 | ok | ||
13 | ok | ||
14 | ok | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tests/in.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tests/in.test new file mode 100644 index 00000000..45c72fd2 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tests/in.test | |||
@@ -0,0 +1,48 @@ | |||
1 | --TEST-- | ||
2 | Twig supports the in operator | ||
3 | --TEMPLATE-- | ||
4 | {% if bar in foo %} | ||
5 | TRUE | ||
6 | {% endif %} | ||
7 | {% if not (bar in foo) %} | ||
8 | {% else %} | ||
9 | TRUE | ||
10 | {% endif %} | ||
11 | {% if bar not in foo %} | ||
12 | {% else %} | ||
13 | TRUE | ||
14 | {% endif %} | ||
15 | {% if 'a' in bar %} | ||
16 | TRUE | ||
17 | {% endif %} | ||
18 | {% if 'c' not in bar %} | ||
19 | TRUE | ||
20 | {% endif %} | ||
21 | {% if '' not in bar %} | ||
22 | TRUE | ||
23 | {% endif %} | ||
24 | {% if '' in '' %} | ||
25 | TRUE | ||
26 | {% endif %} | ||
27 | {% if '0' not in '' %} | ||
28 | TRUE | ||
29 | {% endif %} | ||
30 | {% if 'a' not in '0' %} | ||
31 | TRUE | ||
32 | {% endif %} | ||
33 | {% if '0' in '0' %} | ||
34 | TRUE | ||
35 | {% endif %} | ||
36 | --DATA-- | ||
37 | return array('bar' => 'bar', 'foo' => array('bar' => 'bar')) | ||
38 | --EXPECT-- | ||
39 | TRUE | ||
40 | TRUE | ||
41 | TRUE | ||
42 | TRUE | ||
43 | TRUE | ||
44 | TRUE | ||
45 | TRUE | ||
46 | TRUE | ||
47 | TRUE | ||
48 | TRUE | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tests/in_with_objects.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tests/in_with_objects.test new file mode 100644 index 00000000..8e08061b --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tests/in_with_objects.test | |||
@@ -0,0 +1,19 @@ | |||
1 | --TEST-- | ||
2 | Twig supports the in operator when using objects | ||
3 | --TEMPLATE-- | ||
4 | {% if object in object_list %} | ||
5 | TRUE | ||
6 | {% endif %} | ||
7 | --DATA-- | ||
8 | $foo = new TwigTestFoo(); | ||
9 | $foo1 = new TwigTestFoo(); | ||
10 | |||
11 | $foo->position = $foo1; | ||
12 | $foo1->position = $foo; | ||
13 | |||
14 | return array( | ||
15 | 'object' => $foo, | ||
16 | 'object_list' => array($foo1, $foo), | ||
17 | ); | ||
18 | --EXPECT-- | ||
19 | TRUE | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tests/iterable.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tests/iterable.test new file mode 100644 index 00000000..ec525501 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tests/iterable.test | |||
@@ -0,0 +1,19 @@ | |||
1 | --TEST-- | ||
2 | "iterable" test | ||
3 | --TEMPLATE-- | ||
4 | {{ foo is iterable ? 'ok' : 'ko' }} | ||
5 | {{ traversable is iterable ? 'ok' : 'ko' }} | ||
6 | {{ obj is iterable ? 'ok' : 'ko' }} | ||
7 | {{ val is iterable ? 'ok' : 'ko' }} | ||
8 | --DATA-- | ||
9 | return array( | ||
10 | 'foo' => array(), | ||
11 | 'traversable' => new ArrayIterator(array()), | ||
12 | 'obj' => new stdClass(), | ||
13 | 'val' => 'test', | ||
14 | ); | ||
15 | --EXPECT-- | ||
16 | ok | ||
17 | ok | ||
18 | ko | ||
19 | ko \ No newline at end of file | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Fixtures/tests/odd.test b/vendor/twig/twig/test/Twig/Tests/Fixtures/tests/odd.test new file mode 100644 index 00000000..1b8311e3 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Fixtures/tests/odd.test | |||
@@ -0,0 +1,10 @@ | |||
1 | --TEST-- | ||
2 | "odd" test | ||
3 | --TEMPLATE-- | ||
4 | {{ 1 is odd ? 'ok' : 'ko' }} | ||
5 | {{ 2 is odd ? 'ko' : 'ok' }} | ||
6 | --DATA-- | ||
7 | return array() | ||
8 | --EXPECT-- | ||
9 | ok | ||
10 | ok \ No newline at end of file | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/IntegrationTest.php b/vendor/twig/twig/test/Twig/Tests/IntegrationTest.php new file mode 100644 index 00000000..5feb8f4e --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/IntegrationTest.php | |||
@@ -0,0 +1,217 @@ | |||
1 | <?php | ||
2 | |||
3 | /* | ||
4 | * This file is part of Twig. | ||
5 | * | ||
6 | * (c) 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 | // This function is defined to check that escaping strategies | ||
13 | // like html works even if a function with the same name is defined. | ||
14 | function html() | ||
15 | { | ||
16 | return 'foo'; | ||
17 | } | ||
18 | |||
19 | class Twig_Tests_IntegrationTest extends Twig_Test_IntegrationTestCase | ||
20 | { | ||
21 | public function getExtensions() | ||
22 | { | ||
23 | $policy = new Twig_Sandbox_SecurityPolicy(array(), array(), array(), array(), array()); | ||
24 | |||
25 | return array( | ||
26 | new Twig_Extension_Debug(), | ||
27 | new Twig_Extension_Sandbox($policy, false), | ||
28 | new Twig_Extension_StringLoader(), | ||
29 | new TwigTestExtension(), | ||
30 | ); | ||
31 | } | ||
32 | |||
33 | public function getFixturesDir() | ||
34 | { | ||
35 | return dirname(__FILE__).'/Fixtures/'; | ||
36 | } | ||
37 | } | ||
38 | |||
39 | function test_foo($value = 'foo') | ||
40 | { | ||
41 | return $value; | ||
42 | } | ||
43 | |||
44 | class TwigTestFoo implements Iterator | ||
45 | { | ||
46 | const BAR_NAME = 'bar'; | ||
47 | |||
48 | public $position = 0; | ||
49 | public $array = array(1, 2); | ||
50 | |||
51 | public function bar($param1 = null, $param2 = null) | ||
52 | { | ||
53 | return 'bar'.($param1 ? '_'.$param1 : '').($param2 ? '-'.$param2 : ''); | ||
54 | } | ||
55 | |||
56 | public function getFoo() | ||
57 | { | ||
58 | return 'foo'; | ||
59 | } | ||
60 | |||
61 | public function getSelf() | ||
62 | { | ||
63 | return $this; | ||
64 | } | ||
65 | |||
66 | public function is() | ||
67 | { | ||
68 | return 'is'; | ||
69 | } | ||
70 | |||
71 | public function in() | ||
72 | { | ||
73 | return 'in'; | ||
74 | } | ||
75 | |||
76 | public function not() | ||
77 | { | ||
78 | return 'not'; | ||
79 | } | ||
80 | |||
81 | public function strToLower($value) | ||
82 | { | ||
83 | return strtolower($value); | ||
84 | } | ||
85 | |||
86 | public function rewind() | ||
87 | { | ||
88 | $this->position = 0; | ||
89 | } | ||
90 | |||
91 | public function current() | ||
92 | { | ||
93 | return $this->array[$this->position]; | ||
94 | } | ||
95 | |||
96 | public function key() | ||
97 | { | ||
98 | return 'a'; | ||
99 | } | ||
100 | |||
101 | public function next() | ||
102 | { | ||
103 | ++$this->position; | ||
104 | } | ||
105 | |||
106 | public function valid() | ||
107 | { | ||
108 | return isset($this->array[$this->position]); | ||
109 | } | ||
110 | } | ||
111 | |||
112 | class TwigTestTokenParser_§ extends Twig_TokenParser | ||
113 | { | ||
114 | public function parse(Twig_Token $token) | ||
115 | { | ||
116 | $this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE); | ||
117 | |||
118 | return new Twig_Node_Print(new Twig_Node_Expression_Constant('§', -1), -1); | ||
119 | } | ||
120 | |||
121 | public function getTag() | ||
122 | { | ||
123 | return '§'; | ||
124 | } | ||
125 | } | ||
126 | |||
127 | class TwigTestExtension extends Twig_Extension | ||
128 | { | ||
129 | public function getTokenParsers() | ||
130 | { | ||
131 | return array( | ||
132 | new TwigTestTokenParser_§(), | ||
133 | ); | ||
134 | } | ||
135 | |||
136 | public function getFilters() | ||
137 | { | ||
138 | return array( | ||
139 | '§' => new Twig_Filter_Method($this, '§Filter'), | ||
140 | 'escape_and_nl2br' => new Twig_Filter_Method($this, 'escape_and_nl2br', array('needs_environment' => true, 'is_safe' => array('html'))), | ||
141 | 'nl2br' => new Twig_Filter_Method($this, 'nl2br', array('pre_escape' => 'html', 'is_safe' => array('html'))), | ||
142 | 'escape_something' => new Twig_Filter_Method($this, 'escape_something', array('is_safe' => array('something'))), | ||
143 | 'preserves_safety' => new Twig_Filter_Method($this, 'preserves_safety', array('preserves_safety' => array('html'))), | ||
144 | '*_path' => new Twig_Filter_Method($this, 'dynamic_path'), | ||
145 | '*_foo_*_bar' => new Twig_Filter_Method($this, 'dynamic_foo'), | ||
146 | ); | ||
147 | } | ||
148 | |||
149 | public function getFunctions() | ||
150 | { | ||
151 | return array( | ||
152 | '§' => new Twig_Function_Method($this, '§Function'), | ||
153 | 'safe_br' => new Twig_Function_Method($this, 'br', array('is_safe' => array('html'))), | ||
154 | 'unsafe_br' => new Twig_Function_Method($this, 'br'), | ||
155 | '*_path' => new Twig_Function_Method($this, 'dynamic_path'), | ||
156 | '*_foo_*_bar' => new Twig_Function_Method($this, 'dynamic_foo'), | ||
157 | ); | ||
158 | } | ||
159 | |||
160 | public function §Filter($value) | ||
161 | { | ||
162 | return "§{$value}§"; | ||
163 | } | ||
164 | |||
165 | public function §Function($value) | ||
166 | { | ||
167 | return "§{$value}§"; | ||
168 | } | ||
169 | |||
170 | /** | ||
171 | * nl2br which also escapes, for testing escaper filters | ||
172 | */ | ||
173 | public function escape_and_nl2br($env, $value, $sep = '<br />') | ||
174 | { | ||
175 | return $this->nl2br(twig_escape_filter($env, $value, 'html'), $sep); | ||
176 | } | ||
177 | |||
178 | /** | ||
179 | * nl2br only, for testing filters with pre_escape | ||
180 | */ | ||
181 | public function nl2br($value, $sep = '<br />') | ||
182 | { | ||
183 | // not secure if $value contains html tags (not only entities) | ||
184 | // don't use | ||
185 | return str_replace("\n", "$sep\n", $value); | ||
186 | } | ||
187 | |||
188 | public function dynamic_path($element, $item) | ||
189 | { | ||
190 | return $element.'/'.$item; | ||
191 | } | ||
192 | |||
193 | public function dynamic_foo($foo, $bar, $item) | ||
194 | { | ||
195 | return $foo.'/'.$bar.'/'.$item; | ||
196 | } | ||
197 | |||
198 | public function escape_something($value) | ||
199 | { | ||
200 | return strtoupper($value); | ||
201 | } | ||
202 | |||
203 | public function preserves_safety($value) | ||
204 | { | ||
205 | return strtoupper($value); | ||
206 | } | ||
207 | |||
208 | public function br() | ||
209 | { | ||
210 | return '<br />'; | ||
211 | } | ||
212 | |||
213 | public function getName() | ||
214 | { | ||
215 | return 'integration_test'; | ||
216 | } | ||
217 | } | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/LexerTest.php b/vendor/twig/twig/test/Twig/Tests/LexerTest.php new file mode 100644 index 00000000..9f3c7510 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/LexerTest.php | |||
@@ -0,0 +1,301 @@ | |||
1 | <?php | ||
2 | |||
3 | /* | ||
4 | * This file is part of Twig. | ||
5 | * | ||
6 | * (c) 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_Tests_LexerTest extends PHPUnit_Framework_TestCase | ||
12 | { | ||
13 | public function testNameLabelForTag() | ||
14 | { | ||
15 | $template = '{% § %}'; | ||
16 | |||
17 | $lexer = new Twig_Lexer(new Twig_Environment()); | ||
18 | $stream = $lexer->tokenize($template); | ||
19 | |||
20 | $stream->expect(Twig_Token::BLOCK_START_TYPE); | ||
21 | $this->assertSame('§', $stream->expect(Twig_Token::NAME_TYPE)->getValue()); | ||
22 | } | ||
23 | |||
24 | public function testNameLabelForFunction() | ||
25 | { | ||
26 | $template = '{{ §() }}'; | ||
27 | |||
28 | $lexer = new Twig_Lexer(new Twig_Environment()); | ||
29 | $stream = $lexer->tokenize($template); | ||
30 | |||
31 | $stream->expect(Twig_Token::VAR_START_TYPE); | ||
32 | $this->assertSame('§', $stream->expect(Twig_Token::NAME_TYPE)->getValue()); | ||
33 | } | ||
34 | |||
35 | public function testBracketsNesting() | ||
36 | { | ||
37 | $template = '{{ {"a":{"b":"c"}} }}'; | ||
38 | |||
39 | $this->assertEquals(2, $this->countToken($template, Twig_Token::PUNCTUATION_TYPE, '{')); | ||
40 | $this->assertEquals(2, $this->countToken($template, Twig_Token::PUNCTUATION_TYPE, '}')); | ||
41 | } | ||
42 | |||
43 | protected function countToken($template, $type, $value = null) | ||
44 | { | ||
45 | $lexer = new Twig_Lexer(new Twig_Environment()); | ||
46 | $stream = $lexer->tokenize($template); | ||
47 | |||
48 | $count = 0; | ||
49 | $tokens = array(); | ||
50 | while (!$stream->isEOF()) { | ||
51 | $token = $stream->next(); | ||
52 | if ($type === $token->getType()) { | ||
53 | if (null === $value || $value === $token->getValue()) { | ||
54 | ++$count; | ||
55 | } | ||
56 | } | ||
57 | } | ||
58 | |||
59 | return $count; | ||
60 | } | ||
61 | |||
62 | public function testLineDirective() | ||
63 | { | ||
64 | $template = "foo\n" | ||
65 | . "bar\n" | ||
66 | . "{% line 10 %}\n" | ||
67 | . "{{\n" | ||
68 | . "baz\n" | ||
69 | . "}}\n"; | ||
70 | |||
71 | $lexer = new Twig_Lexer(new Twig_Environment()); | ||
72 | $stream = $lexer->tokenize($template); | ||
73 | |||
74 | // foo\nbar\n | ||
75 | $this->assertSame(1, $stream->expect(Twig_Token::TEXT_TYPE)->getLine()); | ||
76 | // \n (after {% line %}) | ||
77 | $this->assertSame(10, $stream->expect(Twig_Token::TEXT_TYPE)->getLine()); | ||
78 | // {{ | ||
79 | $this->assertSame(11, $stream->expect(Twig_Token::VAR_START_TYPE)->getLine()); | ||
80 | // baz | ||
81 | $this->assertSame(12, $stream->expect(Twig_Token::NAME_TYPE)->getLine()); | ||
82 | } | ||
83 | |||
84 | public function testLineDirectiveInline() | ||
85 | { | ||
86 | $template = "foo\n" | ||
87 | . "bar{% line 10 %}{{\n" | ||
88 | . "baz\n" | ||
89 | . "}}\n"; | ||
90 | |||
91 | $lexer = new Twig_Lexer(new Twig_Environment()); | ||
92 | $stream = $lexer->tokenize($template); | ||
93 | |||
94 | // foo\nbar | ||
95 | $this->assertSame(1, $stream->expect(Twig_Token::TEXT_TYPE)->getLine()); | ||
96 | // {{ | ||
97 | $this->assertSame(10, $stream->expect(Twig_Token::VAR_START_TYPE)->getLine()); | ||
98 | // baz | ||
99 | $this->assertSame(11, $stream->expect(Twig_Token::NAME_TYPE)->getLine()); | ||
100 | } | ||
101 | |||
102 | public function testLongComments() | ||
103 | { | ||
104 | $template = '{# '.str_repeat('*', 100000).' #}'; | ||
105 | |||
106 | $lexer = new Twig_Lexer(new Twig_Environment()); | ||
107 | $lexer->tokenize($template); | ||
108 | |||
109 | // should not throw an exception | ||
110 | } | ||
111 | |||
112 | public function testLongRaw() | ||
113 | { | ||
114 | $template = '{% raw %}'.str_repeat('*', 100000).'{% endraw %}'; | ||
115 | |||
116 | $lexer = new Twig_Lexer(new Twig_Environment()); | ||
117 | $stream = $lexer->tokenize($template); | ||
118 | |||
119 | // should not throw an exception | ||
120 | } | ||
121 | |||
122 | public function testLongVar() | ||
123 | { | ||
124 | $template = '{{ '.str_repeat('x', 100000).' }}'; | ||
125 | |||
126 | $lexer = new Twig_Lexer(new Twig_Environment()); | ||
127 | $stream = $lexer->tokenize($template); | ||
128 | |||
129 | // should not throw an exception | ||
130 | } | ||
131 | |||
132 | public function testLongBlock() | ||
133 | { | ||
134 | $template = '{% '.str_repeat('x', 100000).' %}'; | ||
135 | |||
136 | $lexer = new Twig_Lexer(new Twig_Environment()); | ||
137 | $stream = $lexer->tokenize($template); | ||
138 | |||
139 | // should not throw an exception | ||
140 | } | ||
141 | |||
142 | public function testBigNumbers() | ||
143 | { | ||
144 | $template = '{{ 922337203685477580700 }}'; | ||
145 | |||
146 | $lexer = new Twig_Lexer(new Twig_Environment()); | ||
147 | $stream = $lexer->tokenize($template); | ||
148 | $node = $stream->next(); | ||
149 | $node = $stream->next(); | ||
150 | $this->assertEquals(922337203685477580700, $node->getValue()); | ||
151 | } | ||
152 | |||
153 | public function testStringWithEscapedDelimiter() | ||
154 | { | ||
155 | $tests = array( | ||
156 | "{{ 'foo \' bar' }}" => 'foo \' bar', | ||
157 | '{{ "foo \" bar" }}' => "foo \" bar", | ||
158 | ); | ||
159 | $lexer = new Twig_Lexer(new Twig_Environment()); | ||
160 | foreach ($tests as $template => $expected) { | ||
161 | $stream = $lexer->tokenize($template); | ||
162 | $stream->expect(Twig_Token::VAR_START_TYPE); | ||
163 | $stream->expect(Twig_Token::STRING_TYPE, $expected); | ||
164 | } | ||
165 | } | ||
166 | |||
167 | public function testStringWithInterpolation() | ||
168 | { | ||
169 | $template = 'foo {{ "bar #{ baz + 1 }" }}'; | ||
170 | |||
171 | $lexer = new Twig_Lexer(new Twig_Environment()); | ||
172 | $stream = $lexer->tokenize($template); | ||
173 | $stream->expect(Twig_Token::TEXT_TYPE, 'foo '); | ||
174 | $stream->expect(Twig_Token::VAR_START_TYPE); | ||
175 | $stream->expect(Twig_Token::STRING_TYPE, 'bar '); | ||
176 | $stream->expect(Twig_Token::INTERPOLATION_START_TYPE); | ||
177 | $stream->expect(Twig_Token::NAME_TYPE, 'baz'); | ||
178 | $stream->expect(Twig_Token::OPERATOR_TYPE, '+'); | ||
179 | $stream->expect(Twig_Token::NUMBER_TYPE, '1'); | ||
180 | $stream->expect(Twig_Token::INTERPOLATION_END_TYPE); | ||
181 | $stream->expect(Twig_Token::VAR_END_TYPE); | ||
182 | } | ||
183 | |||
184 | public function testStringWithEscapedInterpolation() | ||
185 | { | ||
186 | $template = '{{ "bar \#{baz+1}" }}'; | ||
187 | |||
188 | $lexer = new Twig_Lexer(new Twig_Environment()); | ||
189 | $stream = $lexer->tokenize($template); | ||
190 | $stream->expect(Twig_Token::VAR_START_TYPE); | ||
191 | $stream->expect(Twig_Token::STRING_TYPE, 'bar #{baz+1}'); | ||
192 | $stream->expect(Twig_Token::VAR_END_TYPE); | ||
193 | } | ||
194 | |||
195 | public function testStringWithHash() | ||
196 | { | ||
197 | $template = '{{ "bar # baz" }}'; | ||
198 | |||
199 | $lexer = new Twig_Lexer(new Twig_Environment()); | ||
200 | $stream = $lexer->tokenize($template); | ||
201 | $stream->expect(Twig_Token::VAR_START_TYPE); | ||
202 | $stream->expect(Twig_Token::STRING_TYPE, 'bar # baz'); | ||
203 | $stream->expect(Twig_Token::VAR_END_TYPE); | ||
204 | } | ||
205 | |||
206 | /** | ||
207 | * @expectedException Twig_Error_Syntax | ||
208 | * @expectedExceptionMessage Unclosed """ | ||
209 | */ | ||
210 | public function testStringWithUnterminatedInterpolation() | ||
211 | { | ||
212 | $template = '{{ "bar #{x" }}'; | ||
213 | |||
214 | $lexer = new Twig_Lexer(new Twig_Environment()); | ||
215 | $stream = $lexer->tokenize($template); | ||
216 | } | ||
217 | |||
218 | public function testStringWithNestedInterpolations() | ||
219 | { | ||
220 | $template = '{{ "bar #{ "foo#{bar}" }" }}'; | ||
221 | |||
222 | $lexer = new Twig_Lexer(new Twig_Environment()); | ||
223 | $stream = $lexer->tokenize($template); | ||
224 | $stream->expect(Twig_Token::VAR_START_TYPE); | ||
225 | $stream->expect(Twig_Token::STRING_TYPE, 'bar '); | ||
226 | $stream->expect(Twig_Token::INTERPOLATION_START_TYPE); | ||
227 | $stream->expect(Twig_Token::STRING_TYPE, 'foo'); | ||
228 | $stream->expect(Twig_Token::INTERPOLATION_START_TYPE); | ||
229 | $stream->expect(Twig_Token::NAME_TYPE, 'bar'); | ||
230 | $stream->expect(Twig_Token::INTERPOLATION_END_TYPE); | ||
231 | $stream->expect(Twig_Token::INTERPOLATION_END_TYPE); | ||
232 | $stream->expect(Twig_Token::VAR_END_TYPE); | ||
233 | } | ||
234 | |||
235 | public function testStringWithNestedInterpolationsInBlock() | ||
236 | { | ||
237 | $template = '{% foo "bar #{ "foo#{bar}" }" %}'; | ||
238 | |||
239 | $lexer = new Twig_Lexer(new Twig_Environment()); | ||
240 | $stream = $lexer->tokenize($template); | ||
241 | $stream->expect(Twig_Token::BLOCK_START_TYPE); | ||
242 | $stream->expect(Twig_Token::NAME_TYPE, 'foo'); | ||
243 | $stream->expect(Twig_Token::STRING_TYPE, 'bar '); | ||
244 | $stream->expect(Twig_Token::INTERPOLATION_START_TYPE); | ||
245 | $stream->expect(Twig_Token::STRING_TYPE, 'foo'); | ||
246 | $stream->expect(Twig_Token::INTERPOLATION_START_TYPE); | ||
247 | $stream->expect(Twig_Token::NAME_TYPE, 'bar'); | ||
248 | $stream->expect(Twig_Token::INTERPOLATION_END_TYPE); | ||
249 | $stream->expect(Twig_Token::INTERPOLATION_END_TYPE); | ||
250 | $stream->expect(Twig_Token::BLOCK_END_TYPE); | ||
251 | } | ||
252 | |||
253 | public function testOperatorEndingWithALetterAtTheEndOfALine() | ||
254 | { | ||
255 | $template = "{{ 1 and\n0}}"; | ||
256 | |||
257 | $lexer = new Twig_Lexer(new Twig_Environment()); | ||
258 | $stream = $lexer->tokenize($template); | ||
259 | $stream->expect(Twig_Token::VAR_START_TYPE); | ||
260 | $stream->expect(Twig_Token::NUMBER_TYPE, 1); | ||
261 | $stream->expect(Twig_Token::OPERATOR_TYPE, 'and'); | ||
262 | } | ||
263 | |||
264 | /** | ||
265 | * @expectedException Twig_Error_Syntax | ||
266 | * @expectedExceptionMessage Unclosed "variable" at line 3 | ||
267 | */ | ||
268 | public function testUnterminatedVariable() | ||
269 | { | ||
270 | $template = ' | ||
271 | |||
272 | {{ | ||
273 | |||
274 | bar | ||
275 | |||
276 | |||
277 | '; | ||
278 | |||
279 | $lexer = new Twig_Lexer(new Twig_Environment()); | ||
280 | $stream = $lexer->tokenize($template); | ||
281 | } | ||
282 | |||
283 | /** | ||
284 | * @expectedException Twig_Error_Syntax | ||
285 | * @expectedExceptionMessage Unclosed "block" at line 3 | ||
286 | */ | ||
287 | public function testUnterminatedBlock() | ||
288 | { | ||
289 | $template = ' | ||
290 | |||
291 | {% | ||
292 | |||
293 | bar | ||
294 | |||
295 | |||
296 | '; | ||
297 | |||
298 | $lexer = new Twig_Lexer(new Twig_Environment()); | ||
299 | $stream = $lexer->tokenize($template); | ||
300 | } | ||
301 | } | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Loader/ArrayTest.php b/vendor/twig/twig/test/Twig/Tests/Loader/ArrayTest.php new file mode 100644 index 00000000..1369a6bd --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Loader/ArrayTest.php | |||
@@ -0,0 +1,97 @@ | |||
1 | <?php | ||
2 | |||
3 | /* | ||
4 | * This file is part of Twig. | ||
5 | * | ||
6 | * (c) 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_Tests_Loader_ArrayTest extends PHPUnit_Framework_TestCase | ||
13 | { | ||
14 | public function testGetSource() | ||
15 | { | ||
16 | $loader = new Twig_Loader_Array(array('foo' => 'bar')); | ||
17 | |||
18 | $this->assertEquals('bar', $loader->getSource('foo')); | ||
19 | } | ||
20 | |||
21 | /** | ||
22 | * @expectedException Twig_Error_Loader | ||
23 | */ | ||
24 | public function testGetSourceWhenTemplateDoesNotExist() | ||
25 | { | ||
26 | $loader = new Twig_Loader_Array(array()); | ||
27 | |||
28 | $loader->getSource('foo'); | ||
29 | } | ||
30 | |||
31 | public function testGetCacheKey() | ||
32 | { | ||
33 | $loader = new Twig_Loader_Array(array('foo' => 'bar')); | ||
34 | |||
35 | $this->assertEquals('bar', $loader->getCacheKey('foo')); | ||
36 | } | ||
37 | |||
38 | /** | ||
39 | * @expectedException Twig_Error_Loader | ||
40 | */ | ||
41 | public function testGetCacheKeyWhenTemplateDoesNotExist() | ||
42 | { | ||
43 | $loader = new Twig_Loader_Array(array()); | ||
44 | |||
45 | $loader->getCacheKey('foo'); | ||
46 | } | ||
47 | |||
48 | public function testSetTemplate() | ||
49 | { | ||
50 | $loader = new Twig_Loader_Array(array()); | ||
51 | $loader->setTemplate('foo', 'bar'); | ||
52 | |||
53 | $this->assertEquals('bar', $loader->getSource('foo')); | ||
54 | } | ||
55 | |||
56 | public function testIsFresh() | ||
57 | { | ||
58 | $loader = new Twig_Loader_Array(array('foo' => 'bar')); | ||
59 | $this->assertTrue($loader->isFresh('foo', time())); | ||
60 | } | ||
61 | |||
62 | /** | ||
63 | * @expectedException Twig_Error_Loader | ||
64 | */ | ||
65 | public function testIsFreshWhenTemplateDoesNotExist() | ||
66 | { | ||
67 | $loader = new Twig_Loader_Array(array()); | ||
68 | |||
69 | $loader->isFresh('foo', time()); | ||
70 | } | ||
71 | |||
72 | public function testTemplateReference() | ||
73 | { | ||
74 | $name = new Twig_Test_Loader_TemplateReference('foo'); | ||
75 | $loader = new Twig_Loader_Array(array('foo' => 'bar')); | ||
76 | |||
77 | $loader->getCacheKey($name); | ||
78 | $loader->getSource($name); | ||
79 | $loader->isFresh($name, time()); | ||
80 | $loader->setTemplate($name, 'foobar'); | ||
81 | } | ||
82 | } | ||
83 | |||
84 | class Twig_Test_Loader_TemplateReference | ||
85 | { | ||
86 | private $name; | ||
87 | |||
88 | public function __construct($name) | ||
89 | { | ||
90 | $this->name = $name; | ||
91 | } | ||
92 | |||
93 | public function __toString() | ||
94 | { | ||
95 | return $this->name; | ||
96 | } | ||
97 | } | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Loader/ChainTest.php b/vendor/twig/twig/test/Twig/Tests/Loader/ChainTest.php new file mode 100644 index 00000000..4fe0db94 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Loader/ChainTest.php | |||
@@ -0,0 +1,79 @@ | |||
1 | <?php | ||
2 | |||
3 | /* | ||
4 | * This file is part of Twig. | ||
5 | * | ||
6 | * (c) 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_Tests_Loader_ChainTest extends PHPUnit_Framework_TestCase | ||
13 | { | ||
14 | public function testGetSource() | ||
15 | { | ||
16 | $loader = new Twig_Loader_Chain(array( | ||
17 | new Twig_Loader_Array(array('foo' => 'bar')), | ||
18 | new Twig_Loader_Array(array('foo' => 'foobar', 'bar' => 'foo')), | ||
19 | )); | ||
20 | |||
21 | $this->assertEquals('bar', $loader->getSource('foo')); | ||
22 | $this->assertEquals('foo', $loader->getSource('bar')); | ||
23 | } | ||
24 | |||
25 | /** | ||
26 | * @expectedException Twig_Error_Loader | ||
27 | */ | ||
28 | public function testGetSourceWhenTemplateDoesNotExist() | ||
29 | { | ||
30 | $loader = new Twig_Loader_Chain(array()); | ||
31 | |||
32 | $loader->getSource('foo'); | ||
33 | } | ||
34 | |||
35 | public function testGetCacheKey() | ||
36 | { | ||
37 | $loader = new Twig_Loader_Chain(array( | ||
38 | new Twig_Loader_Array(array('foo' => 'bar')), | ||
39 | new Twig_Loader_Array(array('foo' => 'foobar', 'bar' => 'foo')), | ||
40 | )); | ||
41 | |||
42 | $this->assertEquals('bar', $loader->getCacheKey('foo')); | ||
43 | $this->assertEquals('foo', $loader->getCacheKey('bar')); | ||
44 | } | ||
45 | |||
46 | /** | ||
47 | * @expectedException Twig_Error_Loader | ||
48 | */ | ||
49 | public function testGetCacheKeyWhenTemplateDoesNotExist() | ||
50 | { | ||
51 | $loader = new Twig_Loader_Chain(array()); | ||
52 | |||
53 | $loader->getCacheKey('foo'); | ||
54 | } | ||
55 | |||
56 | public function testAddLoader() | ||
57 | { | ||
58 | $loader = new Twig_Loader_Chain(); | ||
59 | $loader->addLoader(new Twig_Loader_Array(array('foo' => 'bar'))); | ||
60 | |||
61 | $this->assertEquals('bar', $loader->getSource('foo')); | ||
62 | } | ||
63 | |||
64 | public function testExists() | ||
65 | { | ||
66 | $loader1 = $this->getMock('Twig_Loader_Array', array('exists', 'getSource'), array(), '', false); | ||
67 | $loader1->expects($this->once())->method('exists')->will($this->returnValue(false)); | ||
68 | $loader1->expects($this->never())->method('getSource'); | ||
69 | |||
70 | $loader2 = $this->getMock('Twig_LoaderInterface'); | ||
71 | $loader2->expects($this->once())->method('getSource')->will($this->returnValue('content')); | ||
72 | |||
73 | $loader = new Twig_Loader_Chain(); | ||
74 | $loader->addLoader($loader1); | ||
75 | $loader->addLoader($loader2); | ||
76 | |||
77 | $this->assertTrue($loader->exists('foo')); | ||
78 | } | ||
79 | } | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Loader/FilesystemTest.php b/vendor/twig/twig/test/Twig/Tests/Loader/FilesystemTest.php new file mode 100644 index 00000000..4c874b6b --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Loader/FilesystemTest.php | |||
@@ -0,0 +1,97 @@ | |||
1 | <?php | ||
2 | |||
3 | /* | ||
4 | * This file is part of Twig. | ||
5 | * | ||
6 | * (c) 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_Tests_Loader_FilesystemTest extends PHPUnit_Framework_TestCase | ||
13 | { | ||
14 | /** | ||
15 | * @dataProvider getSecurityTests | ||
16 | */ | ||
17 | public function testSecurity($template) | ||
18 | { | ||
19 | $loader = new Twig_Loader_Filesystem(array(dirname(__FILE__).'/../Fixtures')); | ||
20 | |||
21 | try { | ||
22 | $loader->getCacheKey($template); | ||
23 | $this->fail(); | ||
24 | } catch (Twig_Error_Loader $e) { | ||
25 | $this->assertNotContains('Unable to find template', $e->getMessage()); | ||
26 | } | ||
27 | } | ||
28 | |||
29 | public function getSecurityTests() | ||
30 | { | ||
31 | return array( | ||
32 | array("AutoloaderTest\0.php"), | ||
33 | array('..\\AutoloaderTest.php'), | ||
34 | array('..\\\\\\AutoloaderTest.php'), | ||
35 | array('../AutoloaderTest.php'), | ||
36 | array('..////AutoloaderTest.php'), | ||
37 | array('./../AutoloaderTest.php'), | ||
38 | array('.\\..\\AutoloaderTest.php'), | ||
39 | array('././././././../AutoloaderTest.php'), | ||
40 | array('.\\./.\\./.\\./../AutoloaderTest.php'), | ||
41 | array('foo/../../AutoloaderTest.php'), | ||
42 | array('foo\\..\\..\\AutoloaderTest.php'), | ||
43 | array('foo/../bar/../../AutoloaderTest.php'), | ||
44 | array('foo/bar/../../../AutoloaderTest.php'), | ||
45 | array('filters/../../AutoloaderTest.php'), | ||
46 | array('filters//..//..//AutoloaderTest.php'), | ||
47 | array('filters\\..\\..\\AutoloaderTest.php'), | ||
48 | array('filters\\\\..\\\\..\\\\AutoloaderTest.php'), | ||
49 | array('filters\\//../\\/\\..\\AutoloaderTest.php'), | ||
50 | array('/../AutoloaderTest.php'), | ||
51 | ); | ||
52 | } | ||
53 | |||
54 | public function testPaths() | ||
55 | { | ||
56 | $basePath = dirname(__FILE__).'/Fixtures'; | ||
57 | |||
58 | $loader = new Twig_Loader_Filesystem(array($basePath.'/normal', $basePath.'/normal_bis')); | ||
59 | $loader->setPaths(array($basePath.'/named', $basePath.'/named_bis'), 'named'); | ||
60 | $loader->addPath($basePath.'/named_ter', 'named'); | ||
61 | $loader->addPath($basePath.'/normal_ter'); | ||
62 | $loader->prependPath($basePath.'/normal_final'); | ||
63 | $loader->prependPath($basePath.'/named_final', 'named'); | ||
64 | |||
65 | $this->assertEquals(array( | ||
66 | $basePath.'/normal_final', | ||
67 | $basePath.'/normal', | ||
68 | $basePath.'/normal_bis', | ||
69 | $basePath.'/normal_ter', | ||
70 | ), $loader->getPaths()); | ||
71 | $this->assertEquals(array( | ||
72 | $basePath.'/named_final', | ||
73 | $basePath.'/named', | ||
74 | $basePath.'/named_bis', | ||
75 | $basePath.'/named_ter', | ||
76 | ), $loader->getPaths('named')); | ||
77 | |||
78 | $this->assertEquals("path (final)\n", $loader->getSource('index.html')); | ||
79 | $this->assertEquals("path (final)\n", $loader->getSource('@__main__/index.html')); | ||
80 | $this->assertEquals("named path (final)\n", $loader->getSource('@named/index.html')); | ||
81 | } | ||
82 | |||
83 | public function testEmptyConstructor() | ||
84 | { | ||
85 | $loader = new Twig_Loader_Filesystem(); | ||
86 | $this->assertEquals(array(), $loader->getPaths()); | ||
87 | } | ||
88 | |||
89 | public function testGetNamespaces() | ||
90 | { | ||
91 | $loader = new Twig_Loader_Filesystem(sys_get_temp_dir()); | ||
92 | $this->assertEquals(array(Twig_Loader_Filesystem::MAIN_NAMESPACE), $loader->getNamespaces()); | ||
93 | |||
94 | $loader->addPath(sys_get_temp_dir(), 'named'); | ||
95 | $this->assertEquals(array(Twig_Loader_Filesystem::MAIN_NAMESPACE, 'named'), $loader->getNamespaces()); | ||
96 | } | ||
97 | } | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Loader/Fixtures/named/index.html b/vendor/twig/twig/test/Twig/Tests/Loader/Fixtures/named/index.html new file mode 100644 index 00000000..9e5449c7 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Loader/Fixtures/named/index.html | |||
@@ -0,0 +1 @@ | |||
named path | |||
diff --git a/vendor/twig/twig/test/Twig/Tests/Loader/Fixtures/named_bis/index.html b/vendor/twig/twig/test/Twig/Tests/Loader/Fixtures/named_bis/index.html new file mode 100644 index 00000000..d3a272b1 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Loader/Fixtures/named_bis/index.html | |||
@@ -0,0 +1 @@ | |||
named path (bis) | |||
diff --git a/vendor/twig/twig/test/Twig/Tests/Loader/Fixtures/named_final/index.html b/vendor/twig/twig/test/Twig/Tests/Loader/Fixtures/named_final/index.html new file mode 100644 index 00000000..9f05d150 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Loader/Fixtures/named_final/index.html | |||
@@ -0,0 +1 @@ | |||
named path (final) | |||
diff --git a/vendor/twig/twig/test/Twig/Tests/Loader/Fixtures/named_ter/index.html b/vendor/twig/twig/test/Twig/Tests/Loader/Fixtures/named_ter/index.html new file mode 100644 index 00000000..24fb68ad --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Loader/Fixtures/named_ter/index.html | |||
@@ -0,0 +1 @@ | |||
named path (ter) | |||
diff --git a/vendor/twig/twig/test/Twig/Tests/Loader/Fixtures/normal/index.html b/vendor/twig/twig/test/Twig/Tests/Loader/Fixtures/normal/index.html new file mode 100644 index 00000000..e7a8fd4d --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Loader/Fixtures/normal/index.html | |||
@@ -0,0 +1 @@ | |||
path | |||
diff --git a/vendor/twig/twig/test/Twig/Tests/Loader/Fixtures/normal_bis/index.html b/vendor/twig/twig/test/Twig/Tests/Loader/Fixtures/normal_bis/index.html new file mode 100644 index 00000000..bfa91604 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Loader/Fixtures/normal_bis/index.html | |||
@@ -0,0 +1 @@ | |||
path (bis) | |||
diff --git a/vendor/twig/twig/test/Twig/Tests/Loader/Fixtures/normal_final/index.html b/vendor/twig/twig/test/Twig/Tests/Loader/Fixtures/normal_final/index.html new file mode 100644 index 00000000..73a089bb --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Loader/Fixtures/normal_final/index.html | |||
@@ -0,0 +1 @@ | |||
path (final) | |||
diff --git a/vendor/twig/twig/test/Twig/Tests/Loader/Fixtures/normal_ter/index.html b/vendor/twig/twig/test/Twig/Tests/Loader/Fixtures/normal_ter/index.html new file mode 100644 index 00000000..b7ad97d8 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Loader/Fixtures/normal_ter/index.html | |||
@@ -0,0 +1 @@ | |||
path (ter) | |||
diff --git a/vendor/twig/twig/test/Twig/Tests/NativeExtensionTest.php b/vendor/twig/twig/test/Twig/Tests/NativeExtensionTest.php new file mode 100644 index 00000000..3fafd335 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/NativeExtensionTest.php | |||
@@ -0,0 +1,29 @@ | |||
1 | <?php | ||
2 | |||
3 | /* | ||
4 | * This file is part of Twig. | ||
5 | * | ||
6 | * (c) 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_Tests_NativeExtensionTest extends PHPUnit_Framework_TestCase | ||
13 | { | ||
14 | public function testGetProperties() | ||
15 | { | ||
16 | $twig = new Twig_Environment(new Twig_Loader_String(), array( | ||
17 | 'debug' => true, | ||
18 | 'cache' => false, | ||
19 | 'autoescape' => false | ||
20 | )); | ||
21 | |||
22 | $d1 = new DateTime(); | ||
23 | $d2 = new DateTime(); | ||
24 | $output = $twig->render('{{ d1.date }}{{ d2.date }}', compact('d1', 'd2')); | ||
25 | |||
26 | // If it fails, PHP will crash. | ||
27 | $this->assertEquals($output, $d1->date . $d2->date); | ||
28 | } | ||
29 | } | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Node/AutoEscapeTest.php b/vendor/twig/twig/test/Twig/Tests/Node/AutoEscapeTest.php new file mode 100644 index 00000000..608446bc --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Node/AutoEscapeTest.php | |||
@@ -0,0 +1,44 @@ | |||
1 | <?php | ||
2 | |||
3 | /* | ||
4 | * This file is part of Twig. | ||
5 | * | ||
6 | * (c) 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_Tests_Node_AutoEscapeTest extends Twig_Test_NodeTestCase | ||
13 | { | ||
14 | /** | ||
15 | * @covers Twig_Node_AutoEscape::__construct | ||
16 | */ | ||
17 | public function testConstructor() | ||
18 | { | ||
19 | $body = new Twig_Node(array(new Twig_Node_Text('foo', 1))); | ||
20 | $node = new Twig_Node_AutoEscape(true, $body, 1); | ||
21 | |||
22 | $this->assertEquals($body, $node->getNode('body')); | ||
23 | $this->assertEquals(true, $node->getAttribute('value')); | ||
24 | } | ||
25 | |||
26 | /** | ||
27 | * @covers Twig_Node_AutoEscape::compile | ||
28 | * @dataProvider getTests | ||
29 | */ | ||
30 | public function testCompile($node, $source, $environment = null) | ||
31 | { | ||
32 | parent::testCompile($node, $source, $environment); | ||
33 | } | ||
34 | |||
35 | public function getTests() | ||
36 | { | ||
37 | $body = new Twig_Node(array(new Twig_Node_Text('foo', 1))); | ||
38 | $node = new Twig_Node_AutoEscape(true, $body, 1); | ||
39 | |||
40 | return array( | ||
41 | array($node, "// line 1\necho \"foo\";"), | ||
42 | ); | ||
43 | } | ||
44 | } | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Node/BlockReferenceTest.php b/vendor/twig/twig/test/Twig/Tests/Node/BlockReferenceTest.php new file mode 100644 index 00000000..96d0e101 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Node/BlockReferenceTest.php | |||
@@ -0,0 +1,43 @@ | |||
1 | <?php | ||
2 | |||
3 | /* | ||
4 | * This file is part of Twig. | ||
5 | * | ||
6 | * (c) 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_Tests_Node_BlockReferenceTest extends Twig_Test_NodeTestCase | ||
13 | { | ||
14 | /** | ||
15 | * @covers Twig_Node_BlockReference::__construct | ||
16 | */ | ||
17 | public function testConstructor() | ||
18 | { | ||
19 | $node = new Twig_Node_BlockReference('foo', 1); | ||
20 | |||
21 | $this->assertEquals('foo', $node->getAttribute('name')); | ||
22 | } | ||
23 | |||
24 | /** | ||
25 | * @covers Twig_Node_BlockReference::compile | ||
26 | * @dataProvider getTests | ||
27 | */ | ||
28 | public function testCompile($node, $source, $environment = null) | ||
29 | { | ||
30 | parent::testCompile($node, $source, $environment); | ||
31 | } | ||
32 | |||
33 | public function getTests() | ||
34 | { | ||
35 | return array( | ||
36 | array(new Twig_Node_BlockReference('foo', 1), <<<EOF | ||
37 | // line 1 | ||
38 | \$this->displayBlock('foo', \$context, \$blocks); | ||
39 | EOF | ||
40 | ), | ||
41 | ); | ||
42 | } | ||
43 | } | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Node/BlockTest.php b/vendor/twig/twig/test/Twig/Tests/Node/BlockTest.php new file mode 100644 index 00000000..024049de --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Node/BlockTest.php | |||
@@ -0,0 +1,51 @@ | |||
1 | <?php | ||
2 | |||
3 | /* | ||
4 | * This file is part of Twig. | ||
5 | * | ||
6 | * (c) 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_Tests_Node_BlockTest extends Twig_Test_NodeTestCase | ||
13 | { | ||
14 | /** | ||
15 | * @covers Twig_Node_Block::__construct | ||
16 | */ | ||
17 | public function testConstructor() | ||
18 | { | ||
19 | $body = new Twig_Node_Text('foo', 1); | ||
20 | $node = new Twig_Node_Block('foo', $body, 1); | ||
21 | |||
22 | $this->assertEquals($body, $node->getNode('body')); | ||
23 | $this->assertEquals('foo', $node->getAttribute('name')); | ||
24 | } | ||
25 | |||
26 | /** | ||
27 | * @covers Twig_Node_Block::compile | ||
28 | * @dataProvider getTests | ||
29 | */ | ||
30 | public function testCompile($node, $source, $environment = null) | ||
31 | { | ||
32 | parent::testCompile($node, $source, $environment); | ||
33 | } | ||
34 | |||
35 | public function getTests() | ||
36 | { | ||
37 | $body = new Twig_Node_Text('foo', 1); | ||
38 | $node = new Twig_Node_Block('foo', $body, 1); | ||
39 | |||
40 | return array( | ||
41 | array($node, <<<EOF | ||
42 | // line 1 | ||
43 | public function block_foo(\$context, array \$blocks = array()) | ||
44 | { | ||
45 | echo "foo"; | ||
46 | } | ||
47 | EOF | ||
48 | ), | ||
49 | ); | ||
50 | } | ||
51 | } | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Node/DoTest.php b/vendor/twig/twig/test/Twig/Tests/Node/DoTest.php new file mode 100644 index 00000000..a406e22d --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Node/DoTest.php | |||
@@ -0,0 +1,44 @@ | |||
1 | <?php | ||
2 | |||
3 | /* | ||
4 | * This file is part of Twig. | ||
5 | * | ||
6 | * (c) 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_Tests_Node_DoTest extends Twig_Test_NodeTestCase | ||
13 | { | ||
14 | /** | ||
15 | * @covers Twig_Node_Do::__construct | ||
16 | */ | ||
17 | public function testConstructor() | ||
18 | { | ||
19 | $expr = new Twig_Node_Expression_Constant('foo', 1); | ||
20 | $node = new Twig_Node_Do($expr, 1); | ||
21 | |||
22 | $this->assertEquals($expr, $node->getNode('expr')); | ||
23 | } | ||
24 | |||
25 | /** | ||
26 | * @covers Twig_Node_Do::compile | ||
27 | * @dataProvider getTests | ||
28 | */ | ||
29 | public function testCompile($node, $source, $environment = null) | ||
30 | { | ||
31 | parent::testCompile($node, $source, $environment); | ||
32 | } | ||
33 | |||
34 | public function getTests() | ||
35 | { | ||
36 | $tests = array(); | ||
37 | |||
38 | $expr = new Twig_Node_Expression_Constant('foo', 1); | ||
39 | $node = new Twig_Node_Do($expr, 1); | ||
40 | $tests[] = array($node, "// line 1\n\"foo\";"); | ||
41 | |||
42 | return $tests; | ||
43 | } | ||
44 | } | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Node/Expression/ArrayTest.php b/vendor/twig/twig/test/Twig/Tests/Node/Expression/ArrayTest.php new file mode 100644 index 00000000..c6a9044b --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Node/Expression/ArrayTest.php | |||
@@ -0,0 +1,49 @@ | |||
1 | <?php | ||
2 | |||
3 | /* | ||
4 | * This file is part of Twig. | ||
5 | * | ||
6 | * (c) 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_Tests_Node_Expression_ArrayTest extends Twig_Test_NodeTestCase | ||
13 | { | ||
14 | /** | ||
15 | * @covers Twig_Node_Expression_Array::__construct | ||
16 | */ | ||
17 | public function testConstructor() | ||
18 | { | ||
19 | $elements = array(new Twig_Node_Expression_Constant('foo', 1), $foo = new Twig_Node_Expression_Constant('bar', 1)); | ||
20 | $node = new Twig_Node_Expression_Array($elements, 1); | ||
21 | |||
22 | $this->assertEquals($foo, $node->getNode(1)); | ||
23 | } | ||
24 | |||
25 | /** | ||
26 | * @covers Twig_Node_Expression_Array::compile | ||
27 | * @dataProvider getTests | ||
28 | */ | ||
29 | public function testCompile($node, $source, $environment = null) | ||
30 | { | ||
31 | parent::testCompile($node, $source, $environment); | ||
32 | } | ||
33 | |||
34 | public function getTests() | ||
35 | { | ||
36 | $elements = array( | ||
37 | new Twig_Node_Expression_Constant('foo', 1), | ||
38 | new Twig_Node_Expression_Constant('bar', 1), | ||
39 | |||
40 | new Twig_Node_Expression_Constant('bar', 1), | ||
41 | new Twig_Node_Expression_Constant('foo', 1), | ||
42 | ); | ||
43 | $node = new Twig_Node_Expression_Array($elements, 1); | ||
44 | |||
45 | return array( | ||
46 | array($node, 'array("foo" => "bar", "bar" => "foo")'), | ||
47 | ); | ||
48 | } | ||
49 | } | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Node/Expression/AssignNameTest.php b/vendor/twig/twig/test/Twig/Tests/Node/Expression/AssignNameTest.php new file mode 100644 index 00000000..b156dcc0 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Node/Expression/AssignNameTest.php | |||
@@ -0,0 +1,41 @@ | |||
1 | <?php | ||
2 | |||
3 | /* | ||
4 | * This file is part of Twig. | ||
5 | * | ||
6 | * (c) 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_Tests_Node_Expression_AssignNameTest extends Twig_Test_NodeTestCase | ||
13 | { | ||
14 | /** | ||
15 | * @covers Twig_Node_Expression_AssignName::__construct | ||
16 | */ | ||
17 | public function testConstructor() | ||
18 | { | ||
19 | $node = new Twig_Node_Expression_AssignName('foo', 1); | ||
20 | |||
21 | $this->assertEquals('foo', $node->getAttribute('name')); | ||
22 | } | ||
23 | |||
24 | /** | ||
25 | * @covers Twig_Node_Expression_AssignName::compile | ||
26 | * @dataProvider getTests | ||
27 | */ | ||
28 | public function testCompile($node, $source, $environment = null) | ||
29 | { | ||
30 | parent::testCompile($node, $source, $environment); | ||
31 | } | ||
32 | |||
33 | public function getTests() | ||
34 | { | ||
35 | $node = new Twig_Node_Expression_AssignName('foo', 1); | ||
36 | |||
37 | return array( | ||
38 | array($node, '$context["foo"]'), | ||
39 | ); | ||
40 | } | ||
41 | } | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Node/Expression/Binary/AddTest.php b/vendor/twig/twig/test/Twig/Tests/Node/Expression/Binary/AddTest.php new file mode 100644 index 00000000..a0f49cb3 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Node/Expression/Binary/AddTest.php | |||
@@ -0,0 +1,47 @@ | |||
1 | <?php | ||
2 | |||
3 | /* | ||
4 | * This file is part of Twig. | ||
5 | * | ||
6 | * (c) 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_Tests_Node_Expression_Binary_AddTest extends Twig_Test_NodeTestCase | ||
13 | { | ||
14 | /** | ||
15 | * @covers Twig_Node_Expression_Binary_Add::__construct | ||
16 | */ | ||
17 | public function testConstructor() | ||
18 | { | ||
19 | $left = new Twig_Node_Expression_Constant(1, 1); | ||
20 | $right = new Twig_Node_Expression_Constant(2, 1); | ||
21 | $node = new Twig_Node_Expression_Binary_Add($left, $right, 1); | ||
22 | |||
23 | $this->assertEquals($left, $node->getNode('left')); | ||
24 | $this->assertEquals($right, $node->getNode('right')); | ||
25 | } | ||
26 | |||
27 | /** | ||
28 | * @covers Twig_Node_Expression_Binary_Add::compile | ||
29 | * @covers Twig_Node_Expression_Binary_Add::operator | ||
30 | * @dataProvider getTests | ||
31 | */ | ||
32 | public function testCompile($node, $source, $environment = null) | ||
33 | { | ||
34 | parent::testCompile($node, $source, $environment); | ||
35 | } | ||
36 | |||
37 | public function getTests() | ||
38 | { | ||
39 | $left = new Twig_Node_Expression_Constant(1, 1); | ||
40 | $right = new Twig_Node_Expression_Constant(2, 1); | ||
41 | $node = new Twig_Node_Expression_Binary_Add($left, $right, 1); | ||
42 | |||
43 | return array( | ||
44 | array($node, '(1 + 2)'), | ||
45 | ); | ||
46 | } | ||
47 | } | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Node/Expression/Binary/AndTest.php b/vendor/twig/twig/test/Twig/Tests/Node/Expression/Binary/AndTest.php new file mode 100644 index 00000000..50e551a7 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Node/Expression/Binary/AndTest.php | |||
@@ -0,0 +1,47 @@ | |||
1 | <?php | ||
2 | |||
3 | /* | ||
4 | * This file is part of Twig. | ||
5 | * | ||
6 | * (c) 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_Tests_Node_Expression_Binary_AndTest extends Twig_Test_NodeTestCase | ||
13 | { | ||
14 | /** | ||
15 | * @covers Twig_Node_Expression_Binary_And::__construct | ||
16 | */ | ||
17 | public function testConstructor() | ||
18 | { | ||
19 | $left = new Twig_Node_Expression_Constant(1, 1); | ||
20 | $right = new Twig_Node_Expression_Constant(2, 1); | ||
21 | $node = new Twig_Node_Expression_Binary_And($left, $right, 1); | ||
22 | |||
23 | $this->assertEquals($left, $node->getNode('left')); | ||
24 | $this->assertEquals($right, $node->getNode('right')); | ||
25 | } | ||
26 | |||
27 | /** | ||
28 | * @covers Twig_Node_Expression_Binary_And::compile | ||
29 | * @covers Twig_Node_Expression_Binary_And::operator | ||
30 | * @dataProvider getTests | ||
31 | */ | ||
32 | public function testCompile($node, $source, $environment = null) | ||
33 | { | ||
34 | parent::testCompile($node, $source, $environment); | ||
35 | } | ||
36 | |||
37 | public function getTests() | ||
38 | { | ||
39 | $left = new Twig_Node_Expression_Constant(1, 1); | ||
40 | $right = new Twig_Node_Expression_Constant(2, 1); | ||
41 | $node = new Twig_Node_Expression_Binary_And($left, $right, 1); | ||
42 | |||
43 | return array( | ||
44 | array($node, '(1 && 2)'), | ||
45 | ); | ||
46 | } | ||
47 | } | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Node/Expression/Binary/ConcatTest.php b/vendor/twig/twig/test/Twig/Tests/Node/Expression/Binary/ConcatTest.php new file mode 100644 index 00000000..140329fa --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Node/Expression/Binary/ConcatTest.php | |||
@@ -0,0 +1,47 @@ | |||
1 | <?php | ||
2 | |||
3 | /* | ||
4 | * This file is part of Twig. | ||
5 | * | ||
6 | * (c) 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_Tests_Node_Expression_Binary_ConcatTest extends Twig_Test_NodeTestCase | ||
13 | { | ||
14 | /** | ||
15 | * @covers Twig_Node_Expression_Binary_Concat::__construct | ||
16 | */ | ||
17 | public function testConstructor() | ||
18 | { | ||
19 | $left = new Twig_Node_Expression_Constant(1, 1); | ||
20 | $right = new Twig_Node_Expression_Constant(2, 1); | ||
21 | $node = new Twig_Node_Expression_Binary_Concat($left, $right, 1); | ||
22 | |||
23 | $this->assertEquals($left, $node->getNode('left')); | ||
24 | $this->assertEquals($right, $node->getNode('right')); | ||
25 | } | ||
26 | |||
27 | /** | ||
28 | * @covers Twig_Node_Expression_Binary_Concat::compile | ||
29 | * @covers Twig_Node_Expression_Binary_Concat::operator | ||
30 | * @dataProvider getTests | ||
31 | */ | ||
32 | public function testCompile($node, $source, $environment = null) | ||
33 | { | ||
34 | parent::testCompile($node, $source, $environment); | ||
35 | } | ||
36 | |||
37 | public function getTests() | ||
38 | { | ||
39 | $left = new Twig_Node_Expression_Constant(1, 1); | ||
40 | $right = new Twig_Node_Expression_Constant(2, 1); | ||
41 | $node = new Twig_Node_Expression_Binary_Concat($left, $right, 1); | ||
42 | |||
43 | return array( | ||
44 | array($node, '(1 . 2)'), | ||
45 | ); | ||
46 | } | ||
47 | } | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Node/Expression/Binary/DivTest.php b/vendor/twig/twig/test/Twig/Tests/Node/Expression/Binary/DivTest.php new file mode 100644 index 00000000..0c1a3c7f --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Node/Expression/Binary/DivTest.php | |||
@@ -0,0 +1,47 @@ | |||
1 | <?php | ||
2 | |||
3 | /* | ||
4 | * This file is part of Twig. | ||
5 | * | ||
6 | * (c) 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_Tests_Node_Expression_Binary_DivTest extends Twig_Test_NodeTestCase | ||
13 | { | ||
14 | /** | ||
15 | * @covers Twig_Node_Expression_Binary_Div::__construct | ||
16 | */ | ||
17 | public function testConstructor() | ||
18 | { | ||
19 | $left = new Twig_Node_Expression_Constant(1, 1); | ||
20 | $right = new Twig_Node_Expression_Constant(2, 1); | ||
21 | $node = new Twig_Node_Expression_Binary_Div($left, $right, 1); | ||
22 | |||
23 | $this->assertEquals($left, $node->getNode('left')); | ||
24 | $this->assertEquals($right, $node->getNode('right')); | ||
25 | } | ||
26 | |||
27 | /** | ||
28 | * @covers Twig_Node_Expression_Binary_Div::compile | ||
29 | * @covers Twig_Node_Expression_Binary_Div::operator | ||
30 | * @dataProvider getTests | ||
31 | */ | ||
32 | public function testCompile($node, $source, $environment = null) | ||
33 | { | ||
34 | parent::testCompile($node, $source, $environment); | ||
35 | } | ||
36 | |||
37 | public function getTests() | ||
38 | { | ||
39 | $left = new Twig_Node_Expression_Constant(1, 1); | ||
40 | $right = new Twig_Node_Expression_Constant(2, 1); | ||
41 | $node = new Twig_Node_Expression_Binary_Div($left, $right, 1); | ||
42 | |||
43 | return array( | ||
44 | array($node, '(1 / 2)'), | ||
45 | ); | ||
46 | } | ||
47 | } | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Node/Expression/Binary/FloorDivTest.php b/vendor/twig/twig/test/Twig/Tests/Node/Expression/Binary/FloorDivTest.php new file mode 100644 index 00000000..ead1fde8 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Node/Expression/Binary/FloorDivTest.php | |||
@@ -0,0 +1,47 @@ | |||
1 | <?php | ||
2 | |||
3 | /* | ||
4 | * This file is part of Twig. | ||
5 | * | ||
6 | * (c) 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_Tests_Node_Expression_Binary_FloorDivTest extends Twig_Test_NodeTestCase | ||
13 | { | ||
14 | /** | ||
15 | * @covers Twig_Node_Expression_Binary_FloorDiv::__construct | ||
16 | */ | ||
17 | public function testConstructor() | ||
18 | { | ||
19 | $left = new Twig_Node_Expression_Constant(1, 1); | ||
20 | $right = new Twig_Node_Expression_Constant(2, 1); | ||
21 | $node = new Twig_Node_Expression_Binary_FloorDiv($left, $right, 1); | ||
22 | |||
23 | $this->assertEquals($left, $node->getNode('left')); | ||
24 | $this->assertEquals($right, $node->getNode('right')); | ||
25 | } | ||
26 | |||
27 | /** | ||
28 | * @covers Twig_Node_Expression_Binary_FloorDiv::compile | ||
29 | * @covers Twig_Node_Expression_Binary_FloorDiv::operator | ||
30 | * @dataProvider getTests | ||
31 | */ | ||
32 | public function testCompile($node, $source, $environment = null) | ||
33 | { | ||
34 | parent::testCompile($node, $source, $environment); | ||
35 | } | ||
36 | |||
37 | public function getTests() | ||
38 | { | ||
39 | $left = new Twig_Node_Expression_Constant(1, 1); | ||
40 | $right = new Twig_Node_Expression_Constant(2, 1); | ||
41 | $node = new Twig_Node_Expression_Binary_FloorDiv($left, $right, 1); | ||
42 | |||
43 | return array( | ||
44 | array($node, 'intval(floor((1 / 2)))'), | ||
45 | ); | ||
46 | } | ||
47 | } | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Node/Expression/Binary/ModTest.php b/vendor/twig/twig/test/Twig/Tests/Node/Expression/Binary/ModTest.php new file mode 100644 index 00000000..4fe1a1fc --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Node/Expression/Binary/ModTest.php | |||
@@ -0,0 +1,47 @@ | |||
1 | <?php | ||
2 | |||
3 | /* | ||
4 | * This file is part of Twig. | ||
5 | * | ||
6 | * (c) 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_Tests_Node_Expression_Binary_ModTest extends Twig_Test_NodeTestCase | ||
13 | { | ||
14 | /** | ||
15 | * @covers Twig_Node_Expression_Binary_Mod::__construct | ||
16 | */ | ||
17 | public function testConstructor() | ||
18 | { | ||
19 | $left = new Twig_Node_Expression_Constant(1, 1); | ||
20 | $right = new Twig_Node_Expression_Constant(2, 1); | ||
21 | $node = new Twig_Node_Expression_Binary_Mod($left, $right, 1); | ||
22 | |||
23 | $this->assertEquals($left, $node->getNode('left')); | ||
24 | $this->assertEquals($right, $node->getNode('right')); | ||
25 | } | ||
26 | |||
27 | /** | ||
28 | * @covers Twig_Node_Expression_Binary_Mod::compile | ||
29 | * @covers Twig_Node_Expression_Binary_Mod::operator | ||
30 | * @dataProvider getTests | ||
31 | */ | ||
32 | public function testCompile($node, $source, $environment = null) | ||
33 | { | ||
34 | parent::testCompile($node, $source, $environment); | ||
35 | } | ||
36 | |||
37 | public function getTests() | ||
38 | { | ||
39 | $left = new Twig_Node_Expression_Constant(1, 1); | ||
40 | $right = new Twig_Node_Expression_Constant(2, 1); | ||
41 | $node = new Twig_Node_Expression_Binary_Mod($left, $right, 1); | ||
42 | |||
43 | return array( | ||
44 | array($node, '(1 % 2)'), | ||
45 | ); | ||
46 | } | ||
47 | } | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Node/Expression/Binary/MulTest.php b/vendor/twig/twig/test/Twig/Tests/Node/Expression/Binary/MulTest.php new file mode 100644 index 00000000..12bb35c9 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Node/Expression/Binary/MulTest.php | |||
@@ -0,0 +1,47 @@ | |||
1 | <?php | ||
2 | |||
3 | /* | ||
4 | * This file is part of Twig. | ||
5 | * | ||
6 | * (c) 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_Tests_Node_Expression_Binary_MulTest extends Twig_Test_NodeTestCase | ||
13 | { | ||
14 | /** | ||
15 | * @covers Twig_Node_Expression_Binary_Mul::__construct | ||
16 | */ | ||
17 | public function testConstructor() | ||
18 | { | ||
19 | $left = new Twig_Node_Expression_Constant(1, 1); | ||
20 | $right = new Twig_Node_Expression_Constant(2, 1); | ||
21 | $node = new Twig_Node_Expression_Binary_Mul($left, $right, 1); | ||
22 | |||
23 | $this->assertEquals($left, $node->getNode('left')); | ||
24 | $this->assertEquals($right, $node->getNode('right')); | ||
25 | } | ||
26 | |||
27 | /** | ||
28 | * @covers Twig_Node_Expression_Binary_Mul::compile | ||
29 | * @covers Twig_Node_Expression_Binary_Mul::operator | ||
30 | * @dataProvider getTests | ||
31 | */ | ||
32 | public function testCompile($node, $source, $environment = null) | ||
33 | { | ||
34 | parent::testCompile($node, $source, $environment); | ||
35 | } | ||
36 | |||
37 | public function getTests() | ||
38 | { | ||
39 | $left = new Twig_Node_Expression_Constant(1, 1); | ||
40 | $right = new Twig_Node_Expression_Constant(2, 1); | ||
41 | $node = new Twig_Node_Expression_Binary_Mul($left, $right, 1); | ||
42 | |||
43 | return array( | ||
44 | array($node, '(1 * 2)'), | ||
45 | ); | ||
46 | } | ||
47 | } | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Node/Expression/Binary/OrTest.php b/vendor/twig/twig/test/Twig/Tests/Node/Expression/Binary/OrTest.php new file mode 100644 index 00000000..9534c41c --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Node/Expression/Binary/OrTest.php | |||
@@ -0,0 +1,47 @@ | |||
1 | <?php | ||
2 | |||
3 | /* | ||
4 | * This file is part of Twig. | ||
5 | * | ||
6 | * (c) 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_Tests_Node_Expression_Binary_OrTest extends Twig_Test_NodeTestCase | ||
13 | { | ||
14 | /** | ||
15 | * @covers Twig_Node_Expression_Binary_Or::__construct | ||
16 | */ | ||
17 | public function testConstructor() | ||
18 | { | ||
19 | $left = new Twig_Node_Expression_Constant(1, 1); | ||
20 | $right = new Twig_Node_Expression_Constant(2, 1); | ||
21 | $node = new Twig_Node_Expression_Binary_Or($left, $right, 1); | ||
22 | |||
23 | $this->assertEquals($left, $node->getNode('left')); | ||
24 | $this->assertEquals($right, $node->getNode('right')); | ||
25 | } | ||
26 | |||
27 | /** | ||
28 | * @covers Twig_Node_Expression_Binary_Or::compile | ||
29 | * @covers Twig_Node_Expression_Binary_Or::operator | ||
30 | * @dataProvider getTests | ||
31 | */ | ||
32 | public function testCompile($node, $source, $environment = null) | ||
33 | { | ||
34 | parent::testCompile($node, $source, $environment); | ||
35 | } | ||
36 | |||
37 | public function getTests() | ||
38 | { | ||
39 | $left = new Twig_Node_Expression_Constant(1, 1); | ||
40 | $right = new Twig_Node_Expression_Constant(2, 1); | ||
41 | $node = new Twig_Node_Expression_Binary_Or($left, $right, 1); | ||
42 | |||
43 | return array( | ||
44 | array($node, '(1 || 2)'), | ||
45 | ); | ||
46 | } | ||
47 | } | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Node/Expression/Binary/SubTest.php b/vendor/twig/twig/test/Twig/Tests/Node/Expression/Binary/SubTest.php new file mode 100644 index 00000000..9074893b --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Node/Expression/Binary/SubTest.php | |||
@@ -0,0 +1,47 @@ | |||
1 | <?php | ||
2 | |||
3 | /* | ||
4 | * This file is part of Twig. | ||
5 | * | ||
6 | * (c) 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_Tests_Node_Expression_Binary_SubTest extends Twig_Test_NodeTestCase | ||
13 | { | ||
14 | /** | ||
15 | * @covers Twig_Node_Expression_Binary_Sub::__construct | ||
16 | */ | ||
17 | public function testConstructor() | ||
18 | { | ||
19 | $left = new Twig_Node_Expression_Constant(1, 1); | ||
20 | $right = new Twig_Node_Expression_Constant(2, 1); | ||
21 | $node = new Twig_Node_Expression_Binary_Sub($left, $right, 1); | ||
22 | |||
23 | $this->assertEquals($left, $node->getNode('left')); | ||
24 | $this->assertEquals($right, $node->getNode('right')); | ||
25 | } | ||
26 | |||
27 | /** | ||
28 | * @covers Twig_Node_Expression_Binary_Sub::compile | ||
29 | * @covers Twig_Node_Expression_Binary_Sub::operator | ||
30 | * @dataProvider getTests | ||
31 | */ | ||
32 | public function testCompile($node, $source, $environment = null) | ||
33 | { | ||
34 | parent::testCompile($node, $source, $environment); | ||
35 | } | ||
36 | |||
37 | public function getTests() | ||
38 | { | ||
39 | $left = new Twig_Node_Expression_Constant(1, 1); | ||
40 | $right = new Twig_Node_Expression_Constant(2, 1); | ||
41 | $node = new Twig_Node_Expression_Binary_Sub($left, $right, 1); | ||
42 | |||
43 | return array( | ||
44 | array($node, '(1 - 2)'), | ||
45 | ); | ||
46 | } | ||
47 | } | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Node/Expression/CallTest.php b/vendor/twig/twig/test/Twig/Tests/Node/Expression/CallTest.php new file mode 100644 index 00000000..53b5e6ee --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Node/Expression/CallTest.php | |||
@@ -0,0 +1,67 @@ | |||
1 | <?php | ||
2 | |||
3 | /* | ||
4 | * This file is part of Twig. | ||
5 | * | ||
6 | * (c) 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_Tests_Node_Expression_CallTest extends PHPUnit_Framework_TestCase | ||
13 | { | ||
14 | public function testGetArguments() | ||
15 | { | ||
16 | $node = new Twig_Tests_Node_Expression_Call(array(), array('type' => 'function', 'name' => 'date')); | ||
17 | $this->assertEquals(array('U'), $node->getArguments('date', array('format' => 'U'))); | ||
18 | } | ||
19 | |||
20 | /** | ||
21 | * @expectedException Twig_Error_Syntax | ||
22 | * @expectedExceptionMessage Positional arguments cannot be used after named arguments for function "date". | ||
23 | */ | ||
24 | public function testGetArgumentsWhenPositionalArgumentsAfterNamedArguments() | ||
25 | { | ||
26 | $node = new Twig_Tests_Node_Expression_Call(array(), array('type' => 'function', 'name' => 'date')); | ||
27 | $node->getArguments('date', array('timestamp' => 123456, 'Y-m-d')); | ||
28 | } | ||
29 | |||
30 | /** | ||
31 | * @expectedException Twig_Error_Syntax | ||
32 | * @expectedExceptionMessage Argument "format" is defined twice for function "date". | ||
33 | */ | ||
34 | public function testGetArgumentsWhenArgumentIsDefinedTwice() | ||
35 | { | ||
36 | $node = new Twig_Tests_Node_Expression_Call(array(), array('type' => 'function', 'name' => 'date')); | ||
37 | $node->getArguments('date', array('Y-m-d', 'format' => 'U')); | ||
38 | } | ||
39 | |||
40 | /** | ||
41 | * @expectedException Twig_Error_Syntax | ||
42 | * @expectedExceptionMessage Unknown argument "unknown" for function "date". | ||
43 | */ | ||
44 | public function testGetArgumentsWithWrongNamedArgumentName() | ||
45 | { | ||
46 | $node = new Twig_Tests_Node_Expression_Call(array(), array('type' => 'function', 'name' => 'date')); | ||
47 | $node->getArguments('date', array('Y-m-d', 'unknown' => '')); | ||
48 | } | ||
49 | |||
50 | /** | ||
51 | * @expectedException Twig_Error_Syntax | ||
52 | * @expectedExceptionMessage Unknown arguments "unknown1", "unknown2" for function "date". | ||
53 | */ | ||
54 | public function testGetArgumentsWithWrongNamedArgumentNames() | ||
55 | { | ||
56 | $node = new Twig_Tests_Node_Expression_Call(array(), array('type' => 'function', 'name' => 'date')); | ||
57 | $node->getArguments('date', array('Y-m-d', 'unknown1' => '', 'unknown2' => '')); | ||
58 | } | ||
59 | } | ||
60 | |||
61 | class Twig_Tests_Node_Expression_Call extends Twig_Node_Expression_Call | ||
62 | { | ||
63 | public function getArguments($callable, $arguments) | ||
64 | { | ||
65 | return parent::getArguments($callable, $arguments); | ||
66 | } | ||
67 | } | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Node/Expression/ConditionalTest.php b/vendor/twig/twig/test/Twig/Tests/Node/Expression/ConditionalTest.php new file mode 100644 index 00000000..9906d512 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Node/Expression/ConditionalTest.php | |||
@@ -0,0 +1,50 @@ | |||
1 | <?php | ||
2 | |||
3 | /* | ||
4 | * This file is part of Twig. | ||
5 | * | ||
6 | * (c) 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_Tests_Node_Expression_ConditionalTest extends Twig_Test_NodeTestCase | ||
13 | { | ||
14 | /** | ||
15 | * @covers Twig_Node_Expression_Conditional::__construct | ||
16 | */ | ||
17 | public function testConstructor() | ||
18 | { | ||
19 | $expr1 = new Twig_Node_Expression_Constant(1, 1); | ||
20 | $expr2 = new Twig_Node_Expression_Constant(2, 1); | ||
21 | $expr3 = new Twig_Node_Expression_Constant(3, 1); | ||
22 | $node = new Twig_Node_Expression_Conditional($expr1, $expr2, $expr3, 1); | ||
23 | |||
24 | $this->assertEquals($expr1, $node->getNode('expr1')); | ||
25 | $this->assertEquals($expr2, $node->getNode('expr2')); | ||
26 | $this->assertEquals($expr3, $node->getNode('expr3')); | ||
27 | } | ||
28 | |||
29 | /** | ||
30 | * @covers Twig_Node_Expression_Conditional::compile | ||
31 | * @dataProvider getTests | ||
32 | */ | ||
33 | public function testCompile($node, $source, $environment = null) | ||
34 | { | ||
35 | parent::testCompile($node, $source, $environment); | ||
36 | } | ||
37 | |||
38 | public function getTests() | ||
39 | { | ||
40 | $tests = array(); | ||
41 | |||
42 | $expr1 = new Twig_Node_Expression_Constant(1, 1); | ||
43 | $expr2 = new Twig_Node_Expression_Constant(2, 1); | ||
44 | $expr3 = new Twig_Node_Expression_Constant(3, 1); | ||
45 | $node = new Twig_Node_Expression_Conditional($expr1, $expr2, $expr3, 1); | ||
46 | $tests[] = array($node, '((1) ? (2) : (3))'); | ||
47 | |||
48 | return $tests; | ||
49 | } | ||
50 | } | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Node/Expression/ConstantTest.php b/vendor/twig/twig/test/Twig/Tests/Node/Expression/ConstantTest.php new file mode 100644 index 00000000..d0dec531 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Node/Expression/ConstantTest.php | |||
@@ -0,0 +1,42 @@ | |||
1 | <?php | ||
2 | |||
3 | /* | ||
4 | * This file is part of Twig. | ||
5 | * | ||
6 | * (c) 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_Tests_Node_Expression_ConstantTest extends Twig_Test_NodeTestCase | ||
13 | { | ||
14 | /** | ||
15 | * @covers Twig_Node_Expression_Constant::__construct | ||
16 | */ | ||
17 | public function testConstructor() | ||
18 | { | ||
19 | $node = new Twig_Node_Expression_Constant('foo', 1); | ||
20 | |||
21 | $this->assertEquals('foo', $node->getAttribute('value')); | ||
22 | } | ||
23 | |||
24 | /** | ||
25 | * @covers Twig_Node_Expression_Constant::compile | ||
26 | * @dataProvider getTests | ||
27 | */ | ||
28 | public function testCompile($node, $source, $environment = null) | ||
29 | { | ||
30 | parent::testCompile($node, $source, $environment); | ||
31 | } | ||
32 | |||
33 | public function getTests() | ||
34 | { | ||
35 | $tests = array(); | ||
36 | |||
37 | $node = new Twig_Node_Expression_Constant('foo', 1); | ||
38 | $tests[] = array($node, '"foo"'); | ||
39 | |||
40 | return $tests; | ||
41 | } | ||
42 | } | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Node/Expression/FilterTest.php b/vendor/twig/twig/test/Twig/Tests/Node/Expression/FilterTest.php new file mode 100644 index 00000000..8089b9cb --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Node/Expression/FilterTest.php | |||
@@ -0,0 +1,133 @@ | |||
1 | <?php | ||
2 | |||
3 | /* | ||
4 | * This file is part of Twig. | ||
5 | * | ||
6 | * (c) 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_Tests_Node_Expression_FilterTest extends Twig_Test_NodeTestCase | ||
13 | { | ||
14 | /** | ||
15 | * @covers Twig_Node_Expression_Filter::__construct | ||
16 | */ | ||
17 | public function testConstructor() | ||
18 | { | ||
19 | $expr = new Twig_Node_Expression_Constant('foo', 1); | ||
20 | $name = new Twig_Node_Expression_Constant('upper', 1); | ||
21 | $args = new Twig_Node(); | ||
22 | $node = new Twig_Node_Expression_Filter($expr, $name, $args, 1); | ||
23 | |||
24 | $this->assertEquals($expr, $node->getNode('node')); | ||
25 | $this->assertEquals($name, $node->getNode('filter')); | ||
26 | $this->assertEquals($args, $node->getNode('arguments')); | ||
27 | } | ||
28 | |||
29 | /** | ||
30 | * @covers Twig_Node_Expression_Filter::compile | ||
31 | * @dataProvider getTests | ||
32 | */ | ||
33 | public function testCompile($node, $source, $environment = null) | ||
34 | { | ||
35 | parent::testCompile($node, $source, $environment); | ||
36 | } | ||
37 | |||
38 | public function getTests() | ||
39 | { | ||
40 | $tests = array(); | ||
41 | |||
42 | $expr = new Twig_Node_Expression_Constant('foo', 1); | ||
43 | $node = $this->createFilter($expr, 'upper'); | ||
44 | $node = $this->createFilter($node, 'number_format', array(new Twig_Node_Expression_Constant(2, 1), new Twig_Node_Expression_Constant('.', 1), new Twig_Node_Expression_Constant(',', 1))); | ||
45 | |||
46 | if (function_exists('mb_get_info')) { | ||
47 | $tests[] = array($node, 'twig_number_format_filter($this->env, twig_upper_filter($this->env, "foo"), 2, ".", ",")'); | ||
48 | } else { | ||
49 | $tests[] = array($node, 'twig_number_format_filter($this->env, strtoupper("foo"), 2, ".", ",")'); | ||
50 | } | ||
51 | |||
52 | // named arguments | ||
53 | $date = new Twig_Node_Expression_Constant(0, 1); | ||
54 | $node = $this->createFilter($date, 'date', array( | ||
55 | 'timezone' => new Twig_Node_Expression_Constant('America/Chicago', 1), | ||
56 | 'format' => new Twig_Node_Expression_Constant('d/m/Y H:i:s P', 1), | ||
57 | )); | ||
58 | $tests[] = array($node, 'twig_date_format_filter($this->env, 0, "d/m/Y H:i:s P", "America/Chicago")'); | ||
59 | |||
60 | // skip an optional argument | ||
61 | $date = new Twig_Node_Expression_Constant(0, 1); | ||
62 | $node = $this->createFilter($date, 'date', array( | ||
63 | 'timezone' => new Twig_Node_Expression_Constant('America/Chicago', 1), | ||
64 | )); | ||
65 | $tests[] = array($node, 'twig_date_format_filter($this->env, 0, null, "America/Chicago")'); | ||
66 | |||
67 | // underscores vs camelCase for named arguments | ||
68 | $string = new Twig_Node_Expression_Constant('abc', 1); | ||
69 | $node = $this->createFilter($string, 'reverse', array( | ||
70 | 'preserve_keys' => new Twig_Node_Expression_Constant(true, 1), | ||
71 | )); | ||
72 | $tests[] = array($node, 'twig_reverse_filter($this->env, "abc", true)'); | ||
73 | $node = $this->createFilter($string, 'reverse', array( | ||
74 | 'preserveKeys' => new Twig_Node_Expression_Constant(true, 1), | ||
75 | )); | ||
76 | $tests[] = array($node, 'twig_reverse_filter($this->env, "abc", true)'); | ||
77 | |||
78 | // filter as an anonymous function | ||
79 | if (version_compare(phpversion(), '5.3.0', '>=')) { | ||
80 | $node = $this->createFilter(new Twig_Node_Expression_Constant('foo', 1), 'anonymous'); | ||
81 | $tests[] = array($node, 'call_user_func_array($this->env->getFilter(\'anonymous\')->getCallable(), array("foo"))'); | ||
82 | } | ||
83 | |||
84 | return $tests; | ||
85 | } | ||
86 | |||
87 | /** | ||
88 | * @expectedException Twig_Error_Syntax | ||
89 | * @expectedExceptionMessage Unknown argument "foobar" for filter "date". | ||
90 | */ | ||
91 | public function testCompileWithWrongNamedArgumentName() | ||
92 | { | ||
93 | $date = new Twig_Node_Expression_Constant(0, 1); | ||
94 | $node = $this->createFilter($date, 'date', array( | ||
95 | 'foobar' => new Twig_Node_Expression_Constant('America/Chicago', 1), | ||
96 | )); | ||
97 | |||
98 | $compiler = $this->getCompiler(); | ||
99 | $compiler->compile($node); | ||
100 | } | ||
101 | |||
102 | /** | ||
103 | * @expectedException Twig_Error_Syntax | ||
104 | * @expectedExceptionMessage Value for argument "from" is required for filter "replace". | ||
105 | */ | ||
106 | public function testCompileWithMissingNamedArgument() | ||
107 | { | ||
108 | $value = new Twig_Node_Expression_Constant(0, 1); | ||
109 | $node = $this->createFilter($value, 'replace', array( | ||
110 | 'to' => new Twig_Node_Expression_Constant('foo', 1), | ||
111 | )); | ||
112 | |||
113 | $compiler = $this->getCompiler(); | ||
114 | $compiler->compile($node); | ||
115 | } | ||
116 | |||
117 | protected function createFilter($node, $name, array $arguments = array()) | ||
118 | { | ||
119 | $name = new Twig_Node_Expression_Constant($name, 1); | ||
120 | $arguments = new Twig_Node($arguments); | ||
121 | |||
122 | return new Twig_Node_Expression_Filter($node, $name, $arguments, 1); | ||
123 | } | ||
124 | |||
125 | protected function getEnvironment() | ||
126 | { | ||
127 | if (version_compare(phpversion(), '5.3.0', '>=')) { | ||
128 | return include 'PHP53/FilterInclude.php'; | ||
129 | } | ||
130 | |||
131 | return parent::getEnvironment(); | ||
132 | } | ||
133 | } | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Node/Expression/FunctionTest.php b/vendor/twig/twig/test/Twig/Tests/Node/Expression/FunctionTest.php new file mode 100644 index 00000000..431dc387 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Node/Expression/FunctionTest.php | |||
@@ -0,0 +1,99 @@ | |||
1 | <?php | ||
2 | |||
3 | /* | ||
4 | * This file is part of Twig. | ||
5 | * | ||
6 | * (c) 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_Tests_Node_Expression_FunctionTest extends Twig_Test_NodeTestCase | ||
13 | { | ||
14 | /** | ||
15 | * @covers Twig_Node_Expression_Function::__construct | ||
16 | */ | ||
17 | public function testConstructor() | ||
18 | { | ||
19 | $name = 'function'; | ||
20 | $args = new Twig_Node(); | ||
21 | $node = new Twig_Node_Expression_Function($name, $args, 1); | ||
22 | |||
23 | $this->assertEquals($name, $node->getAttribute('name')); | ||
24 | $this->assertEquals($args, $node->getNode('arguments')); | ||
25 | } | ||
26 | |||
27 | /** | ||
28 | * @covers Twig_Node_Expression_Function::compile | ||
29 | * @dataProvider getTests | ||
30 | */ | ||
31 | public function testCompile($node, $source, $environment = null) | ||
32 | { | ||
33 | parent::testCompile($node, $source, $environment); | ||
34 | } | ||
35 | |||
36 | public function getTests() | ||
37 | { | ||
38 | $environment = new Twig_Environment(); | ||
39 | $environment->addFunction('foo', new Twig_Function_Function('foo', array())); | ||
40 | $environment->addFunction('bar', new Twig_Function_Function('bar', array('needs_environment' => true))); | ||
41 | $environment->addFunction('foofoo', new Twig_Function_Function('foofoo', array('needs_context' => true))); | ||
42 | $environment->addFunction('foobar', new Twig_Function_Function('foobar', array('needs_environment' => true, 'needs_context' => true))); | ||
43 | |||
44 | $tests = array(); | ||
45 | |||
46 | $node = $this->createFunction('foo'); | ||
47 | $tests[] = array($node, 'foo()', $environment); | ||
48 | |||
49 | $node = $this->createFunction('foo', array(new Twig_Node_Expression_Constant('bar', 1), new Twig_Node_Expression_Constant('foobar', 1))); | ||
50 | $tests[] = array($node, 'foo("bar", "foobar")', $environment); | ||
51 | |||
52 | $node = $this->createFunction('bar'); | ||
53 | $tests[] = array($node, 'bar($this->env)', $environment); | ||
54 | |||
55 | $node = $this->createFunction('bar', array(new Twig_Node_Expression_Constant('bar', 1))); | ||
56 | $tests[] = array($node, 'bar($this->env, "bar")', $environment); | ||
57 | |||
58 | $node = $this->createFunction('foofoo'); | ||
59 | $tests[] = array($node, 'foofoo($context)', $environment); | ||
60 | |||
61 | $node = $this->createFunction('foofoo', array(new Twig_Node_Expression_Constant('bar', 1))); | ||
62 | $tests[] = array($node, 'foofoo($context, "bar")', $environment); | ||
63 | |||
64 | $node = $this->createFunction('foobar'); | ||
65 | $tests[] = array($node, 'foobar($this->env, $context)', $environment); | ||
66 | |||
67 | $node = $this->createFunction('foobar', array(new Twig_Node_Expression_Constant('bar', 1))); | ||
68 | $tests[] = array($node, 'foobar($this->env, $context, "bar")', $environment); | ||
69 | |||
70 | // named arguments | ||
71 | $node = $this->createFunction('date', array( | ||
72 | 'timezone' => new Twig_Node_Expression_Constant('America/Chicago', 1), | ||
73 | 'date' => new Twig_Node_Expression_Constant(0, 1), | ||
74 | )); | ||
75 | $tests[] = array($node, 'twig_date_converter($this->env, 0, "America/Chicago")'); | ||
76 | |||
77 | // function as an anonymous function | ||
78 | if (version_compare(phpversion(), '5.3.0', '>=')) { | ||
79 | $node = $this->createFunction('anonymous', array(new Twig_Node_Expression_Constant('foo', 1))); | ||
80 | $tests[] = array($node, 'call_user_func_array($this->env->getFunction(\'anonymous\')->getCallable(), array("foo"))'); | ||
81 | } | ||
82 | |||
83 | return $tests; | ||
84 | } | ||
85 | |||
86 | protected function createFunction($name, array $arguments = array()) | ||
87 | { | ||
88 | return new Twig_Node_Expression_Function($name, new Twig_Node($arguments), 1); | ||
89 | } | ||
90 | |||
91 | protected function getEnvironment() | ||
92 | { | ||
93 | if (version_compare(phpversion(), '5.3.0', '>=')) { | ||
94 | return include 'PHP53/FunctionInclude.php'; | ||
95 | } | ||
96 | |||
97 | return parent::getEnvironment(); | ||
98 | } | ||
99 | } | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Node/Expression/GetAttrTest.php b/vendor/twig/twig/test/Twig/Tests/Node/Expression/GetAttrTest.php new file mode 100644 index 00000000..6a63cce6 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Node/Expression/GetAttrTest.php | |||
@@ -0,0 +1,62 @@ | |||
1 | <?php | ||
2 | |||
3 | /* | ||
4 | * This file is part of Twig. | ||
5 | * | ||
6 | * (c) 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_Tests_Node_Expression_GetAttrTest extends Twig_Test_NodeTestCase | ||
13 | { | ||
14 | /** | ||
15 | * @covers Twig_Node_Expression_GetAttr::__construct | ||
16 | */ | ||
17 | public function testConstructor() | ||
18 | { | ||
19 | $expr = new Twig_Node_Expression_Name('foo', 1); | ||
20 | $attr = new Twig_Node_Expression_Constant('bar', 1); | ||
21 | $args = new Twig_Node_Expression_Array(array(), 1); | ||
22 | $args->addElement(new Twig_Node_Expression_Name('foo', 1)); | ||
23 | $args->addElement(new Twig_Node_Expression_Constant('bar', 1)); | ||
24 | $node = new Twig_Node_Expression_GetAttr($expr, $attr, $args, Twig_TemplateInterface::ARRAY_CALL, 1); | ||
25 | |||
26 | $this->assertEquals($expr, $node->getNode('node')); | ||
27 | $this->assertEquals($attr, $node->getNode('attribute')); | ||
28 | $this->assertEquals($args, $node->getNode('arguments')); | ||
29 | $this->assertEquals(Twig_TemplateInterface::ARRAY_CALL, $node->getAttribute('type')); | ||
30 | } | ||
31 | |||
32 | /** | ||
33 | * @covers Twig_Node_Expression_GetAttr::compile | ||
34 | * @dataProvider getTests | ||
35 | */ | ||
36 | public function testCompile($node, $source, $environment = null) | ||
37 | { | ||
38 | parent::testCompile($node, $source, $environment); | ||
39 | } | ||
40 | |||
41 | public function getTests() | ||
42 | { | ||
43 | $tests = array(); | ||
44 | |||
45 | $expr = new Twig_Node_Expression_Name('foo', 1); | ||
46 | $attr = new Twig_Node_Expression_Constant('bar', 1); | ||
47 | $args = new Twig_Node_Expression_Array(array(), 1); | ||
48 | $node = new Twig_Node_Expression_GetAttr($expr, $attr, $args, Twig_TemplateInterface::ANY_CALL, 1); | ||
49 | $tests[] = array($node, sprintf('%s%s, "bar")', $this->getAttributeGetter(), $this->getVariableGetter('foo'))); | ||
50 | |||
51 | $node = new Twig_Node_Expression_GetAttr($expr, $attr, $args, Twig_TemplateInterface::ARRAY_CALL, 1); | ||
52 | $tests[] = array($node, sprintf('%s%s, "bar", array(), "array")', $this->getAttributeGetter(), $this->getVariableGetter('foo'))); | ||
53 | |||
54 | $args = new Twig_Node_Expression_Array(array(), 1); | ||
55 | $args->addElement(new Twig_Node_Expression_Name('foo', 1)); | ||
56 | $args->addElement(new Twig_Node_Expression_Constant('bar', 1)); | ||
57 | $node = new Twig_Node_Expression_GetAttr($expr, $attr, $args, Twig_TemplateInterface::METHOD_CALL, 1); | ||
58 | $tests[] = array($node, sprintf('%s%s, "bar", array(0 => %s, 1 => "bar"), "method")', $this->getAttributeGetter(), $this->getVariableGetter('foo'), $this->getVariableGetter('foo'))); | ||
59 | |||
60 | return $tests; | ||
61 | } | ||
62 | } | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Node/Expression/NameTest.php b/vendor/twig/twig/test/Twig/Tests/Node/Expression/NameTest.php new file mode 100644 index 00000000..76d109b6 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Node/Expression/NameTest.php | |||
@@ -0,0 +1,49 @@ | |||
1 | <?php | ||
2 | |||
3 | /* | ||
4 | * This file is part of Twig. | ||
5 | * | ||
6 | * (c) 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_Tests_Node_Expression_NameTest extends Twig_Test_NodeTestCase | ||
13 | { | ||
14 | /** | ||
15 | * @covers Twig_Node_Expression_Name::__construct | ||
16 | */ | ||
17 | public function testConstructor() | ||
18 | { | ||
19 | $node = new Twig_Node_Expression_Name('foo', 1); | ||
20 | |||
21 | $this->assertEquals('foo', $node->getAttribute('name')); | ||
22 | } | ||
23 | |||
24 | /** | ||
25 | * @covers Twig_Node_Expression_Name::compile | ||
26 | * @dataProvider getTests | ||
27 | */ | ||
28 | public function testCompile($node, $source, $environment = null) | ||
29 | { | ||
30 | parent::testCompile($node, $source, $environment); | ||
31 | } | ||
32 | |||
33 | public function getTests() | ||
34 | { | ||
35 | $node = new Twig_Node_Expression_Name('foo', 1); | ||
36 | $self = new Twig_Node_Expression_Name('_self', 1); | ||
37 | $context = new Twig_Node_Expression_Name('_context', 1); | ||
38 | |||
39 | $env = new Twig_Environment(null, array('strict_variables' => true)); | ||
40 | $env1 = new Twig_Environment(null, array('strict_variables' => false)); | ||
41 | |||
42 | return array( | ||
43 | version_compare(PHP_VERSION, '5.4.0') >= 0 ? array($node, '(isset($context["foo"]) ? $context["foo"] : $this->getContext($context, "foo"))', $env) : array($node, '$this->getContext($context, "foo")', $env), | ||
44 | array($node, $this->getVariableGetter('foo'), $env1), | ||
45 | array($self, '$this'), | ||
46 | array($context, '$context'), | ||
47 | ); | ||
48 | } | ||
49 | } | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Node/Expression/PHP53/FilterInclude.php b/vendor/twig/twig/test/Twig/Tests/Node/Expression/PHP53/FilterInclude.php new file mode 100644 index 00000000..15e3aa96 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Node/Expression/PHP53/FilterInclude.php | |||
@@ -0,0 +1,6 @@ | |||
1 | <?php | ||
2 | |||
3 | $env = new Twig_Environment(); | ||
4 | $env->addFilter(new Twig_SimpleFilter('anonymous', function () {})); | ||
5 | |||
6 | return $env; | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Node/Expression/PHP53/FunctionInclude.php b/vendor/twig/twig/test/Twig/Tests/Node/Expression/PHP53/FunctionInclude.php new file mode 100644 index 00000000..d2170ed2 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Node/Expression/PHP53/FunctionInclude.php | |||
@@ -0,0 +1,6 @@ | |||
1 | <?php | ||
2 | |||
3 | $env = new Twig_Environment(); | ||
4 | $env->addFunction(new Twig_SimpleFunction('anonymous', function () {})); | ||
5 | |||
6 | return $env; | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Node/Expression/PHP53/TestInclude.php b/vendor/twig/twig/test/Twig/Tests/Node/Expression/PHP53/TestInclude.php new file mode 100644 index 00000000..63662864 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Node/Expression/PHP53/TestInclude.php | |||
@@ -0,0 +1,6 @@ | |||
1 | <?php | ||
2 | |||
3 | $env = new Twig_Environment(); | ||
4 | $env->addTest(new Twig_SimpleTest('anonymous', function () {})); | ||
5 | |||
6 | return $env; | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Node/Expression/ParentTest.php b/vendor/twig/twig/test/Twig/Tests/Node/Expression/ParentTest.php new file mode 100644 index 00000000..4d40419b --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Node/Expression/ParentTest.php | |||
@@ -0,0 +1,40 @@ | |||
1 | <?php | ||
2 | |||
3 | /* | ||
4 | * This file is part of Twig. | ||
5 | * | ||
6 | * (c) 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_Tests_Node_Expression_ParentTest extends Twig_Test_NodeTestCase | ||
13 | { | ||
14 | /** | ||
15 | * @covers Twig_Node_Expression_Parent::__construct | ||
16 | */ | ||
17 | public function testConstructor() | ||
18 | { | ||
19 | $node = new Twig_Node_Expression_Parent('foo', 1); | ||
20 | |||
21 | $this->assertEquals('foo', $node->getAttribute('name')); | ||
22 | } | ||
23 | |||
24 | /** | ||
25 | * @covers Twig_Node_Expression_Parent::compile | ||
26 | * @dataProvider getTests | ||
27 | */ | ||
28 | public function testCompile($node, $source, $environment = null) | ||
29 | { | ||
30 | parent::testCompile($node, $source, $environment); | ||
31 | } | ||
32 | |||
33 | public function getTests() | ||
34 | { | ||
35 | $tests = array(); | ||
36 | $tests[] = array(new Twig_Node_Expression_Parent('foo', 1), '$this->renderParentBlock("foo", $context, $blocks)'); | ||
37 | |||
38 | return $tests; | ||
39 | } | ||
40 | } | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Node/Expression/TestTest.php b/vendor/twig/twig/test/Twig/Tests/Node/Expression/TestTest.php new file mode 100644 index 00000000..0664150a --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Node/Expression/TestTest.php | |||
@@ -0,0 +1,68 @@ | |||
1 | <?php | ||
2 | |||
3 | /* | ||
4 | * This file is part of Twig. | ||
5 | * | ||
6 | * (c) 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_Tests_Node_Expression_TestTest extends Twig_Test_NodeTestCase | ||
13 | { | ||
14 | /** | ||
15 | * @covers Twig_Node_Expression_Test::__construct | ||
16 | */ | ||
17 | public function testConstructor() | ||
18 | { | ||
19 | $expr = new Twig_Node_Expression_Constant('foo', 1); | ||
20 | $name = new Twig_Node_Expression_Constant('null', 1); | ||
21 | $args = new Twig_Node(); | ||
22 | $node = new Twig_Node_Expression_Test($expr, $name, $args, 1); | ||
23 | |||
24 | $this->assertEquals($expr, $node->getNode('node')); | ||
25 | $this->assertEquals($args, $node->getNode('arguments')); | ||
26 | $this->assertEquals($name, $node->getAttribute('name')); | ||
27 | } | ||
28 | |||
29 | /** | ||
30 | * @covers Twig_Node_Expression_Test::compile | ||
31 | * @dataProvider getTests | ||
32 | */ | ||
33 | public function testCompile($node, $source, $environment = null) | ||
34 | { | ||
35 | parent::testCompile($node, $source, $environment); | ||
36 | } | ||
37 | |||
38 | public function getTests() | ||
39 | { | ||
40 | $tests = array(); | ||
41 | |||
42 | $expr = new Twig_Node_Expression_Constant('foo', 1); | ||
43 | $node = new Twig_Node_Expression_Test_Null($expr, 'null', new Twig_Node(array()), 1); | ||
44 | $tests[] = array($node, '(null === "foo")'); | ||
45 | |||
46 | // test as an anonymous function | ||
47 | if (version_compare(phpversion(), '5.3.0', '>=')) { | ||
48 | $node = $this->createTest(new Twig_Node_Expression_Constant('foo', 1), 'anonymous', array(new Twig_Node_Expression_Constant('foo', 1))); | ||
49 | $tests[] = array($node, 'call_user_func_array($this->env->getTest(\'anonymous\')->getCallable(), array("foo", "foo"))'); | ||
50 | } | ||
51 | |||
52 | return $tests; | ||
53 | } | ||
54 | |||
55 | protected function createTest($node, $name, array $arguments = array()) | ||
56 | { | ||
57 | return new Twig_Node_Expression_Test($node, $name, new Twig_Node($arguments), 1); | ||
58 | } | ||
59 | |||
60 | protected function getEnvironment() | ||
61 | { | ||
62 | if (version_compare(phpversion(), '5.3.0', '>=')) { | ||
63 | return include 'PHP53/TestInclude.php'; | ||
64 | } | ||
65 | |||
66 | return parent::getEnvironment(); | ||
67 | } | ||
68 | } | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Node/Expression/Unary/NegTest.php b/vendor/twig/twig/test/Twig/Tests/Node/Expression/Unary/NegTest.php new file mode 100644 index 00000000..d55ab333 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Node/Expression/Unary/NegTest.php | |||
@@ -0,0 +1,44 @@ | |||
1 | <?php | ||
2 | |||
3 | /* | ||
4 | * This file is part of Twig. | ||
5 | * | ||
6 | * (c) 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_Tests_Node_Expression_Unary_NegTest extends Twig_Test_NodeTestCase | ||
13 | { | ||
14 | /** | ||
15 | * @covers Twig_Node_Expression_Unary_Neg::__construct | ||
16 | */ | ||
17 | public function testConstructor() | ||
18 | { | ||
19 | $expr = new Twig_Node_Expression_Constant(1, 1); | ||
20 | $node = new Twig_Node_Expression_Unary_Neg($expr, 1); | ||
21 | |||
22 | $this->assertEquals($expr, $node->getNode('node')); | ||
23 | } | ||
24 | |||
25 | /** | ||
26 | * @covers Twig_Node_Expression_Unary_Neg::compile | ||
27 | * @covers Twig_Node_Expression_Unary_Neg::operator | ||
28 | * @dataProvider getTests | ||
29 | */ | ||
30 | public function testCompile($node, $source, $environment = null) | ||
31 | { | ||
32 | parent::testCompile($node, $source, $environment); | ||
33 | } | ||
34 | |||
35 | public function getTests() | ||
36 | { | ||
37 | $node = new Twig_Node_Expression_Constant(1, 1); | ||
38 | $node = new Twig_Node_Expression_Unary_Neg($node, 1); | ||
39 | |||
40 | return array( | ||
41 | array($node, '(-1)'), | ||
42 | ); | ||
43 | } | ||
44 | } | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Node/Expression/Unary/NotTest.php b/vendor/twig/twig/test/Twig/Tests/Node/Expression/Unary/NotTest.php new file mode 100644 index 00000000..625c2527 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Node/Expression/Unary/NotTest.php | |||
@@ -0,0 +1,44 @@ | |||
1 | <?php | ||
2 | |||
3 | /* | ||
4 | * This file is part of Twig. | ||
5 | * | ||
6 | * (c) 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_Tests_Node_Expression_Unary_NotTest extends Twig_Test_NodeTestCase | ||
13 | { | ||
14 | /** | ||
15 | * @covers Twig_Node_Expression_Unary_Not::__construct | ||
16 | */ | ||
17 | public function testConstructor() | ||
18 | { | ||
19 | $expr = new Twig_Node_Expression_Constant(1, 1); | ||
20 | $node = new Twig_Node_Expression_Unary_Not($expr, 1); | ||
21 | |||
22 | $this->assertEquals($expr, $node->getNode('node')); | ||
23 | } | ||
24 | |||
25 | /** | ||
26 | * @covers Twig_Node_Expression_Unary_Not::compile | ||
27 | * @covers Twig_Node_Expression_Unary_Not::operator | ||
28 | * @dataProvider getTests | ||
29 | */ | ||
30 | public function testCompile($node, $source, $environment = null) | ||
31 | { | ||
32 | parent::testCompile($node, $source, $environment); | ||
33 | } | ||
34 | |||
35 | public function getTests() | ||
36 | { | ||
37 | $node = new Twig_Node_Expression_Constant(1, 1); | ||
38 | $node = new Twig_Node_Expression_Unary_Not($node, 1); | ||
39 | |||
40 | return array( | ||
41 | array($node, '(!1)'), | ||
42 | ); | ||
43 | } | ||
44 | } | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Node/Expression/Unary/PosTest.php b/vendor/twig/twig/test/Twig/Tests/Node/Expression/Unary/PosTest.php new file mode 100644 index 00000000..047a0977 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Node/Expression/Unary/PosTest.php | |||
@@ -0,0 +1,44 @@ | |||
1 | <?php | ||
2 | |||
3 | /* | ||
4 | * This file is part of Twig. | ||
5 | * | ||
6 | * (c) 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_Tests_Node_Expression_Unary_PosTest extends Twig_Test_NodeTestCase | ||
13 | { | ||
14 | /** | ||
15 | * @covers Twig_Node_Expression_Unary_Pos::__construct | ||
16 | */ | ||
17 | public function testConstructor() | ||
18 | { | ||
19 | $expr = new Twig_Node_Expression_Constant(1, 1); | ||
20 | $node = new Twig_Node_Expression_Unary_Pos($expr, 1); | ||
21 | |||
22 | $this->assertEquals($expr, $node->getNode('node')); | ||
23 | } | ||
24 | |||
25 | /** | ||
26 | * @covers Twig_Node_Expression_Unary_Pos::compile | ||
27 | * @covers Twig_Node_Expression_Unary_Pos::operator | ||
28 | * @dataProvider getTests | ||
29 | */ | ||
30 | public function testCompile($node, $source, $environment = null) | ||
31 | { | ||
32 | parent::testCompile($node, $source, $environment); | ||
33 | } | ||
34 | |||
35 | public function getTests() | ||
36 | { | ||
37 | $node = new Twig_Node_Expression_Constant(1, 1); | ||
38 | $node = new Twig_Node_Expression_Unary_Pos($node, 1); | ||
39 | |||
40 | return array( | ||
41 | array($node, '(+1)'), | ||
42 | ); | ||
43 | } | ||
44 | } | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Node/ForTest.php b/vendor/twig/twig/test/Twig/Tests/Node/ForTest.php new file mode 100644 index 00000000..21cc84e6 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Node/ForTest.php | |||
@@ -0,0 +1,203 @@ | |||
1 | <?php | ||
2 | |||
3 | /* | ||
4 | * This file is part of Twig. | ||
5 | * | ||
6 | * (c) 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_Tests_Node_ForTest extends Twig_Test_NodeTestCase | ||
13 | { | ||
14 | /** | ||
15 | * @covers Twig_Node_For::__construct | ||
16 | */ | ||
17 | public function testConstructor() | ||
18 | { | ||
19 | $keyTarget = new Twig_Node_Expression_AssignName('key', 1); | ||
20 | $valueTarget = new Twig_Node_Expression_AssignName('item', 1); | ||
21 | $seq = new Twig_Node_Expression_Name('items', 1); | ||
22 | $ifexpr = new Twig_Node_Expression_Constant(true, 1); | ||
23 | $body = new Twig_Node(array(new Twig_Node_Print(new Twig_Node_Expression_Name('foo', 1), 1)), array(), 1); | ||
24 | $else = null; | ||
25 | $node = new Twig_Node_For($keyTarget, $valueTarget, $seq, $ifexpr, $body, $else, 1); | ||
26 | $node->setAttribute('with_loop', false); | ||
27 | |||
28 | $this->assertEquals($keyTarget, $node->getNode('key_target')); | ||
29 | $this->assertEquals($valueTarget, $node->getNode('value_target')); | ||
30 | $this->assertEquals($seq, $node->getNode('seq')); | ||
31 | $this->assertTrue($node->getAttribute('ifexpr')); | ||
32 | $this->assertEquals('Twig_Node_If', get_class($node->getNode('body'))); | ||
33 | $this->assertEquals($body, $node->getNode('body')->getNode('tests')->getNode(1)->getNode(0)); | ||
34 | $this->assertEquals(null, $node->getNode('else')); | ||
35 | |||
36 | $else = new Twig_Node_Print(new Twig_Node_Expression_Name('foo', 1), 1); | ||
37 | $node = new Twig_Node_For($keyTarget, $valueTarget, $seq, $ifexpr, $body, $else, 1); | ||
38 | $node->setAttribute('with_loop', false); | ||
39 | $this->assertEquals($else, $node->getNode('else')); | ||
40 | } | ||
41 | |||
42 | /** | ||
43 | * @covers Twig_Node_For::compile | ||
44 | * @dataProvider getTests | ||
45 | */ | ||
46 | public function testCompile($node, $source, $environment = null) | ||
47 | { | ||
48 | parent::testCompile($node, $source, $environment); | ||
49 | } | ||
50 | |||
51 | public function getTests() | ||
52 | { | ||
53 | $tests = array(); | ||
54 | |||
55 | $keyTarget = new Twig_Node_Expression_AssignName('key', 1); | ||
56 | $valueTarget = new Twig_Node_Expression_AssignName('item', 1); | ||
57 | $seq = new Twig_Node_Expression_Name('items', 1); | ||
58 | $ifexpr = null; | ||
59 | $body = new Twig_Node(array(new Twig_Node_Print(new Twig_Node_Expression_Name('foo', 1), 1)), array(), 1); | ||
60 | $else = null; | ||
61 | $node = new Twig_Node_For($keyTarget, $valueTarget, $seq, $ifexpr, $body, $else, 1); | ||
62 | $node->setAttribute('with_loop', false); | ||
63 | |||
64 | $tests[] = array($node, <<<EOF | ||
65 | // line 1 | ||
66 | \$context['_parent'] = (array) \$context; | ||
67 | \$context['_seq'] = twig_ensure_traversable({$this->getVariableGetter('items')}); | ||
68 | foreach (\$context['_seq'] as \$context["key"] => \$context["item"]) { | ||
69 | echo {$this->getVariableGetter('foo')}; | ||
70 | } | ||
71 | \$_parent = \$context['_parent']; | ||
72 | unset(\$context['_seq'], \$context['_iterated'], \$context['key'], \$context['item'], \$context['_parent'], \$context['loop']); | ||
73 | \$context = array_intersect_key(\$context, \$_parent) + \$_parent; | ||
74 | EOF | ||
75 | ); | ||
76 | |||
77 | $keyTarget = new Twig_Node_Expression_AssignName('k', 1); | ||
78 | $valueTarget = new Twig_Node_Expression_AssignName('v', 1); | ||
79 | $seq = new Twig_Node_Expression_Name('values', 1); | ||
80 | $ifexpr = null; | ||
81 | $body = new Twig_Node(array(new Twig_Node_Print(new Twig_Node_Expression_Name('foo', 1), 1)), array(), 1); | ||
82 | $else = null; | ||
83 | $node = new Twig_Node_For($keyTarget, $valueTarget, $seq, $ifexpr, $body, $else, 1); | ||
84 | $node->setAttribute('with_loop', true); | ||
85 | |||
86 | $tests[] = array($node, <<<EOF | ||
87 | // line 1 | ||
88 | \$context['_parent'] = (array) \$context; | ||
89 | \$context['_seq'] = twig_ensure_traversable({$this->getVariableGetter('values')}); | ||
90 | \$context['loop'] = array( | ||
91 | 'parent' => \$context['_parent'], | ||
92 | 'index0' => 0, | ||
93 | 'index' => 1, | ||
94 | 'first' => true, | ||
95 | ); | ||
96 | if (is_array(\$context['_seq']) || (is_object(\$context['_seq']) && \$context['_seq'] instanceof Countable)) { | ||
97 | \$length = count(\$context['_seq']); | ||
98 | \$context['loop']['revindex0'] = \$length - 1; | ||
99 | \$context['loop']['revindex'] = \$length; | ||
100 | \$context['loop']['length'] = \$length; | ||
101 | \$context['loop']['last'] = 1 === \$length; | ||
102 | } | ||
103 | foreach (\$context['_seq'] as \$context["k"] => \$context["v"]) { | ||
104 | echo {$this->getVariableGetter('foo')}; | ||
105 | ++\$context['loop']['index0']; | ||
106 | ++\$context['loop']['index']; | ||
107 | \$context['loop']['first'] = false; | ||
108 | if (isset(\$context['loop']['length'])) { | ||
109 | --\$context['loop']['revindex0']; | ||
110 | --\$context['loop']['revindex']; | ||
111 | \$context['loop']['last'] = 0 === \$context['loop']['revindex0']; | ||
112 | } | ||
113 | } | ||
114 | \$_parent = \$context['_parent']; | ||
115 | unset(\$context['_seq'], \$context['_iterated'], \$context['k'], \$context['v'], \$context['_parent'], \$context['loop']); | ||
116 | \$context = array_intersect_key(\$context, \$_parent) + \$_parent; | ||
117 | EOF | ||
118 | ); | ||
119 | |||
120 | $keyTarget = new Twig_Node_Expression_AssignName('k', 1); | ||
121 | $valueTarget = new Twig_Node_Expression_AssignName('v', 1); | ||
122 | $seq = new Twig_Node_Expression_Name('values', 1); | ||
123 | $ifexpr = new Twig_Node_Expression_Constant(true, 1); | ||
124 | $body = new Twig_Node(array(new Twig_Node_Print(new Twig_Node_Expression_Name('foo', 1), 1)), array(), 1); | ||
125 | $else = null; | ||
126 | $node = new Twig_Node_For($keyTarget, $valueTarget, $seq, $ifexpr, $body, $else, 1); | ||
127 | $node->setAttribute('with_loop', true); | ||
128 | |||
129 | $tests[] = array($node, <<<EOF | ||
130 | // line 1 | ||
131 | \$context['_parent'] = (array) \$context; | ||
132 | \$context['_seq'] = twig_ensure_traversable({$this->getVariableGetter('values')}); | ||
133 | \$context['loop'] = array( | ||
134 | 'parent' => \$context['_parent'], | ||
135 | 'index0' => 0, | ||
136 | 'index' => 1, | ||
137 | 'first' => true, | ||
138 | ); | ||
139 | foreach (\$context['_seq'] as \$context["k"] => \$context["v"]) { | ||
140 | if (true) { | ||
141 | echo {$this->getVariableGetter('foo')}; | ||
142 | ++\$context['loop']['index0']; | ||
143 | ++\$context['loop']['index']; | ||
144 | \$context['loop']['first'] = false; | ||
145 | } | ||
146 | } | ||
147 | \$_parent = \$context['_parent']; | ||
148 | unset(\$context['_seq'], \$context['_iterated'], \$context['k'], \$context['v'], \$context['_parent'], \$context['loop']); | ||
149 | \$context = array_intersect_key(\$context, \$_parent) + \$_parent; | ||
150 | EOF | ||
151 | ); | ||
152 | |||
153 | $keyTarget = new Twig_Node_Expression_AssignName('k', 1); | ||
154 | $valueTarget = new Twig_Node_Expression_AssignName('v', 1); | ||
155 | $seq = new Twig_Node_Expression_Name('values', 1); | ||
156 | $ifexpr = null; | ||
157 | $body = new Twig_Node(array(new Twig_Node_Print(new Twig_Node_Expression_Name('foo', 1), 1)), array(), 1); | ||
158 | $else = new Twig_Node_Print(new Twig_Node_Expression_Name('foo', 1), 1); | ||
159 | $node = new Twig_Node_For($keyTarget, $valueTarget, $seq, $ifexpr, $body, $else, 1); | ||
160 | $node->setAttribute('with_loop', true); | ||
161 | |||
162 | $tests[] = array($node, <<<EOF | ||
163 | // line 1 | ||
164 | \$context['_parent'] = (array) \$context; | ||
165 | \$context['_seq'] = twig_ensure_traversable({$this->getVariableGetter('values')}); | ||
166 | \$context['_iterated'] = false; | ||
167 | \$context['loop'] = array( | ||
168 | 'parent' => \$context['_parent'], | ||
169 | 'index0' => 0, | ||
170 | 'index' => 1, | ||
171 | 'first' => true, | ||
172 | ); | ||
173 | if (is_array(\$context['_seq']) || (is_object(\$context['_seq']) && \$context['_seq'] instanceof Countable)) { | ||
174 | \$length = count(\$context['_seq']); | ||
175 | \$context['loop']['revindex0'] = \$length - 1; | ||
176 | \$context['loop']['revindex'] = \$length; | ||
177 | \$context['loop']['length'] = \$length; | ||
178 | \$context['loop']['last'] = 1 === \$length; | ||
179 | } | ||
180 | foreach (\$context['_seq'] as \$context["k"] => \$context["v"]) { | ||
181 | echo {$this->getVariableGetter('foo')}; | ||
182 | \$context['_iterated'] = true; | ||
183 | ++\$context['loop']['index0']; | ||
184 | ++\$context['loop']['index']; | ||
185 | \$context['loop']['first'] = false; | ||
186 | if (isset(\$context['loop']['length'])) { | ||
187 | --\$context['loop']['revindex0']; | ||
188 | --\$context['loop']['revindex']; | ||
189 | \$context['loop']['last'] = 0 === \$context['loop']['revindex0']; | ||
190 | } | ||
191 | } | ||
192 | if (!\$context['_iterated']) { | ||
193 | echo {$this->getVariableGetter('foo')}; | ||
194 | } | ||
195 | \$_parent = \$context['_parent']; | ||
196 | unset(\$context['_seq'], \$context['_iterated'], \$context['k'], \$context['v'], \$context['_parent'], \$context['loop']); | ||
197 | \$context = array_intersect_key(\$context, \$_parent) + \$_parent; | ||
198 | EOF | ||
199 | ); | ||
200 | |||
201 | return $tests; | ||
202 | } | ||
203 | } | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Node/IfTest.php b/vendor/twig/twig/test/Twig/Tests/Node/IfTest.php new file mode 100644 index 00000000..92fc29dc --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Node/IfTest.php | |||
@@ -0,0 +1,100 @@ | |||
1 | <?php | ||
2 | |||
3 | /* | ||
4 | * This file is part of Twig. | ||
5 | * | ||
6 | * (c) 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_Tests_Node_IfTest extends Twig_Test_NodeTestCase | ||
13 | { | ||
14 | /** | ||
15 | * @covers Twig_Node_If::__construct | ||
16 | */ | ||
17 | public function testConstructor() | ||
18 | { | ||
19 | $t = new Twig_Node(array( | ||
20 | new Twig_Node_Expression_Constant(true, 1), | ||
21 | new Twig_Node_Print(new Twig_Node_Expression_Name('foo', 1), 1), | ||
22 | ), array(), 1); | ||
23 | $else = null; | ||
24 | $node = new Twig_Node_If($t, $else, 1); | ||
25 | |||
26 | $this->assertEquals($t, $node->getNode('tests')); | ||
27 | $this->assertEquals(null, $node->getNode('else')); | ||
28 | |||
29 | $else = new Twig_Node_Print(new Twig_Node_Expression_Name('bar', 1), 1); | ||
30 | $node = new Twig_Node_If($t, $else, 1); | ||
31 | $this->assertEquals($else, $node->getNode('else')); | ||
32 | } | ||
33 | |||
34 | /** | ||
35 | * @covers Twig_Node_If::compile | ||
36 | * @dataProvider getTests | ||
37 | */ | ||
38 | public function testCompile($node, $source, $environment = null) | ||
39 | { | ||
40 | parent::testCompile($node, $source, $environment); | ||
41 | } | ||
42 | |||
43 | public function getTests() | ||
44 | { | ||
45 | $tests = array(); | ||
46 | |||
47 | $t = new Twig_Node(array( | ||
48 | new Twig_Node_Expression_Constant(true, 1), | ||
49 | new Twig_Node_Print(new Twig_Node_Expression_Name('foo', 1), 1), | ||
50 | ), array(), 1); | ||
51 | $else = null; | ||
52 | $node = new Twig_Node_If($t, $else, 1); | ||
53 | |||
54 | $tests[] = array($node, <<<EOF | ||
55 | // line 1 | ||
56 | if (true) { | ||
57 | echo {$this->getVariableGetter('foo')}; | ||
58 | } | ||
59 | EOF | ||
60 | ); | ||
61 | |||
62 | $t = new Twig_Node(array( | ||
63 | new Twig_Node_Expression_Constant(true, 1), | ||
64 | new Twig_Node_Print(new Twig_Node_Expression_Name('foo', 1), 1), | ||
65 | new Twig_Node_Expression_Constant(false, 1), | ||
66 | new Twig_Node_Print(new Twig_Node_Expression_Name('bar', 1), 1), | ||
67 | ), array(), 1); | ||
68 | $else = null; | ||
69 | $node = new Twig_Node_If($t, $else, 1); | ||
70 | |||
71 | $tests[] = array($node, <<<EOF | ||
72 | // line 1 | ||
73 | if (true) { | ||
74 | echo {$this->getVariableGetter('foo')}; | ||
75 | } elseif (false) { | ||
76 | echo {$this->getVariableGetter('bar')}; | ||
77 | } | ||
78 | EOF | ||
79 | ); | ||
80 | |||
81 | $t = new Twig_Node(array( | ||
82 | new Twig_Node_Expression_Constant(true, 1), | ||
83 | new Twig_Node_Print(new Twig_Node_Expression_Name('foo', 1), 1), | ||
84 | ), array(), 1); | ||
85 | $else = new Twig_Node_Print(new Twig_Node_Expression_Name('bar', 1), 1); | ||
86 | $node = new Twig_Node_If($t, $else, 1); | ||
87 | |||
88 | $tests[] = array($node, <<<EOF | ||
89 | // line 1 | ||
90 | if (true) { | ||
91 | echo {$this->getVariableGetter('foo')}; | ||
92 | } else { | ||
93 | echo {$this->getVariableGetter('bar')}; | ||
94 | } | ||
95 | EOF | ||
96 | ); | ||
97 | |||
98 | return $tests; | ||
99 | } | ||
100 | } | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Node/ImportTest.php b/vendor/twig/twig/test/Twig/Tests/Node/ImportTest.php new file mode 100644 index 00000000..db36581a --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Node/ImportTest.php | |||
@@ -0,0 +1,52 @@ | |||
1 | <?php | ||
2 | |||
3 | /* | ||
4 | * This file is part of Twig. | ||
5 | * | ||
6 | * (c) 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_Tests_Node_ImportTest extends Twig_Test_NodeTestCase | ||
13 | { | ||
14 | /** | ||
15 | * @covers Twig_Node_Import::__construct | ||
16 | */ | ||
17 | public function testConstructor() | ||
18 | { | ||
19 | $macro = new Twig_Node_Expression_Constant('foo.twig', 1); | ||
20 | $var = new Twig_Node_Expression_AssignName('macro', 1); | ||
21 | $node = new Twig_Node_Import($macro, $var, 1); | ||
22 | |||
23 | $this->assertEquals($macro, $node->getNode('expr')); | ||
24 | $this->assertEquals($var, $node->getNode('var')); | ||
25 | } | ||
26 | |||
27 | /** | ||
28 | * @covers Twig_Node_Import::compile | ||
29 | * @dataProvider getTests | ||
30 | */ | ||
31 | public function testCompile($node, $source, $environment = null) | ||
32 | { | ||
33 | parent::testCompile($node, $source, $environment); | ||
34 | } | ||
35 | |||
36 | public function getTests() | ||
37 | { | ||
38 | $tests = array(); | ||
39 | |||
40 | $macro = new Twig_Node_Expression_Constant('foo.twig', 1); | ||
41 | $var = new Twig_Node_Expression_AssignName('macro', 1); | ||
42 | $node = new Twig_Node_Import($macro, $var, 1); | ||
43 | |||
44 | $tests[] = array($node, <<<EOF | ||
45 | // line 1 | ||
46 | \$context["macro"] = \$this->env->loadTemplate("foo.twig"); | ||
47 | EOF | ||
48 | ); | ||
49 | |||
50 | return $tests; | ||
51 | } | ||
52 | } | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Node/IncludeTest.php b/vendor/twig/twig/test/Twig/Tests/Node/IncludeTest.php new file mode 100644 index 00000000..3b7da6e0 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Node/IncludeTest.php | |||
@@ -0,0 +1,96 @@ | |||
1 | <?php | ||
2 | |||
3 | /* | ||
4 | * This file is part of Twig. | ||
5 | * | ||
6 | * (c) 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_Tests_Node_IncludeTest extends Twig_Test_NodeTestCase | ||
13 | { | ||
14 | /** | ||
15 | * @covers Twig_Node_Include::__construct | ||
16 | */ | ||
17 | public function testConstructor() | ||
18 | { | ||
19 | $expr = new Twig_Node_Expression_Constant('foo.twig', 1); | ||
20 | $node = new Twig_Node_Include($expr, null, false, false, 1); | ||
21 | |||
22 | $this->assertEquals(null, $node->getNode('variables')); | ||
23 | $this->assertEquals($expr, $node->getNode('expr')); | ||
24 | $this->assertFalse($node->getAttribute('only')); | ||
25 | |||
26 | $vars = new Twig_Node_Expression_Array(array(new Twig_Node_Expression_Constant('foo', 1), new Twig_Node_Expression_Constant(true, 1)), 1); | ||
27 | $node = new Twig_Node_Include($expr, $vars, true, false, 1); | ||
28 | $this->assertEquals($vars, $node->getNode('variables')); | ||
29 | $this->assertTrue($node->getAttribute('only')); | ||
30 | } | ||
31 | |||
32 | /** | ||
33 | * @covers Twig_Node_Include::compile | ||
34 | * @dataProvider getTests | ||
35 | */ | ||
36 | public function testCompile($node, $source, $environment = null) | ||
37 | { | ||
38 | parent::testCompile($node, $source, $environment); | ||
39 | } | ||
40 | |||
41 | public function getTests() | ||
42 | { | ||
43 | $tests = array(); | ||
44 | |||
45 | $expr = new Twig_Node_Expression_Constant('foo.twig', 1); | ||
46 | $node = new Twig_Node_Include($expr, null, false, false, 1); | ||
47 | $tests[] = array($node, <<<EOF | ||
48 | // line 1 | ||
49 | \$this->env->loadTemplate("foo.twig")->display(\$context); | ||
50 | EOF | ||
51 | ); | ||
52 | |||
53 | $expr = new Twig_Node_Expression_Conditional( | ||
54 | new Twig_Node_Expression_Constant(true, 1), | ||
55 | new Twig_Node_Expression_Constant('foo', 1), | ||
56 | new Twig_Node_Expression_Constant('foo', 1), | ||
57 | 0 | ||
58 | ); | ||
59 | $node = new Twig_Node_Include($expr, null, false, false, 1); | ||
60 | $tests[] = array($node, <<<EOF | ||
61 | // line 1 | ||
62 | \$template = \$this->env->resolveTemplate(((true) ? ("foo") : ("foo"))); | ||
63 | \$template->display(\$context); | ||
64 | EOF | ||
65 | ); | ||
66 | |||
67 | $expr = new Twig_Node_Expression_Constant('foo.twig', 1); | ||
68 | $vars = new Twig_Node_Expression_Array(array(new Twig_Node_Expression_Constant('foo', 1), new Twig_Node_Expression_Constant(true, 1)), 1); | ||
69 | $node = new Twig_Node_Include($expr, $vars, false, false, 1); | ||
70 | $tests[] = array($node, <<<EOF | ||
71 | // line 1 | ||
72 | \$this->env->loadTemplate("foo.twig")->display(array_merge(\$context, array("foo" => true))); | ||
73 | EOF | ||
74 | ); | ||
75 | |||
76 | $node = new Twig_Node_Include($expr, $vars, true, false, 1); | ||
77 | $tests[] = array($node, <<<EOF | ||
78 | // line 1 | ||
79 | \$this->env->loadTemplate("foo.twig")->display(array("foo" => true)); | ||
80 | EOF | ||
81 | ); | ||
82 | |||
83 | $node = new Twig_Node_Include($expr, $vars, true, true, 1); | ||
84 | $tests[] = array($node, <<<EOF | ||
85 | // line 1 | ||
86 | try { | ||
87 | \$this->env->loadTemplate("foo.twig")->display(array("foo" => true)); | ||
88 | } catch (Twig_Error_Loader \$e) { | ||
89 | // ignore missing template | ||
90 | } | ||
91 | EOF | ||
92 | ); | ||
93 | |||
94 | return $tests; | ||
95 | } | ||
96 | } | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Node/MacroTest.php b/vendor/twig/twig/test/Twig/Tests/Node/MacroTest.php new file mode 100644 index 00000000..4d2f641b --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Node/MacroTest.php | |||
@@ -0,0 +1,73 @@ | |||
1 | <?php | ||
2 | |||
3 | /* | ||
4 | * This file is part of Twig. | ||
5 | * | ||
6 | * (c) 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_Tests_Node_MacroTest extends Twig_Test_NodeTestCase | ||
13 | { | ||
14 | /** | ||
15 | * @covers Twig_Node_Macro::__construct | ||
16 | */ | ||
17 | public function testConstructor() | ||
18 | { | ||
19 | $body = new Twig_Node_Text('foo', 1); | ||
20 | $arguments = new Twig_Node(array(new Twig_Node_Expression_Name('foo', 1)), array(), 1); | ||
21 | $node = new Twig_Node_Macro('foo', $body, $arguments, 1); | ||
22 | |||
23 | $this->assertEquals($body, $node->getNode('body')); | ||
24 | $this->assertEquals($arguments, $node->getNode('arguments')); | ||
25 | $this->assertEquals('foo', $node->getAttribute('name')); | ||
26 | } | ||
27 | |||
28 | /** | ||
29 | * @covers Twig_Node_Macro::compile | ||
30 | * @dataProvider getTests | ||
31 | */ | ||
32 | public function testCompile($node, $source, $environment = null) | ||
33 | { | ||
34 | parent::testCompile($node, $source, $environment); | ||
35 | } | ||
36 | |||
37 | public function getTests() | ||
38 | { | ||
39 | $body = new Twig_Node_Text('foo', 1); | ||
40 | $arguments = new Twig_Node(array( | ||
41 | 'foo' => new Twig_Node_Expression_Constant(null, 1), | ||
42 | 'bar' => new Twig_Node_Expression_Constant('Foo', 1), | ||
43 | ), array(), 1); | ||
44 | $node = new Twig_Node_Macro('foo', $body, $arguments, 1); | ||
45 | |||
46 | return array( | ||
47 | array($node, <<<EOF | ||
48 | // line 1 | ||
49 | public function getfoo(\$_foo = null, \$_bar = "Foo") | ||
50 | { | ||
51 | \$context = \$this->env->mergeGlobals(array( | ||
52 | "foo" => \$_foo, | ||
53 | "bar" => \$_bar, | ||
54 | )); | ||
55 | |||
56 | \$blocks = array(); | ||
57 | |||
58 | ob_start(); | ||
59 | try { | ||
60 | echo "foo"; | ||
61 | } catch (Exception \$e) { | ||
62 | ob_end_clean(); | ||
63 | |||
64 | throw \$e; | ||
65 | } | ||
66 | |||
67 | return ('' === \$tmp = ob_get_clean()) ? '' : new Twig_Markup(\$tmp, \$this->env->getCharset()); | ||
68 | } | ||
69 | EOF | ||
70 | ), | ||
71 | ); | ||
72 | } | ||
73 | } | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Node/ModuleTest.php b/vendor/twig/twig/test/Twig/Tests/Node/ModuleTest.php new file mode 100644 index 00000000..9411e99e --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Node/ModuleTest.php | |||
@@ -0,0 +1,196 @@ | |||
1 | <?php | ||
2 | |||
3 | /* | ||
4 | * This file is part of Twig. | ||
5 | * | ||
6 | * (c) 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_Tests_Node_ModuleTest extends Twig_Test_NodeTestCase | ||
13 | { | ||
14 | /** | ||
15 | * @covers Twig_Node_Module::__construct | ||
16 | */ | ||
17 | public function testConstructor() | ||
18 | { | ||
19 | $body = new Twig_Node_Text('foo', 1); | ||
20 | $parent = new Twig_Node_Expression_Constant('layout.twig', 1); | ||
21 | $blocks = new Twig_Node(); | ||
22 | $macros = new Twig_Node(); | ||
23 | $traits = new Twig_Node(); | ||
24 | $filename = 'foo.twig'; | ||
25 | $node = new Twig_Node_Module($body, $parent, $blocks, $macros, $traits, new Twig_Node(array()), $filename); | ||
26 | |||
27 | $this->assertEquals($body, $node->getNode('body')); | ||
28 | $this->assertEquals($blocks, $node->getNode('blocks')); | ||
29 | $this->assertEquals($macros, $node->getNode('macros')); | ||
30 | $this->assertEquals($parent, $node->getNode('parent')); | ||
31 | $this->assertEquals($filename, $node->getAttribute('filename')); | ||
32 | } | ||
33 | |||
34 | /** | ||
35 | * @covers Twig_Node_Module::compile | ||
36 | * @covers Twig_Node_Module::compileTemplate | ||
37 | * @covers Twig_Node_Module::compileMacros | ||
38 | * @covers Twig_Node_Module::compileClassHeader | ||
39 | * @covers Twig_Node_Module::compileDisplayHeader | ||
40 | * @covers Twig_Node_Module::compileDisplayBody | ||
41 | * @covers Twig_Node_Module::compileDisplayFooter | ||
42 | * @covers Twig_Node_Module::compileClassFooter | ||
43 | * @dataProvider getTests | ||
44 | */ | ||
45 | public function testCompile($node, $source, $environment = null) | ||
46 | { | ||
47 | parent::testCompile($node, $source, $environment); | ||
48 | } | ||
49 | |||
50 | public function getTests() | ||
51 | { | ||
52 | $twig = new Twig_Environment(new Twig_Loader_String()); | ||
53 | |||
54 | $tests = array(); | ||
55 | |||
56 | $body = new Twig_Node_Text('foo', 1); | ||
57 | $extends = null; | ||
58 | $blocks = new Twig_Node(); | ||
59 | $macros = new Twig_Node(); | ||
60 | $traits = new Twig_Node(); | ||
61 | $filename = 'foo.twig'; | ||
62 | |||
63 | $node = new Twig_Node_Module($body, $extends, $blocks, $macros, $traits, new Twig_Node(array()), $filename); | ||
64 | $tests[] = array($node, <<<EOF | ||
65 | <?php | ||
66 | |||
67 | /* foo.twig */ | ||
68 | class __TwigTemplate_be925a7b06dda0dfdbd18a1509f7eb34 extends Twig_Template | ||
69 | { | ||
70 | public function __construct(Twig_Environment \$env) | ||
71 | { | ||
72 | parent::__construct(\$env); | ||
73 | |||
74 | \$this->parent = false; | ||
75 | |||
76 | \$this->blocks = array( | ||
77 | ); | ||
78 | } | ||
79 | |||
80 | protected function doDisplay(array \$context, array \$blocks = array()) | ||
81 | { | ||
82 | // line 1 | ||
83 | echo "foo"; | ||
84 | } | ||
85 | |||
86 | public function getTemplateName() | ||
87 | { | ||
88 | return "foo.twig"; | ||
89 | } | ||
90 | |||
91 | public function getDebugInfo() | ||
92 | { | ||
93 | return array ( 19 => 1,); | ||
94 | } | ||
95 | } | ||
96 | EOF | ||
97 | , $twig); | ||
98 | |||
99 | $import = new Twig_Node_Import(new Twig_Node_Expression_Constant('foo.twig', 1), new Twig_Node_Expression_AssignName('macro', 1), 1); | ||
100 | |||
101 | $body = new Twig_Node(array($import)); | ||
102 | $extends = new Twig_Node_Expression_Constant('layout.twig', 1); | ||
103 | |||
104 | $node = new Twig_Node_Module($body, $extends, $blocks, $macros, $traits, new Twig_Node(array()), $filename); | ||
105 | $tests[] = array($node, <<<EOF | ||
106 | <?php | ||
107 | |||
108 | /* foo.twig */ | ||
109 | class __TwigTemplate_be925a7b06dda0dfdbd18a1509f7eb34 extends Twig_Template | ||
110 | { | ||
111 | public function __construct(Twig_Environment \$env) | ||
112 | { | ||
113 | parent::__construct(\$env); | ||
114 | |||
115 | \$this->parent = \$this->env->loadTemplate("layout.twig"); | ||
116 | |||
117 | \$this->blocks = array( | ||
118 | ); | ||
119 | } | ||
120 | |||
121 | protected function doGetParent(array \$context) | ||
122 | { | ||
123 | return "layout.twig"; | ||
124 | } | ||
125 | |||
126 | protected function doDisplay(array \$context, array \$blocks = array()) | ||
127 | { | ||
128 | // line 1 | ||
129 | \$context["macro"] = \$this->env->loadTemplate("foo.twig"); | ||
130 | \$this->parent->display(\$context, array_merge(\$this->blocks, \$blocks)); | ||
131 | } | ||
132 | |||
133 | public function getTemplateName() | ||
134 | { | ||
135 | return "foo.twig"; | ||
136 | } | ||
137 | |||
138 | public function isTraitable() | ||
139 | { | ||
140 | return false; | ||
141 | } | ||
142 | |||
143 | public function getDebugInfo() | ||
144 | { | ||
145 | return array ( 24 => 1,); | ||
146 | } | ||
147 | } | ||
148 | EOF | ||
149 | , $twig); | ||
150 | |||
151 | $body = new Twig_Node(); | ||
152 | $extends = new Twig_Node_Expression_Conditional( | ||
153 | new Twig_Node_Expression_Constant(true, 1), | ||
154 | new Twig_Node_Expression_Constant('foo', 1), | ||
155 | new Twig_Node_Expression_Constant('foo', 1), | ||
156 | 0 | ||
157 | ); | ||
158 | |||
159 | $node = new Twig_Node_Module($body, $extends, $blocks, $macros, $traits, new Twig_Node(array()), $filename); | ||
160 | $tests[] = array($node, <<<EOF | ||
161 | <?php | ||
162 | |||
163 | /* foo.twig */ | ||
164 | class __TwigTemplate_be925a7b06dda0dfdbd18a1509f7eb34 extends Twig_Template | ||
165 | { | ||
166 | protected function doGetParent(array \$context) | ||
167 | { | ||
168 | return \$this->env->resolveTemplate(((true) ? ("foo") : ("foo"))); | ||
169 | } | ||
170 | |||
171 | protected function doDisplay(array \$context, array \$blocks = array()) | ||
172 | { | ||
173 | \$this->getParent(\$context)->display(\$context, array_merge(\$this->blocks, \$blocks)); | ||
174 | } | ||
175 | |||
176 | public function getTemplateName() | ||
177 | { | ||
178 | return "foo.twig"; | ||
179 | } | ||
180 | |||
181 | public function isTraitable() | ||
182 | { | ||
183 | return false; | ||
184 | } | ||
185 | |||
186 | public function getDebugInfo() | ||
187 | { | ||
188 | return array (); | ||
189 | } | ||
190 | } | ||
191 | EOF | ||
192 | , $twig); | ||
193 | |||
194 | return $tests; | ||
195 | } | ||
196 | } | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Node/PrintTest.php b/vendor/twig/twig/test/Twig/Tests/Node/PrintTest.php new file mode 100644 index 00000000..6fe43a41 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Node/PrintTest.php | |||
@@ -0,0 +1,41 @@ | |||
1 | <?php | ||
2 | |||
3 | /* | ||
4 | * This file is part of Twig. | ||
5 | * | ||
6 | * (c) 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_Tests_Node_PrintTest extends Twig_Test_NodeTestCase | ||
13 | { | ||
14 | /** | ||
15 | * @covers Twig_Node_Print::__construct | ||
16 | */ | ||
17 | public function testConstructor() | ||
18 | { | ||
19 | $expr = new Twig_Node_Expression_Constant('foo', 1); | ||
20 | $node = new Twig_Node_Print($expr, 1); | ||
21 | |||
22 | $this->assertEquals($expr, $node->getNode('expr')); | ||
23 | } | ||
24 | |||
25 | /** | ||
26 | * @covers Twig_Node_Print::compile | ||
27 | * @dataProvider getTests | ||
28 | */ | ||
29 | public function testCompile($node, $source, $environment = null) | ||
30 | { | ||
31 | parent::testCompile($node, $source, $environment); | ||
32 | } | ||
33 | |||
34 | public function getTests() | ||
35 | { | ||
36 | $tests = array(); | ||
37 | $tests[] = array(new Twig_Node_Print(new Twig_Node_Expression_Constant('foo', 1), 1), "// line 1\necho \"foo\";"); | ||
38 | |||
39 | return $tests; | ||
40 | } | ||
41 | } | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Node/SandboxTest.php b/vendor/twig/twig/test/Twig/Tests/Node/SandboxTest.php new file mode 100644 index 00000000..db9dbf95 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Node/SandboxTest.php | |||
@@ -0,0 +1,56 @@ | |||
1 | <?php | ||
2 | |||
3 | /* | ||
4 | * This file is part of Twig. | ||
5 | * | ||
6 | * (c) 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_Tests_Node_SandboxTest extends Twig_Test_NodeTestCase | ||
13 | { | ||
14 | /** | ||
15 | * @covers Twig_Node_Sandbox::__construct | ||
16 | */ | ||
17 | public function testConstructor() | ||
18 | { | ||
19 | $body = new Twig_Node_Text('foo', 1); | ||
20 | $node = new Twig_Node_Sandbox($body, 1); | ||
21 | |||
22 | $this->assertEquals($body, $node->getNode('body')); | ||
23 | } | ||
24 | |||
25 | /** | ||
26 | * @covers Twig_Node_Sandbox::compile | ||
27 | * @dataProvider getTests | ||
28 | */ | ||
29 | public function testCompile($node, $source, $environment = null) | ||
30 | { | ||
31 | parent::testCompile($node, $source, $environment); | ||
32 | } | ||
33 | |||
34 | public function getTests() | ||
35 | { | ||
36 | $tests = array(); | ||
37 | |||
38 | $body = new Twig_Node_Text('foo', 1); | ||
39 | $node = new Twig_Node_Sandbox($body, 1); | ||
40 | |||
41 | $tests[] = array($node, <<<EOF | ||
42 | // line 1 | ||
43 | \$sandbox = \$this->env->getExtension('sandbox'); | ||
44 | if (!\$alreadySandboxed = \$sandbox->isSandboxed()) { | ||
45 | \$sandbox->enableSandbox(); | ||
46 | } | ||
47 | echo "foo"; | ||
48 | if (!\$alreadySandboxed) { | ||
49 | \$sandbox->disableSandbox(); | ||
50 | } | ||
51 | EOF | ||
52 | ); | ||
53 | |||
54 | return $tests; | ||
55 | } | ||
56 | } | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Node/SandboxedModuleTest.php b/vendor/twig/twig/test/Twig/Tests/Node/SandboxedModuleTest.php new file mode 100644 index 00000000..217e3408 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Node/SandboxedModuleTest.php | |||
@@ -0,0 +1,173 @@ | |||
1 | <?php | ||
2 | |||
3 | /* | ||
4 | * This file is part of Twig. | ||
5 | * | ||
6 | * (c) 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_Tests_Node_SandboxedModuleTest extends Twig_Test_NodeTestCase | ||
13 | { | ||
14 | /** | ||
15 | * @covers Twig_Node_SandboxedModule::__construct | ||
16 | */ | ||
17 | public function testConstructor() | ||
18 | { | ||
19 | $body = new Twig_Node_Text('foo', 1); | ||
20 | $parent = new Twig_Node_Expression_Constant('layout.twig', 1); | ||
21 | $blocks = new Twig_Node(); | ||
22 | $macros = new Twig_Node(); | ||
23 | $traits = new Twig_Node(); | ||
24 | $filename = 'foo.twig'; | ||
25 | $node = new Twig_Node_Module($body, $parent, $blocks, $macros, $traits, new Twig_Node(array()), $filename); | ||
26 | $node = new Twig_Node_SandboxedModule($node, array('for'), array('upper'), array('cycle')); | ||
27 | |||
28 | $this->assertEquals($body, $node->getNode('body')); | ||
29 | $this->assertEquals($blocks, $node->getNode('blocks')); | ||
30 | $this->assertEquals($macros, $node->getNode('macros')); | ||
31 | $this->assertEquals($parent, $node->getNode('parent')); | ||
32 | $this->assertEquals($filename, $node->getAttribute('filename')); | ||
33 | } | ||
34 | |||
35 | /** | ||
36 | * @covers Twig_Node_SandboxedModule::compile | ||
37 | * @covers Twig_Node_SandboxedModule::compileDisplayBody | ||
38 | * @covers Twig_Node_SandboxedModule::compileDisplayFooter | ||
39 | * @dataProvider getTests | ||
40 | */ | ||
41 | public function testCompile($node, $source, $environment = null) | ||
42 | { | ||
43 | parent::testCompile($node, $source, $environment); | ||
44 | } | ||
45 | |||
46 | public function getTests() | ||
47 | { | ||
48 | $twig = new Twig_Environment(new Twig_Loader_String()); | ||
49 | |||
50 | $tests = array(); | ||
51 | |||
52 | $body = new Twig_Node_Text('foo', 1); | ||
53 | $extends = null; | ||
54 | $blocks = new Twig_Node(); | ||
55 | $macros = new Twig_Node(); | ||
56 | $traits = new Twig_Node(); | ||
57 | $filename = 'foo.twig'; | ||
58 | |||
59 | $node = new Twig_Node_Module($body, $extends, $blocks, $macros, $traits, new Twig_Node(array()), $filename); | ||
60 | $node = new Twig_Node_SandboxedModule($node, array('for'), array('upper'), array('cycle')); | ||
61 | |||
62 | $tests[] = array($node, <<<EOF | ||
63 | <?php | ||
64 | |||
65 | /* foo.twig */ | ||
66 | class __TwigTemplate_be925a7b06dda0dfdbd18a1509f7eb34 extends Twig_Template | ||
67 | { | ||
68 | public function __construct(Twig_Environment \$env) | ||
69 | { | ||
70 | parent::__construct(\$env); | ||
71 | |||
72 | \$this->parent = false; | ||
73 | |||
74 | \$this->blocks = array( | ||
75 | ); | ||
76 | } | ||
77 | |||
78 | protected function doDisplay(array \$context, array \$blocks = array()) | ||
79 | { | ||
80 | \$this->checkSecurity(); | ||
81 | // line 1 | ||
82 | echo "foo"; | ||
83 | } | ||
84 | |||
85 | protected function checkSecurity() | ||
86 | { | ||
87 | \$this->env->getExtension('sandbox')->checkSecurity( | ||
88 | array('upper'), | ||
89 | array('for'), | ||
90 | array('cycle') | ||
91 | ); | ||
92 | } | ||
93 | |||
94 | public function getTemplateName() | ||
95 | { | ||
96 | return "foo.twig"; | ||
97 | } | ||
98 | |||
99 | public function getDebugInfo() | ||
100 | { | ||
101 | return array ( 20 => 1,); | ||
102 | } | ||
103 | } | ||
104 | EOF | ||
105 | , $twig); | ||
106 | |||
107 | $body = new Twig_Node(); | ||
108 | $extends = new Twig_Node_Expression_Constant('layout.twig', 1); | ||
109 | $blocks = new Twig_Node(); | ||
110 | $macros = new Twig_Node(); | ||
111 | $traits = new Twig_Node(); | ||
112 | $filename = 'foo.twig'; | ||
113 | |||
114 | $node = new Twig_Node_Module($body, $extends, $blocks, $macros, $traits, new Twig_Node(array()), $filename); | ||
115 | $node = new Twig_Node_SandboxedModule($node, array('for'), array('upper'), array('cycle')); | ||
116 | |||
117 | $tests[] = array($node, <<<EOF | ||
118 | <?php | ||
119 | |||
120 | /* foo.twig */ | ||
121 | class __TwigTemplate_be925a7b06dda0dfdbd18a1509f7eb34 extends Twig_Template | ||
122 | { | ||
123 | public function __construct(Twig_Environment \$env) | ||
124 | { | ||
125 | parent::__construct(\$env); | ||
126 | |||
127 | \$this->parent = \$this->env->loadTemplate("layout.twig"); | ||
128 | |||
129 | \$this->blocks = array( | ||
130 | ); | ||
131 | } | ||
132 | |||
133 | protected function doGetParent(array \$context) | ||
134 | { | ||
135 | return "layout.twig"; | ||
136 | } | ||
137 | |||
138 | protected function doDisplay(array \$context, array \$blocks = array()) | ||
139 | { | ||
140 | \$this->checkSecurity(); | ||
141 | \$this->parent->display(\$context, array_merge(\$this->blocks, \$blocks)); | ||
142 | } | ||
143 | |||
144 | protected function checkSecurity() | ||
145 | { | ||
146 | \$this->env->getExtension('sandbox')->checkSecurity( | ||
147 | array('upper'), | ||
148 | array('for'), | ||
149 | array('cycle') | ||
150 | ); | ||
151 | } | ||
152 | |||
153 | public function getTemplateName() | ||
154 | { | ||
155 | return "foo.twig"; | ||
156 | } | ||
157 | |||
158 | public function isTraitable() | ||
159 | { | ||
160 | return false; | ||
161 | } | ||
162 | |||
163 | public function getDebugInfo() | ||
164 | { | ||
165 | return array (); | ||
166 | } | ||
167 | } | ||
168 | EOF | ||
169 | , $twig); | ||
170 | |||
171 | return $tests; | ||
172 | } | ||
173 | } | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Node/SandboxedPrintTest.php b/vendor/twig/twig/test/Twig/Tests/Node/SandboxedPrintTest.php new file mode 100644 index 00000000..058e02bc --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Node/SandboxedPrintTest.php | |||
@@ -0,0 +1,45 @@ | |||
1 | <?php | ||
2 | |||
3 | /* | ||
4 | * This file is part of Twig. | ||
5 | * | ||
6 | * (c) 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_Tests_Node_SandboxedPrintTest extends Twig_Test_NodeTestCase | ||
13 | { | ||
14 | /** | ||
15 | * @covers Twig_Node_SandboxedPrint::__construct | ||
16 | */ | ||
17 | public function testConstructor() | ||
18 | { | ||
19 | $node = new Twig_Node_SandboxedPrint($expr = new Twig_Node_Expression_Constant('foo', 1), 1); | ||
20 | |||
21 | $this->assertEquals($expr, $node->getNode('expr')); | ||
22 | } | ||
23 | |||
24 | /** | ||
25 | * @covers Twig_Node_SandboxedPrint::compile | ||
26 | * @dataProvider getTests | ||
27 | */ | ||
28 | public function testCompile($node, $source, $environment = null) | ||
29 | { | ||
30 | parent::testCompile($node, $source, $environment); | ||
31 | } | ||
32 | |||
33 | public function getTests() | ||
34 | { | ||
35 | $tests = array(); | ||
36 | |||
37 | $tests[] = array(new Twig_Node_SandboxedPrint(new Twig_Node_Expression_Constant('foo', 1), 1), <<<EOF | ||
38 | // line 1 | ||
39 | echo \$this->env->getExtension('sandbox')->ensureToStringAllowed("foo"); | ||
40 | EOF | ||
41 | ); | ||
42 | |||
43 | return $tests; | ||
44 | } | ||
45 | } | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Node/SetTest.php b/vendor/twig/twig/test/Twig/Tests/Node/SetTest.php new file mode 100644 index 00000000..d64d671a --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Node/SetTest.php | |||
@@ -0,0 +1,81 @@ | |||
1 | <?php | ||
2 | |||
3 | /* | ||
4 | * This file is part of Twig. | ||
5 | * | ||
6 | * (c) 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_Tests_Node_SetTest extends Twig_Test_NodeTestCase | ||
13 | { | ||
14 | /** | ||
15 | * @covers Twig_Node_Set::__construct | ||
16 | */ | ||
17 | public function testConstructor() | ||
18 | { | ||
19 | $names = new Twig_Node(array(new Twig_Node_Expression_AssignName('foo', 1)), array(), 1); | ||
20 | $values = new Twig_Node(array(new Twig_Node_Expression_Constant('foo', 1)), array(), 1); | ||
21 | $node = new Twig_Node_Set(false, $names, $values, 1); | ||
22 | |||
23 | $this->assertEquals($names, $node->getNode('names')); | ||
24 | $this->assertEquals($values, $node->getNode('values')); | ||
25 | $this->assertEquals(false, $node->getAttribute('capture')); | ||
26 | } | ||
27 | |||
28 | /** | ||
29 | * @covers Twig_Node_Set::compile | ||
30 | * @dataProvider getTests | ||
31 | */ | ||
32 | public function testCompile($node, $source, $environment = null) | ||
33 | { | ||
34 | parent::testCompile($node, $source, $environment); | ||
35 | } | ||
36 | |||
37 | public function getTests() | ||
38 | { | ||
39 | $tests = array(); | ||
40 | |||
41 | $names = new Twig_Node(array(new Twig_Node_Expression_AssignName('foo', 1)), array(), 1); | ||
42 | $values = new Twig_Node(array(new Twig_Node_Expression_Constant('foo', 1)), array(), 1); | ||
43 | $node = new Twig_Node_Set(false, $names, $values, 1); | ||
44 | $tests[] = array($node, <<<EOF | ||
45 | // line 1 | ||
46 | \$context["foo"] = "foo"; | ||
47 | EOF | ||
48 | ); | ||
49 | |||
50 | $names = new Twig_Node(array(new Twig_Node_Expression_AssignName('foo', 1)), array(), 1); | ||
51 | $values = new Twig_Node(array(new Twig_Node_Print(new Twig_Node_Expression_Constant('foo', 1), 1)), array(), 1); | ||
52 | $node = new Twig_Node_Set(true, $names, $values, 1); | ||
53 | $tests[] = array($node, <<<EOF | ||
54 | // line 1 | ||
55 | ob_start(); | ||
56 | echo "foo"; | ||
57 | \$context["foo"] = ('' === \$tmp = ob_get_clean()) ? '' : new Twig_Markup(\$tmp, \$this->env->getCharset()); | ||
58 | EOF | ||
59 | ); | ||
60 | |||
61 | $names = new Twig_Node(array(new Twig_Node_Expression_AssignName('foo', 1)), array(), 1); | ||
62 | $values = new Twig_Node_Text('foo', 1); | ||
63 | $node = new Twig_Node_Set(true, $names, $values, 1); | ||
64 | $tests[] = array($node, <<<EOF | ||
65 | // line 1 | ||
66 | \$context["foo"] = ('' === \$tmp = "foo") ? '' : new Twig_Markup(\$tmp, \$this->env->getCharset()); | ||
67 | EOF | ||
68 | ); | ||
69 | |||
70 | $names = new Twig_Node(array(new Twig_Node_Expression_AssignName('foo', 1), new Twig_Node_Expression_AssignName('bar', 1)), array(), 1); | ||
71 | $values = new Twig_Node(array(new Twig_Node_Expression_Constant('foo', 1), new Twig_Node_Expression_Name('bar', 1)), array(), 1); | ||
72 | $node = new Twig_Node_Set(false, $names, $values, 1); | ||
73 | $tests[] = array($node, <<<EOF | ||
74 | // line 1 | ||
75 | list(\$context["foo"], \$context["bar"]) = array("foo", {$this->getVariableGetter('bar')}); | ||
76 | EOF | ||
77 | ); | ||
78 | |||
79 | return $tests; | ||
80 | } | ||
81 | } | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Node/SpacelessTest.php b/vendor/twig/twig/test/Twig/Tests/Node/SpacelessTest.php new file mode 100644 index 00000000..6735dc31 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Node/SpacelessTest.php | |||
@@ -0,0 +1,49 @@ | |||
1 | <?php | ||
2 | |||
3 | /* | ||
4 | * This file is part of Twig. | ||
5 | * | ||
6 | * (c) 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_Tests_Node_SpacelessTest extends Twig_Test_NodeTestCase | ||
13 | { | ||
14 | /** | ||
15 | * @covers Twig_Node_Spaceless::__construct | ||
16 | */ | ||
17 | public function testConstructor() | ||
18 | { | ||
19 | $body = new Twig_Node(array(new Twig_Node_Text('<div> <div> foo </div> </div>', 1))); | ||
20 | $node = new Twig_Node_Spaceless($body, 1); | ||
21 | |||
22 | $this->assertEquals($body, $node->getNode('body')); | ||
23 | } | ||
24 | |||
25 | /** | ||
26 | * @covers Twig_Node_Spaceless::compile | ||
27 | * @dataProvider getTests | ||
28 | */ | ||
29 | public function testCompile($node, $source, $environment = null) | ||
30 | { | ||
31 | parent::testCompile($node, $source, $environment); | ||
32 | } | ||
33 | |||
34 | public function getTests() | ||
35 | { | ||
36 | $body = new Twig_Node(array(new Twig_Node_Text('<div> <div> foo </div> </div>', 1))); | ||
37 | $node = new Twig_Node_Spaceless($body, 1); | ||
38 | |||
39 | return array( | ||
40 | array($node, <<<EOF | ||
41 | // line 1 | ||
42 | ob_start(); | ||
43 | echo "<div> <div> foo </div> </div>"; | ||
44 | echo trim(preg_replace('/>\s+</', '><', ob_get_clean())); | ||
45 | EOF | ||
46 | ), | ||
47 | ); | ||
48 | } | ||
49 | } | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/Node/TextTest.php b/vendor/twig/twig/test/Twig/Tests/Node/TextTest.php new file mode 100644 index 00000000..6f85576e --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/Node/TextTest.php | |||
@@ -0,0 +1,40 @@ | |||
1 | <?php | ||
2 | |||
3 | /* | ||
4 | * This file is part of Twig. | ||
5 | * | ||
6 | * (c) 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_Tests_Node_TextTest extends Twig_Test_NodeTestCase | ||
13 | { | ||
14 | /** | ||
15 | * @covers Twig_Node_Text::__construct | ||
16 | */ | ||
17 | public function testConstructor() | ||
18 | { | ||
19 | $node = new Twig_Node_Text('foo', 1); | ||
20 | |||
21 | $this->assertEquals('foo', $node->getAttribute('data')); | ||
22 | } | ||
23 | |||
24 | /** | ||
25 | * @covers Twig_Node_Text::compile | ||
26 | * @dataProvider getTests | ||
27 | */ | ||
28 | public function testCompile($node, $source, $environment = null) | ||
29 | { | ||
30 | parent::testCompile($node, $source, $environment); | ||
31 | } | ||
32 | |||
33 | public function getTests() | ||
34 | { | ||
35 | $tests = array(); | ||
36 | $tests[] = array(new Twig_Node_Text('foo', 1), "// line 1\necho \"foo\";"); | ||
37 | |||
38 | return $tests; | ||
39 | } | ||
40 | } | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/NodeVisitor/OptimizerTest.php b/vendor/twig/twig/test/Twig/Tests/NodeVisitor/OptimizerTest.php new file mode 100644 index 00000000..d35740d5 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/NodeVisitor/OptimizerTest.php | |||
@@ -0,0 +1,114 @@ | |||
1 | <?php | ||
2 | |||
3 | /* | ||
4 | * This file is part of Twig. | ||
5 | * | ||
6 | * (c) 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_Tests_NodeVisitor_OptimizerTest extends PHPUnit_Framework_TestCase | ||
12 | { | ||
13 | public function testRenderBlockOptimizer() | ||
14 | { | ||
15 | $env = new Twig_Environment(new Twig_Loader_String(), array('cache' => false, 'autoescape' => false)); | ||
16 | |||
17 | $stream = $env->parse($env->tokenize('{{ block("foo") }}', 'index')); | ||
18 | |||
19 | $node = $stream->getNode('body')->getNode(0); | ||
20 | |||
21 | $this->assertEquals('Twig_Node_Expression_BlockReference', get_class($node)); | ||
22 | $this->assertTrue($node->getAttribute('output')); | ||
23 | } | ||
24 | |||
25 | public function testRenderParentBlockOptimizer() | ||
26 | { | ||
27 | $env = new Twig_Environment(new Twig_Loader_String(), array('cache' => false, 'autoescape' => false)); | ||
28 | |||
29 | $stream = $env->parse($env->tokenize('{% extends "foo" %}{% block content %}{{ parent() }}{% endblock %}', 'index')); | ||
30 | |||
31 | $node = $stream->getNode('blocks')->getNode('content')->getNode(0)->getNode('body'); | ||
32 | |||
33 | $this->assertEquals('Twig_Node_Expression_Parent', get_class($node)); | ||
34 | $this->assertTrue($node->getAttribute('output')); | ||
35 | } | ||
36 | |||
37 | public function testRenderVariableBlockOptimizer() | ||
38 | { | ||
39 | if (version_compare(phpversion(), '5.4.0RC1', '>=')) { | ||
40 | return; | ||
41 | } | ||
42 | |||
43 | $env = new Twig_Environment(new Twig_Loader_String(), array('cache' => false, 'autoescape' => false)); | ||
44 | $stream = $env->parse($env->tokenize('{{ block(name|lower) }}', 'index')); | ||
45 | |||
46 | $node = $stream->getNode('body')->getNode(0)->getNode(1); | ||
47 | |||
48 | $this->assertEquals('Twig_Node_Expression_BlockReference', get_class($node)); | ||
49 | $this->assertTrue($node->getAttribute('output')); | ||
50 | } | ||
51 | |||
52 | /** | ||
53 | * @dataProvider getTestsForForOptimizer | ||
54 | */ | ||
55 | public function testForOptimizer($template, $expected) | ||
56 | { | ||
57 | $env = new Twig_Environment(new Twig_Loader_String(), array('cache' => false)); | ||
58 | |||
59 | $stream = $env->parse($env->tokenize($template, 'index')); | ||
60 | |||
61 | foreach ($expected as $target => $withLoop) { | ||
62 | $this->assertTrue($this->checkForConfiguration($stream, $target, $withLoop), sprintf('variable %s is %soptimized', $target, $withLoop ? 'not ' : '')); | ||
63 | } | ||
64 | } | ||
65 | |||
66 | public function getTestsForForOptimizer() | ||
67 | { | ||
68 | return array( | ||
69 | array('{% for i in foo %}{% endfor %}', array('i' => false)), | ||
70 | |||
71 | array('{% for i in foo %}{{ loop.index }}{% endfor %}', array('i' => true)), | ||
72 | |||
73 | array('{% for i in foo %}{% for j in foo %}{% endfor %}{% endfor %}', array('i' => false, 'j' => false)), | ||
74 | |||
75 | array('{% for i in foo %}{% include "foo" %}{% endfor %}', array('i' => true)), | ||
76 | |||
77 | array('{% for i in foo %}{% include "foo" only %}{% endfor %}', array('i' => false)), | ||
78 | |||
79 | array('{% for i in foo %}{% include "foo" with { "foo": "bar" } only %}{% endfor %}', array('i' => false)), | ||
80 | |||
81 | array('{% for i in foo %}{% include "foo" with { "foo": loop.index } only %}{% endfor %}', array('i' => true)), | ||
82 | |||
83 | array('{% for i in foo %}{% for j in foo %}{{ loop.index }}{% endfor %}{% endfor %}', array('i' => false, 'j' => true)), | ||
84 | |||
85 | array('{% for i in foo %}{% for j in foo %}{{ loop.parent.loop.index }}{% endfor %}{% endfor %}', array('i' => true, 'j' => true)), | ||
86 | |||
87 | array('{% for i in foo %}{% set l = loop %}{% for j in foo %}{{ l.index }}{% endfor %}{% endfor %}', array('i' => true, 'j' => false)), | ||
88 | |||
89 | array('{% for i in foo %}{% for j in foo %}{{ foo.parent.loop.index }}{% endfor %}{% endfor %}', array('i' => false, 'j' => false)), | ||
90 | |||
91 | array('{% for i in foo %}{% for j in foo %}{{ loop["parent"].loop.index }}{% endfor %}{% endfor %}', array('i' => true, 'j' => true)), | ||
92 | ); | ||
93 | } | ||
94 | |||
95 | public function checkForConfiguration(Twig_NodeInterface $node = null, $target, $withLoop) | ||
96 | { | ||
97 | if (null === $node) { | ||
98 | return; | ||
99 | } | ||
100 | |||
101 | foreach ($node as $n) { | ||
102 | if ($n instanceof Twig_Node_For) { | ||
103 | if ($target === $n->getNode('value_target')->getAttribute('name')) { | ||
104 | return $withLoop == $n->getAttribute('with_loop'); | ||
105 | } | ||
106 | } | ||
107 | |||
108 | $ret = $this->checkForConfiguration($n, $target, $withLoop); | ||
109 | if (null !== $ret) { | ||
110 | return $ret; | ||
111 | } | ||
112 | } | ||
113 | } | ||
114 | } | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/ParserTest.php b/vendor/twig/twig/test/Twig/Tests/ParserTest.php new file mode 100644 index 00000000..55eb7fb4 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/ParserTest.php | |||
@@ -0,0 +1,180 @@ | |||
1 | <?php | ||
2 | |||
3 | /* | ||
4 | * This file is part of Twig. | ||
5 | * | ||
6 | * (c) 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_Tests_ParserTest extends PHPUnit_Framework_TestCase | ||
12 | { | ||
13 | /** | ||
14 | * @expectedException Twig_Error_Syntax | ||
15 | */ | ||
16 | public function testSetMacroThrowsExceptionOnReservedMethods() | ||
17 | { | ||
18 | $parser = $this->getParser(); | ||
19 | $parser->setMacro('display', $this->getMock('Twig_Node_Macro', array(), array(), '', null)); | ||
20 | } | ||
21 | |||
22 | /** | ||
23 | * @expectedException Twig_Error_Syntax | ||
24 | * @expectedExceptionMessage Unknown tag name "foo". Did you mean "for" at line 1 | ||
25 | */ | ||
26 | public function testUnknownTag() | ||
27 | { | ||
28 | $stream = new Twig_TokenStream(array( | ||
29 | new Twig_Token(Twig_Token::BLOCK_START_TYPE, '', 1), | ||
30 | new Twig_Token(Twig_Token::NAME_TYPE, 'foo', 1), | ||
31 | new Twig_Token(Twig_Token::BLOCK_END_TYPE, '', 1), | ||
32 | new Twig_Token(Twig_Token::EOF_TYPE, '', 1), | ||
33 | )); | ||
34 | $parser = new Twig_Parser(new Twig_Environment()); | ||
35 | $parser->parse($stream); | ||
36 | } | ||
37 | |||
38 | /** | ||
39 | * @dataProvider getFilterBodyNodesData | ||
40 | */ | ||
41 | public function testFilterBodyNodes($input, $expected) | ||
42 | { | ||
43 | $parser = $this->getParser(); | ||
44 | |||
45 | $this->assertEquals($expected, $parser->filterBodyNodes($input)); | ||
46 | } | ||
47 | |||
48 | public function getFilterBodyNodesData() | ||
49 | { | ||
50 | return array( | ||
51 | array( | ||
52 | new Twig_Node(array(new Twig_Node_Text(' ', 1))), | ||
53 | new Twig_Node(array()), | ||
54 | ), | ||
55 | array( | ||
56 | $input = new Twig_Node(array(new Twig_Node_Set(false, new Twig_Node(), new Twig_Node(), 1))), | ||
57 | $input, | ||
58 | ), | ||
59 | array( | ||
60 | $input = new Twig_Node(array(new Twig_Node_Set(true, new Twig_Node(), new Twig_Node(array(new Twig_Node(array(new Twig_Node_Text('foo', 1))))), 1))), | ||
61 | $input, | ||
62 | ), | ||
63 | ); | ||
64 | } | ||
65 | |||
66 | /** | ||
67 | * @dataProvider getFilterBodyNodesDataThrowsException | ||
68 | * @expectedException Twig_Error_Syntax | ||
69 | */ | ||
70 | public function testFilterBodyNodesThrowsException($input) | ||
71 | { | ||
72 | $parser = $this->getParser(); | ||
73 | |||
74 | $parser->filterBodyNodes($input); | ||
75 | } | ||
76 | |||
77 | public function getFilterBodyNodesDataThrowsException() | ||
78 | { | ||
79 | return array( | ||
80 | array(new Twig_Node_Text('foo', 1)), | ||
81 | array(new Twig_Node(array(new Twig_Node(array(new Twig_Node_Text('foo', 1)))))), | ||
82 | ); | ||
83 | } | ||
84 | |||
85 | /** | ||
86 | * @expectedException Twig_Error_Syntax | ||
87 | * @expectedExceptionMessage A template that extends another one cannot have a body but a byte order mark (BOM) has been detected; it must be removed at line 1. | ||
88 | */ | ||
89 | public function testFilterBodyNodesWithBOM() | ||
90 | { | ||
91 | $parser = $this->getParser(); | ||
92 | $parser->filterBodyNodes(new Twig_Node_Text(chr(0xEF).chr(0xBB).chr(0xBF), 1)); | ||
93 | } | ||
94 | |||
95 | public function testParseIsReentrant() | ||
96 | { | ||
97 | $twig = new Twig_Environment(null, array( | ||
98 | 'autoescape' => false, | ||
99 | 'optimizations' => 0, | ||
100 | )); | ||
101 | $twig->addTokenParser(new TestTokenParser()); | ||
102 | |||
103 | $parser = new Twig_Parser($twig); | ||
104 | |||
105 | $parser->parse(new Twig_TokenStream(array( | ||
106 | new Twig_Token(Twig_Token::BLOCK_START_TYPE, '', 1), | ||
107 | new Twig_Token(Twig_Token::NAME_TYPE, 'test', 1), | ||
108 | new Twig_Token(Twig_Token::BLOCK_END_TYPE, '', 1), | ||
109 | new Twig_Token(Twig_Token::VAR_START_TYPE, '', 1), | ||
110 | new Twig_Token(Twig_Token::NAME_TYPE, 'foo', 1), | ||
111 | new Twig_Token(Twig_Token::VAR_END_TYPE, '', 1), | ||
112 | new Twig_Token(Twig_Token::EOF_TYPE, '', 1), | ||
113 | ))); | ||
114 | |||
115 | $this->assertEquals(null, $parser->getParent()); | ||
116 | } | ||
117 | |||
118 | // The getVarName() must not depend on the template loaders, | ||
119 | // If this test does not throw any exception, that's good. | ||
120 | // see https://github.com/symfony/symfony/issues/4218 | ||
121 | public function testGetVarName() | ||
122 | { | ||
123 | $twig = new Twig_Environment(null, array( | ||
124 | 'autoescape' => false, | ||
125 | 'optimizations' => 0, | ||
126 | )); | ||
127 | |||
128 | $twig->parse($twig->tokenize(<<<EOF | ||
129 | {% from _self import foo %} | ||
130 | |||
131 | {% macro foo() %} | ||
132 | {{ foo }} | ||
133 | {% endmacro %} | ||
134 | EOF | ||
135 | )); | ||
136 | } | ||
137 | |||
138 | protected function getParser() | ||
139 | { | ||
140 | $parser = new TestParser(new Twig_Environment()); | ||
141 | $parser->setParent(new Twig_Node()); | ||
142 | $parser->stream = $this->getMockBuilder('Twig_TokenStream')->disableOriginalConstructor()->getMock(); | ||
143 | |||
144 | return $parser; | ||
145 | } | ||
146 | } | ||
147 | |||
148 | class TestParser extends Twig_Parser | ||
149 | { | ||
150 | public $stream; | ||
151 | |||
152 | public function filterBodyNodes(Twig_NodeInterface $node) | ||
153 | { | ||
154 | return parent::filterBodyNodes($node); | ||
155 | } | ||
156 | } | ||
157 | |||
158 | class TestTokenParser extends Twig_TokenParser | ||
159 | { | ||
160 | public function parse(Twig_Token $token) | ||
161 | { | ||
162 | // simulate the parsing of another template right in the middle of the parsing of the current template | ||
163 | $this->parser->parse(new Twig_TokenStream(array( | ||
164 | new Twig_Token(Twig_Token::BLOCK_START_TYPE, '', 1), | ||
165 | new Twig_Token(Twig_Token::NAME_TYPE, 'extends', 1), | ||
166 | new Twig_Token(Twig_Token::STRING_TYPE, 'base', 1), | ||
167 | new Twig_Token(Twig_Token::BLOCK_END_TYPE, '', 1), | ||
168 | new Twig_Token(Twig_Token::EOF_TYPE, '', 1), | ||
169 | ))); | ||
170 | |||
171 | $this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE); | ||
172 | |||
173 | return new Twig_Node(array()); | ||
174 | } | ||
175 | |||
176 | public function getTag() | ||
177 | { | ||
178 | return 'test'; | ||
179 | } | ||
180 | } | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/TemplateTest.php b/vendor/twig/twig/test/Twig/Tests/TemplateTest.php new file mode 100644 index 00000000..823a9ce9 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/TemplateTest.php | |||
@@ -0,0 +1,626 @@ | |||
1 | <?php | ||
2 | |||
3 | /* | ||
4 | * This file is part of Twig. | ||
5 | * | ||
6 | * (c) 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_Tests_TemplateTest extends PHPUnit_Framework_TestCase | ||
12 | { | ||
13 | /** | ||
14 | * @dataProvider getAttributeExceptions | ||
15 | */ | ||
16 | public function testGetAttributeExceptions($template, $message, $useExt) | ||
17 | { | ||
18 | $name = 'index_'.($useExt ? 1 : 0); | ||
19 | $templates = array( | ||
20 | $name => $template.$useExt, // appending $useExt makes the template content unique | ||
21 | ); | ||
22 | |||
23 | $env = new Twig_Environment(new Twig_Loader_Array($templates), array('strict_variables' => true)); | ||
24 | if (!$useExt) { | ||
25 | $env->addNodeVisitor(new CExtDisablingNodeVisitor()); | ||
26 | } | ||
27 | $template = $env->loadTemplate($name); | ||
28 | |||
29 | $context = array( | ||
30 | 'string' => 'foo', | ||
31 | 'array' => array('foo' => 'foo'), | ||
32 | 'array_access' => new Twig_TemplateArrayAccessObject(), | ||
33 | 'magic_exception' => new Twig_TemplateMagicPropertyObjectWithException(), | ||
34 | ); | ||
35 | |||
36 | try { | ||
37 | $template->render($context); | ||
38 | $this->fail('Accessing an invalid attribute should throw an exception.'); | ||
39 | } catch (Twig_Error_Runtime $e) { | ||
40 | $this->assertSame(sprintf($message, $name), $e->getMessage()); | ||
41 | } | ||
42 | } | ||
43 | |||
44 | public function getAttributeExceptions() | ||
45 | { | ||
46 | $tests = array( | ||
47 | array('{{ string["a"] }}', 'Impossible to access a key ("a") on a string variable ("foo") in "%s" at line 1', false), | ||
48 | array('{{ array["a"] }}', 'Key "a" for array with keys "foo" does not exist in "%s" at line 1', false), | ||
49 | array('{{ array_access["a"] }}', 'Key "a" in object (with ArrayAccess) of type "Twig_TemplateArrayAccessObject" does not exist in "%s" at line 1', false), | ||
50 | array('{{ string.a }}', 'Impossible to access an attribute ("a") on a string variable ("foo") in "%s" at line 1', false), | ||
51 | array('{{ string.a() }}', 'Impossible to invoke a method ("a") on a string variable ("foo") in "%s" at line 1', false), | ||
52 | array('{{ array.a }}', 'Key "a" for array with keys "foo" does not exist in "%s" at line 1', false), | ||
53 | array('{{ attribute(array, -10) }}', 'Key "-10" for array with keys "foo" does not exist in "%s" at line 1', false), | ||
54 | array('{{ array_access.a }}', 'Method "a" for object "Twig_TemplateArrayAccessObject" does not exist in "%s" at line 1', false), | ||
55 | array('{% macro foo(obj) %}{{ obj.missing_method() }}{% endmacro %}{{ _self.foo(array_access) }}', 'Method "missing_method" for object "Twig_TemplateArrayAccessObject" does not exist in "%s" at line 1', false), | ||
56 | array('{{ magic_exception.test }}', 'An exception has been thrown during the rendering of a template ("Hey! Don\'t try to isset me!") in "%s" at line 1.', false), | ||
57 | ); | ||
58 | |||
59 | if (function_exists('twig_template_get_attributes')) { | ||
60 | foreach (array_slice($tests, 0) as $test) { | ||
61 | $test[2] = true; | ||
62 | $tests[] = $test; | ||
63 | } | ||
64 | } | ||
65 | |||
66 | return $tests; | ||
67 | } | ||
68 | |||
69 | /** | ||
70 | * @dataProvider getGetAttributeWithSandbox | ||
71 | */ | ||
72 | public function testGetAttributeWithSandbox($object, $item, $allowed, $useExt) | ||
73 | { | ||
74 | $twig = new Twig_Environment(); | ||
75 | $policy = new Twig_Sandbox_SecurityPolicy(array(), array(), array(/*method*/), array(/*prop*/), array()); | ||
76 | $twig->addExtension(new Twig_Extension_Sandbox($policy, !$allowed)); | ||
77 | $template = new Twig_TemplateTest($twig, $useExt); | ||
78 | |||
79 | try { | ||
80 | $template->getAttribute($object, $item, array(), 'any'); | ||
81 | |||
82 | if (!$allowed) { | ||
83 | $this->fail(); | ||
84 | } | ||
85 | } catch (Twig_Sandbox_SecurityError $e) { | ||
86 | if ($allowed) { | ||
87 | $this->fail(); | ||
88 | } | ||
89 | |||
90 | $this->assertContains('is not allowed', $e->getMessage()); | ||
91 | } | ||
92 | } | ||
93 | |||
94 | public function getGetAttributeWithSandbox() | ||
95 | { | ||
96 | $tests = array( | ||
97 | array(new Twig_TemplatePropertyObject(), 'defined', false, false), | ||
98 | array(new Twig_TemplatePropertyObject(), 'defined', true, false), | ||
99 | array(new Twig_TemplateMethodObject(), 'defined', false, false), | ||
100 | array(new Twig_TemplateMethodObject(), 'defined', true, false), | ||
101 | ); | ||
102 | |||
103 | if (function_exists('twig_template_get_attributes')) { | ||
104 | foreach (array_slice($tests, 0) as $test) { | ||
105 | $test[3] = true; | ||
106 | $tests[] = $test; | ||
107 | } | ||
108 | } | ||
109 | |||
110 | return $tests; | ||
111 | } | ||
112 | |||
113 | /** | ||
114 | * @dataProvider getGetAttributeWithTemplateAsObject | ||
115 | */ | ||
116 | public function testGetAttributeWithTemplateAsObject($useExt) | ||
117 | { | ||
118 | $template = new Twig_TemplateTest(new Twig_Environment(), $useExt); | ||
119 | $template1 = new Twig_TemplateTest(new Twig_Environment(), false); | ||
120 | |||
121 | $this->assertInstanceof('Twig_Markup', $template->getAttribute($template1, 'string')); | ||
122 | $this->assertEquals('some_string', $template->getAttribute($template1, 'string')); | ||
123 | |||
124 | $this->assertInstanceof('Twig_Markup', $template->getAttribute($template1, 'true')); | ||
125 | $this->assertEquals('1', $template->getAttribute($template1, 'true')); | ||
126 | |||
127 | $this->assertInstanceof('Twig_Markup', $template->getAttribute($template1, 'zero')); | ||
128 | $this->assertEquals('0', $template->getAttribute($template1, 'zero')); | ||
129 | |||
130 | $this->assertNotInstanceof('Twig_Markup', $template->getAttribute($template1, 'empty')); | ||
131 | $this->assertSame('', $template->getAttribute($template1, 'empty')); | ||
132 | } | ||
133 | |||
134 | public function getGetAttributeWithTemplateAsObject() | ||
135 | { | ||
136 | $bools = array( | ||
137 | array(false), | ||
138 | ); | ||
139 | |||
140 | if (function_exists('twig_template_get_attributes')) { | ||
141 | $bools[] = array(true); | ||
142 | } | ||
143 | |||
144 | return $bools; | ||
145 | } | ||
146 | |||
147 | /** | ||
148 | * @dataProvider getTestsDependingOnExtensionAvailability | ||
149 | */ | ||
150 | public function testGetAttributeOnArrayWithConfusableKey($useExt = false) | ||
151 | { | ||
152 | $template = new Twig_TemplateTest( | ||
153 | new Twig_Environment(), | ||
154 | $useExt | ||
155 | ); | ||
156 | |||
157 | $array = array('Zero', 'One', -1 => 'MinusOne', '' => 'EmptyString', '1.5' => 'FloatButString', '01' => 'IntegerButStringWithLeadingZeros'); | ||
158 | |||
159 | $this->assertSame('Zero', $array[false]); | ||
160 | $this->assertSame('One', $array[true]); | ||
161 | $this->assertSame('One', $array[1.5]); | ||
162 | $this->assertSame('One', $array['1']); | ||
163 | $this->assertSame('MinusOne', $array[-1.5]); | ||
164 | $this->assertSame('FloatButString', $array['1.5']); | ||
165 | $this->assertSame('IntegerButStringWithLeadingZeros', $array['01']); | ||
166 | $this->assertSame('EmptyString', $array[null]); | ||
167 | |||
168 | $this->assertSame('Zero', $template->getAttribute($array, false), 'false is treated as 0 when accessing an array (equals PHP behavior)'); | ||
169 | $this->assertSame('One', $template->getAttribute($array, true), 'true is treated as 1 when accessing an array (equals PHP behavior)'); | ||
170 | $this->assertSame('One', $template->getAttribute($array, 1.5), 'float is casted to int when accessing an array (equals PHP behavior)'); | ||
171 | $this->assertSame('One', $template->getAttribute($array, '1'), '"1" is treated as integer 1 when accessing an array (equals PHP behavior)'); | ||
172 | $this->assertSame('MinusOne', $template->getAttribute($array, -1.5), 'negative float is casted to int when accessing an array (equals PHP behavior)'); | ||
173 | $this->assertSame('FloatButString', $template->getAttribute($array, '1.5'), '"1.5" is treated as-is when accessing an array (equals PHP behavior)'); | ||
174 | $this->assertSame('IntegerButStringWithLeadingZeros', $template->getAttribute($array, '01'), '"01" is treated as-is when accessing an array (equals PHP behavior)'); | ||
175 | $this->assertSame('EmptyString', $template->getAttribute($array, null), 'null is treated as "" when accessing an array (equals PHP behavior)'); | ||
176 | } | ||
177 | |||
178 | public function getTestsDependingOnExtensionAvailability() | ||
179 | { | ||
180 | if (function_exists('twig_template_get_attributes')) { | ||
181 | return array(array(false), array(true)); | ||
182 | } | ||
183 | |||
184 | return array(array(false)); | ||
185 | } | ||
186 | |||
187 | /** | ||
188 | * @dataProvider getGetAttributeTests | ||
189 | */ | ||
190 | public function testGetAttribute($defined, $value, $object, $item, $arguments, $type, $useExt = false) | ||
191 | { | ||
192 | $template = new Twig_TemplateTest(new Twig_Environment(), $useExt); | ||
193 | |||
194 | $this->assertEquals($value, $template->getAttribute($object, $item, $arguments, $type)); | ||
195 | } | ||
196 | |||
197 | /** | ||
198 | * @dataProvider getGetAttributeTests | ||
199 | */ | ||
200 | public function testGetAttributeStrict($defined, $value, $object, $item, $arguments, $type, $useExt = false, $exceptionMessage = null) | ||
201 | { | ||
202 | $template = new Twig_TemplateTest(new Twig_Environment(null, array('strict_variables' => true)), $useExt); | ||
203 | |||
204 | if ($defined) { | ||
205 | $this->assertEquals($value, $template->getAttribute($object, $item, $arguments, $type)); | ||
206 | } else { | ||
207 | try { | ||
208 | $this->assertEquals($value, $template->getAttribute($object, $item, $arguments, $type)); | ||
209 | |||
210 | throw new Exception('Expected Twig_Error_Runtime exception.'); | ||
211 | } catch (Twig_Error_Runtime $e) { | ||
212 | if (null !== $exceptionMessage) { | ||
213 | $this->assertSame($exceptionMessage, $e->getMessage()); | ||
214 | } | ||
215 | } | ||
216 | } | ||
217 | } | ||
218 | |||
219 | /** | ||
220 | * @dataProvider getGetAttributeTests | ||
221 | */ | ||
222 | public function testGetAttributeDefined($defined, $value, $object, $item, $arguments, $type, $useExt = false) | ||
223 | { | ||
224 | $template = new Twig_TemplateTest(new Twig_Environment(), $useExt); | ||
225 | |||
226 | $this->assertEquals($defined, $template->getAttribute($object, $item, $arguments, $type, true)); | ||
227 | } | ||
228 | |||
229 | /** | ||
230 | * @dataProvider getGetAttributeTests | ||
231 | */ | ||
232 | public function testGetAttributeDefinedStrict($defined, $value, $object, $item, $arguments, $type, $useExt = false) | ||
233 | { | ||
234 | $template = new Twig_TemplateTest(new Twig_Environment(null, array('strict_variables' => true)), $useExt); | ||
235 | |||
236 | $this->assertEquals($defined, $template->getAttribute($object, $item, $arguments, $type, true)); | ||
237 | } | ||
238 | |||
239 | public function getGetAttributeTests() | ||
240 | { | ||
241 | $array = array( | ||
242 | 'defined' => 'defined', | ||
243 | 'zero' => 0, | ||
244 | 'null' => null, | ||
245 | '1' => 1, | ||
246 | 'bar' => true, | ||
247 | '09' => '09', | ||
248 | '+4' => '+4', | ||
249 | ); | ||
250 | |||
251 | $objectArray = new Twig_TemplateArrayAccessObject(); | ||
252 | $stdObject = (object) $array; | ||
253 | $magicPropertyObject = new Twig_TemplateMagicPropertyObject(); | ||
254 | $propertyObject = new Twig_TemplatePropertyObject(); | ||
255 | $propertyObject1 = new Twig_TemplatePropertyObjectAndIterator(); | ||
256 | $propertyObject2 = new Twig_TemplatePropertyObjectAndArrayAccess(); | ||
257 | $methodObject = new Twig_TemplateMethodObject(); | ||
258 | $magicMethodObject = new Twig_TemplateMagicMethodObject(); | ||
259 | |||
260 | $anyType = Twig_TemplateInterface::ANY_CALL; | ||
261 | $methodType = Twig_TemplateInterface::METHOD_CALL; | ||
262 | $arrayType = Twig_TemplateInterface::ARRAY_CALL; | ||
263 | |||
264 | $basicTests = array( | ||
265 | // array(defined, value, property to fetch) | ||
266 | array(true, 'defined', 'defined'), | ||
267 | array(false, null, 'undefined'), | ||
268 | array(false, null, 'protected'), | ||
269 | array(true, 0, 'zero'), | ||
270 | array(true, 1, 1), | ||
271 | array(true, 1, 1.0), | ||
272 | array(true, null, 'null'), | ||
273 | array(true, true, 'bar'), | ||
274 | array(true, '09', '09'), | ||
275 | array(true, '+4', '+4'), | ||
276 | ); | ||
277 | $testObjects = array( | ||
278 | // array(object, type of fetch) | ||
279 | array($array, $arrayType), | ||
280 | array($objectArray, $arrayType), | ||
281 | array($stdObject, $anyType), | ||
282 | array($magicPropertyObject, $anyType), | ||
283 | array($methodObject, $methodType), | ||
284 | array($methodObject, $anyType), | ||
285 | array($propertyObject, $anyType), | ||
286 | array($propertyObject1, $anyType), | ||
287 | array($propertyObject2, $anyType), | ||
288 | ); | ||
289 | |||
290 | $tests = array(); | ||
291 | foreach ($testObjects as $testObject) { | ||
292 | foreach ($basicTests as $test) { | ||
293 | // properties cannot be numbers | ||
294 | if (($testObject[0] instanceof stdClass || $testObject[0] instanceof Twig_TemplatePropertyObject) && is_numeric($test[2])) { | ||
295 | continue; | ||
296 | } | ||
297 | |||
298 | if ('+4' === $test[2] && $methodObject === $testObject[0]) { | ||
299 | continue; | ||
300 | } | ||
301 | |||
302 | $tests[] = array($test[0], $test[1], $testObject[0], $test[2], array(), $testObject[1]); | ||
303 | } | ||
304 | } | ||
305 | |||
306 | // additional method tests | ||
307 | $tests = array_merge($tests, array( | ||
308 | array(true, 'defined', $methodObject, 'defined', array(), $methodType), | ||
309 | array(true, 'defined', $methodObject, 'DEFINED', array(), $methodType), | ||
310 | array(true, 'defined', $methodObject, 'getDefined', array(), $methodType), | ||
311 | array(true, 'defined', $methodObject, 'GETDEFINED', array(), $methodType), | ||
312 | array(true, 'static', $methodObject, 'static', array(), $methodType), | ||
313 | array(true, 'static', $methodObject, 'getStatic', array(), $methodType), | ||
314 | |||
315 | array(true, '__call_undefined', $magicMethodObject, 'undefined', array(), $methodType), | ||
316 | array(true, '__call_UNDEFINED', $magicMethodObject, 'UNDEFINED', array(), $methodType), | ||
317 | )); | ||
318 | |||
319 | // add the same tests for the any type | ||
320 | foreach ($tests as $test) { | ||
321 | if ($anyType !== $test[5]) { | ||
322 | $test[5] = $anyType; | ||
323 | $tests[] = $test; | ||
324 | } | ||
325 | } | ||
326 | |||
327 | $methodAndPropObject = new Twig_TemplateMethodAndPropObject; | ||
328 | |||
329 | // additional method tests | ||
330 | $tests = array_merge($tests, array( | ||
331 | array(true, 'a', $methodAndPropObject, 'a', array(), $anyType), | ||
332 | array(true, 'a', $methodAndPropObject, 'a', array(), $methodType), | ||
333 | array(false, null, $methodAndPropObject, 'a', array(), $arrayType), | ||
334 | |||
335 | array(true, 'b_prop', $methodAndPropObject, 'b', array(), $anyType), | ||
336 | array(true, 'b', $methodAndPropObject, 'B', array(), $anyType), | ||
337 | array(true, 'b', $methodAndPropObject, 'b', array(), $methodType), | ||
338 | array(true, 'b', $methodAndPropObject, 'B', array(), $methodType), | ||
339 | array(false, null, $methodAndPropObject, 'b', array(), $arrayType), | ||
340 | |||
341 | array(false, null, $methodAndPropObject, 'c', array(), $anyType), | ||
342 | array(false, null, $methodAndPropObject, 'c', array(), $methodType), | ||
343 | array(false, null, $methodAndPropObject, 'c', array(), $arrayType), | ||
344 | |||
345 | )); | ||
346 | |||
347 | // tests when input is not an array or object | ||
348 | $tests = array_merge($tests, array( | ||
349 | array(false, null, 42, 'a', array(), $anyType, false, 'Impossible to access an attribute ("a") on a integer variable ("42")'), | ||
350 | array(false, null, "string", 'a', array(), $anyType, false, 'Impossible to access an attribute ("a") on a string variable ("string")'), | ||
351 | array(false, null, array(), 'a', array(), $anyType, false, 'Key "a" for array with keys "" does not exist'), | ||
352 | )); | ||
353 | |||
354 | // add twig_template_get_attributes tests | ||
355 | |||
356 | if (function_exists('twig_template_get_attributes')) { | ||
357 | foreach (array_slice($tests, 0) as $test) { | ||
358 | $test = array_pad($test, 7, null); | ||
359 | $test[6] = true; | ||
360 | $tests[] = $test; | ||
361 | } | ||
362 | } | ||
363 | |||
364 | return $tests; | ||
365 | } | ||
366 | } | ||
367 | |||
368 | class Twig_TemplateTest extends Twig_Template | ||
369 | { | ||
370 | protected $useExtGetAttribute = false; | ||
371 | |||
372 | public function __construct(Twig_Environment $env, $useExtGetAttribute = false) | ||
373 | { | ||
374 | parent::__construct($env); | ||
375 | $this->useExtGetAttribute = $useExtGetAttribute; | ||
376 | Twig_Template::clearCache(); | ||
377 | } | ||
378 | |||
379 | public function getZero() | ||
380 | { | ||
381 | return 0; | ||
382 | } | ||
383 | |||
384 | public function getEmpty() | ||
385 | { | ||
386 | return ''; | ||
387 | } | ||
388 | |||
389 | public function getString() | ||
390 | { | ||
391 | return 'some_string'; | ||
392 | } | ||
393 | |||
394 | public function getTrue() | ||
395 | { | ||
396 | return true; | ||
397 | } | ||
398 | |||
399 | public function getTemplateName() | ||
400 | { | ||
401 | } | ||
402 | |||
403 | public function getDebugInfo() | ||
404 | { | ||
405 | return array(); | ||
406 | } | ||
407 | |||
408 | protected function doGetParent(array $context) | ||
409 | { | ||
410 | } | ||
411 | |||
412 | protected function doDisplay(array $context, array $blocks = array()) | ||
413 | { | ||
414 | } | ||
415 | |||
416 | public function getAttribute($object, $item, array $arguments = array(), $type = Twig_TemplateInterface::ANY_CALL, $isDefinedTest = false, $ignoreStrictCheck = false) | ||
417 | { | ||
418 | if ($this->useExtGetAttribute) { | ||
419 | return twig_template_get_attributes($this, $object, $item, $arguments, $type, $isDefinedTest, $ignoreStrictCheck); | ||
420 | } else { | ||
421 | return parent::getAttribute($object, $item, $arguments, $type, $isDefinedTest, $ignoreStrictCheck); | ||
422 | } | ||
423 | } | ||
424 | } | ||
425 | |||
426 | class Twig_TemplateArrayAccessObject implements ArrayAccess | ||
427 | { | ||
428 | protected $protected = 'protected'; | ||
429 | |||
430 | public $attributes = array( | ||
431 | 'defined' => 'defined', | ||
432 | 'zero' => 0, | ||
433 | 'null' => null, | ||
434 | '1' => 1, | ||
435 | 'bar' => true, | ||
436 | '09' => '09', | ||
437 | '+4' => '+4', | ||
438 | ); | ||
439 | |||
440 | public function offsetExists($name) | ||
441 | { | ||
442 | return array_key_exists($name, $this->attributes); | ||
443 | } | ||
444 | |||
445 | public function offsetGet($name) | ||
446 | { | ||
447 | return array_key_exists($name, $this->attributes) ? $this->attributes[$name] : null; | ||
448 | } | ||
449 | |||
450 | public function offsetSet($name, $value) | ||
451 | { | ||
452 | } | ||
453 | |||
454 | public function offsetUnset($name) | ||
455 | { | ||
456 | } | ||
457 | } | ||
458 | |||
459 | class Twig_TemplateMagicPropertyObject | ||
460 | { | ||
461 | public $defined = 'defined'; | ||
462 | |||
463 | public $attributes = array( | ||
464 | 'zero' => 0, | ||
465 | 'null' => null, | ||
466 | '1' => 1, | ||
467 | 'bar' => true, | ||
468 | '09' => '09', | ||
469 | '+4' => '+4', | ||
470 | ); | ||
471 | |||
472 | protected $protected = 'protected'; | ||
473 | |||
474 | public function __isset($name) | ||
475 | { | ||
476 | return array_key_exists($name, $this->attributes); | ||
477 | } | ||
478 | |||
479 | public function __get($name) | ||
480 | { | ||
481 | return array_key_exists($name, $this->attributes) ? $this->attributes[$name] : null; | ||
482 | } | ||
483 | } | ||
484 | |||
485 | class Twig_TemplateMagicPropertyObjectWithException | ||
486 | { | ||
487 | public function __isset($key) | ||
488 | { | ||
489 | throw new Exception("Hey! Don't try to isset me!"); | ||
490 | } | ||
491 | } | ||
492 | |||
493 | class Twig_TemplatePropertyObject | ||
494 | { | ||
495 | public $defined = 'defined'; | ||
496 | public $zero = 0; | ||
497 | public $null = null; | ||
498 | public $bar = true; | ||
499 | |||
500 | protected $protected = 'protected'; | ||
501 | } | ||
502 | |||
503 | class Twig_TemplatePropertyObjectAndIterator extends Twig_TemplatePropertyObject implements IteratorAggregate | ||
504 | { | ||
505 | public function getIterator() | ||
506 | { | ||
507 | return new ArrayIterator(array('foo', 'bar')); | ||
508 | } | ||
509 | } | ||
510 | |||
511 | class Twig_TemplatePropertyObjectAndArrayAccess extends Twig_TemplatePropertyObject implements ArrayAccess | ||
512 | { | ||
513 | private $data = array(); | ||
514 | |||
515 | public function offsetExists($offset) | ||
516 | { | ||
517 | return array_key_exists($offset, $this->data); | ||
518 | } | ||
519 | |||
520 | public function offsetGet($offset) | ||
521 | { | ||
522 | return $this->offsetExists($offset) ? $this->data[$offset] : 'n/a'; | ||
523 | } | ||
524 | |||
525 | public function offsetSet($offset, $value) | ||
526 | { | ||
527 | } | ||
528 | |||
529 | public function offsetUnset($offset) | ||
530 | { | ||
531 | } | ||
532 | } | ||
533 | |||
534 | class Twig_TemplateMethodObject | ||
535 | { | ||
536 | public function getDefined() | ||
537 | { | ||
538 | return 'defined'; | ||
539 | } | ||
540 | |||
541 | public function get1() | ||
542 | { | ||
543 | return 1; | ||
544 | } | ||
545 | |||
546 | public function get09() | ||
547 | { | ||
548 | return '09'; | ||
549 | } | ||
550 | |||
551 | public function getZero() | ||
552 | { | ||
553 | return 0; | ||
554 | } | ||
555 | |||
556 | public function getNull() | ||
557 | { | ||
558 | return null; | ||
559 | } | ||
560 | |||
561 | public function isBar() | ||
562 | { | ||
563 | return true; | ||
564 | } | ||
565 | |||
566 | protected function getProtected() | ||
567 | { | ||
568 | return 'protected'; | ||
569 | } | ||
570 | |||
571 | public static function getStatic() | ||
572 | { | ||
573 | return 'static'; | ||
574 | } | ||
575 | } | ||
576 | |||
577 | class Twig_TemplateMethodAndPropObject | ||
578 | { | ||
579 | private $a = 'a_prop'; | ||
580 | public function getA() | ||
581 | { | ||
582 | return 'a'; | ||
583 | } | ||
584 | |||
585 | public $b = 'b_prop'; | ||
586 | public function getB() | ||
587 | { | ||
588 | return 'b'; | ||
589 | } | ||
590 | |||
591 | private $c = 'c_prop'; | ||
592 | private function getC() | ||
593 | { | ||
594 | return 'c'; | ||
595 | } | ||
596 | } | ||
597 | |||
598 | class Twig_TemplateMagicMethodObject | ||
599 | { | ||
600 | public function __call($method, $arguments) | ||
601 | { | ||
602 | return '__call_'.$method; | ||
603 | } | ||
604 | } | ||
605 | |||
606 | class CExtDisablingNodeVisitor implements Twig_NodeVisitorInterface | ||
607 | { | ||
608 | public function enterNode(Twig_NodeInterface $node, Twig_Environment $env) | ||
609 | { | ||
610 | if ($node instanceof Twig_Node_Expression_GetAttr) { | ||
611 | $node->setAttribute('disable_c_ext', true); | ||
612 | } | ||
613 | |||
614 | return $node; | ||
615 | } | ||
616 | |||
617 | public function leaveNode(Twig_NodeInterface $node, Twig_Environment $env) | ||
618 | { | ||
619 | return $node; | ||
620 | } | ||
621 | |||
622 | public function getPriority() | ||
623 | { | ||
624 | return 0; | ||
625 | } | ||
626 | } | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/TokenStreamTest.php b/vendor/twig/twig/test/Twig/Tests/TokenStreamTest.php new file mode 100644 index 00000000..fd4ec633 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/TokenStreamTest.php | |||
@@ -0,0 +1,70 @@ | |||
1 | <?php | ||
2 | |||
3 | /* | ||
4 | * This file is part of Twig. | ||
5 | * | ||
6 | * (c) 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_Tests_TokenStreamTest extends PHPUnit_Framework_TestCase | ||
13 | { | ||
14 | protected static $tokens; | ||
15 | |||
16 | public function setUp() | ||
17 | { | ||
18 | self::$tokens = array( | ||
19 | new Twig_Token(Twig_Token::TEXT_TYPE, 1, 1), | ||
20 | new Twig_Token(Twig_Token::TEXT_TYPE, 2, 1), | ||
21 | new Twig_Token(Twig_Token::TEXT_TYPE, 3, 1), | ||
22 | new Twig_Token(Twig_Token::TEXT_TYPE, 4, 1), | ||
23 | new Twig_Token(Twig_Token::TEXT_TYPE, 5, 1), | ||
24 | new Twig_Token(Twig_Token::TEXT_TYPE, 6, 1), | ||
25 | new Twig_Token(Twig_Token::TEXT_TYPE, 7, 1), | ||
26 | new Twig_Token(Twig_Token::EOF_TYPE, 0, 1), | ||
27 | ); | ||
28 | } | ||
29 | |||
30 | public function testNext() | ||
31 | { | ||
32 | $stream = new Twig_TokenStream(self::$tokens); | ||
33 | $repr = array(); | ||
34 | while (!$stream->isEOF()) { | ||
35 | $token = $stream->next(); | ||
36 | |||
37 | $repr[] = $token->getValue(); | ||
38 | } | ||
39 | $this->assertEquals('1, 2, 3, 4, 5, 6, 7', implode(', ', $repr), '->next() advances the pointer and returns the current token'); | ||
40 | } | ||
41 | |||
42 | /** | ||
43 | * @expectedException Twig_Error_Syntax | ||
44 | * @expectedMessage Unexpected end of template | ||
45 | */ | ||
46 | public function testEndOfTemplateNext() | ||
47 | { | ||
48 | $stream = new Twig_TokenStream(array( | ||
49 | new Twig_Token(Twig_Token::BLOCK_START_TYPE, 1, 1), | ||
50 | )); | ||
51 | while (!$stream->isEOF()) { | ||
52 | $stream->next(); | ||
53 | } | ||
54 | } | ||
55 | |||
56 | /** | ||
57 | * @expectedException Twig_Error_Syntax | ||
58 | * @expectedMessage Unexpected end of template | ||
59 | */ | ||
60 | public function testEndOfTemplateLook() | ||
61 | { | ||
62 | $stream = new Twig_TokenStream(array( | ||
63 | new Twig_Token(Twig_Token::BLOCK_START_TYPE, 1, 1), | ||
64 | )); | ||
65 | while (!$stream->isEOF()) { | ||
66 | $stream->look(); | ||
67 | $stream->next(); | ||
68 | } | ||
69 | } | ||
70 | } | ||
diff --git a/vendor/twig/twig/test/Twig/Tests/escapingTest.php b/vendor/twig/twig/test/Twig/Tests/escapingTest.php new file mode 100644 index 00000000..b41b5f97 --- /dev/null +++ b/vendor/twig/twig/test/Twig/Tests/escapingTest.php | |||
@@ -0,0 +1,320 @@ | |||
1 | <?php | ||
2 | |||
3 | /** | ||
4 | * This class is adapted from code coming from Zend Framework. | ||
5 | * | ||
6 | * @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com) | ||
7 | * @license http://framework.zend.com/license/new-bsd New BSD License | ||
8 | */ | ||
9 | |||
10 | class Twig_Test_EscapingTest extends PHPUnit_Framework_TestCase | ||
11 | { | ||
12 | /** | ||
13 | * All character encodings supported by htmlspecialchars() | ||
14 | */ | ||
15 | protected $htmlSpecialChars = array( | ||
16 | '\'' => ''', | ||
17 | '"' => '"', | ||
18 | '<' => '<', | ||
19 | '>' => '>', | ||
20 | '&' => '&' | ||
21 | ); | ||
22 | |||
23 | protected $htmlAttrSpecialChars = array( | ||
24 | '\'' => ''', | ||
25 | /* Characters beyond ASCII value 255 to unicode escape */ | ||
26 | 'Ā' => 'Ā', | ||
27 | /* Immune chars excluded */ | ||
28 | ',' => ',', | ||
29 | '.' => '.', | ||
30 | '-' => '-', | ||
31 | '_' => '_', | ||
32 | /* Basic alnums excluded */ | ||
33 | 'a' => 'a', | ||
34 | 'A' => 'A', | ||
35 | 'z' => 'z', | ||
36 | 'Z' => 'Z', | ||
37 | '0' => '0', | ||
38 | '9' => '9', | ||
39 | /* Basic control characters and null */ | ||
40 | "\r" => '
', | ||
41 | "\n" => '
', | ||
42 | "\t" => '	', | ||
43 | "\0" => '�', // should use Unicode replacement char | ||
44 | /* Encode chars as named entities where possible */ | ||
45 | '<' => '<', | ||
46 | '>' => '>', | ||
47 | '&' => '&', | ||
48 | '"' => '"', | ||
49 | /* Encode spaces for quoteless attribute protection */ | ||
50 | ' ' => ' ', | ||
51 | ); | ||
52 | |||
53 | protected $jsSpecialChars = array( | ||
54 | /* HTML special chars - escape without exception to hex */ | ||
55 | '<' => '\\x3C', | ||
56 | '>' => '\\x3E', | ||
57 | '\'' => '\\x27', | ||
58 | '"' => '\\x22', | ||
59 | '&' => '\\x26', | ||
60 | /* Characters beyond ASCII value 255 to unicode escape */ | ||
61 | 'Ā' => '\\u0100', | ||
62 | /* Immune chars excluded */ | ||
63 | ',' => ',', | ||
64 | '.' => '.', | ||
65 | '_' => '_', | ||
66 | /* Basic alnums excluded */ | ||
67 | 'a' => 'a', | ||
68 | 'A' => 'A', | ||
69 | 'z' => 'z', | ||
70 | 'Z' => 'Z', | ||
71 | '0' => '0', | ||
72 | '9' => '9', | ||
73 | /* Basic control characters and null */ | ||
74 | "\r" => '\\x0D', | ||
75 | "\n" => '\\x0A', | ||
76 | "\t" => '\\x09', | ||
77 | "\0" => '\\x00', | ||
78 | /* Encode spaces for quoteless attribute protection */ | ||
79 | ' ' => '\\x20', | ||
80 | ); | ||
81 | |||
82 | protected $urlSpecialChars = array( | ||
83 | /* HTML special chars - escape without exception to percent encoding */ | ||
84 | '<' => '%3C', | ||
85 | '>' => '%3E', | ||
86 | '\'' => '%27', | ||
87 | '"' => '%22', | ||
88 | '&' => '%26', | ||
89 | /* Characters beyond ASCII value 255 to hex sequence */ | ||
90 | 'Ā' => '%C4%80', | ||
91 | /* Punctuation and unreserved check */ | ||
92 | ',' => '%2C', | ||
93 | '.' => '.', | ||
94 | '_' => '_', | ||
95 | '-' => '-', | ||
96 | ':' => '%3A', | ||
97 | ';' => '%3B', | ||
98 | '!' => '%21', | ||
99 | /* Basic alnums excluded */ | ||
100 | 'a' => 'a', | ||
101 | 'A' => 'A', | ||
102 | 'z' => 'z', | ||
103 | 'Z' => 'Z', | ||
104 | '0' => '0', | ||
105 | '9' => '9', | ||
106 | /* Basic control characters and null */ | ||
107 | "\r" => '%0D', | ||
108 | "\n" => '%0A', | ||
109 | "\t" => '%09', | ||
110 | "\0" => '%00', | ||
111 | /* PHP quirks from the past */ | ||
112 | ' ' => '%20', | ||
113 | '~' => '~', | ||
114 | '+' => '%2B', | ||
115 | ); | ||
116 | |||
117 | protected $cssSpecialChars = array( | ||
118 | /* HTML special chars - escape without exception to hex */ | ||
119 | '<' => '\\3C ', | ||
120 | '>' => '\\3E ', | ||
121 | '\'' => '\\27 ', | ||
122 | '"' => '\\22 ', | ||
123 | '&' => '\\26 ', | ||
124 | /* Characters beyond ASCII value 255 to unicode escape */ | ||
125 | 'Ā' => '\\100 ', | ||
126 | /* Immune chars excluded */ | ||
127 | ',' => '\\2C ', | ||
128 | '.' => '\\2E ', | ||
129 | '_' => '\\5F ', | ||
130 | /* Basic alnums excluded */ | ||
131 | 'a' => 'a', | ||
132 | 'A' => 'A', | ||
133 | 'z' => 'z', | ||
134 | 'Z' => 'Z', | ||
135 | '0' => '0', | ||
136 | '9' => '9', | ||
137 | /* Basic control characters and null */ | ||
138 | "\r" => '\\D ', | ||
139 | "\n" => '\\A ', | ||
140 | "\t" => '\\9 ', | ||
141 | "\0" => '\\0 ', | ||
142 | /* Encode spaces for quoteless attribute protection */ | ||
143 | ' ' => '\\20 ', | ||
144 | ); | ||
145 | |||
146 | protected $env; | ||
147 | |||
148 | public function setUp() | ||
149 | { | ||
150 | $this->env = new Twig_Environment(); | ||
151 | } | ||
152 | |||
153 | public function testHtmlEscapingConvertsSpecialChars() | ||
154 | { | ||
155 | foreach ($this->htmlSpecialChars as $key => $value) { | ||
156 | $this->assertEquals($value, twig_escape_filter($this->env, $key, 'html'), 'Failed to escape: '.$key); | ||
157 | } | ||
158 | } | ||
159 | |||
160 | public function testHtmlAttributeEscapingConvertsSpecialChars() | ||
161 | { | ||
162 | foreach ($this->htmlAttrSpecialChars as $key => $value) { | ||
163 | $this->assertEquals($value, twig_escape_filter($this->env, $key, 'html_attr'), 'Failed to escape: '.$key); | ||
164 | } | ||
165 | } | ||
166 | |||
167 | public function testJavascriptEscapingConvertsSpecialChars() | ||
168 | { | ||
169 | foreach ($this->jsSpecialChars as $key => $value) { | ||
170 | $this->assertEquals($value, twig_escape_filter($this->env, $key, 'js'), 'Failed to escape: '.$key); | ||
171 | } | ||
172 | } | ||
173 | |||
174 | public function testJavascriptEscapingReturnsStringIfZeroLength() | ||
175 | { | ||
176 | $this->assertEquals('', twig_escape_filter($this->env, '', 'js')); | ||
177 | } | ||
178 | |||
179 | public function testJavascriptEscapingReturnsStringIfContainsOnlyDigits() | ||
180 | { | ||
181 | $this->assertEquals('123', twig_escape_filter($this->env, '123', 'js')); | ||
182 | } | ||
183 | |||
184 | public function testCssEscapingConvertsSpecialChars() | ||
185 | { | ||
186 | foreach ($this->cssSpecialChars as $key => $value) { | ||
187 | $this->assertEquals($value, twig_escape_filter($this->env, $key, 'css'), 'Failed to escape: '.$key); | ||
188 | } | ||
189 | } | ||
190 | |||
191 | public function testCssEscapingReturnsStringIfZeroLength() | ||
192 | { | ||
193 | $this->assertEquals('', twig_escape_filter($this->env, '', 'css')); | ||
194 | } | ||
195 | |||
196 | public function testCssEscapingReturnsStringIfContainsOnlyDigits() | ||
197 | { | ||
198 | $this->assertEquals('123', twig_escape_filter($this->env, '123', 'css')); | ||
199 | } | ||
200 | |||
201 | public function testUrlEscapingConvertsSpecialChars() | ||
202 | { | ||
203 | foreach ($this->urlSpecialChars as $key => $value) { | ||
204 | $this->assertEquals($value, twig_escape_filter($this->env, $key, 'url'), 'Failed to escape: '.$key); | ||
205 | } | ||
206 | } | ||
207 | |||
208 | /** | ||
209 | * Range tests to confirm escaped range of characters is within OWASP recommendation | ||
210 | */ | ||
211 | |||
212 | /** | ||
213 | * Only testing the first few 2 ranges on this prot. function as that's all these | ||
214 | * other range tests require | ||
215 | */ | ||
216 | public function testUnicodeCodepointConversionToUtf8() | ||
217 | { | ||
218 | $expected = " ~ޙ"; | ||
219 | $codepoints = array(0x20, 0x7e, 0x799); | ||
220 | $result = ''; | ||
221 | foreach ($codepoints as $value) { | ||
222 | $result .= $this->codepointToUtf8($value); | ||
223 | } | ||
224 | $this->assertEquals($expected, $result); | ||
225 | } | ||
226 | |||
227 | /** | ||
228 | * Convert a Unicode Codepoint to a literal UTF-8 character. | ||
229 | * | ||
230 | * @param int Unicode codepoint in hex notation | ||
231 | * @return string UTF-8 literal string | ||
232 | */ | ||
233 | protected function codepointToUtf8($codepoint) | ||
234 | { | ||
235 | if ($codepoint < 0x80) { | ||
236 | return chr($codepoint); | ||
237 | } | ||
238 | if ($codepoint < 0x800) { | ||
239 | return chr($codepoint >> 6 & 0x3f | 0xc0) | ||
240 | . chr($codepoint & 0x3f | 0x80); | ||
241 | } | ||
242 | if ($codepoint < 0x10000) { | ||
243 | return chr($codepoint >> 12 & 0x0f | 0xe0) | ||
244 | . chr($codepoint >> 6 & 0x3f | 0x80) | ||
245 | . chr($codepoint & 0x3f | 0x80); | ||
246 | } | ||
247 | if ($codepoint < 0x110000) { | ||
248 | return chr($codepoint >> 18 & 0x07 | 0xf0) | ||
249 | . chr($codepoint >> 12 & 0x3f | 0x80) | ||
250 | . chr($codepoint >> 6 & 0x3f | 0x80) | ||
251 | . chr($codepoint & 0x3f | 0x80); | ||
252 | } | ||
253 | throw new Exception('Codepoint requested outside of Unicode range'); | ||
254 | } | ||
255 | |||
256 | public function testJavascriptEscapingEscapesOwaspRecommendedRanges() | ||
257 | { | ||
258 | $immune = array(',', '.', '_'); // Exceptions to escaping ranges | ||
259 | for ($chr=0; $chr < 0xFF; $chr++) { | ||
260 | if ($chr >= 0x30 && $chr <= 0x39 | ||
261 | || $chr >= 0x41 && $chr <= 0x5A | ||
262 | || $chr >= 0x61 && $chr <= 0x7A) { | ||
263 | $literal = $this->codepointToUtf8($chr); | ||
264 | $this->assertEquals($literal, twig_escape_filter($this->env, $literal, 'js')); | ||
265 | } else { | ||
266 | $literal = $this->codepointToUtf8($chr); | ||
267 | if (in_array($literal, $immune)) { | ||
268 | $this->assertEquals($literal, twig_escape_filter($this->env, $literal, 'js')); | ||
269 | } else { | ||
270 | $this->assertNotEquals( | ||
271 | $literal, | ||
272 | twig_escape_filter($this->env, $literal, 'js'), | ||
273 | "$literal should be escaped!"); | ||
274 | } | ||
275 | } | ||
276 | } | ||
277 | } | ||
278 | |||
279 | public function testHtmlAttributeEscapingEscapesOwaspRecommendedRanges() | ||
280 | { | ||
281 | $immune = array(',', '.', '-', '_'); // Exceptions to escaping ranges | ||
282 | for ($chr=0; $chr < 0xFF; $chr++) { | ||
283 | if ($chr >= 0x30 && $chr <= 0x39 | ||
284 | || $chr >= 0x41 && $chr <= 0x5A | ||
285 | || $chr >= 0x61 && $chr <= 0x7A) { | ||
286 | $literal = $this->codepointToUtf8($chr); | ||
287 | $this->assertEquals($literal, twig_escape_filter($this->env, $literal, 'html_attr')); | ||
288 | } else { | ||
289 | $literal = $this->codepointToUtf8($chr); | ||
290 | if (in_array($literal, $immune)) { | ||
291 | $this->assertEquals($literal, twig_escape_filter($this->env, $literal, 'html_attr')); | ||
292 | } else { | ||
293 | $this->assertNotEquals( | ||
294 | $literal, | ||
295 | twig_escape_filter($this->env, $literal, 'html_attr'), | ||
296 | "$literal should be escaped!"); | ||
297 | } | ||
298 | } | ||
299 | } | ||
300 | } | ||
301 | |||
302 | public function testCssEscapingEscapesOwaspRecommendedRanges() | ||
303 | { | ||
304 | $immune = array(); // CSS has no exceptions to escaping ranges | ||
305 | for ($chr=0; $chr < 0xFF; $chr++) { | ||
306 | if ($chr >= 0x30 && $chr <= 0x39 | ||
307 | || $chr >= 0x41 && $chr <= 0x5A | ||
308 | || $chr >= 0x61 && $chr <= 0x7A) { | ||
309 | $literal = $this->codepointToUtf8($chr); | ||
310 | $this->assertEquals($literal, twig_escape_filter($this->env, $literal, 'css')); | ||
311 | } else { | ||
312 | $literal = $this->codepointToUtf8($chr); | ||
313 | $this->assertNotEquals( | ||
314 | $literal, | ||
315 | twig_escape_filter($this->env, $literal, 'css'), | ||
316 | "$literal should be escaped!"); | ||
317 | } | ||
318 | } | ||
319 | } | ||
320 | } | ||
diff --git a/vendor/twig/twig/test/bootstrap.php b/vendor/twig/twig/test/bootstrap.php new file mode 100644 index 00000000..aecb976f --- /dev/null +++ b/vendor/twig/twig/test/bootstrap.php | |||
@@ -0,0 +1,13 @@ | |||
1 | <?php | ||
2 | |||
3 | /* | ||
4 | * This file is part of Twig. | ||
5 | * | ||
6 | * (c) 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 | require_once dirname(__FILE__).'/../lib/Twig/Autoloader.php'; | ||
13 | Twig_Autoloader::register(true); | ||