Skip to content

Commit b38d2ae

Browse files
[DependencyInjection] Deprecate default index/priority methods when defining tagged locators/iterators
1 parent 42a8072 commit b38d2ae

27 files changed

+294
-71
lines changed

UPGRADE-7.4.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ DependencyInjection
5252
+ ],
5353
+]);
5454
```
55+
* Deprecate default index/priority methods when defining tagged locators/iterators; use the `#[AsTaggedItem]` attribute instead
5556

5657
DoctrineBridge
5758
--------------

src/Symfony/Component/DependencyInjection/Argument/TaggedIteratorArgument.php

Lines changed: 37 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -21,34 +21,43 @@ class TaggedIteratorArgument extends IteratorArgument
2121
private mixed $indexAttribute = null;
2222
private ?string $defaultIndexMethod = null;
2323
private ?string $defaultPriorityMethod = null;
24+
private bool $needsIndexes = false;
25+
private array $exclude = [];
26+
private bool $excludeSelf = true;
2427

2528
/**
26-
* @param string $tag The name of the tag identifying the target services
27-
* @param string|null $indexAttribute The name of the attribute that defines the key referencing each service in the tagged collection
28-
* @param string|null $defaultIndexMethod The static method that should be called to get each service's key when their tag doesn't define the previous attribute
29-
* @param bool $needsIndexes Whether indexes are required and should be generated when computing the map
30-
* @param string|null $defaultPriorityMethod The static method that should be called to get each service's priority when their tag doesn't define the "priority" attribute
31-
* @param array $exclude Services to exclude from the iterator
32-
* @param bool $excludeSelf Whether to automatically exclude the referencing service from the iterator
29+
* @param string $tag The name of the tag identifying the target services
30+
* @param string|null $indexAttribute The name of the attribute that defines the key referencing each service in the tagged collection
31+
* @param bool $needsIndexes Whether indexes are required and should be generated when computing the map
32+
* @param string[] $exclude Services to exclude from the iterator
33+
* @param bool $excludeSelf Whether to automatically exclude the referencing service from the iterator
3334
*/
3435
public function __construct(
3536
private string $tag,
3637
?string $indexAttribute = null,
37-
?string $defaultIndexMethod = null,
38-
private bool $needsIndexes = false,
39-
?string $defaultPriorityMethod = null,
40-
private array $exclude = [],
41-
private bool $excludeSelf = true,
38+
bool|string|null $needsIndexes = false,
39+
array|bool $exclude = [],
40+
bool|string|null $excludeSelf = true,
4241
) {
4342
parent::__construct([]);
4443

44+
if (\func_num_args() > 5 || !\is_bool($needsIndexes) || !\is_array($exclude) || !\is_bool($excludeSelf)) {
45+
[, , $defaultIndexMethod, $needsIndexes, $defaultPriorityMethod, $exclude, $excludeSelf] = \func_get_args() + [2 => null, false, null, [], true];
46+
trigger_deprecation('symfony/dependency-injection', '7.4', 'The $defaultIndexMethod and $defaultPriorityMethod arguments of tagged locators and iterators are deprecated, use the #[AsTaggedItem] attribute instead.');
47+
} else {
48+
$defaultIndexMethod = $defaultPriorityMethod = false;
49+
}
50+
4551
if (null === $indexAttribute && $needsIndexes) {
4652
$indexAttribute = preg_match('/[^.]++$/', $tag, $m) ? $m[0] : $tag;
4753
}
4854

4955
$this->indexAttribute = $indexAttribute;
5056
$this->defaultIndexMethod = $defaultIndexMethod ?: ($indexAttribute ? 'getDefault'.str_replace(' ', '', ucwords(preg_replace('/[^a-zA-Z0-9\x7f-\xff]++/', ' ', $indexAttribute))).'Name' : null);
5157
$this->defaultPriorityMethod = $defaultPriorityMethod ?: ($indexAttribute ? 'getDefault'.str_replace(' ', '', ucwords(preg_replace('/[^a-zA-Z0-9\x7f-\xff]++/', ' ', $indexAttribute))).'Priority' : null);
58+
$this->needsIndexes = $needsIndexes;
59+
$this->exclude = $exclude;
60+
$this->excludeSelf = $excludeSelf;
5261
}
5362

