Problem/Motivation
Follow-up from #2624770: Use more specific entity.manager services in core.services.yml that updated all core.services.yml services, this does all the remaining ones.
Proposed resolution
Per discussion with and reviews from @alexpott, the basic approach is like this:
* entity manager -> one single other service does not need an explicit @trigger_error() as entity manager can still be injected and will eventually trigger deprecated messages on its own when called.
* All other added or removed dependencies are optional, backwards compatible and do a @trigger_error()
* All services that had $this->entityManager now is the DeprecatedServicePropertyTrait in case any subclasses expect that to still exist.
Remaining tasks
User interface changes
None
API changes
All constructor changes should be backwards compatible in case they were subclassed in contrib. Even SystemManager, where the dependency is simply removed as it was unused.
Data model changes
| Comment | File | Size | Author |
|---|---|---|---|
| #35 | entity-manager-module-services-2977107-35.patch | 186.56 KB | berdir |
| #30 | entity-manager-module-services-2977107-27-interdiff.txt | 19.75 KB | berdir |
| #30 | entity-manager-module-services-2977107-30.patch | 189.82 KB | berdir |
| #27 | entity-manager-module-services-2977107-27-interdiff.txt | 29.12 KB | berdir |
| #27 | entity-manager-module-services-2977107-27.patch | 186.72 KB | berdir |
Comments
Comment #2
berdirComment #3
berdirSplitting off the modules part from the related issue. I suspect this will have some problems without core changes, lets see.
Comment #5
berdirComment #7
berdirYay, the other issue is finally in, so here's a reroll.
Comment #9
berdirLets see how much this fixes.
Comment #11
berdirBetter. Starting with the deprecations. I have to say, I do hate myself a bit for making me do this ;)
Comment #13
berdirThis conflicted with #3001309: Replace usages of UrlGeneratorTrait in non-api classes, which just removed an argument from CommentManager without deprecation or anything :-/
It's kinda frustrating that we decide per-issue how we handle constructor changes and some get in with obvious breaking changes while others need to add that convoluted @trigger_error() stuff. (See #2624770: Use more specific entity.manager services in core.services.yml , comment #148-154).
The trait + optional argument is one thing and quite useful, but those @trigger_error()'s in constructors are a pain to add, easy to get wrong and will also be more work to remove again as @alexpott correctly pointed out. It also means we have a ton of instanceof EntityManagerInterface cases still including use statements.
Also, we have too many REST tests, the amount of fails due to a wrong check in BasicAuth is pretty crazy.
Comment #15
jibranI think @Wim Leers would disagree. :)
Comment #16
alexpottI don't think this is worth it. Because EntityManagerInterface implements EntityTypeManagerInterface so if something is override and passing in the entity manager then it'll work. Once we can properly deprecate the entity manager service custom or contrib code that does this will get a deprecation message anyway so there's not a lot gained as far as I can tell.
Comment #17
alexpottIn the case where we are adding an new argument I think we need code to handle the new argument. So anything that extends this will not be broken.
Comment #18
berdir@alexpott: Definitely.
My question is whether we need a trigger_error() for it or if we can do it as a $this->entityFieldManager = $entity_field_manager ?: \Drupal::service('...'); oneliner.
Comment #19
alexpottI think we need an @trigger_error() because unlike #16 service deprecation messages won't help us.
Comment #20
berdir> I think we need an @trigger_error() because unlike #16 service deprecation messages won't help us.
Fair enough. Can we compromise on not adding explicit test coverage for all those constructors though? :)
This should cover them all.
Comment #22
berdirForgot to update the corresponding services.yml files for the argument order.
Comment #24
berdirThat fixed the last test fail.
Comment #25
berdirRerolled and updated the BC pattern.
Comment #27
berdirFixed one wrong BC check, went through the patch again and found one more case that was missing a BC check in the constructor. Also unified all changed property/argument descriptions to not use "service", I think that's not required.
Comment #29
larowlando you reckon its worth a novice followup to add a nodeStorage protected property and initialize that in the constructor and avoid this duplication? (out of scope here)
with this one you switch to using ::class constant, but for the rest you retain the class as a string.
Should we standardize? I'd be plus one on making them all use the class constant.
unneeded?
example where you've kept the class as a string (there are many more)
hah, nice cleanup
are these even used? not seeing them in this class so is it child classes only?
ouch
Comment #30
berdir1. Hm. I'm actually not a big fan of "injecting" entity storages directly as a property in the constructor, it's more work when it might not be needed. We now have a way to reset the static cache directly, but it also used to be a problem that the useCaches() workaround for unsetting the handlers didn't work then because the old instance was still injected. Seen similar problems with injected config objects for example.
2. I'm usually updating the lines that I'm touching, but I didn't write the whole patch here. I can update them.
3. Fixed.
6. It's hard to see in the patch, but the class uses FieldableEntityNormalizerTrait, which needs them.
7. Yeah, not sure if this is overkill, but it's the way for how we can handle removing injected dependencies in a BC-compatible way. I'd also be OK if we say that we're not going to that, at least not here as it is most likely not a class that's commonly subclassed.
Also fixed the change constructor argument order in hal.services.yml, not sure why there are two files in the previous comment...
Comment #31
larowlanI'm actually not a big fan of "injecting" entity storagesme neither since I spent 3 hrs this working working out why after saving a contact form all of its field definitions went missing.
Turned out there was a ->getQuery() to get an entity query call in a constructor of a service that was doing inbound/outbound route processing before modules were loaded resulting in field_entity_storage_info not being loaded and being dropped from the module implements cache
Comment #32
jibranI was unable to find any occurrence other then
core/core.services.ymlI like this.
I'd like to know more about it. Can we document it somewhere?
Patch looks good to me so setting it RTBC.
Comment #33
wim leersSame!
EDIT: also, EPIC patch! 😵
Comment #34
alexpottWe need assert on the interfaces here or we lose type safety. I think the thing to do here is to remove the entity manager type hint and pass a NULL in via the .services file and then file a follow-up for Drupal 9 to fix this. Because then we can make a breaking change... or maybe we have auto-wiring at that point.
Comment #35
berdirAs discussed with @alexpott, I think that half-step of removing it doesn't really have any benefits, so I'm dropping that part completely from this issue/patch and will create a separate issue for it.
Comment #36
berdirFollow-up: #3025152: Remove entityManager constructor argument from SystemManager
Comment #37
jibran#34 is moved to follow-up so back to RTBC.
Comment #38
alexpottCrediting myself, @jibran, @larowlan for reviews.
Committed 7dcda1f and pushed to 8.7.x. Thanks!
Fixed the above coding standards / documentation issues on commit.