8000 [DependencyInjection] add `#[AutowireLocator]` attribute · symfony/symfony@5fa830d · GitHub
[go: up one dir, main page]

Skip to content

Commit 5fa830d

Browse files
kbondnicolas-grekas
authored andcommitted
[DependencyInjection] add #[AutowireLocator] attribute
1 parent ff654da commit 5fa830d

18 files changed

+214
-61
lines changed
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
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\Component\DependencyInjection\Attribute;
13+
14+
use Symfony\Component\DependencyInjection\Argument\ServiceLocatorArgument;
15+
use Symfony\Component\DependencyInjection\ContainerInterface;
16+
use Symfony\Component\DependencyInjection\Reference;
17+
18+
#[\Attribute(\Attribute::TARGET_PARAMETER)]
19+
class AutowireLocator extends Autowire
20+
{
21+
public function __construct(string ...$serviceIds)
22+
{
23+
$values = [];
24+
25+
foreach ($serviceIds as $key => $serviceId) {
26+
if ($nullable = str_starts_with($serviceId, '?')) {
27+
$serviceId = substr($serviceId, 1);
28+
}
29+
30+
if (is_numeric($key)) {
31+
$key = $serviceId;
32+
}
33+
34+
$values[$key] = new Reference(
35+
$serviceId,
36+
$nullable ? ContainerInterface::IGNORE_ON_INVALID_REFERENCE : ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE,
37+
);
38+
}
39+
40+
parent::__construct(new ServiceLocatorArgument($values));
41+
}
42+
}

src/Symfony/Component/DependencyInjection/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ CHANGELOG
77
* Allow using `#[Target]` with no arguments to state that a parameter must match a named autowiring alias
88
* Deprecate `ContainerAwareInterface` and `ContainerAwareTrait`, use dependency injection instead
99
* Add `defined` env var processor that returns `true` for defined and neither null nor empty env vars
10+
* Add `#[AutowireLocator]` attribute
1011

1112
6.3
1213
---
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
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\Component\DependencyInjection\Tests\Attribute;
13+
14+
use PHPUnit\Framework\TestCase;
15+
use Symfony\Component\DependencyInjection\Argument\ServiceLocatorArgument;
16+
use Symfony\Component\DependencyInjection\Attribute\AutowireLocator;
17+
use Symfony\Component\DependencyInjection\ContainerInterface;
18+
use Symfony\Component\DependencyInjection\Reference;
19+
20+
class AutowireLocatorTest extends TestCase
21+
{
22+
public function testSimpleLocator()
23+
{
24+
$locator = new AutowireLocator('foo', 'bar');
25+
26+
$this->assertEquals(
27+
new ServiceLocatorArgument(['foo' => new Reference('foo'), 'bar' => new Reference('bar')]),
28+
$locator->value,
29+
);
30+
}
31+
32+
public function testComplexLocator()
33+
{
34+
$locator = new AutowireLocator(
35+
'?qux',
36+
foo: 'bar',
37+
bar: '?baz',
38+
);
39+
40+
$this->assertEquals(
41+
new ServiceLocatorArgument([
42+
'qux' => new Reference('qux', ContainerInterface::IGNORE_ON_INVALID_REFERENCE),
43+
'foo' => new Reference('bar'),
44+
'bar' => new Reference('baz', ContainerInterface::IGNORE_ON_INVALID_REFERENCE),
45+
]),
46+
$locator->value,
47+
);
48+
}
49+
}

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

