Author image
Senior Developer

Drupal 7 node_load references

In Drupal 6, if you called node_load then what you'd be returned would be your own copy of the node to change and modify as you pleased, but in Drupal 7 this was changed. By default, what you actually get back from a node_load is essentially a reference to a global singleton for that node. This has the interesting side effect of meaning that if you change anything in the node object, you are probably changing everyone else's copies of that node too. This is explained in this issue: http://drupal.org/node/154859

So, why should you care? Well, in the right circumstances data loss is really easy!

For example, add a file field to a node type, and allow users to select whether to display files when viewing a node. Now, create a new node, and add a file and uncheck the display checkbox. So, when viewing the node normally, no file is shown.

Now, imagine the following code runs:

// Load up the node with files on it.
$node = node_load(1);

// Render the node.
$rendered = node_view($node);

// Later, decide you want a 'fresh' copy of the node.
$fresh_node = node_load(1);

// Save the fresh node.
node_save($fresh_node);

Now go and edit your file in Drupal, where has your uploaded file gone?

Well, the call to node_view means that file.module directly unsets the files that shouldn't be displayed. But, in my code, this node is effectively global, so when I call my second node load, it's not 'fresh' at all, I just get back a reference to the node that's had the file removed, so calling node_save on it was a very bad idea.

Note that the node_view and node_save don't have to be in the same code, they could be in different modules, that know nothing of what the other is doing.

I'd like to know what the solution here is, one solution might be to clone the node when we get it back from node_load, but that was removed from D6, so it seems silly to add it back everywhere it gets used. Or, you could try to only clone it when the data in the node will be changed, but that will be pretty much every time we do anything with the node, and because of the way Drupal works, things could be changed even when we don't think it would be. It seems like the only safe solution is to clone most times, but core doesn't do this, so you'll still run into issues like the one outlined above.

Thoughts?

Comments

When you want a fresh copy, use node_load($nid, NULL, TRUE);

I don't think that's the d.o nid that you meant to link to. It talks about somebody hacking chameleon theme back in 2005.

No it wasn't, I was missing a '9'

Don't change $node on node_view().
$node represents the data stored for a node, so only change it if you want to change the stored data + call node_save() to make your changes permanent.

>Well, the call to node_view means that file.module directly unsets the files that shouldn't be displayed.

If file.module does that, it's a bug. Please file an issue for it if there is none yet.

This is something of which I was completely unaware in Drupal 7, so thanks for pointing this out, as it is a major issue for people like me who would otherwise not have grasped it.

I strongly feel there should be mention made of this in the documentation. The current documentation, http://www.computerminds.co.uk/articles/drupal-7-nodeload-references simply says "Load a node object from the database.' Is there a case for making mention, in the API docs for this function, of the effects described in this blog post?

Sorry, I've linked back to the article itself instead of the documentation! The doc link is http://api.drupal.org/api/drupal/modules--node--node.module/function/nod...

> Don't change $node on node_view().
$node represents the data stored for a node, so only change it if you want to change the stored data + call node_save() to make your changes permanent.

The entire rendering system in core changes the contents of a node so it would seem that core doesn't agree with the only change a node if you want that data saved principle.

Please, I hove you can help me... You said "imagine this work"... but... How can i make it working real and print fields of "nodeloaded node" into my tpl??? Plz help...

Comments on this article are now closed, if you want to give us feeback you can use our contact form instead.