Browse code

bug #2200 fixed regression when registering two extensions with the same class (fabpot)

This PR was merged into the 1.x branch.

Discussion
----------

fixed regression when registering two extensions with the same class

fixed #2165

Commits
-------

47432f3 fixed regression when registering two extensions having the same class name

Fabien Potencier authored on 23/10/2016 20:13:39
Showing 3 changed files
... ...
@@ -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;
... ...
@@ -808,12 +808,16 @@ class Twig_Environment
808 808
      */
809 809
     public function hasExtension($class)
810 810
     {
811
-        if (isset($this->legacyExtensionNames[$class])) {
812
-            $class = $this->legacyExtensionNames[$class];
813
-            @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);
811
+        $class = ltrim($class, '\\');
812
+        if (isset($this->extensions[$class])) {
813
+            if ($class !== get_class($this->extensions[$class])) {
814
+                @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);
815
+            }
816
+
817
+            return true;
814 818
         }
815 819
 
816
-        return isset($this->extensions[ltrim($class, '\\')]);
820
+        return isset($this->extensionsByClass[ltrim($class, '\\')]);
817 821
     }
818 822
 
819 823
     /**
... ...
@@ -833,18 +837,21 @@ class Twig_Environment
833 837
      */
834 838
     public function getExtension($class)
835 839
     {
836
-        if (isset($this->legacyExtensionNames[$class])) {
837
-            $class = $this->legacyExtensionNames[$class];
838
-            @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);
839
-        }
840
-
841 840
         $class = ltrim($class, '\\');
842 841
 
843
-        if (!isset($this->extensions[$class])) {
842
+        if (isset($this->extensions[$class])) {
843
+            if ($class !== get_class($this->extensions[$class])) {
844
+                @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);
845
+            }
846
+
847
+            return $this->extensions[$class];
848
+        }
849
+
850
+        if (!isset($this->extensionsByClass[$class])) {
844 851
             throw new Twig_Error_Runtime(sprintf('The "%s" extension is not enabled.', $class));
845 852
         }
846 853
 
847
-        return $this->extensions[$class];
854
+        return $this->extensionsByClass[$class];
848 855
     }
849 856
 
850 857
     /**
... ...
@@ -878,25 +885,21 @@ class Twig_Environment
878 885
      */
879 886
     public function addExtension(Twig_ExtensionInterface $extension)
880 887
     {
881
-        $class = get_class($extension);
882
-
883 888
         if ($this->extensionInitialized) {
884
-            throw new LogicException(sprintf('Unable to register extension "%s" as extensions have already been initialized.', $class));
889
+            throw new LogicException(sprintf('Unable to register extension "%s" as extensions have already been initialized.', $extension->getName()));
885 890
         }
886 891
 
887
-        $m = new ReflectionMethod($extension, 'getName');
888
-        $legacyName = 'Twig_Extension' !== $m->getDeclaringClass()->getName() ? $extension->getName() : null;
889
-
890
-        if (isset($this->extensions[$class]) || (null !== $legacyName && isset($this->legacyExtensionNames[$legacyName]))) {
891
-            unset($this->extensions[$this->legacyExtensionNames[$legacyName]], $this->legacyExtensionNames[$legacyName]);
892
-            @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);
892
+        $class = get_class($extension);
893
+        if ($class !== $extension->getName()) {
894
+            if (isset($this->extensions[$extension->getName()])) {
895
+                unset($this->extensions[$extension->getName()], $this->extensionsByClass[$class]);
896
+                @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);
897
+            }
893 898
         }
894 899
 
895 900
         $this->lastModifiedExtension = 0;
896
-        if ($legacyName !== $class) {
897
-            $this->legacyExtensionNames[$legacyName] = $class;
898
-        }
899
-        $this->extensions[$class] = $extension;
901
+        $this->extensionsByClass[$class] = $extension;
902
+        $this->extensions[$extension->getName()] = $extension;
900 903
         $this->updateOptionsHash();
901 904
     }
902 905
 
... ...
@@ -913,16 +916,20 @@ class Twig_Environment
913 916
     {
914 917
         @trigger_error(sprintf('The %s method is deprecated since version 1.12 and will be removed in Twig 2.0.', __METHOD__), E_USER_DEPRECATED);
915 918
 
916
-        if (isset($this->legacyExtensionNames[$name])) {
917
-            $name = $this->legacyExtensionNames[$name];
918
-            @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);
919
-        }
920
-
921 919
         if ($this->extensionInitialized) {
922 920
             throw new LogicException(sprintf('Unable to remove extension "%s" as extensions have already been initialized.', $name));
923 921
         }
924 922
 
925
-        unset($this->extensions[ltrim($name, '\\')]);
923
+        $class = ltrim($name, '\\');
924
+        if (isset($this->extensions[$class])) {
925
+            if ($class !== get_class($this->extensions[$class])) {
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.', $class), E_USER_DEPRECATED);
927
+            }
928
+
929
+            unset($this->extensions[$class]);
930
+        }
931
+
932
+        unset($this->extensions[$class]);
926 933
         $this->updateOptionsHash();
927 934
     }
928 935
 
... ...
@@ -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)