5463
public function getTag(): string
@@ -61,8 +70,15 @@ public function getIndexAttribute(): ?string
6170
return $this->indexAttribute;
6271
}
6372

64-
public function getDefaultIndexMethod(): ?string
73+
/**
74+
* @deprecated since Symfony 7.4, use the #[AsTaggedItem] attribute instead of default methods
75+
*/
76+
public function getDefaultIndexMethod(/* bool $triggerDeprecation = true */): ?string
6577
{
78+
if (!\func_num_args() || func_get_arg(0)) {
79+
trigger_deprecation('symfony/dependency-injection', '7.4', 'The "%s()" method is deprecated, use the #[AsTaggedItem] attribute instead of default methods.', __METHOD__);
80+
}
81+
6682
return $this->defaultIndexMethod;
6783
}
6884

@@ -71,8 +87,15 @@ public function needsIndexes(): bool
7187
return $this->needsIndexes;
7288
}
7389

74-
public function getDefaultPriorityMethod(): ?string
90+
/**
91+
* @deprecated since Symfony 7.4, use the #[AsTaggedItem] attribute instead of default methods
92+
*/
93+
public function getDefaultPriorityMethod(/* bool $triggerDeprecation = true */): ?string
7594
{
95+
if (!\func_num_args() || func_get_arg(0)) {
96+
trigger_deprecation('symfony/dependency-injection', '7.4', 'The "%s()" method is deprecated, use the #[AsTaggedItem] attribute instead of default methods.', __METHOD__);
97+
}
98+
7699
return $this->defaultPriorityMethod;
77100
}
78101

src/Symfony/Component/DependencyInjection/Attribute/AutowireIterator.php

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -22,21 +22,31 @@ class AutowireIterator extends Autowire
2222
/**
2323
* @see ServiceSubscriberInterface::getSubscribedServices()
2424
*
25-
* @param string $tag A tag name to search for to populate the iterator
26-
* @param string|null $indexAttribute The name of the attribute that defines the key referencing each service in the tagged collection
27-
* @param string|null $defaultIndexMethod The static method that should be called to get each service's key when their tag doesn't define the previous attribute
28-
* @param string|null $defaultPriorityMethod The static method that should be called to get each service's priority when their tag doesn't define the "priority" attribute
29-
* @param string|array<string> $exclude A service id or a list of service ids to exclude
30-
* @param bool $excludeSelf Whether to automatically exclude the referencing service from the iterator
25+
* @param string $tag A tag name to search for to populate the iterator
26+
* @param string|null $indexAttribute The name of the attribute that defines the key referencing each service in the tagged collection
27+
* @param string|string[] $exclude A service id or a list of service ids to exclude
28+
* @param bool $excludeSelf Whether to automatically exclude the referencing service from the iterator
3129
*/
3230
public function __construct(
3331
string $tag,
3432
?string $indexAttribute = null,
35-
?string $defaultIndexMethod = null,
36-
?string $defaultPriorityMethod = null,
37-
string|array $exclude = [],
38-
bool $excludeSelf = true,
33+
string|array|null $exclude = [],
34+
bool|string|null $excludeSelf = true,
35+
...$_,
3936
) {
40-
parent::__construct(new TaggedIteratorArgument($tag, $indexAttribute, $defaultIndexMethod, false, $defaultPriorityMethod, (array) $exclude, $excludeSelf));
37+
if (\func_num_args() > 4 || !\is_bool($excludeSelf) || null === $exclude || (\is_string($exclude) && str_starts_with($exclude, 'get') && !\array_key_exists('defaultIndexMethod', $_))) {
38+
[, , $defaultIndexMethod, $defaultPriorityMethod, $exclude, $excludeSelf] = \func_get_args() + [2 => null, null, [], true];
39+
} else {
40+
$defaultIndexMethod = \array_key_exists('defaultIndexMethod', $_) ? $_['defaultIndexMethod'] : false;
41+
$defaultPriorityMethod = \array_key_exists('defaultPriorityMethod', $_) ? $_['defaultPriorityMethod'] : false;
42+
}
43+
44+
if (false !== $defaultIndexMethod || false !== $defaultPriorityMethod) {
45+
parent::__construct(new TaggedIteratorArgument($tag, $indexAttribute, $defaultIndexMethod, false, $defaultPriorityMethod, (array) $exclude, $excludeSelf));
46+
47+
return;
48+
}
49+
50+
parent::__construct(new TaggedIteratorArgument($tag, $indexAttribute, false, (array) $exclude, $excludeSelf));
4151
}
4252
}

