Skip to content

Commit

Permalink
[DI] Allow definitions to inherit tags from parent context
Browse files Browse the repository at this point in the history
  • Loading branch information
nicolas-grekas committed Jan 7, 2017
1 parent 05f24d5 commit beec1cf
Show file tree
Hide file tree
Showing 10 changed files with 111 additions and 27 deletions.
12 changes: 7 additions & 5 deletions src/Symfony/Component/DependencyInjection/CHANGELOG.md
Expand Up @@ -4,11 +4,13 @@ CHANGELOG
3.3.0
-----

* Add "iterator" argument type for lazy iteration over a set of values and services

* Using the `PhpDumper` with an uncompiled `ContainerBuilder` is deprecated and
will not be supported anymore in 4.0.

* added "iterator" argument type for lazy iteration over a set of values and services
* added "closure-proxy" argument type for turning services' methods into lazy callables
* added file-wide configurable defaults for service attributes "public", "tags",
"autowire" and a new "inherit-tags"
* made the "class" attribute optional, using the "id" as fallback
* using the `PhpDumper` with an uncompiled `ContainerBuilder` is deprecated and
will not be supported anymore in 4.0
* deprecated the `DefinitionDecorator` class in favor of `ChildDefinition`

3.2.0
Expand Down
25 changes: 25 additions & 0 deletions src/Symfony/Component/DependencyInjection/ChildDefinition.php
Expand Up @@ -22,6 +22,7 @@
class ChildDefinition extends Definition
{
private $parent;
private $inheritTags = false;
private $changes = array();

/**
Expand Down Expand Up @@ -54,6 +55,30 @@ public function getChanges()
return $this->changes;
}

/**
* Sets whether tags should be inherited from the parent or not.
*
* @param bool $boolean
*
* @return $this
*/
public function setInheritTags($boolean)
{
$this->inheritTags = (bool) $boolean;

return $this;
}

/**
* Returns whether tags should be inherited from the parent or not.
*
* @return bool
*/
public function getInheritTags()
{
return $this->inheritTags;
}

/**
* {@inheritdoc}
*/
Expand Down
Expand Up @@ -216,6 +216,15 @@ private function doResolveDefinition(ContainerBuilder $container, ChildDefinitio
$def->setShared($definition->isShared());
$def->setTags($definition->getTags());

// append parent tags when inheriting is enabled
if ($definition->getInheritTags()) {
foreach ($parentDef->getTags() as $k => $v) {
foreach ($v as $v) {
$def->addTag($k, $v);
}
}
}

return $def;
}
}
20 changes: 18 additions & 2 deletions src/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php
Expand Up @@ -150,6 +150,9 @@ private function getServiceDefaults(\DOMDocument $xml, $file)
if ($defaultsNode->hasAttribute('public')) {
$defaults['public'] = XmlUtils::phpize($defaultsNode->getAttribute('public'));
}
if ($defaultsNode->hasAttribute('inherit-tags')) {
$defaults['inherit-tags'] = XmlUtils::phpize($defaultsNode->getAttribute('inherit-tags'));
}
if (!$defaultsNode->hasAttribute('autowire')) {
foreach ($defaults['autowire'] as $k => $v) {
$defaults['autowire'][$k] = $v->textContent;
Expand Down Expand Up @@ -194,6 +197,12 @@ private function parseDefinition(\DOMElement $service, $file, array $defaults =

if ($parent = $service->getAttribute('parent')) {
$definition = new ChildDefinition($parent);

if ($value = $service->getAttribute('inherit-tags')) {
$definition->setInheritTags(XmlUtils::phpize($value));
} elseif (isset($defaults['inherit-tags'])) {
$definition->setInheritTags($defaults['inherit-tags']);
}
$defaults = array();
} else {
$definition = new Definition();
Expand Down Expand Up @@ -270,8 +279,15 @@ private function parseDefinition(\DOMElement $service, $file, array $defaults =
}

$tags = $this->getChildren($service, 'tag');
if (!$tags && !empty($defaults['tags'])) {
$tags = $defaults['tags'];

if (empty($defaults['tags'])) {
// no-op
} elseif (!$value = $service->getAttribute('inherit-tags')) {
if (!$tags) {
$tags = $defaults['tags'];
}
} elseif (XmlUtils::phpize($value)) {
$tags = array_merge($tags, $defaults['tags']);
}

foreach ($tags as $tag) {
Expand Down
Expand Up @@ -52,6 +52,7 @@ class YamlFileLoader extends FileLoader
'configurator' => 'configurator',
'calls' => 'calls',
'tags' => 'tags',
'inherit_tags' => 'inherit_tags',
'decorates' => 'decorates',
'decoration_inner_name' => 'decoration_inner_name',
'decoration_priority' => 'decoration_priority',
Expand Down Expand Up @@ -156,7 +157,7 @@ private function parseDefinitions($content, $file)
@trigger_error('Giving a service the "_defaults" name is deprecated since Symfony 3.3 and will be forbidden in 4.0. Rename your service.', E_USER_DEPRECATED);
$defaults = array();
} else {
$defaultKeys = array('public', 'tags', 'autowire');
$defaultKeys = array('public', 'tags', 'inherit_tags', 'autowire');
unset($content['services']['_defaults']);

foreach ($defaults as $key => $default) {
Expand Down Expand Up @@ -240,6 +241,11 @@ private function parseDefinition($id, $service, $file, array $defaults)

if (isset($service['parent'])) {
$definition = new ChildDefinition($service['parent']);

$inheritTag = isset($service['inherit_tags']) ? $service['inherit_tags'] : (isset($defaults['inherit_tags']) ? $defaults['inherit_tags'] : null);
if (null !== $inheritTag) {
$definition->setInheritTags($inheritTag);
}
$defaults = array();
} else {
$definition = new Definition();
Expand Down Expand Up @@ -312,7 +318,18 @@ private function parseDefinition($id, $service, $file, array $defaults)
}
}

$tags = isset($service['tags']) ? $service['tags'] : (isset($defaults['tags']) ? $defaults['tags'] : null);
$tags = isset($service['tags']) ? $service['tags'] : array();

if (!isset($defaults['tags'])) {
// no-op
} elseif (!isset($service['inherit_tags'])) {
if (!isset($service['tags'])) {
$tags = $defaults['tags'];
}
} elseif ($service['inherit_tags']) {
$tags = array_merge($tags, $defaults['tags']);
}

if (null !== $tags) {
if (!is_array($tags)) {
throw new InvalidArgumentException(sprintf('Parameter "tags" must be an array for service "%s" in %s. Check your YAML syntax.', $id, $file));
Expand Down
Expand Up @@ -102,6 +102,7 @@
</xsd:choice>
<xsd:attribute name="public" type="boolean" />
<xsd:attribute name="autowire" type="boolean" />
<xsd:attribute name="inherit-tags" type="boolean" />
</xsd:complexType>

<xsd:complexType name="service">
Expand Down Expand Up @@ -130,6 +131,7 @@
<xsd:attribute name="decoration-inner-name" type="xsd:string" />
<xsd:attribute name="decoration-priority" type="xsd:integer" />
<xsd:attribute name="autowire" type="boolean" />
<xsd:attribute name="inherit-tags" type="boolean" />
</xsd:complexType>

<xsd:complexType name="tag">
Expand Down
Expand Up @@ -6,12 +6,13 @@
</defaults>

<service id="with_defaults" class="Foo" />
<service id="no_defaults" class="Foo" public="true" autowire="false">
<tag name="bar" />
<service id="no_defaults" class="Foo" public="true" autowire="false" inherit-tags="false">
</service>
<service id="no_defaults_child" class="Foo" parent="no_defaults">
<tag name="bar" />
</service>
<service id="with_defaults_child" class="Foo" parent="with_defaults" />
<service id="with_defaults_child" class="Foo" parent="with_defaults" public="true" inherit-tags="true">
<tag name="baz" />
</service>
</services>
</container>
Expand Up @@ -10,9 +10,9 @@ services:

with_null:
class: Foo
public: ~
public: true
autowire: ~
tags: ~
inherit_tags: false

no_defaults:
class: Foo
Expand All @@ -28,3 +28,7 @@ services:

with_defaults_child:
parent: with_defaults
public: true
inherit_tags: true
tags:
- name: baz
Expand Up @@ -625,19 +625,23 @@ public function testDefaults()
$loader->load('services29.xml');

$this->assertFalse($container->getDefinition('with_defaults')->isPublic());
$this->assertSame(array('foo' => array(array())), $container->getDefinition('with_defaults')->getTags());
$this->assertTrue($container->getDefinition('with_defaults')->isAutowired());

$this->assertArrayNotHasKey('public', $container->getDefinition('no_defaults_child')->getChanges());
$this->assertArrayNotHasKey('autowire', $container->getDefinition('no_defaults_child')->getChanges());

$container->compile();

$this->assertTrue($container->getDefinition('no_defaults')->isPublic());
$this->assertTrue($container->getDefinition('no_defaults_child')->isPublic());
$this->assertArrayNotHasKey('public', $container->getDefinition('no_defaults_child')->getChanges());

$this->assertSame(array('foo' => array(array())), $container->getDefinition('with_defaults')->getTags());
$this->assertSame(array('bar' => array(array())), $container->getDefinition('no_defaults')->getTags());
$this->assertSame(array(), $container->getDefinition('no_defaults')->getTags());
$this->assertSame(array('bar' => array(array())), $container->getDefinition('no_defaults_child')->getTags());
$this->assertSame(array(), $container->getDefinition('with_defaults_child')->getTags());
$this->assertSame(array('baz' => array(array()), 'foo' => array(array())), $container->getDefinition('with_defaults_child')->getTags());

$this->assertTrue($container->getDefinition('with_defaults')->isAutowired());
$this->assertFalse($container->getDefinition('no_defaults')->isAutowired());
$this->assertFalse($container->getDefinition('no_defaults_child')->isAutowired());
$this->assertArrayNotHasKey('autowire', $container->getDefinition('no_defaults_child')->getChanges());
}

public function testDefaultsWithAutowiredMethods()
Expand Down
Expand Up @@ -359,22 +359,26 @@ public function testDefaults()
$loader->load('services28.yml');

$this->assertFalse($container->getDefinition('with_defaults')->isPublic());
$this->assertFalse($container->getDefinition('with_null')->isPublic());
$this->assertSame(array('foo' => array(array())), $container->getDefinition('with_defaults')->getTags());
$this->assertTrue($container->getDefinition('with_defaults')->isAutowired());

$this->assertArrayNotHasKey('public', $container->getDefinition('no_defaults_child')->getChanges());
$this->assertArrayNotHasKey('autowire', $container->getDefinition('no_defaults_child')->getChanges());

$container->compile();

$this->assertTrue($container->getDefinition('with_null')->isPublic());
$this->assertTrue($container->getDefinition('no_defaults')->isPublic());
$this->assertTrue($container->getDefinition('no_defaults_child')->isPublic());
$this->assertArrayNotHasKey('public', $container->getDefinition('no_defaults_child')->getChanges());

$this->assertSame(array('foo' => array(array())), $container->getDefinition('with_defaults')->getTags());
$this->assertSame(array('foo' => array(array())), $container->getDefinition('with_null')->getTags());
$this->assertSame(array(), $container->getDefinition('with_null')->getTags());
$this->assertSame(array(), $container->getDefinition('no_defaults')->getTags());
$this->assertSame(array('bar' => array(array())), $container->getDefinition('no_defaults_child')->getTags());
$this->assertSame(array(), $container->getDefinition('with_defaults_child')->getTags());
$this->assertSame(array('baz' => array(array()), 'foo' => array(array())), $container->getDefinition('with_defaults_child')->getTags());

$this->assertTrue($container->getDefinition('with_defaults')->isAutowired());
$this->assertTrue($container->getDefinition('with_null')->isAutowired());
$this->assertFalse($container->getDefinition('no_defaults')->isAutowired());
$this->assertFalse($container->getDefinition('no_defaults_child')->isAutowired());
$this->assertArrayNotHasKey('autowire', $container->getDefinition('no_defaults_child')->getChanges());
}

/**
Expand Down

0 comments on commit beec1cf

Please sign in to comment.