feature #15416 [DependencyInjection] Added a way to define the priority of service decoration (dosten)
This PR was merged into the 2.8 branch.
Discussion
----------
[DependencyInjection] Added a way to define the priority of service decoration
| Q | A
| ------------- | ---
| Bug fix? | no
| New feature? | yes
| BC breaks? | no
| Deprecations? | no
| Tests pass? | yes
| Fixed tickets | #10634
| License | MIT
| Doc PR | symfony/symfony-docs#5600
This PR adds a way to define the priority of service decoration, so, the service with the highest priority will be applied first (the default priority is zero).
```yaml
services:
foo:
class: Foo
bar:
class: Bar
arguments: ['@bar.inner']
decorates: foo
public: false
foobar:
class: Foobar
arguments: ['@foobar.inner']
decorates: foo
decoration_priority: 1
public: false
```
This will result in this code:
```php
$this->services['foo'] = new Bar(new Foobar(new Foo)));
```
Commits
-------
75c98cb
Added a way to define the priority of service decoration
This commit is contained in:
commit
a00687f43a
|
@ -8,6 +8,7 @@ CHANGELOG
|
|||
* deprecated the concept of scopes
|
||||
* added `Definition::setShared()` and `Definition::isShared()`
|
||||
* 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
|
||||
-----
|
||||
|
|
|
@ -19,18 +19,28 @@ use Symfony\Component\DependencyInjection\Alias;
|
|||
*
|
||||
* @author Christophe Coevoet <stof@notk.org>
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
* @author Diego Saint Esteben <diego@saintesteben.me>
|
||||
*/
|
||||
class DecoratorServicePass implements CompilerPassInterface
|
||||
{
|
||||
public function process(ContainerBuilder $container)
|
||||
{
|
||||
$definitions = new \SplPriorityQueue();
|
||||
$order = PHP_INT_MAX;
|
||||
|
||||
foreach ($container->getDefinitions() as $id => $definition) {
|
||||
if (!$decorated = $definition->getDecoratedService()) {
|
||||
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);
|
||||
|
||||
list($inner, $renamedId) = $decorated;
|
||||
if (!$renamedId) {
|
||||
$renamedId = $id.'.inner';
|
||||
}
|
||||
|
|
|
@ -150,12 +150,13 @@ class Definition
|
|||
*
|
||||
* @param null|string $id The decorated service id, use null to remove decoration
|
||||
* @param null|string $renamedId The new decorated service id
|
||||
* @param int $priority The priority of decoration
|
||||
*
|
||||
* @return Definition The current instance
|
||||
*
|
||||
* @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) {
|
||||
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) {
|
||||
$this->decoratedService = null;
|
||||
} else {
|
||||
$this->decoratedService = array($id, $renamedId);
|
||||
$this->decoratedService = array($id, $renamedId, (int) $priority);
|
||||
}
|
||||
|
||||
return $this;
|
||||
|
@ -173,7 +174,7 @@ class Definition
|
|||
/**
|
||||
* 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()
|
||||
{
|
||||
|
|
|
@ -173,11 +173,11 @@ class DefinitionDecorator extends Definition
|
|||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setDecoratedService($id, $renamedId = null)
|
||||
public function setDecoratedService($id, $renamedId = null, $priority = 0)
|
||||
{
|
||||
$this->changes['decorated_service'] = true;
|
||||
|
||||
return parent::setDecoratedService($id, $renamedId);
|
||||
return parent::setDecoratedService($id, $renamedId, $priority);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -149,11 +149,14 @@ class XmlDumper extends Dumper
|
|||
$service->setAttribute('lazy', 'true');
|
||||
}
|
||||
if (null !== $decorated = $definition->getDecoratedService()) {
|
||||
list($decorated, $renamedId) = $decorated;
|
||||
list($decorated, $renamedId, $priority) = $decorated;
|
||||
$service->setAttribute('decorates', $decorated);
|
||||
if (null !== $renamedId) {
|
||||
$service->setAttribute('decoration-inner-name', $renamedId);
|
||||
}
|
||||
if (0 !== $priority) {
|
||||
$service->setAttribute('decoration-priority', $priority);
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($definition->getTags() as $name => $tags) {
|
||||
|
|
|
@ -141,11 +141,14 @@ class YamlDumper extends Dumper
|
|||
}
|
||||
|
||||
if (null !== $decorated = $definition->getDecoratedService()) {
|
||||
list($decorated, $renamedId) = $decorated;
|
||||
list($decorated, $renamedId, $priority) = $decorated;
|
||||
$code .= sprintf(" decorates: %s\n", $decorated);
|
||||
if (null !== $renamedId) {
|
||||
$code .= sprintf(" decoration_inner_name: %s\n", $renamedId);
|
||||
}
|
||||
if (0 !== $priority) {
|
||||
$code .= sprintf(" decoration_priority: %s\n", $priority);
|
||||
}
|
||||
}
|
||||
|
||||
if ($callable = $definition->getFactory()) {
|
||||
|
|
|
@ -245,7 +245,8 @@ class XmlFileLoader extends FileLoader
|
|||
|
||||
if ($value = $service->getAttribute('decorates')) {
|
||||
$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;
|
||||
|
|
|
@ -290,7 +290,8 @@ class YamlFileLoader extends FileLoader
|
|||
|
||||
if (isset($service['decorates'])) {
|
||||
$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);
|
||||
|
|
|
@ -101,6 +101,7 @@
|
|||
<xsd:attribute name="parent" type="xsd:string" />
|
||||
<xsd:attribute name="decorates" type="xsd:string" />
|
||||
<xsd:attribute name="decoration-inner-name" type="xsd:string" />
|
||||
<xsd:attribute name="decoration-priority" type="xsd:integer" />
|
||||
</xsd:complexType>
|
||||
|
||||
<xsd:complexType name="tag">
|
||||
|
|
|
@ -73,6 +73,48 @@ class DecoratorServicePassTest extends \PHPUnit_Framework_TestCase
|
|||
$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)
|
||||
{
|
||||
$repeatedPass = new DecoratorServicePass();
|
||||
|
|
|
@ -241,7 +241,7 @@ class ResolveDefinitionTemplatesPassTest extends \PHPUnit_Framework_TestCase
|
|||
->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)
|
||||
|
|
|
@ -56,16 +56,23 @@ class DefinitionTest extends \PHPUnit_Framework_TestCase
|
|||
|
||||
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');
|
||||
$this->assertNull($def->getDecoratedService());
|
||||
$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);
|
||||
$this->assertNull($def->getDecoratedService());
|
||||
|
||||
$def = new Definition('stdClass');
|
||||
$def->setDecoratedService('foo');
|
||||
$this->assertEquals(array('foo', null), $def->getDecoratedService());
|
||||
$this->assertEquals(array('foo', null, 0), $def->getDecoratedService());
|
||||
$def->setDecoratedService(null);
|
||||
$this->assertNull($def->getDecoratedService());
|
||||
|
||||
|
|
|
@ -47,6 +47,7 @@
|
|||
<service id="another_alias_for_foo" alias="foo" public="false" />
|
||||
<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_and_priority" decorates="decorated" decoration-inner-name="decorated.pif-pouf" decoration-priority="5"/>
|
||||
<service id="new_factory1" class="FooBarClass">
|
||||
<factory function="factory" />
|
||||
</service>
|
||||
|
|
|
@ -26,6 +26,10 @@ services:
|
|||
decorator_service_with_name:
|
||||
decorates: decorated
|
||||
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_factory2: { class: FooBarClass, factory: [@baz, getClass]}
|
||||
new_factory3: { class: FooBarClass, factory: [BazClass, getInstance]}
|
||||
|
|
|
@ -242,8 +242,9 @@ class XmlFileLoaderTest extends \PHPUnit_Framework_TestCase
|
|||
$this->assertEquals('foo', (string) $aliases['another_alias_for_foo']);
|
||||
$this->assertFalse($aliases['another_alias_for_foo']->isPublic());
|
||||
|
||||
$this->assertEquals(array('decorated', null), $services['decorator_service']->getDecoratedService());
|
||||
$this->assertEquals(array('decorated', 'decorated.pif-pouf'), $services['decorator_service_with_name']->getDecoratedService());
|
||||
$this->assertEquals(array('decorated', null, 0), $services['decorator_service']->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()
|
||||
|
|
|
@ -171,8 +171,9 @@ class YamlFileLoaderTest extends \PHPUnit_Framework_TestCase
|
|||
$this->assertEquals('foo', (string) $aliases['another_alias_for_foo']);
|
||||
$this->assertFalse($aliases['another_alias_for_foo']->isPublic());
|
||||
|
||||
$this->assertEquals(array('decorated', null), $services['decorator_service']->getDecoratedService());
|
||||
$this->assertEquals(array('decorated', 'decorated.pif-pouf'), $services['decorator_service_with_name']->getDecoratedService());
|
||||
$this->assertEquals(array('decorated', null, 0), $services['decorator_service']->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()
|
||||
|
|
Reference in New Issue