I am working on a D7 module that implements http://api.drupal.org/api/function/hook_node_load/7 and has code that checks the $types parameter to that hook (and only runs for particular node types).

I found that on some pages of the site, the code ran, but others it didn't.

I tracked it down to the way the node module builds up the arguments for this hook. Instead of always ensuring that the $types argument is set to the correct types for this particular node_load_multiple() call, it instead keeps adding new parameters to the hook invocation. So if multiple node load calls happen on the same page, the $types parameter is always set to what it was for the first call, and there are a bunch of phantom parameters added to the hook invocation that represent what should have been set on subsequent calls....

This patch fixes it and also provides a test.

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

pwolanin’s picture

This needs a code comment, and/or use some slightly more verbose code, like:

+   $this->hookLoadArguments = array();
    $this->hookLoadArguments[] = array_keys($typed_nodes);

or:

+   $this->hookLoadArguments = array();
-   $this->hookLoadArguments[] = array_keys($typed_nodes);
+   $this->hookLoadArguments[0] = array_keys($typed_nodes);

David_Rothstein’s picture

Here it is with a code comment, plus slight code changes similar to the above recommendation (so we explicitly set the hook to have exactly one additional parameter).

benshell’s picture

Status: Needs review » Reviewed & tested by the community

Looks good to me. I was just debugging through the code for this problem (which I experienced with a Webform as a block) and I found that the hookLoadArguments was the issue (causing the webform module's hook_node_load function not to work correctly). This patch solved the problem.

Dries’s picture

+++ modules/node/node.module	16 Aug 2010 20:18:32 -0000
@@ -3670,7 +3670,9 @@ class NodeController extends DrupalDefau
+    $this->hookLoadArguments = array(array_keys($typed_nodes));

Any reason why we store an array in an array?

David_Rothstein’s picture

-    $this->hookLoadArguments[] = array_keys($typed_nodes);
+    // Besides the list of nodes, pass one additional argument to
+    // hook_node_load(), containing a list of node types that were loaded.
+    $this->hookLoadArguments = array(array_keys($typed_nodes));

As shown in the full diff, it's the same array-within-an-array as before; and the reason is that hookLoadArguments is an array of arguments, but the argument we are putting in it is itself an array.

Possibly we could make it a bit more clear by defining $argument = array_keys($typed_nodes) beforehand and then doing $this->hookLoadArguments = array($argument) after that...?

Dries’s picture

So it is an array-within-an-array without keys? Not sure I understand why but I'll dig a bit deeper.

tom_o_t’s picture

webchick’s picture

Leaving this one for Dries.

David_Rothstein’s picture

Changed the patch to use a separate $argument variable, as per #5. I'm not sure we can make it any more clear than that :) In any case, it's preexisting code; this is just fixing a bug.

Should still be RTBC as long as the tests pass.

Dries’s picture

Status: Reviewed & tested by the community » Fixed

Committed to CVS HEAD. Thanks.

Status: Fixed » Closed (fixed)

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