Skip to content

Commit 1539a0a

Browse files
bug #57298 [DependencyInjection] Fix handling of repeated #[Autoconfigure] attributes (alexandre-daubois)
This PR was merged into the 5.4 branch. Discussion ---------- [DependencyInjection] Fix handling of repeated `#[Autoconfigure]` attributes | Q | A | ------------- | --- | Branch? | 5.4 | Bug fix? | yes | New feature? | no | Deprecations? | no | Issues | Fix #56841 | License | MIT When repeating `#[Autoconfigure]`, arguments from all attributes are now used. If an option is defined multiple times in repeated attributes, the last attribute defined will sets value. Commits ------- e9de5a0b95 [DependencyInjection] Add tests for repeating `#[Autoconfigure]` attributes 7399a898cd [DependencyInjection] Fix handling of repeated `#[Autoconfigure]` attributes
2 parents aa89b59 + 960d259 commit 1539a0a

8 files changed

+175
-2
lines changed

Loader/YamlFileLoader.php

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -448,8 +448,9 @@ private function parseDefinition(string $id, $service, string $file, array $defa
448448
return $return ? $alias : $this->container->setAlias($id, $alias);
449449
}
450450

451+
$changes = [];
451452
if (null !== $definition) {
452-
// no-op
453+
$changes = $definition->getChanges();
453454
} elseif ($this->isLoadingInstanceof) {
454455
$definition = new ChildDefinition('');
455456
} elseif (isset($service['parent'])) {
@@ -472,7 +473,7 @@ private function parseDefinition(string $id, $service, string $file, array $defa
472473
$definition->setAutoconfigured($defaults['autoconfigure']);
473474
}
474475

475-
$definition->setChanges([]);
476+
$definition->setChanges($changes);
476477

477478
if (isset($service['class'])) {
478479
$definition->setClass($service['class']);

Tests/Compiler/RegisterAutoconfigureAttributesPassTest.php

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,12 @@
1919
use Symfony\Component\DependencyInjection\Reference;
2020
use Symfony\Component\DependencyInjection\Tests\Fixtures\AutoconfigureAttributed;
2121
use Symfony\Component\DependencyInjection\Tests\Fixtures\AutoconfiguredInterface;
22+
use Symfony\Component\DependencyInjection\Tests\Fixtures\AutoconfigureRepeated;
23+
use Symfony\Component\DependencyInjection\Tests\Fixtures\AutoconfigureRepeatedBindings;
24+
use Symfony\Component\DependencyInjection\Tests\Fixtures\AutoconfigureRepeatedCalls;
25+
use Symfony\Component\DependencyInjection\Tests\Fixtures\AutoconfigureRepeatedOverwrite;
26+
use Symfony\Component\DependencyInjection\Tests\Fixtures\AutoconfigureRepeatedProperties;
27+
use Symfony\Component\DependencyInjection\Tests\Fixtures\AutoconfigureRepeatedTag;
2228
use Symfony\Component\DependencyInjection\Tests\Fixtures\ParentNotExists;
2329

2430
/**
@@ -77,6 +83,99 @@ public function testAutoconfiguredTag()
7783
$this->assertEquals([AutoconfiguredInterface::class => $expected], $container->getAutoconfiguredInstanceof());
7884
}
7985

86+
public function testAutoconfiguredRepeated()
87+
{
88+
$container = new ContainerBuilder();
89+
$container->register('foo', AutoconfigureRepeated::class)
90+
->setAutoconfigured(true);
91+
92+
(new RegisterAutoconfigureAttributesPass())->process($container);
93+
94+
$expected = (new ChildDefinition(''))
95+
->setLazy(true)
96+
->setPublic(true)
97+
->setShared(false);
98+
99+
$this->assertEquals([AutoconfigureRepeated::class => $expected], $container->getAutoconfiguredInstanceof());
100+
}
101+
102+
public function testAutoconfiguredRepeatedOverwrite()
103+
{
104+
$container = new ContainerBuilder();
105+
$container->register('foo', AutoconfigureRepeatedOverwrite::class)
106+
->setAutoconfigured(true);
107+
108+
(new RegisterAutoconfigureAttributesPass())->process($container);
109+
110+
$expected = (new ChildDefinition(''))
111+
->setLazy(true)
112+
->setPublic(false)
113+
->setShared(true);
114+
115+
$this->assertEquals([AutoconfigureRepeatedOverwrite::class => $expected], $container->getAutoconfiguredInstanceof());
116+
}
117+
118+
public function testAutoconfiguredRepeatedTag()
119+
{
120+
$container = new ContainerBuilder();
121+
$container->register('foo', AutoconfigureRepeatedTag::class)
122+
->setAutoconfigured(true);
123+
124+
(new RegisterAutoconfigureAttributesPass())->process($container);
125+
126+
$expected = (new ChildDefinition(''))
127+
->addTag('foo', ['priority' => 2])
128+
->addTag('bar');
129+
130+
$this->assertEquals([AutoconfigureRepeatedTag::class => $expected], $container->getAutoconfiguredInstanceof());
131+
}
132+
133+
public function testAutoconfiguredRepeatedCalls()
134+
{
135+
$container = new ContainerBuilder();
136+
$container->register('foo', AutoconfigureRepeatedCalls::class)
137+
->setAutoconfigured(true);
138+
139+
(new RegisterAutoconfigureAttributesPass())->process($container);
140+
141+
$expected = (new ChildDefinition(''))
142+
->addMethodCall('setBar', ['arg2'])
143+
->addMethodCall('setFoo', ['arg1']);
144+
145+
$this->assertEquals([AutoconfigureRepeatedCalls::class => $expected], $container->getAutoconfiguredInstanceof());
146+
}
147+
148+
public function testAutoconfiguredRepeatedBindingsOverwrite()
149+
{
150+
$container = new ContainerBuilder();
151+
$container->register('foo', AutoconfigureRepeatedBindings::class)
152+
->setAutoconfigured(true);
153+
154+
(new RegisterAutoconfigureAttributesPass())->process($container);
155+
156+
$expected = (new ChildDefinition(''))
157+
->setBindings(['$arg' => new BoundArgument('bar', false, BoundArgument::INSTANCEOF_BINDING, realpath(__DIR__.'/../Fixtures/AutoconfigureRepeatedBindings.php'))]);
158+
159+
$this->assertEquals([AutoconfigureRepeatedBindings::class => $expected], $container->getAutoconfiguredInstanceof());
160+
}
161+
162+
public function testAutoconfiguredRepeatedPropertiesOverwrite()
163+
{
164+
$container = new ContainerBuilder();
165+
$container->register('foo', AutoconfigureRepeatedProperties::class)
166+
->setAutoconfigured(true);
167+
168+
(new RegisterAutoconfigureAttributesPass())->process($container);
169+
170+
$expected = (new ChildDefinition(''))
171+
->setProperties([
172+
'$foo' => 'bar',
173+
'$bar' => 'baz',
174+
]);
175+
176+
$this->assertEquals([AutoconfigureRepeatedProperties::class => $expected], $container->getAutoconfiguredInstanceof());
177+
}
178+
80179
public function testMissingParent()
81180
{
82181
$container = new ContainerBuilder();
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<?php
2+
3+
namespace Symfony\Component\DependencyInjection\Tests\Fixtures;
4+
5+
use Symfony\Component\DependencyInjection\Attribute\Autoconfigure;
6+
7+
#[Autoconfigure(public: true, shared: false)]
8+
#[Autoconfigure(lazy: true)]
9+
class AutoconfigureRepeated
10+
{
11+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<?php
2+
3+
namespace Symfony\Component\DependencyInjection\Tests\Fixtures;
4+
5+
use Symfony\Component\DependencyInjection\Attribute\Autoconfigure;
6+
7+
#[Autoconfigure(bind: ['$arg' => 'foo'])]
8+
#[Autoconfigure(bind: ['$arg' => 'bar'])]
9+
class AutoconfigureRepeatedBindings
10+
{
11+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<?php
2+
3+
namespace Symfony\Component\DependencyInjection\Tests\Fixtures;
4+
5+
use Symfony\Component\DependencyInjection\Attribute\Autoconfigure;
6+
7+
#[Autoconfigure(calls: [['setBar', ['arg2']]])]
8+
#[Autoconfigure(calls: [['setFoo', ['arg1']]])]
9+
class AutoconfigureRepeatedCalls
10+
{
11+
public function setFoo(string $arg)
12+
{
13+
}
14+
15+
public function setBar(string $arg)
16+
{
17+
}
18+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<?php
2+
3+
namespace Symfony\Component\DependencyInjection\Tests\Fixtures;
4+
5+
use Symfony\Component\DependencyInjection\Attribute\Autoconfigure;
6+
7+
#[Autoconfigure(public: true, shared: false)]
8+
#[Autoconfigure(lazy: true, shared: true, public: false)]
9+
class AutoconfigureRepeatedOverwrite
10+
{
11+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<?php
2+
3+
namespace Symfony\Component\DependencyInjection\Tests\Fixtures;
4+
5+
use Symfony\Component\DependencyInjection\Attribute\Autoconfigure;
6+
7+
#[Autoconfigure(properties: ['$replaced' => 'to be replaced', '$bar' => 'existing to be replaced'])]
8+
#[Autoconfigure(properties: ['$foo' => 'bar', '$bar' => 'baz'])]
9+
class AutoconfigureRepeatedProperties
10+
{
11+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<?php
2+
3+
namespace Symfony\Component\DependencyInjection\Tests\Fixtures;
4+
5+
use Symfony\Component\DependencyInjection\Attribute\AutoconfigureTag;
6+
7+
#[AutoconfigureTag('foo', ['priority' => 2])]
8+
#[AutoconfigureTag('bar')]
9+
class AutoconfigureRepeatedTag
10+
{
11+
}

0 commit comments

Comments
 (0)