[DI] fix auto-binding service providers to their service subscribers

This commit is contained in:
Nicolas Grekas 2019-12-16 19:31:23 +01:00
parent 624f2e345b
commit 6c2ceb0c44
3 changed files with 45 additions and 1 deletions

View File

@ -11,11 +11,14 @@
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\Definition;
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\DependencyInjection\TypedReference;
use Symfony\Contracts\Service\ServiceProviderInterface;
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));
}
$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);
}

View File

@ -16,6 +16,7 @@ use Psr\Container\ContainerInterface as PsrContainerInterface;
use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument;
use Symfony\Component\DependencyInjection\Compiler\AutowirePass;
use Symfony\Component\DependencyInjection\Compiler\RegisterServiceSubscribersPass;
use Symfony\Component\DependencyInjection\Compiler\ResolveBindingsPass;
use Symfony\Component\DependencyInjection\Compiler\ResolveServiceSubscribersPass;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\ContainerInterface;
@ -235,4 +236,32 @@ class RegisterServiceSubscribersPassTest extends TestCase
];
$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));
}
}

View File

@ -2,6 +2,7 @@
namespace Symfony\Component\DependencyInjection\Tests\Fixtures;
use Symfony\Contracts\Service\ServiceProviderInterface;
use Symfony\Contracts\Service\ServiceSubscriberInterface;
class TestServiceSubscriber implements ServiceSubscriberInterface
@ -10,6 +11,10 @@ class TestServiceSubscriber implements ServiceSubscriberInterface
{
}
public function setServiceProvider(ServiceProviderInterface $container)
{
}
public static function getSubscribedServices()
{
return [