2424use Symfony \Component \DependencyInjection \Reference ;
2525use Symfony \Component \DependencyInjection \ServiceLocator ;
2626use Symfony \Component \DependencyInjection \Tests \Fixtures \CustomDefinition ;
27+ use Symfony \Component \DependencyInjection \Tests \Fixtures \LegacyTestServiceSubscriberChild ;
28+ use Symfony \Component \DependencyInjection \Tests \Fixtures \LegacyTestServiceSubscriberParent ;
2729use Symfony \Component \DependencyInjection \Tests \Fixtures \TestDefinition1 ;
2830use Symfony \Component \DependencyInjection \Tests \Fixtures \TestDefinition2 ;
2931use Symfony \Component \DependencyInjection \Tests \Fixtures \TestDefinition3 ;
3032use Symfony \Component \DependencyInjection \Tests \Fixtures \TestServiceSubscriber ;
3133use Symfony \Component \DependencyInjection \Tests \Fixtures \TestServiceSubscriberChild ;
3234use Symfony \Component \DependencyInjection \Tests \Fixtures \TestServiceSubscriberParent ;
3335use Symfony \Component \DependencyInjection \TypedReference ;
36+ use Symfony \Contracts \Service \Attribute \SubscribedService ;
3437use Symfony \Contracts \Service \ServiceSubscriberInterface ;
3538use Symfony \Contracts \Service \ServiceSubscriberTrait ;
3639
@@ -143,11 +146,14 @@ public function testExtraServiceSubscriber()
143146$ container ->compile ();
144147 }
145148
149+ /**
150+ * @group legacy
151+ */
146152public function testServiceSubscriberTrait ()
147153 {
148154$ container =new ContainerBuilder ();
149155
150- $ container ->register ('foo ' ,TestServiceSubscriberChild ::class)
156+ $ container ->register ('foo ' ,LegacyTestServiceSubscriberChild ::class)
151157 ->addMethodCall ('setContainer ' , [new Reference (PsrContainerInterface::class)])
152158 ->addTag ('container.service_subscriber ' )
153159 ;
@@ -159,15 +165,18 @@ public function testServiceSubscriberTrait()
159165$ locator =$ container ->getDefinition ((string )$ foo ->getMethodCalls ()[0 ][1 ][0 ]);
160166
161167$ expected = [
162- TestServiceSubscriberChild ::class.'::invalidDefinition ' =>new ServiceClosureArgument (new TypedReference ('Symfony\Component\DependencyInjection\Tests\Fixtures\InvalidDefinition ' ,'Symfony\Component\DependencyInjection\Tests\Fixtures\InvalidDefinition ' , ContainerInterface::IGNORE_ON_INVALID_REFERENCE )),
163- TestServiceSubscriberChild ::class.'::testDefinition2 ' =>new ServiceClosureArgument (new TypedReference (TestDefinition2::class, TestDefinition2::class, ContainerInterface::IGNORE_ON_INVALID_REFERENCE )),
164- TestServiceSubscriberChild ::class.'::testDefinition3 ' =>new ServiceClosureArgument (new TypedReference (TestDefinition3::class, TestDefinition3::class, ContainerInterface::IGNORE_ON_INVALID_REFERENCE )),
165- TestServiceSubscriberParent ::class.'::testDefinition1 ' =>new ServiceClosureArgument (new TypedReference (TestDefinition1::class, TestDefinition1::class, ContainerInterface::IGNORE_ON_INVALID_REFERENCE )),
168+ LegacyTestServiceSubscriberChild ::class.'::invalidDefinition ' =>new ServiceClosureArgument (new TypedReference ('Symfony\Component\DependencyInjection\Tests\Fixtures\InvalidDefinition ' ,'Symfony\Component\DependencyInjection\Tests\Fixtures\InvalidDefinition ' , ContainerInterface::IGNORE_ON_INVALID_REFERENCE )),
169+ LegacyTestServiceSubscriberChild ::class.'::testDefinition2 ' =>new ServiceClosureArgument (new TypedReference (TestDefinition2::class, TestDefinition2::class, ContainerInterface::IGNORE_ON_INVALID_REFERENCE )),
170+ LegacyTestServiceSubscriberChild ::class.'::testDefinition3 ' =>new ServiceClosureArgument (new TypedReference (TestDefinition3::class, TestDefinition3::class, ContainerInterface::IGNORE_ON_INVALID_REFERENCE )),
171+ LegacyTestServiceSubscriberParent ::class.'::testDefinition1 ' =>new ServiceClosureArgument (new TypedReference (TestDefinition1::class, TestDefinition1::class, ContainerInterface::IGNORE_ON_INVALID_REFERENCE )),
166172 ];
167173
168174$ this ->assertEquals ($ expected ,$ container ->getDefinition ((string )$ locator ->getFactory ()[0 ])->getArgument (0 ));
169175 }
170176
177+ /**
178+ * @group legacy
179+ */
171180public function testServiceSubscriberTraitWithGetter ()
172181 {
173182$ container =new ContainerBuilder ();
@@ -195,6 +204,132 @@ public function getFoo(): \stdClass
195204$ this ->assertEquals ($ expected ,$ container ->getDefinition ((string )$ locator ->getFactory ()[0 ])->getArgument (0 ));
196205 }
197206
207+ /**
208+ * @requires PHP 8
209+ */
210+ public function testServiceSubscriberTraitWithSubscribedServiceAttribute ()
211+ {
212+ $ container =new ContainerBuilder ();
213+
214+ $ container ->register ('foo ' , TestServiceSubscriberChild::class)
215+ ->addMethodCall ('setContainer ' , [new Reference (PsrContainerInterface::class)])
216+ ->addTag ('container.service_subscriber ' )
217+ ;
218+
219+ (new RegisterServiceSubscribersPass ())->process ($ container );
220+ (new ResolveServiceSubscribersPass ())->process ($ container );
221+
222+ $ foo =$ container ->getDefinition ('foo ' );
223+ $ locator =$ container ->getDefinition ((string )$ foo ->getMethodCalls ()[0 ][1 ][0 ]);
224+
225+ $ expected = [
226+ TestServiceSubscriberChild::class.'::invalidDefinition ' =>new ServiceClosureArgument (new TypedReference ('Symfony\Component\DependencyInjection\Tests\Fixtures\InvalidDefinition ' ,'Symfony\Component\DependencyInjection\Tests\Fixtures\InvalidDefinition ' , ContainerInterface::IGNORE_ON_INVALID_REFERENCE )),
227+ TestServiceSubscriberChild::class.'::testDefinition2 ' =>new ServiceClosureArgument (new TypedReference (TestDefinition2::class, TestDefinition2::class, ContainerInterface::IGNORE_ON_INVALID_REFERENCE )),
228+ TestServiceSubscriberChild::class.'::testDefinition4 ' =>new ServiceClosureArgument (new TypedReference (TestDefinition3::class, TestDefinition3::class, ContainerInterface::IGNORE_ON_INVALID_REFERENCE )),
229+ TestServiceSubscriberParent::class.'::testDefinition1 ' =>new ServiceClosureArgument (new TypedReference (TestDefinition1::class, TestDefinition1::class, ContainerInterface::IGNORE_ON_INVALID_REFERENCE )),
230+ 'custom_name ' =>new ServiceClosureArgument (new TypedReference (TestDefinition3::class, TestDefinition3::class, ContainerInterface::IGNORE_ON_INVALID_REFERENCE ,'custom_name ' )),
231+ ];
232+
233+ $ this ->assertEquals ($ expected ,$ container ->getDefinition ((string )$ locator ->getFactory ()[0 ])->getArgument (0 ));
234+ }
235+
236+ /**
237+ * @requires PHP 8
238+ */
239+ public function testServiceSubscriberTraitWithSubscribedServiceAttributeOnStaticMethod ()
240+ {
241+ $ subscriber =new class ()implements ServiceSubscriberInterface {
242+ use ServiceSubscriberTrait;
243+
244+ #[SubscribedService]
245+ public static function method ():TestDefinition1
246+ {
247+ }
248+ };
249+
250+ $ this ->expectException (\LogicException::class);
251+
252+ $ subscriber ::getSubscribedServices ();
253+ }
254+
255+ /**
256+ * @requires PHP 8
257+ */
258+ public function testServiceSubscriberTraitWithSubscribedServiceAttributeOnMethodWithRequiredParameters ()
259+ {
260+ $ subscriber =new class ()implements ServiceSubscriberInterface {
261+ use ServiceSubscriberTrait;
262+
263+ #[SubscribedService]
264+ public function method ($ param1 ,$ param2 =null ):TestDefinition1
265+ {
266+ }
267+ };
268+
269+ $ this ->expectException (\LogicException::class);
270+
271+ $ subscriber ::getSubscribedServices ();
272+ }
273+
274+ /**
275+ * @requires PHP 8
276+ */
277+ public function testServiceSubscriberTraitWithSubscribedServiceAttributeOnMethodMissingReturnType ()
278+ {
279+ $ subscriber =new class ()implements ServiceSubscriberInterface {
280+ use ServiceSubscriberTrait;
281+
282+ #[SubscribedService]
283+ public function method ()
284+ {
285+ }
286+ };
287+
288+ $ this ->expectException (\LogicException::class);
289+
290+ $ subscriber ::getSubscribedServices ();
291+ }
292+
293+ /**
294+ * @requires PHP 8
295+ */
296+ public function testServiceSubscriberTraitWithSubscribedServiceAttributeOnMethodWithBuiltInReturnType ()
297+ {
298+ $ subscriber =new class ()implements ServiceSubscriberInterface {
299+ use ServiceSubscriberTrait;
300+
301+ #[SubscribedService]
302+ public function method ():string
303+ {
304+ }
305+ };
306+
307+ $ this ->expectException (\LogicException::class);
308+
309+ $ subscriber ::getSubscribedServices ();
310+ }
311+
312+ /**
313+ * @requires PHP 8
314+ */
315+ public function testServiceSubscriberTraitWithSubscribedServiceAttributeOnMethodWithUnionReturnType ()
316+ {
317+ eval ('
318+ $subscriber = new class() implements Symfony\Contracts\Service\ServiceSubscriberInterface {
319+ use Symfony\Contracts\Service\ServiceSubscriberTrait;
320+
321+ #[Symfony\Contracts\Service\Attribute\SubscribedService]
322+ public function method(): TestDefinition1|TestDefinition2
323+ {
324+ }
325+ };
326+ ' );
327+
328+ $ this ->expectException (\LogicException::class);
329+
330+ $ subscriber ::getSubscribedServices ();
331+ }
332+
198333public function testServiceSubscriberWithSemanticId ()
199334 {
200335$ container =new ContainerBuilder ();