8000 [DependencyInjection] Add `constructor` option to `#[Autoconfigure]` · symfony/symfony@1a2f758 · GitHub
[go: up one dir, main page]

Skip to content
8000

Commit 1a2f758

Browse files
[DependencyInjection] Add constructor option to #[Autoconfigure]
1 parent 4df47ec commit 1a2f758

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

42 files changed

+399
-113
lines changed

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ public function __construct(
2929
public ?bool $autowire = null,
3030
public ?array $properties = null,
3131
public array|string|null $configurator = null,
32-
public array|string|null $factory = null,
32+
public string|null $constructor = null,
3333
) {
3434
}
3535
}

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

Lines changed: 0 additions & 29 deletions
This file was deleted.

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ public function __construct()
5959
new RegisterServiceSubscribersPass(),
6060
new ResolveParameterPlaceHoldersPass(false, false),
6161
new ResolveFactoryClassPass(),
62+
new ResolveStaticConstructorPass(),
6263
new ResolveNamedArgumentsPass(),
6364
new AutowireRequiredMethodsPass(),
6465
new AutowireRequiredPropertiesPass(),

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

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
namespace Symfony\Component\DependencyInjection\Compiler;
1313

1414
use Symfony\Component\DependencyInjection\Attribute\Autoconfigure;
15-
use Symfony\Component\DependencyInjection\Attribute\Factory;
1615
use Symfony\Component\DependencyInjection\ContainerBuilder;
1716
use Symfony\Component\DependencyInjection\Definition;
1817
use Symfony\Component\DependencyInjection\Loader\YamlFileLoader;
@@ -58,15 +57,8 @@ privat 10000 e static function registerForAutoconfiguration(ContainerBuilder $container
5857
$yamlLoader = $parseDefinitions->getDeclaringClass()->newInstanceWithoutConstructor();
5958

6059
self::$registerForAutoconfiguration = static function (ContainerBuilder $container, \ReflectionClass $class, \ReflectionAttribute $attribute) use ($parseDefinitions, $yamlLoader) {
61-
$attribute = $attribute->newInstance();
60+
$attribute = (array) $attribute->newInstance();
6261

63-
if ($attribute instanceof Factory) {
64-
if (\is_string($attribute->factory) && $class->hasMethod($attribute->factory)) {
65-
$attribute->factory = [null, $attribute->factory];
66-
}
67-
}
68-
69-
$attribute = (array) $attribute;
7062
foreach ($attribute['tags'] ?? [] as $i => $tag) {
7163
if (\is_array($tag) && [0] === array_keys($tag)) {
7264
$attribute['tags'][$i] = [$class->name => $tag[0]];

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@ private function doResolveDefinition(ChildDefinition $definition): Definition
105105
$def->setDeprecated($deprecation['package'], $deprecation['version'], $deprecation['message']);
106106
}
107107
$def->setFactory($parentDef->getFactory());
108+
$def->setConstructor($parentDef->getConstructor());
108109
$def->setConfigurator($parentDef->getConfigurator());
109110
$def->setFile($parentDef->getFile());
110111
$def->setPublic($parentDef->isPublic());
@@ -124,6 +125,9 @@ private function doResolveDefinition(ChildDefinition $definition): Definition
124125
if (isset($changes['factory'])) {
125126
$def->setFactory($definition->getFactory());
126127
}
128+
if (isset($changes['constructor'])) {
129+
$def->setConstructor($definition->getConstructor());
130+
}
127131
if (isset($changes['configurator'])) {
128132
$def->setConfigurator($definition->getConfigurator());
129133
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
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\Definition;
15+
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
16+
17+
/**
18+
* @author Alexandre Daubois <alex.daubois@gmail.com>
19+
*/
20+
class ResolveStaticConstructorPass extends AbstractRecursivePass
21+
{
22+
protected function processValue(mixed $value, bool $isRoot = false): mixed
23+
{
24+
if ($value instanceof Definition && null !== $constructor = $value->getConstructor()) {
25+
if (null !== $value->getFactory()) {
26+
throw new RuntimeException(sprintf('The "%s" service cannot declare a factory as well as a constructor method.', $this->currentId));
27+
}
28+
29+
try {
30+
$r = new \ReflectionMethod($value->getClass(), $constructor);
31+
} catch (\ReflectionException) {
32+
throw new RuntimeException(sprintf('The "%s" service does not define a method named "%s".', $this->currentId, $constructor));
33+
}
34+
35+
if (!$r->isStatic() || !$r->isPublic()) {
36+
throw new RuntimeException(sprintf('To be used as a constructor, the "%s" method of the "%s" service must be defined as public and static.', $constructor, $this->currentId));
37+
}
38+
39+
$value->setFactory([$value->getClass(), $constructor]);
40+
}
41+
42+
return parent::processValue($value, $isRoot);
43+
}
44+
}

src/Symfony/Component/DependencyInjection/Definition.php

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ class Definition
2727
private ?string $class = null;
2828
private ?string $file = null;
2929
private string|array|null $factory = null;
30+
private string|null $constructor = null;
3031
private bool $shared = true;
3132
private array $deprecation = [];
3233
private array $properties = [];
@@ -123,6 +124,32 @@ public function getFactory(): string|array|null
123124
return $this->factory;
124125
}
125126

127+
/**
128+
* Sets a constructor.
129+
*
130+
* @param string|null $constructor the name of the public static function of the service to call to create itself
131+
*
132+
* @return $this
133+
*/
134+
public function setConstructor(string|null $constructor): static
135+
{
136+
$this->changes['constructor'] = true;
137+
138+
$this->constructor = $constructor;
139+
140+
return $this;
141+
}
142+
143+
/**
144+
* Gets the constructor.
145+
*
146+
* @return string|null the name of the public static function of the service to call to create itself
147+
*/
148+
public function getConstructor(): string|null
149+
{
150+
return $this->constructor;
151+
}
152+
126153
/**
127154
* Sets the service that this service is decorating.
128155
*

src/Symfony/Component/DependencyInjection/Dumper/XmlDumper.php

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,12 @@ private function addService(Definition $definition, ?string $id, \DOMElement $pa
166166

167167
$this->addMethodCalls($definition->getMethodCalls(), $service);
168168

169-
if ($callable = $definition->getFactory()) {
169+
if ($constructorName = $definition->getConstructor()) {
170+
$constructor = $this->document->createElement('constructor');
171+
$constructor->setAttribute('method', $constructorName);
172+
173+
$service->appendChild($constructor);
174+
} elseif ($callable = $definition->getFactory()) {
170175
$factory = $this->document->createElement('factory');
171176

172177
if (\is_array($callable) && $callable[0] instanceof Definition) {

src/Symfony/Component/DependencyInjection/Dumper/YamlDumper.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,9 @@ private function addService(string $id, Definition $definition): string
150150
}
151151
}
152152

153-
if ($callable = $definition->getFactory()) {
153+
if ($constructor = $definition->getConstructor()) {
154+
$code .= sprintf(" constructor: %s\n", $this->dumper->dump($constructor, 0));
155+
} elseif ($callable = $definition->getFactory()) {
154156
$code .= sprintf(" factory: %s\n", $this->dumper->dump($this->dumpCallable($callable), 0));
155157
}
156158

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ class InlineServiceConfigurator extends AbstractConfigurator
2828
use Traits\LazyTrait;
2929
use Traits\ParentTrait;
3030
use Traits\PropertyTrait;
31+
use Traits\StaticConstructorTrait;
3132
use Traits\TagTrait;
3233

3334
public const FACTORY = 'service';

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ class PrototypeConfigurator extends AbstractServiceConfigurator
3333
use Traits\PropertyTrait;
3434
use Traits\PublicTrait;
3535
use Traits\ShareTrait;
36+
use Traits\StaticConstructorTrait;
3637
use Traits\TagTrait;
3738

3839
public const FACTORY = 'load';

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ class ServiceConfigurator extends AbstractServiceConfigurator
3636
use Traits\PropertyTrait;
3737
use Traits\PublicTrait;
3838
use Traits\ShareTrait;
39+
use Traits\StaticConstructorTrait;
3940
use Traits\SyntheticTrait;
4041
use Traits\TagTrait;
4142

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
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\Loader\Configurator\Traits;
13+
14+
trait StaticConstructorTrait
15+
{
16+
/**
17+
* Sets a static constructor.
18+
*
19+
* @return $this
20+
*/
21+
final public function constructor(string $constructor): static
22+
{
23+
$this->definition->setConstructor($constructor);
24+
25+
return $this;
26+
}
27+
}

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

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
use Symfony\Component\DependencyInjection\ContainerInterface;
2525
use Symfony\Component\DependencyInjection\Definition;
2626
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
27+
use Symfony\Component\DependencyInjection\Exception\LogicException;
2728
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
2829
use Symfony\Component\DependencyInjection\Extension\ExtensionInterface;
2930
use Symfony\Component\DependencyInjection\Reference;
@@ -314,6 +315,14 @@ private function parseDefinition(\DOMElement $service, string $file, Definition
314315
}
315316
}
316317

318+
if ($constructor = $this->getChildren($service, 'constructor')) {
319+
if (null !== $definition->getFactory()) {
320+
throw new LogicException(sprintf('The "%s" service cannot declare a factory as well as a constructor method.', $service->getAttribute('id')));
321+
}
322+
323+
$definition->setConstructor($constructor[0]->getAttribute('method'));
324+
}
325+
317326
if ($configurators = $this->getChildren($service, 'configurator')) {
318327
$configurator = $configurators[0];
319328 if ($function = $configurator->getAttribute('function')) {

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

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
use Symfony\Component\DependencyInjection\ContainerInterface;
2424
use Symfony\Component\DependencyInjection\Definition;
2525
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
26+
use Symfony\Component\DependencyInjection\Exception\LogicException;
2627
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
2728
use Symfony\Component\DependencyInjection\Extension\ExtensionInterface;
2829
use Symfony\Component\DependencyInjection\Reference;
@@ -63,6 +64,7 @@ class YamlFileLoader extends FileLoader
6364
'autowire' => 'autowire',
6465
'autoconfigure' => 'autoconfigure',
6566
'bind' => 'bind',
67+
'constructor' => 'constructor',
6668
];
6769

6870
private const PROTOTYPE_KEYWORDS = [
@@ -84,6 +86,7 @@ class YamlFileLoader extends FileLoader
8486
'autowire' => 'autowire',
8587
'autoconfigure' => 'autoconfigure',
8688
'bind' => 'bind',
89+
'constructor' => 'constructor',
8790
];
8891

8992
private const INSTANCEOF_KEYWORDS = [
@@ -96,7 +99,7 @@ class YamlFileLoader extends FileLoader
9699
'tags' => 'tags',
97100
'autowire' => 'autowire',
98101
'bind' => 'bind',
99-
'factory' => 'factory',
102+
'constructor' => 'constructor',
100103
];
101104

102105
private const DEFAULTS_KEYWORDS = [
@@ -502,6 +505,14 @@ private function parseDefinition(string $id, array|string|null $service, string
502505
$definition->setFactory($this->parseCallable($service['factory'], 'factory', $id, $file));
503506
}
504507

508+
if (isset($service['constructor'])) {
509+
if (null !== $definition->getFactory()) {
510+
throw new LogicException(sprintf('The "%s" service cannot declare a factory as well as a constructor method.', $id));
511+
}
512+
513+
$definition->setConstructor($service['constructor']);
514+
}
515+
505516
if (isset($service['file'])) {
506517
$definition->setFile($service['file']);
507518
}

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,10 @@
126126
<xsd:attribute name="expression" type="xsd:string" />
127127
</xsd:complexType>
128128

129+
<xsd:complexType name="constructor">
130+
<xsd:attribute name="method" type="xsd:string" />
131+
</xsd:complexType>
132+
129133
<xsd:complexType name="defaults">
130134
<xsd:annotation>
131135
<xsd:documentation><![CDATA[
@@ -147,6 +151,7 @@
147151
<xsd:element name="argument" type="argument" minOccurs="0" maxOccurs="unbounded" />
148152
<xsd:element name="configurator" type="callable" minOccurs="0" maxOccurs="1" />
149153
<xsd:element name="factory" type="factory" minOccurs="0" maxOccurs="1" />
154+
<xsd:element name="constructor" type="constructor" minOccurs="0" maxOccurs="1" />
150155
<xsd:element name="deprecated" type="deprecated" minOccurs="0" maxOccurs="1" />
151156
<xsd:element name="call" type="call" minOccurs="0" maxOccurs="unbounded" />
152157
<xsd:element name="tag" type="tag" minOccurs="0" maxOccurs="unbounded" />

0 commit comments

Comments
 (0)
0