Drupal tightens up node_load()

The other day we had an error on our Drupal 7 site where users would receive error messages whenever they tried to register for a conference. The site would register them, but the only thing the user would see is a JavaScript dialog box with an AJAX callback error message with some code in it; since the users didn't know that the site had registered them, they kept clicking the register button, getting registered multiple times. Not a desirable state of affairs.

Having only started here about a month ago, I was not very familiar with the site yet, but I was able to pinpoint the problem by running this code in the JavaScript console:

jQuery( document ).ajaxComplete(function( event, xhr, settings ) {
  console.log(event);
  console.log(xhr);
  console.log(settings);
});

The objects returned in the console gave me the clue I needed. xhr.responseText should have been a JSON string, but instead was the code from a template file--this was the file where the problem was. After further investigation, our Director of Web Development found that for some reason a node object wasn't getting loaded in this template file. This is the code that was supposed to load the node:

$event = node_load(array('nid' => intval($submission->data['1']['value'][0])));

See the problem? According to the online Drupal documentation, node_load is defined thusly:

node_load($nid = NULL, $vid = NULL, $reset = FALSE)

The node id ($nid) can't be passed to node_load() in an array; node_load() only accepts an integer! In Drupal 6, you were supposed to pass the node id in an array, but not in Drupal 7. To correct the problem, all we had to do is change the way the node id was being passed to node_load:

$event = node_load(intval($submission->data['1']['value'][0]));

Well, that solved the problem, but why had the script been working for an entire year when it had been passing the node id to the function incorrectly? Apparently, node_load() in Drupal 7 had been accepting node ids in an array (Drupal 6-style), even though this was not documented. And then in the Drupal 7.37 release in May 2015, they tightened things up. The Director of Web Development looked through the change log for the latest release and found that node_load() calls node_load_multiple(), which calls entity_load(), which calls DrupalDefaultEntityController::load. And buried in DrupalDefaultEntityController::load were a few new lines in the 7.37 release:

// Ensure integer entity IDs are valid.
if (!empty($ids)) {
  $this->cleanIds($ids);
}

The newly added lines ensured that the node ids would not work if passed into node_load() as an array. All of which just goes to show that just because your code works does not mean it is correct--and if it's not correct, then you never know when functions you depend on might be tightened up to only be used correctly.

Tags