Lines changed: 68 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -32,23 +32,24 @@
3232
use Symfony\Component\DependencyInjection\Tests\Fixtures\AutoconfiguredInterface2;
3333
use Symfony\Component\DependencyInjection\Tests\Fixtures\AutoconfiguredService1;
3434
use Symfony\Component\DependencyInjection\Tests\Fixtures\AutoconfiguredService2;
35+
use Symfony\Component\DependencyInjection\Tests\Fixtures\AutowireLocatorConsumer;
3536
use Symfony\Component\DependencyInjection\Tests\Fixtures\BarTagClass;
3637
use Symfony\Component\DependencyInjection\Tests\Fixtures\FooBarTaggedClass;
3738
use Symfony\Component\DependencyInjection\Tests\Fixtures\FooBarTaggedForDefaultPriorityClass;
3839
use Symfony\Component\DependencyInjection\Tests\Fixtures\FooTagClass;
39-
use Symfony\Component\DependencyInjection\Tests\Fixtures\IteratorConsumer;
40-
use Symfony\Component\DependencyInjection\Tests\Fixtures\IteratorConsumerWithDefaultIndexMethod;
41-
use Symfony\Component\DependencyInjection\Tests\Fixtures\IteratorConsumerWithDefaultIndexMethodAndWithDefaultPriorityMethod;
42-
use Symfony\Component\DependencyInjection\Tests\Fixtures\IteratorConsumerWithDefaultPriorityMethod;
43-
use Symfony\Component\DependencyInjection\Tests\Fixtures\LocatorConsumer;
44-
use Symfony\Component\DependencyInjection\Tests\Fixtures\LocatorConsumerConsumer;
45-
use Symfony\Component\DependencyInjection\Tests\Fixtures\LocatorConsumerFactory;
46-
use Symfony\Component\DependencyInjection\Tests\Fixtures\LocatorConsumerWithDefaultIndexMethod;
47-
use Symfony\Component\DependencyInjection\Tests\Fixtures\LocatorConsumerWithDefaultIndexMethodAndWithDefaultPriorityMethod;
48-
use Symfony\Component\DependencyInjection\Tests\Fixtures\LocatorConsumerWithDefaultPriorityMethod;
49-
use Symfony\Component\DependencyInjection\Tests\Fixtures\LocatorConsumerWithoutIndex;
5040
use Symfony\Component\DependencyInjection\Tests\Fixtures\StaticMethodTag;
5141
use Symfony\Component\DependencyInjection\Tests\Fixtures\TaggedConsumerWithExclude;
42+
use Symfony\Component\DependencyInjection\Tests\Fixtures\TaggedIteratorConsumer;
43+
use Symfony\Component\DependencyInjection\Tests\Fixtures\TaggedIteratorConsumerWithDefaultIndexMethod;
44+
use Symfony\Component\DependencyInjection\Tests\Fixtures\TaggedIteratorConsumerWithDefaultIndexMethodAndWithDefaultPriorityMethod;
45+
use Symfony\Component\DependencyInjection\Tests\Fixtures\TaggedIteratorConsumerWithDefaultPriorityMethod;
46+
use Symfony\Component\DependencyInjection\Tests\Fixtures\TaggedLocatorConsumer;
47+
use Symfony\Component\DependencyInjection\Tests\Fixtures\TaggedLocatorConsumerConsumer;
48+
use Symfony\Component\DependencyInjection\Tests\Fixtures\TaggedLocatorConsumerFactory;
49+
use Symfony\Component\DependencyInjection\Tests\Fixtures\TaggedLocatorConsumerWithDefaultIndexMethod;
50+
use Symfony\Component\DependencyInjection\Tests\Fixtures\TaggedLocatorConsumerWithDefaultIndexMethodAndWithDefaultPriorityMethod;
51+
use Symfony\Component\DependencyInjection\Tests\Fixtures\TaggedLocatorConsumerWithDefaultPriorityMethod;
52+
use Symfony\Component\DependencyInjection\Tests\Fixtures\TaggedLocatorConsumerWithoutIndex;
5253
use Symfony\Component\DependencyInjection\Tests\Fixtures\TaggedService1;
5354
use Symfony\Component\DependencyInjection\Tests\Fixtures\TaggedService2;
5455
use Symfony\Component\DependencyInjection\Tests\Fixtures\TaggedService3;
@@ -388,6 +389,30 @@ public function testTaggedServiceWithIndexAttributeAndDefaultMethod()
388389
$this->assertSame(['bar_tab_class_with_defaultmethod' => $container->get(BarTagClass::class), 'foo' => $container->get(FooTagClass::class)], $param);
389390
}
390391

