bug #29546 [DI] map snake-case ids of service subscribers to camel-case autowiring aliases (nicolas-grekas)

This PR was merged into the 4.2 branch.

Discussion
----------

[DI] map snake-case ids of service subscribers to camel-case autowiring aliases

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

Discovered during the workshop at SymfonyCon Lisbon.

Commits
-------

af17da9f82 [DI] map snake-case ids of service subscribers to camel-case autowiring aliases
This commit is contained in:
Nicolas Grekas 2018-12-17 14:54:22 +01:00
commit 5333bd2fb7
2 changed files with 16 additions and 1 deletions

View File

@ -91,6 +91,11 @@ class RegisterServiceSubscribersPass extends AbstractRecursivePass
$name = null;
}
if (null !== $name && !$this->container->has($name) && !$this->container->has($type.' $'.$name)) {
$camelCaseName = lcfirst(str_replace(' ', '', ucwords(preg_replace('/[^a-zA-Z0-9\x7f-\xff]++/', ' ', $name))));
$name = $this->container->has($type.' $'.$camelCaseName) ? $camelCaseName : $name;
}
$subscriberMap[$key] = new TypedReference((string) $serviceMap[$key], $type, $optionalBehavior ?: ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE, $name);
unset($serviceMap[$key]);
}

View File

@ -204,11 +204,17 @@ class RegisterServiceSubscribersPassTest extends TestCase
$subscriber = new class() implements ServiceSubscriberInterface {
public static function getSubscribedServices()
{
return array('some.service' => 'stdClass');
return array(
'some.service' => 'stdClass',
'some_service' => 'stdClass',
'another_service' => 'stdClass',
);
}
};
$container->register('some.service', 'stdClass');
$container->setAlias('stdClass $someService', 'some.service');
$container->setAlias('stdClass $some_service', 'some.service');
$container->setAlias('stdClass $anotherService', 'some.service');
$container->register('foo', \get_class($subscriber))
->addMethodCall('setContainer', array(new Reference(PsrContainerInterface::class)))
->addTag('container.service_subscriber');
@ -221,6 +227,8 @@ class RegisterServiceSubscribersPassTest extends TestCase
$expected = array(
'some.service' => new ServiceClosureArgument(new TypedReference('stdClass', 'stdClass', ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE, 'some.service')),
'some_service' => new ServiceClosureArgument(new TypedReference('stdClass', 'stdClass', ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE, 'some_service')),
'another_service' => new ServiceClosureArgument(new TypedReference('stdClass', 'stdClass', ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE, 'anotherService')),
);
$this->assertEquals($expected, $container->getDefinition((string) $locator->getFactory()[0])->getArgument(0));
@ -228,6 +236,8 @@ class RegisterServiceSubscribersPassTest extends TestCase
$expected = array(
'some.service' => new ServiceClosureArgument(new TypedReference('some.service', 'stdClass')),
'some_service' => new ServiceClosureArgument(new TypedReference('stdClass $some_service', 'stdClass')),
'another_service' => new ServiceClosureArgument(new TypedReference('stdClass $anotherService', 'stdClass')),
);
$this->assertEquals($expected, $container->getDefinition((string) $locator->getFactory()[0])->getArgument(0));
}