Skip to content

[DependencyInjection] added a simple way to replace a service by keeping a reference to the old one #9003

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

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
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
5 changes: 5 additions & 0 deletions src/Symfony/Component/DependencyInjection/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
CHANGELOG
=========

2.5.0
-----

* added DecoratorServicePass and a way to override a service definition (Definition::setDecoratedService())

2.4.0
-----

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
<?php

/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Symfony\Component\DependencyInjection\Compiler;

use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Alias;

/**
* Overwrites a service but keeps the overridden one.
*
* @author Christophe Coevoet <stof@notk.org>
* @author Fabien Potencier <fabien@symfony.com>
*/
class DecoratorServicePass implements CompilerPassInterface
{
public function process(ContainerBuilder $container)
{
foreach ($container->getDefinitions() as $id => $definition) {
if (!$decorated = $definition->getDecoratedService()) {
continue;
}

list ($decorated, $renamedId) = $decorated;
if (!$renamedId) {
$renamedId = $id.'.inner';
}

// we create a new alias/service for the service we are replacing
// to be able to reference it in the new one
if ($container->hasAlias($decorated)) {
$alias = $container->getAlias($decorated);
$public = $alias->isPublic();
$container->setAlias($renamedId, new Alias((string) $alias, false));
} else {
$definition = $container->getDefinition($decorated);
$public = $definition->isPublic();
$definition->setPublic(false);
$container->setDefinition($renamedId, $definition);
}

$container->setAlias($decorated, new Alias($id, $public));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ public function __construct()

$this->optimizationPasses = array(
new ResolveDefinitionTemplatesPass(),
new DecoratorServicePass(),
new ResolveParameterPlaceHoldersPass(),
new CheckDefinitionValidityPass(),
new ResolveReferencesToAliasesPass(),
Expand Down
26 changes: 26 additions & 0 deletions src/Symfony/Component/DependencyInjection/Definition.php
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ class Definition
private $abstract;
private $synchronized;
private $lazy;
private $decoratedService;

protected $arguments;

Expand All @@ -64,6 +65,31 @@ public function __construct($class = null, array $arguments = array())
$this->properties = array();
}

/**
* Sets the service that this service is decorating.
*
* @param string $id The decorated service id
* @param string $renamedId The new decorated service id
*/
public function setDecoratedService($id, $renamedId = null)
{
if ($renamedId && $id == $renamedId) {
throw new \LogicException(sprintf('The decorated service parent name for "%s" must be different than the service name itself.', $id));
}

$this->decoratedService = array($id, $renamedId);
}

/**
* Gets the service that decorates this service.
*
* @return array An array composed of the decorated service id and the new id for it
*/
public function getDecoratedService()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you should add some phpdoc about the return type

{
return $this->decoratedService;
}

/**
* Sets the name of the class that acts as a factory using the factory method,
* which will be invoked statically.
Expand Down