... | ... |
@@ -1,5 +1,6 @@ |
1 | 1 |
* 1.27.0 (2016-XX-XX) |
2 | 2 |
|
3 |
+ * fixed regression when registering two extensions having the same class name |
|
3 | 4 |
* deprecated Twig_LoaderInterface::getSource() (implement Twig_SourceContextLoaderInterface instead) |
4 | 5 |
* fixed the filesystem loader with relative paths |
5 | 6 |
* deprecated Twig_Node::getLine() in favor of Twig_Node::getTemplateLine() |
... | ... |
@@ -49,7 +49,7 @@ class Twig_Environment |
49 | 49 |
private $bcWriteCacheFile = false; |
50 | 50 |
private $bcGetCacheFilename = false; |
51 | 51 |
private $lastModifiedExtension = 0; |
52 |
- private $legacyExtensionNames = array(); |
|
52 |
+ private $extensionsByClass = array(); |
|
53 | 53 |
private $runtimeLoaders = array(); |
54 | 54 |
private $runtimes = array(); |
55 | 55 |
private $optionsHash; |
... | ... |
@@ -816,12 +816,16 @@ class Twig_Environment |
816 | 816 |
*/ |
817 | 817 |
public function hasExtension($class) |
818 | 818 |
{ |
819 |
- if (isset($this->legacyExtensionNames[$class])) { |
|
820 |
- $class = $this->legacyExtensionNames[$class]; |
|
821 |
- @trigger_error(sprintf('Referencing the "%s" extension by its name (defined by getName()) is deprecated since 1.26 and will be removed in Twig 2.0. Use the Fully Qualified Extension Class Name instead.', $class), E_USER_DEPRECATED); |
|
819 |
+ $class = ltrim($class, '\\'); |
|
820 |
+ if (isset($this->extensions[$class])) { |
|
821 |
+ if ($class !== get_class($this->extensions[$class])) { |
|
822 |
+ @trigger_error(sprintf('Referencing the "%s" extension by its name (defined by getName()) is deprecated since 1.26 and will be removed in Twig 2.0. Use the Fully Qualified Extension Class Name instead.', $class), E_USER_DEPRECATED); |
|
823 |
+ } |
|
824 |
+ |
|
825 |
+ return true; |
|
822 | 826 |
} |
823 | 827 |
|
824 |
- return isset($this->extensions[ltrim($class, '\\')]); |
|
828 |
+ return isset($this->extensionsByClass[ltrim($class, '\\')]); |
|
825 | 829 |
} |
826 | 830 |
|
827 | 831 |
/** |
... | ... |
@@ -841,18 +845,21 @@ class Twig_Environment |
841 | 845 |
*/ |
842 | 846 |
public function getExtension($class) |
843 | 847 |
{ |
844 |
- if (isset($this->legacyExtensionNames[$class])) { |
|
845 |
- $class = $this->legacyExtensionNames[$class]; |
|
846 |
- @trigger_error(sprintf('Referencing the "%s" extension by its name (defined by getName()) is deprecated since 1.26 and will be removed in Twig 2.0. Use the Fully Qualified Extension Class Name instead.', $class), E_USER_DEPRECATED); |
|
847 |
- } |
|
848 |
- |
|
849 | 848 |
$class = ltrim($class, '\\'); |
850 | 849 |
|
851 |
- if (!isset($this->extensions[$class])) { |
|
850 |
+ if (isset($this->extensions[$class])) { |
|
851 |
+ if ($class !== get_class($this->extensions[$class])) { |
|
852 |
+ @trigger_error(sprintf('Referencing the "%s" extension by its name (defined by getName()) is deprecated since 1.26 and will be removed in Twig 2.0. Use the Fully Qualified Extension Class Name instead.', $class), E_USER_DEPRECATED); |
|
853 |
+ } |
|
854 |
+ |
|
855 |
+ return $this->extensions[$class]; |
|
856 |
+ } |
|
857 |
+ |
|
858 |
+ if (!isset($this->extensionsByClass[$class])) { |
|
852 | 859 |
throw new Twig_Error_Runtime(sprintf('The "%s" extension is not enabled.', $class)); |
853 | 860 |
} |
854 | 861 |
|
855 |
- return $this->extensions[$class]; |
|
862 |
+ return $this->extensionsByClass[$class]; |
|
856 | 863 |
} |
857 | 864 |
|
858 | 865 |
/** |
... | ... |
@@ -886,25 +893,21 @@ class Twig_Environment |
886 | 893 |
*/ |
887 | 894 |
public function addExtension(Twig_ExtensionInterface $extension) |
888 | 895 |
{ |
889 |
- $class = get_class($extension); |
|
890 |
- |
|
891 | 896 |
if ($this->extensionInitialized) { |
892 |
- throw new LogicException(sprintf('Unable to register extension "%s" as extensions have already been initialized.', $class)); |
|
897 |
+ throw new LogicException(sprintf('Unable to register extension "%s" as extensions have already been initialized.', $extension->getName())); |
|
893 | 898 |
} |
894 | 899 |
|
895 |
- $m = new ReflectionMethod($extension, 'getName'); |
|
896 |
- $legacyName = 'Twig_Extension' !== $m->getDeclaringClass()->getName() ? $extension->getName() : null; |
|
897 |
- |
|
898 |
- if (isset($this->extensions[$class]) || (null !== $legacyName && isset($this->legacyExtensionNames[$legacyName]))) { |
|
899 |
- unset($this->extensions[$this->legacyExtensionNames[$legacyName]], $this->legacyExtensionNames[$legacyName]); |
|
900 |
- @trigger_error(sprintf('The possibility to register the same extension twice ("%s") is deprecated since version 1.23 and will be removed in Twig 2.0. Use proper PHP inheritance instead.', $class), E_USER_DEPRECATED); |
|
900 |
+ $class = get_class($extension); |
|
901 |
+ if ($class !== $extension->getName()) { |
|
902 |
+ if (isset($this->extensions[$extension->getName()])) { |
|
903 |
+ unset($this->extensions[$extension->getName()], $this->extensionsByClass[$class]); |
|
904 |
+ @trigger_error(sprintf('The possibility to register the same extension twice ("%s") is deprecated since version 1.23 and will be removed in Twig 2.0. Use proper PHP inheritance instead.', $extension->getName()), E_USER_DEPRECATED); |
|
905 |
+ } |
|
901 | 906 |
} |
902 | 907 |
|
903 | 908 |
$this->lastModifiedExtension = 0; |
904 |
- if ($legacyName !== $class) { |
|
905 |
- $this->legacyExtensionNames[$legacyName] = $class; |
|
906 |
- } |
|
907 |
- $this->extensions[$class] = $extension; |
|
909 |
+ $this->extensionsByClass[$class] = $extension; |
|
910 |
+ $this->extensions[$extension->getName()] = $extension; |
|
908 | 911 |
$this->updateOptionsHash(); |
909 | 912 |
} |
910 | 913 |
|
... | ... |
@@ -921,16 +924,20 @@ class Twig_Environment |
921 | 924 |
{ |
922 | 925 |
@trigger_error(sprintf('The %s method is deprecated since version 1.12 and will be removed in Twig 2.0.', __METHOD__), E_USER_DEPRECATED); |
923 | 926 |
|
924 |
- if (isset($this->legacyExtensionNames[$name])) { |
|
925 |
- $name = $this->legacyExtensionNames[$name]; |
|
926 |
- @trigger_error(sprintf('Referencing the "%s" extension by its name (defined by getName()) is deprecated since 1.26 and will be removed in Twig 2.0. Use the Fully Qualified Extension Class Name instead.', $name), E_USER_DEPRECATED); |
|
927 |
- } |
|
928 |
- |
|
929 | 927 |
if ($this->extensionInitialized) { |
930 | 928 |
throw new LogicException(sprintf('Unable to remove extension "%s" as extensions have already been initialized.', $name)); |
931 | 929 |
} |
932 | 930 |
|
933 |
- unset($this->extensions[ltrim($name, '\\')]); |
|
931 |
+ $class = ltrim($name, '\\'); |
|
932 |
+ if (isset($this->extensions[$class])) { |
|
933 |
+ if ($class !== get_class($this->extensions[$class])) { |
|
934 |
+ @trigger_error(sprintf('Referencing the "%s" extension by its name (defined by getName()) is deprecated since 1.26 and will be removed in Twig 2.0. Use the Fully Qualified Extension Class Name instead.', $class), E_USER_DEPRECATED); |
|
935 |
+ } |
|
936 |
+ |
|
937 |
+ unset($this->extensions[$class]); |
|
938 |
+ } |
|
939 |
+ |
|
940 |
+ unset($this->extensions[$class]); |
|
934 | 941 |
$this->updateOptionsHash(); |
935 | 942 |
} |
936 | 943 |
|
... | ... |
@@ -277,6 +277,27 @@ class Twig_Tests_EnvironmentTest extends PHPUnit_Framework_TestCase |
277 | 277 |
$twig->loadTemplate($templateName); |
278 | 278 |
} |
279 | 279 |
|
280 |
+ /** |
|
281 |
+ * @group legacy |
|
282 |
+ */ |
|
283 |
+ public function testHasGetExtensionWithDynamicName() |
|
284 |
+ { |
|
285 |
+ $twig = new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock()); |
|
286 |
+ |
|
287 |
+ $ext1 = new Twig_Tests_EnvironmentTest_Extension_DynamicWithDeprecatedName('ext1'); |
|
288 |
+ $ext2 = new Twig_Tests_EnvironmentTest_Extension_DynamicWithDeprecatedName('ext2'); |
|
289 |
+ $twig->addExtension($ext1); |
|
290 |
+ $twig->addExtension($ext2); |
|
291 |
+ |
|
292 |
+ $this->assertTrue($twig->hasExtension('ext1')); |
|
293 |
+ $this->assertTrue($twig->hasExtension('ext2')); |
|
294 |
+ |
|
295 |
+ $this->assertTrue($twig->hasExtension('Twig_Tests_EnvironmentTest_Extension_DynamicWithDeprecatedName')); |
|
296 |
+ |
|
297 |
+ $this->assertSame($ext1, $twig->getExtension('ext1')); |
|
298 |
+ $this->assertSame($ext2, $twig->getExtension('ext2')); |
|
299 |
+ } |
|
300 |
+ |
|
280 | 301 |
public function testHasGetExtensionByClassName() |
281 | 302 |
{ |
282 | 303 |
$twig = new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock()); |
... | ... |
@@ -538,6 +559,21 @@ class Twig_Tests_EnvironmentTest_Extension_WithDeprecatedName extends Twig_Exten |
538 | 559 |
} |
539 | 560 |
} |
540 | 561 |
|
562 |
+class Twig_Tests_EnvironmentTest_Extension_DynamicWithDeprecatedName extends Twig_Extension |
|
563 |
+{ |
|
564 |
+ private $name; |
|
565 |
+ |
|
566 |
+ public function __construct($name) |
|
567 |
+ { |
|
568 |
+ $this->name = $name; |
|
569 |
+ } |
|
570 |
+ |
|
571 |
+ public function getName() |
|
572 |
+ { |
|
573 |
+ return $this->name; |
|
574 |
+ } |
|
575 |
+} |
|
576 |
+ |
|
541 | 577 |
class Twig_Tests_EnvironmentTest_TokenParser extends Twig_TokenParser |
542 | 578 |
{ |
543 | 579 |
public function parse(Twig_Token $token) |