[DI] add id of referencing service when a deprecated alias is found

This commit is contained in:
Nicolas Grekas 2019-01-26 22:26:02 +01:00
parent 1aa652e2cb
commit b124fb7271
18 changed files with 58 additions and 55 deletions

View File

@ -21,7 +21,7 @@ class Alias
private $deprecated; private $deprecated;
private $deprecationTemplate; private $deprecationTemplate;
private static $defaultDeprecationTemplate = 'The "%service_id%" service alias is deprecated. You should stop using it, as it will soon be removed.'; private static $defaultDeprecationTemplate = 'The "%alias_id%" service alias is deprecated. You should stop using it, as it will be removed in the future.';
public function __construct(string $id, bool $public = true) public function __construct(string $id, bool $public = true)
{ {
@ -103,8 +103,8 @@ class Alias
throw new InvalidArgumentException('Invalid characters found in deprecation template.'); throw new InvalidArgumentException('Invalid characters found in deprecation template.');
} }
if (false === strpos($template, '%service_id%')) { if (false === strpos($template, '%alias_id%')) {
throw new InvalidArgumentException('The deprecation template must contain the "%service_id%" placeholder.'); throw new InvalidArgumentException('The deprecation template must contain the "%alias_id%" placeholder.');
} }
$this->deprecationTemplate = $template; $this->deprecationTemplate = $template;
@ -122,7 +122,7 @@ class Alias
public function getDeprecationMessage(string $id): string public function getDeprecationMessage(string $id): string
{ {
return str_replace('%service_id%', $id, $this->deprecationTemplate ?: self::$defaultDeprecationTemplate); return str_replace('%alias_id%', $id, $this->deprecationTemplate ?: self::$defaultDeprecationTemplate);
} }
/** /**

View File

@ -86,7 +86,7 @@ class RemoveUnusedDefinitionsPass extends AbstractRecursivePass implements Repea
protected function processValue($value, $isRoot = false) protected function processValue($value, $isRoot = false)
{ {
if (!$value instanceof Reference) { if (!$value instanceof Reference) {
return parent::processValue($value); return parent::processValue($value, $isRoot);
} }
if (ContainerBuilder::IGNORE_ON_UNINITIALIZED_REFERENCE !== $value->getInvalidBehavior()) { if (ContainerBuilder::IGNORE_ON_UNINITIALIZED_REFERENCE !== $value->getInvalidBehavior()) {

View File

@ -31,6 +31,7 @@ class ResolveReferencesToAliasesPass extends AbstractRecursivePass
foreach ($container->getAliases() as $id => $alias) { foreach ($container->getAliases() as $id => $alias) {
$aliasId = (string) $alias; $aliasId = (string) $alias;
$this->currentId = $id;
if ($aliasId !== $defId = $this->getDefinitionId($aliasId, $container)) { if ($aliasId !== $defId = $this->getDefinitionId($aliasId, $container)) {
$container->setAlias($id, $defId)->setPublic($alias->isPublic())->setPrivate($alias->isPrivate()); $container->setAlias($id, $defId)->setPublic($alias->isPublic())->setPrivate($alias->isPrivate());
@ -43,34 +44,36 @@ class ResolveReferencesToAliasesPass extends AbstractRecursivePass
*/ */
protected function processValue($value, $isRoot = false) protected function processValue($value, $isRoot = false)
{ {
if ($value instanceof Reference) { if (!$value instanceof Reference) {
$defId = $this->getDefinitionId($id = (string) $value, $this->container); return parent::processValue($value, $isRoot);
if ($defId !== $id) {
return new Reference($defId, $value->getInvalidBehavior());
}
} }
return parent::processValue($value); $defId = $this->getDefinitionId($id = (string) $value, $this->container);
return $defId !== $id ? new Reference($defId, $value->getInvalidBehavior()) : $value;
} }
private function getDefinitionId(string $id, ContainerBuilder $container): string private function getDefinitionId(string $id, ContainerBuilder $container): string
{ {
if (!$container->hasAlias($id)) {
return $id;
}
$alias = $container->getAlias($id);
if ($alias->isDeprecated()) {
@trigger_error(sprintf('%s. It is being referenced by the "%s" %s.', rtrim($alias->getDeprecationMessage($id), '. '), $this->currentId, $container->hasDefinition($this->currentId) ? 'service' : 'alias'), E_USER_DEPRECATED);
}
$seen = []; $seen = [];
while ($container->hasAlias($id)) { do {
if (isset($seen[$id])) { if (isset($seen[$id])) {
throw new ServiceCircularReferenceException($id, array_merge(array_keys($seen), [$id])); throw new ServiceCircularReferenceException($id, array_merge(array_keys($seen), [$id]));
} }
$seen[$id] = true; $seen[$id] = true;
$alias = $container->getAlias($id); $id = (string) $container->getAlias($id);
} while ($container->hasAlias($id));
if ($alias->isDeprecated()) {
@trigger_error($alias->getDeprecationMessage($id), E_USER_DEPRECATED);
}
$id = (string) $alias;
}
return $id; return $id;
} }

