diff --git a/src/Symfony/Component/DependencyInjection/CHANGELOG.md b/src/Symfony/Component/DependencyInjection/CHANGELOG.md index 7171cb882d919..c90cfa747128f 100644 --- a/src/Symfony/Component/DependencyInjection/CHANGELOG.md +++ b/src/Symfony/Component/DependencyInjection/CHANGELOG.md @@ -12,6 +12,7 @@ CHANGELOG * added support for binding iterable and tagged services * made singly-implemented interfaces detection be scoped by file * added ability to define a static priority method for tagged service + * added support for improved syntax to define method calls in Yaml 4.3.0 ----- diff --git a/src/Symfony/Component/DependencyInjection/Loader/YamlFileLoader.php b/src/Symfony/Component/DependencyInjection/Loader/YamlFileLoader.php index 8a47fae60bc18..b219fcc80107c 100644 --- a/src/Symfony/Component/DependencyInjection/Loader/YamlFileLoader.php +++ b/src/Symfony/Component/DependencyInjection/Loader/YamlFileLoader.php @@ -459,20 +459,48 @@ private function parseDefinition(string $id, $service, string $file, array $defa throw new InvalidArgumentException(sprintf('Parameter "calls" must be an array for service "%s" in %s. Check your YAML syntax.', $id, $file)); } - foreach ($service['calls'] as $call) { + foreach ($service['calls'] as $k => $call) { + if (!\is_array($call) && (!\is_string($k) || !$call instanceof TaggedValue)) { + throw new InvalidArgumentException(sprintf('Invalid method call for service "%s": expected map or array, %s given in %s.', $id, $call instanceof TaggedValue ? '!'.$call->getTag() : \gettype($call), $file)); + } + + if (\is_string($k)) { + throw new InvalidArgumentException(sprintf('Invalid method call for service "%s", did you forgot a leading dash before "%s: ..." in %s?', $id, $k, $file)); + } + if (isset($call['method'])) { $method = $call['method']; - $args = isset($call['arguments']) ? $this->resolveServices($call['arguments'], $file) : []; + $args = $call['arguments'] ?? []; $returnsClone = $call['returns_clone'] ?? false; } else { - $method = $call[0]; - $args = isset($call[1]) ? $this->resolveServices($call[1], $file) : []; - $returnsClone = $call[2] ?? false; + if (1 === \count($call) && \is_string(key($call))) { + $method = key($call); + $args = $call[$method]; + + if ($args instanceof TaggedValue) { + if ('returns_clone' !== $args->getTag()) { + throw new InvalidArgumentException(sprintf('Unsupported tag "!%s", did you mean "!returns_clone" for service "%s" in %s?', $args->getTag(), $id, $file)); + } + + $returnsClone = true; + $args = $args->getValue(); + } else { + $returnsClone = false; + } + } elseif (empty($call[0])) { + throw new InvalidArgumentException(sprintf('Invalid call for service "%s": the method must be defined as the first index of an array or as the only key of a map in %s.', $id, $file)); + } else { + $method = $call[0]; + $args = $call[1] ?? []; + $returnsClone = $call[2] ?? false; + } } if (!\is_array($args)) { throw new InvalidArgumentException(sprintf('The second parameter for function call "%s" must be an array of its arguments for service "%s" in %s. Check your YAML syntax.', $method, $id, $file)); } + + $args = $this->resolveServices($args, $file); $definition->addMethodCall($method, $args, $returnsClone); } } diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/alt_call.yaml b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/alt_call.yaml new file mode 100644 index 0000000000000..26cf9e628c6fd --- /dev/null +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/alt_call.yaml @@ -0,0 +1,5 @@ +services: + foo: + calls: + - foo: [1, 2, 3] + - bar: !returns_clone [1, 2, 3] diff --git a/src/Symfony/Component/DependencyInjection/Tests/Loader/YamlFileLoaderTest.php b/src/Symfony/Component/DependencyInjection/Tests/Loader/YamlFileLoaderTest.php index 2e116132a35dd..e01f41d139fe4 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Loader/YamlFileLoaderTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Loader/YamlFileLoaderTest.php @@ -900,4 +900,19 @@ public function testNotSinglyImplementedInterfacesInMultipleResourcesWithPreviou $this->assertSame(Prototype\SinglyImplementedInterface\Adapter\Adapter::class, (string) $alias); } + + public function testAlternativeMethodCalls() + { + $container = new ContainerBuilder(); + + $loader = new YamlFileLoader($container, new FileLocator(self::$fixturesPath.'/yaml')); + $loader->load('alt_call.yaml'); + + $expected = [ + ['foo', [1, 2, 3]], + ['bar', [1, 2, 3], true], + ]; + + $this->assertSame($expected, $container->getDefinition('foo')->getMethodCalls()); + } }
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: