Problem/Motivation
This is a follow-up to #2881348: SessionCacheContext calls getId() on null.
@larowlan commented (#9),
Also I note that SessionCacheContext is used as a cache context, but doesn't implement \Drupal\Core\Cache\Context\CacheContextInterface - perhaps it should, otherwise it's missing methods might cause other fatals namely
getCacheableMetadata. Perhaps that is a different issue though.
Later, @alexpott said (#44),
I think the addition of the interface should go in a separate issue. Afaics from the code because the ID does not contain a "." or ":" we'll never call getCacheableMetadata(). If this change doesn't have the interface addition then it is a bugfix that can get resolved in 8.4.x as well as 8.5.x. Which is good because it is fixing a problem that people are facing.
Proposed resolution
Declare the interface and implement the getCacheableMetadata() method.
Compare with patches already on the original issue, such as 2881348-39.patch.
Remaining tasks
User interface changes
None
API changes
Code can rely on SessionCacheContext to implement CacheContextInterface.
Data model changes
None
| Comment | File | Size | Author |
|---|---|---|---|
| #24 | 2915594.patch | 2.69 KB | borisson_ |
| #18 | 2915594-18.patch | 8.71 KB | andypost |
| #2 | 2915594-2.patch | 953 bytes | benjifisher |
Issue fork drupal-2915594
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:
Comments
Comment #2
benjifisherLet's try reversing interdiff-39-46.txt from #2881348: SessionCacheContext calls getId() on null.
Comment #3
andypostDoes it makes sense to add unit test for that? or maybe kinda integration test?
Comment #4
benjifisher@andypost: That sort of feels like a test to verify that the class implements the interface it declares ... and I think that PHP already confirms that.
I searches
core/tests/for "getCacheableMetadata" and only found a few instances: test classes inCacheContextsManagerTestthat implementCacheContextInterfaceorCalculatedCacheContextInterfaceand a couple of lines inTrustedRedirectResponseTest::testCreateFromRedirectResponse(). None of these looks as though it is testinggetCacheableMetadata()itself, so I do not have any good models.If you really think this needs a test, can you give me some ideas about how to test it?
Comment #5
wim leersAgreed with @benjifisher that that is overkill. Explicit test coverage was added at
\Drupal\KernelTests\Core\Cache\CacheContextOptimizationTest, in #2512866: CacheContextsManager::optimizeTokens() optimizes ['user', 'user.permissions'] to ['user'] without adding cache tags to invalidate that when the user's roles are modified.Comment #6
alexpottSo do we think all cache contexts need to implement this? At the moment obviously nothing is enforcing this. I think before just implementing the interface here we need to think about the wider issue.
Comment #7
wim leersThat's fair! I'd like that too, then we'd never have to deal with this again.
I can think of two ways to do this:
cache.context-tagged service implementsCacheContextInterfaceor\Drupal\Core\Cache\Context\CalculatedCacheContextInterface.assert()in\Drupal\Core\Cache\Context\CacheContextsManager::__construct()that gets each service and asserts it implements either of those two interfaces.Comment #8
alexpott@Wim Leers but is it true that we should ensure that all cache contexts have this interface? Is it wrong if they don't?
Comment #9
wim leersI'm not sure what you're asking. Is it absolutely necessary? No. But then we might as well remove 90% of interfaces in Drupal core. Is it useful to ensure consistency? Yes.
Comment #10
wim leersComment #11
alexpottThe thing that bothers me here is that we're adding an interface that is not enforced that enforces a method that is never called.
Comment #12
wim leersAgreed. I proposed solutions for that in #7. I'd be happy to address either of those solutions (or another one) in a follow-up.
\Drupal\Core\Cache\Context\CacheContextInterface::getCacheableMetadata()definitely does get called. It just happens to never get called for thesessioncache context because that cache context doesn't have parent cache contexts, which means it can never be optimized away. At least not until #2453835: Allow non-intrinsic (implementation-dependent) cache context services to specify their parents via DynamicParentContextInterface::getParents() lands.Comment #13
alexpott@Wim Leers I meant that it does not get called in this instance.
Comment #14
wim leersOkay, I understand.
That's because the interface was designed to be forward-thinking, to allow #2453835: Allow non-intrinsic (implementation-dependent) cache context services to specify their parents via DynamicParentContextInterface::getParents() to land without the need for further changes.
Comment #15
alexpott@Wim Leers but then that change needs to check if contexts implement the interface because as we can see - at the moment that is not enforced (and can't be without a BC breaking change). So in someways it's good to have an example in core of a context that doesn't implement an interface because this is perfectly possible in contrib.
Comment #16
wim leersSo let's do this and revisit this after 8.5.0-alpha.
Comment #18
andypostI think it makes sense to remove mostly all boilerplate code to base class because only few "contexts" override this method
Comment #19
andypost@Wim Leers I think we need both options from #7
Comment #20
wim leersThanks for reviving this issue, @andypost!
However, I don't understand where you're going with #18.
Comment #21
andypost@Wim this probably needs separate issue but imo fits in task
Comment #22
wim leersCan you explain what you're doing and why? It looks very different from previous patches.
Comment #23
andypostI just moved common boilerplate code to base class
Comment #24
borisson_I think @andypost's patch is a good idea, but it's not in scope for this issue. That should go in a new issue.
Instead #7 should be implemented. The assertion isn't that easy to implement in the __construct, because it get's an array of cache context ids, not the actual services. Loading the services to check for the services would be a big hit in performance.
I added a test, not sure about the location and if it's sufficient.
Comment #25
andypostFiled follow-up #2971941: Move boilerplate code for cache metadata to base class
This one good to go
Comment #26
alexpottI'm not sure that #24 or #18 is really what @Wim Leers and I discussed in #15 and #16.
Comment #36
longwaveFound this following #3221128: Enable service autoconfiguration for core event subscribers
If we enable autoconfiguration, that means we can automatically add the
cache.contexttag to services that implement a specific interface. But as I found over there, not all cache contexts actually implement CacheContextInterface.Comment #37
andypostI think we should start throw deprecation if cache contexts does not implement context interface
This test still makes sense but needs to throw deprecation if collector discovers cache context without interface
Comment #38
andypostThe change in #18 is BC break so collector should care about it
Looking at usage of
CalculatedCacheContextInterfacethere's only one check for interface in\Drupal\Core\Cache\Context\CacheContextsManager::getLabels()