Skip to content

Commit 5dca66e

Browse files
committed
[DependencyInjection] add factory argument in the #[Autoconfigure] attribute and allow instanceof factory
1 parent 6e2fcec commit 5dca66e

18 files changed

+313
-4
lines changed

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ class Autoconfigure
3030
* @param array<string, mixed>|null $properties The properties to define when creating the service
3131
* @param array{string, string}|string|null $configurator A PHP function, reference or an array containing a class/reference and a method to call after the service is fully initialized
3232
* @param string|null $constructor The public static method to use to instantiate the service
33+
* @param array<string|null, string|null>|string|null $factory The factory that defines how to create the service
3334
*/
3435
public function __construct(
3536
public ?array $tags = null,
@@ -42,6 +43,7 @@ public function __construct(
4243
public ?array $properties = null,
4344
public array|string|null $configurator = null,
4445
public ?string $constructor = null,
46+
public array|string|null $factory = null,
4547
) {
4648
}
4749
}

src/Symfony/Component/DependencyInjection/CHANGELOG.md

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

77
* Allow `#[AsAlias]` to be extended
88
* Add argument `$target` to `ContainerBuilder::registerAliasForArgument()`
9+
* Add support for a `factory` argument in the `#[Autoconfigure]` attribute to define service instantiation via a factory
10+
* Enable the use of `factory` within `instanceof`
911

1012
7.3
1113
---

src/Symfony/Component/DependencyInjection/Loader/Configurator/InstanceofConfigurator.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ class InstanceofConfigurator extends AbstractServiceConfigurator
2323
use Traits\CallTrait;
2424
use Traits\ConfiguratorTrait;
2525
use Traits\ConstructorTrait;
26+
use Traits\FactoryTrait;
2627
use Traits\LazyTrait;
2728
use Traits\PropertyTrait;
2829
use Traits\PublicTrait;

src/Symfony/Component/DependencyInjection/Loader/YamlFileLoader.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@ class YamlFileLoader extends FileLoader
100100
'autowire' => 'autowire',
101101
'bind' => 'bind',
102102
'constructor' => 'constructor',
103+
'factory' => 'factory',
103104
];
104105

105106
private const DEFAULTS_KEYWORDS = [

src/Symfony/Component/DependencyInjection/Loader/schema/dic/services/services-1.0.xsd

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,7 @@
175175
<xsd:complexType name="instanceof">
176176
<xsd:choice maxOccurs="unbounded">
177177
<xsd:element name="configurator" type="callable" minOccurs="0" maxOccurs="1" />
178+
<xsd:element name="factory" type="factory" minOccurs="0" maxOccurs="1" />
178179
<xsd:element name="call" type="call" minOccurs="0" maxOccurs="unbounded" />
179180
<xsd:element name="tag" type="tag" minOccurs="0" maxOccurs="unbounded" />
180181
<xsd:element name="property" type="property" minOccurs="0" maxOccurs="unbounded" />

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

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,12 @@
2626
use Symfony\Component\DependencyInjection\Tests\Fixtures\AutoconfigureRepeatedOverwrite;
2727
use Symfony\Component\DependencyInjection\Tests\Fixtures\AutoconfigureRepeatedProperties;
2828
use Symfony\Component\DependencyInjection\Tests\Fixtures\AutoconfigureRepeatedTag;
29+
use Symfony\Component\DependencyInjection\Tests\Fixtures\AutoconfigureWithExpressionFactory;
30+
use Symfony\Component\DependencyInjection\Tests\Fixtures\AutoconfigureWithInstanceExternalFactory;
31+
use Symfony\Component\DependencyInjection\Tests\Fixtures\AutoconfigureWithInvokableFactory;
32+
use Symfony\Component\DependencyInjection\Tests\Fixtures\AutoconfigureWithStaticExternalFactory;
33+
use Symfony\Component\DependencyInjection\Tests\Fixtures\AutoconfigureWithStaticSelfFactory;
34+
use Symfony\Component\DependencyInjection\Tests\Fixtures\FactoryDummy;
2935
use Symfony\Component\DependencyInjection\Tests\Fixtures\LazyAutoconfigured;
3036
use Symfony\Component\DependencyInjection\Tests\Fixtures\LazyLoaded;
3137
use Symfony\Component\DependencyInjection\Tests\Fixtures\MultipleAutoconfigureAttributed;
@@ -208,6 +214,88 @@ public function testStaticConstructor()
208214
$this->assertEquals([StaticConstructorAutoconfigure::class => $expected], $container->getAutoconfiguredInstanceof());
209215
}
210216

