10000 [DI] Added support for deprecating aliases by renanbr · Pull Request #29968 · symfony/symfony · GitHub
[go: up one dir, main page]

Skip to content

[DI] Added support for deprecating aliases #29968

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jan 25, 2019
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Added support for deprecating aliases (runtime+dumper)
  • Loading branch information
Renan committed Jan 25, 2019
commit 6c571adda784fa248d6871067d7e351889d40dbe
20 changes: 4 additions & 16 deletions src/Symfony/Component/DependencyInjection/Alias.php
Original file line number Diff line number Diff line change
Expand Up @@ -86,10 +86,10 @@ public function isPrivate()
}

/**
* Whether this alias is deprecated, that means it should not be called
* Whether this alias is deprecated, that means it should not be referenced
* anymore.
*
* @param bool $status Defaults to true
* @param bool $status Whether this alias is deprecated, defaults to true
* @param string $template Optional template message to use if the alias is deprecated
*
* @return $this
Expand All @@ -115,24 +115,12 @@ public function setDeprecated($status = true, $template = null)
return $this;
}

/**
* Returns whether this alias is deprecated.
*
* @return bool
*/
public function isDeprecated()
public function isDeprecated(): bool
{
return $this->deprecated;
}

/**
* Message to use if this alias is deprecated.
*
* @param string $id Service id relying on this alias
*
* @return string
*/
public function getDeprecationMessage($id)
public function getDeprecationMessage(string $id): string
{
return str_replace('%service_id%', $id, $this->deprecationTemplate ?: self::$defaultDeprecationTemplate);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ public function process(ContainerBuilder $container)

foreach ($container->getAliases() as $id => $alias) {
$aliasId = (string) $alias;

if ($aliasId !== $defId = $this->getDefinitionId($aliasId, $container)) {
$container->setAlias($id, $defId)->setPublic($alias->isPublic())->setPrivate($alias->isPrivate());
}
Expand Down Expand Up @@ -60,8 +61,15 @@ private function getDefinitionId(string $id, ContainerBuilder $container): strin
if (isset($seen[$id])) {
throw new ServiceCircularReferenceException($id, array_merge(array_keys($seen), [$id]));
}

$seen[$id] = true;
$id = (string) $container->getAlias($id);
$alias = $container->getAlias($id);

if ($alias->isDeprecated()) {
@trigger_error($alias->getDeprecationMessage($id), E_USER_DEPRECATED);
}

$id = (string) $alias;
}

return $id;
Expand Down
8000
Original file line number Diff line number Diff line change
Expand Up @@ -579,12 +579,13 @@ private function doGet($id, $invalidBehavior = ContainerInterface::EXCEPTION_ON_
}

if (!isset($this->definitions[$id]) && isset($this->aliasDefinitions[$id])) {
$aliasDefinition = $this->aliasDefinitions[$id];
if ($aliasDefinition->isDeprecated()) {
@trigger_error($aliasDefinition->getDeprecationMessage($id), E_USER_DEPRECATED);
$alias = $this->aliasDefinitions[$id];

if ($alias->isDeprecated()) {
@trigger_error($alias->getDeprecationMessage($id), E_USER_DEPRECATED);
}

return $this->doGet((string) $aliasDefinition, $invalidBehavior, $inlineServices, $isConstructorArgument);
return $this->doGet((string) $alias, $invalidBehavior, $inlineServices, $isConstructorArgument);
}

try {
Expand Down
47 changes: 47 additions & 0 deletions src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,7 @@ public function dump(array $options = [])
$code =
$this->startClass($options['class'], $baseClass, $baseClassWithNamespace).
$this->addServices($services).
$this->addDeprecatedAliases().
$this->addDefaultParametersMethod()
;

Expand Down Expand Up @@ -1115,6 +1116,15 @@ private function addMethodMap(): string
}
}

$aliases = $this->container->getAliases();
foreach ($aliases as $alias => $id) {
if (!$id->isDeprecated()) {
continue;
}
$id = (string) $id;
$code .= ' '.$this->doExport($alias).' => '.$this->doExport($this->generateMethodName($alias)).",\n";
}

return $code ? " \$this->methodMap = [\n{$code} ];\n" : '';
}

Expand All @@ -1141,6 +1151,10 @@ private function addAliases(): string
$code = " \$this->aliases = [\n";
ksort($aliases);
foreach ($aliases as $alias => $id) {
if ($id->isDeprecated()) {
continue;
}

$id = (string) $id;
while (isset($aliases[$id])) {
$id = (string) $aliases[$id];
Expand All @@ -1151,6 +1165,39 @@ private function addAliases(): string
return $code." ];\n";
}

private function addDeprecatedAliases(): string
{
$code = '';
$aliases = $this->container->getAliases();
foreach ($aliases as $alias => $definition) {
if (!$definition->isDeprecated()) {
continue;
}
$public = $definition->isPublic() ? 'public' : 'private';
$id = (string) $definition;
$methodNameAlias = $this->generateMethodName($alias);
$idExported = $this->export($id);
$messageExported = $this->export($definition->getDeprecationMessage($alias));
$code = <<<EOF

/*{$this->docStar}
* Gets the $public '$alias' alias.
*
* @return object The "$id" service.
*/
protected function {$methodNameAlias}()
{
@trigger_error($messageExported, E_USER_DEPRECATED);

return \$this->get($idExported);
}

EOF;
}

return $code;
}

private function addInlineRequires(): string
{
if (!$this->hotPathTag || !$this->inlineRequires) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -671,12 +671,11 @@ private function validateAlias(\DOMElement $alias, $file)
}
}

