Problem/Motivation

NodeRouteContext should not provide a context if there is no node to be found in the route. Currently it does.

Proposed resolution

Make it stop

Remaining tasks

Make it stop

User interface changes

None

API changes

None

Data model changes

None

Comments

EclipseGc created an issue. See original summary.

eclipsegc’s picture

StatusFileSize
new1003 bytes

Let's start with a simple patch and see what goes wrong.

Eclipse

eclipsegc’s picture

Status: Active » Needs review

Testbot, show me what I broke!

Status: Needs review » Needs work

The last submitted patch, 2: NodeRouteContext.patch, failed testing. View results

dawehner’s picture

I'm curious, don't we need to add the cacheability metadata always?

eclipsegc’s picture

For what? The lack of a context doesn't represent data that we need to cache. You don't visit /user/1 and need to cache "nope, no node here". The system cache what is where, not what isn't where. This isn't to be confused with "yes there's a node here, but you don't have access". In that case, of course we'd need to cache that there was a node there and that our response is dependent upon who has access to the node. But these are different things.

As an example of what I'm saying, there's not a context provider (yet) that accounts for all possible entities. If there were, it'd not need to inform Drupal that there were no terms/users/comments/etc on a given page, it need only inform when there ARE entities. (And I intend on writing that code, so yeah we should establish this quickly)

Eclipse

wim leers’s picture

@dawehner is right, you'd still need the route cache context. Because the value returned by getRuntimeContexts() still depends on the route that was matched. Since that return value (and the cacheability of it) affect Condition plugins, which are used by block visibility, which is central in block access checking, and therefore hugely important in caching of blocks (which cached variant of a block to retrieve, and which cached partial page to retrieve from Dynamic Page Cache), cacheability metadata even for the case of "nope, no node" at /user/1 (or /foobar for that matter) is essential.

You've asked basically the same question at #2375695-69: Condition plugins should provide cache contexts AND cacheability metadata needs to be exposed.4, in June 2015. @Berdir answered it in #70.4. This patch is forgetting the discussion that was had there, and is effectively reverting that change (which was a critical bugfix).

NodeRouteContext is indeed returning a Context object, but it's not erroneous, it's correct AFAICT: it's necessary to ensure that everything consuming those contexts (i.e. using them as inputs) can be cached correctly. The value that is associated with that Context object is NULL. This is also why ContextInterface::hasContextValue() was added in #2513244: ContextHandler incorrectly checks required/optional contexts of plugins, which was a blocker for #2375695.

Is it possible you forgot about that? 😳 I feel like I'm missing something…

eclipsegc’s picture

Version: 8.5.x-dev » 9.x-dev
Status: Needs work » Postponed

Yeah... this is a difference between how core and contrib generally want to make use of contexts. Since the core block system is horribly naive, this sort of solution is fundamentally broken for contrib, which means they have to know that, understand that, and manually disregard the node context from core. We'll have to circle back around to this when we stop misusing blocks and contexts in this way, so I guess I'll postpone it till D9 for the time being.

So, to reiterate, yeah ok, but it needs to change.

Eclipse

wim leers’s picture

Version: 9.x-dev » 8.5.x-dev
Status: Postponed » Active

Please act more constructively. Simply postponing this to 9.x is not going to solve this.

Especially because Drupal 9 is not allowed to break backwards compatibility — we can only drop deprecated APIs. So we should already look into any potential deprecations here.

#2375695: Condition plugins should provide cache contexts AND cacheability metadata needs to be exposed was a critical bugfix to ensure that things using the context system would still be cacheable. #8 is saying as far as I can tell that we should give up on cacheability to get back the DX you imagined. (Today's if ($result['node']->hasContextValue()) {…} vs if (!empty($result)) {…} which you prefer.) But in either case, the calling code needs to know how to interpret the result of getRuntimeContexts(). So I'm not sure the difference is that big?

An initial idea/suggestion: what if we'd add a class NoContext implements ContextInterface {…}? Then NodeRouteContext could return new NoContext(['route']). That'd make the NodeRouteContext:getRuntimeContexts() code clearer. It'd still require similar calling code though — which makes sense: we can't break BC.

eclipsegc’s picture

@wim,

Not trying to be unconstructive, an no, I don't "prefer" the boolean approach. Yes I did 3 years ago before I understood what you'd built and the nuances involved, but I generally understand what you've built, and I have no desire to abandon it. That being said, let's actually address my comment since it was instructive of my position:

the core block system is horribly naive

This isn't an opinion, it's absolutely true, and this issue we are discussing is a perfect example of why and how. Block placement outside of core collects the actual contexts on a page, and then uses that list of contexts to inform itself about what blocks (and conditions) are even viable in a given environment. If there's no node, there won't be node context consuming blocks. The same is true of conditions. In this case, there's no need to store the "negative" data that core needs.

So why does core need this?

My fatal flaw in filing this issue was that I'd gotten used to how contrib thinks. I got a bit ahead of myself on this issue. The simple fact of the matter is that Core's page block layout tool doesn't ever try to assert when and where contexts are ACTUALLY available. A point I forgot over the last 3 years. So our NodeRouteContext is instructive in this regard. It says "well, a user might want to place a block but only show it when a node is available and that node is of type page". Thus we're into this negative logic.