217+
public function testAutoconfigureWithStaticSelfFactory()
218+
{
219+
$container = new ContainerBuilder();
220+
$container->register('foo', AutoconfigureWithStaticSelfFactory::class)
221+
->setAutoconfigured(true);
222+
223+
$argument = new BoundArgument('foo', false, BoundArgument::INSTANCEOF_BINDING, realpath(__DIR__.'/../Fixtures/AutoconfigureWithStaticSelfFactory.php'));
224+
225+
(new RegisterAutoconfigureAttributesPass())->process($container);
226+
227+
$expected = (new ChildDefinition(''))
228+
->setFactory([null, 'create'])
229+
->setBindings(['$foo' => $argument])
230+
;
231+
$this->assertEquals([AutoconfigureWithStaticSelfFactory::class => $expected], $container->getAutoconfiguredInstanceof());
232+
}
233+
234+
public function testAutoconfigureWithStaticExternalFactory()
235+
{
236+
$container = new ContainerBuilder();
237+
$container->register('foo', AutoconfigureWithStaticExternalFactory::class)
238+
->setAutoconfigured(true);
239+
240+
$argument = new BoundArgument('foo', false, BoundArgument::INSTANCEOF_BINDING, realpath(__DIR__.'/../Fixtures/AutoconfigureWithStaticExternalFactory.php'));
241+
242+
(new RegisterAutoconfigureAttributesPass())->process($container);
243+
244+
$expected = (new ChildDefinition(''))
245+
->setFactory([FactoryDummy::class, 'create'])
246+
->setBindings(['$foo' => $argument])
247+
;
248+
$this->assertEquals([AutoconfigureWithStaticExternalFactory::class => $expected], $container->getAutoconfiguredInstanceof());
249+
}
250+
251+
public function testAutoconfigureWithInstanceExternalFactory()
252+
{
253+
$container = new ContainerBuilder();
254+
$container->register('foo', AutoconfigureWithInstanceExternalFactory::class)
255+
->setAutoconfigured(true);
256+
257+
$argument = new BoundArgument('foo', false, BoundArgument::INSTANCEOF_BINDING, realpath(__DIR__.'/../Fixtures/AutoconfigureWithInstanceExternalFactory.php'));
258+
259+
(new RegisterAutoconfigureAttributesPass())->process($container);
260+
261+
$expected = (new ChildDefinition(''))
262+
->setFactory([new Reference('factory_for_autoconfigure'), 'createStatic'])
263+
->setBindings(['$foo' => $argument])
264+
;
265+
$this->assertEquals([AutoconfigureWithInstanceExternalFactory::class => $expected], $container->getAutoconfiguredInstanceof());
266+
}
267+
268+
public function testAutoconfigureWithInvokableFactory()
269+
{
270+
$container = new ContainerBuilder();
271+
$container->register('foo', AutoconfigureWithInvokableFactory::class)
272+
->setAutoconfigured(true);
273+
274+
$argument = new BoundArgument('foo', false, BoundArgument::INSTANCEOF_BINDING, realpath(__DIR__.'/../Fixtures/AutoconfigureWithInvokableFactory.php'));
275+
276+
(new RegisterAutoconfigureAttributesPass())->process($container);
277+
278+
$expected = (new ChildDefinition(''))
279+
->setFactory([new Reference('factory_for_autoconfigure'), '__invoke'])
280+
->setBindings(['$foo' => $argument])
281+
;
282+
$this->assertEquals([AutoconfigureWithInvokableFactory::class => $expected], $container->getAutoconfiguredInstanceof());
283+
}
284+
285+
public function testAutoconfigureWithExpressionFactory()
286+
{
287+
$container = new ContainerBuilder();
288+
$container->register('foo', AutoconfigureWithExpressionFactory::class)
289+
->setAutoconfigured(true);
290+
291+
(new RegisterAutoconfigureAttributesPass())->process($container);
292+
293+
$expected = (new ChildDefinition(''))
294+
->setFactory('@=service("factory_for_autoconfigure").create()')
295+
;
296+
$this->assertEquals([AutoconfigureWithExpressionFactory::class => $expected], $container->getAutoconfiguredInstanceof());
297+
}
298+
211299
public function testLazyServiceAttribute()
212300
{
213301
$container = new ContainerBuilder();
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
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\Fixtures;
13+
14+
use Symfony\Component\DependencyInjection\Attribute\Autoconfigure;
15+
16+
#[Autoconfigure(factory: '@=service("factory_for_autoconfigure").create()')]
17+
class AutoconfigureWithExpressionFactory
18+
{
19+
public function __construct(public readonly string $foo)
20+
{
21+
}
22+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
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\Fixtures;
13+
14+
use Symfony\Component\DependencyInjection\Attribute\Autoconfigure;
15+
16+
#[Autoconfigure(bind: ['$foo' => 'foo'], factory: ['@factory_for_autoconfigure', 'createStatic'])]
17+
class AutoconfigureWithInstanceExternalFactory
18+
{
19+
public function __construct(public readonly string $foo)
20+
{
21+
}
22+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
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\Fixtures;
13+
14+
use Symfony\Component\DependencyInjection\Attribute\Autoconfigure;
15+
16+
#[Autoconfigure(bind: ['$foo' => 'foo'], factory: '@factory_for_autoconfigure')]
17+
class AutoconfigureWithInvokableFactory
18+
{
19+
public function __construct(public readonly string $foo)
20+
{
21+
}
22+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
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\Fixtures;
13+
14+
use Symfony\Component\DependencyInjection\Attribute\Autoconfigure;
15+
16+
#[Autoconfigure(bind: ['$foo' => 'foo'], factory: [FactoryDummy::class, 'create'])]
17+
class AutoconfigureWithStaticExternalFactory
18+
{
19+
public function __construct(public readonly string $foo)
20+
{
21+
}
22+
}

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy