Skip to content

Commit c58e6ea

Browse files
committed
[DependencyInjection] add Autowire attribute
1 parent 1df76df commit c58e6ea

File tree

5 files changed

+117
-0
lines changed

5 files changed

+117
-0
lines changed
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
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\Exception\LogicException;
15+
use Symfony\Component\DependencyInjection\Reference;
16+
use Symfony\Component\ExpressionLanguage\Expression;
17+
18+
/**
19+
* Attribute to tell a parameter how to be autowired.
20+
*
21+
* @author Kevin Bond <kevinbond@gmail.com>
22+
*/
23+
#[\Attribute(\Attribute::TARGET_PARAMETER)]
24+
final class Autowire
25+
{
26+
public readonly string|Expression|Reference $value;
27+
28+
/**
29+
* Use only ONE of the following.
30+
*
31+
* @param string|null $service Service ID (ie "some.service")
32+
* @param string|null $expression Expression (ie 'service("some.service").someMethod()')
33+
* @param string|null $value Parameter value (ie "%kernel.project_dir%/some/path")
34+
*/
35+
public function __construct(
36+
?string $service = null,
37+
?string $expression = null,
38+
?string $value = null
39+
) {
40+
if (!($service xor $expression xor $value)) {
41+
throw new LogicException('Can only set one of $service, $expression, $value.');
42+
}
43+
44+
if ($service) {
45+
$this->value = new Reference($service);
46+
47+
return;
48+
}
49+
50+
if ($expression) {
51+
$this->value = new Expression($expression);
52+
53+
return;
54+
}
55+
56+
if ($value) {
57+
$this->value = $value;
58+
59+
return;
60+
}
61+
62+
throw new LogicException('One of $service, $expression, $value must be set.');
63+
}
64+
}

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
* Add `$exclude` to `TaggedIterator` and `TaggedLocator` attributes
88
* Add `$exclude` to `tagged_iterator` and `tagged_locator` configurator
99
* Add an `env` function to the expression language provider
10+
* Add an `Autowire` attribute to tell a parameter how to be autowired
1011

1112
6.0
1213
---

src/Symfony/Component/DependencyInjection/Compiler/AutowirePass.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
use Symfony\Component\Config\Resource\ClassExistenceResource;
1515
use Symfony\Component\DependencyInjection\Argument\ServiceLocatorArgument;
1616
use Symfony\Component\DependencyInjection\Argument\TaggedIteratorArgument;
17+
use Symfony\Component\DependencyInjection\Attribute\Autowire;
1718
use Symfony\Component\DependencyInjection\Attribute\TaggedIterator;
1819
use Symfony\Component\DependencyInjection\Attribute\TaggedLocator;
1920
use Symfony\Component\DependencyInjection\Attribute\Target;
@@ -256,6 +257,12 @@ private function autowireMethod(\ReflectionFunctionAbstract $reflectionMethod, a
256257
$arguments[$index] = new ServiceLocatorArgument(new TaggedIteratorArgument($attribute->tag, $attribute->indexAttribute, $attribute->defaultIndexMethod, true, $attribute->defaultPriorityMethod, (array) $attribute->exclude));
257258
break;
258259
}
260+
261+
if (Autowire::class === $attribute->getName()) {
262+
$arguments[$index] = $attribute->newInstance()->value;
263+
264+
break;
265+
}
259266
}
260267

261268
if ('' !== ($arguments[$index] ?? '')) {

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

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1121,4 +1121,35 @@ public function testDecorationWithServiceAndAliasedInterface()
11211121
static::assertInstanceOf(DecoratedDecorator::class, $container->get(DecoratorInterface::class));
11221122
static::assertInstanceOf(DecoratedDecorator::class, $container->get(DecoratorImpl::class));
11231123
}
1124+
1125+
public function testAutowireAttribute()
1126+
{
1127+
$container = new ContainerBuilder();
1128+
1129+
$container->register(AutowireAttribute::class)
1130+
->setAutowired(true)
1131+
->setPublic(true)
1132+
;
1133+
1134+
$container->register('some.id', \stdClass::class);
1135+
$container->setParameter('some.parameter', 'foo');
1136+
1137+
(new ResolveClassPass())->process($container);
1138+
(new AutowirePass())->process($container);
1139+
1140+
$definition = $container->getDefinition(AutowireAttribute::class);
1141+
1142+
$this->assertCount(3, $definition->getArguments());
1143+
$this->assertSame('some.id', (string) $definition->getArgument(0));
1144+
$this->assertSame("parameter('some.parameter')", (string) $definition->getArgument(1));
1145+
$this->assertSame('%some.parameter%/bar', (string) $definition->getArgument(2));
1146+
1147+
$container->compile();
1148+
1149+
$service = $container->get(AutowireAttribute::class);
1150+
1151+
$this->assertInstanceOf(\stdClass::class, $service->service);
1152+
$this->assertSame('foo', $service->expression);
1153+
$this->assertSame('foo/bar', $service->value);
1154+
}
11241155
}

src/Symfony/Component/DependencyInjection/Tests/Fixtures/includes/autowiring_classes_80.php

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
namespace Symfony\Component\DependencyInjection\Tests\Compiler;
44

5+
use Symfony\Component\DependencyInjection\Attribute\Autowire;
56
use Symfony\Contracts\Service\Attribute\Required;
67

78
class AutowireSetter
@@ -26,3 +27,16 @@ class AutowireProperty
2627
#[Required]
2728
public Foo $foo;
2829
}
30+
31+
class AutowireAttribute
32+
{
33+
public function __construct(
34+
#[Autowire(service: 'some.id')]
35+
public $service,
36+
#[Autowire(expression: "parameter('some.parameter')")]
37+
public $expression,
38+
#[Autowire(value: '%some.parameter%/bar')]
39+
public $value
40+
){
41+
}
42+
}

0 commit comments

Comments
 (0)