Unfortunately, even though I appreciate your suggested solution Wim, I don't think it's workable. The returned context would still need to identify as a node context in order to be passed into the condition/block that uses it, and it's only from the conditions or blocks that the cache tags/context/max-ages are retrieved.

I'm super happy to discuss viable next steps if you still feel like there might be one, but in my mind I just need to do the long-hard work of replacing our core block placement tools with viable solutions that people want to adopt so that we can deprecate the entire block module's way of block placement. In the mean time, I'll simply manually remove this context from block placement tools with better insight into their actual present contexts.

Thanks!

Eclipse

eclipsegc’s picture

Also, I didn't intend that move to D9 as a "screw this" or anything. I was just trying to acknowledge that you were correct and I didn't have the time to work on a bigger solution right now since that's what it'd take. That's all. Sorry if I caused any offense.

Eclipse

wim leers’s picture

Title: NodeRouteContext erroneously returns a new Context object, even when a node is not available. » [NodeRouteContext erroneously returns a new Context object, even when a node is not available.
Category: Bug report » Plan
Issue tags: +Needs title update, +Needs issue summary update

In this case, there's no need to store the "negative" data that core needs.

This is not true. We still need to know that this "no context" result varies by the route cache context, i.e. that if a different route were requested, that it may not be a "no context" result, but in fact there may be a context!

Unfortunately, even though I appreciate your suggested solution Wim, I don't think it's workable.

That's totally possible 🙂 It was just an initial suggestion to get the discussion going.

I'm super happy to discuss viable next steps if you still feel like there might be one, but in my mind I just need to do the long-hard work of replacing our core block placement tools with viable solutions that people want to adopt so that we can deprecate the entire block module's way of block placement.

Well, that is going to have to happen in a way that does not break BC. So postponing this to D9 is not actually going to help, because all that D9 is going to be allowed to do is remove things that are @deprecated. See https://dri.es/making-drupal-upgrades-easy-forever.

In other words: we'll have to start doing the work of a better system during the Drupal 8 cycle anyway. So there's no point in waiting :)

This is definitely (VERY!) hard for Drupal core developers, but it makes things much easier for the end users of Drupal of course. I've been doing this for the REST module for the past ~1.5 year now, and in that time, we've accumulated >2000 LoC that will be deleted in Drupal 9. I last updated that "remove BC layers" patch a few days ago: #2893804-6: Remove rest.module BC layers.

In the mean time, I'll simply manually remove this context from block placement tools with better insight into their actual present contexts.

I'm sorry, I'm not familiar enough with those tools and these APIs to understand this 100%. Does this mean you are you going to start relying on the API that #2513244: ContextHandler incorrectly checks required/optional contexts of plugins introduced, or that you're going to work around it by limiting what the user is allowed to do?


So, why not use this issue to do the analysis of what's broken in the current system, and come up with a step-by-step plan that would not break BC that would get us to a place where everything is working? We would be able to mark existing APIs @deprecated, and they'd disappear in 9.0.0.
It sounds like it'll be impossible to have everything work as nicely and simply as we'd want, but that is the cost we have to pay for not breaking BC. But we can make plugins opt in to improved APIs one-by-one, and then offer a better user experience for those, perhaps. That'd be an incentive to update to the new APIs. Plus, there's the trigger_error('Some message saying why you should not be using this anymore but the other thing instead', E_USER_DEPRECATED), which will show up in A) test runs, B) people's actual dev environments, which is another incentive.

In any case, there's nothing stopping us from looking into what the problems are and articulating a plan to fix it for 9. I currently don't fully understand what the problems are. You're the main Context component maintainer AFAIK, so you have the most complete insight.

P.S.: why isn't there a Context component in MAINTAINERS.txt or on d.o?

eclipsegc’s picture

why isn't there a Context component in MAINTAINERS.txt or on d.o?

Because Context is part of plugins, so in that regard, Tim Plunkett and I are the maintainers of it because plugins. :-D

use this issue to do the analysis of what's broken in the current system

Ok, that sounds like "Change the IS & title drastically and turn this into a META so you can solve the stuff that's driving this issue." which seems like the next obvious step to take, so I'll begin that work. Thanks for the input!

Eclipse

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.

andres.torres’s picture

When creating an image field for a simple contentype (node), create a new user role, non admin, assign the proper permissions to the role so it can create/edit/delete, when creating a new node as this new role, the issue is also present:

The website encountered an unexpected error. Please try again later.
Error: Call to a member function getType() on null in

The Alt text is not available for non-admins, see screenshot for reference, so it triggers the error described.

andres.torres’s picture

Please ignore my last comment since it was a bad implementation of a hook causing the issue.

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.

andypost’s picture

Status: Needs review » Needs work

The last submitted patch, 18: 2918555-18.patch, failed testing. View results

tim.plunkett’s picture

Title: [NodeRouteContext erroneously returns a new Context object, even when a node is not available. » [meta] ContextProviders must return a Context object for cacheability metadata, even when a value is not available, breaking expectations of calling code
Component: other » plugin system
Issue tags: -Needs title update

Isn't that the same patch from #2?

Anyway, retitling.

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.

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.

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.