Problem/Motivation

There are routes where {node} is used but it is not upcasted, for example if the controller does not type hint it as NodeInterface.

Proposed resolution

Check with if ($node instanceof NodeInterface) instead of just if ($node}.

Remaining tasks

User interface changes

API changes

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

Berdir’s picture

Status: Active » Needs review
FileSize
1.13 KB
hass’s picture

Is this something we always need to do? I have no idea why there could be a non-node object in $node. Maybe you could explain this to me a bit more. You know D8 internals better than me I think and I try to learn.

There may be one more place... See http://cgit.drupalcode.org/google_analytics/tree/google_analytics.module...

Berdir’s picture

Upcasting depends on the type hints of the controller/form.

Things are only upcasted if the "target" has a matching interface, so if you define a route with {node}, if you use "NodeInterface $node" in your controller, then you get an upcasted node object, if you just have "$node", then you just get the ID.

If you have generic code that just accesses a route parameter based on the name, then you don't know what is the case.

Another thing, the correct way to access it would be \Drupal::routeMatch()->getParameter('node') (see https://api.drupal.org/api/drupal/core%21lib%21Drupal%21Core%21Routing%2...), but I think the behavior is the same.

hass’s picture

I'm sorry, but I understand nothing what you wrote.

  • hass committed 83ea9de on 8.x-2.x authored by Berdir
    Issue #2397325 by berdir: Fix incorrect settings structure
    
hass’s picture

FileSize
1.3 KB

@Bedir: Can you take a look to this, please? Are you able to explain this change to me a bit, please?

Berdir’s picture

That's what I tried before :)

Let's say you have two routes (more or less made up):

/node/{node} => NodeController::view(NodeInterface $node)

and

/whatever/{node} => WhateverController::doSomething($node)

Then you access it with node/1 vs. whatever/1.

For node/1, the routing/upcasting system automatically loads node 1 and the parameter that is passed around from then on is a Node entity object. for whatever/1, this doesn't happen, and $request->attributes->get('node') or \Drupal::routeMatch()->getParameter('node') is just "1".

Now, if your code runs on such a page, it current fails. I think I've seen this on the confirmation page for reverting a revision, which has this route "/node/{node}/revisions/{node_revision}/revert". Because it never actually uses {node}, it is also not upcasted. So just create a revision of a node, and then try to revert that and you should see some errors.

hass’s picture

How can content ->has('node') = TRUE and than is not a node? Is there any other way to detect if we are running a node or not?

Berdir’s picture

Because of what I just explained, twice? It is only upcasted when the controller requests an object with a type hint.

Why do you want another way, one is enough?

hass’s picture

I do not understand what you are talking about. That is the main problem. No idea what upcasting is. And I have no idea why this $node is not a node object. I'm asking for something simplier as I do not understand anything and I have no clue why $node is not a node. It is a WTF DX to me.

hass’s picture

I'm looking into the running request

This tells me we are running a node:

if ($request->attributes->has('node')) {

This gets these current node object:

$node = $request->attributes->get('node');

And now you say this $node is not a node!? It looks like I have seriously not understood how Drupal works.

if ($node) {
Berdir’s picture

This tells me we are running a node:

No. That is *not* what it means.

It means you are on a route with a parameter {node}.

That is *just* a name. It could be anything. You can define a route '/whatever/{node}' and call it with whatever/banana. Technically, that is perfectly fine.

Now, there is a bit of magic, that for example for node/1, converts the route parameter {node} with the value '1' into a Node object. That magic is called upcasting (or sometimes parameter converting). That magic works by default*, under one condition: The controller for that route must type hint with NodeInterface, or at least EntityInterface, only then this happens.

* It works by default, but it is also configurable. You can load a {node} as a user, or a {whatever} as a node (sometimes, you want to load two different nodes in a route, but you can only have one {node}, this is why). See paramconverter_test.routing.yml for some fun examples.

Basically, this is the same as % and %node in D7, except that there are some more conditions now and it is more flexible/configurable.

And all of this is why you need to check if $node is actually a node entity. Because someone might have created a route where {node} is 'banana', just to mess with your head.

hass’s picture

Huh... I reviewed the D7 version, and menu_get_object($type = 'node') made sure it only loads node objects. So we are fine there. So now you say $node instanceof NodeInterface makes sure we also only load nodes here. Ok so far. I wish I could grad a node object a lot easier from a request.

Now I think I got at least your banana example. Let's come back to #7. I'm confused by your first sentence.

That's what I tried before :)

Does this mean my patch in #6 will not work or what are you trying to say? :-)

Berdir’s picture

No, I meant to I tried to explain it before. The patch is fine.

hass’s picture

Title: Token replacement in google_analytics_page_attachments() does not check if $node is a node object » Check if $node is a node object

  • hass committed 42ed87a on 8.x-2.x authored by Berdir
    Issue #2397325: Check if $node is a node object
    
hass’s picture

Status: Needs review » Fixed

Thanks for your help.

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.

The last submitted patch, 1: google_analytics-node-2397325-1.patch, failed testing.

Status: Closed (fixed) » Needs work

The last submitted patch, 6: Issue-2397325-Use-node-instanceof-NodeInterface.patch, failed testing.

hass’s picture

Status: Needs work » Closed (fixed)