View File

@ -47,7 +47,7 @@ class Definition
protected $arguments = []; protected $arguments = [];
private static $defaultDeprecationTemplate = 'The "%service_id%" service is deprecated. You should stop using it, as it will soon be removed.'; private static $defaultDeprecationTemplate = 'The "%service_id%" service is deprecated. You should stop using it, as it will be removed in the future.';
/** /**
* @internal * @internal

View File

@ -52,7 +52,7 @@ class AliasTest extends TestCase
public function testCanDeprecateAnAlias() public function testCanDeprecateAnAlias()
{ {
$alias = new Alias('foo', false); $alias = new Alias('foo', false);
$alias->setDeprecated(true, 'The %service_id% service is deprecated.'); $alias->setDeprecated(true, 'The %alias_id% service is deprecated.');
$this->assertTrue($alias->isDeprecated()); $this->assertTrue($alias->isDeprecated());
} }
@ -62,14 +62,14 @@ class AliasTest extends TestCase
$alias = new Alias('foo', false); $alias = new Alias('foo', false);
$alias->setDeprecated(); $alias->setDeprecated();
$expectedMessage = 'The "foo" service alias is deprecated. You should stop using it, as it will soon be removed.'; $expectedMessage = 'The "foo" service alias is deprecated. You should stop using it, as it will be removed in the future.';
$this->assertEquals($expectedMessage, $alias->getDeprecationMessage('foo')); $this->assertEquals($expectedMessage, $alias->getDeprecationMessage('foo'));
} }
public function testReturnsCorrectDeprecationMessage() public function testReturnsCorrectDeprecationMessage()
{ {
$alias = new Alias('foo', false); $alias = new Alias('foo', false);
$alias->setDeprecated(true, 'The "%service_id%" is deprecated.'); $alias->setDeprecated(true, 'The "%alias_id%" is deprecated.');
$expectedMessage = 'The "foo" is deprecated.'; $expectedMessage = 'The "foo" is deprecated.';
$this->assertEquals($expectedMessage, $alias->getDeprecationMessage('foo')); $this->assertEquals($expectedMessage, $alias->getDeprecationMessage('foo'));
@ -101,10 +101,10 @@ class AliasTest extends TestCase
public function invalidDeprecationMessageProvider() public function invalidDeprecationMessageProvider()
{ {
return [ return [
"With \rs" => ["invalid \r message %service_id%"], "With \rs" => ["invalid \r message %alias_id%"],
"With \ns" => ["invalid \n message %service_id%"], "With \ns" => ["invalid \n message %alias_id%"],
'With */s' => ['invalid */ message %service_id%'], 'With */s' => ['invalid */ message %alias_id%'],
'message not containing required %service_id% variable' => ['this is deprecated'], 'message not containing required %alias_id% variable' => ['this is deprecated'],
]; ];
} }
} }

View File

@ -85,7 +85,7 @@ class ResolveReferencesToAliasesPassTest extends TestCase
/** /**
* @group legacy * @group legacy
* @expectedDeprecation The "deprecated_foo_alias" service alias is deprecated. You should stop using it, as it will soon be removed. * @expectedDeprecation The "deprecated_foo_alias" service alias is deprecated. You should stop using it, as it will be removed in the future. It is being referenced by the "alias" alias.
*/ */
public function testDeprecationNoticeWhenReferencedByAlias() public function testDeprecationNoticeWhenReferencedByAlias()
{ {
@ -105,7 +105,7 @@ class ResolveReferencesToAliasesPassTest extends TestCase
/** /**
* @group legacy * @group legacy
* @expectedDeprecation The "foo_aliased" service alias is deprecated. You should stop using it, as it will soon be removed. * @expectedDeprecation The "foo_aliased" service alias is deprecated. You should stop using it, as it will be removed in the future. It is being referenced by the "definition" service.
*/ */
public function testDeprecationNoticeWhenReferencedByDefinition() public function testDeprecationNoticeWhenReferencedByDefinition()
{ {

View File

@ -88,7 +88,7 @@ class ContainerBuilderTest extends TestCase
/** /**
* @group legacy * @group legacy
* @expectedDeprecation The "deprecated_foo" service is deprecated. You should stop using it, as it will soon be removed. * @expectedDeprecation The "deprecated_foo" service is deprecated. You should stop using it, as it will be removed in the future.
*/ */
public function testCreateDeprecatedService() public function testCreateDeprecatedService()
{ {
@ -261,7 +261,7 @@ class ContainerBuilderTest extends TestCase
/** /**
* @group legacy * @group legacy
* @expectedDeprecation The "foobar" service alias is deprecated. You should stop using it, as it will soon be removed. * @expectedDeprecation The "foobar" service alias is deprecated. You should stop using it, as it will be removed in the future.
*/ */
public function testDeprecatedAlias() public function testDeprecatedAlias()
{ {

View File

@ -164,7 +164,7 @@ class DefinitionTest extends TestCase
$this->assertFalse($def->isDeprecated(), '->isDeprecated() returns false by default'); $this->assertFalse($def->isDeprecated(), '->isDeprecated() returns false by default');
$this->assertSame($def, $def->setDeprecated(true), '->setDeprecated() implements a fluent interface'); $this->assertSame($def, $def->setDeprecated(true), '->setDeprecated() implements a fluent interface');
$this->assertTrue($def->isDeprecated(), '->isDeprecated() returns true if the instance should not be used anymore.'); $this->assertTrue($def->isDeprecated(), '->isDeprecated() returns true if the instance should not be used anymore.');
$this->assertSame('The "deprecated_service" service is deprecated. You should stop using it, as it will soon be removed.', $def->getDeprecationMessage('deprecated_service'), '->getDeprecationMessage() should return a formatted message template'); $this->assertSame('The "deprecated_service" service is deprecated. You should stop using it, as it will be removed in the future.', $def->getDeprecationMessage('deprecated_service'), '->getDeprecationMessage() should return a formatted message template');
} }
/** /**

View File

@ -327,7 +327,7 @@ class PhpDumperTest extends TestCase
/** /**
* @group legacy * @group legacy
* @expectedDeprecation The "alias_for_foo_deprecated" service alias is deprecated. You should stop using it, as it will soon be removed. * @expectedDeprecation The "alias_for_foo_deprecated" service alias is deprecated. You should stop using it, as it will be removed in the future.
*/ */
public function testAliasesDeprecation() public function testAliasesDeprecation()
{ {
@ -1067,7 +1067,7 @@ class PhpDumperTest extends TestCase
* This test checks the trigger of a deprecation note and should not be removed in major releases. * This test checks the trigger of a deprecation note and should not be removed in major releases.
* *
* @group legacy * @group legacy
* @expectedDeprecation The "foo" service is deprecated. You should stop using it, as it will soon be removed. * @expectedDeprecation The "foo" service is deprecated. You should stop using it, as it will be removed in the future.
*/ */
public function testPrivateServiceTriggersDeprecation() public function testPrivateServiceTriggersDeprecation()
{ {

View File

@ -66,7 +66,7 @@ class Symfony_DI_PhpDumper_Test_Aliases_Deprecation extends Container
*/ */
protected function getAliasForFooDeprecatedService() protected function getAliasForFooDeprecatedService()
{ {
@trigger_error('The "alias_for_foo_deprecated" service alias is deprecated. You should stop using it, as it will soon be removed.', E_USER_DEPRECATED); @trigger_error('The "alias_for_foo_deprecated" service alias is deprecated. You should stop using it, as it will be removed in the future.', E_USER_DEPRECATED);
return $this->get('foo'); return $this->get('foo');
} }

View File

@ -124,7 +124,7 @@ use Symfony\Component\DependencyInjection\Exception\RuntimeException;
// This file has been auto-generated by the Symfony Dependency Injection Component for internal use. // This file has been auto-generated by the Symfony Dependency Injection Component for internal use.
// Returns the public 'deprecated_service' shared service. // Returns the public 'deprecated_service' shared service.
@trigger_error('The "deprecated_service" service is deprecated. You should stop using it, as it will soon be removed.', E_USER_DEPRECATED); @trigger_error('The "deprecated_service" service is deprecated. You should stop using it, as it will be removed in the future.', E_USER_DEPRECATED);
return $this->services['deprecated_service'] = new \stdClass(); return $this->services['deprecated_service'] = new \stdClass();
@ -156,7 +156,7 @@ use Symfony\Component\DependencyInjection\Exception\RuntimeException;
// This file has been auto-generated by the Symfony Dependency Injection Component for internal use. // This file has been auto-generated by the Symfony Dependency Injection Component for internal use.
// Returns the private 'factory_simple' shared service. // Returns the private 'factory_simple' shared service.
@trigger_error('The "factory_simple" service is deprecated. You should stop using it, as it will soon be removed.', E_USER_DEPRECATED); @trigger_error('The "factory_simple" service is deprecated. You should stop using it, as it will be removed in the future.', E_USER_DEPRECATED);
return new \SimpleFactoryClass('foo'); return new \SimpleFactoryClass('foo');

View File

@ -206,11 +206,11 @@ class ProjectServiceContainer extends Container
* *
* @return \stdClass * @return \stdClass
* *
* @deprecated The "deprecated_service" service is deprecated. You should stop using it, as it will soon be removed. * @deprecated The "deprecated_service" service is deprecated. You should stop using it, as it will be removed in the future.
*/ */
protected function getDeprecatedServiceService() protected function getDeprecatedServiceService()
{ {
@trigger_error('The "deprecated_service" service is deprecated. You should stop using it, as it will soon be removed.', E_USER_DEPRECATED); @trigger_error('The "deprecated_service" service is deprecated. You should stop using it, as it will be removed in the future.', E_USER_DEPRECATED);
return $this->services['deprecated_service'] = new \stdClass(); return $this->services['deprecated_service'] = new \stdClass();
} }
@ -400,11 +400,11 @@ class ProjectServiceContainer extends Container
* *
* @return \SimpleFactoryClass * @return \SimpleFactoryClass
* *
* @deprecated The "factory_simple" service is deprecated. You should stop using it, as it will soon be removed. * @deprecated The "factory_simple" service is deprecated. You should stop using it, as it will be removed in the future.
*/ */
protected function getFactorySimpleService() protected function getFactorySimpleService()
{ {
@trigger_error('The "factory_simple" service is deprecated. You should stop using it, as it will soon be removed.', E_USER_DEPRECATED); @trigger_error('The "factory_simple" service is deprecated. You should stop using it, as it will be removed in the future.', E_USER_DEPRECATED);
return new \SimpleFactoryClass('foo'); return new \SimpleFactoryClass('foo');
} }

View File

@ -206,11 +206,11 @@ class Symfony_DI_PhpDumper_Errored_Definition extends Container
* *
* @return \stdClass * @return \stdClass
* *
* @deprecated The "deprecated_service" service is deprecated. You should stop using it, as it will soon be removed. * @deprecated The "deprecated_service" service is deprecated. You should stop using it, as it will be removed in the future.
*/ */
protected function getDeprecatedServiceService() protected function getDeprecatedServiceService()
{ {
@trigger_error('The "deprecated_service" service is deprecated. You should stop using it, as it will soon be removed.', E_USER_DEPRECATED); @trigger_error('The "deprecated_service" service is deprecated. You should stop using it, as it will be removed in the future.', E_USER_DEPRECATED);
return $this->services['deprecated_service'] = new \stdClass(); return $this->services['deprecated_service'] = new \stdClass();
} }
@ -400,11 +400,11 @@ class Symfony_DI_PhpDumper_Errored_Definition extends Container
* *
* @return \SimpleFactoryClass * @return \SimpleFactoryClass
* *
* @deprecated The "factory_simple" service is deprecated. You should stop using it, as it will soon be removed. * @deprecated The "factory_simple" service is deprecated. You should stop using it, as it will be removed in the future.
*/ */
protected function getFactorySimpleService() protected function getFactorySimpleService()
{ {
@trigger_error('The "factory_simple" service is deprecated. You should stop using it, as it will soon be removed.', E_USER_DEPRECATED); @trigger_error('The "factory_simple" service is deprecated. You should stop using it, as it will be removed in the future.', E_USER_DEPRECATED);
return new \SimpleFactoryClass('foo'); return new \SimpleFactoryClass('foo');
} }

View File

@ -7,7 +7,7 @@
<deprecated /> <deprecated />
</service> </service>
<service id="alias_for_foobar" alias="foobar"> <service id="alias_for_foobar" alias="foobar">
<deprecated>The "%service_id%" service alias is deprecated.</deprecated> <deprecated>The "%alias_id%" service alias is deprecated.</deprecated>
</service> </service>
</services> </services>
</container> </container>

View File

@ -97,7 +97,7 @@
<service id="decorator_service" class="stdClass" public="true" decorates="decorated"/> <service id="decorator_service" class="stdClass" public="true" decorates="decorated"/>
<service id="decorator_service_with_name" class="stdClass" public="true" decorates="decorated" decoration-inner-name="decorated.pif-pouf"/> <service id="decorator_service_with_name" class="stdClass" public="true" decorates="decorated" decoration-inner-name="decorated.pif-pouf"/>
<service id="deprecated_service" class="stdClass" public="true"> <service id="deprecated_service" class="stdClass" public="true">
<deprecated>The "%service_id%" service is deprecated. You should stop using it, as it will soon be removed.</deprecated> <deprecated>The "%service_id%" service is deprecated. You should stop using it, as it will be removed in the future.</deprecated>
</service> </service>
<service id="new_factory" class="FactoryClass" public="false"> <service id="new_factory" class="FactoryClass" public="false">
<property name="foo">bar</property> <property name="foo">bar</property>
@ -114,7 +114,7 @@
</service> </service>
<service id="factory_simple" class="SimpleFactoryClass" public="false"> <service id="factory_simple" class="SimpleFactoryClass" public="false">
<argument>foo</argument> <argument>foo</argument>
<deprecated>The "%service_id%" service is deprecated. You should stop using it, as it will soon be removed.</deprecated> <deprecated>The "%service_id%" service is deprecated. You should stop using it, as it will be removed in the future.</deprecated>
</service> </service>
<service id="factory_service_simple" class="Bar" public="true"> <service id="factory_service_simple" class="Bar" public="true">
<factory service="factory_simple" method="getInstance"/> <factory service="factory_simple" method="getInstance"/>

View File

@ -1,4 +1,4 @@
services: services:
alias_for_foobar: alias_for_foobar:
alias: foobar alias: foobar
deprecated: The "%service_id%" service alias is deprecated. deprecated: The "%alias_id%" service alias is deprecated.

View File

@ -103,7 +103,7 @@ services:
public: true public: true
deprecated_service: deprecated_service:
class: stdClass class: stdClass
deprecated: The "%service_id%" service is deprecated. You should stop using it, as it will soon be removed. deprecated: The "%service_id%" service is deprecated. You should stop using it, as it will be removed in the future.
public: true public: true
new_factory: new_factory:
class: FactoryClass class: FactoryClass
@ -124,7 +124,7 @@ services:
public: true public: true
factory_simple: factory_simple:
class: SimpleFactoryClass class: SimpleFactoryClass
deprecated: The "%service_id%" service is deprecated. You should stop using it, as it will soon be removed. deprecated: The "%service_id%" service is deprecated. You should stop using it, as it will be removed in the future.
public: false public: false
arguments: ['foo'] arguments: ['foo']
factory_service_simple: factory_service_simple:

View File

@ -343,7 +343,7 @@ class XmlFileLoaderTest extends TestCase
$loader->load('services_deprecated.xml'); $loader->load('services_deprecated.xml');
$this->assertTrue($container->getDefinition('foo')->isDeprecated()); $this->assertTrue($container->getDefinition('foo')->isDeprecated());
$message = 'The "foo" service is deprecated. You should stop using it, as it will soon be removed.'; $message = 'The "foo" service is deprecated. You should stop using it, as it will be removed in the future.';
$this->assertSame($message, $container->getDefinition('foo')->getDeprecationMessage('foo')); $this->assertSame($message, $container->getDefinition('foo')->getDeprecationMessage('foo'));
$this->assertTrue($container->getDefinition('bar')->isDeprecated()); $this->assertTrue($container->getDefinition('bar')->isDeprecated());
@ -358,7 +358,7 @@ class XmlFileLoaderTest extends TestCase
$loader->load('deprecated_alias_definitions.xml'); $loader->load('deprecated_alias_definitions.xml');
$this->assertTrue($container->getAlias('alias_for_foo')->isDeprecated()); $this->assertTrue($container->getAlias('alias_for_foo')->isDeprecated());
$message = 'The "alias_for_foo" service alias is deprecated. You should stop using it, as it will soon be removed.'; $message = 'The "alias_for_foo" service alias is deprecated. You should stop using it, as it will be removed in the future.';
$this->assertSame($message, $container->getAlias('alias_for_foo')->getDeprecationMessage('alias_for_foo')); $this->assertSame($message, $container->getAlias('alias_for_foo')->getDeprecationMessage('alias_for_foo'));
$this->assertTrue($container->getAlias('alias_for_foobar')->isDeprecated()); $this->assertTrue($container->getAlias('alias_for_foobar')->isDeprecated());