Problem/Motivation
In #3392616: Update to Symfony 6.4 we decided to convert both BookNavigationCacheContext and MenuActiveTrailsCacheContext into lazy services.
Whilst looking into this, I've stumbled over the way core currently handles this: Using a script to create a Proxy class.
Looking at https://symfony.com/doc/current/service_container/lazy_services.html Symfony supports this natively (since 6.2 without additional packages/traits).
Steps to reproduce
Proposed resolution
Replace our proxy lazy service solution with the native one from Symfony itself.
This would get us more "of the island", reduce custom solutions we have to maintain.
Remaining tasks
User interface changes
API changes
Data model changes
Release notes snippet
| Comment | File | Size | Author |
|---|---|---|---|
| #7 | do-not-try-this-at-home.patch | 944 bytes | spokje |
| #7 | LazyStateGhost.jpg | 358.33 KB | spokje |
Issue fork drupal-3396928
Show commands
Start within a Git clone of the project using the version control instructions.
Or, if you do not have SSH keys set up on git.drupalcode.org:
- 3396928-deprecate-drupal-proxybuilder
changes, plain diff MR !5140
Comments
Comment #3
spokjeThis needs some TLC tomorrow, but I'm not unhappy so far...
Comment #4
spokjeComment #5
spokjeComment #6
longwaveThis seemed too good to be true, and unfortunately I think it is. As per the docs:
With this MR checked out and after a container rebuild:
ie. I don't think the ghost objects are working. I suspect our container and/or dumper need to add support for them, somewhere.
Comment #7
spokje@longwave: Hmm, at the very least #6 points out that this MR is missing test coverage.
I'm a tad more optimistic.
The attached (incredibly nasty hacky do-not-try-this-at-home) test patch on top of this MR shows that the following service-IDs implement
Symfony\Component\VarExporter\LazyObjectInterface:That list matches on first glance what I expected.
Can the difference between your and my findings be explained by looking at different times in the Container lifecycle maybe?
As a sidenote: I also didn't believe this to work, but putting breakpoints in tests using the lazy services indeed shows the presence of LazyObjectState and [ActualClassName]Ghost[hashID] classes. (See https://www.drupal.org/files/issues/2023-10-27/LazyStateGhost.jpg)
Of course, that's no proof at all.
Comment #8
longwaveIn kernel tests, the container is a
\Drupal\Core\DependencyInjection\ContainerBuilder- you can see this by dumping$container::classin that sample test. This is a thin layer over Symfony's ContainerBuilder which does support lazy services.However at runtime the container is a
\Drupal\Core\DependencyInjection\Containerwhich is not based on Symfony at all, it only implements their interface. The ContainerBuilder is dumped and stored in cache by the rebuild process, and reloaded from there as a normal Container on subsequent page loads.IIRC we were bitten by this before when adding service deprecations: #3215611: Service deprecations are only triggered on container build,not ::get()
#2529516: Decouple tests from relying that $container is a container builder would make this distinction better for kernel tests.
Comment #9
longwaveNot that this should put us off; the fact the kernel tests are passing here are a good sign that these lazy services are working, just they are no longer lazy at runtime or in functional tests. But if we add support for them to the dumper/container then they should be usable at runtime too!
Comment #10
longwaveComment #11
spokjeThanks @longwave, that's the reason I always danced around the container bit, never got a firm grasp of it.
The explanation helped, still got hope this is going to work and shouldn't be that hard.
(It seems the actual container is fed the drupal proxy classes instead of the actual services, let's see if that can be altered quickly)
#FamousLastWords
#OnHisWayToTheDrawingBoard
Final question (for now):
How, what, and where did you do that class_implements?
Also un-parenting, since this isn't directly SF6.4 related.
Comment #12
longwaveI use DDEV for all Drupal dev work; drush provides a shell that bootstraps Drupal so you can run PHP code interactively:
Comment #13
spokje*hat is tipped*
Much obliged, kind sir.
Comment #14
joachim commented> In kernel tests, the container is a \Drupal\Core\DependencyInjection\ContainerBuilder - you can see this by dumping $container::class in that sample test. This is a thin layer over Symfony's ContainerBuilder which does support lazy services.
Aside: is that documented somewhere?
Comment #15
longwaveI don't remember seeing it anywhere, we could add some docs to KernelTestBase I guess but really we should fix #2529516: Decouple tests from relying that $container is a container builder
Comment #16
spokjeComment #17
spokjeSadly SF uses eval for the proxy classes which at least I can't see working with our serialized container solution
Comment #18
bkosborneI wonder if the change record can be deleted? It comes up in Google Search and it's not super obvious when looking at a draft CR that it's a draft
Comment #19
alexpott@bkosborne I unpublished the CR.