Added a way to define the priority of service decoration

This commit is contained in:
Diego Saint Esteben 2015-07-30 22:41:40 -03:00
parent 2655072bfd
commit 75c98cba03
16 changed files with 94 additions and 17 deletions

View File

@ -8,6 +8,7 @@ CHANGELOG
* deprecated the concept of scopes * deprecated the concept of scopes
* added `Definition::setShared()` and `Definition::isShared()` * added `Definition::setShared()` and `Definition::isShared()`
* added ResettableContainerInterface to be able to reset the container to release memory on shutdown * added ResettableContainerInterface to be able to reset the container to release memory on shutdown
* added a way to define the priority of service decoration
2.7.0 2.7.0
----- -----

View File

@ -19,18 +19,28 @@ use Symfony\Component\DependencyInjection\Alias;
* *
* @author Christophe Coevoet <stof@notk.org> * @author Christophe Coevoet <stof@notk.org>
* @author Fabien Potencier <fabien@symfony.com> * @author Fabien Potencier <fabien@symfony.com>
* @author Diego Saint Esteben <diego@saintesteben.me>
*/ */
class DecoratorServicePass implements CompilerPassInterface class DecoratorServicePass implements CompilerPassInterface
{ {
public function process(ContainerBuilder $container) public function process(ContainerBuilder $container)
{ {
$definitions = new \SplPriorityQueue();
$order = PHP_INT_MAX;
foreach ($container->getDefinitions() as $id => $definition) { foreach ($container->getDefinitions() as $id => $definition) {
if (!$decorated = $definition->getDecoratedService()) { if (!$decorated = $definition->getDecoratedService()) {
continue; continue;
} }
$definitions->insert(array($id, $definition), array($decorated[2], --$order));
}
foreach ($definitions as $arr) {
list($id, $definition) = $arr;
list($inner, $renamedId) = $definition->getDecoratedService();
$definition->setDecoratedService(null); $definition->setDecoratedService(null);
list($inner, $renamedId) = $decorated;
if (!$renamedId) { if (!$renamedId) {
$renamedId = $id.'.inner'; $renamedId = $id.'.inner';
} }

View File

@ -150,12 +150,13 @@ class Definition
* *
* @param null|string $id The decorated service id, use null to remove decoration * @param null|string $id The decorated service id, use null to remove decoration
* @param null|string $renamedId The new decorated service id * @param null|string $renamedId The new decorated service id
* @param int $priority The priority of decoration
* *
* @return Definition The current instance * @return Definition The current instance
* *
* @throws InvalidArgumentException In case the decorated service id and the new decorated service id are equals. * @throws InvalidArgumentException In case the decorated service id and the new decorated service id are equals.
*/ */
public function setDecoratedService($id, $renamedId = null) public function setDecoratedService($id, $renamedId = null, $priority = 0)
{ {
if ($renamedId && $id == $renamedId) { if ($renamedId && $id == $renamedId) {
throw new \InvalidArgumentException(sprintf('The decorated service inner name for "%s" must be different than the service name itself.', $id)); throw new \InvalidArgumentException(sprintf('The decorated service inner name for "%s" must be different than the service name itself.', $id));
@ -164,7 +165,7 @@ class Definition
if (null === $id) { if (null === $id) {
$this->decoratedService = null; $this->decoratedService = null;
} else { } else {
$this->decoratedService = array($id, $renamedId); $this->decoratedService = array($id, $renamedId, (int) $priority);
} }
return $this; return $this;
@ -173,7 +174,7 @@ class Definition
/** /**
* Gets the service that decorates this service. * Gets the service that decorates this service.
* *
* @return null|array An array composed of the decorated service id and the new id for it, null if no service is decorated * @return null|array An array composed of the decorated service id, the new id for it and the priority of decoration, null if no service is decorated
*/ */
public function getDecoratedService() public function getDecoratedService()
{ {

View File

@ -173,11 +173,11 @@ class DefinitionDecorator extends Definition
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function setDecoratedService($id, $renamedId = null) public function setDecoratedService($id, $renamedId = null, $priority = 0)
{ {
$this->changes['decorated_service'] = true; $this->changes['decorated_service'] = true;
return parent::setDecoratedService($id, $renamedId); return parent::setDecoratedService($id, $renamedId, $priority);
} }
/** /**

View File

@ -145,11 +145,14 @@ class XmlDumper extends Dumper
$service->setAttribute('lazy', 'true'); $service->setAttribute('lazy', 'true');
} }
if (null !== $decorated = $definition->getDecoratedService()) { if (null !== $decorated = $definition->getDecoratedService()) {
list($decorated, $renamedId) = $decorated; list($decorated, $renamedId, $priority) = $decorated;
$service->setAttribute('decorates', $decorated); $service->setAttribute('decorates', $decorated);
if (null !== $renamedId) { if (null !== $renamedId) {
$service->setAttribute('decoration-inner-name', $renamedId); $service->setAttribute('decoration-inner-name', $renamedId);
} }
if (0 !== $priority) {
$service->setAttribute('decoration-priority', $priority);
}
} }
foreach ($definition->getTags() as $name => $tags) { foreach ($definition->getTags() as $name => $tags) {

View File

@ -137,11 +137,14 @@ class YamlDumper extends Dumper
} }
if (null !== $decorated = $definition->getDecoratedService()) { if (null !== $decorated = $definition->getDecoratedService()) {
list($decorated, $renamedId) = $decorated; list($decorated, $renamedId, $priority) = $decorated;
$code .= sprintf(" decorates: %s\n", $decorated); $code .= sprintf(" decorates: %s\n", $decorated);
if (null !== $renamedId) { if (null !== $renamedId) {
$code .= sprintf(" decoration_inner_name: %s\n", $renamedId); $code .= sprintf(" decoration_inner_name: %s\n", $renamedId);
} }
if (0 !== $priority) {
$code .= sprintf(" decoration_priority: %s\n", $priority);
}
} }
if ($callable = $definition->getFactory()) { if ($callable = $definition->getFactory()) {

View File

@ -245,7 +245,8 @@ class XmlFileLoader extends FileLoader
if ($value = $service->getAttribute('decorates')) { if ($value = $service->getAttribute('decorates')) {
$renameId = $service->hasAttribute('decoration-inner-name') ? $service->getAttribute('decoration-inner-name') : null; $renameId = $service->hasAttribute('decoration-inner-name') ? $service->getAttribute('decoration-inner-name') : null;
$definition->setDecoratedService($value, $renameId); $priority = $service->hasAttribute('decoration-priority') ? $service->getAttribute('decoration-priority') : 0;
$definition->setDecoratedService($value, $renameId, $priority);
} }
return $definition; return $definition;

View File

@ -290,7 +290,8 @@ class YamlFileLoader extends FileLoader
if (isset($service['decorates'])) { if (isset($service['decorates'])) {
$renameId = isset($service['decoration_inner_name']) ? $service['decoration_inner_name'] : null; $renameId = isset($service['decoration_inner_name']) ? $service['decoration_inner_name'] : null;
$definition->setDecoratedService($service['decorates'], $renameId); $priority = isset($service['decoration_priority']) ? $service['decoration_priority'] : 0;
$definition->setDecoratedService($service['decorates'], $renameId, $priority);
} }
$this->container->setDefinition($id, $definition); $this->container->setDefinition($id, $definition);

View File

@ -101,6 +101,7 @@
<xsd:attribute name="parent" type="xsd:string" /> <xsd:attribute name="parent" type="xsd:string" />
<xsd:attribute name="decorates" type="xsd:string" /> <xsd:attribute name="decorates" type="xsd:string" />
<xsd:attribute name="decoration-inner-name" type="xsd:string" /> <xsd:attribute name="decoration-inner-name" type="xsd:string" />
<xsd:attribute name="decoration-priority" type="xsd:integer" />
</xsd:complexType> </xsd:complexType>
<xsd:complexType name="tag"> <xsd:complexType name="tag">

View File

@ -73,6 +73,48 @@ class DecoratorServicePassTest extends \PHPUnit_Framework_TestCase
$this->assertNull($fooExtendedDefinition->getDecoratedService()); $this->assertNull($fooExtendedDefinition->getDecoratedService());
} }
public function testProcessWithPriority()
{
$container = new ContainerBuilder();
$fooDefinition = $container
->register('foo')
->setPublic(false)
;
$barDefinition = $container
->register('bar')
->setPublic(true)
->setDecoratedService('foo')
;
$bazDefinition = $container
->register('baz')
->setPublic(true)
->setDecoratedService('foo', null, 5)
;
$quxDefinition = $container
->register('qux')
->setPublic(true)
->setDecoratedService('foo', null, 3)
;
$this->process($container);
$this->assertEquals('bar', $container->getAlias('foo'));
$this->assertFalse($container->getAlias('foo')->isPublic());
$this->assertSame($fooDefinition, $container->getDefinition('baz.inner'));
$this->assertFalse($container->getDefinition('baz.inner')->isPublic());
$this->assertEquals('qux', $container->getAlias('bar.inner'));
$this->assertFalse($container->getAlias('bar.inner')->isPublic());
$this->assertEquals('baz', $container->getAlias('qux.inner'));
$this->assertFalse($container->getAlias('qux.inner')->isPublic());
$this->assertNull($barDefinition->getDecoratedService());
$this->assertNull($bazDefinition->getDecoratedService());
$this->assertNull($quxDefinition->getDecoratedService());
}
protected function process(ContainerBuilder $container) protected function process(ContainerBuilder $container)
{ {
$repeatedPass = new DecoratorServicePass(); $repeatedPass = new DecoratorServicePass();

View File

@ -241,7 +241,7 @@ class ResolveDefinitionTemplatesPassTest extends \PHPUnit_Framework_TestCase
->setDecoratedService('foo', 'foo_inner') ->setDecoratedService('foo', 'foo_inner')
; ;
$this->assertEquals(array('foo', 'foo_inner'), $container->getDefinition('child1')->getDecoratedService()); $this->assertEquals(array('foo', 'foo_inner', 0), $container->getDefinition('child1')->getDecoratedService());
} }
protected function process(ContainerBuilder $container) protected function process(ContainerBuilder $container)

View File

@ -56,16 +56,23 @@ class DefinitionTest extends \PHPUnit_Framework_TestCase
public function testSetGetDecoratedService() public function testSetGetDecoratedService()
{ {
$def = new Definition('stdClass');
$this->assertNull($def->getDecoratedService());
$def->setDecoratedService('foo', 'foo.renamed', 5);
$this->assertEquals(array('foo', 'foo.renamed', 5), $def->getDecoratedService());
$def->setDecoratedService(null);
$this->assertNull($def->getDecoratedService());
$def = new Definition('stdClass'); $def = new Definition('stdClass');
$this->assertNull($def->getDecoratedService()); $this->assertNull($def->getDecoratedService());
$def->setDecoratedService('foo', 'foo.renamed'); $def->setDecoratedService('foo', 'foo.renamed');
$this->assertEquals(array('foo', 'foo.renamed'), $def->getDecoratedService()); $this->assertEquals(array('foo', 'foo.renamed', 0), $def->getDecoratedService());
$def->setDecoratedService(null); $def->setDecoratedService(null);
$this->assertNull($def->getDecoratedService()); $this->assertNull($def->getDecoratedService());
$def = new Definition('stdClass'); $def = new Definition('stdClass');
$def->setDecoratedService('foo'); $def->setDecoratedService('foo');
$this->assertEquals(array('foo', null), $def->getDecoratedService()); $this->assertEquals(array('foo', null, 0), $def->getDecoratedService());
$def->setDecoratedService(null); $def->setDecoratedService(null);
$this->assertNull($def->getDecoratedService()); $this->assertNull($def->getDecoratedService());

View File

@ -47,6 +47,7 @@
<service id="another_alias_for_foo" alias="foo" public="false" /> <service id="another_alias_for_foo" alias="foo" public="false" />
<service id="decorator_service" decorates="decorated" /> <service id="decorator_service" decorates="decorated" />
<service id="decorator_service_with_name" decorates="decorated" decoration-inner-name="decorated.pif-pouf"/> <service id="decorator_service_with_name" decorates="decorated" decoration-inner-name="decorated.pif-pouf"/>
<service id="decorator_service_with_name_and_priority" decorates="decorated" decoration-inner-name="decorated.pif-pouf" decoration-priority="5"/>
<service id="new_factory1" class="FooBarClass"> <service id="new_factory1" class="FooBarClass">
<factory function="factory" /> <factory function="factory" />
</service> </service>

View File

@ -26,6 +26,10 @@ services:
decorator_service_with_name: decorator_service_with_name:
decorates: decorated decorates: decorated
decoration_inner_name: decorated.pif-pouf decoration_inner_name: decorated.pif-pouf
decorator_service_with_name_and_priority:
decorates: decorated
decoration_inner_name: decorated.pif-pouf
decoration_priority: 5
new_factory1: { class: FooBarClass, factory: factory} new_factory1: { class: FooBarClass, factory: factory}
new_factory2: { class: FooBarClass, factory: [@baz, getClass]} new_factory2: { class: FooBarClass, factory: [@baz, getClass]}
new_factory3: { class: FooBarClass, factory: [BazClass, getInstance]} new_factory3: { class: FooBarClass, factory: [BazClass, getInstance]}

View File

@ -242,8 +242,9 @@ class XmlFileLoaderTest extends \PHPUnit_Framework_TestCase
$this->assertEquals('foo', (string) $aliases['another_alias_for_foo']); $this->assertEquals('foo', (string) $aliases['another_alias_for_foo']);
$this->assertFalse($aliases['another_alias_for_foo']->isPublic()); $this->assertFalse($aliases['another_alias_for_foo']->isPublic());
$this->assertEquals(array('decorated', null), $services['decorator_service']->getDecoratedService()); $this->assertEquals(array('decorated', null, 0), $services['decorator_service']->getDecoratedService());
$this->assertEquals(array('decorated', 'decorated.pif-pouf'), $services['decorator_service_with_name']->getDecoratedService()); $this->assertEquals(array('decorated', 'decorated.pif-pouf', 0), $services['decorator_service_with_name']->getDecoratedService());
$this->assertEquals(array('decorated', 'decorated.pif-pouf', 5), $services['decorator_service_with_name_and_priority']->getDecoratedService());
} }
public function testParsesTags() public function testParsesTags()

View File

@ -171,8 +171,9 @@ class YamlFileLoaderTest extends \PHPUnit_Framework_TestCase
$this->assertEquals('foo', (string) $aliases['another_alias_for_foo']); $this->assertEquals('foo', (string) $aliases['another_alias_for_foo']);
$this->assertFalse($aliases['another_alias_for_foo']->isPublic()); $this->assertFalse($aliases['another_alias_for_foo']->isPublic());
$this->assertEquals(array('decorated', null), $services['decorator_service']->getDecoratedService()); $this->assertEquals(array('decorated', null, 0), $services['decorator_service']->getDecoratedService());
$this->assertEquals(array('decorated', 'decorated.pif-pouf'), $services['decorator_service_with_name']->getDecoratedService()); $this->assertEquals(array('decorated', 'decorated.pif-pouf', 0), $services['decorator_service_with_name']->getDecoratedService());
$this->assertEquals(array('decorated', 'decorated.pif-pouf', 5), $services['decorator_service_with_name_and_priority']->getDecoratedService());
} }
public function testLoadFactoryShortSyntax() public function testLoadFactoryShortSyntax()