Skip to content

Commit 997292c

Browse files
Merge branch '4.3' into 4.4
* 4.3: [DI] Service locators can't be decorated [Console][SymfonyQuestionHelper] Handle multibytes question choices keys and custom prompt [DI] fix auto-binding service providers to their service subscribers
2 parents 08a39b4 + 0ffbd72 commit 997292c

File tree

5 files changed

+100
-4
lines changed

5 files changed

+100
-4
lines changed

Compiler/PassConfig.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,14 +52,14 @@ public function __construct()
5252
new ValidateEnvPlaceholdersPass(),
5353
new ResolveChildDefinitionsPass(),
5454
new RegisterServiceSubscribersPass(),
55-
new DecoratorServicePass(),
5655
new ResolveParameterPlaceHoldersPass(false),
57-
new ResolveFactoryClassPass(),
5856
new ResolveNamedArgumentsPass(),
59-
new AutowireRequiredMethodsPass(),
6057
new ResolveBindingsPass(),
6158
new ServiceLocatorTagPass(),
6259
new CheckDefinitionValidityPass(),
60+
new DecoratorServicePass(),
61+
new ResolveFactoryClassPass(),
62+
new AutowireRequiredMethodsPass(),
6363
new AutowirePass(false),
6464
new ResolveTaggedIteratorArgumentPass(),
6565
new ResolveServiceSubscribersPass(),

Compiler/RegisterServiceSubscribersPass.php

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,14 @@
1111

1212
namespace Symfony\Component\DependencyInjection\Compiler;
1313

14+
use Psr\Container\ContainerInterface as PsrContainerInterface;
15+
use Symfony\Component\DependencyInjection\Argument\BoundArgument;
1416
use Symfony\Component\DependencyInjection\ContainerInterface;
1517
use Symfony\Component\DependencyInjection\Definition;
1618
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
1719
use Symfony\Component\DependencyInjection\Reference;
1820
use Symfony\Component\DependencyInjection\TypedReference;
21+
use Symfony\Contracts\Service\ServiceProviderInterface;
1922
use Symfony\Contracts\Service\ServiceSubscriberInterface;
2023

2124
/**
@@ -105,7 +108,14 @@ protected function processValue($value, $isRoot = false)
105108
throw new InvalidArgumentException(sprintf('Service %s not exist in the map returned by "%s::getSubscribedServices()" for service "%s".', $message, $class, $this->currentId));
106109
}
107110

108-
$value->addTag('container.service_subscriber.locator', ['id' => (string) ServiceLocatorTagPass::register($this->container, $subscriberMap, $this->currentId)]);
111+
$locatorRef = ServiceLocatorTagPass::register($this->container, $subscriberMap, $this->currentId);
112+
113+
$value->addTag('container.service_subscriber.locator', ['id' => (string) $locatorRef]);
114+
115+
$value->setBindings([
116+
PsrContainerInterface::class => new BoundArgument($locatorRef, false),
117+
ServiceProviderInterface::class => new BoundArgument($locatorRef, false),
118+
] + $value->getBindings());
109119

110120
return parent::processValue($value);
111121
}

Tests/Compiler/IntegrationTest.php

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
use Symfony\Component\DependencyInjection\Tests\Fixtures\FooBarTaggedClass;
2626
use Symfony\Component\DependencyInjection\Tests\Fixtures\FooBarTaggedForDefaultPriorityClass;
2727
use Symfony\Component\DependencyInjection\Tests\Fixtures\FooTagClass;
28+
use Symfony\Contracts\Service\ServiceProviderInterface;
2829

2930
/**
3031
* This class tests the integration of the different compiler passes.
@@ -143,6 +144,29 @@ public function testCanDecorateServiceSubscriber()
143144
$this->assertInstanceOf(DecoratedServiceSubscriber::class, $container->get(ServiceSubscriberStub::class));
144145
}
145146

147+
public function testCanDecorateServiceLocator()
148+
{
149+
$container = new ContainerBuilder();
150+
151+
$container->register('foo', 'stdClass')->setPublic(true);
152+
153+
$container->register(ServiceLocator::class)
154+
->addTag('container.service_locator')
155+
->setArguments([[new Reference('foo')]])
156+
;
157+
158+
$container->register(DecoratedServiceLocator::class)
159+
->setDecoratedService(ServiceLocator::class)
160+
->setPublic(true)
161+
->setArguments([new Reference(DecoratedServiceLocator::class.'.inner')])
162+
;
163+
164+
$container->compile();
165+
166+
$this->assertInstanceOf(DecoratedServiceLocator::class, $container->get(DecoratedServiceLocator::class));
167+
$this->assertSame($container->get('foo'), $container->get(DecoratedServiceLocator::class)->get('foo'));
168+
}
169+
146170
/**
147171
* @dataProvider getYamlCompileTests
148172
*/
@@ -441,6 +465,34 @@ class DecoratedServiceSubscriber
441465
{
442466
}
443467

