Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 9baa209

Browse files
committed
add SubscribedService attribute, deprecate current ServiceSubscriberTrait usage
1 parent c1c973c commit 9baa209

File tree

3 files changed

+97
-3
lines changed

3 files changed

+97
-3
lines changed

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,9 @@ public function testExtraServiceSubscriber()
143143
$container->compile();
144144
}
145145

146+
/**
147+
* @group legacy
148+
*/
146149
public function testServiceSubscriberTrait()
147150
{
148151
$container = new ContainerBuilder();
@@ -168,6 +171,9 @@ public function testServiceSubscriberTrait()
168171
$this->assertEquals($expected, $container->getDefinition((string) $locator->getFactory()[0])->getArgument(0));
169172
}
170173

174+
/**
175+
* @group legacy
176+
*/
171177
public function testServiceSubscriberTraitWithGetter()
172178
{
173179
$container = new ContainerBuilder();
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <[email protected]>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Contracts\Service\Attribute;
13+
14+
use Symfony\Contracts\Service\ServiceSubscriberTrait;
15+
16+
/**
17+
* Use with {@see ServiceSubscriberTrait} to mark a method's return type
18+
* as a subscribed service.
19+
*
20+
* @author Kevin Bond <[email protected]>
21+
*/
22+
#[\Attribute(\Attribute::TARGET_METHOD)]
23+
final class SubscribedService
24+
{
25+
public ?string $key;
26+
27+
/**
28+
* @param string|null $key The key to use for the service
29+
* If null, use "ClassName::methodName"
30+
*/
31+
public function __construct(string $key = null)
32+
{
33+
$this->key = $key;
34+
}
35+
}

src/Symfony/Contracts/Service/ServiceSubscriberTrait.php

Lines changed: 56 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,11 @@
1212
namespace Symfony\Contracts\Service;
1313

1414
use Psr\Container\ContainerInterface;
15+
use Symfony\Contracts\Service\Attribute\SubscribedService;
1516

1617
/**
1718
* Implementation of ServiceSubscriberInterface that determines subscribed services from
18-
* private method return types. Service ids are available as "ClassName::methodName".
19+
* method return types. Service ids are available as "ClassName::methodName".
1920
*
2021
* @author Kevin Bond <[email protected]>
2122
*/
@@ -42,8 +43,60 @@ public static function getSubscribedServices(): array
4243
continue;
4344
}
4445

45-
if (self::class === $method->getDeclaringClass()->name && ($returnType = $method->getReturnType()) && !$returnType->isBuiltin()) {
46-
$services[self::class.'::'.$method->name] = '?'.($returnType instanceof \ReflectionNamedType ? $returnType->getName() : $returnType);
46+
if (self::class !== $method->getDeclaringClass()->name) {
47+
continue;
48+
}
49+
50+
if (!$returnType = $method->getReturnType()) {
51+
continue;
52+
}
53+
54+
if ($returnType->isBuiltin()) {
55+
continue;
56+
}
57+
58+
if (\PHP_VERSION_ID >= 80000) {
59+
if (\count($method->getAttributes(SubscribedService::class))) {
60+
continue;
61+
}
62+
63+
trigger_deprecation('symfony/service-contracts', '5.4', 'Using the "%s" trait in "%s" without subscribed service methods marked with the "%s" attribute is deprecated and will not be allowed in Symfony 6.0.', ServiceSubscriberTrait::class, self::class, SubscribedService::class);
64+
}
65+
66+
$services[self::class.'::'.$method->name] = '?'.($returnType instanceof \ReflectionNamedType ? $returnType->getName() : $returnType);
67+
}
68+
69+
if (\PHP_VERSION_ID > 80000) {
70+
foreach ((new \ReflectionClass(self::class))->getMethods() as $method) {
71+
if (self::class !== $method->getDeclaringClass()->name) {
72+
continue;
73+
}
74+
75+
if (!$attribute = $method->getAttributes(SubscribedService::class)[0] ?? null) {
76+
continue;
77+
}
78+
79+
if ($method->isStatic() || $method->isAbstract() || $method->isGenerator() || $method->isInternal() || $method->getNumberOfRequiredParameters()) {
80+
// todo, what exception to throw?
81+
throw new \RuntimeException(sprintf('Cannot use "%s" on method "%s::%s()" (can only be used on non-static, non-abstract methods with no parameters).', SubscribedService::class, self::class, $method->name));
82+
}
83+
84+
if (!$returnType = $method->getReturnType()) {
85+
// todo, what exception to throw?
86+
throw new \RuntimeException(sprintf('Cannot use "%s" on methods without a return type in "%s::%s()".', SubscribedService::class, $method->name, self::class));
87+
}
88+
89+
if (!$returnType instanceof \ReflectionNamedType) {
90+
// todo, what exception to throw?
91+
throw new \RuntimeException(sprintf('Cannot use "%s" on methods with a union return type in "%s::%s()".', SubscribedService::class, $method->name, self::class));
92+
}
93+
94+
if ($returnType->isBuiltin()) {
95+
// todo, what exception to throw?
96+
throw new \RuntimeException(sprintf('Cannot use "%s" on methods with a native return type in "%s::%s()".', SubscribedService::class, $method->name, self::class));
97+
}
98+
99+
$services[$attribute->newInstance()->key ?? self::class.'::'.$method->name] = '?'.$returnType->getName();
47100
}
48101
}
49102

0 commit comments

Comments
 (0)