Skip to content

Commit

Permalink
Add traits extensions
Browse files Browse the repository at this point in the history
  • Loading branch information
EmmanuelVella committed Apr 22, 2015
1 parent a516465 commit 3d3677f
Show file tree
Hide file tree
Showing 7 changed files with 103 additions and 1 deletion.
20 changes: 20 additions & 0 deletions DependencyInjection/Compiler/ExtensionCompilerPass.php
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,12 @@ protected function getExtensionsForAdmin($id, Definition $admin, ContainerBuilde
$extensions = array_merge($extensions, $extensionList);
}
}

if ('uses' == $type) {
if ($this->hasTrait($classReflection, $subject)) {
$extensions = array_merge($extensions, $extensionList);
}
}
}
}

Expand Down Expand Up @@ -160,6 +166,7 @@ protected function flattenExtensionConfiguration(array $config)
'implements' => array(),
'extends' => array(),
'instanceof' => array(),
'uses' => array(),
);

foreach ($config as $extension => $options) {
Expand All @@ -175,4 +182,17 @@ protected function flattenExtensionConfiguration(array $config)

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);
}
}
12 changes: 11 additions & 1 deletion DependencyInjection/Configuration.php
Original file line number Diff line number Diff line change
Expand Up @@ -330,12 +330,13 @@ public function getConfigTreeBuilder()

->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()
Expand All @@ -352,6 +353,15 @@ public function getConfigTreeBuilder()
->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()
Expand Down
1 change: 1 addition & 0 deletions Resources/doc/reference/configuration.rst
Original file line number Diff line number Diff line change
Expand Up @@ -190,4 +190,5 @@ Full Configuration Options
implements: []
extends: []
instanceof: []
uses: []
persist_filters: false
6 changes: 6 additions & 0 deletions Resources/doc/reference/extensions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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::

Expand All @@ -106,3 +110,5 @@ instanceof:
- Acme\Demo\Document\Blog
instanceof:
- Acme\Demo\Document\Page
uses:
- Acme\Demo\Trait\Timestampable
50 changes: 50 additions & 0 deletions Tests/DependencyInjection/Compiler/ExtensionCompilerPassTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -42,12 +44,14 @@ public function setUp()
$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');
}

/**
Expand All @@ -65,6 +69,7 @@ public function testAdminExtensionLoad()
$this->assertArrayHasKey('implements', $extensionMap);
$this->assertArrayHasKey('extends', $extensionMap);
$this->assertArrayHasKey('instanceof', $extensionMap);
$this->assertArrayHasKey('uses', $extensionMap);
}

/**
Expand All @@ -87,12 +92,14 @@ public function testFlattenEmptyExtensionConfiguration()
$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']);
}

/**
Expand Down Expand Up @@ -154,6 +161,19 @@ public function testFlattenExtensionConfiguration()
$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']);
}
}

/**
Expand Down Expand Up @@ -219,6 +239,7 @@ public function testProcess()
$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'));
Expand Down Expand Up @@ -250,6 +271,28 @@ public function testProcess()
$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
*/
Expand All @@ -273,6 +316,10 @@ protected function getConfig()
)
);

if ($this->hasTraits) {
$config['extensions']['sonata_extension_post']['uses'] = array('Sonata\AdminBundle\Tests\Fixtures\DependencyInjection\TimestampableTrait');
}

return $config;
}

Expand Down Expand Up @@ -342,6 +389,9 @@ private function getContainer()
$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))
Expand Down
8 changes: 8 additions & 0 deletions Tests/Fixtures/DependencyInjection/Post.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?php

namespace Sonata\AdminBundle\Tests\Fixtures\DependencyInjection;

class Post
{
use TimestampableTrait;
}
7 changes: 7 additions & 0 deletions Tests/Fixtures/DependencyInjection/TimestampableTrait.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?php

namespace Sonata\AdminBundle\Tests\Fixtures\DependencyInjection;

trait TimestampableTrait
{
}

0 comments on commit 3d3677f

Please sign in to comment.