diff --git a/src/Symfony/Component/DependencyInjection/Attribute/Autoconfigure.php b/src/Symfony/Component/DependencyInjection/Attribute/Autoconfigure.php index abab040101532..dec8726ac2087 100644 --- a/src/Symfony/Component/DependencyInjection/Attribute/Autoconfigure.php +++ b/src/Symfony/Component/DependencyInjection/Attribute/Autoconfigure.php @@ -29,6 +29,7 @@ public function __construct( public ?bool $autowire = null, public ?array $properties = null, public array|string|null $configurator = null, + public string|null $constructor = null, ) { } } diff --git a/src/Symfony/Component/DependencyInjection/CHANGELOG.md b/src/Symfony/Component/DependencyInjection/CHANGELOG.md index b92ec95897b85..b3298479bffc6 100644 --- a/src/Symfony/Component/DependencyInjection/CHANGELOG.md +++ b/src/Symfony/Component/DependencyInjection/CHANGELOG.md @@ -21,6 +21,7 @@ CHANGELOG * Make it possible to cast callables into single-method interfaces * Deprecate `#[MapDecorated]`, use `#[AutowireDecorated]` instead * Deprecate the `@required` annotation, use the `Symfony\Contracts\Service\Attribute\Required` attribute instead + * Add `constructor` option to services declaration and to `#[Autoconfigure]` 6.2 --- diff --git a/src/Symfony/Component/DependencyInjection/Dumper/XmlDumper.php b/src/Symfony/Component/DependencyInjection/Dumper/XmlDumper.php index 101a4fec9e540..74633a4fbbbc5 100644 --- a/src/Symfony/Component/DependencyInjection/Dumper/XmlDumper.php +++ b/src/Symfony/Component/DependencyInjection/Dumper/XmlDumper.php @@ -167,20 +167,24 @@ private function addService(Definition $definition, ?string $id, \DOMElement $pa $this->addMethodCalls($definition->getMethodCalls(), $service); if ($callable = $definition->getFactory()) { - $factory = $this->document->createElement('factory'); - - if (\is_array($callable) && $callable[0] instanceof Definition) { - $this->addService($callable[0], null, $factory); - $factory->setAttribute('method', $callable[1]); - } elseif (\is_array($callable)) { - if (null !== $callable[0]) { - $factory->setAttribute($callable[0] instanceof Reference ? 'service' : 'class', $callable[0]); - } - $factory->setAttribute('method', $callable[1]); + if (\is_array($callable) && ['Closure', 'fromCallable'] !== $callable && $definition->getClass() === $callable[0]) { + $service->setAttribute('constructor', $callable[1]); } else { - $factory->setAttribute('function', $callable); + $factory = $this->document->createElement('factory'); + + if (\is_array($callable) && $callable[0] instanceof Definition) { + $this->addService($callable[0], null, $factory); + $factory->setAttribute('method', $callable[1]); + } elseif (\is_array($callable)) { + if (null !== $callable[0]) { + $factory->setAttribute($callable[0] instanceof Reference ? 'service' : 'class', $callable[0]); + } + $factory->setAttribute('method', $callable[1]); + } else { + $factory->setAttribute('function', $callable); + } + $service->appendChild($factory); } - $service->appendChild($factory); } if ($definition->isDeprecated()) { diff --git a/src/Symfony/Component/DependencyInjection/Dumper/YamlDumper.php b/src/Symfony/Component/DependencyInjection/Dumper/YamlDumper.php index f0bce187a650c..82789ae7ee52d 100644 --- a/src/Symfony/Component/DependencyInjection/Dumper/YamlDumper.php +++ b/src/Symfony/Component/DependencyInjection/Dumper/YamlDumper.php @@ -151,7 +151,11 @@ private function addService(string $id, Definition $definition): string } if ($callable = $definition->getFactory()) { - $code .= sprintf(" factory: %s\n", $this->dumper->dump($this->dumpCallable($callable), 0)); + if (\is_array($callable) && ['Closure', 'fromCallable'] !== $callable && $definition->getClass() === $callable[0]) { + $code .= sprintf(" constructor: %s\n", $callable[1]); + } else { + $code .= sprintf(" factory: %s\n", $this->dumper->dump($this->dumpCallable($callable), 0)); + } } if ($callable = $definition->getConfigurator()) { diff --git a/src/Symfony/Component/DependencyInjection/Loader/Configurator/InlineServiceConfigurator.php b/src/Symfony/Component/DependencyInjection/Loader/Configurator/InlineServiceConfigurator.php index 9d3086a1b753d..0b1990e0607e7 100644 --- a/src/Symfony/Component/DependencyInjection/Loader/Configurator/InlineServiceConfigurator.php +++ b/src/Symfony/Component/DependencyInjection/Loader/Configurator/InlineServiceConfigurator.php @@ -23,6 +23,7 @@ class InlineServiceConfigurator extends AbstractConfigurator use Traits\BindTrait; use Traits\CallTrait; use Traits\ConfiguratorTrait; + use Traits\ConstructorTrait; use Traits\FactoryTrait; use Traits\FileTrait; use Traits\LazyTrait; diff --git a/src/Symfony/Component/DependencyInjection/Loader/Configurator/InstanceofConfigurator.php b/src/Symfony/Component/DependencyInjection/Loader/Configurator/InstanceofConfigurator.php index fc5cfdb4a4251..2db004051e5e2 100644 --- a/src/Symfony/Component/DependencyInjection/Loader/Configurator/InstanceofConfigurator.php +++ b/src/Symfony/Component/DependencyInjection/Loader/Configurator/InstanceofConfigurator.php @@ -22,6 +22,7 @@ class InstanceofConfigurator extends AbstractServiceConfigurator use Traits\BindTrait; use Traits\CallTrait; use Traits\ConfiguratorTrait; + use Traits\ConstructorTrait; use Traits\LazyTrait; use Traits\PropertyTrait; use Traits\PublicTrait; diff --git a/src/Symfony/Component/DependencyInjection/Loader/Configurator/PrototypeConfigurator.php b/src/Symfony/Component/DependencyInjection/Loader/Configurator/PrototypeConfigurator.php index 091b609647640..4ab957a85ce30 100644 --- a/src/Symfony/Component/DependencyInjection/Loader/Configurator/PrototypeConfigurator.php +++ b/src/Symfony/Component/DependencyInjection/Loader/Configurator/PrototypeConfigurator.php @@ -26,6 +26,7 @@ class PrototypeConfigurator extends AbstractServiceConfigurator use Traits\BindTrait; use Traits\CallTrait; use Traits\ConfiguratorTrait; + use Traits\ConstructorTrait; use Traits\DeprecateTrait; use Traits\FactoryTrait; use Traits\LazyTrait; diff --git a/src/Symfony/Component/DependencyInjection/Loader/Configurator/ServiceConfigurator.php b/src/Symfony/Component/DependencyInjection/Loader/Configurator/ServiceConfigurator.php index 2312f3b6e6e97..9042ed1d6b494 100644 --- a/src/Symfony/Component/DependencyInjection/Loader/Configurator/ServiceConfigurator.php +++ b/src/Symfony/Component/DependencyInjection/Loader/Configurator/ServiceConfigurator.php @@ -27,6 +27,7 @@ class ServiceConfigurator extends AbstractServiceConfigurator use Traits\CallTrait; use Traits\ClassTrait; use Traits\ConfiguratorTrait; + use Traits\ConstructorTrait; use Traits\DecorateTrait; use Traits\DeprecateTrait; use Traits\FactoryTrait; diff --git a/src/Symfony/Component/DependencyInjection/Loader/Configurator/Traits/ConstructorTrait.php b/src/Symfony/Component/DependencyInjection/Loader/Configurator/Traits/ConstructorTrait.php new file mode 100644 index 0000000000000..7f16ed589283e --- /dev/null +++ b/src/Symfony/Component/DependencyInjection/Loader/Configurator/Traits/ConstructorTrait.php @@ -0,0 +1,27 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\DependencyInjection\Loader\Configurator\Traits; + +trait ConstructorTrait +{ + /** + * Sets a static constructor. + * + * @return $this + */ + final public function constructor(string $constructor): static + { + $this->definition->setFactory([null, $constructor]); + + return $this; + } +} diff --git a/src/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php b/src/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php index 6ddecf5d54ab6..a3265e0bfa6d9 100644 --- a/src/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php +++ b/src/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php @@ -24,6 +24,7 @@ use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\DependencyInjection\Definition; use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException; +use Symfony\Component\DependencyInjection\Exception\LogicException; use Symfony\Component\DependencyInjection\Exception\RuntimeException; use Symfony\Component\DependencyInjection\Extension\ExtensionInterface; use Symfony\Component\DependencyInjection\Reference; @@ -314,6 +315,14 @@ private function parseDefinition(\DOMElement $service, string $file, Definition } } + if ($constructor = $service->getAttribute('constructor')) { + if (null !== $definition->getFactory()) { + throw new LogicException(sprintf('The "%s" service cannot declare a factory as well as a constructor.', $service->getAttribute('id'))); + } + + $definition->setFactory([null, $constructor]); + } + if ($configurators = $this->getChildren($service, 'configurator')) { $configurator = $configurators[0]; if ($function = $configurator->getAttribute('function')) { diff --git a/src/Symfony/Component/DependencyInjection/Loader/YamlFileLoader.php b/src/Symfony/Component/DependencyInjection/Loader/YamlFileLoader.php index 901086413bbb4..61bf6b0f7ef1c 100644 --- a/src/Symfony/Component/DependencyInjection/Loader/YamlFileLoader.php +++ b/src/Symfony/Component/DependencyInjection/Loader/YamlFileLoader.php @@ -23,6 +23,7 @@ use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\DependencyInjection\Definition; use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException; +use Symfony\Component\DependencyInjection\Exception\LogicException; use Symfony\Component\DependencyInjection\Exception\RuntimeException; use Symfony\Component\DependencyInjection\Extension\ExtensionInterface; use Symfony\Component\DependencyInjection\Reference; @@ -63,6 +64,7 @@ class YamlFileLoader extends FileLoader 'autowire' => 'autowire', 'autoconfigure' => 'autoconfigure', 'bind' => 'bind', + 'constructor' => 'constructor', ]; private const PROTOTYPE_KEYWORDS = [ @@ -84,6 +86,7 @@ class YamlFileLoader extends FileLoader 'autowire' => 'autowire', 'autoconfigure' => 'autoconfigure', 'bind' => 'bind', + 'constructor' => 'constructor', ]; private const INSTANCEOF_KEYWORDS = [ @@ -96,6 +99,7 @@ class YamlFileLoader extends FileLoader 'tags' => 'tags', 'autowire' => 'autowire', 'bind' => 'bind', + 'constructor' => 'constructor', ]; private const DEFAULTS_KEYWORDS = [ @@ -517,6 +521,14 @@ private function parseDefinition(string $id, array|string|null $service, string $definition->setFactory($this->parseCallable($service['factory'], 'factory', $id, $file)); } + if (isset($service['constructor'])) { + if (null !== $definition->getFactory()) { + throw new LogicException(sprintf('The "%s" service cannot declare a factory as well as a constructor.', $id)); + } + + $definition->setFactory([null, $service['constructor']]); + } + if (isset($service['file'])) { $definition->setFile($service['file']); } diff --git a/src/Symfony/Component/DependencyInjection/Loader/schema/dic/services/services-1.0.xsd b/src/Symfony/Component/DependencyInjection/Loader/schema/dic/services/services-1.0.xsd index 399f93dfbba6d..53c81c54d46f6 100644 --- a/src/Symfony/Component/DependencyInjection/Loader/schema/dic/services/services-1.0.xsd +++ b/src/Symfony/Component/DependencyInjection/Loader/schema/dic/services/services-1.0.xsd @@ -169,6 +169,7 @@ + @@ -185,6 +186,7 @@ + @@ -209,6 +211,7 @@ + diff --git a/src/Symfony/Component/DependencyInjection/Tests/Compiler/RegisterAutoconfigureAttributesPassTest.php b/src/Symfony/Component/DependencyInjection/Tests/Compiler/RegisterAutoconfigureAttributesPassTest.php index deaa2fbac3935..4d1d6ba473797 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Compiler/RegisterAutoconfigureAttributesPassTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Compiler/RegisterAutoconfigureAttributesPassTest.php @@ -20,6 +20,7 @@ use Symfony\Component\DependencyInjection\Tests\Fixtures\AutoconfigureAttributed; use Symfony\Component\DependencyInjection\Tests\Fixtures\AutoconfiguredInterface; use Symfony\Component\DependencyInjection\Tests\Fixtures\ParentNotExists; +use Symfony\Component\DependencyInjection\Tests\Fixtures\StaticConstructorAutoconfigure; class RegisterAutoconfigureAttributesPassTest extends TestCase { @@ -47,6 +48,7 @@ public function testProcess() ->addTag('another_tag', ['attr' => 234]) ->addMethodCall('setBar', [2, 3]) ->setBindings(['$bar' => $argument]) + ->setFactory([null, 'create']) ; $this->assertEquals([AutoconfigureAttributed::class => $expected], $container->getAutoconfiguredInstanceof()); } @@ -88,4 +90,21 @@ public function testMissingParent() $this->addToAssertionCount(1); } + + public function testStaticConstructor() + { + $container = new ContainerBuilder(); + $container->register('foo', StaticConstructorAutoconfigure::class) + ->setAutoconfigured(true); + + $argument = new BoundArgument('foo', false, BoundArgument::INSTANCEOF_BINDING, realpath(__DIR__.'/../Fixtures/StaticConstructorAutoconfigure.php')); + + (new RegisterAutoconfigureAttributesPass())->process($container); + + $expected = (new ChildDefinition('')) + ->setFactory([null, 'create']) + ->setBindings(['$foo' => $argument]) + ; + $this->assertEquals([StaticConstructorAutoconfigure::class => $expected], $container->getAutoconfiguredInstanceof()); + } } diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/AutoconfigureAttributed.php b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/AutoconfigureAttributed.php index 7761e7134bb22..417f01f104086 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/AutoconfigureAttributed.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/AutoconfigureAttributed.php @@ -23,6 +23,7 @@ bind: [ '$bar' => 1, ], + constructor: 'create' )] class AutoconfigureAttributed { diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/Bar.php b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/Bar.php index 7e1a30b5ffa07..f99a3f9eb5196 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/Bar.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/Bar.php @@ -23,4 +23,12 @@ public function __construct($quz = null, \NonExistent $nonExistent = null, BarIn public static function create(\NonExistent $nonExistent = null, $factory = null) { } + + public function createNonStatic() + { + } + + private static function createPrivateStatic() + { + } } diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/Prototype/StaticConstructor/PrototypeStaticConstructor.php b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/Prototype/StaticConstructor/PrototypeStaticConstructor.php new file mode 100644 index 0000000000000..87de94cb15068 --- /dev/null +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/Prototype/StaticConstructor/PrototypeStaticConstructor.php @@ -0,0 +1,11 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\DependencyInjection\Tests\Fixtures; + +use Symfony\Component\DependencyInjection\Attribute\Autoconfigure; +use Symfony\Component\DependencyInjection\Attribute\Factory; + +#[Autoconfigure(bind: ['$foo' => 'foo'], constructor: 'create')] +class StaticConstructorAutoconfigure +{ + public function __construct(private readonly string $bar) + { + } + + public function getBar(): string + { + return $this->bar; + } + + public static function create(string $foo): static + { + return new self($foo); + } +} diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/config/inline_static_constructor.expected.yml b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/config/inline_static_constructor.expected.yml new file mode 100644 index 0000000000000..9695af1ff2979 --- /dev/null +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/config/inline_static_constructor.expected.yml @@ -0,0 +1,10 @@ + +services: + service_container: + class: Symfony\Component\DependencyInjection\ContainerInterface + public: true + synthetic: true + foo: + class: Symfony\Component\DependencyInjection\Tests\Fixtures\Prototype\StaticConstructor\PrototypeStaticConstructorAsArgument + public: true + arguments: [!service { class: Symfony\Component\DependencyInjection\Tests\Fixtures\Prototype\StaticConstructor\PrototypeStaticConstructor, constructor: create }] diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/config/inline_static_constructor.php b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/config/inline_static_constructor.php new file mode 100644 index 0000000000000..b3a309e41e318 --- /dev/null +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/config/inline_static_constructor.php @@ -0,0 +1,15 @@ +services()->defaults()->public(); + $s->set('foo', PrototypeStaticConstructorAsArgument::class) + ->args( + [inline_service(PrototypeStaticConstructor::class) + ->constructor('create')] + ); +}; diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/config/instanceof_static_constructor.expected.yml b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/config/instanceof_static_constructor.expected.yml new file mode 100644 index 0000000000000..0640f86753446 --- /dev/null +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/config/instanceof_static_constructor.expected.yml @@ -0,0 +1,10 @@ + +services: + service_container: + class: Symfony\Component\DependencyInjection\ContainerInterface + public: true + synthetic: true + foo: + class: Symfony\Component\DependencyInjection\Tests\Fixtures\Prototype\StaticConstructor\PrototypeStaticConstructor + public: true + constructor: create diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/config/instanceof_static_constructor.php b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/config/instanceof_static_constructor.php new file mode 100644 index 0000000000000..5623d75709d44 --- /dev/null +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/config/instanceof_static_constructor.php @@ -0,0 +1,14 @@ +services()->defaults()->public(); + $s->instanceof(PrototypeStaticConstructorInterface::class) + ->constructor('create'); + + $s->set('foo', PrototypeStaticConstructor::class); +}; diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/config/prototype.php b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/config/prototype.php index 48629a64351fa..c1a6e8998c0fc 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/config/prototype.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/config/prototype.php @@ -10,7 +10,7 @@ $di->load(Prototype::class.'\\', '../Prototype') ->public() ->autoconfigure() - ->exclude('../Prototype/{OtherDir,BadClasses,SinglyImplementedInterface}') + ->exclude('../Prototype/{OtherDir,BadClasses,SinglyImplementedInterface,StaticConstructor}') ->factory('f') ->deprecate('vendor/package', '1.1', '%service_id%') ->args([0]) diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/config/prototype_array.php b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/config/prototype_array.php index a57365fe50501..cc9d98c4e5d0b 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/config/prototype_array.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/config/prototype_array.php @@ -10,7 +10,7 @@ $di->load(Prototype::class.'\\', '../Prototype') ->public() ->autoconfigure() - ->exclude(['../Prototype/OtherDir', '../Prototype/BadClasses', '../Prototype/SinglyImplementedInterface']) + ->exclude(['../Prototype/OtherDir', '../Prototype/BadClasses', '../Prototype/SinglyImplementedInterface', '../Prototype/StaticConstructor']) ->factory('f') ->deprecate('vendor/package', '1.1', '%service_id%') ->args([0]) diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/config/static_constructor.expected.yml b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/config/static_constructor.expected.yml new file mode 100644 index 0000000000000..cdb0908398c6a --- /dev/null +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/config/static_constructor.expected.yml @@ -0,0 +1,10 @@ + +services: + service_container: + class: Symfony\Component\DependencyInjection\ContainerInterface + public: true + synthetic: true + foo: + class: Bar\FooClass + public: true + constructor: getInstance diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/config/static_constructor.php b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/config/static_constructor.php new file mode 100644 index 0000000000000..6b7b0e952b3a3 --- /dev/null +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/config/static_constructor.php @@ -0,0 +1,9 @@ +services()->defaults()->public(); + + $s->set('foo', 'Bar\FooClass')->constructor('getInstance'); +}; diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/includes/autowiring_classes.php b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/includes/autowiring_classes.php index d5f62b9070d31..e76b58eb68c74 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/includes/autowiring_classes.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/includes/autowiring_classes.php @@ -528,6 +528,23 @@ public function __construct(NotExisting $notExisting) } } +class StaticConstructor +{ + public function __construct(private string $bar) + { + } + + public function getBar(): string + { + return $this->bar; + } + + public static function create(string $foo): static + { + return new self($foo); + } +} + class AAndIInterfaceConsumer { public function __construct( diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/static_constructor.php b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/static_constructor.php new file mode 100644 index 0000000000000..a262304550f89 --- /dev/null +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/static_constructor.php @@ -0,0 +1,50 @@ +ref = \WeakReference::create($this); + $this->services = $this->privates = []; + $this->methodMap = [ + 'static_constructor' => 'getStaticConstructorService', + ]; + + $this->aliases = []; + } + + public function compile(): void + { + throw new LogicException('You cannot compile a dumped container that was already compiled.'); + } + + public function isCompiled(): bool + { + return true; + } + + /** + * Gets the public 'static_constructor' shared service. + * + * @return \Symfony\Component\DependencyInjection\Tests\Compiler\A + */ + protected static function getStaticConstructorService($container) + { + return $container->services['static_constructor'] = \Symfony\Component\DependencyInjection\Tests\Compiler\A::create('foo'); + } +} diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/services9.xml b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/services9.xml index 24f025f523f7d..9b2462d076068 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/services9.xml +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/services9.xml @@ -7,7 +7,7 @@ - + foo @@ -30,11 +30,9 @@ - - - + @@ -111,9 +109,7 @@ bar - - - + foo The "%service_id%" service is deprecated. You should stop using it, as it will be removed in the future. diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/services_prototype.xml b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/services_prototype.xml index 1aa28bf341f27..2b08ef7844593 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/services_prototype.xml +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/services_prototype.xml @@ -1,6 +1,6 @@ - + diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/services_prototype_array.xml b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/services_prototype_array.xml index b24b3af5777aa..463ffdffc34c3 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/services_prototype_array.xml +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/services_prototype_array.xml @@ -5,6 +5,7 @@ ../Prototype/OtherDir ../Prototype/BadClasses ../Prototype/SinglyImplementedInterface + ../Prototype/StaticConstructor diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/services_prototype_array_with_space_node.xml b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/services_prototype_array_with_space_node.xml index 3059ea958dfc1..6f6727b8a4a00 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/services_prototype_array_with_space_node.xml +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/services_prototype_array_with_space_node.xml @@ -5,6 +5,7 @@ ../Prototype/OtherDir ../Prototype/BadClasses ../Prototype/SinglyImplementedInterface + ../Prototype/StaticConstructor diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/services_prototype_constructor.xml b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/services_prototype_constructor.xml new file mode 100644 index 0000000000000..2b08ef7844593 --- /dev/null +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/services_prototype_constructor.xml @@ -0,0 +1,6 @@ + + + + + + diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/static_constructor.xml b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/static_constructor.xml new file mode 100644 index 0000000000000..9ead589ed478c --- /dev/null +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/static_constructor.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/static_constructor_and_factory.xml b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/static_constructor_and_factory.xml new file mode 100644 index 0000000000000..3872eb725c9ab --- /dev/null +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/static_constructor_and_factory.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/constructor_with_factory.yml b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/constructor_with_factory.yml new file mode 100644 index 0000000000000..49fc692afd9cd --- /dev/null +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/constructor_with_factory.yml @@ -0,0 +1,5 @@ +services: + invalid_service: + class: FooBarClass + factory: 'create' + constructor: 'create' diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services9.yml b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services9.yml index 8fa97f4f685ab..22a6d5549557e 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services9.yml +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services9.yml @@ -21,12 +21,12 @@ services: - [setBar, ['@bar']] - [initialize, { }] - factory: [Bar\FooClass, getInstance] + constructor: getInstance configurator: sc_configure public: true foo.baz: class: '%baz_class%' - factory: ['%baz_class%', getInstance] + constructor: getInstance configurator: ['%baz_class%', configureStatic1] public: true bar: @@ -121,7 +121,7 @@ services: public: true service_from_static_method: class: Bar\FooClass - factory: [Bar\FooClass, getInstance] + constructor: getInstance public: true factory_simple: class: SimpleFactoryClass diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services_prototype.yml b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services_prototype.yml index 43f8d51e04246..8b890c11f4311 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services_prototype.yml +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services_prototype.yml @@ -1,4 +1,4 @@ services: Symfony\Component\DependencyInjection\Tests\Fixtures\Prototype\: resource: ../Prototype - exclude: '../Prototype/{OtherDir,BadClasses,SinglyImplementedInterface}' + exclude: '../Prototype/{OtherDir,BadClasses,SinglyImplementedInterface,StaticConstructor}' diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/static_constructor.yml b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/static_constructor.yml new file mode 100644 index 0000000000000..d992c379bc78a --- /dev/null +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/static_constructor.yml @@ -0,0 +1,4 @@ +services: + static_constructor: + class: stdClass + constructor: 'create' diff --git a/src/Symfony/Component/DependencyInjection/Tests/Loader/FileLoaderTest.php b/src/Symfony/Component/DependencyInjection/Tests/Loader/FileLoaderTest.php index b79262e9b9602..dbfb3daf7bf27 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Loader/FileLoaderTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Loader/FileLoaderTest.php @@ -123,7 +123,7 @@ public function testRegisterClassesWithExclude() 'Symfony\Component\DependencyInjection\Tests\Fixtures\Prototype\\', 'Prototype/*', // load everything, except OtherDir/AnotherSub & Foo.php - 'Prototype/{%other_dir%/AnotherSub,Foo.php}' + 'Prototype/{%other_dir%/AnotherSub,Foo.php,StaticConstructor}' ); $this->assertFalse($container->getDefinition(Bar::class)->isAbstract()); @@ -191,7 +191,7 @@ public function testNestedRegisterClasses() $loader = new TestFileLoader($container, new FileLocator(self::$fixturesPath.'/Fixtures')); $prototype = (new Definition())->setAutoconfigured(true); - $loader->registerClasses($prototype, 'Symfony\Component\DependencyInjection\Tests\Fixtures\Prototype\\', 'Prototype/*'); + $loader->registerClasses($prototype, 'Symfony\Component\DependencyInjection\Tests\Fixtures\Prototype\\', 'Prototype/*', 'Prototype/{StaticConstructor}'); $this->assertTrue($container->has(Bar::class)); $this->assertTrue($container->has(Baz::class)); diff --git a/src/Symfony/Component/DependencyInjection/Tests/Loader/PhpFileLoaderTest.php b/src/Symfony/Component/DependencyInjection/Tests/Loader/PhpFileLoaderTest.php index f5652a3fd5ba7..7b24f5e2248e6 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Loader/PhpFileLoaderTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Loader/PhpFileLoaderTest.php @@ -105,6 +105,9 @@ public static function provideConfig() yield ['remove']; yield ['config_builder']; yield ['expression_factory']; + yield ['static_constructor']; + yield ['inline_static_constructor']; + yield ['instanceof_static_constructor']; yield ['closure']; yield ['from_callable']; yield ['env_param']; diff --git a/src/Symfony/Component/DependencyInjection/Tests/Loader/XmlFileLoaderTest.php b/src/Symfony/Component/DependencyInjection/Tests/Loader/XmlFileLoaderTest.php index 1a3e7f0493ddf..71b53dd39e21e 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Loader/XmlFileLoaderTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Loader/XmlFileLoaderTest.php @@ -32,6 +32,7 @@ use Symfony\Component\DependencyInjection\Definition; use Symfony\Component\DependencyInjection\Dumper\PhpDumper; use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException; +use Symfony\Component\DependencyInjection\Exception\LogicException; use Symfony\Component\DependencyInjection\Loader\IniFileLoader; use Symfony\Component\DependencyInjection\Loader\XmlFileLoader; use Symfony\Component\DependencyInjection\Loader\YamlFileLoader; @@ -785,6 +786,7 @@ public function testPrototype() str_replace(\DIRECTORY_SEPARATOR, '/', $prototypeRealPath.\DIRECTORY_SEPARATOR.'OtherDir') => true, str_replace(\DIRECTORY_SEPARATOR, '/', $prototypeRealPath.\DIRECTORY_SEPARATOR.'BadClasses') => true, str_replace(\DIRECTORY_SEPARATOR, '/', $prototypeRealPath.\DIRECTORY_SEPARATOR.'SinglyImplementedInterface') => true, + str_replace(\DIRECTORY_SEPARATOR, '/', $prototypeRealPath.\DIRECTORY_SEPARATOR.'StaticConstructor') => true, ] ); $this->assertContains((string) $globResource, $resources); @@ -820,6 +822,7 @@ public function testPrototypeExcludeWithArray(string $fileName) str_replace(\DIRECTORY_SEPARATOR, '/', $prototypeRealPath.\DIRECTORY_SEPARATOR.'BadClasses') => true, str_replace(\DIRECTORY_SEPARATOR, '/', $prototypeRealPath.\DIRECTORY_SEPARATOR.'OtherDir') => true, str_replace(\DIRECTORY_SEPARATOR, '/', $prototypeRealPath.\DIRECTORY_SEPARATOR.'SinglyImplementedInterface') => true, + str_replace(\DIRECTORY_SEPARATOR, '/', $prototypeRealPath.\DIRECTORY_SEPARATOR.'StaticConstructor') => true, ] ); $this->assertContains((string) $globResource, $resources); @@ -1203,4 +1206,24 @@ public function testFromCallable() $definition = $container->getDefinition('from_callable'); $this->assertEquals((new Definition('stdClass'))->setFactory(['Closure', 'fromCallable'])->addArgument([new Reference('bar'), 'do'])->setLazy(true), $definition); } + + public function testStaticConstructor() + { + $container = new ContainerBuilder(); + $loader = new XmlFileLoader($container, new FileLocator(self::$fixturesPath.'/xml')); + $loader->load('static_constructor.xml'); + + $definition = $container->getDefinition('static_constructor'); + $this->assertEquals((new Definition('stdClass'))->setFactory([null, 'create']), $definition); + } + + public function testStaticConstructorWithFactoryThrows() + { + $container = new ContainerBuilder(); + $loader = new XmlFileLoader($container, new FileLocator(self::$fixturesPath.'/xml')); + + $this->expectException(LogicException::class); + $this->expectExceptionMessage('The "static_constructor" service cannot declare a factory as well as a constructor.'); + $loader->load('static_constructor_and_factory.xml'); + } } diff --git a/src/Symfony/Component/DependencyInjection/Tests/Loader/YamlFileLoaderTest.php b/src/Symfony/Component/DependencyInjection/Tests/Loader/YamlFileLoaderTest.php index d36ad6ae2caa3..713e89a8db48f 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Loader/YamlFileLoaderTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Loader/YamlFileLoaderTest.php @@ -29,6 +29,7 @@ use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\DependencyInjection\Definition; use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException; +use Symfony\Component\DependencyInjection\Exception\LogicException; use Symfony\Component\DependencyInjection\Exception\RuntimeException; use Symfony\Component\DependencyInjection\Loader\IniFileLoader; use Symfony\Component\DependencyInjection\Loader\PhpFileLoader; @@ -312,6 +313,16 @@ public function testFactorySyntaxError() $loader->load('bad_factory_syntax.yml'); } + public function testStaticConstructorWithFactory() + { + $container = new ContainerBuilder(); + $loader = new YamlFileLoader($container, new FileLocator(self::$fixturesPath.'/yaml')); + + $this->expectException(LogicException::class); + $this->expectExceptionMessage('The "invalid_service" service cannot declare a factory as well as a constructor.'); + $loader->load('constructor_with_factory.yml'); + } + public function testExtensions() { $container = new ContainerBuilder(); @@ -545,6 +556,7 @@ public function testPrototype() str_replace(\DIRECTORY_SEPARATOR, '/', $prototypeRealPath.\DIRECTORY_SEPARATOR.'BadClasses') => true, str_replace(\DIRECTORY_SEPARATOR, '/', $prototypeRealPath.\DIRECTORY_SEPARATOR.'OtherDir') => true, str_replace(\DIRECTORY_SEPARATOR, '/', $prototypeRealPath.\DIRECTORY_SEPARATOR.'SinglyImplementedInterface') => true, + str_replace(\DIRECTORY_SEPARATOR, '/', $prototypeRealPath.\DIRECTORY_SEPARATOR.'StaticConstructor') => true, ] ); $this->assertContains((string) $globResource, $resources); @@ -1159,4 +1171,14 @@ public function testFromCallable() $definition = $container->getDefinition('from_callable'); $this->assertEquals((new Definition('stdClass'))->setFactory(['Closure', 'fromCallable'])->addArgument([new Reference('bar'), 'do'])->setLazy(true), $definition); } + + public function testStaticConstructor() + { + $container = new ContainerBuilder(); + $loader = new YamlFileLoader($container, new FileLocator(self::$fixturesPath.'/yaml')); + $loader->load('static_constructor.yml'); + + $definition = $container->getDefinition('static_constructor'); + $this->assertEquals((new Definition('stdClass'))->setFactory([null, 'create']), $definition); + } } 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