392+
public function testLocatorConfiguredViaAttribute()
393+
{
394+
$container = new ContainerBuilder();
395+
$container->register(BarTagClass::class)
396+
->setPublic(true)
397+
;
398+
$container->register(FooTagClass::class)
399+
->setPublic(true)
400+
;
401+
$container->register(AutowireLocatorConsumer::class)
402+
->setAutowired(true)
403+
->setPublic(true)
404+
;
405+
406+
$container->compile();
407+
408+
/** @var AutowireLocatorConsumer $s */
409+
$s = $container->get(AutowireLocatorConsumer::class);
410+
411+
self::assertSame($container->get(BarTagClass::class), $s->locator->get(BarTagClass::class));
412+
self::assertSame($container->get(FooTagClass::class), $s->locator->get('with_key'));
413+
self::assertFalse($s->locator->has('nullable'));
414+
}
415+
391416
public function testTaggedServiceWithIndexAttributeAndDefaultMethodConfiguredViaAttribute()
392417
{
393418
$container = new ContainerBuilder();
@@ -399,14 +424,14 @@ public function testTaggedServiceWithIndexAttributeAndDefaultMethodConfiguredVia
399424
->setPublic(true)
400425
->addTag('foo_bar', ['foo' => 'foo'])
401426
;
402-
$container->register(IteratorConsumer::class)
427+
$container->register(TaggedIteratorConsumer::class)
403428
->setAutowired(true)
404429
->setPublic(true)
405430
;
406431

407432
$container->compile();
408433

409-
$s = $container->get(IteratorConsumer::class);
434+
$s = $container->get(TaggedIteratorConsumer::class);
410435

411436
$param = iterator_to_array($s->getParam()->getIterator());
412437
$this->assertSame(['bar_tab_class_with_defaultmethod' => $container->get(BarTagClass::class), 'foo' => $container->get(FooTagClass::class)], $param);
@@ -423,14 +448,14 @@ public function testTaggedIteratorWithDefaultIndexMethodConfiguredViaAttribute()
423448
->setPublic(true)
424449
->addTag('foo_bar')
425450
;
426-
$container->register(IteratorConsumerWithDefaultIndexMethod::class)
451+
$container->register(TaggedIteratorConsumerWithDefaultIndexMethod::class)
427452
->setAutowired(true)
428453
->setPublic(true)
429454
;
430455

431456
$container->compile();
432457

433-
$s = $container->get(IteratorConsumerWithDefaultIndexMethod::class);
458+
$s = $container->get(TaggedIteratorConsumerWithDefaultIndexMethod::class);
434459

435460
$param = iterator_to_array($s->getParam()->getIterator());
436461
$this->assertSame(['bar_tag_class' => $container->get(BarTagClass::class), 'foo_tag_class' => $container->get(FooTagClass::class)], $param);
@@ -447,14 +472,14 @@ public function testTaggedIteratorWithDefaultPriorityMethodConfiguredViaAttribut
447472
->setPublic(true)
448473
->addTag('foo_bar')
449474
;
450-
$container->register(IteratorConsumerWithDefaultPriorityMethod::class)
475+
$container->register(TaggedIteratorConsumerWithDefaultPriorityMethod::class)
451476
->setAutowired(true)
452477
->setPublic(true)
453478
;
454479

455480
$container->compile();
456481

457-
$s = $container->get(IteratorConsumerWithDefaultPriorityMethod::class);
482+
$s = $container->get(TaggedIteratorConsumerWithDefaultPriorityMethod::class);
458483

459484
$param = iterator_to_array($s->getParam()->getIterator());
460485
$this->assertSame([0 => $container->get(FooTagClass::class), 1 => $container->get(BarTagClass::class)], $param);
@@ -471,14 +496,14 @@ public function testTaggedIteratorWithDefaultIndexMethodAndWithDefaultPriorityMe
471496
->setPublic(true)
472497
->addTag('foo_bar')
473498
;
474-
$container->register(IteratorConsumerWithDefaultIndexMethodAndWithDefaultPriorityMethod::class)
499+
$container->register(TaggedIteratorConsumerWithDefaultIndexMethodAndWithDefaultPriorityMethod::class)
475500
->setAutowired(true)
476501
->setPublic(true)
477502
;
478503

479504
$container->compile();
480505

481-
$s = $container->get(IteratorConsumerWithDefaultIndexMethodAndWithDefaultPriorityMethod::class);
506+
$s = $container->get(TaggedIteratorConsumerWithDefaultIndexMethodAndWithDefaultPriorityMethod::class);
482507

483508
$param = iterator_to_array($s->getParam()->getIterator());
484509
$this->assertSame(['foo_tag_class' => $container->get(FooTagClass::class), 'bar_tag_class' => $container->get(BarTagClass::class)], $param);
@@ -495,15 +520,15 @@ public function testTaggedLocatorConfiguredViaAttribute()
495520
->setPublic(true)
496521
->addTag('foo_bar', ['foo' => 'foo'])
497522
;
498-
$container->register(LocatorConsumer::class)
523+
$container->register(TaggedLocatorConsumer::class)
499524
->setAutowired(true)
500525
->setPublic(true)
501526
;
502527

503528
$container->compile();
504529

505-
/** @var LocatorConsumer $s */
506-
$s = $container->get(LocatorConsumer::class);
530+
/** @var TaggedLocatorConsumer $s */
531+
$s = $container->get(TaggedLocatorConsumer::class);
507532

508533
$locator = $s->getLocator();
509534
self::assertSame($container->get(BarTagClass::class), $locator->get('bar_tab_class_with_defaultmethod'));
@@ -521,15 +546,15 @@ public function testTaggedLocatorConfiguredViaAttributeWithoutIndex()
521546
->setPublic(true)
522547
->addTag('foo_bar')
523548
;
524-
$container->register(LocatorConsumerWithoutIndex::class)
549+
$container->register(TaggedLocatorConsumerWithoutIndex::class)
525550
->setAutowired(true)
526551
->setPublic(true)
527552
;
528553

529554
$container->compile();
530555

531-
/** @var LocatorConsumerWithoutIndex $s */
532-
$s = $container->get(LocatorConsumerWithoutIndex::class);
556+
/** @var TaggedLocatorConsumerWithoutIndex $s */
557+
$s = $container->get(TaggedLocatorConsumerWithoutIndex::class);
533558

534559
$locator = $s->getLocator();
535560
self::assertSame($container->get(BarTagClass::class), $locator->get(BarTagClass::class));
@@ -547,15 +572,15 @@ public function testTaggedLocatorWithDefaultIndexMethodConfiguredViaAttribute()
547572
->setPublic(true)
548573
->addTag('foo_bar')
549574
;
550-
$container->register(LocatorConsumerWithDefaultIndexMethod::class)
575+
$container->register(TaggedLocatorConsumerWithDefaultIndexMethod::class)
551576
->setAutowired(true)
552577
->setPublic(true)
553578
;
554579

555580
$container->compile();
556581

557-
/** @var LocatorConsumerWithoutIndex $s */
558-
$s = $container->get(LocatorConsumerWithDefaultIndexMethod::class);
582+
/** @var TaggedLocatorConsumerWithoutIndex $s */
583+
$s = $container->get(TaggedLocatorConsumerWithDefaultIndexMethod::class);
559584

560585
$locator = $s->getLocator();
561586
self::assertSame($container->get(BarTagClass::class), $locator->get('bar_tag_class'));
@@ -573,15 +598,15 @@ public function testTaggedLocatorWithDefaultPriorityMethodConfiguredViaAttribute
573598
->setPublic(true)
574599
->addTag('foo_bar')
575600
;
576-
$container->register(LocatorConsumerWithDefaultPriorityMethod::class)
601+
$container->register(TaggedLocatorConsumerWithDefaultPriorityMethod::class)
577602
->setAutowired(true)
578603
->setPublic(true)
579604
;
580605

581606
$container->compile();
582607

583-
/** @var LocatorConsumerWithoutIndex $s */
584-
$s = $container->get(LocatorConsumerWithDefaultPriorityMethod::class);
608+
/** @var TaggedLocatorConsumerWithoutIndex $s */
609+
$s = $container->get(TaggedLocatorConsumerWithDefaultPriorityMethod::class);
585610

586611
$locator = $s->getLocator();
587612

@@ -602,15 +627,15 @@ public function testTaggedLocatorWithDefaultIndexMethodAndWithDefaultPriorityMet
602627
->setPublic(true)
603628
->addTag('foo_bar')
604629
;
605-
$container->register(LocatorConsumerWithDefaultIndexMethodAndWithDefaultPriorityMethod::class)
630+
$container->register(TaggedLocatorConsumerWithDefaultIndexMethodAndWithDefaultPriorityMethod::class)
606631
->setAutowired(true)
607632
->setPublic(true)
608633
;
609634

610635
$container->compile();
611636

612-
/** @var LocatorConsumerWithoutIndex $s */
613-
$s = $container->get(LocatorConsumerWithDefaultIndexMethodAndWithDefaultPriorityMethod::class);
637+
/** @var TaggedLocatorConsumerWithoutIndex $s */
638+
$s = $container->get(TaggedLocatorConsumerWithDefaultIndexMethodAndWithDefaultPriorityMethod::class);
614639

615640
$locator = $s->getLocator();
616641

@@ -629,18 +654,18 @@ public function testNestedDefinitionWithAutoconfiguredConstructorArgument()
629654
->setPublic(true)
630655
->addTag('foo_bar', ['foo' => 'foo'])
631656
;
632-
$container->register(LocatorConsumerConsumer::class)
657+
$container->register(TaggedLocatorConsumerConsumer::class)
633658
->setPublic(true)
634659
->setArguments([
635-
(new Definition(LocatorConsumer::class))
660+
(new Definition(TaggedLocatorConsumer::class))
636661
->setAutowired(true),
637662
])
638663
;
639664

640665
$container->compile();
641666

642-
/** @var LocatorConsumerConsumer $s */
643-
$s = $container->get(LocatorConsumerConsumer::class);
667+
/** @var TaggedLocatorConsumerConsumer $s */
668+
$s = $container->get(TaggedLocatorConsumerConsumer::class);
644669

645670
$locator = $s->getLocatorConsumer()->getLocator();
646671
self::assertSame($container->get(FooTagClass::class), $locator->get('foo'));
@@ -653,17 +678,17 @@ public function testFactoryWithAutoconfiguredArgument()
653678
->setPublic(true)
654679
->addTag('foo_bar', ['key' => 'my_service'])
655680
;
656-
$container->register(LocatorConsumerFactory::class);
657-
$container->register(LocatorConsumer::class)
681+
$container->register(TaggedLocatorConsumerFactory::class);
682+
$container->register(TaggedLocatorConsumer::class)
658683
->setPublic(true)
659684
->setAutowired(true)
660-
->setFactory(new Reference(LocatorConsumerFactory::class))
685+
->setFactory(new Reference(TaggedLocatorConsumerFactory::class))
661686
;
662687

663688
$container->compile();
664689

665-
/** @var LocatorConsumer $s */
666-
$s = $container->get(LocatorConsumer::class);
690+
/** @var TaggedLocatorConsumer $s */
691+
$s = $container->get(TaggedLocatorConsumer::class);
667692

668693
$locator = $s->getLocator();
669694
self::assertSame($container->get(FooTagClass::class), $locator->get('my_service'));

0 commit comments

Comments
 (0)
0