8000 Try to implement resolving named arguments for autowire inline · symfony/symfony@5144cea · GitHub
[go: up one dir, main page]

Skip to content

Commit 5144cea

Browse files
committed
Try to implement resolving named arguments for autowire inline
1 parent 021a469 commit 5144cea

File tree

6 files changed

+149
-1
lines changed

6 files changed

+149
-1
lines changed

src/Symfony/Component/DependencyInjection/Attribute/AutowireInline.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616

1717
/**
1818
* Allows inline service definition for a constructor argument.
19+
* Using this attribute on a class autowires it as a new instance
20+
* which is not shared between different services.
1921
*
2022
* @author Ismail Özgün Turan <oezguen.turan@dadadev.com>
2123
*/

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -322,7 +322,7 @@ private function autowireMethod(\ReflectionFunctionAbstract $reflectionMethod, a
322322

323323
if ($attribute instanceof AutowireInline) {
324324
$value = $attribute->buildDefinition($value, $type, $parameter);
325-
$value = $this->doProcessValue($value);
325+
$value = new Reference('.autowire_inline.'.ContainerBuilder::hash($value));
326326
} elseif ($lazy = $attribute->lazy) {
327327
$definition = (new Definition($type))
328328
->setFactory('current')

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ public function __construct()
5555
new AutoAliasServicePass(),
5656
new ValidateEnvPlaceholdersPass(),
5757
new ResolveDecoratorStackPass(),
58+
new ResolveAutowireInlineAttributesPass(),
5859
new ResolveChildDefinitionsPass(),
5960
new RegisterServiceSubscribersPass(),
6061
new ResolveParameterPlaceHoldersPass(false, false),
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
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\Compiler;
13+
14+
use Symfony\Component\DependencyInjection\Attribute\AutowireInline;
15+
use Symfony\Component\DependencyInjection\ContainerBuilder;
16+
use Symfony\Component\DependencyInjection\Definition;
17+
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
18+
use Symfony\Component\VarExporter\ProxyHelper;
19+
20+
/**
21+
* Inspects existing autowired services for {@see AutowireInline} attribute and registers the definitions for reuse.
22+
*
23+
* @author Ismail Özgün Turan <oezguen.turan@dadadev.com>
24+
*/
25+
class ResolveAutowireInlineAttributesPass extends AbstractRecursivePass
26+
{
27+
protected bool $skipScalars = true;
28+
29+
protected function processValue(mixed $value, bool $isRoot = false): mixed
30+
{
31+
$value = parent::processValue($value, $isRoot);
32+
33+
if (!$value instanceof Definition || !$value->isAutowired() || $value->isAbstract() || !$value->getClass()) {
34+
return $value;
35+
}
36+
37+
try {
38+
$constructor = $this->getConstructor($value, false);
39+
} catch (RuntimeException) {
40+
$this->container->log($this, sprintf('Skipping service "%s": Class or interface "%s" cannot be loaded.', $this->currentId, $value->getClass()));
41+
42+
return $value;
43+
}
44+
45+
if ($constructor === null) {
46+
return $value;
47+
}
48+
49+
$reflectionParameters = $constructor->getParameters();
50+
foreach ($reflectionParameters as $reflectionParameter) {
51+
$autowireInlineAttributes = $reflectionParameter->getAttributes(AutowireInline::class, \ReflectionAttribute::IS_INSTANCEOF);
52+
foreach ($autowireInlineAttributes as $autowireInlineAttribute) {
53+
/** @var AutowireInline $aut B41A owireInlineAttributeInstance */
54+
$autowireInlineAttributeInstance = $autowireInlineAttribute->newInstance();
55+
56+
$type = ProxyHelper::exportType($reflectionParameter, true);
57+
$definition = $autowireInlineAttributeInstance->buildDefinition($autowireInlineAttributeInstance->value, $type, $reflectionParameter);
58+
59+
$this->container->setDefinition('.autowire_inline.'.ContainerBuilder::hash($definition), $definition);
60+
}
61+
}
62+
63+
return $value;
64+
}
65+
}
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\Compiler;
13+
14+
use PHPUnit\Framework\TestCase;
15+
use Symfony\Component\DependencyInjection\Compiler\AutowirePass;
16+
use Symfony\Component\DependencyInjection\Compiler\ResolveAutowireInlineAttributesPass;
17+
use Symfony\Component\DependencyInjection\Compiler\ResolveChildDefinitionsPass;
18+
use Symfony\Component\DependencyInjection\Compiler\ResolveClassPass;
19+
use Symfony\Component\DependencyInjection\Compiler\ResolveNamedArgumentsPass;
20+
use Symfony\Component\DependencyInjection\ContainerBuilder;
21+
22+
require_once __DIR__.'/../Fixtures/includes/autowiring_classes.php';
23+
24+
class ResolveAutowireInlineAttributesPassTest extends TestCase
25+
{
26+
public function testAttribute()
27+
{
28+
$container = new ContainerBuilder();
29+
$container->register(Foo::class)->setAutowired(true);
30+
31+
$container->register('autowire_inline1', AutowireInlineAttributes1::class)
32+
->setAutowired(true);
33+
34+
$container->register('autowire_inline2', AutowireInlineAttributes2::class)
35+
->setAutowired(true);
36+
37+
(new ResolveNamedArgumentsPass())->process($container);
38+
(new ResolveClassPass())->process($container);
39+
(new ResolveChildDefinitionsPass())->process($container);
40+
(new ResolveAutowireInlineAttributesPass())->process($container);
41+
(new AutowirePass())->process($container);
42+
43+
$autowireInlineAttributes1 = $container->get('autowire_inline1');
44+
self::assertInstanceOf(AutowireInlineAttributes1::class, $autowireInlineAttributes1);
45+
46+
$autowireInlineAttributes2 = $container->get('autowire_inline2');
47+
self::assertInstanceOf(AutowireInlineAttributes2::class, $autowireInlineAttributes2);
48+
}
49+
}

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

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
use Symfony\Component\DependencyInjection\Attribute\AsDecorator;
66
use Symfony\Component\DependencyInjection\Attribute\Autowire;
77
use Symfony\Component\DependencyInjection\Attribute\AutowireDecorated;
8+
use Symfony\Component\DependencyInjection\Attribute\AutowireInline;
89
use Symfony\Component\DependencyInjection\Attribute\Lazy;
910
use Symfony\Component\DependencyInjection\Attribute\TaggedIterator;
1011
use Symfony\Component\DependencyInjection\Attribute\TaggedLocator;
@@ -140,3 +141,33 @@ public function __construct(#[Lazy, Autowire(lazy: true)] A $a)
140141
{
141142
}
142143
}
144+
145+
class AutowireInlineAttributesBar
146+
{
147+
public function __construct(Foo $foo, string $someString)
148+
{
149+
}
150+
}
151+
152+
class AutowireInlineAttributes1
153+
{
154+
public function __construct(
155+
#[AutowireInline(AutowireInlineAttributesBar::class, [
156+
'$foo' => Foo::class,
157+
'$someString' => 'testString',
158+
])]
159+
public AutowireInlineAttributesBar $inlined,
160+
) {
161+
}
162+
}
163+
164+
class AutowireInlineAttributes2
165+
{
166+
public function __construct(
167+
#[AutowireInline(AutowireInlineAttributesBar::class, [
168+
'$someString' => 'testString',
169+
])]
170+
public AutowireInlineAttributesBar $inlined,
171+
) {
172+
}
173+
}

0 commit comments

Comments
 (0)
0