Ver Fonte

Add traits extensions

Emmanuel Vella há 10 anos atrás
pai
commit
3d3677f6b3

+ 20 - 0
DependencyInjection/Compiler/ExtensionCompilerPass.php

@@ -124,6 +124,12 @@ class ExtensionCompilerPass implements CompilerPassInterface
                         $extensions = array_merge($extensions, $extensionList);
                     }
                 }
+
+                if ('uses' == $type) {
+                    if ($this->hasTrait($classReflection, $subject)) {
+                        $extensions = array_merge($extensions, $extensionList);
+                    }
+                }
             }
         }
 
@@ -160,6 +166,7 @@ class ExtensionCompilerPass implements CompilerPassInterface
             'implements' => array(),
             'extends'    => array(),
             'instanceof' => array(),
+            'uses'       => array(),
         );
 
         foreach ($config as $extension => $options) {
@@ -175,4 +182,17 @@ class ExtensionCompilerPass implements CompilerPassInterface
 
         return $extensionMap;
     }
+
+    protected function hasTrait(\ReflectionClass $class, $traitName)
+    {
+        if (in_array($traitName, $class->getTraitNames())) {
+            return true;
+        }
+
+        if (!$parentClass = $class->getParentClass()) {
+            return false;
+        }
+
+        return $this->hasTrait($parentClass, $traitName);
+    }
 }

+ 11 - 1
DependencyInjection/Configuration.php

@@ -330,12 +330,13 @@ class Configuration implements ConfigurationInterface
 
                 ->arrayNode('extensions')
                 ->useAttributeAsKey('id')
-                ->defaultValue(array('admins' => array(), 'excludes' => array(), 'implements' => array(), 'extends' => array(), 'instanceof' => array()))
+                ->defaultValue(array('admins' => array(), 'excludes' => array(), 'implements' => array(), 'extends' => array(), 'instanceof' => array(), 'uses' => array()))
                     ->prototype('array')
                         ->fixXmlConfig('admin')
                         ->fixXmlConfig('exclude')
                         ->fixXmlConfig('implement')
                         ->fixXmlConfig('extend')
+                        ->fixXmlConfig('use')
                         ->children()
                             ->arrayNode('admins')
                                 ->prototype('scalar')->end()
@@ -352,6 +353,15 @@ class Configuration implements ConfigurationInterface
                             ->arrayNode('instanceof')
                                 ->prototype('scalar')->end()
                             ->end()
+                            ->arrayNode('uses')
+                                ->prototype('scalar')->end()
+                                ->validate()
+                                    ->ifTrue(function ($v) {
+                                        return !empty($v) && version_compare(PHP_VERSION, '5.4.0', '<');
+                                    })
+                                    ->thenInvalid('PHP >= 5.4.0 is required to use traits.')
+                                ->end()
+                            ->end()
                         ->end()
                     ->end()
                 ->end()

+ 1 - 0
Resources/doc/reference/configuration.rst

@@ -190,4 +190,5 @@ Full Configuration Options
                     implements:           []
                     extends:              []
                     instanceof:           []
+                    uses:                 []
             persist_filters:      false

+ 6 - 0
Resources/doc/reference/extensions.rst

@@ -86,6 +86,10 @@ instanceof:
     specify one or more classes. If the managed class of an admin extends one of the specified classes or is an instance
     of that class the extension will be added to that admin.
 
+uses:
+    Requires PHP >= 5.4.0. Specify one or more traits. If the managed class of an admin uses one of the specified traits the extension will be
+    added to that admin.
+
 
 .. configuration-block::
 
@@ -106,3 +110,5 @@ instanceof:
                             - Acme\Demo\Document\Blog
                         instanceof:
                             -  Acme\Demo\Document\Page
+                        uses:
+                            -  Acme\Demo\Trait\Timestampable

+ 50 - 0
Tests/DependencyInjection/Compiler/ExtensionCompilerPassTest.php

@@ -29,6 +29,8 @@ class ExtensionCompilerPassTest extends \PHPUnit_Framework_TestCase
     private $orderExtension;
     private $securityExtension;
     private $filterExtension;
