bug #33670 [DI] Service locators can't be decorated (malarzm)

This PR was squashed before being merged into the 4.3 branch.

Discussion
----------

[DI] Service locators can't be decorated

| Q             | A
| ------------- | ---
| Branch?       | 4.3
| Bug fix?      | yes
| New feature?  | no
| Deprecations? | no
| Tickets       | n/a
| License       | MIT
| Doc PR        | n/a

This popped up while I was trying to update my work project as we have decorated the `messenger.receiver_locator` service. Not sure if this is a regression in DI or a change in messenger that caused the issue thus I'm not marking this as a BC break.

Exception while trying to compile the container:

```
Invalid definition for service "Symfony\Component\DependencyInjection\Tests\Compiler\DecoratedServiceLocator": an array of references is expected as first argument when the "container.service_locator" tag is set.
```

Expected result: service locator can be decorated.

Commits
-------

343282b9d4 [DI] Service locators can't be decorated
This commit is contained in:
Nicolas Grekas 2019-12-17 11:22:17 +01:00
commit 672fbf5a2b
2 changed files with 55 additions and 3 deletions

View File

@ -52,14 +52,14 @@ class PassConfig
new ValidateEnvPlaceholdersPass(),
new ResolveChildDefinitionsPass(),
new RegisterServiceSubscribersPass(),
new DecoratorServicePass(),
new ResolveParameterPlaceHoldersPass(false),
new ResolveFactoryClassPass(),
new ResolveNamedArgumentsPass(),
new AutowireRequiredMethodsPass(),
new ResolveBindingsPass(),
new ServiceLocatorTagPass(),
new CheckDefinitionValidityPass(),
new DecoratorServicePass(),
new ResolveFactoryClassPass(),
new AutowireRequiredMethodsPass(),
new AutowirePass(false),
new ResolveTaggedIteratorArgumentPass(),
new ResolveServiceSubscribersPass(),

View File

@ -24,6 +24,7 @@ use Symfony\Component\DependencyInjection\ServiceSubscriberInterface;
use Symfony\Component\DependencyInjection\Tests\Fixtures\BarTagClass;
use Symfony\Component\DependencyInjection\Tests\Fixtures\FooBarTaggedClass;
use Symfony\Component\DependencyInjection\Tests\Fixtures\FooTagClass;
use Symfony\Contracts\Service\ServiceProviderInterface;
/**
* This class tests the integration of the different compiler passes.
@ -142,6 +143,29 @@ class IntegrationTest extends TestCase
$this->assertInstanceOf(DecoratedServiceSubscriber::class, $container->get(ServiceSubscriberStub::class));
}
public function testCanDecorateServiceLocator()
{
$container = new ContainerBuilder();
$container->register('foo', 'stdClass')->setPublic(true);
$container->register(ServiceLocator::class)
->addTag('container.service_locator')
->setArguments([[new Reference('foo')]])
;
$container->register(DecoratedServiceLocator::class)
->setDecoratedService(ServiceLocator::class)
->setPublic(true)
->setArguments([new Reference(DecoratedServiceLocator::class.'.inner')])
;
$container->compile();
$this->assertInstanceOf(DecoratedServiceLocator::class, $container->get(DecoratedServiceLocator::class));
$this->assertSame($container->get('foo'), $container->get(DecoratedServiceLocator::class)->get('foo'));
}
/**
* @dataProvider getYamlCompileTests
*/
@ -416,6 +440,34 @@ class DecoratedServiceSubscriber
{
}
class DecoratedServiceLocator implements ServiceProviderInterface
{
/**
* @var ServiceLocator
*/
private $locator;
public function __construct(ServiceLocator $locator)
{
$this->locator = $locator;
}
public function get($id)
{
return $this->locator->get($id);
}
public function has($id): bool
{
return $this->locator->has($id);
}
public function getProvidedServices(): array
{
return $this->locator->getProvidedServices();
}
}
class IntegrationTestStub extends IntegrationTestStubParent
{
}