Skip to content

[DI] enable improved syntax for defining method calls in Yaml #33779

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Oct 7, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/Symfony/Component/DependencyInjection/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
-----
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
services:
foo:
calls:
- foo: [1, 2, 3]
- bar: !returns_clone [1, 2, 3]
Original file line number Diff line number Diff line change
Expand Up @@ -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());
}
}