$allowedTags = array('deprecated');
foreach ($alias->childNodes as $child) {
if (!$child instanceof \DOMElement && self::NS !== $child->namespaceURI) {
continue;
}
if (!in_array($child->localName, $allowedTags, true)) {
if (!\in_array($child->localName, ['deprecated'], true)) {
throw new InvalidArgumentException(sprintf('Invalid child element "%s" defined for alias "%s" in "%s".', $child->localName, $alias->getAttribute('id'), $file));
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -351,7 +351,6 @@ private function parseDefinition($id, $service, $file, array $defaults)
foreach ($service as $key => $value) {
if (!\in_array($key, ['alias', 'public', 'deprecated'])) {
throw new InvalidArgumentException(sprintf('The configuration key "%s" is unsupported for the service "%s" which is defined as an alias in "%s". Allowed configuration keys for service aliases are "alias" and "public".', $key, $id, $file));
continue;
}

if ('deprecated' === $key) {
Expand Down
12 changes: 6 additions & 6 deletions src/Symfony/Component/DependencyInjection/Tests/AliasTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -100,11 +100,11 @@ public function testCannotDeprecateWithAnInvalidTemplate($message)

public function invalidDeprecationMessageProvider()
{
return array(
"With \rs" => array("invalid \r message %service_id%"),
"With \ns" => array("invalid \n message %service_id%"),
'With */s' => array('invalid */ message %service_id%'),
'message not containing required %service_id% variable' => array('this is deprecated'),
);
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'],
];
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,48 @@ public function testResolveFactory()
$this->assertSame('Factory', (string) $resolvedBarFactory[0]);
}

/**
* @group legacy
* @expectedDeprecation The "deprecated_foo_alias" service alias is deprecated. You should stop using it, as it will soon be removed.
*/
public function testDeprecationNoticeWhenReferencedByAlias()
{
$container = new ContainerBuilder();

$container->register('foo', 'stdClass');

$aliasDeprecated = new Alias('foo');
$aliasDeprecated->setDeprecated(true);
$container->setAlias('deprecated_foo_alias', $aliasDeprecated);

$alias = new Alias('deprecated_foo_alias');
$container->setAlias('alias', $alias);

$this->process($container);
}

/**
* @group legacy
* @expectedDeprecation The "foo_aliased" service alias is deprecated. You should stop using it, as it will soon be removed.
*/
public function testDeprecationNoticeWhenReferencedByDefinition()
{
$container = new ContainerBuilder();

$container->register('foo', 'stdClass');

$aliasDeprecated = new Alias('foo');
$aliasDeprecated->setDeprecated(true);
$container->setAlias('foo_aliased', $aliasDeprecated);

$container
->register('definition')
->setArguments([new Reference('foo_aliased')])
;

$this->process($container);
}

protected function process(ContainerBuilder $container)
{
$pass = new ResolveReferencesToAliasesPass();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -325,6 +325,24 @@ public function testAliases()
$this->assertSame($foo, $container->get('alias_for_alias'));
}

/**
* @group legacy
* @expectedDeprecation The "alias_for_foo_deprecated" service alias is deprecated. You should stop using it, as it will soon be removed.
*/
public function testAliasesDeprecation()
{
$container = include self::$fixturesPath.'/containers/container_alias_deprecation.php';
$container->compile();
$dumper = new PhpDumper($container);

$this->assertStringEqualsFile(self::$fixturesPath.'/php/container_alias_deprecation.php', $dumper->dump(['class' => 'Symfony_DI_PhpDumper_Test_Aliases_Deprecation']));

require self::$fixturesPath.'/php/container_alias_deprecation.php';
$container = new \Symfony_DI_PhpDumper_Test_Aliases_Deprecation();
$container->get('alias_for_foo_non_deprecated');
$container->get('alias_for_foo_deprecated');
}

public function testFrozenContainerWithoutAliases()
{
$container = new ContainerBuilder();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?php

use Symfony\Component\DependencyInjection\ContainerBuilder;

$container = new ContainerBuilder();

$container
->register('foo', 'stdClass')
->setPublic(true)
;

$container
->setAlias('alias_for_foo_deprecated', 'foo')
->setDeprecated(true)
->setPublic(true);

$container
->setAlias('alias_for_foo_non_deprecated', 'foo')
->setPublic(true);

return $container;
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
<?php

use Symfony\Component\DependencyInjection\Argument\RewindableGenerator;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\DependencyInjection\Container;
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
use Symfony\Component\DependencyInjection\Exception\LogicException;
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
use Symfony\Component\DependencyInjection\ParameterBag\FrozenParameterBag;

/**
* This class has been auto-generated
* by the Symfony Dependency Injection Component.
*
* @final since Symfony 3.3
*/
class Symfony_DI_PhpDumper_Test_Aliases_Deprecation extends Container
{
private $parameters;
private $targetDirs = [];

public function __construct()
{
$this->services = $this->privates = [];
$this->methodMap = [
'foo' => 'getFooService',
'alias_for_foo_deprecated' => 'getAliasForFooDeprecatedService',
];
$this->aliases = [
'alias_for_foo_non_deprecated' => 'foo',
];
}

public function compile()
{
throw new LogicException('You cannot compile a dumped container that was already compiled.');
}

public function isCompiled()
{
return true;
}

public function getRemovedIds()
{
return [
'Psr\\Container\\ContainerInterface' => true,
'Symfony\\Component\\DependencyInjection\\ContainerInterface' => true,
];
}

/**
* Gets the public 'foo' shared service.
*
* @return \stdClass
*/
protected function getFooService()
{
return $this->services['foo'] = new \stdClass();
}

/**
* Gets the public 'alias_for_foo_deprecated' alias.
*
* @return object The "foo" service.
*/
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);

return $this->get('foo');
}
}
0