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

Skip to content

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 1b5b1f8

Browse files
committed
Allow to choose an index for tagged collection
1 parent f2590d1 commit 1b5b1f8

File tree

5 files changed

+73
-10
lines changed

5 files changed

+73
-10
lines changed

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

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,16 +19,30 @@
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(array());
2628

2729
$this->tag = $tag;
30+
$this->indexAttribute = $indexAttribute;
31+
$this->defaultIndexMethod = $defaultIndexMethod;
2832
}
2933

3034
public function getTag()
3135
{
3236
return $this->tag;
3337
}
38+
39+
public function getIndexAttribute(): ?string
40+
{
41+
return $this->indexAttribute;
42+
}
43+
44+
public function getDefaultIndexMethod(): ?string
45+
{
46+
return $this->defaultIndexMethod;
47+
}
3448
}

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

Lines changed: 49 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212
namespace Symfony\Component\DependencyInjection\Compiler;
1313

1414
use Symfony\Component\DependencyInjection\ContainerBuilder;
15+
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
16+
use Symfony\Component\DependencyInjection\Exception\LogicException;
1517
use Symfony\Component\DependencyInjection\Reference;
1618

1719
/**
@@ -36,13 +38,58 @@ trait PriorityTaggedServiceTrait
3638
*
3739
* @return Reference[]
3840
*/
39-
private function findAndSortTaggedServices($tagName, ContainerBuilder $container)
41+
private function findAndSortTaggedServices($tagName, ContainerBuilder $container, string $indexAttribute = null, string $defaultIndexMethod = null)
4042
{
4143
$services = array();
4244

45+
if (null === $indexAttribute && null !== $defaultIndexMethod) {
46+
throw new InvalidArgumentException('Default index method cannot be used without specifying a tag attribute.');
47+
} else {
48+
if ('' === $defaultIndexMethod) {
49+
throw new InvalidArgumentException('Default index method cannot be an empty string.');
50+
}
51+
52+
$defaultIndexMethod = $defaultIndexMethod ?? 'getDefault'.str_replace(' ', '', ucwords(preg_replace('/[^a-zA-Z0-9\x7f-\xff]++/', ' ', $indexAttribute))).'Name';
53+
}
54+
4355
foreach ($container->findTaggedServiceIds($tagName, true) as $serviceId => $attributes) {
4456
$priority = isset($attributes[0]['priority']) ? $attributes[0]['priority'] : 0;
45-
$services[$priority][] = new Reference($serviceId);
57+
58+
if (null === $indexAttribute && null === $defaultIndexMethod) {
59+
$services[$priority][] = new Reference($serviceId);
60+
61+
continue;
62+
}
63+
64+
if (isset($attributes[0][$indexAttribute])) {
65+
$services[$priority][$attributes[0][$indexAttribute]] = new Reference($serviceId);
66+
67+
continue;
68+
}
69+
70+
if (!$r = $container->getReflectionClass($class = $container->getDefinition($serviceId)->getClass())) {
71+
throw new InvalidArgumentException(sprintf('Class "%s" used for service "%s" cannot be found.', $class, $serviceId));
72+
}
73+
74+
if (!$r->hasMethod($defaultIndexMethod)) {
75+
throw new InvalidArgumentException(sprintf('Method "%s::%s()" not found: Tag "%s" on service "%s" is missing "%s" attribute.', $class, $defaultIndexMethod, $tagName, $serviceId, $indexAttribute));
76+
}
77+
78+
if (!($rm = $r->getMethod($defaultIndexMethod))->isStatic()) {
79+
throw new InvalidArgumentException(sprintf('Method "%s::%s()" used for service "%s" must be static.', $class, $defaultIndexMethod, $serviceId));
80+
}
81+
82+
if (!$rm->isPublic()) {
83+
throw new InvalidArgumentException(sprintf('Method "%s::%s()" used for service "%s" must be public.', $class, $defaultIndexMethod, $serviceId));
84+
}
85+
86+
$key = $rm->invoke(null);
87+
88+
if (!\is_string($key)) {
89+
throw new LogicException(sprintf('Return value of method "%s::%s()" used for service "%s" must be of type string.', $class, $defaultIndexMethod, $serviceId));
90+
}
91+
92+
$services[$priority][$key] = new Reference($serviceId);
4693
}
4794

4895
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->getTag(), $this->container, $value->getIndexAttribute(), $value->getDefaultIndexMethod()));
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: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -706,11 +706,13 @@ private function resolveServices($value, $file, $isParameter = false)
706706
}
707707
}
708708
if ('tagged' === $value->getTag()) {
709-
if (!\is_string($argument) || !$argument) {
710-
throw new InvalidArgumentException(sprintf('"!tagged" tag only accepts non empty string in "%s".', $file));
709+
if (\is_string($argument) && $argument) {
710+
return new TaggedIteratorArgument($argument);
711+
} elseif (\is_array($argument) && isset($argument['name']) && $argument['name']) {
712+
return new TaggedIteratorArgument($argument['name'], $argument['index_by'] ?? null, $argument['default_index_method'] ?? null);
713+
} else {
714+
throw new InvalidArgumentException(sprintf('"!tagged" tag only accepts a non empty string or an array with a key "name" in "%s".', $file));
711715
}
712-
713-
return new TaggedIteratorArgument($argument);
714716
}
715717
if ('service' === $value->getTag()) {
716718
if ($isParameter) {

0 commit comments

Comments
 (0)
0