bug #31541 [DI] fix using bindings with locators of service subscribers (nicolas-grekas)
This PR was merged into the 3.4 branch.
Discussion
----------
[DI] fix using bindings with locators of service subscribers
| Q | A
| ------------- | ---
| Branch? | 3.4
| Bug fix? | yes
| New feature? | no
| BC breaks? | no
| Deprecations? | no
| Tests pass? | yes
| Fixed tickets | -
| License | MIT
| Doc PR | -
Spotted during the workshop in Sao Paulo, with @tsantos84, @andreia and others :)
Commits
-------
7146b95303
[DI] fix using bindings with locators of service subscribers
This commit is contained in:
commit
f93e252f6a
@ -48,6 +48,12 @@ final class ServiceLocatorTagPass extends AbstractRecursivePass
|
|||||||
if (!$v instanceof Reference) {
|
if (!$v instanceof Reference) {
|
||||||
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, "%s" found for key "%s".', $this->currentId, \is_object($v) ? \get_class($v) : \gettype($v), $k));
|
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, "%s" found for key "%s".', $this->currentId, \is_object($v) ? \get_class($v) : \gettype($v), $k));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (\is_int($k)) {
|
||||||
|
unset($arguments[0][$k]);
|
||||||
|
|
||||||
|
$k = (string) $v;
|
||||||
|
}
|
||||||
$arguments[0][$k] = new ServiceClosureArgument($v);
|
$arguments[0][$k] = new ServiceClosureArgument($v);
|
||||||
}
|
}
|
||||||
ksort($arguments[0]);
|
ksort($arguments[0]);
|
||||||
@ -91,7 +97,11 @@ final class ServiceLocatorTagPass extends AbstractRecursivePass
|
|||||||
->setPublic(false)
|
->setPublic(false)
|
||||||
->addTag('container.service_locator');
|
->addTag('container.service_locator');
|
||||||
|
|
||||||
if (!$container->has($id = 'service_locator.'.ContainerBuilder::hash($locator))) {
|
if (null !== $callerId && $container->hasDefinition($callerId)) {
|
||||||
|
$locator->setBindings($container->getDefinition($callerId)->getBindings());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$container->hasDefinition($id = 'service_locator.'.ContainerBuilder::hash($locator))) {
|
||||||
$container->setDefinition($id, $locator);
|
$container->setDefinition($id, $locator);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -0,0 +1,147 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Symfony\Component\DependencyInjection\Tests\Compiler;
|
||||||
|
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
use Symfony\Component\DependencyInjection\Argument\BoundArgument;
|
||||||
|
use Symfony\Component\DependencyInjection\Compiler\ServiceLocatorTagPass;
|
||||||
|
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||||
|
use Symfony\Component\DependencyInjection\Reference;
|
||||||
|
use Symfony\Component\DependencyInjection\ServiceLocator;
|
||||||
|
use Symfony\Component\DependencyInjection\Tests\Fixtures\CustomDefinition;
|
||||||
|
use Symfony\Component\DependencyInjection\Tests\Fixtures\TestDefinition1;
|
||||||
|
use Symfony\Component\DependencyInjection\Tests\Fixtures\TestDefinition2;
|
||||||
|
|
||||||
|
require_once __DIR__.'/../Fixtures/includes/classes.php';
|
||||||
|
|
||||||
|
class ServiceLocatorTagPassTest extends TestCase
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @expectedException \Symfony\Component\DependencyInjection\Exception\InvalidArgumentException
|
||||||
|
* @expectedExceptionMessage Invalid definition for service "foo": an array of references is expected as first argument when the "container.service_locator" tag is set.
|
||||||
|
*/
|
||||||
|
public function testNoServices()
|
||||||
|
{
|
||||||
|
$container = new ContainerBuilder();
|
||||||
|
|
||||||
|
$container->register('foo', ServiceLocator::class)
|
||||||
|
->addTag('container.service_locator')
|
||||||
|
;
|
||||||
|
|
||||||
|
(new ServiceLocatorTagPass())->process($container);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @expectedException \Symfony\Component\DependencyInjection\Exception\InvalidArgumentException
|
||||||
|
* @expectedExceptionMessage Invalid definition for service "foo": an array of references is expected as first argument when the "container.service_locator" tag is set, "string" found for key "0".
|
||||||
|
*/
|
||||||
|
public function testInvalidServices()
|
||||||
|
{
|
||||||
|
$container = new ContainerBuilder();
|
||||||
|
|
||||||
|
$container->register('foo', ServiceLocator::class)
|
||||||
|
->setArguments([[
|
||||||
|
'dummy',
|
||||||
|
]])
|
||||||
|
->addTag('container.service_locator')
|
||||||
|
;
|
||||||
|
|
||||||
|
(new ServiceLocatorTagPass())->process($container);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testProcessValue()
|
||||||
|
{
|
||||||
|
$container = new ContainerBuilder();
|
||||||
|
|
||||||
|
$container->register('bar', CustomDefinition::class);
|
||||||
|
$container->register('baz', CustomDefinition::class);
|
||||||
|
|
||||||
|
$container->register('foo', ServiceLocator::class)
|
||||||
|
->setArguments([[
|
||||||
|
new Reference('bar'),
|
||||||
|
new Reference('baz'),
|
||||||
|
'some.service' => new Reference('bar'),
|
||||||
|
]])
|
||||||
|
->addTag('container.service_locator')
|
||||||
|
;
|
||||||
|
|
||||||
|
(new ServiceLocatorTagPass())->process($container);
|
||||||
|
|
||||||
|
/** @var ServiceLocator $locator */
|
||||||
|
$locator = $container->get('foo');
|
||||||
|
|
||||||
|
$this->assertSame(CustomDefinition::class, \get_class($locator('bar')));
|
||||||
|
$this->assertSame(CustomDefinition::class, \get_class($locator('baz')));
|
||||||
|
$this->assertSame(CustomDefinition::class, \get_class($locator('some.service')));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testServiceWithKeyOverwritesPreviousInheritedKey()
|
||||||
|
{
|
||||||
|
$container = new ContainerBuilder();
|
||||||
|
|
||||||
|
$container->register('bar', TestDefinition1::class);
|
||||||
|
$container->register('baz', TestDefinition2::class);
|
||||||
|
|
||||||
|
$container->register('foo', ServiceLocator::class)
|
||||||
|
->setArguments([[
|
||||||
|
new Reference('bar'),
|
||||||
|
'bar' => new Reference('baz'),
|
||||||
|
]])
|
||||||
|
->addTag('container.service_locator')
|
||||||
|
;
|
||||||
|
|
||||||
|
(new ServiceLocatorTagPass())->process($container);
|
||||||
|
|
||||||
|
/** @var ServiceLocator $locator */
|
||||||
|
$locator = $container->get('foo');
|
||||||
|
|
||||||
|
$this->assertSame(TestDefinition2::class, \get_class($locator('bar')));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testInheritedKeyOverwritesPreviousServiceWithKey()
|
||||||
|
{
|
||||||
|
$container = new ContainerBuilder();
|
||||||
|
|
||||||
|
$container->register('bar', TestDefinition1::class);
|
||||||
|
$container->register('baz', TestDefinition2::class);
|
||||||
|
|
||||||
|
$container->register('foo', ServiceLocator::class)
|
||||||
|
->setArguments([[
|
||||||
|
'bar' => new Reference('baz'),
|
||||||
|
new Reference('bar'),
|
||||||
|
]])
|
||||||
|
->addTag('container.service_locator')
|
||||||
|
;
|
||||||
|
|
||||||
|
(new ServiceLocatorTagPass())->process($container);
|
||||||
|
|
||||||
|
/** @var ServiceLocator $locator */
|
||||||
|
$locator = $container->get('foo');
|
||||||
|
|
||||||
|
$this->assertSame(TestDefinition1::class, \get_class($locator('bar')));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testBindingsAreCopied()
|
||||||
|
{
|
||||||
|
$container = new ContainerBuilder();
|
||||||
|
|
||||||
|
$container->register('foo')
|
||||||
|
->setBindings(['foo' => 'foo']);
|
||||||
|
|
||||||
|
$locator = ServiceLocatorTagPass::register($container, ['foo' => new Reference('foo')], 'foo');
|
||||||
|
$locator = $container->getDefinition($locator);
|
||||||
|
$locator = $container->getDefinition($locator->getFactory()[0]);
|
||||||
|
|
||||||
|
$this->assertSame(['foo'], array_keys($locator->getBindings()));
|
||||||
|
$this->assertInstanceOf(BoundArgument::class, $locator->getBindings()['foo']);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,9 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Symfony\Component\DependencyInjection\Tests\Fixtures;
|
||||||
|
|
||||||
|
use Symfony\Component\DependencyInjection\Definition;
|
||||||
|
|
||||||
|
class TestDefinition2 extends Definition
|
||||||
|
{
|
||||||
|
}
|
Reference in New Issue
Block a user