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

Issue fork drupal-2915594

Command icon 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

benjifisher created an issue. See original summary.

benjifisher’s picture

Status: Active » Needs review
Issue tags: +session cache
StatusFileSize
new953 bytes
andypost’s picture

+++ b/core/lib/Drupal/Core/Cache/Context/SessionCacheContext.php
@@ -29,4 +30,11 @@ public function getContext() {
+  public function getCacheableMetadata() {

Does it makes sense to add unit test for that? or maybe kinda integration test?

benjifisher’s picture

@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 in CacheContextsManagerTest that implement CacheContextInterface or CalculatedCacheContextInterface and a couple of lines in TrustedRedirectResponseTest::testCreateFromRedirectResponse(). None of these looks as though it is testing getCacheableMetadata() 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?

wim leers’s picture

alexpott’s picture

Status: Reviewed & tested by the community » Needs review

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().

So 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.

wim leers’s picture

That'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:

  1. Add a test that verifies that every cache.context-tagged service implements CacheContextInterface or \Drupal\Core\Cache\Context\CalculatedCacheContextInterface.
  2. Add an assert() in \Drupal\Core\Cache\Context\CacheContextsManager::__construct() that gets each service and asserts it implements either of those two interfaces.
alexpott’s picture

@Wim Leers but is it true that we should ensure that all cache contexts have this interface? Is it wrong if they don't?

wim leers’s picture

I'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.

wim leers’s picture

Status: Needs review » Reviewed & tested by the community
alexpott’s picture

The thing that bothers me here is that we're adding an interface that is not enforced that enforces a method that is never called.

wim leers’s picture

The thing that bothers me here is that we're adding an interface that is not enforced

Agreed. I proposed solutions for that in #7. I'd be happy to address either of those solutions (or another one) in a follow-up.

that enforces a method that is never called.

\Drupal\Core\Cache\Context\CacheContextInterface::getCacheableMetadata() definitely does get called. It just happens to never get called for the session cache 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.

alexpott’s picture

@Wim Leers I meant that it does not get called in this instance.

wim leers’s picture

Okay, 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.

alexpott’s picture

@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.

wim leers’s picture

Status: Reviewed & tested by the community » Active

So let's do this and revisit this after 8.5.0-alpha.

Version: 8.5.x-dev » 8.6.x-dev

Drupal 8.5.0-alpha1 will be released the week of January 17, 2018, which means new developments and disruptive changes should now be targeted against the 8.6.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

andypost’s picture

Status: Active » Needs review
StatusFileSize
new8.71 KB

I think it makes sense to remove mostly all boilerplate code to base class because only few "contexts" override this method

andypost’s picture

@Wim Leers I think we need both options from #7

wim leers’s picture

Thanks for reviving this issue, @andypost!

However, I don't understand where you're going with #18.

andypost’s picture

@Wim this probably needs separate issue but imo fits in task

wim leers’s picture

Can you explain what you're doing and why? It looks very different from previous patches.

andypost’s picture

I just moved common boilerplate code to base class

borisson_’s picture

StatusFileSize
new2.69 KB

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.

andypost’s picture

Status: Needs review » Reviewed & tested by the community
alexpott’s picture

Status: Reviewed & tested by the community » Needs work

I'm not sure that #24 or #18 is really what @Wim Leers and I discussed in #15 and #16.

Version: 8.6.x-dev » 8.7.x-dev

Drupal 8.6.0-alpha1 will be released the week of July 16, 2018, which means new developments and disruptive changes should now be targeted against the 8.7.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.7.x-dev » 8.8.x-dev

Drupal 8.7.0-alpha1 will be released the week of March 11, 2019, which means new developments and disruptive changes should now be targeted against the 8.8.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.8.x-dev » 8.9.x-dev

Drupal 8.8.0-alpha1 will be released the week of October 14th, 2019, which means new developments and disruptive changes should now be targeted against the 8.9.x-dev branch. (Any changes to 8.9.x will also be committed to 9.0.x in preparation for Drupal 9’s release, but some changes like significant feature additions will be deferred to 9.1.x.). For more information see the Drupal 8 and 9 minor version schedule and the Allowed changes during the Drupal 8 and 9 release cycles.

Version: 8.9.x-dev » 9.1.x-dev

Drupal 8.9.0-beta1 was released on March 20, 2020. 8.9.x is the final, long-term support (LTS) minor release of Drupal 8, which means new developments and disruptive changes should now be targeted against the 9.1.x-dev branch. For more information see the Drupal 8 and 9 minor version schedule and the Allowed changes during the Drupal 8 and 9 release cycles.

Version: 9.1.x-dev » 9.2.x-dev

Drupal 9.1.0-alpha1 will be released the week of October 19, 2020, which means new developments and disruptive changes should now be targeted for the 9.2.x-dev branch. For more information see the Drupal 9 minor version schedule and the Allowed changes during the Drupal 9 release cycle.

Version: 9.2.x-dev » 9.3.x-dev

Drupal 9.2.0-alpha1 will be released the week of May 3, 2021, which means new developments and disruptive changes should now be targeted for the 9.3.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 9.3.x-dev » 9.4.x-dev

Drupal 9.3.0-rc1 was released on November 26, 2021, which means new developments and disruptive changes should now be targeted for the 9.4.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 9.4.x-dev » 9.5.x-dev

Drupal 9.4.0-alpha1 was released on May 6, 2022, which means new developments and disruptive changes should now be targeted for the 9.5.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 9.5.x-dev » 10.1.x-dev

Drupal 9.5.0-beta2 and Drupal 10.0.0-beta2 were released on September 29, 2022, which means new developments and disruptive changes should now be targeted for the 10.1.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

longwave’s picture

Found this following #3221128: Enable service autoconfiguration for core event subscribers

If we enable autoconfiguration, that means we can automatically add the cache.context tag to services that implement a specific interface. But as I found over there, not all cache contexts actually implement CacheContextInterface.

andypost’s picture

I think we should start throw deprecation if cache contexts does not implement context interface

+++ b/core/tests/Drupal/KernelTests/Core/Cache/CacheCollectorTest.php
@@ -60,4 +62,15 @@ public function providerTestInvalidCharacters() {
+   * Tests that cache contexts implement the right interfaces.
...
+  public function testContextImplementsInterface() {
+    $cache_contexts = \Drupal::service('service_container')->findTaggedServiceIds('cache.context');
+    foreach (array_keys($cache_contexts) as $context) {
+      $service = \Drupal::service($context);
+      $this->assertTrue($service instanceof CalculatedCacheContextInterface || $service instanceof CacheContextInterface);

This test still makes sense but needs to throw deprecation if collector discovers cache context without interface

andypost’s picture

+++ b/core/lib/Drupal/Core/Cache/Context/RequestStackCacheContextBase.php
@@ -11,7 +12,7 @@
-abstract class RequestStackCacheContextBase {
+abstract class RequestStackCacheContextBase implements CacheContextInterface {

The change in #18 is BC break so collector should care about it

Looking at usage of CalculatedCacheContextInterface there's only one check for interface in \Drupal\Core\Cache\Context\CacheContextsManager::getLabels()

Version: 10.1.x-dev » 11.x-dev

Drupal core is moving towards using a “main” branch. As an interim step, a new 11.x branch has been opened, as Drupal.org infrastructure cannot currently fully support a branch named main. New developments and disruptive changes should now be targeted for the 11.x branch, which currently accepts only minor-version allowed changes. For more information, see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

prudloff made their first commit to this issue’s fork.

Version: 11.x-dev » main

Drupal core is now using the main branch as the primary development branch. New developments and disruptive changes should now be targeted to the main branch.

Read more in the announcement.