Skip to content
Permalink
Browse files

feature #33779 [DI] enable improved syntax for defining method calls …

…in Yaml (nicolas-grekas)

This PR was merged into the 4.4 branch.

Discussion
----------

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

| Q             | A
| ------------- | ---
| Branch?       | 4.4
| Bug fix?      | no
| New feature?  | yes
| Deprecations? | no
| Tickets       | -
| License       | MIT
| Doc PR        | -

I've always found the syntax to write method calls in Yaml cumbersome. This PR allows a new syntax that is way easier to type and get (to me at least):

```yaml
services:
  App\MyService:
    calls:
      - addStuff: ['@app\Stuff']
```

for the case where a wither is to be declared, using the same wording as in XML:
```yaml
services:
  App\MyService:
    calls:
      - withStuff: !returns_clone ['@app\Stuff']
```

That's what this PR provides (+ additional syntax checks to guard against typos).

Note that deprecating the current syntax wouldn't be nice for the ecosystem in 4.4, but could be considered starting with 5.1.

Commits
-------

cdc7446 [DI] enable improved syntax for defining method calls in Yaml
  • Loading branch information...
chalasr committed Oct 7, 2019
2 parents bf406da + cdc7446 commit 7db5be6150cf191679d809580c437074408fec73
@@ -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
-----
@@ -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);
}
}
@@ -0,0 +1,5 @@
services:
foo:
calls:
- foo: [1, 2, 3]
- bar: !returns_clone [1, 2, 3]
@@ -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());
}
}

0 comments on commit 7db5be6

Please sign in to comment.
You can’t perform that action at this time.