From: Fabien Potencier Date: Thu, 27 Dec 2012 08:44:14 +0000 (+0100) Subject: changed the way globals behave to be more BC with 1.11 and to avoid speed problems... X-Git-Url: http://git.silmor.de/gitweb/?a=commitdiff_plain;h=2450f79a0efccc65cd7c2d7c338d6c4e36c9da35;p=konrad%2Ftwig.git changed the way globals behave to be more BC with 1.11 and to avoid speed problems at runtime introduced in 4487387 (closes #932) * Globals are now managed by themselves, independently of other elements contained in extensions * A global variable value can now be changed after the runtime has been initialized (to be more BC with the way Twig 1.11 works) * Extensions are not initialized anymore when rendering a template that is already in the cache (like in Twig 1.11) --- diff --git a/lib/Twig/Environment.php b/lib/Twig/Environment.php index 9958573..d8e700e 100644 --- a/lib/Twig/Environment.php +++ b/lib/Twig/Environment.php @@ -964,16 +964,24 @@ class Twig_Environment /** * Registers a Global. * + * New globals can be added before compiling or rendering a template; + * but after, you can only update existing globals. + * * @param string $name The global name * @param mixed $value The global value */ public function addGlobal($name, $value) { - if ($this->extensionInitialized) { - throw new LogicException(sprintf('Unable to add global "%s" as extensions have already been initialized.', $name)); + if (($this->extensionInitialized || $this->runtimeInitialized) && !array_key_exists($name, $this->globals)) { + throw new LogicException(sprintf('Unable to add global "%s" as the runtime or the extensions have already been initialized.', $name)); } - $this->staging->addGlobal($name, $value); + if ($this->extensionInitialized || $this->runtimeInitialized) { + // update the value + $this->globals[$name] = $value; + } else { + $this->staging->addGlobal($name, $value); + } } /** @@ -983,8 +991,8 @@ class Twig_Environment */ public function getGlobals() { - if (!$this->extensionInitialized) { - $this->initExtensions(); + if (null === $this->globals || !($this->runtimeInitialized || $this->extensionInitialized)) { + $this->initGlobals(); } return $this->globals; @@ -1052,6 +1060,15 @@ class Twig_Environment return array_keys($alternatives); } + protected function initGlobals() + { + $this->globals = array(); + foreach ($this->extensions as $extension) { + $this->globals = array_merge($this->globals, $extension->getGlobals()); + } + $this->globals = array_merge($this->globals, $this->staging->getGlobals()); + } + protected function initExtensions() { if ($this->extensionInitialized) { @@ -1063,7 +1080,6 @@ class Twig_Environment $this->filters = array(); $this->functions = array(); $this->tests = array(); - $this->globals = array(); $this->visitors = array(); $this->unaryOperators = array(); $this->binaryOperators = array(); @@ -1112,9 +1128,6 @@ class Twig_Environment $this->tests[$name] = $test; } - // globals - $this->globals = array_merge($this->globals, $extension->getGlobals()); - // token parsers foreach ($extension->getTokenParsers() as $parser) { if ($parser instanceof Twig_TokenParserInterface) { diff --git a/test/Twig/Tests/EnvironmentTest.php b/test/Twig/Tests/EnvironmentTest.php index 72a9025..76f787d 100644 --- a/test/Twig/Tests/EnvironmentTest.php +++ b/test/Twig/Tests/EnvironmentTest.php @@ -33,6 +33,111 @@ class Twig_Tests_EnvironmentTest extends PHPUnit_Framework_TestCase return $filename; } + public function testGlobals() + { + // globals can be added after calling getGlobals + $twig = new Twig_Environment(new Twig_Loader_String()); + $twig->addGlobal('foo', 'foo'); + $globals = $twig->getGlobals(); + $twig->addGlobal('foo', 'bar'); + $globals = $twig->getGlobals(); + $this->assertEquals('bar', $globals['foo']); + + // globals can be modified after runtime init + $twig = new Twig_Environment(new Twig_Loader_String()); + $twig->addGlobal('foo', 'foo'); + $globals = $twig->getGlobals(); + $twig->initRuntime(); + $twig->addGlobal('foo', 'bar'); + $globals = $twig->getGlobals(); + $this->assertEquals('bar', $globals['foo']); + + // globals can be modified after extensions init + $twig = new Twig_Environment(new Twig_Loader_String()); + $twig->addGlobal('foo', 'foo'); + $globals = $twig->getGlobals(); + $twig->getFunctions(); + $twig->addGlobal('foo', 'bar'); + $globals = $twig->getGlobals(); + $this->assertEquals('bar', $globals['foo']); + + // globals can be modified after extensions and runtime init + $twig = new Twig_Environment(new Twig_Loader_String()); + $twig->addGlobal('foo', 'foo'); + $globals = $twig->getGlobals(); + $twig->getFunctions(); + $twig->initRuntime(); + $twig->addGlobal('foo', 'bar'); + $globals = $twig->getGlobals(); + $this->assertEquals('bar', $globals['foo']); + + // globals cannot be added after runtime init + $twig = new Twig_Environment(new Twig_Loader_String()); + $twig->addGlobal('foo', 'foo'); + $globals = $twig->getGlobals(); + $twig->initRuntime(); + try { + $twig->addGlobal('bar', 'bar'); + $this->fail(); + } catch (LogicException $e) { + $this->assertFalse(array_key_exists('bar', $twig->getGlobals())); + } + + // globals cannot be added after extensions init + $twig = new Twig_Environment(new Twig_Loader_String()); + $twig->addGlobal('foo', 'foo'); + $globals = $twig->getGlobals(); + $twig->getFunctions(); + try { + $twig->addGlobal('bar', 'bar'); + $this->fail(); + } catch (LogicException $e) { + $this->assertFalse(array_key_exists('bar', $twig->getGlobals())); + } + + // globals cannot be added after extensions and runtime init + $twig = new Twig_Environment(new Twig_Loader_String()); + $twig->addGlobal('foo', 'foo'); + $globals = $twig->getGlobals(); + $twig->getFunctions(); + $twig->initRuntime(); + try { + $twig->addGlobal('bar', 'bar'); + $this->fail(); + } catch (LogicException $e) { + $this->assertFalse(array_key_exists('bar', $twig->getGlobals())); + } + } + + public function testExtensionsAreNotInitializedWhenRenderingACompiledTemplate() + { + $options = array('cache' => sys_get_temp_dir().'/twig', 'auto_reload' => false, 'debug' => false); + + // force compilation + $twig = new Twig_Environment(new Twig_Loader_String(), $options); + $cache = $twig->getCacheFilename('{{ foo }}'); + if (!is_dir(dirname($cache))) { + mkdir(dirname($cache), 0777, true); + } + file_put_contents($cache, $twig->compileSource('{{ foo }}', '{{ foo }}')); + + // check that extensions won't be initialized when rendering a template that is already in the cache + $twig = $this + ->getMockBuilder('Twig_Environment') + ->setConstructorArgs(array(new Twig_Loader_String(), $options)) + ->setMethods(array('initExtensions')) + ->getMock() + ; + + $twig->expects($this->never())->method('initExtensions'); + + // render template + $output = $twig->render('{{ foo }}', array('foo' => 'bar')); + $this->assertEquals('bar', $output); + + unlink($cache); + } + public function testAddExtension() { $twig = new Twig_Environment(new Twig_Loader_String());