src/Symfony/Component/DependencyInjection/Attribute/AutowireLocator.php

Lines changed: 23 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -28,26 +28,38 @@ class AutowireLocator extends Autowire
2828
/**
2929
* @see ServiceSubscriberInterface::getSubscribedServices()
3030
*
31-
* @param string|array<string|Autowire|SubscribedService> $services A tag name or an explicit list of service ids
32-
* @param string|null $indexAttribute The name of the attribute that defines the key referencing each service in the locator
33-
* @param string|null $defaultIndexMethod The static method that should be called to get each service's key when their tag doesn't define the previous attribute
34-
* @param string|null $defaultPriorityMethod The static method that should be called to get each service's priority when their tag doesn't define the "priority" attribute
35-
* @param string|array $exclude A service id or a list of service ids to exclude
36-
* @param bool $excludeSelf Whether to automatically exclude the referencing service from the locator
31+
* @param string|array<string|Autowire|SubscribedService> $services A tag name or an explicit list of service ids
32+
* @param string|null $indexAttribute The name of the attribute that defines the key referencing each service in the locator
33+
* @param string|string[] $exclude A service id or a list of service ids to exclude
34+
* @param bool $excludeSelf Whether to automatically exclude the referencing service from the locator
3735
*/
3836
public function __construct(
3937
string|array $services,
4038
?string $indexAttribute = null,
41-
?string $defaultIndexMethod = null,
42-
?string $defaultPriorityMethod = null,
43-
string|array $exclude = [],
44-
bool $excludeSelf = true,
39+
string|array|null $exclude = [],
40+
bool|string|null $excludeSelf = true,
41+
...$_,
4542
) {
43+
if (\func_num_args() > 4 || !\is_bool($excludeSelf) || null === $exclude || (\is_string($exclude) && str_starts_with($exclude, 'get') && !\array_key_exists('defaultIndexMethod', $_))) {
44+
[, , $defaultIndexMethod, $defaultPriorityMethod, $exclude, $excludeSelf] = \func_get_args() + [2 => null, null, [], true];
45+
} else {
46+
$defaultIndexMethod = \array_key_exists('defaultIndexMethod', $_) ? $_['defaultIndexMethod'] : false;
47+
$defaultPriorityMethod = \array_key_exists('defaultPriorityMethod', $_) ? $_['defaultPriorityMethod'] : false;
48+
}
49+
4650
if (\is_string($services)) {
47-
parent::__construct(new ServiceLocatorArgument(new TaggedIteratorArgument($services, $indexAttribute, $defaultIndexMethod, true, $defaultPriorityMethod, (array) $exclude, $excludeSelf)));
51+
if (false !== $defaultIndexMethod || false !== $defaultPriorityMethod) {
52+
parent::__construct(new ServiceLocatorArgument(new TaggedIteratorArgument($services, $indexAttribute, $defaultIndexMethod, true, $defaultPriorityMethod, (array) $exclude, $excludeSelf)));
53+
54+
return;
55+
}
56+
parent::__construct(new ServiceLocatorArgument(new TaggedIteratorArgument($services, $indexAttribute, true, (array) $exclude, $excludeSelf)));
4857

4958
return;
5059
}
60+
if (false !== $defaultIndexMethod || false !== $defaultPriorityMethod) {
61+
trigger_deprecation('symfony/dependency-injection', '7.4', 'The $defaultIndexMethod and $defaultPriorityMethod arguments of tagged locators and iterators attributes are deprecated, use the #[AsTaggedItem] attribute instead of default methods.');
62+
}
5163

5264
$references = [];
5365

src/Symfony/Component/DependencyInjection/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ CHANGELOG
1616
* Deprecate XML configuration format, use YAML or PHP instead
1717
* Deprecate `ExtensionInterface::getXsdValidationBasePath()` and `getNamespace()`
1818
* Deprecate the fluent PHP format for semantic configuration, use `$container->extension()` or return an array instead
19+
* Deprecate default index/priority methods when defining tagged locators/iterators; use the `#[AsTaggedItem]` attribute instead
1920

2021
7.3
2122
---

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

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,9 +43,9 @@ private function findAndSortTaggedServices(string|TaggedIteratorArgument $tagNam
4343

4444
if ($tagName instanceof TaggedIteratorArgument) {
4545
$indexAttribute = $tagName->getIndexAttribute();
46-
$defaultIndexMethod = $tagName->getDefaultIndexMethod();
46+
$defaultIndexMethod = $tagName->getDefaultIndexMethod(false);
4747
$needsIndexes = $tagName->needsIndexes();
48-
$defaultPriorityMethod = $tagName->getDefaultPriorityMethod() ?? 'getDefaultPriority';
48+
$defaultPriorityMethod = $tagName->getDefaultPriorityMethod(false) ?? 'getDefaultPriority';
4949
$exclude = array_merge($exclude, $tagName->getExclude());
5050
$tagName = $tagName->getTag();
5151
}
@@ -163,6 +163,8 @@ public static function getDefault(string $serviceId, \ReflectionClass $r, string
163163
throw new InvalidArgumentException(implode('be public', $message));
164164
}
165165

166+
trigger_deprecation('symfony/dependency-injection', '7.4', 'Calling "%s::%s()" to get the "%s" index is deprecated, use the #[AsTaggedItem] attribute instead.', $class, $defaultMethod, $indexAttribute);
167+
166168
$default = $rm->invoke(null);
167169

168170
if ('priority' === $indexAttribute) {

src/Symfony/Component/DependencyInjection/Dumper/XmlDumper.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -308,11 +308,11 @@ private function convertParameters(array $parameters, string $type, string $keyA
308308
if (null !== $tag->getIndexAttribute()) {
309309
$xmlAttr .= \sprintf(' index-by="%s"', $this->encode($tag->getIndexAttribute()));
310310

311-
if (null !== $tag->getDefaultIndexMethod()) {
312-
$xmlAttr .= \sprintf(' default-index-method="%s"', $this->encode($tag->getDefaultIndexMethod()));
311+
if (null !== $tag->getDefaultIndexMethod(false)) {
312+
$xmlAttr .= \sprintf(' default-index-method="%s"', $this->encode($tag->getDefaultIndexMethod(false)));
313313
}
314-
if (null !== $tag->getDefaultPriorityMethod()) {
315-
$xmlAttr .= \sprintf(' default-priority-method="%s"', $this->encode($tag->getDefaultPriorityMethod()));
314+
if (null !== $tag->getDefaultPriorityMethod(false)) {
315+
$xmlAttr .= \sprintf(' default-priority-method="%s"', $this->encode($tag->getDefaultPriorityMethod(false)));
316316
}
317317
}
318318
if (1 === \count($excludes = $tag->getExclude())) {

src/Symfony/Component/DependencyInjection/Dumper/YamlDumper.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -265,11 +265,11 @@ private function dumpValue(mixed $value): mixed
265265
'index_by' => $tag->getIndexAttribute(),
266266
];
267267

268-
if (null !== $tag->getDefaultIndexMethod()) {
269-
$content['default_index_method'] = $tag->getDefaultIndexMethod();
268+
if (null !== $tag->getDefaultIndexMethod(false)) {
269+
$content['default_index_method'] = $tag->getDefaultIndexMethod(false);
270270
}
271-
if (null !== $tag->getDefaultPriorityMethod()) {
272-
$content['default_priority_method'] = $tag->getDefaultPriorityMethod();
271+
if (null !== $tag->getDefaultPriorityMethod(false)) {
272+
$content['default_priority_method'] = $tag->getDefaultPriorityMethod(false);
273273
}
274274
}
275275
if ($excludes = $tag->getExclude()) {

src/Symfony/Component/DependencyInjection/Loader/Configurator/ContainerConfigurator.php

Lines changed: 36 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -143,18 +143,50 @@ function iterator(array $values): IteratorArgument
143143

144144
/**
145145
* Creates a lazy iterator by tag name.
146+
*
147+
* @param string $tag The name of the tag identifying the target services
148+
* @param string|null $indexAttribute The name of the attribute that defines the key referencing each service in the tagged collection
149+
* @param string|string[] $exclude Services to exclude from the iterator
150+
* @param bool $excludeSelf Whether to automatically exclude the referencing service from the iterator
146151
*/
147-
function tagged_iterator(string $tag, ?string $indexAttribute = null, ?string $defaultIndexMethod = null, ?string $defaultPriorityMethod = null, string|array $exclude = [], bool $excludeSelf = true): TaggedIteratorArgument
152+
function tagged_iterator(string $tag, ?string $indexAttribute = null, string|array|null $exclude = [], bool|string|null $excludeSelf = true, ...$_): TaggedIteratorArgument
148153
{
149-
return new TaggedIteratorArgument($tag, $indexAttribute, $defaultIndexMethod, false, $defaultPriorityMethod, (array) $exclude, $excludeSelf);
154+
if (\func_num_args() > 4 || !\is_bool($excludeSelf) || null === $exclude || (\is_string($exclude) && str_starts_with($exclude, 'get') && !\array_key_exists('defaultIndexMethod', $_))) {
155+
[, , $defaultIndexMethod, $defaultPriorityMethod, $exclude, $excludeSelf] = \func_get_args() + [2 => null, null, [], true];
156+
} else {
157+
$defaultIndexMethod = \array_key_exists('defaultIndexMethod', $_) ? $_['defaultIndexMethod'] : false;
158+
$defaultPriorityMethod = \array_key_exists('defaultPriorityMethod', $_) ? $_['defaultPriorityMethod'] : false;
159+
}
160+
161+
if (false !== $defaultIndexMethod || false !== $defaultPriorityMethod) {
162+
return new TaggedIteratorArgument($tag, $indexAttribute, $defaultIndexMethod, false, $defaultPriorityMethod, (array) $exclude, $excludeSelf);
163+
}
164+
165+
return new TaggedIteratorArgument($tag, $indexAttribute, false, (array) $exclude, $excludeSelf);
150166
}
151167

152168
/**
153169
* Creates a service locator by tag name.
170+
*
171+
* @param string $tag The name of the tag identifying the target services
172+
* @param string|null $indexAttribute The name of the attribute that defines the key referencing each service in the tagged collection
173+
* @param string|string[] $exclude Services to exclude from the iterator
174+
* @param bool $excludeSelf Whether to automatically exclude the referencing service from the iterator
154175
*/
155-
function tagged_locator(string $tag, ?string $indexAttribute = null, ?string $defaultIndexMethod = null, ?string $defaultPriorityMethod = null, string|array $exclude = [], bool $excludeSelf = true): ServiceLocatorArgument
176+
function tagged_locator(string $tag, ?string $indexAttribute = null, string|array|null $exclude = [], bool|string|null $excludeSelf = true, ...$_): ServiceLocatorArgument
156177
{
157-
return new ServiceLocatorArgument(new TaggedIteratorArgument($tag, $indexAttribute, $defaultIndexMethod, true, $defaultPriorityMethod, (array) $exclude, $excludeSelf));
178+
if (\func_num_args() > 4 || !\is_bool($excludeSelf) || null === $exclude || (\is_string($exclude) && str_starts_with($exclude, 'get') && !\array_key_exists('defaultIndexMethod', $_))) {
179+
[, , $defaultIndexMethod, $defaultPriorityMethod, $exclude, $excludeSelf] = \func_get_args() + [2 => null, null, [], true];
180+
} else {
181+
$defaultIndexMethod = \array_key_exists('defaultIndexMethod', $_) ? $_['defaultIndexMethod'] : false;
182+
$defaultPriorityMethod = \array_key_exists('defaultPriorityMethod', $_) ? $_['defaultPriorityMethod'] : false;
183+
}
184+
185+
if (false !== $defaultIndexMethod || false !== $defaultPriorityMethod) {
186+
return new ServiceLocatorArgument(new TaggedIteratorArgument($tag, $indexAttribute, $defaultIndexMethod, true, $defaultPriorityMethod, (array) $exclude, $excludeSelf));
187+
}
188+
189+
return new ServiceLocatorArgument(new TaggedIteratorArgument($tag, $indexAttribute, true, (array) $exclude, $excludeSelf));
158190
}
159191

160192
/**

0 commit comments

Comments
 (0)