fbpx Drupal node load references : Drupal 7 | ComputerMinds Skip to main content

Drupal node load references : Drupal 7

12th Jul 2011

Steven Jones

Senior Developer

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?