-
-
Notifications
You must be signed in to change notification settings - Fork 9.6k
[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
Conversation
public function setSquashedService($id, $renamedId = null) | ||
{ | ||
if ($renamedId && $id == $renamedId) { | ||
throw new \LogicException(sprintf('A squashed service must have a unique name ("%s")', $id)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This exception message looks weird to me
I like this implementation as it does not even require registering our own compiler pass. |
Before implemeting the missing features (loaders/dumpers), I'd like to settle on a name for this feature. Is |
@fabpot what about |
|
@fabpot |
Have you considered a generic decorator compiler pass? Something like a generic version of this. Could possibly even be extended with priorities. The basic premise is that adding tags (metadata) is much more generic and requires less adjustments to loaders/dumpers/schemata than adding a new service attribute. I agree that if the intent of this feature is decoration, then that term should be used. |
@iGrow I'm not a big fan of using tags for built-in features. In fact (I might be wrong as I haven't checked), I think we don't have any tags in the component. |
@igorw This is how I suggested to implement it in the original issue, by simply making the 3 ids configurable in my original code @fabpot we indeed don't have any tag defined in the DI component itself. |
Hum, |
@Taluu At the end of this, the the goal of this feature is not to replace a service totally (which can already be done currently) but to apply a decorator on it. |
How about |
renamed |
does |
what about |
It seems like all of these suggestions are of something the service definition should do but it seems like all the other attributes (name, class etc) are about describing what the definition is that's why i like say decorates over decorate. |
would it be possible for a (non shared) service to decorate many (non shared) services ? |
@docteurklein I don't understand what you mean when saying "decorate many services" ? |
What about This term is used in AngularJS when replacing a view element with something else and getting a copy/reference to the replaced element to be able to insert it inside the replacing element. |
@stof here's an example of the resulting object graph i'd like to have: $firstVoter = new FirstVoter;
$secondVoter = new SecondVoter;
$registry->addVoter(new LoggerVoter($firstVoter));
$registry->addVoter(new LoggerVoter($secondVoter)); The I hope what I say is comprehensible :) |
@docteurklein You will need 2 service definitions (one per LoggerVoter) as you have 2 services (the can use the definition inheritance to share common stuff though). |
@docteurklein you are doing the config in the opposite way in your case, which makes it much less useful as a sevrice needs to know who is decorating it (and it limits it to doing it once). this feature is about making 1 service declare that it will overwirte another service using composition (and so we want to be able to access the previous definition, not just overwriting it totally by reusing the same id). This approach is much more flexible: the I18nRoutingBundle will be able to decorate the core router without requiring changing the core service, and applying both the i18n decorator and another decorator (doing something else) would work without having to make one bundle aware of the other one. |
|
||
list ($decorated, $renamedId) = $decorated; | ||
if (!$renamedId) { | ||
$renamedId = $id.'.parent'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should this be .decorator
instead of parent?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is not the decorator. It is the decorated service.
I agree that .parent
may not be the best choice when using composition through. .inner
may be easier to understand
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
or .overridden
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@cordoval It would be weird to use be_simple.i18n_router.overriden
to store the router service being decorated by be_simple.i18n_router
. .overridden
would be even worse than .parent
in term of understanding when looking at the bundle services.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
.wrapped
then?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
renamed to .inner
.
…ing a reference to the old one
closing in favor of #10600 |
…service by keeping a reference to the old one (romainneutron) This PR was merged into the 2.5-dev branch. Discussion ---------- [DependencyInjection] added a simple way to replace a service by keeping a reference to the old one | Q | A | ------------- | --- | Bug fix? | no | New feature? | yes | BC breaks? | no | Deprecations? | no | Tests pass? | yes | Fixed tickets | #5920 | License | MIT | Doc PR | symfony/symfony-docs#3745 This PR replaces #9003. Here's the todo list: - [x] add a cookbook entry for this new feature - [x] add support in all loaders/dumpers - [x] add unit tests - [x] see if there are use cases in Symfony that would benefit from this new feature - [x] find the best name for this feature I've implemented YAML and XML Loader / Dumper. From what I see, PhpDumper, PhpLoader, IniLoader, GraphvizDumper do not require an update, am I wrong? Commits ------- 140f807 [DependencyInjection] Update dumpers and loaders, add unit tests 1eb1f4d [DependencyInjection] added a simple way to replace a service by keeping a reference to the old one
Bad practice and error prone: also see symfony/symfony#11881 and symfony/symfony#9003
Bad practice and error prone: also see symfony/symfony#11881 and symfony/symfony#9003
TODO:
When overriding an existing definition, the old service is lost:
Most of the time, that's exactly what you want to do, but sometimes, you might want to decorate the old one instead. In this case, the old service should be kept around to be able to reference it in the new one. This PR implements this new feature:
Here is what's going on here: the
setDecoratedService()
method tells the container that thefoo1
service should replace thefoo
service. By convention, the oldfoo
service is going to be renamedfoo1.parent
, so I can inject it into my new service.You can change the parent service name if you want to:
Also, several service can decorate a single one and everything should work fine:
Note that this is different from the existing
parent
definition attribute, where a service inherit/extends another one (as the two services co-exist independently).In XML, that would work like this: