Problem/Motivation
This is a follow-up to #2863986: Allow updating modules with new service dependencies.
Original motivation:
When a module update introduces a dependency on a new module and adds a service with a dependency on a service of the new module. The system breaks and the update hook can not be called because the service container can not be built.
The fb_instant_articles module facilitates setter injection in its services.yml, the arguments of these calls are not checked by the fix in #286398 breaking the system.
Proposed resolution
Take setter arguments into account when checking for dependencies.
Remaining tasks
User interface changes
API changes
Data model changes
Release notes snippet
| Comment | File | Size | Author |
|---|---|---|---|
| #29 | 3085751-9.0.x-29.patch | 7.3 KB | alexpott |
| #29 | 3085751-9.1.x-29.patch | 888 bytes | alexpott |
| #20 | diff_13-20.txt | 1.13 KB | deepak goyal |
| #20 | 3085751-20.patch | 7.3 KB | deepak goyal |
| #13 | 3085751-13.patch | 7.3 KB | longwave |
Comments
Comment #3
alexpottInteresting so this is happening because fb_instant_articles has added a new dependency on the serialization module which declares a service that's now used via setter injection. I wonder why fb_instant_articles is using setter injection - anyhow I guess we need to look through the methods as well and see if they are using any services which cannot be meet. As a quickfix fb_instant_articles could allow a null to be passed in the setter. Ie.
public function setSerializer(NormalizerInterface $serializer) {will need a change too.Another question is why is it necessary to construct this service during an update.
Comment #4
alexpottNow we have the UpdateCompilerPass this is not too tricky to deal with fortunately.
Comment #6
volkerk commentedI think this should continue only 2 levels up.
I tested this with fb_instant_articles, the setter argument checking works fine.
Comment #7
alexpott@volkerk you're totally right - great catch.
Comment #8
volkerk commented#6 is addressed, looks good to me.
Comment #9
alexpottI think this is a major bug because without this you potentially can't upgrade a contrib module which in theory could prevent you from getting a security upgrade.
Comment #10
catchLogic looks fine but this needs a re-roll.
Comment #11
rpayanmComment #13
longwave#11 was missing a file.
Comment #14
rpayanmNice :)
Comment #16
kristiaanvandeneyndeLooks good to me. Wish we could do the same for 'factory:' also :)
Comment #17
kristiaanvandeneyndeActually, here we go: #3150512: [PP-1]: Factory arguments are not checked for unmet dependencies
Comment #18
dwwMostly this looks great, and *much* needed. Thanks! Only found a few very minor documentation cleanups. Could be a follow-up, but probably easier to just fix them quickly here. Happy to re-RTBC with a new patch.
These comments are great, thanks! Really helpful to orient readers on why 2 vs. 3 in the
continuestatements.s/is if/if/
Is
@param mixed $argumentmore accurate?s/InjectedService/SetterInjection/
Comment #19
deepak goyal commentedComment #20
deepak goyal commentedHi @dww
Updated patch as you suggested please review.
Comment #21
kristiaanvandeneyndeLGTM
Comment #22
dwwYup, this is ready.
Thanks!
-Derek
Comment #23
volkerk commentedI tested this in the original scenario, the module which implements setter injection arguments can now be updated.
Code looks good as well, I think this is ready to go.
Comment #25
catchCommitted c70642a and pushed to 9.1.x. Thanks!
Comment #26
catchMoving to 9.0.x for backport consideration.
Comment #27
catchBeen hesitating on the backport here because of the new protected method. Discussed with @xjm and she suggested inlining the logic for backport, which makes sense to me.
Comment #28
alexpottThere is not really a use-case for extending this compiler pass. If you did you'd have to somehow unregistered this one - which would be very hard to do. Because it's hardcoded in \Drupal\Core\Update\UpdateServiceProvider which is hardcoded in \Drupal\Core\Update\UpdateKernel::discoverServiceProviders. I think that changing the method to be inline or even private creates an unnecessary variance which makes any future bugfixes harder. In an ideal world all of Drupal's implementations of CompilerPassInterface would be marked with @internal but given how they are used - ie. all statically hardcoded by design - that's strongly implied anyway.
Re why this should be backported: if you add a new service and change an existing service to use setter injection to get this new service in a dependent module it's just not possible for Drupal to update. This bug was discovered through a real-world use-case affected Drupal 8.9.x
Comment #29
alexpottSo here's a way to have 0 BC concerns, reflect the static nature of compiler passes and have no variance between 9.1.x and earlier branches... we can make the new method private everywhere.
The Drupal 9.1.x patch is the interdiff.
Comment #30
catchPrivate method is a good idea to me, back to RTBC.
Comment #33
catchCommitted/pushed the follow-up to 9.1.x and the new version to 9.0.x and 8.9.x, thanks!