* 1.x:
added Twig_Source to hold information about the original template
... | ... |
@@ -19,6 +19,7 @@ |
19 | 19 |
|
20 | 20 |
* 1.27.0 (2016-XX-XX) |
21 | 21 |
|
22 |
+ * added Twig_Source to hold information about the original template |
|
22 | 23 |
* deprecated Twig_Error::getTemplateFile() and Twig_Error::setTemplateFile() in favor of Twig_Error::getTemplateName() and Twig_Error::setTemplateName() |
23 | 24 |
* deprecated Parser::getFilename() |
24 | 25 |
* fixed template paths when a template name contains a protocol like vfs:// |
... | ... |
@@ -44,7 +44,11 @@ an instance of ``Twig_Token``, and the stream is an instance of |
44 | 44 |
You can manually convert a source code into a token stream by calling the |
45 | 45 |
``tokenize()`` method of an environment:: |
46 | 46 |
|
47 |
- $stream = $twig->tokenize($source, $identifier); |
|
47 |
+ $stream = $twig->tokenize(new Twig_Source($source, $identifier)); |
|
48 |
+ |
|
49 |
+.. versionadded:: 1.27 |
|
50 |
+ ``Twig_Source`` was introduced in version 1.27, pass the source and the |
|
51 |
+ identifier directly on previous versions. |
|
48 | 52 |
|
49 | 53 |
As the stream has a ``__toString()`` method, you can have a textual |
50 | 54 |
representation of it by echoing the object:: |
... | ... |
@@ -303,7 +303,7 @@ saving it. If the template code is stored in a `$template` variable, here is |
303 | 303 |
how you can do it:: |
304 | 304 |
|
305 | 305 |
try { |
306 |
- $twig->parse($twig->tokenize($template)); |
|
306 |
+ $twig->parse($twig->tokenize(new Twig_Source($template))); |
|
307 | 307 |
|
308 | 308 |
// the $template is valid |
309 | 309 |
} catch (Twig_Error_Syntax $e) { |
... | ... |
@@ -315,7 +315,7 @@ If you iterate over a set of files, you can pass the filename to the |
315 | 315 |
|
316 | 316 |
foreach ($files as $file) { |
317 | 317 |
try { |
318 |
- $twig->parse($twig->tokenize($template, $file)); |
|
318 |
+ $twig->parse($twig->tokenize(new Twig_Source($template, $file->getFilename(), $file))); |
|
319 | 319 |
|
320 | 320 |
// the $template is valid |
321 | 321 |
} catch (Twig_Error_Syntax $e) { |
... | ... |
@@ -323,6 +323,10 @@ If you iterate over a set of files, you can pass the filename to the |
323 | 323 |
} |
324 | 324 |
} |
325 | 325 |
|
326 |
+.. versionadded:: 1.27 |
|
327 |
+ ``Twig_Source`` was introduced in version 1.27, pass the source and the |
|
328 |
+ identifier directly on previous versions. |
|
329 |
+ |
|
326 | 330 |
.. note:: |
327 | 331 |
|
328 | 332 |
This method won't catch any sandbox policy violations because the policy |
... | ... |
@@ -325,7 +325,14 @@ class Twig_Environment |
325 | 325 |
} |
326 | 326 |
|
327 | 327 |
if (!class_exists($cls, false)) { |
328 |
- $content = $this->compileSource($this->getLoader()->getSource($name), $name); |
|
328 |
+ $loader = $this->getLoader(); |
|
329 |
+ if ($loader instanceof Twig_SourceContextLoaderInterface) { |
|
330 |
+ $source = $loader->getSourceContext($name); |
|
331 |
+ } else { |
|
332 |
+ $source = new Twig_Source($loader->getSource($name), $name); |
|
333 |
+ } |
|
334 |
+ $content = $this->compileSource($source); |
|
335 |
+ |
|
329 | 336 |
$this->cache->write($key, $content); |
330 | 337 |
|
331 | 338 |
eval('?>'.$content); |
... | ... |
@@ -436,8 +443,8 @@ class Twig_Environment |
436 | 443 |
/** |
437 | 444 |
* Tokenizes a source code. |
438 | 445 |
* |
439 |
- * @param string $source The template source code |
|
440 |
- * @param string $name The template name |
|
446 |
+ * @param string|Twig_Source $source The template source code |
|
447 |
+ * @param string $name The template name (deprecated) |
|
441 | 448 |
* |
442 | 449 |
* @return Twig_TokenStream A Twig_TokenStream instance |
443 | 450 |
* |
... | ... |
@@ -445,11 +452,16 @@ class Twig_Environment |
445 | 452 |
*/ |
446 | 453 |
public function tokenize($source, $name = null) |
447 | 454 |
{ |
455 |
+ if (!$source instanceof Twig_Source) { |
|
456 |
+ @trigger_error(sprintf('Passing a string as the $source argument of %s() is deprecated since version 1.27. Pass a Twig_Source instance instead.', __METHOD__), E_USER_DEPRECATED); |
|
457 |
+ $source = new Twig_Source($source, $name); |
|
458 |
+ } |
|
459 |
+ |
|
448 | 460 |
if (null === $this->lexer) { |
449 | 461 |
$this->lexer = new Twig_Lexer($this); |
450 | 462 |
} |
451 | 463 |
|
452 |
- return $this->lexer->tokenize($source, $name); |
|
464 |
+ return $this->lexer->tokenize($source); |
|
453 | 465 |
} |
454 | 466 |
|
455 | 467 |
/** |
... | ... |
@@ -509,8 +521,8 @@ class Twig_Environment |
509 | 521 |
/** |
510 | 522 |
* Compiles a template source code. |
511 | 523 |
* |
512 |
- * @param string $source The template source code |
|
513 |
- * @param string $name The template name |
|
524 |
+ * @param string|Twig_Source $source The template source code |
|
525 |
+ * @param string $name The template name (deprecated) |
|
514 | 526 |
* |
515 | 527 |
* @return string The compiled PHP source code |
516 | 528 |
* |
... | ... |
@@ -518,13 +530,18 @@ class Twig_Environment |
518 | 530 |
*/ |
519 | 531 |
public function compileSource($source, $name = null) |
520 | 532 |
{ |
533 |
+ if (!$source instanceof Twig_Source) { |
|
534 |
+ @trigger_error(sprintf('Passing a string as the $source argument of %s() is deprecated since version 1.27. Pass a Twig_Source instance instead.', __METHOD__), E_USER_DEPRECATED); |
|
535 |
+ $source = new Twig_Source($source, $name); |
|
536 |
+ } |
|
537 |
+ |
|
521 | 538 |
try { |
522 |
- return $this->compile($this->parse($this->tokenize($source, $name))); |
|
539 |
+ return $this->compile($this->parse($this->tokenize($source))); |
|
523 | 540 |
} catch (Twig_Error $e) { |
524 |
- $e->setTemplateName($name); |
|
541 |
+ $e->setTemplateName($source->getName()); |
|
525 | 542 |
throw $e; |
526 | 543 |
} catch (Exception $e) { |
527 |
- throw new Twig_Error_Syntax(sprintf('An exception has been thrown during the compilation of a template ("%s").', $e->getMessage()), -1, $name, $e); |
|
544 |
+ throw new Twig_Error_Syntax(sprintf('An exception has been thrown during the compilation of a template ("%s").', $e->getMessage()), -1, $source->getName(), $e); |
|
528 | 545 |
} |
529 | 546 |
} |
530 | 547 |
|
... | ... |
@@ -171,7 +171,7 @@ class Twig_ExpressionParser |
171 | 171 |
$negClass = 'Twig_Node_Expression_Unary_Neg'; |
172 | 172 |
$posClass = 'Twig_Node_Expression_Unary_Pos'; |
173 | 173 |
if (!(in_array($ref->getName(), array($negClass, $posClass)) || $ref->isSubclassOf($negClass) || $ref->isSubclassOf($posClass))) { |
174 |
- throw new Twig_Error_Syntax(sprintf('Unexpected unary operator "%s".', $token->getValue()), $token->getLine(), $this->parser->getStream()->getFilename()); |
|
174 |
+ throw new Twig_Error_Syntax(sprintf('Unexpected unary operator "%s".', $token->getValue()), $token->getLine(), $this->parser->getStream()->getSourceContext()->getName()); |
|
175 | 175 |
} |
176 | 176 |
|
177 | 177 |
$this->parser->getStream()->next(); |
... | ... |
@@ -187,7 +187,7 @@ class Twig_ExpressionParser |
187 | 187 |
} elseif ($token->test(Twig_Token::PUNCTUATION_TYPE, '{')) { |
188 | 188 |
$node = $this->parseHashExpression(); |
189 | 189 |
} else { |
190 |
- throw new Twig_Error_Syntax(sprintf('Unexpected token "%s" of value "%s".', Twig_Token::typeToEnglish($token->getType()), $token->getValue()), $token->getLine(), $this->parser->getStream()->getFilename()); |
|
190 |
+ throw new Twig_Error_Syntax(sprintf('Unexpected token "%s" of value "%s".', Twig_Token::typeToEnglish($token->getType()), $token->getValue()), $token->getLine(), $this->parser->getStream()->getSourceContext()->getName()); |
|
191 | 191 |
} |
192 | 192 |
} |
193 | 193 |
|
... | ... |
@@ -278,7 +278,7 @@ class Twig_ExpressionParser |
278 | 278 |
} else { |
279 | 279 |
$current = $stream->getCurrent(); |
280 | 280 |
|
281 |
- throw new Twig_Error_Syntax(sprintf('A hash key must be a quoted string, a number, a name, or an expression enclosed in parentheses (unexpected token "%s" of value "%s".', Twig_Token::typeToEnglish($current->getType()), $current->getValue()), $current->getLine(), $stream->getFilename()); |
|
281 |
+ throw new Twig_Error_Syntax(sprintf('A hash key must be a quoted string, a number, a name, or an expression enclosed in parentheses (unexpected token "%s" of value "%s".', Twig_Token::typeToEnglish($current->getType()), $current->getValue()), $current->getLine(), $stream->getSourceContext()->getName()); |
|
282 | 282 |
} |
283 | 283 |
|
284 | 284 |
$stream->expect(Twig_Token::PUNCTUATION_TYPE, ':', 'A hash key must be followed by a colon (:)'); |
... | ... |
@@ -317,11 +317,11 @@ class Twig_ExpressionParser |
317 | 317 |
case 'parent': |
318 | 318 |
$this->parseArguments(); |
319 | 319 |
if (!count($this->parser->getBlockStack())) { |
320 |
- throw new Twig_Error_Syntax('Calling "parent" outside a block is forbidden.', $line, $this->parser->getStream()->getFilename()); |
|
320 |
+ throw new Twig_Error_Syntax('Calling "parent" outside a block is forbidden.', $line, $this->parser->getStream()->getSourceContext()->getName()); |
|
321 | 321 |
} |
322 | 322 |
|
323 | 323 |
if (!$this->parser->getParent() && !$this->parser->hasTraits()) { |
324 |
- throw new Twig_Error_Syntax('Calling "parent" on a template that does not extend nor "use" another template is forbidden.', $line, $this->parser->getStream()->getFilename()); |
|
324 |
+ throw new Twig_Error_Syntax('Calling "parent" on a template that does not extend nor "use" another template is forbidden.', $line, $this->parser->getStream()->getSourceContext()->getName()); |
|
325 | 325 |
} |
326 | 326 |
|
327 | 327 |
return new Twig_Node_Expression_Parent($this->parser->peekBlockStack(), $line); |
... | ... |
@@ -330,7 +330,7 @@ class Twig_ExpressionParser |
330 | 330 |
case 'attribute': |
331 | 331 |
$args = $this->parseArguments(); |
332 | 332 |
if (count($args) < 2) { |
333 |
- throw new Twig_Error_Syntax('The "attribute" function takes at least two arguments (the variable and the attributes).', $line, $this->parser->getStream()->getFilename()); |
|
333 |
+ throw new Twig_Error_Syntax('The "attribute" function takes at least two arguments (the variable and the attributes).', $line, $this->parser->getStream()->getSourceContext()->getName()); |
|
334 | 334 |
} |
335 | 335 |
|
336 | 336 |
return new Twig_Node_Expression_GetAttr($args->getNode(0), $args->getNode(1), count($args) > 2 ? $args->getNode(2) : null, Twig_Template::ANY_CALL, $line); |
... | ... |
@@ -379,12 +379,12 @@ class Twig_ExpressionParser |
379 | 379 |
} |
380 | 380 |
} |
381 | 381 |
} else { |
382 |
- throw new Twig_Error_Syntax('Expected name or number.', $lineno, $stream->getFilename()); |
|
382 |
+ throw new Twig_Error_Syntax('Expected name or number.', $lineno, $stream->getSourceContext()->getName()); |
|
383 | 383 |
} |
384 | 384 |
|
385 | 385 |
if ($node instanceof Twig_Node_Expression_Name && null !== $this->parser->getImportedSymbol('template', $node->getAttribute('name'))) { |
386 | 386 |
if (!$arg instanceof Twig_Node_Expression_Constant) { |
387 |
- throw new Twig_Error_Syntax(sprintf('Dynamic macro names are not supported (called on "%s").', $node->getAttribute('name')), $token->getLine(), $stream->getFilename()); |
|
387 |
+ throw new Twig_Error_Syntax(sprintf('Dynamic macro names are not supported (called on "%s").', $node->getAttribute('name')), $token->getLine(), $stream->getSourceContext()->getName()); |
|
388 | 388 |
} |
389 | 389 |
|
390 | 390 |
$name = $arg->getAttribute('value'); |
... | ... |
@@ -496,7 +496,7 @@ class Twig_ExpressionParser |
496 | 496 |
$name = null; |
497 | 497 |
if ($namedArguments && $token = $stream->nextIf(Twig_Token::OPERATOR_TYPE, '=')) { |
498 | 498 |
if (!$value instanceof Twig_Node_Expression_Name) { |
499 |
- throw new Twig_Error_Syntax(sprintf('A parameter name must be a string, "%s" given.', get_class($value)), $token->getLine(), $stream->getFilename()); |
|
499 |
+ throw new Twig_Error_Syntax(sprintf('A parameter name must be a string, "%s" given.', get_class($value)), $token->getLine(), $stream->getSourceContext()->getName()); |
|
500 | 500 |
} |
501 | 501 |
$name = $value->getAttribute('name'); |
502 | 502 |
|
... | ... |
@@ -504,7 +504,7 @@ class Twig_ExpressionParser |
504 | 504 |
$value = $this->parsePrimaryExpression(); |
505 | 505 |
|
506 | 506 |
if (!$this->checkConstantExpression($value)) { |
507 |
- 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(), $stream->getFilename()); |
|
507 |
+ 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(), $stream->getSourceContext()->getName()); |
|
508 | 508 |
} |
509 | 509 |
} else { |
510 | 510 |
$value = $this->parseExpression(); |
... | ... |
@@ -538,7 +538,7 @@ class Twig_ExpressionParser |
538 | 538 |
$token = $stream->expect(Twig_Token::NAME_TYPE, null, 'Only variables can be assigned to'); |
539 | 539 |
$value = $token->getValue(); |
540 | 540 |
if (in_array(strtolower($value), array('true', 'false', 'none', 'null'))) { |
541 |
- throw new Twig_Error_Syntax(sprintf('You cannot assign a value to "%s".', $value), $token->getLine(), $stream->getFilename()); |
|
541 |
+ throw new Twig_Error_Syntax(sprintf('You cannot assign a value to "%s".', $value), $token->getLine(), $stream->getSourceContext()->getName()); |
|
542 | 542 |
} |
543 | 543 |
$targets[] = new Twig_Node_Expression_AssignName($value, $token->getLine()); |
544 | 544 |
|
... | ... |
@@ -568,7 +568,7 @@ class Twig_ExpressionParser |
568 | 568 |
$env = $this->parser->getEnvironment(); |
569 | 569 |
|
570 | 570 |
if (false === $function = $env->getFunction($name)) { |
571 |
- $e = new Twig_Error_Syntax(sprintf('Unknown "%s" function.', $name), $line, $this->parser->getStream()->getFilename()); |
|
571 |
+ $e = new Twig_Error_Syntax(sprintf('Unknown "%s" function.', $name), $line, $this->parser->getStream()->getSourceContext()->getName()); |
|
572 | 572 |
$e->addSuggestions($name, array_keys($env->getFunctions())); |
573 | 573 |
|
574 | 574 |
throw $e; |
... | ... |
@@ -582,7 +582,7 @@ class Twig_ExpressionParser |
582 | 582 |
if ($function->getAlternative()) { |
583 | 583 |
$message .= sprintf('. Use "%s" instead', $function->getAlternative()); |
584 | 584 |
} |
585 |
- $message .= sprintf(' in %s at line %d.', $this->parser->getStream()->getFilename(), $line); |
|
585 |
+ $message .= sprintf(' in %s at line %d.', $this->parser->getStream()->getSourceContext()->getName(), $line); |
|
586 | 586 |
|
587 | 587 |
@trigger_error($message, E_USER_DEPRECATED); |
588 | 588 |
} |
... | ... |
@@ -595,7 +595,7 @@ class Twig_ExpressionParser |
595 | 595 |
$env = $this->parser->getEnvironment(); |
596 | 596 |
|
597 | 597 |
if (false === $filter = $env->getFilter($name)) { |
598 |
- $e = new Twig_Error_Syntax(sprintf('Unknown "%s" filter.', $name), $line, $this->parser->getStream()->getFilename()); |
|
598 |
+ $e = new Twig_Error_Syntax(sprintf('Unknown "%s" filter.', $name), $line, $this->parser->getStream()->getSourceContext()->getName()); |
|
599 | 599 |
$e->addSuggestions($name, array_keys($env->getFilters())); |
600 | 600 |
|
601 | 601 |
throw $e; |
... | ... |
@@ -609,7 +609,7 @@ class Twig_ExpressionParser |
609 | 609 |
if ($filter->getAlternative()) { |
610 | 610 |
$message .= sprintf('. Use "%s" instead', $filter->getAlternative()); |
611 | 611 |
} |
612 |
- $message .= sprintf(' in %s at line %d.', $this->parser->getStream()->getFilename(), $line); |
|
612 |
+ $message .= sprintf(' in %s at line %d.', $this->parser->getStream()->getSourceContext()->getName(), $line); |
|
613 | 613 |
|
614 | 614 |
@trigger_error($message, E_USER_DEPRECATED); |
615 | 615 |
} |
... | ... |
@@ -296,7 +296,7 @@ class Twig_Extension_Core extends Twig_Extension |
296 | 296 |
} |
297 | 297 |
} |
298 | 298 |
|
299 |
- $e = new Twig_Error_Syntax(sprintf('Unknown "%s" test.', $name), $line, $stream->getFilename()); |
|
299 |
+ $e = new Twig_Error_Syntax(sprintf('Unknown "%s" test.', $name), $line, $stream->getSourceContext()->getName()); |
|
300 | 300 |
$e->addSuggestions($name, array_keys($env->getTests())); |
301 | 301 |
|
302 | 302 |
throw $e; |
... | ... |
@@ -26,6 +26,7 @@ class Twig_Lexer |
26 | 26 |
private $states; |
27 | 27 |
private $brackets; |
28 | 28 |
private $env; |
29 |
+ // to be renamed to $name in 2.0 (where it is private) |
|
29 | 30 |
private $filename; |
30 | 31 |
private $options; |
31 | 32 |
private $regexes; |
... | ... |
@@ -75,8 +76,10 @@ class Twig_Lexer |
75 | 76 |
/** |
76 | 77 |
* {@inheritdoc} |
77 | 78 |
*/ |
78 |
- public function tokenize($code, $filename = null) |
|
79 |
+ public function tokenize($code, $name = null) |
|
79 | 80 |
{ |
81 |
+ $source = $code; |
|
82 |
+ |
|
80 | 83 |
if (((int) ini_get('mbstring.func_overload')) & 2) { |
81 | 84 |
$mbEncoding = mb_internal_encoding(); |
82 | 85 |
mb_internal_encoding('ASCII'); |
... | ... |
@@ -84,8 +87,8 @@ class Twig_Lexer |
84 | 87 |
$mbEncoding = null; |
85 | 88 |
} |
86 | 89 |
|
87 |
- $this->code = str_replace(array("\r\n", "\r"), "\n", $code); |
|
88 |
- $this->filename = $filename; |
|
90 |
+ $this->code = str_replace(array("\r\n", "\r"), "\n", $source->getCode()); |
|
91 |
+ $this->filename = $source->getName(); |
|
89 | 92 |
$this->cursor = 0; |
90 | 93 |
$this->lineno = 1; |
91 | 94 |
$this->end = strlen($this->code); |
... | ... |
@@ -136,7 +139,7 @@ class Twig_Lexer |
136 | 139 |
mb_internal_encoding($mbEncoding); |
137 | 140 |
} |
138 | 141 |
|
139 |
- return new Twig_TokenStream($this->tokens, $this->filename, $this->env->isDebug() ? $code : ''); |
|
142 |
+ return new Twig_TokenStream($this->tokens, $source); |
|
140 | 143 |
} |
141 | 144 |
|
142 | 145 |
private function lexData() |
... | ... |
@@ -14,7 +14,7 @@ |
14 | 14 |
* |
15 | 15 |
* @author Fabien Potencier <fabien@symfony.com> |
16 | 16 |
*/ |
17 |
-class Twig_Loader_Chain implements Twig_LoaderInterface, Twig_ExistsLoaderInterface |
|
17 |
+class Twig_Loader_Chain implements Twig_LoaderInterface, Twig_ExistsLoaderInterface, Twig_SourceContextLoaderInterface |
|
18 | 18 |
{ |
19 | 19 |
private $hasSourceCache = array(); |
20 | 20 |
private $loaders = array(); |
... | ... |
@@ -66,6 +66,35 @@ class Twig_Loader_Chain implements Twig_LoaderInterface, Twig_ExistsLoaderInterf |
66 | 66 |
/** |
67 | 67 |
* {@inheritdoc} |
68 | 68 |
*/ |
69 |
+ public function getSourceContext($name) |
|
70 |
+ { |
|
71 |
+ $exceptions = array(); |
|
72 |
+ foreach ($this->loaders as $loader) { |
|
73 |
+ if (!$loader instanceof Twig_SourceContextLoaderInterface) { |
|
74 |
+ continue; |
|
75 |
+ } |
|
76 |
+ |
|
77 |
+ if ($loader instanceof Twig_ExistsLoaderInterface && !$loader->exists($name)) { |
|
78 |
+ continue; |
|
79 |
+ } |
|
80 |
+ |
|
81 |
+ try { |
|
82 |
+ return $loader->getSourceContext($name); |
|
83 |
+ } catch (Twig_Error_Loader $e) { |
|
84 |
+ $exceptions[] = $e->getMessage(); |
|
85 |
+ } |
|
86 |
+ } |
|
87 |
+ |
|
88 |
+ if ($exceptions) { |
|
89 |
+ throw new Twig_Error_Loader(sprintf('Template "%s" is not defined%s.', $name, $exceptions ? ' ('.implode(', ', $exceptions).')' : '')); |
|
90 |
+ } |
|
91 |
+ |
|
92 |
+ return new Twig_Source($this->getSource($name), $name); |
|
93 |
+ } |
|
94 |
+ |
|
95 |
+ /** |
|
96 |
+ * {@inheritdoc} |
|
97 |
+ */ |
|
69 | 98 |
public function exists($name) |
70 | 99 |
{ |
71 | 100 |
if (isset($this->hasSourceCache[$name])) { |
... | ... |
@@ -14,7 +14,7 @@ |
14 | 14 |
* |
15 | 15 |
* @author Fabien Potencier <fabien@symfony.com> |
16 | 16 |
*/ |
17 |
-class Twig_Loader_Filesystem implements Twig_LoaderInterface, Twig_ExistsLoaderInterface |
|
17 |
+class Twig_Loader_Filesystem implements Twig_LoaderInterface, Twig_ExistsLoaderInterface, Twig_SourceContextLoaderInterface |
|
18 | 18 |
{ |
19 | 19 |
/** Identifier of the main namespace. */ |
20 | 20 |
const MAIN_NAMESPACE = '__main__'; |
... | ... |
@@ -134,6 +134,16 @@ class Twig_Loader_Filesystem implements Twig_LoaderInterface, Twig_ExistsLoaderI |
134 | 134 |
/** |
135 | 135 |
* {@inheritdoc} |
136 | 136 |
*/ |
137 |
+ public function getSourceContext($name) |
|
138 |
+ { |
|
139 |
+ $path = $this->findTemplate($name); |
|
140 |
+ |
|
141 |
+ return new Twig_Source(file_get_contents($path), $name, $path); |
|
142 |
+ } |
|
143 |
+ |
|
144 |
+ /** |
|
145 |
+ * {@inheritdoc} |
|
146 |
+ */ |
|
137 | 147 |
public function getCacheKey($name) |
138 | 148 |
{ |
139 | 149 |
return $this->findTemplate($name); |
... | ... |
@@ -21,8 +21,15 @@ |
21 | 21 |
*/ |
22 | 22 |
class Twig_Node_Module extends Twig_Node |
23 | 23 |
{ |
24 |
- public function __construct(Twig_Node $body, Twig_Node_Expression $parent = null, Twig_Node $blocks, Twig_Node $macros, Twig_Node $traits, $embeddedTemplates, $filename, $source = '') |
|
24 |
+ public function __construct(Twig_Node $body, Twig_Node_Expression $parent = null, Twig_Node $blocks, Twig_Node $macros, Twig_Node $traits, $embeddedTemplates, $name, $source = '') |
|
25 | 25 |
{ |
26 |
+ if (!$name instanceof Twig_Source) { |
|
27 |
+ @trigger_error(sprintf('Passing a string as the $name argument of %s() is deprecated since version 1.27. Pass a Twig_Source instance instead.', __METHOD__), E_USER_DEPRECATED); |
|
28 |
+ $source = new Twig_Source($source, $name); |
|
29 |
+ } else { |
|
30 |
+ $source = $name; |
|
31 |
+ } |
|
32 |
+ |
|
26 | 33 |
$nodes = array( |
27 | 34 |
'body' => $body, |
28 | 35 |
'blocks' => $blocks, |
... | ... |
@@ -40,8 +47,11 @@ class Twig_Node_Module extends Twig_Node |
40 | 47 |
|
41 | 48 |
// embedded templates are set as attributes so that they are only visited once by the visitors |
42 | 49 |
parent::__construct($nodes, array( |
43 |
- 'source' => $source, |
|
44 |
- 'filename' => $filename, |
|
50 |
+ 'source' => $source->getCode(), |
|
51 |
+ 'name' => $source->getName(), |
|
52 |
+ // filename to be remove in 2.0 (use name instead) |
|
53 |
+ 'filename' => $source->getName(), |
|
54 |
+ 'path' => $source->getPath(), |
|
45 | 55 |
'index' => null, |
46 | 56 |
'embedded_templates' => $embeddedTemplates, |
47 | 57 |
), 1); |
... | ... |
@@ -96,6 +106,8 @@ class Twig_Node_Module extends Twig_Node |
96 | 106 |
|
97 | 107 |
$this->compileGetSource($compiler); |
98 | 108 |
|
109 |
+ $this->compileGetSourceContext($compiler); |
|
110 |
+ |
|
99 | 111 |
$this->compileClassFooter($compiler); |
100 | 112 |
} |
101 | 113 |
|
... | ... |
@@ -120,7 +132,7 @@ class Twig_Node_Module extends Twig_Node |
120 | 132 |
->raw('$this->loadTemplate(') |
121 | 133 |
->subcompile($parent) |
122 | 134 |
->raw(', ') |
123 |
- ->repr($this->getAttribute('filename')) |
|
135 |
+ ->repr($this->getAttribute('name')) |
|
124 | 136 |
->raw(', ') |
125 | 137 |
->repr($parent->getLine()) |
126 | 138 |
->raw(')') |
... | ... |
@@ -139,8 +151,8 @@ class Twig_Node_Module extends Twig_Node |
139 | 151 |
$compiler |
140 | 152 |
->write("\n\n") |
141 | 153 |
// if the filename contains */, add a blank to avoid a PHP parse error |
142 |
- ->write('/* '.str_replace('*/', '* /', $this->getAttribute('filename'))." */\n") |
|
143 |
- ->write('class '.$compiler->getEnvironment()->getTemplateClass($this->getAttribute('filename'), $this->getAttribute('index'))) |
|
154 |
+ ->write('/* '.str_replace('*/', '* /', $this->getAttribute('name'))." */\n") |
|
155 |
+ ->write('class '.$compiler->getEnvironment()->getTemplateClass($this->getAttribute('name'), $this->getAttribute('index'))) |
|
144 | 156 |
->raw(sprintf(" extends %s\n", $compiler->getEnvironment()->getBaseTemplateClass())) |
145 | 157 |
->write("{\n") |
146 | 158 |
->indent() |
... | ... |
@@ -165,7 +177,7 @@ class Twig_Node_Module extends Twig_Node |
165 | 177 |
->write('$this->parent = $this->loadTemplate(') |
166 | 178 |
->subcompile($parent) |
167 | 179 |
->raw(', ') |
168 |
- ->repr($this->getAttribute('filename')) |
|
180 |
+ ->repr($this->getAttribute('name')) |
|
169 | 181 |
->raw(', ') |
170 | 182 |
->repr($parent->getLine()) |
171 | 183 |
->raw(");\n") |
... | ... |
@@ -333,7 +345,7 @@ class Twig_Node_Module extends Twig_Node |
333 | 345 |
->write("public function getTemplateName()\n", "{\n") |
334 | 346 |
->indent() |
335 | 347 |
->write('return ') |
336 |
- ->repr($this->getAttribute('filename')) |
|
348 |
+ ->repr($this->getAttribute('name')) |
|
337 | 349 |
->raw(";\n") |
338 | 350 |
->outdent() |
339 | 351 |
->write("}\n\n") |
... | ... |
@@ -409,9 +421,26 @@ class Twig_Node_Module extends Twig_Node |
409 | 421 |
->write("public function getSource()\n", "{\n") |
410 | 422 |
->indent() |
411 | 423 |
->write('return ') |
412 |
- ->string($this->getAttribute('source')) |
|
424 |
+ ->string($compiler->getEnvironment()->isDebug() ? $this->getAttribute('source') : '') |
|
413 | 425 |
->raw(";\n") |
414 | 426 |
->outdent() |
427 |
+ ->write("}\n\n") |
|
428 |
+ ; |
|
429 |
+ } |
|
430 |
+ |
|
431 |
+ protected function compileGetSourceContext(Twig_Compiler $compiler) |
|
432 |
+ { |
|
433 |
+ $compiler |
|
434 |
+ ->write("public function getSourceContext()\n", "{\n") |
|
435 |
+ ->indent() |
|
436 |
+ ->write('return new Twig_Source(') |
|
437 |
+ ->string($compiler->getEnvironment()->isDebug() ? $this->getAttribute('source') : '') |
|
438 |
+ ->raw(', ') |
|
439 |
+ ->string($this->getAttribute('name')) |
|
440 |
+ ->raw(', ') |
|
441 |
+ ->string($this->getAttribute('path')) |
|
442 |
+ ->raw(");\n") |
|
443 |
+ ->outdent() |
|
415 | 444 |
->write("}\n") |
416 | 445 |
; |
417 | 446 |
} |
... | ... |
@@ -102,7 +102,7 @@ class Twig_Parser |
102 | 102 |
} |
103 | 103 |
} catch (Twig_Error_Syntax $e) { |
104 | 104 |
if (!$e->getTemplateName()) { |
105 |
- $e->setTemplateName($this->stream->getFilename()); |
|
105 |
+ $e->setTemplateName($this->stream->getSourceContext()->getName()); |
|
106 | 106 |
} |
107 | 107 |
|
108 | 108 |
if (!$e->getTemplateLine()) { |
... | ... |
@@ -112,7 +112,7 @@ class Twig_Parser |
112 | 112 |
throw $e; |
113 | 113 |
} |
114 | 114 |
|
115 |
- $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->stream->getFilename(), $stream->getSource()); |
|
115 |
+ $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, $stream->getSourceContext()); |
|
116 | 116 |
|
117 | 117 |
$traverser = new Twig_NodeTraverser($this->env, $this->visitors); |
118 | 118 |
|
... | ... |
@@ -149,7 +149,7 @@ class Twig_Parser |
149 | 149 |
$token = $this->getCurrentToken(); |
150 | 150 |
|
151 | 151 |
if ($token->getType() !== Twig_Token::NAME_TYPE) { |
152 |
- throw new Twig_Error_Syntax('A block must start with a tag name.', $token->getLine(), $this->stream->getFilename()); |
|
152 |
+ throw new Twig_Error_Syntax('A block must start with a tag name.', $token->getLine(), $this->stream->getSourceContext()->getName()); |
|
153 | 153 |
} |
154 | 154 |
|
155 | 155 |
if (null !== $test && $test($token)) { |
... | ... |
@@ -166,13 +166,13 @@ class Twig_Parser |
166 | 166 |
|
167 | 167 |
if (!isset($this->handlers[$token->getValue()])) { |
168 | 168 |
if (null !== $test) { |
169 |
- $e = new Twig_Error_Syntax(sprintf('Unexpected "%s" tag', $token->getValue()), $token->getLine(), $this->stream->getFilename()); |
|
169 |
+ $e = new Twig_Error_Syntax(sprintf('Unexpected "%s" tag', $token->getValue()), $token->getLine(), $this->stream->getSourceContext()->getName()); |
|
170 | 170 |
|
171 | 171 |
if (is_array($test) && isset($test[0]) && $test[0] instanceof Twig_TokenParserInterface) { |
172 | 172 |
$e->appendMessage(sprintf(' (expecting closing tag for the "%s" tag defined near line %s).', $test[0]->getTag(), $lineno)); |
173 | 173 |
} |
174 | 174 |
} else { |
175 |
- $e = new Twig_Error_Syntax(sprintf('Unknown "%s" tag.', $token->getValue()), $token->getLine(), $this->stream->getFilename()); |
|
175 |
+ $e = new Twig_Error_Syntax(sprintf('Unknown "%s" tag.', $token->getValue()), $token->getLine(), $this->stream->getSourceContext()->getName()); |
|
176 | 176 |
$e->addSuggestions($token->getValue(), array_keys($this->env->getTags())); |
177 | 177 |
} |
178 | 178 |
|
... | ... |
@@ -189,7 +189,7 @@ class Twig_Parser |
189 | 189 |
break; |
190 | 190 |
|
191 | 191 |
default: |
192 |
- throw new Twig_Error_Syntax('Lexer or parser ended up in unsupported state.', 0, $this->stream->getFilename()); |
|
192 |
+ throw new Twig_Error_Syntax('Lexer or parser ended up in unsupported state.', 0, $this->stream->getSourceContext()->getName()); |
|
193 | 193 |
} |
194 | 194 |
} |
195 | 195 |
|
... | ... |
@@ -355,10 +355,10 @@ class Twig_Parser |
355 | 355 |
(!$node instanceof Twig_Node_Text && !$node instanceof Twig_Node_BlockReference && $node instanceof Twig_NodeOutputInterface) |
356 | 356 |
) { |
357 | 357 |
if (false !== strpos((string) $node, chr(0xEF).chr(0xBB).chr(0xBF))) { |
358 |
- throw new Twig_Error_Syntax('A template that extends another one cannot start with a byte order mark (BOM); it must be removed.', $node->getLine(), $this->stream->getFilename()); |
|
358 |
+ throw new Twig_Error_Syntax('A template that extends another one cannot start with a byte order mark (BOM); it must be removed.', $node->getLine(), $this->stream->getSourceContext()->getName()); |
|
359 | 359 |
} |
360 | 360 |
|
361 |
- throw new Twig_Error_Syntax('A template that extends another one cannot include contents outside Twig blocks. Did you forget to put the contents inside a {% block %} tag?', $node->getLine(), $this->stream->getFilename()); |
|
361 |
+ throw new Twig_Error_Syntax('A template that extends another one cannot include contents outside Twig blocks. Did you forget to put the contents inside a {% block %} tag?', $node->getLine(), $this->stream->getSourceContext()->getName()); |
|
362 | 362 |
} |
363 | 363 |
|
364 | 364 |
// bypass "set" nodes as they "capture" the output |
365 | 365 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,49 @@ |
1 |
+<?php |
|
2 |
+ |
|
3 |
+/* |
|
4 |
+ * This file is part of Twig. |
|
5 |
+ * |
|
6 |
+ * (c) 2016 Fabien Potencier |
|
7 |
+ * |
|
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 |
+ * Holds information about a non-compiled Twig template. |
|
14 |
+ * |
|
15 |
+ * @author Fabien Potencier <fabien@symfony.com> |
|
16 |
+ */ |
|
17 |
+class Twig_Source |
|
18 |
+{ |
|
19 |
+ private $code; |
|
20 |
+ private $name; |
|
21 |
+ private $path; |
|
22 |
+ |
|
23 |
+ /** |
|
24 |
+ * @param string $code The template source code |
|
25 |
+ * @param string $name The template logical name |
|
26 |
+ * @param string $path The filesystem path of the template if any |
|
27 |
+ */ |
|
28 |
+ public function __construct($code, $name = null, $path = null) |
|
29 |
+ { |
|
30 |
+ $this->code = $code; |
|
31 |
+ $this->name = $name; |
|
32 |
+ $this->path = $path; |
|
33 |
+ } |
|
34 |
+ |
|
35 |
+ public function getCode() |
|
36 |
+ { |
|
37 |
+ return $this->code; |
|
38 |
+ } |
|
39 |
+ |
|
40 |
+ public function getName() |
|
41 |
+ { |
|
42 |
+ return $this->name; |
|
43 |
+ } |
|
44 |
+ |
|
45 |
+ public function getPath() |
|
46 |
+ { |
|
47 |
+ return $this->path; |
|
48 |
+ } |
|
49 |
+} |
0 | 50 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,22 @@ |
1 |
+<?php |
|
2 |
+ |
|
3 |
+/* |
|
4 |
+ * This file is part of Twig. |
|
5 |
+ * |
|
6 |
+ * (c) 2016 Fabien Potencier |
|
7 |
+ * |
|
8 |
+ * For the full copyright and license information, please view the LICENSE |
|
9 |
+ * file that was distributed with this source code. |
|
10 |
+ */ |
|
11 |
+ |
|
12 |
+interface Twig_SourceContextLoaderInterface |
|
13 |
+{ |
|
14 |
+ /** |
|
15 |
+ * Returns the source context for a given template logical name. |
|
16 |
+ * |
|
17 |
+ * @param string $name The template logical name |
|
18 |
+ * |
|
19 |
+ * @return Twig_Source |
|
20 |
+ */ |
|
21 |
+ public function getSourceContext($name); |
|
22 |
+} |
... | ... |
@@ -24,7 +24,7 @@ class Twig_TokenParser_AutoEscape extends Twig_TokenParser |
24 | 24 |
} else { |
25 | 25 |
$expr = $this->parser->getExpressionParser()->parseExpression(); |
26 | 26 |
if (!$expr instanceof Twig_Node_Expression_Constant) { |
27 |
- throw new Twig_Error_Syntax('An escaping strategy must be a string or false.', $stream->getCurrent()->getLine(), $stream->getFilename()); |
|
27 |
+ throw new Twig_Error_Syntax('An escaping strategy must be a string or false.', $stream->getCurrent()->getLine(), $stream->getSourceContext()->getName()); |
|
28 | 28 |
} |
29 | 29 |
$value = $expr->getAttribute('value'); |
30 | 30 |
} |
... | ... |
@@ -28,7 +28,7 @@ class Twig_TokenParser_Block extends Twig_TokenParser |
28 | 28 |
$stream = $this->parser->getStream(); |
29 | 29 |
$name = $stream->expect(Twig_Token::NAME_TYPE)->getValue(); |
30 | 30 |
if ($this->parser->hasBlock($name)) { |
31 |
- throw new Twig_Error_Syntax(sprintf("The block '%s' has already been defined line %d.", $name, $this->parser->getBlock($name)->getLine()), $stream->getCurrent()->getLine(), $stream->getFilename()); |
|
31 |
+ throw new Twig_Error_Syntax(sprintf("The block '%s' has already been defined line %d.", $name, $this->parser->getBlock($name)->getLine()), $stream->getCurrent()->getLine(), $stream->getSourceContext()->getName()); |
|
32 | 32 |
} |
33 | 33 |
$this->parser->setBlock($name, $block = new Twig_Node_Block($name, new Twig_Node(array()), $lineno)); |
34 | 34 |
$this->parser->pushLocalScope(); |
... | ... |
@@ -40,7 +40,7 @@ class Twig_TokenParser_Block extends Twig_TokenParser |
40 | 40 |
$value = $token->getValue(); |
41 | 41 |
|
42 | 42 |
if ($value != $name) { |
43 |
- throw new Twig_Error_Syntax(sprintf('Expected endblock for block "%s" (but "%s" given).', $name, $value), $stream->getCurrent()->getLine(), $stream->getFilename()); |
|
43 |
+ throw new Twig_Error_Syntax(sprintf('Expected endblock for block "%s" (but "%s" given).', $name, $value), $stream->getCurrent()->getLine(), $stream->getSourceContext()->getName()); |
|
44 | 44 |
} |
45 | 45 |
} |
46 | 46 |
} else { |
... | ... |
@@ -24,11 +24,11 @@ class Twig_TokenParser_Extends extends Twig_TokenParser |
24 | 24 |
$stream = $this->parser->getStream(); |
25 | 25 |
|
26 | 26 |
if (!$this->parser->isMainScope()) { |
27 |
- throw new Twig_Error_Syntax('Cannot extend from a block.', $token->getLine(), $stream->getFilename()); |
|
27 |
+ throw new Twig_Error_Syntax('Cannot extend from a block.', $token->getLine(), $stream->getSourceContext()->getName()); |
|
28 | 28 |
} |
29 | 29 |
|
30 | 30 |
if (null !== $this->parser->getParent()) { |
31 |
- throw new Twig_Error_Syntax('Multiple extends tags are forbidden.', $token->getLine(), $stream->getFilename()); |
|
31 |
+ throw new Twig_Error_Syntax('Multiple extends tags are forbidden.', $token->getLine(), $stream->getSourceContext()->getName()); |
|
32 | 32 |
} |
33 | 33 |
$this->parser->setParent($this->parser->getExpressionParser()->parseExpression()); |
34 | 34 |
|
... | ... |
@@ -79,7 +79,7 @@ class Twig_TokenParser_For extends Twig_TokenParser |
79 | 79 |
private function checkLoopUsageCondition(Twig_TokenStream $stream, Twig_Node $node) |
80 | 80 |
{ |
81 | 81 |
if ($node instanceof Twig_Node_Expression_GetAttr && $node->getNode('node') instanceof Twig_Node_Expression_Name && 'loop' == $node->getNode('node')->getAttribute('name')) { |
82 |
- throw new Twig_Error_Syntax('The "loop" variable cannot be used in a looping condition.', $node->getLine(), $stream->getFilename()); |
|
82 |
+ throw new Twig_Error_Syntax('The "loop" variable cannot be used in a looping condition.', $node->getLine(), $stream->getSourceContext()->getName()); |
|
83 | 83 |
} |
84 | 84 |
|
85 | 85 |
foreach ($node as $n) { |
... | ... |
@@ -98,7 +98,7 @@ class Twig_TokenParser_For extends Twig_TokenParser |
98 | 98 |
if ($node instanceof Twig_Node_Expression_GetAttr && $node->getNode('node') instanceof Twig_Node_Expression_Name && 'loop' == $node->getNode('node')->getAttribute('name')) { |
99 | 99 |
$attribute = $node->getNode('attribute'); |
100 | 100 |
if ($attribute instanceof Twig_Node_Expression_Constant && in_array($attribute->getAttribute('value'), array('length', 'revindex0', 'revindex', 'last'))) { |
101 |
- 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()); |
|
101 |
+ throw new Twig_Error_Syntax(sprintf('The "loop.%s" variable is not defined when looping with a condition.', $attribute->getAttribute('value')), $node->getLine(), $stream->getSourceContext()->getName()); |
|
102 | 102 |
} |
103 | 103 |
} |
104 | 104 |
|
... | ... |
@@ -56,7 +56,7 @@ class Twig_TokenParser_If extends Twig_TokenParser |
56 | 56 |
break; |
57 | 57 |
|
58 | 58 |
default: |
59 |
- 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()); |
|
59 |
+ 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->getSourceContext()->getName()); |
|
60 | 60 |
} |
61 | 61 |
} |
62 | 62 |
|
... | ... |
@@ -35,7 +35,7 @@ class Twig_TokenParser_Macro extends Twig_TokenParser |
35 | 35 |
$value = $token->getValue(); |
36 | 36 |
|
37 | 37 |
if ($value != $name) { |
38 |
- throw new Twig_Error_Syntax(sprintf('Expected endmacro for macro "%s" (but "%s" given).', $name, $value), $stream->getCurrent()->getLine(), $stream->getFilename()); |
|
38 |
+ throw new Twig_Error_Syntax(sprintf('Expected endmacro for macro "%s" (but "%s" given).', $name, $value), $stream->getCurrent()->getLine(), $stream->getSourceContext()->getName()); |
|
39 | 39 |
} |
40 | 40 |
} |
41 | 41 |
$this->parser->popLocalScope(); |
... | ... |
@@ -37,7 +37,7 @@ class Twig_TokenParser_Sandbox extends Twig_TokenParser |
37 | 37 |
} |
38 | 38 |
|
39 | 39 |
if (!$node instanceof Twig_Node_Include) { |
40 |
- throw new Twig_Error_Syntax('Only "include" tags are allowed within a "sandbox" section.', $node->getLine(), $stream->getFilename()); |
|
40 |
+ throw new Twig_Error_Syntax('Only "include" tags are allowed within a "sandbox" section.', $node->getLine(), $stream->getSourceContext()->getName()); |
|
41 | 41 |
} |
42 | 42 |
} |
43 | 43 |
} |
... | ... |
@@ -41,13 +41,13 @@ class Twig_TokenParser_Set extends Twig_TokenParser |
41 | 41 |
$stream->expect(Twig_Token::BLOCK_END_TYPE); |
42 | 42 |
|
43 | 43 |
if (count($names) !== count($values)) { |
44 |
- throw new Twig_Error_Syntax('When using set, you must have the same number of variables and assignments.', $stream->getCurrent()->getLine(), $stream->getFilename()); |
|
44 |
+ throw new Twig_Error_Syntax('When using set, you must have the same number of variables and assignments.', $stream->getCurrent()->getLine(), $stream->getSourceContext()->getName()); |
|
45 | 45 |
} |
46 | 46 |
} else { |
47 | 47 |
$capture = true; |
48 | 48 |
|
49 | 49 |
if (count($names) > 1) { |
50 |
- throw new Twig_Error_Syntax('When using set with a block, you cannot have a multi-target.', $stream->getCurrent()->getLine(), $stream->getFilename()); |
|
50 |
+ throw new Twig_Error_Syntax('When using set with a block, you cannot have a multi-target.', $stream->getCurrent()->getLine(), $stream->getSourceContext()->getName()); |
|
51 | 51 |
} |
52 | 52 |
|
53 | 53 |
$stream->expect(Twig_Token::BLOCK_END_TYPE); |
... | ... |
@@ -31,7 +31,7 @@ class Twig_TokenParser_Use extends Twig_TokenParser |
31 | 31 |
$stream = $this->parser->getStream(); |
32 | 32 |
|
33 | 33 |
if (!$template instanceof Twig_Node_Expression_Constant) { |
34 |
- throw new Twig_Error_Syntax('The template references in a "use" statement must be a string.', $stream->getCurrent()->getLine(), $stream->getFilename()); |
|
34 |
+ throw new Twig_Error_Syntax('The template references in a "use" statement must be a string.', $stream->getCurrent()->getLine(), $stream->getSourceContext()->getName()); |
|
35 | 35 |
} |
36 | 36 |
|
37 | 37 |
$targets = array(); |
... | ... |
@@ -26,15 +26,25 @@ class Twig_TokenStream |
26 | 26 |
/** |
27 | 27 |
* Constructor. |
28 | 28 |
* |
29 |
- * @param array $tokens An array of tokens |
|
30 |
- * @param string|null $filename The name of the filename which tokens are associated with |
|
31 |
- * @param string|null $source The source code associated with the tokens |
|
29 |
+ * @param array $tokens An array of tokens |
|
30 |
+ * @param string|null $name The name of the template which tokens are associated with |
|
31 |
+ * @param string|null $source The source code associated with the tokens |
|
32 | 32 |
*/ |
33 |
- public function __construct(array $tokens, $filename = null, $source = null) |
|
33 |
+ public function __construct(array $tokens, $name = null, $source = null) |
|
34 | 34 |
{ |
35 |
+ if (!$name instanceof Twig_Source) { |
|
36 |
+ if (null !== $name || null !== $source) { |
|
37 |
+ @trigger_error(sprintf('Passing a string as the $name argument of %s() is deprecated since version 1.27. Pass a Twig_Source instance instead.', __METHOD__), E_USER_DEPRECATED); |
|
38 |
+ } |
|
39 |
+ $this->source = new Twig_Source($source, $name); |
|
40 |
+ } else { |
|
41 |
+ $this->source = $name; |
|
42 |
+ } |
|
43 |
+ |
|
35 | 44 |
$this->tokens = $tokens; |
36 |
- $this->filename = $filename; |
|
37 |
- $this->source = $source ? $source : ''; |
|
45 |
+ |
|
46 |
+ // deprecated, not used anymore, to be removed in 2.0 |
|
47 |
+ $this->filename = $this->source->getName(); |
|
38 | 48 |
} |
39 | 49 |
|
40 | 50 |
/** |
... | ... |
@@ -60,7 +70,7 @@ class Twig_TokenStream |
60 | 70 |
public function next() |
61 | 71 |
{ |
62 | 72 |
if (!isset($this->tokens[++$this->current])) { |
63 |
- throw new Twig_Error_Syntax('Unexpected end of template.', $this->tokens[$this->current - 1]->getLine(), $this->filename); |
|
73 |
+ throw new Twig_Error_Syntax('Unexpected end of template.', $this->tokens[$this->current - 1]->getLine(), $this->source->getName()); |
|
64 | 74 |
} |
65 | 75 |
|
66 | 76 |
return $this->tokens[$this->current - 1]; |
... | ... |
@@ -93,7 +103,7 @@ class Twig_TokenStream |
93 | 103 |
Twig_Token::typeToEnglish($token->getType()), $token->getValue(), |
94 | 104 |
Twig_Token::typeToEnglish($type), $value ? sprintf(' with value "%s"', $value) : ''), |
95 | 105 |
$line, |
96 |
- $this->filename |
|
106 |
+ $this->source->getName() |
|
97 | 107 |
); |
98 | 108 |
} |
99 | 109 |
$this->next(); |
... | ... |
@@ -111,7 +121,7 @@ class Twig_TokenStream |
111 | 121 |
public function look($number = 1) |
112 | 122 |
{ |
113 | 123 |
if (!isset($this->tokens[$this->current + $number])) { |
114 |
- throw new Twig_Error_Syntax('Unexpected end of template.', $this->tokens[$this->current + $number - 1]->getLine(), $this->filename); |
|
124 |
+ throw new Twig_Error_Syntax('Unexpected end of template.', $this->tokens[$this->current + $number - 1]->getLine(), $this->source->getName()); |
|
115 | 125 |
} |
116 | 126 |
|
117 | 127 |
return $this->tokens[$this->current + $number]; |
... | ... |
@@ -148,13 +158,17 @@ class Twig_TokenStream |
148 | 158 |
} |
149 | 159 |
|
150 | 160 |
/** |
151 |
- * Gets the filename associated with this stream (null if not defined). |
|
161 |
+ * Gets the name associated with this stream (null if not defined). |
|
152 | 162 |
* |
153 | 163 |
* @return string|null |
164 |
+ * |
|
165 |
+ * @deprecated since 1.27 (to be removed in 2.0) |
|
154 | 166 |
*/ |
155 | 167 |
public function getFilename() |
156 | 168 |
{ |
157 |
- return $this->filename; |
|
169 |
+ @trigger_error(sprintf('The %s() method is deprecated since version 1.27 and will be removed in 2.0. Use getSourceContext() instead.', __METHOD__), E_USER_DEPRECATED); |
|
170 |
+ |
|
171 |
+ return $this->source->getName(); |
|
158 | 172 |
} |
159 | 173 |
|
160 | 174 |
/** |
... | ... |
@@ -163,9 +177,25 @@ class Twig_TokenStream |
163 | 177 |
* @return string |
164 | 178 |
* |
165 | 179 |
* @internal Don't use this as it might be empty depending on the environment configuration |
180 |
+ * |
|
181 |
+ * @deprecated since 1.27 (to be removed in 2.0) |
|
166 | 182 |
*/ |
167 | 183 |
public function getSource() |
168 | 184 |
{ |
185 |
+ @trigger_error(sprintf('The %s() method is deprecated since version 1.27 and will be removed in 2.0. Use getSourceContext() instead.', __METHOD__), E_USER_DEPRECATED); |
|
186 |
+ |
|
187 |
+ return $this->source->getCode(); |
|
188 |
+ } |
|
189 |
+ |
|
190 |
+ /** |
|
191 |
+ * Gets the source associated with this stream. |
|
192 |
+ * |
|
193 |
+ * @return Twig_Source |
|
194 |
+ * |
|
195 |
+ * @internal |
|
196 |
+ */ |
|
197 |
+ public function getSourceContext() |
|
198 |
+ { |
|
169 | 199 |
return $this->source; |
170 | 200 |
} |
171 | 201 |
} |
... | ... |
@@ -134,7 +134,7 @@ class Twig_Tests_EnvironmentTest extends PHPUnit_Framework_TestCase |
134 | 134 |
$twig = new Twig_Environment($loader = new Twig_Loader_Array(array('index' => '{{ foo }}')), $options); |
135 | 135 |
|
136 | 136 |
$key = $cache->generateKey('index', $twig->getTemplateClass('index')); |
137 |
- $cache->write($key, $twig->compileSource('{{ foo }}', 'index')); |
|
137 |
+ $cache->write($key, $twig->compileSource(new Twig_Source('{{ foo }}', 'index'))); |
|
138 | 138 |
|
139 | 139 |
// check that extensions won't be initialized when rendering a template that is already in the cache |
140 | 140 |
$twig = $this |
... | ... |
@@ -20,7 +20,7 @@ class Twig_Tests_ExpressionParserTest extends PHPUnit_Framework_TestCase |
20 | 20 |
$env = new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock(), array('cache' => false, 'autoescape' => false)); |
21 | 21 |
$parser = new Twig_Parser($env); |
22 | 22 |
|
23 |
- $parser->parse($env->tokenize($template, 'index')); |
|
23 |
+ $parser->parse($env->tokenize(new Twig_Source($template, 'index'))); |
|
24 | 24 |
} |
25 | 25 |
|
26 | 26 |
public function getFailingTestsForAssignment() |
... | ... |
@@ -47,7 +47,7 @@ class Twig_Tests_ExpressionParserTest extends PHPUnit_Framework_TestCase |
47 | 47 |
public function testArrayExpression($template, $expected) |
48 | 48 |
{ |
49 | 49 |
$env = new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock(), array('cache' => false, 'autoescape' => false)); |
50 |
- $stream = $env->tokenize($template, 'index'); |
|
50 |
+ $stream = $env->tokenize(new Twig_Source($template, 'index')); |
|
51 | 51 |
$parser = new Twig_Parser($env); |
52 | 52 |
|
53 | 53 |
$this->assertEquals($expected, $parser->parse($stream)->getNode('body')->getNode(0)->getNode('expr')); |
... | ... |
@@ -62,7 +62,7 @@ class Twig_Tests_ExpressionParserTest extends PHPUnit_Framework_TestCase |
62 | 62 |
$env = new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock(), array('cache' => false, 'autoescape' => false)); |
63 | 63 |
$parser = new Twig_Parser($env); |
64 | 64 |
|
65 |
- $parser->parse($env->tokenize($template, 'index')); |
|
65 |
+ $parser->parse($env->tokenize(new Twig_Source($template, 'index'))); |
|
66 | 66 |
} |
67 | 67 |
|
68 | 68 |
public function getFailingTestsForArray() |
... | ... |
@@ -155,7 +155,7 @@ class Twig_Tests_ExpressionParserTest extends PHPUnit_Framework_TestCase |
155 | 155 |
public function testStringExpressionDoesNotConcatenateTwoConsecutiveStrings() |
156 | 156 |
{ |
157 | 157 |
$env = new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock(), array('cache' => false, 'autoescape' => false, 'optimizations' => 0)); |
158 |
- $stream = $env->tokenize('{{ "a" "b" }}', 'index'); |
|
158 |
+ $stream = $env->tokenize(new Twig_Source('{{ "a" "b" }}', 'index')); |
|
159 | 159 |
$parser = new Twig_Parser($env); |
160 | 160 |
|
161 | 161 |
$parser->parse($stream); |
... | ... |
@@ -167,7 +167,7 @@ class Twig_Tests_ExpressionParserTest extends PHPUnit_Framework_TestCase |
167 | 167 |
public function testStringExpression($template, $expected) |
168 | 168 |
{ |
169 | 169 |
$env = new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock(), array('cache' => false, 'autoescape' => false, 'optimizations' => 0)); |
170 |
- $stream = $env->tokenize($template, 'index'); |
|
170 |
+ $stream = $env->tokenize(new Twig_Source($template, 'index')); |
|
171 | 171 |
$parser = new Twig_Parser($env); |
172 | 172 |
|
173 | 173 |
$this->assertEquals($expected, $parser->parse($stream)->getNode('body')->getNode(0)->getNode('expr')); |
... | ... |
@@ -228,7 +228,7 @@ class Twig_Tests_ExpressionParserTest extends PHPUnit_Framework_TestCase |
228 | 228 |
$env = new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock(), array('cache' => false, 'autoescape' => false)); |
229 | 229 |
$parser = new Twig_Parser($env); |
230 | 230 |
|
231 |
- $parser->parse($env->tokenize('{{ foo.bar(name="Foo") }}', 'index')); |
|
231 |
+ $parser->parse($env->tokenize(new Twig_Source('{{ foo.bar(name="Foo") }}', 'index'))); |
|
232 | 232 |
} |
233 | 233 |
|
234 | 234 |
/** |
... | ... |
@@ -239,7 +239,7 @@ class Twig_Tests_ExpressionParserTest extends PHPUnit_Framework_TestCase |
239 | 239 |
$env = new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock(), array('cache' => false, 'autoescape' => false)); |
240 | 240 |
$parser = new Twig_Parser($env); |
241 | 241 |
|
242 |
- $parser->parse($env->tokenize('{% from _self import foo %}{% macro foo() %}{% endmacro %}{{ foo(name="Foo") }}', 'index')); |
|
242 |
+ $parser->parse($env->tokenize(new Twig_Source('{% from _self import foo %}{% macro foo() %}{% endmacro %}{{ foo(name="Foo") }}', 'index'))); |
|
243 | 243 |
} |
244 | 244 |
|
245 | 245 |
/** |
... | ... |
@@ -251,7 +251,7 @@ class Twig_Tests_ExpressionParserTest extends PHPUnit_Framework_TestCase |
251 | 251 |
$env = new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock(), array('cache' => false, 'autoescape' => false)); |
252 | 252 |
$parser = new Twig_Parser($env); |
253 | 253 |
|
254 |
- $parser->parse($env->tokenize('{% macro foo("a") %}{% endmacro %}', 'index')); |
|
254 |
+ $parser->parse($env->tokenize(new Twig_Source('{% macro foo("a") %}{% endmacro %}', 'index'))); |
|
255 | 255 |
} |
256 | 256 |
|
257 | 257 |
/** |
... | ... |
@@ -264,7 +264,7 @@ class Twig_Tests_ExpressionParserTest extends PHPUnit_Framework_TestCase |
264 | 264 |
$env = new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock(), array('cache' => false, 'autoescape' => false)); |
265 | 265 |
$parser = new Twig_Parser($env); |
266 | 266 |
|
267 |
- $parser->parse($env->tokenize($template, 'index')); |
|
267 |
+ $parser->parse($env->tokenize(new Twig_Source($template, 'index'))); |
|
268 | 268 |
} |
269 | 269 |
|
270 | 270 |
public function getMacroDefinitionDoesNotSupportNonConstantDefaultValues() |
... | ... |
@@ -283,7 +283,7 @@ class Twig_Tests_ExpressionParserTest extends PHPUnit_Framework_TestCase |
283 | 283 |
$env = new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock(), array('cache' => false, 'autoescape' => false)); |
284 | 284 |
$parser = new Twig_Parser($env); |
285 | 285 |
|
286 |
- $parser->parse($env->tokenize($template, 'index')); |
|
286 |
+ $parser->parse($env->tokenize(new Twig_Source($template, 'index'))); |
|
287 | 287 |
} |
288 | 288 |
|
289 | 289 |
public function getMacroDefinitionSupportsConstantDefaultValues() |
... | ... |
@@ -308,7 +308,7 @@ class Twig_Tests_ExpressionParserTest extends PHPUnit_Framework_TestCase |
308 | 308 |
$env = new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock(), array('cache' => false, 'autoescape' => false)); |
309 | 309 |
$parser = new Twig_Parser($env); |
310 | 310 |
|
311 |
- $parser->parse($env->tokenize('{{ cycl() }}', 'index')); |
|
311 |
+ $parser->parse($env->tokenize(new Twig_Source('{{ cycl() }}', 'index'))); |
|
312 | 312 |
} |
313 | 313 |
|
314 | 314 |
/** |
... | ... |
@@ -320,7 +320,7 @@ class Twig_Tests_ExpressionParserTest extends PHPUnit_Framework_TestCase |
320 | 320 |
$env = new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock(), array('cache' => false, 'autoescape' => false)); |
321 | 321 |
$parser = new Twig_Parser($env); |
322 | 322 |
|
323 |
- $parser->parse($env->tokenize('{{ foobar() }}', 'index')); |
|
323 |
+ $parser->parse($env->tokenize(new Twig_Source('{{ foobar() }}', 'index'))); |
|
324 | 324 |
} |
325 | 325 |
|
326 | 326 |
/** |
... | ... |
@@ -332,7 +332,7 @@ class Twig_Tests_ExpressionParserTest extends PHPUnit_Framework_TestCase |
332 | 332 |
$env = new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock(), array('cache' => false, 'autoescape' => false)); |
333 | 333 |
$parser = new Twig_Parser($env); |
334 | 334 |
|
335 |
- $parser->parse($env->tokenize('{{ 1|lowe }}', 'index')); |
|
335 |
+ $parser->parse($env->tokenize(new Twig_Source('{{ 1|lowe }}', 'index'))); |
|
336 | 336 |
} |
337 | 337 |
|
338 | 338 |
/** |
... | ... |
@@ -344,7 +344,7 @@ class Twig_Tests_ExpressionParserTest extends PHPUnit_Framework_TestCase |
344 | 344 |
$env = new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock(), array('cache' => false, 'autoescape' => false)); |
345 | 345 |
$parser = new Twig_Parser($env); |
346 | 346 |
|
347 |
- $parser->parse($env->tokenize('{{ 1|foobar }}', 'index')); |
|
347 |
+ $parser->parse($env->tokenize(new Twig_Source('{{ 1|foobar }}', 'index'))); |
|
348 | 348 |
} |
349 | 349 |
|
350 | 350 |
/** |
... | ... |
@@ -355,8 +355,8 @@ class Twig_Tests_ExpressionParserTest extends PHPUnit_Framework_TestCase |
355 | 355 |
{ |
356 | 356 |
$env = new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock(), array('cache' => false, 'autoescape' => false)); |
357 | 357 |
$parser = new Twig_Parser($env); |
358 |
- |
|
359 |
- $parser->parse($env->tokenize('{{ 1 is nul }}', 'index')); |
|
358 |
+ $stream = $env->tokenize(new Twig_Source('{{ 1 is nul }}', 'index')); |
|
359 |
+ $parser->parse($stream); |
|
360 | 360 |
} |
361 | 361 |
|
362 | 362 |
/** |
... | ... |
@@ -368,6 +368,6 @@ class Twig_Tests_ExpressionParserTest extends PHPUnit_Framework_TestCase |
368 | 368 |
$env = new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock(), array('cache' => false, 'autoescape' => false)); |
369 | 369 |
$parser = new Twig_Parser($env); |
370 | 370 |
|
371 |
- $parser->parse($env->tokenize('{{ 1 is foobar }}', 'index')); |
|
371 |
+ $parser->parse($env->tokenize(new Twig_Source('{{ 1 is foobar }}', 'index'))); |
|
372 | 372 |
} |
373 | 373 |
} |
... | ... |
@@ -10,16 +10,15 @@ |
10 | 10 |
*/ |
11 | 11 |
class Twig_Tests_LexerTest extends PHPUnit_Framework_TestCase |
12 | 12 |
{ |
13 |
- public function testStreamSource() |
|
13 |
+ /** |
|
14 |
+ * @group legacy |
|
15 |
+ */ |
|
16 |
+ public function testLegacyConstructorSignature() |
|
14 | 17 |
{ |
15 |
- $env = new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock()); |
|
16 |
- $lexer = new Twig_Lexer($env); |
|
17 |
- |
|
18 |
- $env->disableDebug(); |
|
19 |
- $this->assertSame('', $lexer->tokenize('foo')->getSource()); |
|
20 |
- |
|
21 |
- $env->enableDebug(); |
|
22 |
- $this->assertSame('foo', $lexer->tokenize('foo')->getSource()); |
|
18 |
+ $lexer = new Twig_Lexer(new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock())); |
|
19 |
+ $stream = $lexer->tokenize('{{ foo }}', 'foo'); |
|
20 |
+ $this->assertEquals('foo', $stream->getFilename()); |
|
21 |
+ $this->assertEquals('{{ foo }}', $stream->getSource()); |
|
23 | 22 |
} |
24 | 23 |
|
25 | 24 |
public function testNameLabelForTag() |
... | ... |
@@ -27,7 +26,7 @@ class Twig_Tests_LexerTest extends PHPUnit_Framework_TestCase |
27 | 26 |
$template = '{% § %}'; |
28 | 27 |
|
29 | 28 |
$lexer = new Twig_Lexer(new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock())); |
30 |
- $stream = $lexer->tokenize($template); |
|
29 |
+ $stream = $lexer->tokenize(new Twig_Source($template)); |
|
31 | 30 |
|
32 | 31 |
$stream->expect(Twig_Token::BLOCK_START_TYPE); |
33 | 32 |
$this->assertSame('§', $stream->expect(Twig_Token::NAME_TYPE)->getValue()); |
... | ... |
@@ -38,7 +37,7 @@ class Twig_Tests_LexerTest extends PHPUnit_Framework_TestCase |
38 | 37 |
$template = '{{ §() }}'; |
39 | 38 |
|
40 | 39 |
$lexer = new Twig_Lexer(new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock())); |
41 |
- $stream = $lexer->tokenize($template); |
|
40 |
+ $stream = $lexer->tokenize(new Twig_Source($template)); |
|
42 | 41 |
|
43 | 42 |
$stream->expect(Twig_Token::VAR_START_TYPE); |
44 | 43 |
$this->assertSame('§', $stream->expect(Twig_Token::NAME_TYPE)->getValue()); |
... | ... |
@@ -55,7 +54,7 @@ class Twig_Tests_LexerTest extends PHPUnit_Framework_TestCase |
55 | 54 |
protected function countToken($template, $type, $value = null) |
56 | 55 |
{ |
57 | 56 |
$lexer = new Twig_Lexer(new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock())); |
58 |
- $stream = $lexer->tokenize($template); |
|
57 |
+ $stream = $lexer->tokenize(new Twig_Source($template)); |
|
59 | 58 |
|
60 | 59 |
$count = 0; |
61 | 60 |
while (!$stream->isEOF()) { |
... | ... |
@@ -80,7 +79,7 @@ class Twig_Tests_LexerTest extends PHPUnit_Framework_TestCase |
80 | 79 |
."}}\n"; |
81 | 80 |
|
82 | 81 |
$lexer = new Twig_Lexer(new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock())); |
83 |
- $stream = $lexer->tokenize($template); |
|
82 |
+ $stream = $lexer->tokenize(new Twig_Source($template)); |
|
84 | 83 |
|
85 | 84 |
// foo\nbar\n |
86 | 85 |
$this->assertSame(1, $stream->expect(Twig_Token::TEXT_TYPE)->getLine()); |
... | ... |
@@ -100,7 +99,7 @@ class Twig_Tests_LexerTest extends PHPUnit_Framework_TestCase |
100 | 99 |
."}}\n"; |
101 | 100 |
|
102 | 101 |
$lexer = new Twig_Lexer(new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock())); |
103 |
- $stream = $lexer->tokenize($template); |
|
102 |
+ $stream = $lexer->tokenize(new Twig_Source($template)); |
|
104 | 103 |
|
105 | 104 |
// foo\nbar |
106 | 105 |
$this->assertSame(1, $stream->expect(Twig_Token::TEXT_TYPE)->getLine()); |
... | ... |
@@ -115,7 +114,7 @@ class Twig_Tests_LexerTest extends PHPUnit_Framework_TestCase |
115 | 114 |
$template = '{# '.str_repeat('*', 100000).' #}'; |
116 | 115 |
|
117 | 116 |
$lexer = new Twig_Lexer(new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock())); |
118 |
- $lexer->tokenize($template); |
|
117 |
+ $lexer->tokenize(new Twig_Source($template)); |
|
119 | 118 |
|
120 | 119 |
// should not throw an exception |
121 | 120 |
} |
... | ... |
@@ -125,7 +124,7 @@ class Twig_Tests_LexerTest extends PHPUnit_Framework_TestCase |
125 | 124 |
$template = '{% verbatim %}'.str_repeat('*', 100000).'{% endverbatim %}'; |
126 | 125 |
|
127 | 126 |
$lexer = new Twig_Lexer(new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock())); |
128 |
- $lexer->tokenize($template); |
|
127 |
+ $lexer->tokenize(new Twig_Source($template)); |
|
129 | 128 |
|
130 | 129 |
// should not throw an exception |
131 | 130 |
} |
... | ... |
@@ -135,7 +134,7 @@ class Twig_Tests_LexerTest extends PHPUnit_Framework_TestCase |
135 | 134 |
$template = '{{ '.str_repeat('x', 100000).' }}'; |
136 | 135 |
|
137 | 136 |
$lexer = new Twig_Lexer(new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock())); |
138 |
- $lexer->tokenize($template); |
|
137 |
+ $lexer->tokenize(new Twig_Source($template)); |
|
139 | 138 |
|
140 | 139 |
// should not throw an exception |
141 | 140 |
} |
... | ... |
@@ -145,7 +144,7 @@ class Twig_Tests_LexerTest extends PHPUnit_Framework_TestCase |
145 | 144 |
$template = '{% '.str_repeat('x', 100000).' %}'; |
146 | 145 |
|
147 | 146 |
$lexer = new Twig_Lexer(new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock())); |
148 |
- $lexer->tokenize($template); |
|
147 |
+ $lexer->tokenize(new Twig_Source($template)); |
|
149 | 148 |
|
150 | 149 |
// should not throw an exception |
151 | 150 |
} |
... | ... |
@@ -155,7 +154,7 @@ class Twig_Tests_LexerTest extends PHPUnit_Framework_TestCase |
155 | 154 |
$template = '{{ 922337203685477580700 }}'; |
156 | 155 |
|
157 | 156 |
$lexer = new Twig_Lexer(new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock())); |
158 |
- $stream = $lexer->tokenize($template); |
|
157 |
+ $stream = $lexer->tokenize(new Twig_Source($template)); |
|
159 | 158 |
$stream->next(); |
160 | 159 |
$node = $stream->next(); |
161 | 160 |
$this->assertEquals('922337203685477580700', $node->getValue()); |
... | ... |
@@ -170,7 +169,7 @@ class Twig_Tests_LexerTest extends PHPUnit_Framework_TestCase |
170 | 169 |
|
171 | 170 |
$lexer = new Twig_Lexer(new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock())); |
172 | 171 |
foreach ($tests as $template => $expected) { |
173 |
- $stream = $lexer->tokenize($template); |
|
172 |
+ $stream = $lexer->tokenize(new Twig_Source($template)); |
|
174 | 173 |
$stream->expect(Twig_Token::VAR_START_TYPE); |
175 | 174 |
$stream->expect(Twig_Token::STRING_TYPE, $expected); |
176 | 175 |
} |
... | ... |
@@ -181,7 +180,7 @@ class Twig_Tests_LexerTest extends PHPUnit_Framework_TestCase |
181 | 180 |
$template = 'foo {{ "bar #{ baz + 1 }" }}'; |
182 | 181 |
|
183 | 182 |
$lexer = new Twig_Lexer(new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock())); |
184 |
- $stream = $lexer->tokenize($template); |
|
183 |
+ $stream = $lexer->tokenize(new Twig_Source($template)); |
|
185 | 184 |
$stream->expect(Twig_Token::TEXT_TYPE, 'foo '); |
186 | 185 |
$stream->expect(Twig_Token::VAR_START_TYPE); |
187 | 186 |
$stream->expect(Twig_Token::STRING_TYPE, 'bar '); |
... | ... |
@@ -198,7 +197,7 @@ class Twig_Tests_LexerTest extends PHPUnit_Framework_TestCase |
198 | 197 |
$template = '{{ "bar \#{baz+1}" }}'; |
199 | 198 |
|
200 | 199 |
$lexer = new Twig_Lexer(new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock())); |
201 |
- $stream = $lexer->tokenize($template); |
|
200 |
+ $stream = $lexer->tokenize(new Twig_Source($template)); |
|
202 | 201 |
$stream->expect(Twig_Token::VAR_START_TYPE); |
203 | 202 |
$stream->expect(Twig_Token::STRING_TYPE, 'bar #{baz+1}'); |
204 | 203 |
$stream->expect(Twig_Token::VAR_END_TYPE); |
... | ... |
@@ -209,7 +208,7 @@ class Twig_Tests_LexerTest extends PHPUnit_Framework_TestCase |
209 | 208 |
$template = '{{ "bar # baz" }}'; |
210 | 209 |
|
211 | 210 |
$lexer = new Twig_Lexer(new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock())); |
212 |
- $stream = $lexer->tokenize($template); |
|
211 |
+ $stream = $lexer->tokenize(new Twig_Source($template)); |
|
213 | 212 |
$stream->expect(Twig_Token::VAR_START_TYPE); |
214 | 213 |
$stream->expect(Twig_Token::STRING_TYPE, 'bar # baz'); |
215 | 214 |
$stream->expect(Twig_Token::VAR_END_TYPE); |
... | ... |
@@ -224,7 +223,7 @@ class Twig_Tests_LexerTest extends PHPUnit_Framework_TestCase |
224 | 223 |
$template = '{{ "bar #{x" }}'; |
225 | 224 |
|
226 | 225 |
$lexer = new Twig_Lexer(new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock())); |
227 |
- $lexer->tokenize($template); |
|
226 |
+ $lexer->tokenize(new Twig_Source($template)); |
|
228 | 227 |
} |
229 | 228 |
|
230 | 229 |
public function testStringWithNestedInterpolations() |
... | ... |
@@ -232,7 +231,7 @@ class Twig_Tests_LexerTest extends PHPUnit_Framework_TestCase |
232 | 231 |
$template = '{{ "bar #{ "foo#{bar}" }" }}'; |
233 | 232 |
|
234 | 233 |
$lexer = new Twig_Lexer(new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock())); |
235 |
- $stream = $lexer->tokenize($template); |
|
234 |
+ $stream = $lexer->tokenize(new Twig_Source($template)); |
|
236 | 235 |
$stream->expect(Twig_Token::VAR_START_TYPE); |
237 | 236 |
$stream->expect(Twig_Token::STRING_TYPE, 'bar '); |
238 | 237 |
$stream->expect(Twig_Token::INTERPOLATION_START_TYPE); |
... | ... |
@@ -249,7 +248,7 @@ class Twig_Tests_LexerTest extends PHPUnit_Framework_TestCase |
249 | 248 |
$template = '{% foo "bar #{ "foo#{bar}" }" %}'; |
250 | 249 |
|
251 | 250 |
$lexer = new Twig_Lexer(new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock())); |
252 |
- $stream = $lexer->tokenize($template); |
|
251 |
+ $stream = $lexer->tokenize(new Twig_Source($template)); |
|
253 | 252 |
$stream->expect(Twig_Token::BLOCK_START_TYPE); |
254 | 253 |
$stream->expect(Twig_Token::NAME_TYPE, 'foo'); |
255 | 254 |
$stream->expect(Twig_Token::STRING_TYPE, 'bar '); |
... | ... |
@@ -267,7 +266,7 @@ class Twig_Tests_LexerTest extends PHPUnit_Framework_TestCase |
267 | 266 |
$template = "{{ 1 and\n0}}"; |
268 | 267 |
|
269 | 268 |
$lexer = new Twig_Lexer(new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock())); |
270 |
- $stream = $lexer->tokenize($template); |
|
269 |
+ $stream = $lexer->tokenize(new Twig_Source($template)); |
|
271 | 270 |
$stream->expect(Twig_Token::VAR_START_TYPE); |
272 | 271 |
$stream->expect(Twig_Token::NUMBER_TYPE, 1); |
273 | 272 |
$stream->expect(Twig_Token::OPERATOR_TYPE, 'and'); |
... | ... |
@@ -289,7 +288,7 @@ bar |
289 | 288 |
'; |
290 | 289 |
|
291 | 290 |
$lexer = new Twig_Lexer(new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock())); |
292 |
- $lexer->tokenize($template); |
|
291 |
+ $lexer->tokenize(new Twig_Source($template)); |
|
293 | 292 |
} |
294 | 293 |
|
295 | 294 |
/** |
... | ... |
@@ -308,6 +307,6 @@ bar |
308 | 307 |
'; |
309 | 308 |
|
310 | 309 |
$lexer = new Twig_Lexer(new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock())); |
311 |
- $lexer->tokenize($template); |
|
310 |
+ $lexer->tokenize(new Twig_Source($template)); |
|
312 | 311 |
} |
313 | 312 |
} |
... | ... |
@@ -22,6 +22,21 @@ class Twig_Tests_Loader_ChainTest extends PHPUnit_Framework_TestCase |
22 | 22 |
$this->assertEquals('foo', $loader->getSource('bar')); |
23 | 23 |
} |
24 | 24 |
|
25 |
+ public function testGetSourceContext() |
|
26 |
+ { |
|
27 |
+ $path = dirname(__FILE__).'/../Fixtures'; |
|
28 |
+ $loader = new Twig_Loader_Chain(array( |
|
29 |
+ new Twig_Loader_Array(array('foo' => 'bar')), |
|
30 |
+ new Twig_Loader_Filesystem(array($path)), |
|
31 |
+ )); |
|
32 |
+ |
|
33 |
+ $this->assertEquals('foo', $loader->getSourceContext('foo')->getName()); |
|
34 |
+ $this->assertNull($loader->getSourceContext('foo')->getPath()); |
|
35 |
+ |
|
36 |
+ $this->assertEquals('errors/index.html', $loader->getSourceContext('errors/index.html')->getName()); |
|
37 |
+ $this->assertEquals(realpath($path.'/errors/index.html'), realpath($loader->getSourceContext('errors/index.html')->getPath())); |
|
38 |
+ } |
|
39 |
+ |
|
25 | 40 |
/** |
26 | 41 |
* @expectedException Twig_Error_Loader |
27 | 42 |
*/ |
... | ... |
@@ -11,6 +11,14 @@ |
11 | 11 |
|
12 | 12 |
class Twig_Tests_Loader_FilesystemTest extends PHPUnit_Framework_TestCase |
13 | 13 |
{ |
14 |
+ public function testGetSourceContext() |
|
15 |
+ { |
|
16 |
+ $path = dirname(__FILE__).'/../Fixtures'; |
|
17 |
+ $loader = new Twig_Loader_Filesystem(array($path)); |
|
18 |
+ $this->assertEquals('errors/index.html', $loader->getSourceContext('errors/index.html')->getName()); |
|
19 |
+ $this->assertEquals(realpath($path.'/errors/index.html'), realpath($loader->getSourceContext('errors/index.html')->getPath())); |
|
20 |
+ } |
|
21 |
+ |
|
14 | 22 |
/** |
15 | 23 |
* @dataProvider getSecurityTests |
16 | 24 |
*/ |
... | ... |
@@ -18,14 +18,14 @@ class Twig_Tests_Node_ModuleTest extends Twig_Test_NodeTestCase |
18 | 18 |
$blocks = new Twig_Node(); |
19 | 19 |
$macros = new Twig_Node(); |
20 | 20 |
$traits = new Twig_Node(); |
21 |
- $filename = 'foo.twig'; |
|
22 |
- $node = new Twig_Node_Module($body, $parent, $blocks, $macros, $traits, new Twig_Node(array()), $filename); |
|
21 |
+ $source = new Twig_Source('{{ foo }}', 'foo.twig'); |
|
22 |
+ $node = new Twig_Node_Module($body, $parent, $blocks, $macros, $traits, new Twig_Node(array()), $source); |
|
23 | 23 |
|
24 | 24 |
$this->assertEquals($body, $node->getNode('body')); |
25 | 25 |
$this->assertEquals($blocks, $node->getNode('blocks')); |
26 | 26 |
$this->assertEquals($macros, $node->getNode('macros')); |
27 | 27 |
$this->assertEquals($parent, $node->getNode('parent')); |
28 |
- $this->assertEquals($filename, $node->getAttribute('filename')); |
|
28 |
+ $this->assertEquals($source->getName(), $node->getAttribute('name')); |
|
29 | 29 |
} |
30 | 30 |
|
31 | 31 |
public function getTests() |
... | ... |
@@ -39,9 +39,9 @@ class Twig_Tests_Node_ModuleTest extends Twig_Test_NodeTestCase |
39 | 39 |
$blocks = new Twig_Node(); |
40 | 40 |
$macros = new Twig_Node(); |
41 | 41 |
$traits = new Twig_Node(); |
42 |
- $filename = 'foo.twig'; |
|
42 |
+ $source = new Twig_Source('{{ foo }}', 'foo.twig'); |
|
43 | 43 |
|
44 |
- $node = new Twig_Node_Module($body, $extends, $blocks, $macros, $traits, new Twig_Node(array()), $filename); |
|
44 |
+ $node = new Twig_Node_Module($body, $extends, $blocks, $macros, $traits, new Twig_Node(array()), $source); |
|
45 | 45 |
$tests[] = array($node, <<<EOF |
46 | 46 |
<?php |
47 | 47 |
|
... | ... |
@@ -78,6 +78,11 @@ class __TwigTemplate_%x extends Twig_Template |
78 | 78 |
{ |
79 | 79 |
return ""; |
80 | 80 |
} |
81 |
+ |
|
82 |
+ public function getSourceContext() |
|
83 |
+ { |
|
84 |
+ return new Twig_Source("", "foo.twig", ""); |
|
85 |
+ } |
|
81 | 86 |
} |
82 | 87 |
EOF |
83 | 88 |
, $twig, true); |
... | ... |
@@ -87,7 +92,7 @@ EOF |
87 | 92 |
$body = new Twig_Node(array($import)); |
88 | 93 |
$extends = new Twig_Node_Expression_Constant('layout.twig', 1); |
89 | 94 |
|
90 |
- $node = new Twig_Node_Module($body, $extends, $blocks, $macros, $traits, new Twig_Node(array()), $filename); |
|
95 |
+ $node = new Twig_Node_Module($body, $extends, $blocks, $macros, $traits, new Twig_Node(array()), $source); |
|
91 | 96 |
$tests[] = array($node, <<<EOF |
92 | 97 |
<?php |
93 | 98 |
|
... | ... |
@@ -136,6 +141,11 @@ class __TwigTemplate_%x extends Twig_Template |
136 | 141 |
{ |
137 | 142 |
return ""; |
138 | 143 |
} |
144 |
+ |
|
145 |
+ public function getSourceContext() |
|
146 |
+ { |
|
147 |
+ return new Twig_Source("", "foo.twig", ""); |
|
148 |
+ } |
|
139 | 149 |
} |
140 | 150 |
EOF |
141 | 151 |
, $twig, true); |
... | ... |
@@ -149,7 +159,8 @@ EOF |
149 | 159 |
2 |
150 | 160 |
); |
151 | 161 |
|
152 |
- $node = new Twig_Node_Module($body, $extends, $blocks, $macros, $traits, new Twig_Node(array()), $filename, '{{ foo }}'); |
|
162 |
+ $twig = new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock(), array('debug' => true)); |
|
163 |
+ $node = new Twig_Node_Module($body, $extends, $blocks, $macros, $traits, new Twig_Node(array()), $source); |
|
153 | 164 |
$tests[] = array($node, <<<EOF |
154 | 165 |
<?php |
155 | 166 |
|
... | ... |
@@ -189,6 +200,11 @@ class __TwigTemplate_%x extends Twig_Template |
189 | 200 |
{ |
190 | 201 |
return "{{ foo }}"; |
191 | 202 |
} |
203 |
+ |
|
204 |
+ public function getSourceContext() |
|
205 |
+ { |
|
206 |
+ return new Twig_Source("{{ foo }}", "foo.twig", ""); |
|
207 |
+ } |
|
192 | 208 |
} |
193 | 209 |
EOF |
194 | 210 |
, $twig, true); |
... | ... |
@@ -14,7 +14,7 @@ class Twig_Tests_NodeVisitor_OptimizerTest extends PHPUnit_Framework_TestCase |
14 | 14 |
{ |
15 | 15 |
$env = new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock(), array('cache' => false, 'autoescape' => false)); |
16 | 16 |
|
17 |
- $stream = $env->parse($env->tokenize('{{ block("foo") }}', 'index')); |
|
17 |
+ $stream = $env->parse($env->tokenize(new Twig_Source('{{ block("foo") }}', 'index'))); |
|
18 | 18 |
|
19 | 19 |
$node = $stream->getNode('body')->getNode(0); |
20 | 20 |
|
... | ... |
@@ -26,7 +26,7 @@ class Twig_Tests_NodeVisitor_OptimizerTest extends PHPUnit_Framework_TestCase |
26 | 26 |
{ |
27 | 27 |
$env = new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock(), array('cache' => false, 'autoescape' => false)); |
28 | 28 |
|
29 |
- $stream = $env->parse($env->tokenize('{% extends "foo" %}{% block content %}{{ parent() }}{% endblock %}', 'index')); |
|
29 |
+ $stream = $env->parse($env->tokenize(new Twig_Source('{% extends "foo" %}{% block content %}{{ parent() }}{% endblock %}', 'index'))); |
|
30 | 30 |
|
31 | 31 |
$node = $stream->getNode('blocks')->getNode('content')->getNode(0)->getNode('body'); |
32 | 32 |
|
... | ... |
@@ -41,7 +41,7 @@ class Twig_Tests_NodeVisitor_OptimizerTest extends PHPUnit_Framework_TestCase |
41 | 41 |
{ |
42 | 42 |
$env = new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock(), array('cache' => false)); |
43 | 43 |
|
44 |
- $stream = $env->parse($env->tokenize($template, 'index')); |
|
44 |
+ $stream = $env->parse($env->tokenize(new Twig_Source($template, 'index'))); |
|
45 | 45 |
|
46 | 46 |
foreach ($expected as $target => $withLoop) { |
47 | 47 |
$this->assertTrue($this->checkForConfiguration($stream, $target, $withLoop), sprintf('variable %s is %soptimized', $target, $withLoop ? 'not ' : '')); |
... | ... |
@@ -140,23 +140,27 @@ class Twig_Tests_ParserTest extends PHPUnit_Framework_TestCase |
140 | 140 |
'optimizations' => 0, |
141 | 141 |
)); |
142 | 142 |
|
143 |
- $twig->parse($twig->tokenize(<<<EOF |
|
143 |
+ $twig->parse($twig->tokenize(new Twig_Source(<<<EOF |
|
144 | 144 |
{% from _self import foo %} |
145 | 145 |
|
146 | 146 |
{% macro foo() %} |
147 | 147 |
{{ foo }} |
148 | 148 |
{% endmacro %} |
149 | 149 |
EOF |
150 |
- )); |
|
150 |
+ ))); |
|
151 | 151 |
} |
152 | 152 |
|
153 | 153 |
protected function getParser() |
154 | 154 |
{ |
155 | 155 |
$parser = new Twig_Parser(new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock())); |
156 | 156 |
$parser->setParent(new Twig_Node()); |
157 |
+ |
|
158 |
+ $stream = $this->getMockBuilder('Twig_TokenStream')->disableOriginalConstructor()->getMock(); |
|
159 |
+ $stream->expects($this->any())->method('getSourceContext')->will($this->returnValue(new Twig_Source(''))); |
|
160 |
+ |
|
157 | 161 |
$p = new ReflectionProperty($parser, 'stream'); |
158 | 162 |
$p->setAccessible(true); |
159 |
- $p->setValue($parser, $this->getMockBuilder('Twig_TokenStream')->disableOriginalConstructor()->getMock()); |
|
163 |
+ $p->setValue($parser, $stream); |
|
160 | 164 |
|
161 | 165 |
return $parser; |
162 | 166 |
} |
... | ... |
@@ -27,6 +27,18 @@ class Twig_Tests_TokenStreamTest extends PHPUnit_Framework_TestCase |
27 | 27 |
); |
28 | 28 |
} |
29 | 29 |
|
30 |
+ /** |
|
31 |
+ * @group legacy |
|
32 |
+ */ |
|
33 |
+ public function testLegacyConstructorSignature() |
|
34 |
+ { |
|
35 |
+ $stream = new Twig_TokenStream(array(), 'foo', '{{ foo }}'); |
|
36 |
+ $this->assertEquals('foo', $stream->getFilename()); |
|
37 |
+ $this->assertEquals('{{ foo }}', $stream->getSource()); |
|
38 |
+ $this->assertEquals('foo', $stream->getSourceContext()->getName()); |
|
39 |
+ $this->assertEquals('{{ foo }}', $stream->getSourceContext()->getCode()); |
|
40 |
+ } |
|
41 |
+ |
|
30 | 42 |
public function testNext() |
31 | 43 |
{ |
32 |