8000 feature #43015 [DependencyInjection] Allow injecting tagged iterator … · symfony/symfony@2018f0c · GitHub
[go: up one dir, main page]

65FD
Skip to content

Commit 2018f0c

Browse files
feature #43015 [DependencyInjection] Allow injecting tagged iterator as service locator arguments (IonBazan)
This PR was merged into the 5.4 branch. Discussion ---------- [DependencyInjection] Allow injecting tagged iterator as service locator arguments | Q | A | ------------- | --- | Branch? | 5.4 | Bug fix? | no | New feature? | yes | Deprecations? | no | Tickets | - | License | MIT | Doc PR | symfony/symfony-docs#15821 Not sure if this is a feature or bug fix - kindly update the description and target branch and I will backport the changes for older version if needed. This feature allows creating a named (reusable) service locator using tagg 10000 ed services: ```yml services: _instanceof: App\Command\HandlerInterface: tags: ['app.command_handler'] app.command_handlers: class: Symfony\Component\DependencyInjection\ServiceLocator arguments: [!tagged_iterator { tag: 'app.command_handler', default_index_method: 'getCommandName' }] App\CommandBus: arguments: ['`@app`.command_handlers'] App\AnotherCommandBus: arguments: ['`@app`.command_handlers'] ``` Prior to this change, following error would be thrown: ``` Invalid definition for service "app.command_handlers": an array of references is expected as first argument when the "container.service_locator" tag is set. ``` Commits ------- 7c86ac8 Allow injecting tagged iterator as service locator arguments
2 parents a2c60ad + 7c86ac8 commit 2018f0c

File tree

2 files changed

+34
-7
lines changed

2 files changed

+34
-7
lines changed

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

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
use Symfony\Component\DependencyInjection\Alias;
1515
use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument;
1616
use Symfony\Component\DependencyInjection\Argument\ServiceLocatorArgument;
17+
use Symfony\Component\DependencyInjection\Argument\TaggedIteratorArgument;
1718
use Symfony\Component\DependencyInjection\ContainerBuilder;
1819
use Symfony\Component\DependencyInjection\Definition;
1920
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
@@ -47,14 +48,19 @@ protected function processValue($value, bool $isRoot = false)
4748
$value->setClass(ServiceLocator::class);
4849
}
4950

50-
$arguments = $value->getArguments();
51-
if (!isset($arguments[0]) || !\is_array($arguments[0])) {
51+
$services = $value->getArguments()[0] ?? null;
52+
53+
if ($services instanceof TaggedIteratorArgument) {
54+
$services = $this->findAndSortTaggedServices($services, $this->container);
55+
}
56+
57+
if (!\is_array($services)) {
5258
throw new InvalidArgumentException(sprintf('Invalid definition for service "%s": an array of references is expected as first argument when the "container.service_locator" tag is set.', $this->currentId));
5359
}
5460

5561
$i = 0;
5662

57-
foreach ($arguments[0] as $k => $v) {
63+
foreach ($services as $k => $v) {
5864
if ($v instanceof ServiceClosureArgument) {
5965
continue;
6066
}
@@ -63,18 +69,18 @@ protected function processValue($value, bool $isRoot = false)
6369
}
6470

6571
if ($i === $k) {
66-
unset($arguments[0][$k]);
72+
unset($services[$k]);
6773

6874
$k = (string) $v;
6975
++$i;
7076
} elseif (\is_int($k)) {
7177
$i = null;
7278
}
73-
$arguments[0][$k] = new ServiceClosureArgument($v);
79+
$services[$k] = new ServiceClosureArgument($v);
7480
}
75-
ksort($arguments[0]);
81+
ksort($services);
7682

77-
$value->setArguments($arguments);
83+
$value->setArgument(0, $services);
7884

7985
$id = '.service_locator.'.ContainerBuilder::hash($value);
8086

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

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,27 @@ public function testBindingsAreCopied()
147147
$this->assertInstanceOf(BoundArgument::class, $locator->getBindings()['foo']);
148148
}
149149

150+
public function testTaggedServices()
151+
{
152+
$container = new ContainerBuilder();
153+
154+
$container->register('bar', TestDefinition1::class)->addTag('test_tag');
155+
$container->register('baz', TestDefinition2::class)->addTag('test_tag');
156+
157+
$container->register('foo', ServiceLocator::class)
158+
->setArguments([new TaggedIteratorArgument('test_tag', null, null, true)])
159+
->addTag('container.service_locator')
160+
;
161+
162+
(new ServiceLocatorTagPass())->process($container);
163+
164+
/** @var ServiceLocator $locator */
165+
$locator = $container->get('foo');
166+
167+
$this->assertSame(TestDefinition1::class, \get_class($locator('bar')));
168+
$this->assertSame(TestDefinition2::class, \get_class($locator('baz')));
169+
}
170+
150171
public function testIndexedByServiceIdWithDecoration()
151172
{
152173
$container = new ContainerBuilder();

0 commit comments

Comments
 (0)
0