Skip to content

Commit 1ddb17b

Browse files
[DI] add ServiceClosureArgument::register() to share service locators
1 parent 6cc9dc7 commit 1ddb17b

File tree

20 files changed

+152
-149
lines changed

20 files changed

+152
-149
lines changed

src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/TranslatorPass.php

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,10 @@
1111

1212
namespace Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler;
1313

14-
use Symfony\Component\DependencyInjection\Definition;
14+
use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument;
1515
use Symfony\Component\DependencyInjection\Reference;
1616
use Symfony\Component\DependencyInjection\ContainerBuilder;
1717
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
18-
use Symfony\Component\DependencyInjection\ServiceLocator;
1918

2019
class TranslatorPass implements CompilerPassInterface
2120
{
@@ -46,7 +45,7 @@ public function process(ContainerBuilder $container)
4645

4746
$container
4847
->findDefinition('translator.default')
49-
->replaceArgument(0, (new Definition(ServiceLocator::class, array($loaderRefs)))->addTag('container.service_locator'))
48+
->replaceArgument(0, ServiceClosureArgument::register($container, $loaderRefs))
5049
->replaceArgument(3, $loaders)
5150
;
5251
}

src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Compiler/AddConstraintValidatorsPassTest.php

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,11 +41,12 @@ public function testThatConstraintValidatorServicesAreProcessed()
4141
$addConstraintValidatorsPass = new AddConstraintValidatorsPass();
4242
$addConstraintValidatorsPass->process($container);
4343

44-
$this->assertEquals((new Definition(ServiceLocator::class, array(array(
44+
$expected = (new Definition(ServiceLocator::class, array(array(
4545
Validator1::class => new ServiceClosureArgument(new Reference('my_constraint_validator_service1')),
4646
'my_constraint_validator_alias1' => new ServiceClosureArgument(new Reference('my_constraint_validator_service1')),
4747
Validator2::class => new ServiceClosureArgument(new Reference('my_constraint_validator_service2')),
48-
))))->addTag('container.service_locator'), $validatorFactory->getArgument(0));
48+
))))->addTag('container.service_locator')->setPublic(false);
49+
$this->assertEquals($expected, $container->getDefinition((string) $validatorFactory->getArgument(0)));
4950
}
5051

5152
public function testThatCompilerPassIsIgnoredIfThereIsNoConstraintValidatorFactoryDefinition()

src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Compiler/FormPassTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ public function testAddTaggedTypes()
5353
(new Definition(ServiceLocator::class, array(array(
5454
__CLASS__.'_Type1' => new ServiceClosureArgument(new Reference('my.type1')),
5555
__CLASS__.'_Type2' => new ServiceClosureArgument(new Reference('my.type2')),
56-
))))->addTag('container.service_locator'),
56+
))))->addTag('container.service_locator')->setPublic(false),
5757
$extDefinition->getArgument(0)
5858
);
5959
}

src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Compiler/TranslatorPassTest.php

Lines changed: 25 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -12,45 +12,40 @@
1212
namespace Symfony\Bundle\FrameworkBundle\Tests\DependencyInjection\Compiler;
1313

1414
use PHPUnit\Framework\TestCase;
15+
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\TranslatorPass;
16+
use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument;
17+
use Symfony\Component\DependencyInjection\ContainerBuilder;
1518
use Symfony\Component\DependencyInjection\Definition;
1619
use Symfony\Component\DependencyInjection\Reference;
17-
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\TranslatorPass;
1820
use Symfony\Component\DependencyInjection\ServiceLocator;
1921

