Skip to content

Commit

Permalink
bug #57298 [DependencyInjection] Fix handling of repeated `#[Autoconf…
Browse files Browse the repository at this point in the history
…igure]` 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
  • Loading branch information
nicolas-grekas committed Aug 20, 2024
2 parents aa89b59 + 960d259 commit 1539a0a
Show file tree
Hide file tree
Showing 8 changed files with 175 additions and 2 deletions.
5 changes: 3 additions & 2 deletions Loader/YamlFileLoader.php
Original file line number Diff line number Diff line change
Expand Up @@ -448,8 +448,9 @@ private function parseDefinition(string $id, $service, string $file, array $defa
return $return ? $alias : $this->container->setAlias($id, $alias);
}

$changes = [];
if (null !== $definition) {
// no-op
$changes = $definition->getChanges();
} elseif ($this->isLoadingInstanceof) {
$definition = new ChildDefinition('');
} elseif (isset($service['parent'])) {
Expand All @@ -472,7 +473,7 @@ private function parseDefinition(string $id, $service, string $file, array $defa
$definition->setAutoconfigured($defaults['autoconfigure']);
}

$definition->setChanges([]);
$definition->setChanges($changes);

if (isset($service['class'])) {
$definition->setClass($service['class']);
Expand Down
99 changes: 99 additions & 0 deletions Tests/Compiler/RegisterAutoconfigureAttributesPassTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,12 @@
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\DependencyInjection\Tests\Fixtures\AutoconfigureAttributed;
use Symfony\Component\DependencyInjection\Tests\Fixtures\AutoconfiguredInterface;
use Symfony\Component\DependencyInjection\Tests\Fixtures\AutoconfigureRepeated;
use Symfony\Component\DependencyInjection\Tests\Fixtures\AutoconfigureRepeatedBindings;
use Symfony\Component\DependencyInjection\Tests\Fixtures\AutoconfigureRepeatedCalls;
use Symfony\Component\DependencyInjection\Tests\Fixtures\AutoconfigureRepeatedOverwrite;
use Symfony\Component\DependencyInjection\Tests\Fixtures\AutoconfigureRepeatedProperties;
use Symfony\Component\DependencyInjection\Tests\Fixtures\AutoconfigureRepeatedTag;
use Symfony\Component\DependencyInjection\Tests\Fixtures\ParentNotExists;

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

public function testAutoconfiguredRepeated()
{
$container = new ContainerBuilder();
$container->register('foo', AutoconfigureRepeated::class)
->setAutoconfigured(true);

(new RegisterAutoconfigureAttributesPass())->process($container);

$expected = (new ChildDefinition(''))
->setLazy(true)
->setPublic(true)
->setShared(false);

$this->assertEquals([AutoconfigureRepeated::class => $expected], $container->getAutoconfiguredInstanceof());
}

public function testAutoconfiguredRepeatedOverwrite()
{
$container = new ContainerBuilder();
$container->register('foo', AutoconfigureRepeatedOverwrite::class)
->setAutoconfigured(true);

(new RegisterAutoconfigureAttributesPass())->process($container);

$expected = (new ChildDefinition(''))
->setLazy(true)
->setPublic(false)
->setShared(true);

$this->assertEquals([AutoconfigureRepeatedOverwrite::class => $expected], $container->getAutoconfiguredInstanceof());
}

public function testAutoconfiguredRepeatedTag()
{
$container = new ContainerBuilder();
$container->register('foo', AutoconfigureRepeatedTag::class)
->setAutoconfigured(true);

(new RegisterAutoconfigureAttributesPass())->process($container);

$expected = (new ChildDefinition(''))
->addTag('foo', ['priority' => 2])
->addTag('bar');

$this->assertEquals([AutoconfigureRepeatedTag::class => $expected], $container->getAutoconfiguredInstanceof());
}

public function testAutoconfiguredRepeatedCalls()
{
$container = new ContainerBuilder();
$container->register('foo', AutoconfigureRepeatedCalls::class)
->setAutoconfigured(true);

(new RegisterAutoconfigureAttributesPass())->process($container);

$expected = (new ChildDefinition(''))
->addMethodCall('setBar', ['arg2'])
->addMethodCall('setFoo', ['arg1']);

$this->assertEquals([AutoconfigureRepeatedCalls::class => $expected], $container->getAutoconfiguredInstanceof());
}

public function testAutoconfiguredRepeatedBindingsOverwrite()
{
$container = new ContainerBuilder();
$container->register('foo', AutoconfigureRepeatedBindings::class)
->setAutoconfigured(true);

(new RegisterAutoconfigureAttributesPass())->process($container);

$expected = (new ChildDefinition(''))
->setBindings(['$arg' => new BoundArgument('bar', false, BoundArgument::INSTANCEOF_BINDING, realpath(__DIR__.'/../Fixtures/AutoconfigureRepeatedBindings.php'))]);

$this->assertEquals([AutoconfigureRepeatedBindings::class => $expected], $container->getAutoconfiguredInstanceof());
}

public function testAutoconfiguredRepeatedPropertiesOverwrite()
{
$container = new ContainerBuilder();
$container->register('foo', AutoconfigureRepeatedProperties::class)
->setAutoconfigured(true);

(new RegisterAutoconfigureAttributesPass())->process($container);

$expected = (new ChildDefinition(''))
->setProperties([
'$foo' => 'bar',
'$bar' => 'baz',
]);

$this->assertEquals([AutoconfigureRepeatedProperties::class => $expected], $container->getAutoconfiguredInstanceof());
}

public function testMissingParent()
{
$container = new ContainerBuilder();
Expand Down
11 changes: 11 additions & 0 deletions Tests/Fixtures/AutoconfigureRepeated.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?php

namespace Symfony\Component\DependencyInjection\Tests\Fixtures;

use Symfony\Component\DependencyInjection\Attribute\Autoconfigure;

#[Autoconfigure(public: true, shared: false)]
#[Autoconfigure(lazy: true)]
class AutoconfigureRepeated
{
}
11 changes: 11 additions & 0 deletions Tests/Fixtures/AutoconfigureRepeatedBindings.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?php

namespace Symfony\Component\DependencyInjection\Tests\Fixtures;

use Symfony\Component\DependencyInjection\Attribute\Autoconfigure;

#[Autoconfigure(bind: ['$arg' => 'foo'])]
#[Autoconfigure(bind: ['$arg' => 'bar'])]
class AutoconfigureRepeatedBindings
{
}
18 changes: 18 additions & 0 deletions Tests/Fixtures/AutoconfigureRepeatedCalls.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<?php

namespace Symfony\Component\DependencyInjection\Tests\Fixtures;

use Symfony\Component\DependencyInjection\Attribute\Autoconfigure;

#[Autoconfigure(calls: [['setBar', ['arg2']]])]
#[Autoconfigure(calls: [['setFoo', ['arg1']]])]
class AutoconfigureRepeatedCalls
{
public function setFoo(string $arg)
{
}

public function setBar(string $arg)
{
}
}
11 changes: 11 additions & 0 deletions Tests/Fixtures/AutoconfigureRepeatedOverwrite.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?php

namespace Symfony\Component\DependencyInjection\Tests\Fixtures;

use Symfony\Component\DependencyInjection\Attribute\Autoconfigure;

#[Autoconfigure(public: true, shared: false)]
#[Autoconfigure(lazy: true, shared: true, public: false)]
class AutoconfigureRepeatedOverwrite
{
}
11 changes: 11 additions & 0 deletions Tests/Fixtures/AutoconfigureRepeatedProperties.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?php

namespace Symfony\Component\DependencyInjection\Tests\Fixtures;

use Symfony\Component\DependencyInjection\Attribute\Autoconfigure;

#[Autoconfigure(properties: ['$replaced' => 'to be replaced', '$bar' => 'existing to be replaced'])]
#[Autoconfigure(properties: ['$foo' => 'bar', '$bar' => 'baz'])]
class AutoconfigureRepeatedProperties
{
}
11 changes: 11 additions & 0 deletions Tests/Fixtures/AutoconfigureRepeatedTag.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?php

namespace Symfony\Component\DependencyInjection\Tests\Fixtures;

use Symfony\Component\DependencyInjection\Attribute\AutoconfigureTag;

#[AutoconfigureTag('foo', ['priority' => 2])]
#[AutoconfigureTag('bar')]
class AutoconfigureRepeatedTag
{
}

0 comments on commit 1539a0a

Please sign in to comment.