8000 Allow to choose an index for tagged collection · symfony/symfony@2b54bec · GitHub
[go: up one dir, main page]

Skip to content

Commit 2b54bec

Browse files
committed
Allow to choose an index for tagged collection
1 parent 5ed68ee commit 2b54bec

File tree

5 files changed

+76
-10
lines changed

5 files changed

+76
-10
lines changed

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

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,16 +19,33 @@
1919
class TaggedIteratorArgument extends IteratorArgument
2020
{
2121
private $tag;
22+
private $indexAttribute;
23+
private $defaultIndexMethod;
2224

23-
public function __construct(string $tag)
25+
public function __construct(string $tag, string $indexAttribute = null, string $defaultIndexMethod = null)
2426
{
2527
parent::__construct([]);
2628

2729
$this->tag = $tag;
30+
$this->indexAttribute = $indexAttribute ?: null;
31+
32+
if ($indexAttribute) {
33+
$this->defaultIndexMethod = $defaultIndexMethod ?: ('getDefault'.str_replace(' ', '', ucwords(preg_replace('/[^a-zA-Z0-9\x7f-\xff]++/', ' ', $indexAttribute))).'Name');
34+
}
2835
}
2936

3037
public function getTag()
3138
{
3239
return $this->tag;
3340
}
41+
42+
public function getIndexAttribute(): ?string
43+
{
44+
return $this->indexAttribute;
45+
}
46+
47+
public function getDefaultIndexMethod(): ?string
48+
{
49+
return $this->defaultIndexMethod;
50+
}
3451
}

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

Lines changed: 46 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,9 @@
1111

1212
namespace Symfony\Component\DependencyInjection\Compiler;
1313

14+
use Symfony\Component\DependencyInjection\Argument\TaggedIteratorArgument;
1415
use Symfony\Component\DependencyInjection\ContainerBuilder;
16+
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
1517
use Symfony\Component\DependencyInjection\Reference;
1618

1719
/**
@@ -31,18 +33,59 @@ trait PriorityTaggedServiceTrait
3133
* @see https://bugs.php.net/bug.php?id=53710
3234
* @see https://bugs.php.net/bug.php?id=60926
3335
*
34-
* @param string $tagName
35-
* @param ContainerBuilder $container
36+
* @param string|TaggedIteratorArgument $tagName
37+
* @param ContainerBuilder $container
3638
*
3739
* @return Reference[]
3840
*/
3941
private function findAndSortTaggedServices($tagName, ContainerBuilder $container)
4042
{
43+
$indexAttribute = $defaultIndexMethod = null;
44+
if ($tagName instanceof TaggedIteratorArgument) {
45+
$indexAttribute = $tagName->getIndexAttribute();
46+
$defaultIndexMethod = $tagName->getDefaultIndexMethod();
47+
$tagName = $tagName->getTag();
48+
}
4149
$services = [];
4250

4351
foreach ($container->findTaggedServiceIds($tagName, true) as $serviceId => $attributes) {
4452
$priority = isset($attributes[0]['priority']) ? $attributes[0]['priority'] : 0;
45-
$services[$priority][] = new Reference($serviceId);
53+
54+
if (null === $indexAttribute) {
55+
$services[$priority][] = new Reference($serviceId);
56+
57+
continue;
58+
}
59+
60+
if (isset($attributes[0][$indexAttribute])) {
61+
$services[$priority][$attributes[0][$indexAttribute]] = new Reference($serviceId);
62+
63+
continue;
64+
}
65+
66+
10000 if (!$r = $container->getReflectionClass($class = $container->getDefinition($serviceId)->getClass())) {
67+
throw new InvalidArgumentException(sprintf('Class "%s" used for service "%s" cannot be found.', $class, $serviceId));
68+
}
69+
70+
if (!$r->hasMethod($defaultIndexMethod)) {
71+
throw new InvalidArgumentException(sprintf('Method "%s::%s()" not found: tag "%s" on service "%s" is missing "%s" attribute.', $class, $defaultIndexMethod, $tagName, $serviceId, $indexAttribute));
72+
}
73+
74+
if (!($rm = $r->getMethod($defaultIndexMethod))->isStatic()) {
75+
throw new InvalidArgumentException(sprintf('Method "%s::%s()" should be static: tag "%s" on service "%s" is missing "%s" attribute.', $class, $defaultIndexMethod, $tagName, $serviceId, $indexAttribute));
76+
}
77+
78+
if (!$rm->isPublic()) {
79+
throw new InvalidArgumentException(sprintf('Method "%s::%s()" should be public: tag "%s" on service "%s" is missing "%s" attribute.', $class, $defaultIndexMethod, $tagName, $serviceId, $indexAttribute));
80+
}
81+
82+
$key = $rm->invoke(null);
83+
84+
if (!\is_string($key)) {
85+
throw new InvalidArgumentException(sprintf('Method "%s::%s()" should return a string, got %s: tag "%s" on service "%s" is missing "%s" attribute.', $class, $defaultIndexMethod, \gettype($key), $tagName, $serviceId, $indexAttribute));
86+
}
87+
88+
$services[$priority][$key] = new Reference($serviceId);
4689
}
4790

4891
if ($services) {

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ protected function processValue($value, $isRoot = false)
3131
return parent::processValue($value, $isRoot);
3232
}
3333

34-
$value->setValues($this->findAndSortTaggedServices($value->getTag(), $this->container));
34+
$value->setValues($this->findAndSortTaggedServices($value, $this->container));
3535

3636
return $value;
3737
}

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -116,9 +116,9 @@ function iterator(array $values): IteratorArgument
116116
/**
117117
* Creates a lazy iterator by tag name.
118118
*/
119-
function tagged(string $tag): TaggedIteratorArgument
119+
function tagged(string $tag, string $indexAttribute = null, string $defaultIndexMethod = null): TaggedIteratorArgument
120120
{
121-
return new TaggedIteratorArgument($tag);
121+
return new TaggedIteratorArgument($tag, $indexAttribute, $defaultIndexMethod);
122122
}
123123

124124
/**

src/Symfony/Component/DependencyInjection/Loader/YamlFileLoader.php

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -710,11 +710,17 @@ private function resolveServices($value, $file, $isParameter = false)
710710
}
711711
}
712712
if ('tagged' === $value->getTag()) {
713-
if (!\is_string($argument) || !$argument) {
714-
throw new InvalidArgumentException(sprintf('"!tagged" tag only accepts non empty string in "%s".', $file));
713+
if (\is_string($argument) && $argument) {
714+
return new TaggedIteratorArgument($argument);
715715
}
716+
if (\is_array($argument) && isset($argument['name']) && $argument['name']) {
717+
if (array_diff(array_keys($argument), ['name', 'index_by', 'default_index_method'])) {
718+
throw new InvalidArgumentException(sprintf('"!tagged" tag contains unsupported keys. Supported are: "name, index_by, default_index_method".'));
719+
}
716720

717-
return new TaggedIteratorArgument($argument);
721+
return new TaggedIteratorArgument($argument['name'], $argument['index_by'] ?? null, $argument['default_index_method'] ?? null);
722+
}
723+
throw new InvalidArgumentException(sprintf('"!tagged" tag only accepts a non empty string or an array with a key "name" in "%s".', $file));
718724
}
719725
if ('service' === $value->getTag()) {
720726
if ($isParameter) {

0 commit comments

Comments
 (0)
0