8000 [DI] Rework config hierarchy: defaults > instanceof > service config · symfony/symfony@6fb83a1 · GitHub
[go: up one dir, main page]

Skip to content

Commit 6fb83a1

Browse files
[DI] Rework config hierarchy: defaults > instanceof > service config
1 parent f02a4c8 commit 6fb83a1

8 files changed

+297
-276
lines changed

src/Symfony/Component/DependencyInjection/Compiler/PassConfig.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,8 @@ public function __construct()
4242
$this->beforeOptimizationPasses = array(
4343
100 => array(
4444
$resolveClassPass = new ResolveClassPass(),
45-
new ResolveDefinitionInheritancePass(),
45+
new ResolveInstanceofConditionalsPass(),
46+
new ResolveTagsInheritancePass(),
4647
),
4748
);
4849

src/Symfony/Component/DependencyInjection/Compiler/ResolveDefinitionInheritancePass.php

Lines changed: 0 additions & 99 deletions
This file was deleted.

src/Symfony/Component/DependencyInjection/Compiler/ResolveDefinitionTemplatesPass.php

Lines changed: 16 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ private function doResolveDefinition(ChildDefinition $definition)
8484
$def = new Definition();
8585

8686
// merge in parent definition
87-
// purposely ignored attributes: abstract, tags
87+
// purposely ignored attributes: abstract, shared, tags
8888
$def->setClass($parentDef->getClass());
8989
$def->setArguments($parentDef->getArguments());
9090
$def->setMethodCalls($parentDef->getMethodCalls());
@@ -101,27 +101,8 @@ private function doResolveDefinition(ChildDefinition $definition)
101101
$def->setPublic($parentDef->isPublic());
102102
$def->setLazy($parentDef->isLazy());
103103
$def->setAutowired($parentDef->isAutowired());
104+
$def->setChanges($parentDef->getChanges());
104105

