Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitc0b8f53

Browse files
[DI] Allow autowiring by type + parameter name
1 parent2df7320 commitc0b8f53

File tree

12 files changed

+187
-17
lines changed

12 files changed

+187
-17
lines changed

‎src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php‎

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
useDoctrine\Common\Annotations\AnnotationRegistry;
1515
useDoctrine\Common\Annotations\Reader;
16+
usePsr\Cache\CacheItemPoolInterface;
1617
usePsr\Log\LoggerAwareInterface;
1718
useSymfony\Bridge\Monolog\Processor\DebugProcessor;
1819
useSymfony\Bridge\Monolog\Processor\ProcessorInterface;
@@ -25,6 +26,7 @@
2526
useSymfony\Component\Cache\Adapter\AdapterInterface;
2627
useSymfony\Component\Cache\Adapter\ArrayAdapter;
2728
useSymfony\Component\Cache\Adapter\TagAwareAdapter;
29+
useSymfony\Component\Cache\CacheInterface;
2830
useSymfony\Component\Cache\Marshaller\DefaultMarshaller;
2931
useSymfony\Component\Cache\Marshaller\MarshallerInterface;
3032
useSymfony\Component\Cache\ResettableInterface;
@@ -95,6 +97,7 @@
9597
useSymfony\Component\Validator\ObjectInitializerInterface;
9698
useSymfony\Component\WebLink\HttpHeaderSerializer;
9799
useSymfony\Component\Workflow;
100+
useSymfony\Component\Workflow\WorkflowInterface;
98101
useSymfony\Component\Yaml\Command\LintCommandasBaseYamlLintCommand;
99102
useSymfony\Component\Yaml\Yaml;
100103
useSymfony\Contracts\Service\ResetInterface;
@@ -581,6 +584,7 @@ private function registerWorkflowConfiguration(array $config, ContainerBuilder $
581584
// Store to container
582585
$container->setDefinition($workflowId,$workflowDefinition);
583586
$container->setDefinition(sprintf('%s.definition',$workflowId),$definitionDefinition);
587+
$container->registerAliasForArgument($workflowId, WorkflowInterface::class,$name.'.'.$type);
584588

585589
// Add workflow to Registry
586590
if ($workflow['supports']) {
@@ -1452,6 +1456,10 @@ private function registerLockConfiguration(array $config, ContainerBuilder $cont
14521456
$container->setAlias(StoreInterface::class,newAlias('lock.store',false));
14531457
$container->setAlias(Factory::class,newAlias('lock.factory',false));
14541458
$container->setAlias(LockInterface::class,newAlias('lock',false));
1459+
}else {
1460+
$container->registerAliasForArgument('lock.'.$resourceName.'.store', StoreInterface::class,$resourceName.'.lock.store');
1461+
$container->registerAliasForArgument('lock.'.$resourceName.'.factory', Factory::class,$resourceName.'.lock.factory');
1462+
$container->registerAliasForArgument('lock.'.$resourceName, LockInterface::class,$resourceName.'.lock');
14551463
}
14561464
}
14571465
}
@@ -1509,6 +1517,8 @@ private function registerMessengerConfiguration(array $config, ContainerBuilder
15091517
if ($busId ===$config['default_bus']) {
15101518
$container->setAlias('message_bus',$busId)->setPublic(true);
15111519
$container->setAlias(MessageBusInterface::class,$busId);
1520+
}else {
1521+
$container->registerAliasForArgument($busId, MessageBusInterface::class);
15121522
}
15131523
}
15141524

@@ -1593,6 +1603,8 @@ private function registerCacheConfiguration(array $config, ContainerBuilder $con
15931603
$pool['adapter'] ='.'.$pool['adapter'].'.inner';
15941604
}
15951605
$definition =newChildDefinition($pool['adapter']);
1606+
$container->registerAliasForArgument($name, CacheInterface::class);
1607+
$container->registerAliasForArgument($name, CacheItemPoolInterface::class);
15961608

