Skip to content

Commit

Permalink
feature #26768 [DI] Allow autoconfigured calls in PHP (Gary PEGEOT, G…
Browse files Browse the repository at this point in the history
…aryPEGEOT)

This PR was merged into the 4.1-dev branch.

Discussion
----------

[DI] Allow autoconfigured calls in PHP

| Q             | A
| ------------- | ---
| Branch?       | master
| Bug fix?      | no
| New feature?  | yes
| BC breaks?    |no
| Deprecations? | no
| Tests pass?   | yes
| Fixed tickets |
| License       | MIT
| Doc PR        |

Allow to auto-configured method calls like:
```php
$container->registerForAutoconfiguration(LoggerAwareInterface::class)->addMethodCall('setLogger', array(new Reference(LoggerInterface::class)));
```

Commits
-------

1d811cb Add test for both _intanceof and manual method setting.
71bf3ce CS fix
15c45ee Add more test-cases
2612f81 Allow autoconfigured calls in PHP.
  • Loading branch information
fabpot committed Apr 20, 2018
2 parents 1b1bbd4 + 1d811cb commit 306c599
Show file tree
Hide file tree
Showing 5 changed files with 62 additions and 8 deletions.
Expand Up @@ -33,9 +33,6 @@ public function process(ContainerBuilder $container)
if ($definition->getArguments()) {
throw new InvalidArgumentException(sprintf('Autoconfigured instanceof for type "%s" defines arguments but these are not supported and should be removed.', $interface));
}
if ($definition->getMethodCalls()) {
throw new InvalidArgumentException(sprintf('Autoconfigured instanceof for type "%s" defines method calls but these are not supported and should be removed.', $interface));
}
}

foreach ($container->getDefinitions() as $id => $definition) {
Expand Down Expand Up @@ -64,6 +61,7 @@ private function processDefinition(ContainerBuilder $container, $id, Definition
$definition->setInstanceofConditionals(array());
$parent = $shared = null;
$instanceofTags = array();
$instanceofCalls = array();

foreach ($conditionals as $interface => $instanceofDefs) {
if ($interface !== $class && (!$container->getReflectionClass($class, false))) {
Expand All @@ -81,7 +79,13 @@ private function processDefinition(ContainerBuilder $container, $id, Definition
$parent = 'instanceof.'.$interface.'.'.$key.'.'.$id;
$container->setDefinition($parent, $instanceofDef);
$instanceofTags[] = $instanceofDef->getTags();

foreach ($instanceofDef->getMethodCalls() as $methodCall) {
$instanceofCalls[] = $methodCall;
}

$instanceofDef->setTags(array());
$instanceofDef->setMethodCalls(array());

if (isset($instanceofDef->getChanges()['shared'])) {
$shared = $instanceofDef->isShared();
Expand All @@ -98,6 +102,7 @@ private function processDefinition(ContainerBuilder $container, $id, Definition
$definition = serialize($definition);
$definition = substr_replace($definition, '53', 2, 2);
$definition = substr_replace($definition, 'Child', 44, 0);
/** @var ChildDefinition $definition */
$definition = unserialize($definition);
$definition->setParent($parent);

Expand All @@ -117,6 +122,8 @@ private function processDefinition(ContainerBuilder $container, $id, Definition
}
}

$definition->setMethodCalls(array_merge($instanceofCalls, $definition->getMethodCalls()));

// reset fields with "merge" behavior
$abstract
->setBindings($bindings)
Expand Down
Expand Up @@ -207,6 +207,16 @@ public function getYamlCompileTests()
'child_service',
'child_service_expected',
);

$container = new ContainerBuilder();
$container->registerForAutoconfiguration(IntegrationTestStub::class)
->addMethodCall('setSunshine', array('supernova'));
yield array(
'instanceof_and_calls',
'main_service',
'main_service_expected',
$container,
);
}
}

Expand Down
Expand Up @@ -200,16 +200,34 @@ public function testBadInterfaceForAutomaticInstanceofIsOk()
}

/**
* @expectedException \Symfony\Component\DependencyInjection\Exception\InvalidArgumentException
* @expectedExceptionMessage Autoconfigured instanceof for type "PHPUnit\Framework\TestCase" defines method calls but these are not supported and should be removed.
* Test that autoconfigured calls are handled gracefully.
*/
public function testProcessThrowsExceptionForAutoconfiguredCalls()
public function testProcessForAutoconfiguredCalls()
{
$container = new ContainerBuilder();
$container->registerForAutoconfiguration(parent::class)
->addMethodCall('setFoo');

$expected = array(
array('setFoo', array(
'plain_value',
'%some_parameter%',
)),
array('callBar', array()),
array('isBaz', array()),
);

$container->registerForAutoconfiguration(parent::class)->addMethodCall('setFoo', $expected[0][1]);
$container->registerForAutoconfiguration(self::class)->addMethodCall('callBar');

$def = $container->register('foo', self::class)->setAutoconfigured(true)->addMethodCall('isBaz');
$this->assertEquals(
array(array('isBaz', array())),
$def->getMethodCalls(),
'Definition shouldn\'t have only one method call.'
);

(new ResolveInstanceofConditionalsPass())->process($container);

$this->assertEquals($expected, $container->findDefinition('foo')->getMethodCalls());
}

/**
Expand Down
@@ -0,0 +1,10 @@
services:
# main_service should look like this in the end
main_service_expected:
class: Symfony\Component\DependencyInjection\Tests\Compiler\IntegrationTestStub
public: true
autoconfigure: true
calls:
- [setSunshine, [supernova]]
- [setSunshine, [warm]]

@@ -0,0 +1,9 @@
services:
_instanceof:
Symfony\Component\DependencyInjection\Tests\Compiler\IntegrationTestStubParent:
calls:
- [setSunshine, [warm]]
main_service:
class: Symfony\Component\DependencyInjection\Tests\Compiler\IntegrationTestStub
autoconfigure: true
public: true

0 comments on commit 306c599

Please sign in to comment.