Issue:
Custom PHP code when executed in a rule does not behave as expected. In fact, the same code when run in the Devel module's "Execute PHP" block provides the expected results.

Details:
There are three content types: Parent, Child and Actions. Both Parent and Child have node references to Actions. Parent has a node reference to Child.

The goal is to set up a system such that all Child nodes will inherit the Actions referenced within the Parent nodes. Therefore, the rule is triggered to execute custom PHP code on the condition that a Parent node is being saved.

Custom PHP Code

// Get all the associated actions in the parent category
$parent_assoc_action=$node->field_associate_actions;
$parent_assoc_category=$node->field_associate_categories;

// For each child, check if the parent's associated action is already present, update if not
foreach ($parent_assoc_category as $c) {
  $child_cat=node_load($c['nid']);
  $child_assoc_action=$child_cat->field_associate_actions;

  //need to compare arrays child_assoc_action and parent_assoc_action to see if there are any matches
  //make a copy
  $first_array_s = $parent_assoc_action;
  $second_array_s = $child_assoc_action;

  // serialize all sub-arrays
  array_walk($first_array_s,'my_serialize');
  array_walk($second_array_s,'my_serialize');

  // array_diff the serialized versions
  $diff = array_diff($first_array_s,$second_array_s);

  // unserialize the result
  array_walk($diff,'my_unserialize');

  //update child associated actions as needed
  $new_child_assoc_action=array_merge($child_assoc_action,$diff);
  $child_cat->field_associate_actions=$new_child_assoc_action;

  $child_cat=node_submit($child_cat);
  node_save($child_cat);
}

// functions to help process arrays before comparison
function my_serialize(&$arr,$pos){
  $arr = serialize($arr);
}
function my_unserialize(&$arr,$pos){
  $arr = unserialize($arr);
}

This code fails because it results in the referenced Actions of the Parent node being appended to the Actions of the Child regardless of whether the Child has any of the Actions referenced already. This results in duplicates.

However, if I copy the exact same code and run it in Devel's Execute PHP block (the only change being to execute a node_load at the beginning to load the Parent node into memory), it executes perfectly and updates the Child nodes only if the Parent's referenced Actions are not already present.

The code looks fine to me so I suspect there is something going on inside Rules that prevents the code from being executed properly. Any help would be much appreciated.

Comments

takinola’s picture

Component: Rules Core » Rules Engine

See comment below

takinola’s picture

Title: Custom PHP Code in Rules delivers different results than when executed in Devel » Custom PHP Code in Rules delivers different results than when executed in Devel - SOLVED
Status: Active » Fixed

I finally solved the mystery. The problem stems from the fact that in the devel "Execute PHP" block, the first command is to execute a node_load to load the parent node into memory. However, with Rules, there is no need to perform a node_load since Rules so graciously makes the $node variable available (hence the node_load command is omitted from the code above).

This introduces a subtle problem. The $node variable provided by Rules is not exactly the same $node variable you get from a node_load. There are some extra elements in the Rules version of $node (for example, one CCK field has an extra element named "_error_element"). Normally, this would never be an issue except in the case where you need to perform operations like array_diff where the array structure matters.

To solve my particular problem, I simply re-inserted the node_load at the beginning of the code to provide a fresh version of $node and all was once again fine with the world.

Status: Fixed » Closed (fixed)

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