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

Commit573b694

Browse files
committed
[DI] allowServiceSubscriberTrait to autowire properties
1 parentddaedd2 commit573b694

File tree

5 files changed

+87
-3
lines changed

5 files changed

+87
-3
lines changed

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,8 @@ public function testServiceSubscriberTraitWithSubscribedServiceAttribute()
246246
TestServiceSubscriberChild::class.'::testDefinition4' =>newServiceClosureArgument(newTypedReference(TestDefinition3::class, TestDefinition3::class)),
247247
TestServiceSubscriberParent::class.'::testDefinition1' =>newServiceClosureArgument(newTypedReference(TestDefinition1::class, TestDefinition1::class)),
248248
'custom_name' =>newServiceClosureArgument(newTypedReference(TestDefinition3::class, TestDefinition3::class, ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE,'custom_name')),
249+
'testDefinition1' =>newServiceClosureArgument(newTypedReference(TestDefinition1::class, TestDefinition1::class, ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE,'testDefinition1')),
250+
'testDefinition2' =>newServiceClosureArgument(newTypedReference(TestDefinition2::class, TestDefinition2::class, ContainerInterface::IGNORE_ON_INVALID_REFERENCE,'testDefinition2')),
249251
];
250252

251253
$this->assertEquals($expected,$container->getDefinition((string)$locator->getFactory()[0])->getArgument(0));

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,12 @@ class TestServiceSubscriberChild extends TestServiceSubscriberParent
1010
use ServiceSubscriberTrait;
1111
use TestServiceSubscriberTrait;
1212