2022
class TranslatorPassTest extends TestCase
2123
{
2224
public function testValidCollector()
2325
{
24-
$definition = $this->getMockBuilder('Symfony\Component\DependencyInjection\Definition')->getMock();
25-
$definition->expects($this->at(0))
26-
->method('addMethodCall')
27-
->with('addLoader', array('xliff', new Reference('xliff')));
28-
$definition->expects($this->at(1))
29-
->method('addMethodCall')
30-
->with('addLoader', array('xlf', new Reference('xliff')));
31-
32-
$container = $this->getMockBuilder('Symfony\Component\DependencyInjection\ContainerBuilder')->setMethods(array('hasDefinition', 'getDefinition', 'findTaggedServiceIds', 'findDefinition'))->getMock();
33-
$container->expects($this->any())
34-
->method('hasDefinition')
35-
->will($this->returnValue(true));
36-
$container->expects($this->once())
37-
->method('getDefinition')
38-
->will($this->returnValue($definition));
39-
$container->expects($this->once())
40-
->method('findTaggedServiceIds')
41-
->will($this->returnValue(array('xliff' => array(array('alias' => 'xliff', 'legacy-alias' => 'xlf')))));
42-
$container->expects($this->once())
43-
->method('findDefinition')
44-
->will($this->returnValue($translator = $this->getMockBuilder('Symfony\Component\DependencyInjection\Definition')->getMock()));
45-
$translator->expects($this->at(0))
46-
->method('replaceArgument')
47-
->with(0, $this->equalTo((new Definition(ServiceLocator::class, array(array('xliff' => new Reference('xliff')))))->addTag('container.service_locator')))
48-
->willReturn($translator);
49-
$translator->expects($this->at(1))
50-
->method('replaceArgument')
51-
->with(3, array('xliff' => array('xliff', 'xlf')))
52-
->willReturn($translator);
26+
$loader = (new Definition())
27+
->addTag('translation.loader', array('alias' => 'xliff', 'legacy-alias' => 'xlf'));
28+
29+
$translator = (new Definition())
30+
->setArguments(array(null, null, null, null));
31+
32+
$container = new ContainerBuilder();
33+
$container->setDefinition('translator.default', $translator);
34+
$container->setDefinition('translation.loader', $loader);
35+
5336
$pass = new TranslatorPass();
5437
$pass->process($container);
38+
39+
$expected = (new Definition())
40+
->addTag('translation.loader', array('alias' => 'xliff', 'legacy-alias' => 'xlf'))
41+
->addMethodCall('addLoader', array('xliff', new Reference('translation.loader')))
42+
->addMethodCall('addLoader', array('xlf', new Reference('translation.loader')))
43+
;
44+
$this->assertEquals($expected, $loader);
45+
46+
$this->assertSame(array('translation.loader' => array('xliff', 'xlf')), $translator->getArgument(3));
47+
48+
$expected = array('translation.loader' => new ServiceClosureArgument(new Reference('translation.loader')));
49+
$this->assertEquals($expected, $container->getDefinition((string) $translator->getArgument(0))->getArgument(0));
5550
}
5651
}

src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@
2424
use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
2525
use Symfony\Component\DependencyInjection\ContainerBuilder;
2626
use Symfony\Component\DependencyInjection\Reference;
27-
use Symfony\Component\DependencyInjection\ServiceLocator;
2827
use Symfony\Component\Config\FileLocator;
2928
use Symfony\Component\Security\Core\Authorization\ExpressionLanguage;
3029

@@ -262,10 +261,10 @@ private function createFirewalls($config, ContainerBuilder $container)
262261
->replaceArgument(2, new Reference($configId))
263262
;
264263

265-
$contextRefs[$contextId] = new ServiceClosureArgument(new Reference($contextId));
264+
$contextRefs[$contextId] = new Reference($contextId);
266265
$map[$contextId] = $matcher;
267266
}
268-
$mapDef->replaceArgument(0, (new Definition(ServiceLocator::class, array($contextRefs)))->addTag('container.service_locator'));
267+
$mapDef->replaceArgument(0, ServiceClosureArgument::register($container, $contextRefs));
269268
$mapDef->replaceArgument(1, new IteratorArgument($map));
270269

271270
// add authentication providers to authentication manager

src/Symfony/Bundle/TwigBundle/DependencyInjection/Compiler/RuntimeLoaderPass.php

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,6 @@
1515
use Symfony\Component\DependencyInjection\ContainerBuilder;
1616
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
1717
use Symfony\Component\DependencyInjection\Reference;
18-
use Symfony\Component\DependencyInjection\Definition;
19-
use Symfony\Component\DependencyInjection\ServiceLocator;
2018

2119
/**
2220
* Registers Twig runtime services.
@@ -38,9 +36,9 @@ public function process(ContainerBuilder $container)
3836
continue;
3937
}
4038

41-
$mapping[$def->getClass()] = new ServiceClosureArgument(new Reference($id));
39+
$mapping[$def->getClass()] = new Reference($id);
4240
}
4341

44-
$definition->replaceArgument(0, (new Definition(ServiceLocator::class, array($mapping)))->addTag('container.service_locator'));
42+
$definition->replaceArgument(0, ServiceClosureArgument::register($container, $mapping));
4543
}
4644
}

src/Symfony/Bundle/TwigBundle/Tests/DependencyInjection/TwigExtensionTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -244,7 +244,7 @@ public function testRuntimeLoader()
244244
$container->compile();
245245

246246
$loader = $container->getDefinition('twig.runtime_loader');
247-
$args = $loader->getArgument(0)->getArgument(0);
247+
$args = $container->getDefinition((string) $loader->getArgument(0))->getArgument(0);
248248
$this->assertArrayHasKey('Symfony\Bridge\Twig\Form\TwigRenderer', $args);
249249
$this->assertArrayHasKey('FooClass', $args);
250250
$this->assertEquals('twig.form.renderer', $args['Symfony\Bridge\Twig\Form\TwigRenderer']->getValues()[0]);

src/Symfony/Component/DependencyInjection/Argument/ServiceClosureArgument.php

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

1212
namespace Symfony\Component\DependencyInjection\Argument;
1313

14-
use Symfony\Component\DependencyInjection\Reference;
14+
use Symfony\Component\DependencyInjection\ContainerBuilder;
15+
use Symfony\Component\DependencyInjection\Definition;
1516
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
17+
use Symfony\Component\DependencyInjection\Reference;
18+
use Symfony\Component\DependencyInjection\ServiceLocator;
1619

1720
/**
1821
* Represents a service wrapped in a memoizing closure.
1922
*
2023
* @author Nicolas Grekas <p@tchwork.com>
24+
*
25+
* @final
2126
*/
2227
class ServiceClosureArgument implements ArgumentInterface
2328
{
@@ -28,11 +33,17 @@ public function __construct(Reference $reference)
2833
$this->values = array($reference);
2934
}
3035

