diff --git a/CHANGELOG b/CHANGELOG index 341a6dcf9..b4e77c597 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,5 +1,6 @@ * 1.25.0 (2016-XX-XX) + * changed the way we store template source in template classes * removed usage of realpath in cache keys * fixed Twig cache sharing when used with different versions of PHP * removed embed parent workaround for simple use cases diff --git a/lib/Twig/Environment.php b/lib/Twig/Environment.php index bcddf90d6..c0450aa88 100644 --- a/lib/Twig/Environment.php +++ b/lib/Twig/Environment.php @@ -693,13 +693,7 @@ class Twig_Environment public function compileSource($source, $name = null) { try { - $compiled = $this->compile($this->parse($this->tokenize($source, $name))); - - if (isset($source[0])) { - $compiled .= '/* '.str_replace(array('*/', "\r\n", "\r", "\n"), array('*//* ', "\n", "\n", "*/\n/* "), $source)."*/\n"; - } - - return $compiled; + return $this->compile($this->parse($this->tokenize($source, $name))); } catch (Twig_Error $e) { $e->setTemplateFile($name); throw $e; diff --git a/lib/Twig/Lexer.php b/lib/Twig/Lexer.php index dd7987385..20d1138aa 100644 --- a/lib/Twig/Lexer.php +++ b/lib/Twig/Lexer.php @@ -136,7 +136,7 @@ class Twig_Lexer implements Twig_LexerInterface mb_internal_encoding($mbEncoding); } - return new Twig_TokenStream($this->tokens, $this->filename); + return new Twig_TokenStream($this->tokens, $this->filename, $code); } protected function lexData() diff --git a/lib/Twig/Node/Module.php b/lib/Twig/Node/Module.php index c50d0e5ba..a80ab353c 100644 --- a/lib/Twig/Node/Module.php +++ b/lib/Twig/Node/Module.php @@ -21,7 +21,7 @@ */ class Twig_Node_Module extends Twig_Node { - public function __construct(Twig_NodeInterface $body, Twig_Node_Expression $parent = null, Twig_NodeInterface $blocks, Twig_NodeInterface $macros, Twig_NodeInterface $traits, $embeddedTemplates, $filename) + public function __construct(Twig_NodeInterface $body, Twig_Node_Expression $parent = null, Twig_NodeInterface $blocks, Twig_NodeInterface $macros, Twig_NodeInterface $traits, $embeddedTemplates, $filename, $source = '') { $nodes = array( 'body' => $body, @@ -40,6 +40,7 @@ class Twig_Node_Module extends Twig_Node // embedded templates are set as attributes so that they are only visited once by the visitors parent::__construct($nodes, array( + 'source' => $source, 'filename' => $filename, 'index' => null, 'embedded_templates' => $embeddedTemplates, @@ -93,6 +94,8 @@ class Twig_Node_Module extends Twig_Node $this->compileDebugInfo($compiler); + $this->compileGetSource($compiler); + $this->compileClassFooter($compiler); } @@ -386,6 +389,19 @@ class Twig_Node_Module extends Twig_Node ->indent() ->write(sprintf("return %s;\n", str_replace("\n", '', var_export(array_reverse($compiler->getDebugInfo(), true), true)))) ->outdent() + ->write("}\n\n") + ; + } + + protected function compileGetSource(Twig_Compiler $compiler) + { + $compiler + ->write("public function getSource()\n", "{\n") + ->indent() + ->write('return ') + ->string($this->getAttribute('source')) + ->raw(";\n") + ->outdent() ->write("}\n") ; } diff --git a/lib/Twig/Parser.php b/lib/Twig/Parser.php index 4628d67df..86bd494f0 100644 --- a/lib/Twig/Parser.php +++ b/lib/Twig/Parser.php @@ -114,7 +114,7 @@ class Twig_Parser implements Twig_ParserInterface throw $e; } - $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()); + $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(), $stream->getSource()); $traverser = new Twig_NodeTraverser($this->env, $this->visitors); diff --git a/lib/Twig/Template.php b/lib/Twig/Template.php index d64cfeb20..25633c841 100644 --- a/lib/Twig/Template.php +++ b/lib/Twig/Template.php @@ -51,6 +51,13 @@ abstract class Twig_Template implements Twig_TemplateInterface */ abstract public function getDebugInfo(); + /** + * Returns the template source code. + * + * @return string The template source code + */ + abstract public function getSource(); + /** * @deprecated since 1.20 (to be removed in 2.0) */ @@ -329,33 +336,6 @@ abstract class Twig_Template implements Twig_TemplateInterface return $this->blocks; } - /** - * Returns the template source code. - * - * @return string|null The template source code or null if it is not available - */ - public function getSource() - { - $reflector = new ReflectionClass($this); - $file = $reflector->getFileName(); - - if (!file_exists($file)) { - return; - } - - $source = file($file, FILE_IGNORE_NEW_LINES); - array_splice($source, 0, $reflector->getEndLine()); - - $i = 0; - while (isset($source[$i]) && '/* */' === substr_replace($source[$i], '', 3, -2)) { - $source[$i] = str_replace('*//* ', '*/', substr($source[$i], 3, -2)); - ++$i; - } - array_splice($source, $i); - - return implode("\n", $source); - } - /** * {@inheritdoc} */ diff --git a/lib/Twig/TokenStream.php b/lib/Twig/TokenStream.php index d73229428..cc6bc8050 100644 --- a/lib/Twig/TokenStream.php +++ b/lib/Twig/TokenStream.php @@ -21,16 +21,20 @@ class Twig_TokenStream protected $current = 0; protected $filename; + private $source; + /** * Constructor. * * @param array $tokens An array of tokens * @param string $filename|null The name of the filename which tokens are associated with + * @param string $source|null The source code associated with the tokens */ - public function __construct(array $tokens, $filename = null) + public function __construct(array $tokens, $filename = null, $source = null) { $this->tokens = $tokens; $this->filename = $filename; + $this->source = $source ? $source : ''; } /** @@ -152,4 +156,14 @@ class Twig_TokenStream { return $this->filename; } + + /** + * Gets the source code associated with this stream. + * + * @return string + */ + public function getSource() + { + return $this->source; + } } diff --git a/test/Twig/Tests/EnvironmentTest.php b/test/Twig/Tests/EnvironmentTest.php index 2e514ed52..d72db230c 100644 --- a/test/Twig/Tests/EnvironmentTest.php +++ b/test/Twig/Tests/EnvironmentTest.php @@ -143,18 +143,6 @@ class Twig_Tests_EnvironmentTest extends PHPUnit_Framework_TestCase */ } - public function testCompileSourceInlinesSource() - { - $twig = new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock()); - - $source = "\r\nbar\n"; - $expected = "/* */\n/* bar*/\n/* */\n"; - $compiled = $twig->compileSource($source, 'index'); - - $this->assertContains($expected, $compiled); - $this->assertNotContains('/**', $compiled); - } - public function testExtensionsAreNotInitializedWhenRenderingACompiledTemplate() { $cache = new Twig_Cache_Filesystem($dir = sys_get_temp_dir().'/twig'); diff --git a/test/Twig/Tests/Node/ModuleTest.php b/test/Twig/Tests/Node/ModuleTest.php index 3625f63fc..10cf93be8 100644 --- a/test/Twig/Tests/Node/ModuleTest.php +++ b/test/Twig/Tests/Node/ModuleTest.php @@ -73,6 +73,11 @@ class __TwigTemplate_%x extends Twig_Template { return array ( 19 => 1,); } + + public function getSource() + { + return ""; + } } EOF , $twig, true); @@ -126,6 +131,11 @@ class __TwigTemplate_%x extends Twig_Template { return array ( 26 => 1, 24 => 2, 11 => 1,); } + + public function getSource() + { + return ""; + } } EOF , $twig, true); @@ -139,7 +149,7 @@ EOF 2 ); - $node = new Twig_Node_Module($body, $extends, $blocks, $macros, $traits, new Twig_Node(array()), $filename); + $node = new Twig_Node_Module($body, $extends, $blocks, $macros, $traits, new Twig_Node(array()), $filename, '{{ foo }}'); $tests[] = array($node, << 2, 15 => 4, 9 => 2,); } + + public function getSource() + { + return "{{ foo }}"; + } } EOF , $twig, true); diff --git a/test/Twig/Tests/TemplateTest.php b/test/Twig/Tests/TemplateTest.php index 15adaf7cb..80412c9f9 100644 --- a/test/Twig/Tests/TemplateTest.php +++ b/test/Twig/Tests/TemplateTest.php @@ -84,13 +84,6 @@ class Twig_Tests_TemplateTest extends PHPUnit_Framework_TestCase return $tests; } - public function testGetSource() - { - $template = new Twig_TemplateTest(new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock()), false); - - $this->assertSame("\n", $template->getSource()); - } - /** * @dataProvider getGetAttributeWithSandbox */ @@ -453,6 +446,11 @@ class Twig_TemplateTest extends Twig_Template return array(); } + public function getSource() + { + return ''; + } + protected function doGetParent(array $context) { } @@ -470,8 +468,6 @@ class Twig_TemplateTest extends Twig_Template } } } -/* */ -/* */ class Twig_TemplateArrayAccessObject implements ArrayAccess {