13+
#[SubscribedService]
14+
privateTestDefinition1$testDefinition1;
15+
16+
#[SubscribedService]
17+
private ?TestDefinition2$testDefinition2;
18+
1319
#[SubscribedService]
1420
privatefunctiontestDefinition2(): ?TestDefinition2
1521
{

‎src/Symfony/Contracts/Service/Attribute/SubscribedService.php‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
*
2525
* @author Kevin Bond <kevinbond@gmail.com>
2626
*/
27-
#[\Attribute(\Attribute::TARGET_METHOD)]
27+
#[\Attribute(\Attribute::TARGET_METHOD | \Attribute::TARGET_PROPERTY)]
2828
finalclass SubscribedService
2929
{
3030
/** @var object[] */

‎src/Symfony/Contracts/Service/ServiceSubscriberTrait.php‎

Lines changed: 56 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,9 @@
1717

1818
/**
1919
* Implementation of ServiceSubscriberInterface that determines subscribed services from
20-
* method return types. Service ids are available as "ClassName::methodName".
20+
* method return types and property type-hints for methods/properties marked with the
21+
* "SubscribedService" attribute. Service ids are available as "ClassName::methodName"
22+
* for methods and "propertyName" for properties.
2123
*
2224
* @author Kevin Bond <kevinbond@gmail.com>
2325
*/
@@ -29,8 +31,39 @@ trait ServiceSubscriberTrait
2931
publicstaticfunctiongetSubscribedServices():array
3032
{
3133
$services =method_exists(get_parent_class(self::class) ?:'',__FUNCTION__) ?parent::getSubscribedServices() : [];
34+
$refClass =new \ReflectionClass(self::class);
3235

33-
foreach ((new \ReflectionClass(self::class))->getMethods()as$method) {
36+
foreach ($refClass->getProperties()as$property) {
37+
if (self::class !==$property->getDeclaringClass()->name) {
38+
continue;
39+
}
40+
41+
if (!$attribute =$property->getAttributes(SubscribedService::class)[0] ??null) {
42+
continue;
43+
}
44+
45+
if ($property->isStatic()) {
46+
thrownew \LogicException(sprintf('Cannot use "%s" on property "%s::$%s" (can only be used on non-static properties with a type).', SubscribedService::class,self::class,$property->name));
47+
}
48+
49+
if (!$type =$property->getType()) {
50+
thrownew \LogicException(sprintf('Cannot use "%s" on properties without a type in "%s::%s()".', SubscribedService::class,$property->name,self::class));
51+
}
52+
53+
/* @var SubscribedService $attribute */
54+
$attribute =$attribute->newInstance();
55+
$attribute->key ??=$property->name;
56+
$attribute->type ??=$typeinstanceof \ReflectionNamedType ?$type->getName() : (string)$type;
57+
$attribute->nullable =$type->allowsNull();
58+
59+
if ($attribute->attributes) {
60+
$services[] =$attribute;
61+
}else {
62+
$services[$attribute->key] = ($attribute->nullable ?'?' :'').$attribute->type;
63+
}
64+
}
65+
66+
foreach ($refClass->getMethods()as$method) {
3467
if (self::class !==$method->getDeclaringClass()->name) {
3568
continue;
3669
}
@@ -68,10 +101,31 @@ public function setContainer(ContainerInterface $container): ?ContainerInterface
68101
{
69102
$this->container =$container;
70103

104+
foreach ((new \ReflectionClass(self::class))->getProperties()as$property) {
105+
if (self::class !==$property->getDeclaringClass()->name) {
106+
continue;
107+
}
108+
109+
if (!$property->getAttributes(SubscribedService::class)) {
110+
continue;
111+
}
112+
113+
unset($this->{$property->name});
114+
}
115+
71116
if (method_exists(get_parent_class(self::class) ?:'',__FUNCTION__)) {
72117
returnparent::setContainer($container);
73118
}
74119

75120
returnnull;
76121
}
122+
123+
publicfunction__get(string$name):mixed
124+
{
125+
// TODO: ensure cannot be called from outside of the scope of the object?
126+
// TODO: what if class has a child/parent that allows this?
127+
// TODO: call parent::__get()?
128+
129+
return$this->$name =$this->container->has($name) ?$this->container->get($name) :null;
130+
}
77131
}

‎src/Symfony/Contracts/Tests/Service/ServiceSubscriberTraitTest.php‎

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
useSymfony\Contracts\Service\Attribute\Required;
1919
useSymfony\Contracts\Service\Attribute\SubscribedService;
2020
useSymfony\Contracts\Service\ServiceLocatorTrait;
21+
useSymfony\Contracts\Service\ServiceProviderInterface;
2122
useSymfony\Contracts\Service\ServiceSubscriberInterface;
2223
useSymfony\Contracts\Service\ServiceSubscriberTrait;
2324

@@ -26,6 +27,8 @@ class ServiceSubscriberTraitTest extends TestCase
2627
publicfunctiontestMethodsOnParentsAndChildrenAreIgnoredInGetSubscribedServices()
2728
{
2829
$expected = [
30+
'service1' => Service1::class,
31+
'service2' =>'?'.Service2::class,
2932
TestService::class.'::aService' => Service2::class,
3033
TestService::class.'::nullableService' =>'?'.Service2::class,
3134
newSubscribedService(TestService::class.'::withAttribute', Service2::class,true,newRequired()),
@@ -68,6 +71,19 @@ public function testParentNotCalledIfNoParent()
6871
$this->assertNull($service->setContainer($container));
6972
$this->assertSame([],$service::getSubscribedServices());
7073
}
74+
75+
publicfunctiontestCanGetSubscribedServiceProperties():void
76+
{
77+
$factories = ['service1' =>fn () =>newService1(),'somethingElse' =>fn () =>newService2()];
78+
$container =newclass($factories)implements ServiceProviderInterface {
79+
use ServiceLocatorTrait;
80+
};
81+
$service =newTestService();
82+
$service->setContainer($container);
83+
84+
$this->assertInstanceOf(Service1::class,$service->service1);
85+
$this->assertNull($service->service2);
86+
}
7187
}
7288

7389
class ParentTestService
@@ -86,6 +102,12 @@ class TestService extends ParentTestService implements ServiceSubscriberInterfac
86102
{
87103
use ServiceSubscriberTrait;
88104

105+
#[SubscribedService]
106+
publicService1$service1;
107+
108+
#[SubscribedService]
109+
public ?Service2$service2;
110+
89111
#[SubscribedService]
90112
publicfunctionaService():Service2
91113
{

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp