8000 [Contracts] Rename ServiceSubscriberTrait to ServiceMethodsSubscriber… · symfony/symfony@8f47ced · GitHub
[go: up one dir, main page]

Skip to content

Commit 8f47ced

Browse files
[Contracts] Rename ServiceSubscriberTrait to ServiceMethodsSubscriberTrait
1 parent 4ce4e5e commit 8f47ced

14 files changed

+395
-112
lines changed

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

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,8 @@
4343
use Symfony\Component\DependencyInjection\Tests\Fixtures\TestServiceSubscriberUnionWithTrait;
4444
use Symfony\Component\DependencyInjection\TypedReference;
4545
use Symfony\Contracts\Service\Attribute\SubscribedService;
46+
use Symfony\Contracts\Service\ServiceMethodsSubscriberTrait;
4647
use Symfony\Contracts\Service\ServiceSubscriberInterface;
47-
use Symfony\Contracts\Service\ServiceSubscriberTrait;
4848

4949
require_once __DIR__.'/../Fixtures/includes/classes.php';
5050

@@ -221,7 +221,7 @@ public function testExtraServiceSubscriber()
221221
$container->compile();
222222
}
223223

224-
public function testServiceSubscriberTraitWithSubscribedServiceAttribute()
224+
public function testServiceMethodsSubscriberTraitWithSubscribedServiceAttribute()
225225
{
226226
if (!class_exists(SubscribedService::class)) {
227227
$this->markTestSkipped('SubscribedService attribute not available.');
@@ -251,14 +251,14 @@ public function testServiceSubscriberTraitWithSubscribedServiceAttribute()
251251
$this->assertEquals($expected, $container->getDefinition((string) $locator->getFactory()[0])->getArgument(0));
252252
}
253253

254-
public function testServiceSubscriberTraitWithSubscribedServiceAttributeOnStaticMethod()
254+
public function testServiceMethodsSubscriberTraitWithSubscribedServiceAttributeOnStaticMethod()
255255
{
256256
if (!class_exists(SubscribedService::class)) {
257257
$this->markTestSkipped('SubscribedService attribute not available.');
258258
}
259259

260260
$subscriber = new class() implements ServiceSubscriberInterface {
261-
use ServiceSubscriberTrait;
261+
use ServiceMethodsSubscriberTrait;
262262

263263
#[SubscribedService]
264264
public static function method(): TestDefinition1
@@ -271,14 +271,14 @@ public static function method(): TestDefinition1
271271
$subscriber::getSubscribedServices();
272272
}
273273

274-
public function testServiceSubscriberTraitWithSubscribedServiceAttributeOnMethodWithRequiredParameters()
274+
public function testServiceMethodsSubscriberTraitWithSubscribedServiceAttributeOnMethodWithRequiredParameters()
275275
{
276276
if (!class_exists(SubscribedService::class)) {
277277
$this->markTestSkipped('SubscribedService attribute not available.');
278278
}
279279

280280
$subscriber = new class() implements ServiceSubscriberInterface {
281-
use ServiceSubscriberTrait;
281+
use ServiceMethodsSubscriberTrait;
282282

283283
#[SubscribedService]
284284
public function method($param1, $param2 = null): TestDefinition1
@@ -291,14 +291,14 @@ public function method($param1, $param2 = null): TestDefinition1
291291
$subscriber::getSubscribedServices();
292292
}
293293

294-
public function testServiceSubscriberTraitWithSubscribedServiceAttributeOnMethodMissingReturnType()
294+
public function testServiceMethodsSubscriberTraitWithSubscribedServiceAttributeOnMethodMissingReturnType()
295295
{
296296
if (!class_exists(SubscribedService::class)) {
297297
$this->markTestSkipped('SubscribedService attribute not available.');
298298
}
299299

300300
$subscriber = new class() implements ServiceSubscriberInterface {
301-
use ServiceSubscriberTrait;
301+
use ServiceMethodsSubscriberTrait;
302302

303303
#[SubscribedService]
304304
public function method()
@@ -311,7 +311,7 @@ public function method()
311311
$subscriber::getSubscribedServices();
312312
}
313313

314-
public function testServiceSubscriberTraitWithUnionReturnType()
314+
public function testServiceMethodsSubscriberTraitWithUnionReturnType()
315315
{
316316
if (!class_exists(SubscribedService::class)) {
317317
$this->markTestSkipped('SubscribedService attribute not available.');
@@ -338,7 +338,7 @@ public function testServiceSubscriberTraitWithUnionReturnType()
338338
$this->assertEquals($expected, $container->getDefinition((string) $locator->getFactory()[0])->getArgument(0));
339339
}
340340

341-
public function testServiceSubscriberTraitWithIntersectionReturnType()
341+
public function testServiceMethodsSubscriberTraitWithIntersectionReturnType()
342342
{
343343
if (!class_exists(SubscribedService::class)) {
344344
$this->markTestSkipped('SubscribedService attribute not available.');

src/Symfony/Component/DependencyInjection/Tests/Fixtures/TestServiceSubscriberTrait.php renamed to src/Symfony/Component/DependencyInjection/Tests/Fixtures/TestServiceMethodsSubscriberTrait.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
use Symfony\Contracts\Service\Attribute\SubscribedService;
66

7-
trait TestServiceSubscriberTrait
7+
trait TestServiceMethodsSubscriberTrait
88
{
99
protected function protectedFunction1(): SomeClass
1010
{

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,12 @@
33
namespace Symfony\Component\DependencyInjection\Tests\Fixtures;
44

55
use Symfony\Contracts\Service\Attribute\SubscribedService;
6-
use Symfony\Contracts\Service\ServiceSubscriberTrait;
6+
use Symfony\Contracts\Service\ServiceMethodsSubscriberTrait;
77

88
class TestServiceSubscriberChild extends TestServiceSubscriberParent
99
{
10-
use ServiceSubscriberTrait;
11-
use TestServiceSubscriberTrait;
10+
use ServiceMethodsSubscriberTrait;
11+
use TestServiceMethodsSubscriberTrait;
1212

1313
#[SubscribedService]
1414
private function testDefinition2(): ?TestDefinition2

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,12 @@
33
namespace Symfony\Component\DependencyInjection\Tests\Fixtures;
44

55
use Symfony\Contracts\Service\Attribute\SubscribedService;
6+
use Symfony\Contracts\Service\ServiceMethodsSubscriberTrait;
67
use Symfony\Contracts\Service\ServiceSubscriberInterface;
7-
use Symfony\Contracts\Service\ServiceSubscriberTrait;
88

99
class TestServiceSubscriberIntersectionWithTrait implements ServiceSubscriberInterface
1010
{
11-
use ServiceSubscriberTrait;
11+
use ServiceMethodsSubscriberTrait;
1212

1313
#[SubscribedService]
1414
private function method1(): TestDefinition1&TestDefinition2

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,12 @@
33
namespace Symfony\Component\DependencyInjection\Tests\Fixtures;
44

55
use Symfony\Contracts\Service\Attribute\SubscribedService;
6+
use Symfony\Contracts\Service\ServiceMethodsSubscriberTrait;
67
use Symfony\Contracts\Service\ServiceSubscriberInterface;
7-
use Symfony\Contracts\Service\ServiceSubscriberTrait;
88

99
class TestServiceSubscriberParent implements ServiceSubscriberInterface
1010
{
11-
use ServiceSubscriberTrait;
11+
use ServiceMethodsSubscriberTrait;
1212

1313
public function publicFunction1(): SomeClass
1414
{

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,12 @@
33
namespace Symfony\Component\DependencyInjection\Tests\Fixtures;
44

55
use Symfony\Contracts\Service\Attribute\SubscribedService;
6+
use Symfony\Contracts\Service\ServiceMethodsSubscriberTrait;
67
use Symfony\Contracts\Service\ServiceSubscriberInterface;
7-
use Symfony\Contracts\Service\ServiceSubscriberTrait;
88

99
class TestServiceSubscriberUnionWithTrait implements ServiceSubscriberInterface
1010
{
11-
use ServiceSubscriberTrait;
11+
use ServiceMethodsSubscriberTrait;
1212

1313
#[SubscribedService]
1414
private function method1(): TestDefinition1|TestDefinition2|null

src/Symfony/Contracts/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ CHANGELOG
55
---
66

77
* Add `ServiceCollectionInterface`
8+
* Deprecate `ServiceSubscriberTrait`, use `ServiceMethodsSubscriberTrait` instead
89

910
3.4
1011
---

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

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

1212
namespace Symfony\Contracts\Service\Attribute;
1313

14+
use Symfony\Contracts\Service\ServiceMethodsSubscriberTrait;
1415
use Symfony\Contracts\Service\ServiceSubscriberInterface;
15-
use Symfony\Contracts\Service\ServiceSubscriberTrait;
1616

1717
/**
1818
* For use as the return value for {@see ServiceSubscriberInterface}.
1919
*
2020
* @example new SubscribedService('http_client', HttpClientInterface::class, false, new Target('githubApi'))
2121
*
22-
* Use with {@see ServiceSubscriberTrait} to mark a method's return type
22+
* Use with {@see ServiceMethodsSubscriberTrait} to mark a method's return type
2323
* as a subscribed service.
2424
*
2525
* @author Kevin Bond <kevinbond@gmail.com>
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
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;
13+
14+
use Psr\Container\ContainerInterface;
15+
use Symfony\Contracts\Service\Attribute\Required;
16+
use Symfony\Contracts\Service\Attribute\SubscribedService;
17+
18+
/**
19+
* Implementation of ServiceSubscriberInterface that determines subscribed services
20+
* from methods that have the #[SubscribedService] attribute.
21+
*
22+
* Service ids are available as "ClassName::methodName" so that the implementation
23+
* of subscriber methods can be just `return $this->container->get(__METHOD__);`.
24+
*
25+
* @author Kevin Bond <kevinbond@gmail.com>
26+
*/
27+
trait ServiceMethodsSubscriberTrait
28+
{
29+
protected ContainerInterface $container;
30+
31+
public static function getSubscribedServices(): array
32+
{
33+
$services = method_exists(get_parent_class(self::class) ?: '', __FUNCTION__) ? parent::getSubscribedServices() : [];
34+
35+
foreach ((new \ReflectionClass(self::class))->getMethods() as $method) {
36+
if (self::class !== $method->getDeclaringClass()->name) {
37+
continue;
38+
}
39+
40+
if (!$attribute = $method->getAttributes(SubscribedService::class)[0] ?? null) {
41+
continue;
42+
}
43+
44+
if ($method->isStatic() || $method->isAbstract() || $method->isGenerator() || $method->isInternal() || $method->getNumberOfRequiredParameters()) {
45+
throw new \LogicException(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));
46+
}
47+
48+
if (!$returnType = $method->getReturnType()) {
49+
throw new \LogicException(sprintf('Cannot use "%s" on methods without a return type in "%s::%s()".', SubscribedService::class, $method->name, self::class));
50+
}
51+
52+
/* @var SubscribedService $attribute */
53+
$attribute = $attribute->newInstance();
54+
$attribute->key ??= self::class.'::'.$method->name;
55+
$attribute->type ??= $returnType instanceof \ReflectionNamedType ? $returnType->getName() : (string) $returnType;
56+
$attribute->nullable = $returnType->allowsNull();
57+
58+
if ($attribute->attributes) {
59+
$services[] = $attribute;
60+
} else {
61+
$services[$attribute->key] = ($attribute->nullable ? '?' : '').$attribute->type;
62+
}
63+
}
64+
65+
return $services;
66+
}
67+
68+
#[Required]
69+
public function setContainer(ContainerInterface $container): ?ContainerInterface
70+
{
71+
$ret = null;
72+
if (method_exists(get_parent_class(self::class) ?: '', __FUNCTION__)) {
73+
$ret = parent::setContainer($container);
74+
}
75+
76+
$this->container = $container;
77+
78+
return $ret;
79+
}
80+
}

src/Symfony/Contracts/Service/ServiceSubscriberTrait.php

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,17 +15,23 @@
1515
use Symfony\Contracts\Service\Attribute\Required;
1616
use Symfony\Contracts\Service\Attribute\SubscribedService;
1717

18+
trigger_deprecation('symfony/contracts', 'v3.5', '"%s" is deprecated, use "ServiceMethodsSubscriberTrait" instead.', ServiceSubscriberTrait::class);
19+
1820
/**
19-
* Implementation of ServiceSubscriberInterface that determines subscribed services from
20-
* method return types. Service ids are available as "ClassName::methodName".
21+
* Implementation of ServiceSubscriberInterface that determines subscribed services
22+
* from methods that have the #[SubscribedService] attribute.
23+
*
24+
* Service ids are available as "ClassName::methodName" so that the implementation
25+
* of subscriber methods can be just `return $this->container->get(__METHOD__);`.
26+
*
27+
* @property ContainerInterface $container
2128
*
2229
* @author Kevin Bond <kevinbond@gmail.com>
30+
*
31+
* @deprecated since symfony/contracts v3.5, use ServiceMethodsSubscriberTrait instead
2332
*/
2433
trait ServiceSubscriberTrait
2534
{
26-
/** @var ContainerInterface */
27-
protected $container;
28-
2935
public static function getSubscribedServices(): array
3036
{
3137
$services = method_exists(get_parent_class(self::class) ?: '', __FUNCTION__) ? parent::getSubscribedServices() : [];

src/Symfony/Contracts/Service/composer.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@
1717
],
1818
"require": {
1919
"php": ">=8.1",
20-
"psr/container": "^1.1|^2.0"
20+
"psr/container": "^1.1|^2.0",
21+
"symfony/deprecation-contracts": "^2.5|^3"
2122
},
2223
"conflict": {
2324
"ext-psr": "<1.1|>=2"
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
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\Tests\Service;
13+
14+
use Psr\Container\ContainerInterface;
15+
use Symfony\Contracts\Service\Attribute\Required;
16+
use Symfony\Contracts\Service\Attribute\SubscribedService;
17+
use Symfony\Contracts\Service\ServiceSubscriberInterface;
18+
use Symfony\Contracts\Service\ServiceSubscriberTrait;
19+
20+
class LegacyParentTestService
21+
{
22+
public function aParentService(): Service1
23+
{
24+
}
25+
26+
public function setContainer(ContainerInterface $container): ?ContainerInterface
27+
{
28+
return $container;
29+
}
30+
}
31+
32+
class LegacyTestService extends LegacyParentTestService implements ServiceSubscriberInterface
33+
{
34+
use ServiceSubscriberTrait;
35+
36+
#[SubscribedService]
37+
public function aService(): Service2
38+
{
39+
return $this->container->get(__METHOD__);
40+
}
41+
42+
#[SubscribedService]
43+
public function nullableService(): ?Service2
44+
{
45+
return $this->container->get(__METHOD__);
46+
}
47+
48+
#[SubscribedService(attributes: new Required())]
49+
public function withAttribute(): ?Service2
50+
{
51+
return $this->container->get(__METHOD__);
52+
}
53+
}
54+
55+
class LegacyChildTestService extends LegacyTestService
56+
{
57+
#[SubscribedService()]
58+
public function aChildService(): LegacyService3
59+
{
60+
return $this->container->get(__METHOD__);
61+
}
62+
}
63+
64+
class LegacyParentWithMagicCall
65+
{
66+
public function __call($method, $args)
67+
{
68+
throw new \BadMethodCallException('Should not be called.');
69+
}
70+
71+
public static function __callStatic($method, $args)
72+
{
73+
throw new \BadMethodCallException('Should not be called.');
74+
}
75+
}
76+
77+
class LegacyService3
78+
{
79+
}
80+
81+
class LegacyParentTestService2
82+
{
83+
/** @var ContainerInterface */
84+
protected $container;
85+
86+
public function setContainer(ContainerInterface $container)
87+
{
88+
$previous = $this->container ?? null;
89+
$this->container = $container;
90+
91+
return $previous;
92+
}
93+
}

0 commit comments

Comments
 (0)
0