This could be considered bad code in another module (commerce_cardonfile), but the root cause is from commerce_payment_method_instance_load() imho.

I've been creating, disabling, re-creating a bunch of payment processors.

Commerce CardOnFile attempts to load a payment instance_id which is associated with a cardonfile entry. Unfortunately that processor is now disabled, but cardonfile assumes it's still active and calls commerce_payment_method_instance_load(). CardOnFile correctly checks to see if anything is returned from this function and if nothing is returned it handles the code correctly, but unfortunately commerce_payment_method_instance_load throws an exception as it's code expects a rule to be associated with any properly formatted call to that function.

Here's the code in question:


function commerce_payment_method_instance_load($instance_id) {
  // Return FALSE if there is no pipe delimeter in the instance ID.   
  if (strpos($instance_id, '|') === FALSE) {
    return FALSE;    
  }   

  // Explode the method key into its component parts.  
  list($method_id, $rule_name) = explode('|', $instance_id);

  // Return FALSE if we didn't receive a proper instance ID.  
  if (empty($method_id) || empty($rule_name)) { 
    return FALSE;   
  } 

  // First load the payment method and add the instance ID.   
  $payment_method = commerce_payment_method_load($method_id);  
  $payment_method['instance_id'] = $instance_id;                                                                                           
                                                                                                                                           
  // Then load the Rule configuration that enables the method.      
  // NOTE: Loading a $rule_name which doesn't exists, return null or something.                                                                       
  $rule = rules_config_load($rule_name);  

  // Iterate over its actions to find one with the matching element ID and pull 
  // its settings into the payment method object.  
  $payment_method['settings'] = array();  

  // NOTE: can't call ->actions() on NULL.
  foreach ($rule->actions() as $action) { 

So a test should be made on to see if the rule could be loaded correctly and if it can't return nothing and don't call $rule->actions()

This could be fixed in cardonfile, but I think if you call a load function with an argument that can't be loaded, it should return nothing, instead of throwing a exception.

I'll cross reference my card on file bug, so you guys can figure out where the best place to resolve this issue would be.

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

j0rd’s picture

Status: Active » Needs review
FileSize
588 bytes

Here's patch.

rszrama’s picture

Title: commerce_payment_method_instance_load() throws exception when called with an invalid instance_id » Add rule configuration input validation to commerce_payment_method_instance_load()
Category: bug » task

Yeah, may as well solve this in CoF, since most of our functions (and Drupal's for that matter) typically expect to be passed good data. That said, this particular function does seem to do some input validation before processing it, so one more if statement can't hurt. Just doing some post-DrupalCon clean-up atm, but I'll come back around to commit this when I'm catchin' up.

mitrpaka’s picture

+1 for this.

commerce_payment_method_instance_load throws the very same exception at module installation time if you have hook_commerce_payment_method_info_alter() implemented (as rule does not yet exist at that very moment), e.g.

function xx_commerce_payment_method_info_alter(&$payment_methods) {

  // Load payment method settings
  $instance_id = ...
  $payment_method = commerce_payment_method_instance_load($instance_id);

To prevent this currently happening following check needs to added (before processing instance load):

$rule = rules_config_load('xx');
if (!empty($rule)) {
  // Load payment method settings
  $instance_id = ...
  $payment_method = commerce_payment_method_instance_load($instance_id);

...
rszrama’s picture

Status: Needs review » Fixed

Committed the patch in #1, and after reviewing you've said about the way CoF was using the API, I'm going to say it's a valid use that this function should have been supporting. Not going to bother with an issue to change the behavior in CoF.

Status: Fixed » Closed (fixed)

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