8000 Apply attribute configurator to child classes · symfony/symfony@2390a26 · GitHub
[go: up one dir, main page]

Skip to content

Commit 2390a26

Browse files
committed
Apply attribute configurator to child classes
1 parent 759b6e1 commit 2390a26

File tree

3 files changed

+60
-5
lines changed

3 files changed

+60
-5
lines changed

src/Symfony/Component/DependencyInjection/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ CHANGELOG
99
* Have `ServiceLocator` implement `ServiceCollectionInterface`
1010
* Add `#[Lazy]` attribute as shortcut for `#[Autowire(lazy: [bool|string])]` and `#[Autoconfigure(lazy: [bool|string])]`
1111
* Add `#[AutowireMethodOf]` attribute to autowire a method of a service as a callable
12+
* `ContainerBuilder::registerAttributeForAutoconfiguration()` is applied to child classes for the autoconfigured attribute, except there is another autoconfiguration for this child attribute class.
1213

1314
7.0
1415
---

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

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ protected function processValue(mixed $value, bool $isRoot = false): mixed
9696

9797
if ($this->classAttributeConfigurators) {
9898
foreach ($classReflector->getAttributes() as $attribute) {
99-
if ($configurator = $this->classAttributeConfigurators[$attribute->getName()] ?? null) {
99+
if ($configurator = $this->findConfigurator($this->classAttributeConfigurators, $attribute->getName())) {
100100
$configurator($conditionals, $attribute->newInstance(), $classReflector);
101101
}
102102
}
@@ -112,7 +112,7 @@ protected function processValue(mixed $value, bool $isRoot = false): mixed
112112
if ($constructorReflector) {
113113
foreach ($constructorReflector->getParameters() as $parameterReflector) {
114114
foreach ($parameterReflector->getAttributes() as $attribute) {
115-
if ($configurator = $this->parameterAttributeConfigurators[$attribute->getName()] ?? null) {
115+
if ($configurator = $this->findConfigurator($this->parameterAttributeConfigurators, $attribute->getName())) {
116116
$configurator($conditionals, $attribute->newInstance(), $parameterReflector);
117117
}
118118
}
@@ -128,7 +128,7 @@ protected function processValue(mixed $value, bool $isRoot = false): mixed
128128

129129
if ($this->methodAttributeConfigurators) {
130130
foreach ($methodReflector->getAttributes() as $attribute) {
131-
if ($configurator = $this->methodAttributeConfigurators[$attribute->getName()] ?? null) {
131+
if ($configurator = $this->findConfigurator($this->methodAttributeConfigurators, $attribute->getName())) {
132132
$configurator($conditionals, $attribute->newInstance(), $methodReflector);
133133
}
134134
}
@@ -137,7 +137,7 @@ protected function processValue(mixed $value, bool $isRoot = false): mixed
137137
if ($this->parameterAttributeConfigurators) {
138138
foreach ($methodReflector->getParameters() as $parameterReflector) {
139139
foreach ($parameterReflector->getAttributes() as $attribute) {
140-
if ($configurator = $this->parameterAttributeConfigurators[$attribute->getName()] ?? null) {
140+
if ($configurator = $this->findConfigurator($this->parameterAttributeConfigurators, $attribute->getName())) {
141141
$configurator($conditionals, $attribute->newInstance(), $parameterReflector);
142142
}
143143
}
@@ -153,7 +153,7 @@ protected function processValue(mixed $value, bool $isRoot = false): mixed
153153
}
154154

155155
foreach ($propertyReflector->getAttributes() as $attribute) {
156-
if ($configurator = $this->propertyAttributeConfigurators[$attribute->getName()] ?? null) {
156+
if ($configurator = $this->findConfigurator($this->propertyAttributeConfigurators, $attribute->getName())) {
157157
$configurator($conditionals, $attribute->newInstance(), $propertyReflector);
158158
}
159159
}
@@ -167,4 +167,23 @@ protected function processValue(mixed $value, bool $isRoot = false): mixed
167167

168168
return parent::processValue($value, $isRoot);
169169
}
170+
171+
/**
172+
* Looks for a configurator for the given attribute name in the given configurators array.
173+
* If no configurator is found, the parent class is checked.
174+
* If no configurator is found, null is returned.
175+
* The result is cached in the configurators array passed by reference.
176+
*/
177+
private function findConfigurator(array &$configurators, string $attributeName): ?callable
178+
{
179+
if (\array_key_exists($attributeName, $configurators)) {
180+
return $configurators[$attributeName];
181+
}
182+
183+
if (class_exists($attributeName) && $parent = get_parent_class($attributeName)) {
184+
return $configurators[$attributeName] = self::findConfigurator($configurators, $parent);
185+
}
186+
187+
return $configurators[$attributeName] = null;
188+
}
170189
}

src/Symfony/Component/DependencyInjection/Tests/Compiler/AttributeAutoconfigurationPassTest.php

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,4 +45,39 @@ public function testAttributeConfiguratorCallableMissingType()
4545
$this->expectExceptionMessage('Argument "$reflector" of attribute autoconfigurator should have a type, use one or more of "\ReflectionClass|\ReflectionMethod|\ReflectionProperty|\ReflectionParameter|\Reflector" in ');
4646
(new AttributeAutoconfigurationPass())->process($container);
4747
}
48+
49+
public function testCallNearestParentConfigurator()
50+
{
51+
$calls = [];
52+
$container = new ContainerBuilder();
53+
$container->registerAttributeForAutoconfiguration(AsTaggedItem::class, function (ChildDefinition $definition, AsTaggedItem $attribute, \ReflectionClass $reflector) use (&$calls) {
54+
$calls[] = $attribute;
55+
});
56+
$container->register('foo', ServiceTaggedWithFooIndex::class)
57+
->setAutoconfigured(true)
58+
;
59+
60+
(new AttributeAutoconfigurationPass())->process($container);
61+
62+
$this->assertSame([], $container->getDefinition('foo')->getInstanceofConditionals());
63+
$this->assertCount(1, $calls);
64+
}
65+
}
66+
67+
#[\Attribute(\Attribute::TARGET_CLASS)]
68+
class AsTaggedItemWithFooIndex extends AsTaggedItem
69+
{
70+
public function __construct(
71+
?int $priority = null,
72+
) {
73+
parent::__construct(
74+
index: 'foo',
75+
priority: $priority
76+
);
77+
}
78+
}
79+
80+
#[AsTaggedItemWithFooIndex]
81+
class ServiceTaggedWithFooIndex
82+
{
4883
}

0 commit comments

Comments
 (0)
0