468+
class DecoratedServiceLocator implements ServiceProviderInterface
469+
{
470+
/**
471+
* @var ServiceLocator
472+
*/
473+
private $locator;
474+
475+
public function __construct(ServiceLocator $locator)
476+
{
477+
$this->locator = $locator;
478+
}
479+
480+
public function get($id)
481+
{
482+
return $this->locator->get($id);
483+
}
484+
485+
public function has($id): bool
486+
{
487+
return $this->locator->has($id);
488+
}
489+
490+
public function getProvidedServices(): array
491+
{
492+
return $this->locator->getProvidedServices();
493+
}
494+
}
495+
444496
class IntegrationTestStub extends IntegrationTestStubParent
445497
{
446498
}

Tests/Compiler/RegisterServiceSubscribersPassTest.php

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument;
1717
use Symfony\Component\DependencyInjection\Compiler\AutowirePass;
1818
use Symfony\Component\DependencyInjection\Compiler\RegisterServiceSubscribersPass;
19+
use Symfony\Component\DependencyInjection\Compiler\ResolveBindingsPass;
1920
use Symfony\Component\DependencyInjection\Compiler\ResolveServiceSubscribersPass;
2021
use Symfony\Component\DependencyInjection\ContainerBuilder;
2122
use Symfony\Component\DependencyInjection\ContainerInterface;
@@ -235,4 +236,32 @@ public static function getSubscribedServices(): array
235236
];
236237
$this->assertEquals($expected, $container->getDefinition((string) $locator->getFactory()[0])->getArgument(0));
237238
}
239+
240+
public function testBinding()
241+
{
242+
$container = new ContainerBuilder();
243+
244+
$container->register('foo', TestServiceSubscriber::class)
245+
->addMethodCall('setServiceProvider')
246+
->addTag('container.service_subscriber')
247+
;
248+
249+
(new RegisterServiceSubscribersPass())->process($container);
250+
(new ResolveBindingsPass())->process($container);
251+
252+
$foo = $container->getDefinition('foo');
253+
$locator = $container->getDefinition((string) $foo->getMethodCalls()[0][1][0]);
254+
255+
$this->assertFalse($locator->isPublic());
256+
$this->assertSame(ServiceLocator::class, $locator->getClass());
257+
258+
$expected = [
259+
TestServiceSubscriber::class => new ServiceClosureArgument(new TypedReference(TestServiceSubscriber::class, TestServiceSubscriber::class)),
260+
CustomDefinition::class => new ServiceClosureArgument(new TypedReference(CustomDefinition::class, CustomDefinition::class, ContainerInterface::IGNORE_ON_INVALID_REFERENCE)),
261+
'bar' => new ServiceClosureArgument(new TypedReference(CustomDefinition::class, CustomDefinition::class, ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE, 'bar')),
262+
'baz' => new ServiceClosureArgument(new TypedReference(CustomDefinition::class, CustomDefinition::class, ContainerInterface::IGNORE_ON_INVALID_REFERENCE, 'baz')),
263+
];
264+
265+
$this->assertEquals($expected, $container->getDefinition((string) $locator->getFactory()[0])->getArgument(0));
266+
}
238267
}

Tests/Fixtures/TestServiceSubscriber.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
namespace Symfony\Component\DependencyInjection\Tests\Fixtures;
44

5+
use Symfony\Contracts\Service\ServiceProviderInterface;
56
use Symfony\Contracts\Service\ServiceSubscriberInterface;
67

78
class TestServiceSubscriber implements ServiceSubscriberInterface
@@ -10,6 +11,10 @@ public function __construct($container)
1011
{
1112
}
1213

14+
public function setServiceProvider(ServiceProviderInterface $container)
15+
{
16+
}
17+
1318
public static function getSubscribedServices(): array
1419
{
1520
return [

0 commit comments

Comments
 (0)