15971609
if ($pool['tags']) {
15981610
if ($config['pools'][$pool['tags']]['tags'] ??false) {

‎src/Symfony/Component/DependencyInjection/CHANGELOG.md‎

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,12 @@ CHANGELOG
44
4.2.0
55
-----
66

7-
* added`ServiceSubscriberTrait`
8-
* added`ServiceLocatorArgument` for creating optimized service-locators
7+
* added`ContainerBuilder::registerAliasForArgument()` to support autowiring by type+name
8+
* added support for binding by type+name
9+
* added`ServiceSubscriberTrait` to ease implementing`ServiceSubscriberInterface` using methods' return types
10+
* added`ServiceLocatorArgument` and`!service_locator` config tag for creating optimized service-locators
11+
* added support for autoconfiguring bindings
12+
* added`%env(key:...)%` processor to fetch a specific key from an array
913

1014
4.1.0
1115
-----

‎src/Symfony/Component/DependencyInjection/Compiler/AutowirePass.php‎

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ private function doProcessValue($value, $isRoot = false)
9393
$this->container->register($id =sprintf('.errored.%s.%s',$this->currentId, (string)$value),$value->getType())
9494
->addError($message);
9595

96-
returnnewTypedReference($id,$value->getType(),$value->getInvalidBehavior());
96+
returnnewTypedReference($id,$value->getType(),$value->getInvalidBehavior(),$value->getName());
9797
}
9898
$this->container->log($this,$message);
9999
}
@@ -221,7 +221,7 @@ private function autowireMethod(\ReflectionFunctionAbstract $reflectionMethod, a
221221
}
222222

