Skip to content

Commit 4499030

Browse files
[DependencyInjection] Add #[AutowireMethodOf] attribute to autowire a method of a service as a callable
1 parent 35bdc20 commit 4499030

File tree

4 files changed

+75
-2
lines changed

4 files changed

+75
-2
lines changed

Attribute/AutowireMethodOf.php

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
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\Definition;
15+
use Symfony\Component\DependencyInjection\Reference;
16+
17+
/**
18+
* Tells which method should be turned into a Closure based on the name of the parameter it's attached to.
19+
*/
20+
#[\Attribute(\Attribute::TARGET_PARAMETER)]
21+
class AutowireMethodOf extends AutowireCallable
22+
{
23+
/**
24+
* @param string $service The service containing the method to autowire
25+
* @param bool|class-string $lazy Whether to use lazy-loading for this argument
26+
*/
27+
public function __construct(string $service, bool|string $lazy = false)
28+
{
29+
parent::__construct([new Reference($service)], lazy: $lazy);
30+
}
31+
32+
public function buildDefinition(mixed $value, ?string $type, \ReflectionParameter $parameter): Definition
33+
{
34+
$value[1] = $parameter->name;
35+
36+
return parent::buildDefinition($value, $type, $parameter);
37+
}
38+
}

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ CHANGELOG
88
* Add argument `$prepend` to `ContainerConfigurator::extension()` to prepend the configuration instead of appending it
99
* Have `ServiceLocator` implement `ServiceCollectionInterface`
1010
* Add `#[Lazy]` attribute as shortcut for `#[Autowire(lazy: [bool|string])]` and `#[Autoconfigure(lazy: [bool|string])]`
11+
* Add `#[AutowireMethodOf]` attribute to autowire a method of a service as a callable
1112

1213
7.0
1314
---

Compiler/CheckExceptionOnInvalidReferenceBehaviorPass.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ protected function processValue(mixed $value, bool $isRoot = false): mixed
4747
if (!$value instanceof Reference) {
4848
return parent::processValue($value, $isRoot);
4949
}
50-
if (ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE < $value->getInvalidBehavior() || $this->container->has($id = (string) $value)) {
50+
if (ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE < $value->getInvalidBehavior() || $this->container->has((string) $value)) {
5151
return $value;
5252
}
5353

@@ -83,7 +83,7 @@ protected function processValue(mixed $value, bool $isRoot = false): mixed
8383
$this->throwServiceNotFoundException($value, $currentId, $value);
8484
}
8585

86-
private function throwServiceNotFoundException(Reference $ref, string $sourceId, $value): void
86+
private function throwServiceNotFoundException(Reference $ref, string $sourceId, mixed $value): void
8787
{
8888
$id = (string) $ref;
8989
$alternatives = [];
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
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\Attribute\AutowireMethodOf;
16+
use Symfony\Component\DependencyInjection\Reference;
17+
18+
class AutowireMethodOfTest extends TestCase
19+
{
20+
public function testConstructor()
21+
{
22+
$a = new AutowireMethodOf('foo');
23+
24+
$this->assertEquals([new Reference('foo')], $a->value);
25+
}
26+
27+
public function testBuildDefinition(?\Closure $dummy = null)
28+
{
29+
$a = new AutowireMethodOf('foo');
30+
$r = new \ReflectionParameter([__CLASS__, __FUNCTION__], 0);
31+
32+
$this->assertEquals([[new Reference('foo'), 'dummy']], $a->buildDefinition($a->value, 'Closure', $r)->getArguments());
33+
}
34+
}

0 commit comments

Comments
 (0)