-
-
Notifications
You must be signed in to change notification settings - Fork 9.6k
Making tags under _defaults always apply #22530
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
@@ -363,7 +363,6 @@ private function parseDefinition($id, $service, $file, array $defaults) | |||
if (null !== $inheritTag) { | |||
$definition->setInheritTags($inheritTag); | |||
} | |||
$defaults = array(); |
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 is below the condition : elseif (isset($service['parent'])) {
.
Emptying $defaults
meant that services with a parent did not have _defaults
applied. I think the intention was to not double-apply defaults (since the parent will already have them applied). Removing this causes double tags (as I described in my description). BUT, I think this was a bug. What if I had a child in this file, but my parent in another file? In that case, the neither the child nor the parent would have the _defaults
applied.
d74da57
to
e0bd1ca
Compare
As discussed together, I think this is the right thing to do. |
👍 |
👍 also |
👍 for removing |
👍 for removing it too |
Linked issue should be #22497 I suppose 😉 |
Boom!
@curry684 you're right! Updated with the issue number - your issue is what pushed me to corner Fabien and Nicolas about this ;). |
There are a few other issues still with this PR - specifically that while Status: Needs Work |
this looks weird to me, as a common use case is to tag event subscribers or twig extensions for instance. |
Parent/child definitions, mixed with defaults, instanceof or autoconfig create conflicting expectations. They do not play well with each other. |
See #22563: Almost all of the complexity of handling
Yep, I agree. It's very complex. I just added some test cases to #22563, which include a few I highlighted as potential problems (like this situation). |
…defaults for ChildDefinition (weaverryan) This PR was merged into the 3.3-dev branch. Discussion ---------- Not allowing autoconfigure, instanceofConditionals or defaults for ChildDefinition | Q | A | ------------- | --- | Branch? | master | Bug fix? | yes (removing risky behavior) | New feature? | no | BC breaks? | no | Deprecations? | no | Tests pass? | yes | Fixed tickets | see #22530 | License | MIT | Doc PR | n/a This PR *prohibits* using `autoconfigure`, `_instanceof` and `_defaults` for ChildDefinition. Additionally, I added many "integration" test cases: we need to test and prove all edge cases. These are in the `integration/` directory: the `main.yml` file is parsed and compared to `expected.yml`. Both are in YAML to ease comparing the before/after. We need to check these out and make sure they're right and we're not missing anything else. This PR removes MANY of the "wtf" cases, but there are still 4 that I know of... and of course they all deal with parent-child stuff :). A) [MAJOR] [autoconfigure_parent_child_tags](https://github.com/symfony/symfony/pull/22563/files#diff-fd6cf15470c5abd40156e4e7dc4e7f6d) `instanceof` tags from autoconfigure are NEVER applied to the child (you can't set `autoconfigure` directly on a Child, but you still can set it on a parent and inherit it... sneaky). We could throw an Exception I suppose to prevent this `autoconfigure` from cascading from parent to child... but it's tricky due to `instanceof`. B( [MAJOR] [instanceof_parent_child](https://github.com/symfony/symfony/pull/22563/files#diff-14666e9a25322d44b3c2c583b6814dc2) `instanceof` tags that are applied to the parent, are not applied to the child. Again, you can't set `instanceof` directly on a Child, but you *can* set it on a parent, and have that cascade to the child. Like before, we could maybe throw an exception to prevent this. C) [MINOR] ([autoconfigure_child_not_applied](https://github.com/symfony/symfony/pull/22563/files#diff-3372a1dcaf3af30d14a7d0a6c8bfa988)) automatic `instanceof` will not be applied to the child when the parent class has a different (non-instanceof-ed) class. If we could throw an exception for (A), then it would cover this too. D) `_tags` from defaults are never used (unless you have inherit_tags) - fixed in #22530 A, B & C are effectively caused by there being a "sneaky" way to re-enable `autoconfigure` and `instanceof` for ChildDefinition... which opens up wtf cases. ## Wait, why not support `_defaults`, `autoconfigure` and `_instanceof` for child definitions? 1 big reason: reduction of wtf moments where we arbitrarily decide override logic. PLUS, since `_defaults`, `instanceof` and `autoconfigure` *are* applied to parent definitions, in practice (other than tags), this makes no difference: the configuration will still pass from parent down to child. Also, using parent-child definitions is already an edge case, and this *simply* prevents *just* those services from using the new features. ## Longer reasons why The reason behind this is that parent-child definitions are a different mechanism for "inheritance" than `_instanceof` and `_defaults`... creating some edge cases when trying to figure out which settings "win". For example: ```yml # file1.yml services: _defaults: public: false ChildService: parent: parent_service # file2.yml services: _defaults: public: true ParentService: ~ ``` Is `ChildDefinition` `public: true` (so the parent overrides the child, even though it only came from _defaults) or `public: false` (where the child wins... even though it was only set from its _defaults)? Or, if ParentService is explicitly set to `public: true`, should that override the `public: false` of ChildService (which it got from its `_defaults`)? On one hand, ParentService is being explicitly set. On the other hand, ChildService is explicitly in a file settings `_defaults` `public: false` There's no correct answer. There are also problems with `_instanceof`. The importance goes: > defaults < instanceof < service definition But how do parent-child relationships fit into that? If a child has public: false from an _instanceof, but the parent explicitly sets public: true, which wins? Should we assume the parent definition wins because it's explicitly set? Or would the _instanceof win, because that's being explicitly applied to the child definition's class by an _instanceof that lives in the same file as that class (whereas the parent definition may live in a different file). Because of this, @nicolas-grekas and I (we also talked a bit to Fabien) decided that the complexity was growing too much. The solution is to not allow any of these new feature to be used by ChildDefinition objects. In other words, when you want some sort of "inheritance" for your service, you should *either* giving your service a parent *or* using defaults and instanceof. And instead of silently not applying defaults and instanceof to child definitions, I think it's better to scream that it's not supported. Commits ------- a943b96 Not allowing autoconfigure, instanceofConditionals or defaults for ChildDefinition
Rebase unlocked :) |
50ad8b4
to
3f5014a
Compare
@@ -16,8 +16,7 @@ services: | |||
# these 2 are from instanceof | |||
- { name: foo_tag, tag_option: from_instanceof } | |||
- { name: bar_tag } | |||
# the tag from defaults do NOT cascade (but see #22530) | |||
# - { name: from_defaults } | |||
- { name: from_defaults } |
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 is the key fix for this PR: the from_defaults
tag is now inherited:
Line 6 in 7010a7a
tags: [from_defaults] |
Rebased! This PR is now simple: |
3f5014a
to
2b087b8
Compare
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.
👍 last PR for 3.3 :)
…tirely Now that inherit_tags has been removed, 3.3 has the same functionality as 3.2: tags are *never* cascaded from parent to child (but you tags do inherit from defaults to a service and instanceof to a service).
2b087b8
to
037a782
Compare
Thank you @weaverryan. |
This PR was merged into the 3.3-dev branch. Discussion ---------- Making tags under _defaults always apply | Q | A | ------------- | --- | Branch? | master | Bug fix? | no | New feature? | no | BC breaks? | no | Deprecations? | no | Tests pass? | yes | Fixed tickets | #22497 | License | MIT | Doc PR | n/a Obviously, things under `_defaults` are applied to all services in that file. However, tags was an exception: it was *not* applied unless you have `inherit_tags`. The correct behavior is subjective, but after talking about it today, we (mostly) decided that tags *should* always apply. This does exactly that. One side-effect (explained in the commit message) is that if you have a parent and child service both in the same file, the tag from `_defaults` is applied twice. I think that makes sense, and at some point, we can't protect the users from their own configuration :). This kind of "weird" behavior is likely not a problem, as compiler passes now handle multiple tags well AND it only affects a case where the user has added tags to `_defaults` *and* is using parent-child definitions. That's quite a strange mixture of conditions :). Cheers! Commits ------- 037a782 Making tags under _defaults always apply and removing inherit_tags entirely
Obviously, things under
_defaults
are applied to all services in that file. However, tags was an exception: it was not applied unless you haveinherit_tags
. The correct behavior is subjective, but after talking about it today, we (mostly) decided that tags should always apply. This does exactly that.One side-effect (explained in the commit message) is that if you have a parent and child service both in the same file, the tag from
_defaults
is applied twice. I think that makes sense, and at some point, we can't protect the users from their own configuration :). This kind of "weird" behavior is likely not a problem, as compiler passes now handle multiple tags well AND it only affects a case where the user has added tags to_defaults
and is using parent-child definitions. That's quite a strange mixture of conditions :).Cheers!