bug #34998 [DI] fix auto-binding service providers to their service subscribers (nicolas-grekas)
This PR was merged into the 4.3 branch.
Discussion
----------
[DI] fix auto-binding service providers to their service subscribers
| Q | A
| ------------- | ---
| Branch? | 4.3
| Bug fix? | yes
| New feature? | no
| Deprecations? | no
| Tickets | Fix https://github.com/orgs/symfony/projects/1#card-30503621
| License | MIT
| Doc PR | -
Spotted during a workshop at SymfonyLive Sao Paulo if I recall well :)
Commits
-------
6c2ceb0c44
[DI] fix auto-binding service providers to their service subscribers
This commit is contained in:
commit
8c74562dd8
@ -11,11 +11,14 @@
|
|||||||
|
|
||||||
namespace Symfony\Component\DependencyInjection\Compiler;
|
namespace Symfony\Component\DependencyInjection\Compiler;
|
||||||
|
|
||||||
|
use Psr\Container\ContainerInterface as PsrContainerInterface;
|
||||||
|
use Symfony\Component\DependencyInjection\Argument\BoundArgument;
|
||||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||||
use Symfony\Component\DependencyInjection\Definition;
|
use Symfony\Component\DependencyInjection\Definition;
|
||||||
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
|
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
|
||||||
use Symfony\Component\DependencyInjection\Reference;
|
use Symfony\Component\DependencyInjection\Reference;
|
||||||
use Symfony\Component\DependencyInjection\TypedReference;
|
use Symfony\Component\DependencyInjection\TypedReference;
|
||||||
|
use Symfony\Contracts\Service\ServiceProviderInterface;
|
||||||
use Symfony\Contracts\Service\ServiceSubscriberInterface;
|
use Symfony\Contracts\Service\ServiceSubscriberInterface;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -105,7 +108,14 @@ class RegisterServiceSubscribersPass extends AbstractRecursivePass
|
|||||||
throw new InvalidArgumentException(sprintf('Service %s not exist in the map returned by "%s::getSubscribedServices()" for service "%s".', $message, $class, $this->currentId));
|
throw new InvalidArgumentException(sprintf('Service %s not exist in the map returned by "%s::getSubscribedServices()" for service "%s".', $message, $class, $this->currentId));
|
||||||
}
|
}
|
||||||
|
|
||||||
$value->addTag('container.service_subscriber.locator', ['id' => (string) ServiceLocatorTagPass::register($this->container, $subscriberMap, $this->currentId)]);
|
$locatorRef = ServiceLocatorTagPass::register($this->container, $subscriberMap, $this->currentId);
|
||||||
|
|
||||||
|
$value->addTag('container.service_subscriber.locator', ['id' => (string) $locatorRef]);
|
||||||
|
|
||||||
|
$value->setBindings([
|
||||||
|
PsrContainerInterface::class => new BoundArgument($locatorRef, false),
|
||||||
|
ServiceProviderInterface::class => new BoundArgument($locatorRef, false),
|
||||||
|
] + $value->getBindings());
|
||||||
|
|
||||||
return parent::processValue($value);
|
return parent::processValue($value);
|
||||||
}
|
}
|
||||||
|
@ -16,6 +16,7 @@ use Psr\Container\ContainerInterface as PsrContainerInterface;
|
|||||||
use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument;
|
use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument;
|
||||||
use Symfony\Component\DependencyInjection\Compiler\AutowirePass;
|
use Symfony\Component\DependencyInjection\Compiler\AutowirePass;
|
||||||
use Symfony\Component\DependencyInjection\Compiler\RegisterServiceSubscribersPass;
|
use Symfony\Component\DependencyInjection\Compiler\RegisterServiceSubscribersPass;
|
||||||
|
use Symfony\Component\DependencyInjection\Compiler\ResolveBindingsPass;
|
||||||
use Symfony\Component\DependencyInjection\Compiler\ResolveServiceSubscribersPass;
|
use Symfony\Component\DependencyInjection\Compiler\ResolveServiceSubscribersPass;
|
||||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||||
@ -235,4 +236,32 @@ class RegisterServiceSubscribersPassTest extends TestCase
|
|||||||
];
|
];
|
||||||
$this->assertEquals($expected, $container->getDefinition((string) $locator->getFactory()[0])->getArgument(0));
|
$this->assertEquals($expected, $container->getDefinition((string) $locator->getFactory()[0])->getArgument(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testBinding()
|
||||||
|
{
|
||||||
|
$container = new ContainerBuilder();
|
||||||
|
|
||||||
|
$container->register('foo', TestServiceSubscriber::class)
|
||||||
|
->addMethodCall('setServiceProvider')
|
||||||
|
->addTag('container.service_subscriber')
|
||||||
|
;
|
||||||
|
|
||||||
|
(new RegisterServiceSubscribersPass())->process($container);
|
||||||
|
(new ResolveBindingsPass())->process($container);
|
||||||
|
|
||||||
|
$foo = $container->getDefinition('foo');
|
||||||
|
$locator = $container->getDefinition((string) $foo->getMethodCalls()[0][1][0]);
|
||||||
|
|
||||||
|
$this->assertFalse($locator->isPublic());
|
||||||
|
$this->assertSame(ServiceLocator::class, $locator->getClass());
|
||||||
|
|
||||||
|
$expected = [
|
||||||
|
TestServiceSubscriber::class => new ServiceClosureArgument(new TypedReference(TestServiceSubscriber::class, TestServiceSubscriber::class)),
|
||||||
|
CustomDefinition::class => new ServiceClosureArgument(new TypedReference(CustomDefinition::class, CustomDefinition::class, ContainerInterface::IGNORE_ON_INVALID_REFERENCE)),
|
||||||
|
'bar' => new ServiceClosureArgument(new TypedReference(CustomDefinition::class, CustomDefinition::class, ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE, 'bar')),
|
||||||
|
'baz' => new ServiceClosureArgument(new TypedReference(CustomDefinition::class, CustomDefinition::class, ContainerInterface::IGNORE_ON_INVALID_REFERENCE, 'baz')),
|
||||||
|
];
|
||||||
|
|
||||||
|
$this->assertEquals($expected, $container->getDefinition((string) $locator->getFactory()[0])->getArgument(0));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
namespace Symfony\Component\DependencyInjection\Tests\Fixtures;
|
namespace Symfony\Component\DependencyInjection\Tests\Fixtures;
|
||||||
|
|
||||||
|
use Symfony\Contracts\Service\ServiceProviderInterface;
|
||||||
use Symfony\Contracts\Service\ServiceSubscriberInterface;
|
use Symfony\Contracts\Service\ServiceSubscriberInterface;
|
||||||
|
|
||||||
class TestServiceSubscriber implements ServiceSubscriberInterface
|
class TestServiceSubscriber implements ServiceSubscriberInterface
|
||||||
@ -10,6 +11,10 @@ class TestServiceSubscriber implements ServiceSubscriberInterface
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function setServiceProvider(ServiceProviderInterface $container)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
public static function getSubscribedServices()
|
public static function getSubscribedServices()
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
|
Reference in New Issue
Block a user