223223
$getValue =function ()use ($type,$parameter,$class,$method) {
224-
if (!$value =$this->getAutowiredReference($ref =newTypedReference($type,$type))) {
224+
if (!$value =$this->getAutowiredReference($ref =newTypedReference($type,$type, ContainerBuilder::EXCEPTION_ON_INVALID_REFERENCE,$parameter->name))) {
225225
$failureMessage =$this->createTypeNotFoundMessage($ref,sprintf('argument "$%s" of method "%s()"',$parameter->name,$class !==$this->currentId ?$class.'::'.$method :$method));
226226

227227
if ($parameter->isDefaultValueAvailable()) {
@@ -281,9 +281,27 @@ private function getAutowiredReference(TypedReference $reference)
281281
$this->lastFailure =null;
282282
$type =$reference->getType();
283283

284-
if ($type !== (string)$reference || ($this->container->has($type) && !$this->container->findDefinition($type)->isAbstract())) {
284+
if ($type !== (string)$reference) {
285285
return$reference;
286286
}
287+
288+
if (null !==$name =$reference->getName()) {
289+
if ($this->container->has($alias =$type.' $'.$name) && !$this->container->findDefinition($alias)->isAbstract()) {
290+
returnnewTypedReference($alias,$type,$reference->getInvalidBehavior());
291+
}
292+
293+
if ($this->container->has($name) && !$this->container->findDefinition($name)->isAbstract()) {
294+
foreach ($this->container->getAliases()as$id =>$alias) {
295+
if ($name === (string)$alias &&0 ===strpos($id,$type.' $')) {
296+
returnnewTypedReference($name,$type,$reference->getInvalidBehavior());
297+
}
298+
}
299+
}
300+
}
301+
302+
if ($this->container->has($type) && !$this->container->findDefinition($type)->isAbstract()) {
303+
returnnewTypedReference($type,$type,$reference->getInvalidBehavior());
304+
}
287305
}
288306

289307
/**

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

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,8 +74,9 @@ protected function processValue($value, $isRoot = false)
7474
$type =substr($type,1);
7575
$optionalBehavior = ContainerInterface::IGNORE_ON_INVALID_REFERENCE;
7676
}
77-
if (\is_int($key)) {
77+
if (\is_int($name =$key)) {
7878
$key =$type;
79+
$name =null;
7980
}
8081
if (!isset($serviceMap[$key])) {
8182
if (!$autowire) {
@@ -84,7 +85,13 @@ protected function processValue($value, $isRoot = false)
8485
$serviceMap[$key] =newReference($type);
8586
}
8687

87-
$subscriberMap[$key] =newTypedReference((string)$serviceMap[$key],$type,$optionalBehavior ?: ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE);
88+
if (false !==$i =strpos($name,'::get')) {
89+
$name =lcfirst(substr($name,5 +$i));
90+
}elseif (false !==strpos($name,'::')) {
91+
$name =null;
92+
}
93+
94+
$subscriberMap[$key] =newTypedReference((string)$serviceMap[$key],$type,$optionalBehavior ?: ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE,$name);
8895
unset($serviceMap[$key]);
8996
}
9097

‎src/Symfony/Component/DependencyInjection/ContainerBuilder.php‎

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1337,6 +1337,25 @@ public function registerForAutoconfiguration($interface)
13371337
return$this->autoconfiguredInstanceof[$interface];
13381338
}
13391339

1340+
/**
1341+
* Registers an autowiring alias that only binds to a specific argument name.
1342+
*
1343+
* The argument name is derived from $name if provided (from $id otherwise)
1344+
* using camel case: "foo.bar" or "foo_bar" creates an alias bound to
1345+
* "$fooBar"-named arguments with $type as type-hint. Such arguments will
1346+
* receive the service $id when autowiring is used.
1347+
*/
1348+
publicfunctionregisterAliasForArgument(string$id,string$type,string$name =null):Alias
1349+
{
1350+
$name =lcfirst(str_replace('','',ucwords(preg_replace('/[^a-zA-Z0-9\x7f-\xff]++/','',$name ??$id))));
1351+
1352+
if (!preg_match('/^[a-zA-Z_\x7f-\xff]/',$name)) {
1353+
thrownew \InvalidArgumentException(sprintf('Invalid argument name "%s" for service "%s": the first character must be a letter.',$name,$id));
1354+
}
1355+
1356+
return$this->setAlias($type.' $'.$name,$id);
1357+
}
1358+
13401359
/**
13411360
* Returns an array of ChildDefinition[] keyed by interface.
13421361
*

‎src/Symfony/Component/DependencyInjection/Tests/Compiler/AutowirePassTest.php‎

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -907,4 +907,29 @@ public function testErroredServiceLocator()
907907

908908
$this->assertEquals($erroredDefinition->addError('Cannot autowire service "some_locator": it has type "Symfony\Component\DependencyInjection\Tests\Compiler\MissingClass" but this class was not found.'),$container->getDefinition('.errored.some_locator.'.MissingClass::class));
909909
}
910+
911+
publicfunctiontestNamedArgumentAliasResolveCollisions()
912+
{
913+
$container =newContainerBuilder();
914+
915+
$container->register('c1', CollisionA::class);
916+
$container->register('c2', CollisionB::class);
917+
$container->setAlias(CollisionInterface::class.' $collision','c2');
918+
$aDefinition =$container->register('setter_injection_collision', SetterInjectionCollision::class);
919+
$aDefinition->setAutowired(true);
920+
921+
(newAutowireRequiredMethodsPass())->process($container);
922+
923+
$pass =newAutowirePass();
924+
925+
$pass->process($container);
926+
927+
$expected =array(
928+
array(
929+
'setMultipleInstancesForOneArg',
930+
array(newTypedReference(CollisionInterface::class.' $collision', CollisionInterface::class)),
931+
),
932+
);
933+
$this->assertEquals($expected,$container->getDefinition('setter_injection_collision')->getMethodCalls());
934+
}
910935
}

‎src/Symfony/Component/DependencyInjection/Tests/Compiler/RegisterServiceSubscribersPassTest.php‎

Lines changed: 69 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,15 @@
1414
usePHPUnit\Framework\TestCase;
1515
usePsr\Container\ContainerInterfaceasPsrContainerInterface;
1616
useSymfony\Component\DependencyInjection\Argument\ServiceClosureArgument;
17+
useSymfony\Component\DependencyInjection\Compiler\AutowirePass;
1718
useSymfony\Component\DependencyInjection\Compiler\RegisterServiceSubscribersPass;
1819
useSymfony\Component\DependencyInjection\Compiler\ResolveServiceSubscribersPass;
1920
useSymfony\Component\DependencyInjection\ContainerBuilder;
2021
useSymfony\Component\DependencyInjection\ContainerInterface;
2122
useSymfony\Component\DependencyInjection\Reference;
2223
useSymfony\Component\DependencyInjection\ServiceLocator;
24+
useSymfony\Component\DependencyInjection\ServiceSubscriberInterface;
25+
useSymfony\Component\DependencyInjection\ServiceSubscriberTrait;
2326
useSymfony\Component\DependencyInjection\Tests\Fixtures\CustomDefinition;
2427
useSymfony\Component\DependencyInjection\Tests\Fixtures\TestDefinition1;
2528
useSymfony\Component\DependencyInjection\Tests\Fixtures\TestDefinition2;
@@ -86,8 +89,8 @@ public function testNoAttributes()
8689
$expected =array(
8790
TestServiceSubscriber::class =>newServiceClosureArgument(newTypedReference(TestServiceSubscriber::class, TestServiceSubscriber::class)),
8891
CustomDefinition::class =>newServiceClosureArgument(newTypedReference(CustomDefinition::class, CustomDefinition::class, ContainerInterface::IGNORE_ON_INVALID_REFERENCE)),
89-
'bar' =>newServiceClosureArgument(newTypedReference(CustomDefinition::class, CustomDefinition::class)),
90-
'baz' =>newServiceClosureArgument(newTypedReference(CustomDefinition::class, CustomDefinition::class, ContainerInterface::IGNORE_ON_INVALID_REFERENCE)),
92+
'bar' =>newServiceClosureArgument(newTypedReference(CustomDefinition::class, CustomDefinition::class, ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE,'bar')),
93+
'baz' =>newServiceClosureArgument(newTypedReference(CustomDefinition::class, CustomDefinition::class, ContainerInterface::IGNORE_ON_INVALID_REFERENCE,'baz')),
9194
);
9295

9396
$this->assertEquals($expected,$container->getDefinition((string)$locator->getFactory()[0])->getArgument(0));
@@ -116,8 +119,8 @@ public function testWithAttributes()
116119
$expected =array(
117120
TestServiceSubscriber::class =>newServiceClosureArgument(newTypedReference(TestServiceSubscriber::class, TestServiceSubscriber::class)),
118121
CustomDefinition::class =>newServiceClosureArgument(newTypedReference(CustomDefinition::class, CustomDefinition::class, ContainerInterface::IGNORE_ON_INVALID_REFERENCE)),
119-
'bar' =>newServiceClosureArgument(newTypedReference('bar', CustomDefinition::class)),
120-
'baz' =>newServiceClosureArgument(newTypedReference(CustomDefinition::class, CustomDefinition::class, ContainerInterface::IGNORE_ON_INVALID_REFERENCE)),
122+
'bar' =>newServiceClosureArgument(newTypedReference('bar', CustomDefinition::class, ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE,'bar')),
123+
'baz' =>newServiceClosureArgument(newTypedReference(CustomDefinition::class, CustomDefinition::class, ContainerInterface::IGNORE_ON_INVALID_REFERENCE,'baz')),
121124
);
122125

123126
$this->assertEquals($expected,$container->getDefinition((string)$locator->getFactory()[0])->getArgument(0));
@@ -166,4 +169,66 @@ public function testServiceSubscriberTrait()
166169

167170
$this->assertEquals($expected,$container->getDefinition((string)$locator->getFactory()[0])->getArgument(0));
168171
}
172+
173+
publicfunctiontestServiceSubscriberTraitWithGetter()
174+
{
175+
$container =newContainerBuilder();
176+
177+
$subscriber =newclass()implements ServiceSubscriberInterface {
178+
use ServiceSubscriberTrait;
179+
180+
publicfunctiongetFoo():\stdClass
181+
{
182+
}
183+
};
184+
$container->register('foo',\get_class($subscriber))
185+
->addMethodCall('setContainer',array(newReference(PsrContainerInterface::class)))
186+
->addTag('container.service_subscriber');
187+
188+
(newRegisterServiceSubscribersPass())->process($container);
189+
(newResolveServiceSubscribersPass())->process($container);
190+
191+
$foo =$container->getDefinition('foo');
192+
$locator =$container->getDefinition((string)$foo->getMethodCalls()[0][1][0]);
193+
194+
$expected =array(
195+
\get_class($subscriber).'::getFoo' =>newServiceClosureArgument(newTypedReference('stdClass','stdClass', ContainerInterface::IGNORE_ON_INVALID_REFERENCE,'foo')),
196+
);
197+
$this->assertEquals($expected,$container->getDefinition((string)$locator->getFactory()[0])->getArgument(0));
198+
}
199+
200+
publicfunctiontestServiceSubscriberWithSemanticId()
201+
{
202+
$container =newContainerBuilder();
203+
204+
$subscriber =newclass()implements ServiceSubscriberInterface {
205+
publicstaticfunctiongetSubscribedServices()
206+
{
207+
returnarray('some.service' =>'stdClass');
208+
}
209+
};
210+
$container->register('some.service','stdClass');
211+
$container->setAlias('stdClass $someService','some.service');
212+
$container->register('foo',\get_class($subscriber))
213+
->addMethodCall('setContainer',array(newReference(PsrContainerInterface::class)))
214+
->addTag('container.service_subscriber');
215+
216+
(newRegisterServiceSubscribersPass())->process($container);
217+
(newResolveServiceSubscribersPass())->process($container);
218+
219+
$foo =$container->getDefinition('foo');
220+
$locator =$container->getDefinition((string)$foo->getMethodCalls()[0][1][0]);
221+
222+
$expected =array(
223+
'some.service' =>newServiceClosureArgument(newTypedReference('stdClass','stdClass', ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE,'some.service')),
224+
);
225+
$this->assertEquals($expected,$container->getDefinition((string)$locator->getFactory()[0])->getArgument(0));
226+
227+
(newAutowirePass())->process($container);
228+
229+
$expected =array(
230+
'some.service' =>newServiceClosureArgument(newTypedReference('some.service','stdClass')),
231+
);
232+
$this->assertEquals($expected,$container->getDefinition((string)$locator->getFactory()[0])->getArgument(0));
233+
}
169234
}

‎src/Symfony/Component/DependencyInjection/Tests/ContainerBuilderTest.php‎

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1378,6 +1378,17 @@ public function testRegisterForAutoconfiguration()
13781378
$this->assertSame($childDefA,$container->registerForAutoconfiguration('AInterface'));
13791379
}
13801380

1381+
publicfunctiontestRegisterAliasForArgument()
1382+
{
1383+
$container =newContainerBuilder();
1384+
1385+
$container->registerAliasForArgument('Foo.bar_baz','Some\FooInterface');
1386+
$this->assertEquals(newAlias('Foo.bar_baz'),$container->getAlias('Some\FooInterface $fooBarBaz'));
1387+
1388+
$container->registerAliasForArgument('Foo.bar_baz','Some\FooInterface','Bar_baz.foo');
1389+
$this->assertEquals(newAlias('Foo.bar_baz'),$container->getAlias('Some\FooInterface $barBazFoo'));
1390+
}
1391+
13811392
publicfunctiontestCaseSensitivity()
13821393
{
13831394
$container =newContainerBuilder();

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,8 +54,8 @@ public function isCompiled()
5454
publicfunctiongetRemovedIds()
5555
{
5656
returnarray(
57-
'.service_locator.ljJrY4L' =>true,
58-
'.service_locator.ljJrY4L.foo_service' =>true,
57+
'.service_locator.nZQiwdg' =>true,
58+
'.service_locator.nZQiwdg.foo_service' =>true,
5959
'Psr\\Container\\ContainerInterface' =>true,
6060
'Symfony\\Component\\DependencyInjection\\ContainerInterface' =>true,
6161
'Symfony\\Component\\DependencyInjection\\Tests\\Fixtures\\CustomDefinition' =>true,

‎src/Symfony/Component/DependencyInjection/TypedReference.php‎

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,20 +19,24 @@
1919
class TypedReferenceextends Reference
2020
{
2121
private$type;
22+
private$name;
2223
private$requiringClass;
2324

2425
/**
2526
* @param string $id The service identifier
2627
* @param string $type The PHP type of the identified service
2728
* @param int $invalidBehavior The behavior when the service does not exist
29+
* @param string $name The name of the argument targeting the service
2830
*/
29-
publicfunction__construct(string$id,string$type,$invalidBehavior = ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE)
31+
publicfunction__construct(string$id,string$type,$invalidBehavior = ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE,$name =null)
3032
{
31-
if (\is_string($invalidBehavior) ||3 <\func_num_args()) {
33+
if (\is_string($invalidBehavior ??'') ||\is_int($name)) {
3234
@trigger_error(sprintf('The $requiringClass argument of "%s()" is deprecated since Symfony 4.1.',__METHOD__),E_USER_DEPRECATED);
3335

3436
$this->requiringClass =$invalidBehavior;
3537
$invalidBehavior =3 <\func_num_args() ?\func_get_arg(3) : ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE;
38+
}else {
39+
$this->name =$type ===$id ?$name :null;
3640
}
3741
parent::__construct($id,$invalidBehavior);
3842
$this->type =$type;
@@ -43,6 +47,11 @@ public function getType()
4347
return$this->type;
4448
}
4549

50+
publicfunctiongetName(): ?string
51+
{
52+
return$this->name;
53+
}
54+
4655
/**
4756
* @deprecated since Symfony 4.1
4857
*/

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp