bug #29995 [DI] add id of referencing service when a deprecated alias is found (nicolas-grekas)

This PR was merged into the 4.3-dev branch.

Discussion
----------

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

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

Improves #29968 a bit for DX.

Commits
-------

b124fb7271 [DI] add id of referencing service when a deprecated alias is found
This commit is contained in:
Nicolas Grekas 2019-01-28 17:42:45 +01:00
commit dca09750ed
18 changed files with 58 additions and 55 deletions

View File

@ -21,7 +21,7 @@ class Alias
private $deprecated;
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)
{
@ -103,8 +103,8 @@ class Alias
throw new InvalidArgumentException('Invalid characters found in deprecation template.');
}
if (false === strpos($template, '%service_id%')) {
throw new InvalidArgumentException('The deprecation template must contain the "%service_id%" placeholder.');
if (false === strpos($template, '%alias_id%')) {
throw new InvalidArgumentException('The deprecation template must contain the "%alias_id%" placeholder.');
}
$this->deprecationTemplate = $template;
@ -122,7 +122,7 @@ class Alias
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)
{
if (!$value instanceof Reference) {
return parent::processValue($value);
return parent::processValue($value, $isRoot);
}
if (ContainerBuilder::IGNORE_ON_UNINITIALIZED_REFERENCE !== $value->getInvalidBehavior()) {

View File

@ -31,6 +31,7 @@ class ResolveReferencesToAliasesPass extends AbstractRecursivePass
foreach ($container->getAliases() as $id => $alias) {
$aliasId = (string) $alias;
$this->currentId = $id;
if ($aliasId !== $defId = $this->getDefinitionId($aliasId, $container)) {
$container->setAlias($id, $defId)->setPublic($alias->isPublic())->setPrivate($alias->isPrivate());
@ -43,34 +44,36 @@ class ResolveReferencesToAliasesPass extends AbstractRecursivePass
*/
protected function processValue($value, $isRoot = false)
{
if ($value instanceof Reference) {
$defId = $this->getDefinitionId($id = (string) $value, $this->container);
if ($defId !== $id) {
return new Reference($defId, $value->getInvalidBehavior());
}
if (!$value instanceof Reference) {
return parent::processValue($value, $isRoot);
}
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
{
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 = [];
while ($container->hasAlias($id)) {
do {
if (isset($seen[$id])) {
throw new ServiceCircularReferenceException($id, array_merge(array_keys($seen), [$id]));
}
$seen[$id] = true;
$alias = $container->getAlias($id);
if ($alias->isDeprecated()) {
@trigger_error($alias->getDeprecationMessage($id), E_USER_DEPRECATED);
}
$id = (string) $alias;
}
$id = (string) $container->getAlias($id);
} while ($container->hasAlias($id));
return $id;
}

View File

@ -47,7 +47,7 @@ class Definition
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

View File

@ -52,7 +52,7 @@ class AliasTest extends TestCase
public function testCanDeprecateAnAlias()
{
$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());
}
@ -62,14 +62,14 @@ class AliasTest extends TestCase
$alias = new Alias('foo', false);
$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'));
}
public function testReturnsCorrectDeprecationMessage()
{
$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.';
$this->assertEquals($expectedMessage, $alias->getDeprecationMessage('foo'));
@ -101,10 +101,10 @@ class AliasTest extends TestCase
public function invalidDeprecationMessageProvider()
{
return [
"With \rs" => ["invalid \r message %service_id%"],
"With \ns" => ["invalid \n message %service_id%"],
'With */s' => ['invalid */ message %service_id%'],
'message not containing required %service_id% variable' => ['this is deprecated'],
"With \rs" => ["invalid \r message %alias_id%"],
"With \ns" => ["invalid \n message %alias_id%"],
'With */s' => ['invalid */ message %alias_id%'],
'message not containing required %alias_id% variable' => ['this is deprecated'],
];
}
}

View File

@ -85,7 +85,7 @@ class ResolveReferencesToAliasesPassTest extends TestCase
/**
* @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()
{
@ -105,7 +105,7 @@ class ResolveReferencesToAliasesPassTest extends TestCase
/**
* @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()
{

View File

@ -88,7 +88,7 @@ class ContainerBuilderTest extends TestCase
/**
* @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()
{
@ -261,7 +261,7 @@ class ContainerBuilderTest extends TestCase
/**
* @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()
{

View File

@ -164,7 +164,7 @@ class DefinitionTest extends TestCase
$this->assertFalse($def->isDeprecated(), '->isDeprecated() returns false by default');
$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->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
* @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()
{
@ -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.
*
* @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()
{

View File

@ -66,7 +66,7 @@ class Symfony_DI_PhpDumper_Test_Aliases_Deprecation extends Container
*/
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');
}

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.
// 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();
@ -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.
// 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');

View File

@ -206,11 +206,11 @@ class ProjectServiceContainer extends Container
*
* @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()
{
@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();
}
@ -400,11 +400,11 @@ class ProjectServiceContainer extends Container
*
* @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()
{
@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');
}

View File

@ -206,11 +206,11 @@ class Symfony_DI_PhpDumper_Errored_Definition extends Container
*
* @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()
{
@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();
}
@ -400,11 +400,11 @@ class Symfony_DI_PhpDumper_Errored_Definition extends Container
*
* @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()
{
@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');
}

View File

@ -7,7 +7,7 @@
<deprecated />
</service>
<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>
</services>
</container>

View File

@ -97,7 +97,7 @@
<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="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 id="new_factory" class="FactoryClass" public="false">
<property name="foo">bar</property>
@ -114,7 +114,7 @@
</service>
<service id="factory_simple" class="SimpleFactoryClass" public="false">
<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 id="factory_service_simple" class="Bar" public="true">
<factory service="factory_simple" method="getInstance"/>

View File

@ -1,4 +1,4 @@
services:
alias_for_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
deprecated_service:
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
new_factory:
class: FactoryClass
@ -124,7 +124,7 @@ services:
public: true
factory_simple:
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
arguments: ['foo']
factory_service_simple:

View File

@ -343,7 +343,7 @@ class XmlFileLoaderTest extends TestCase
$loader->load('services_deprecated.xml');
$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->assertTrue($container->getDefinition('bar')->isDeprecated());
@ -358,7 +358,7 @@ class XmlFileLoaderTest extends TestCase
$loader->load('deprecated_alias_definitions.xml');
$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->assertTrue($container->getAlias('alias_for_foobar')->isDeprecated());