105-
self::mergeDefinition($def, $definition);
106-
107-
// merge autowiring types
108-
foreach ($definition->getAutowiringTypes(false) as $autowiringType) {
109-
$def->addAutowiringType($autowiringType);
110-
}
111-
112-
// these attributes are always taken from the child
113-
$def->setAbstract($definition->isAbstract());
114-
$def->setShared($definition->isShared());
115-
$def->setTags($definition->getTags());
116-
117-
return $def;
118-
}
119-
120-
/**
121-
* @internal
122-
*/
123-
public static function mergeDefinition(Definition $def, ChildDefinition $definition)
124-
{
125106
// overwrite with values specified in the decorator
126107
$changes = $definition->getChanges();
127108
if (isset($changes['class'])) {
@@ -148,6 +129,9 @@ public static function mergeDefinition(Definition $def, ChildDefinition $definit
148129
if (isset($changes['autowired'])) {
149130
$def->setAutowired($definition->isAutowired());
150131
}
132+
if (isset($changes['shared'])) {
133+
$def->setShared($definition->isShared());
134+
}
151135
if (isset($changes['decorated_service'])) {
152136
$decoratedService = $definition->getDecoratedService();
153137
if (null === $decoratedService) {
@@ -182,5 +166,16 @@ public static function mergeDefinition(Definition $def, ChildDefinition $definit
182166
if ($calls = $definition->getMethodCalls()) {
183167
$def->setMethodCalls(array_merge($def->getMethodCalls(), $calls));
184168
}
169+
170+
// merge autowiring types
171+
foreach ($definition->getAutowiringTypes(false) as $autowiringType) {
172+
$def->addAutowiringType($autowiringType);
173+
}
174+
175+
// these attributes are always taken from the child
176+
$def->setAbstract($definition->isAbstract());
177+
$def->setTags($definition->getTags());
178+
179+
return $def;
185180
}
186181
}
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\DependencyInjection\Compiler;
13+
14+
use Symfony\Component\DependencyInjection\ChildDefinition;
15+
use Symfony\Component\DependencyInjection\ContainerBuilder;
16+
use Symfony\Component\DependencyInjection\Definition;
17+
18+
/**
19+
* Applies instanceof conditionals to definitions.
20+
*
21+
* @author Nicolas Grekas <p@tchwork.com>
22+
*/
23+
class ResolveInstanceofConditionalsPass implements CompilerPassInterface
24+
{
25+
/**
26+
* {@inheritdoc}
27+
*/
28+
public function process(ContainerBuilder $container)
29+
{
30+
$didProcess = false;
31+
foreach ($container->getDefinitions() as $id => $definition) {
32+
if ($definition instanceof ChildDefinition) {
33+
continue;
34+
}
35+
if ($definition !== $processedDefinition = $this->processDefinition($container, $id, $definition)) {
36+
$didProcess = true;
37+
$container->setDefinition($id, $processedDefinition);
38+
}
39+
}
40+
if ($didProcess) {
41+
$container->register('abstract.'.__CLASS__, '')->setAbstract(true);
42+
}
43+
}
44+
45+
private function processDefinition(ContainerBuilder $container, $id, Definition $definition)
46+
{
47+
if (!$instanceofConditionals = $definition->getInstanceofConditionals()) {
48+
return $definition;
49+
}
50+
if (!$class = $container->getParameterBag()->resolveValue($definition->getClass())) {
51+
return $definition;
52+
}
53+
54+
$definition->setInstanceofConditionals(array());
55+
$instanceofParent = null;
56+
$parent = 'abstract.'.__CLASS__;
57+
$shared = null;
58+
59+
foreach ($instanceofConditionals as $interface => $instanceofDef) {
60+
if ($interface !== $class && (!$container->getReflectionClass($interface) || !$container->getReflectionClass($class))) {
61+
continue;
62+
}
63+
if ($interface === $class || is_subclass_of($class, $interface)) {
64+
$instanceofParent = clone $instanceofDef;
65+
$instanceofParent->setAbstract(true)->setInheritTags(true)->setParent($parent);
66+
$parent = 'instanceof.'.$interface.'.'.$id;
67+
$container->setDefinition($parent, $instanceofParent);
68+
69+
if (isset($instanceofParent->getChanges()['shared'])) {
70+
$shared = $instanceofParent->isShared();
71+
}
72+
}
73+
}
74+
75+
if ($instanceofParent) {
76+
// cast Definition to ChildDefinition
77+
$definition = serialize($definition);
78+
$definition = substr_replace($definition, '53', 2, 2);
79+
$definition = substr_replace($definition, 'Child', 44, 0);
80+
$definition = unserialize($definition);
81+
$definition->setInheritTags(true)->setParent($parent);
82+
83+
if (null !== $shared && !isset($definition->getChanges()['shared'])) {
84+
$definition->setShared($shared);
85+
}
86+
}
87+
88+
return $definition;
89+
}
90+
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\DependencyInjection\Compiler;
13+
14+
use Symfony\Component\DependencyInjection\ChildDefinition;
15+
16+
/**
17+
* Applies tags inheritance to definitions.
18+
*
19+
* @author Nicolas Grekas <p@tchwork.com>
20+
*/
21+
class ResolveTagsInheritancePass extends AbstractRecursivePass
22+
{
23+
/**
24+
* {@inheritdoc}
25+
*/
26+
protected function processValue($value, $isRoot = false)
27+
{
28+
if (!$value instanceof ChildDefinition || !$value->getInheritTags()) {
29+
return parent::processValue($value, $isRoot);
30+
}
31+
$value->setInheritTags(false);
32+
33+
if (!$this->container->has($parent = $value->getParent())) {
34+
return parent::processValue($value, $isRoot);
35+
}
36+
37+
$parentDef = $this->container->findDefinition($parent);
38+
39+
if ($parentDef instanceof ChildDefinition) {
40+
$this->processValue($parentDef);
41+
}
42+
43+
foreach ($parentDef->getTags() as $k => $v) {
44+
foreach ($v as $v) {
45+
$value->addTag($k, $v);
46+
}
47+
}
48+
49+
return parent::processValue($value, $isRoot);
50+
}
51+
}

0 commit comments

Comments
 (0)
0