36+
/**
37+
* {@inheritdoc}
38+
*/
3139
public function getValues()
3240
{
3341
return $this->values;
3442
}
3543

44+
/**
45+
* {@inheritdoc}
46+
*/
3647
public function setValues(array $values)
3748
{
3849
if (array(0) !== array_keys($values) || !($values[0] instanceof Reference || null === $values[0])) {
@@ -41,4 +52,29 @@ public function setValues(array $values)
4152

4253
$this->values = $values;
4354
}
55+
56+
/**
57+
* @param Reference[] $refMap
58+
* @param int|bool $autowired
59+
*
60+
* @return Reference
61+
*/
62+
public static function register(ContainerBuilder $container, array $refMap, $autowired = false)
63+
{
64+
foreach ($refMap as $id => $ref) {
65+
$refMap[$id] = new self($ref);
66+
}
67+
ksort($refMap);
68+
69+
$locator = (new Definition(ServiceLocator::class))
70+
->addArgument($refMap)
71+
->setPublic(false)
72+
->setAutowired($autowired)
73+
->addTag('container.service_locator');
74+
75+
$id = 'service_locator.'.md5(serialize($locator));
76+
$container->setDefinition($id, $locator);
77+
78+
return new Reference($id);
79+
}
4480
}

src/Symfony/Component/DependencyInjection/Compiler/RegisterServiceSubscribersPass.php

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
1818
use Symfony\Component\DependencyInjection\Reference;
1919
use Symfony\Component\DependencyInjection\ServiceSubscriberInterface;
20-
use Symfony\Component\DependencyInjection\ServiceLocator;
2120
use Symfony\Component\DependencyInjection\TypedReference;
2221

2322
/**
@@ -87,7 +86,7 @@ protected function processValue($value, $isRoot = false)
8786
$serviceMap[$key] = new Reference($type);
8887
}
8988

90-
$subscriberMap[$key] = new ServiceClosureArgument(new TypedReference((string) $serviceMap[$key], $type, $optionalBehavior ?: ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE));
89+
$subscriberMap[$key] = new TypedReference((string) $serviceMap[$key], $type, $optionalBehavior ?: ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE);
9190
unset($serviceMap[$key]);
9291
}
9392

@@ -96,12 +95,7 @@ protected function processValue($value, $isRoot = false)
9695
}
9796

9897
$serviceLocator = $this->serviceLocator;
99-
$this->serviceLocator = 'container.'.$this->currentId.'.'.md5(serialize($value));
100-
$this->container->register($this->serviceLocator, ServiceLocator::class)
101-
->addArgument($subscriberMap)
102-
->setPublic(false)
103-
->setAutowired($value->isAutowired())
104-
->addTag('container.service_locator');
98+
$this->serviceLocator = (string) ServiceClosureArgument::register($this->container, $subscriberMap, $value->getAutowired());
10599

106100
try {
107101
return parent::processValue($value);

src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_subscriber.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -99,12 +99,12 @@ protected function getFooServiceService()
9999
{
100100
return $this->services['foo_service'] = new \TestServiceSubscriber(new \Symfony\Component\DependencyInjection\ServiceLocator(array('TestServiceSubscriber' => function () {
101101
$f = function (\TestServiceSubscriber $v) { return $v; }; return $f(${($_ = isset($this->services['TestServiceSubscriber']) ? $this->services['TestServiceSubscriber'] : $this->get('TestServiceSubscriber')) && false ?: '_'});
102-
}, 'stdClass' => function () {
103-
$f = function (\stdClass $v = null) { return $v; }; return $f(${($_ = isset($this->services['autowired.stdClass']) ? $this->services['autowired.stdClass'] : $this->getAutowired_StdClassService()) && false ?: '_'});
104102
}, 'bar' => function () {
105103
$f = function (\stdClass $v) { return $v; }; return $f(${($_ = isset($this->services['autowired.stdClass']) ? $this->services['autowired.stdClass'] : $this->getAutowired_StdClassService()) && false ?: '_'});
106104
}, 'baz' => function () {
107105
$f = function (\stdClass $v = null) { return $v; }; return $f(${($_ = isset($this->services['autowired.stdClass']) ? $this->services['autowired.stdClass'] : $this->getAutowired_StdClassService()) && false ?: '_'});
106+
}, 'stdClass' => function () {
107+
$f = function (\stdClass $v = null) { return $v; }; return $f(${($_ = isset($this->services['autowired.stdClass']) ? $this->services['autowired.stdClass'] : $this->getAutowired_StdClassService()) && false ?: '_'});
108108
})));
109109
}
110110

0 commit comments

Comments
 (0)