Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 69dc71b

Browse files
GromNaNfabpot
authored andcommitted
[DependencyInjection] Apply attribute configurator to child classes
1 parent 759b6e1 commit 69dc71b

File tree

7 files changed

+86
-9
lines changed

7 files changed

+86
-9
lines changed

src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php

+3-3
Original file line numberDiff line numberDiff line change
@@ -699,9 +699,9 @@ public function load(array $configs, ContainerBuilder $container): void
699699
$taskAttributeClass,
700700
static function (ChildDefinition $definition, AsPeriodicTask|AsCronTask $attribute, \ReflectionClass|\ReflectionMethod $reflector): void {
701701
$tagAttributes = get_object_vars($attribute) + [
702-
'trigger' => match ($attribute::class) {
703-
AsPeriodicTask::class => 'every',
704-
AsCronTask::class => 'cron',
702+
'trigger' => match (true) {
703+
$attribute instanceof AsPeriodicTask => 'every',
704+
$attribute instanceof AsCronTask => 'cron',
705705
},
706706
];
707707
if ($reflector instanceof \ReflectionMethod) {

src/Symfony/Component/DependencyInjection/CHANGELOG.md

+1
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+
* Make `ContainerBuilder::registerAttributeForAutoconfiguration()` propagate to attribute classes that extend the registered class
1213

1314
7.0
1415
---

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

+21-5
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,20 @@ protected function processValue(mixed $value, bool $isRoot = false): mixed
167167

168168
return parent::processValue($value, $isRoot);
169169
}
170+
171+
/**
172+
* Find the first configurator for the given attribute name, looking up the class hierarchy.
173+
*/
174+
private function findConfigurator(array &$configurators, string $attributeName): ?callable
175+
{
176+
if (\array_key_exists($attributeName, $configurators)) {
177+
return $configurators[$attributeName];
178+
}
179+
180+
if (class_exists($attributeName) && $parent = get_parent_class($attributeName)) {
181+
return $configurators[$attributeName] = self::findConfigurator($configurators, $parent);
182+
}
183+
184+
return $configurators[$attributeName] = null;
185+
}
170186
}

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

+11
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@
5757
use Symfony\Component\DependencyInjection\Tests\Fixtures\TaggedService3;
5858
use Symfony\Component\DependencyInjection\Tests\Fixtures\TaggedService3Configurator;
5959
use Symfony\Component\DependencyInjection\Tests\Fixtures\TaggedService4;
60+
use Symfony\Component\DependencyInjection\Tests\Fixtures\TaggedService5;
6061
use Symfony\Contracts\Service\Attribute\SubscribedService;
6162
use Symfony\Contracts\Service\ServiceProviderInterface;
6263
use Symfony\Contracts\Service\ServiceSubscriberInterface;
@@ -993,6 +994,10 @@ static function (ChildDefinition $definition, CustomAnyAttribute $attribute, \Re
993994
->setPublic(true)
994995
->setAutoconfigured(true);
995996

997+
$container->register(TaggedService5::class)
998+
->setPublic(true)
999+
->setAutoconfigured(true);
1000+
9961001
$container->register('failing_factory', \stdClass::class);
9971002
$container->register('ccc', TaggedService4::class)
9981003
->setFactory([new Reference('failing_factory'), 'create'])
@@ -1018,6 +1023,12 @@ static function (ChildDefinition $definition, CustomAnyAttribute $attribute, \Re
10181023
['property' => 'name'],
10191024
['someAttribute' => 'on name', 'priority' => 0, 'property' => 'name'],
10201025
],
1026+
TaggedService5::class => [
1027+
['class' => TaggedService5::class],
1028+
['parameter' => 'param1'],
1029+
['method' => 'fooAction'],
1030+
['property' => 'name'],
1031+
],
10211032
'ccc' => [
10221033
['class' => TaggedService4::class],
10231034
['method' => 'fooAction'],

src/Symfony/Component/DependencyInjection/Tests/Fixtures/Attribute/CustomAnyAttribute.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,6 @@
1212
namespace Symfony\Component\DependencyInjection\Tests\Fixtures\Attribute;
1313

1414
#[\Attribute(\Attribute::TARGET_CLASS | \Attribute::TARGET_METHOD | \Attribute::TARGET_PROPERTY | \Attribute::TARGET_PARAMETER)]
15-
final class CustomAnyAttribute
15+
class CustomAnyAttribute
1616
{
1717
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <[email protected]>
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\Tests\Fixtures\Attribute;
13+
14+
#[\Attribute(\Attribute::TARGET_CLASS | \Attribute::TARGET_METHOD | \Attribute::TARGET_PROPERTY | \Attribute::TARGET_PARAMETER)]
15+
class CustomChildAttribute extends CustomAnyAttribute
16+
{
17+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <[email protected]>
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\Tests\Fixtures;
13+
14+
use Symfony\Component\DependencyInjection\Tests\Fixtures\Attribute\CustomChildAttribute;
15+
16+
#[CustomChildAttribute]
17+
final class TaggedService5
18+
{
19+
#[CustomChildAttribute]
20+
public string $name;
21+
22+
public function __construct(
23+
#[CustomChildAttribute]
24+
private string $param1,
25+
) {}
26+
27+
#[CustomChildAttribute]
28+
public function fooAction(
29+
#[CustomChildAttribute]
30+
string $param1
31+
) {}
32+
}

0 commit comments

Comments
 (0)