+    private $timestampExtension;
+    private $hasTraits;
 
     /**
      * Root name of the configuration
@@ -42,12 +44,14 @@ class ExtensionCompilerPassTest extends \PHPUnit_Framework_TestCase
         $this->extension = new SonataAdminExtension();
         $this->config    = $this->getConfig();
         $this->root      = 'sonata.admin';
+        $this->hasTraits = version_compare(PHP_VERSION, '5.4.0', '>=');
 
         $this->publishExtension = $this->getMock('Sonata\AdminBundle\Admin\AdminExtensionInterface');
         $this->historyExtension = $this->getMock('Sonata\AdminBundle\Admin\AdminExtensionInterface');
         $this->orderExtension = $this->getMock('Sonata\AdminBundle\Admin\AdminExtensionInterface');
         $this->securityExtension = $this->getMock('Sonata\AdminBundle\Admin\AdminExtensionInterface');
         $this->filterExtension = $this->getMock('Sonata\AdminBundle\Admin\AdminExtensionInterface');
+        $this->timestampExtension = $this->getMock('Sonata\AdminBundle\Admin\AdminExtensionInterface');
     }
 
     /**
@@ -65,6 +69,7 @@ class ExtensionCompilerPassTest extends \PHPUnit_Framework_TestCase
         $this->assertArrayHasKey('implements', $extensionMap);
         $this->assertArrayHasKey('extends', $extensionMap);
         $this->assertArrayHasKey('instanceof', $extensionMap);
+        $this->assertArrayHasKey('uses', $extensionMap);
     }
 
     /**
@@ -87,12 +92,14 @@ class ExtensionCompilerPassTest extends \PHPUnit_Framework_TestCase
         $this->assertArrayHasKey('implements', $extensionMap);
         $this->assertArrayHasKey('extends', $extensionMap);
         $this->assertArrayHasKey('instanceof', $extensionMap);
+        $this->assertArrayHasKey('uses', $extensionMap);
 
         $this->assertEmpty($extensionMap['admins']);
         $this->assertEmpty($extensionMap['excludes']);
         $this->assertEmpty($extensionMap['implements']);
         $this->assertEmpty($extensionMap['extends']);
         $this->assertEmpty($extensionMap['instanceof']);
+        $this->assertEmpty($extensionMap['uses']);
     }
 
     /**
@@ -154,6 +161,19 @@ class ExtensionCompilerPassTest extends \PHPUnit_Framework_TestCase
         $this->assertArrayHasKey('Sonata\AdminBundle\Tests\DependencyInjection\Post', $extensionMap['instanceof']);
         $this->assertCount(1, $extensionMap['instanceof']['Sonata\AdminBundle\Tests\DependencyInjection\Post']);
         $this->assertContains('sonata_extension_history', $extensionMap['instanceof']['Sonata\AdminBundle\Tests\DependencyInjection\Post']);
+
+        // Uses
+        $this->assertArrayHasKey('uses', $extensionMap);
+
+        if ($this->hasTraits) {
+            $this->assertCount(1, $extensionMap['uses']);
+            $this->assertArrayHasKey('Sonata\AdminBundle\Tests\Fixtures\DependencyInjection\TimestampableTrait', $extensionMap['uses']);
+            $this->assertCount(1, $extensionMap['uses']['Sonata\AdminBundle\Tests\Fixtures\DependencyInjection\TimestampableTrait']);
+            $this->assertContains('sonata_extension_post', $extensionMap['uses']['Sonata\AdminBundle\Tests\Fixtures\DependencyInjection\TimestampableTrait']);
+        } else {
+            $this->assertCount(0, $extensionMap['uses']);
+            $this->assertArrayNotHasKey('Sonata\AdminBundle\Tests\Fixtures\DependencyInjection\TimestampableTrait', $extensionMap['uses']);
+        }
     }
 
     /**
@@ -219,6 +239,7 @@ class ExtensionCompilerPassTest extends \PHPUnit_Framework_TestCase
         $this->assertTrue($container->hasDefinition('sonata_extension_history'));
         $this->assertTrue($container->hasDefinition('sonata_extension_order'));
         $this->assertTrue($container->hasDefinition('sonata_extension_security'));
+        $this->assertTrue($container->hasDefinition('sonata_extension_timestamp'));
 
         $this->assertTrue($container->hasDefinition('sonata_post_admin'));
         $this->assertTrue($container->hasDefinition('sonata_article_admin'));
@@ -250,6 +271,28 @@ class ExtensionCompilerPassTest extends \PHPUnit_Framework_TestCase
         $this->assertInstanceOf(get_class($this->filterExtension), $extensions[4]);
     }
 
+    public function testProcessThrowsExceptionIfTraitsAreNotAvailable()
+    {
+        if (!$this->hasTraits) {
+            $this->setExpectedException('\Symfony\Component\Config\Definition\Exception\InvalidConfigurationException', 'PHP >= 5.4.0 is required to use traits.');
+        }
+
+        $config = array(
+            'extensions' => array(
+                'sonata_extension_post' => array(
+                    'uses' => array('Sonata\AdminBundle\Tests\Fixtures\DependencyInjection\TimestampableTrait'),
+                ),
+            )
+        );
+
+        $container = $this->getContainer();
+        $this->extension->load(array($config), $container);
+
+        $extensionsPass = new ExtensionCompilerPass();
+        $extensionsPass->process($container);
+        $container->compile();
+    }
+
     /**
      * @return array
      */
@@ -273,6 +316,10 @@ class ExtensionCompilerPassTest extends \PHPUnit_Framework_TestCase
             )
         );
 
+        if ($this->hasTraits) {
+            $config['extensions']['sonata_extension_post']['uses'] = array('Sonata\AdminBundle\Tests\Fixtures\DependencyInjection\TimestampableTrait');
+        }
+
         return $config;
     }
 
@@ -342,6 +389,9 @@ class ExtensionCompilerPassTest extends \PHPUnit_Framework_TestCase
         $container
             ->register('sonata_extension_order')
             ->setClass(get_class($this->orderExtension));
+        $container
+            ->register('sonata_extension_timestamp')
+            ->setClass(get_class($this->timestampExtension));
         $container
             ->register('sonata_extension_security')
             ->setClass(get_class($this->securityExtension))

+ 8 - 0
Tests/Fixtures/DependencyInjection/Post.php

@@ -0,0 +1,8 @@
+<?php
+
+namespace Sonata\AdminBundle\Tests\Fixtures\DependencyInjection;
+
+class Post
+{
+    use TimestampableTrait;
+}

+ 7 - 0
Tests/Fixtures/DependencyInjection/TimestampableTrait.php

@@ -0,0 +1,7 @@
+<?php
+
+namespace Sonata\AdminBundle\Tests\Fixtures\DependencyInjection;
+
+trait TimestampableTrait
+{
+}