You are here

function _commerce_cart_matching_products in Commerce Core 7

Returns an array of products matching a set of attribute values.

Parameters

$products: An array of product objects.

$form_state: The $form_state from an Add to Cart form.

1 call to _commerce_cart_matching_products()
commerce_cart_add_to_cart_form in modules/cart/commerce_cart.module
Builds an Add to Cart form for a set of products.

File

modules/cart/commerce_cart.module, line 1733
Implements the shopping cart system and add to cart features.

Code

function _commerce_cart_matching_products($products, &$form_state) {
  $matching_products = array();

  // If the form state contains attribute data...
  if (!empty($form_state['values']['attributes'])) {
    $changed_attribute = NULL;
    $attributes = (array) array_diff_key($form_state['values']['attributes'], array(
      'product_select' => '',
    ));
    $unchanged_attributes = $form_state['values']['unchanged_attributes'];

    // Get the changed attribute.
    foreach ($attributes as $attribute_name => $attribute_value) {

      // If this is the attribute widget that was changed...
      if ($attribute_value != $unchanged_attributes[$attribute_name]) {

        // Store the field name.
        $changed_attribute = $attribute_name;

        // Clear the input for the "Select a product" widget now if it
        // exists on the form since we know an attribute was changed.
        unset($form_state['input']['attributes']['product_select']);

        // We found the changed attribute so we're done.
        break;
      }
    }

    // If we found a changed attribute and it's not already in the first
    // position of the array.
    if (!empty($changed_attribute) && array_search($changed_attribute, array_keys($attributes))) {

      // Move the changed attribute to the first position of the array so it's
      // handled first.
      $attributes = array(
        $changed_attribute => $attributes[$changed_attribute],
      ) + $attributes;
    }

    // Create a list of all products associated with each attribute for
    // filtering.
    $attributes_products = array_fill_keys(array_keys($attributes), array());
    foreach ($products as $product_id => $product) {

      // Store which attributes this product is associated with.
      foreach ($attributes as $attribute_name => $attribute_value) {
        $product_attribute_items = field_get_items('commerce_product', $product, $attribute_name);
        $product_attribute_value = reset($product_attribute_items[0]);
        if ($product_attribute_value == $attribute_value) {
          $attributes_products[$attribute_name][$product_id] = $product;
        }
      }
    }

    // Filter out products starting with those not associated with the changed
    // attribute and proceeding with those not associated with other attributes
    // in the order the attributes appear in the form.
    $matching_products = array_shift($attributes_products);
    foreach ($attributes_products as $attribute_name => $attribute_products) {
      $filtered_products = array_intersect_key($matching_products, $attribute_products);

      // If all products have been filtered out, use the set of products prior
      // to filtering on the current attribute.
      if (!empty($filtered_products)) {
        $matching_products = $filtered_products;
      }
      else {
        break;
      }
    }

    // Only accept the first matching product and subsequent matching products
    // with identical attribute values.
    if (count($matching_products) > 1) {
      $default_product = reset($matching_products);
      unset($matching_products[key($matching_products)]);
      $default_products[$default_product->product_id] = $default_product;
      foreach ($matching_products as $matching_product_id => $matching_product) {
        foreach ($attributes as $attribute_name => $attribute_value) {
          $matching_product_attribute_items = field_get_items('commerce_product', $matching_product, $attribute_name);
          $matching_product_attribute_value = reset($matching_product_attribute_items[0]);
          $default_product_attribute_items = field_get_items('commerce_product', $default_product, $attribute_name);
          $default_product_attribute_value = reset($default_product_attribute_items[0]);
          if ($matching_product_attribute_value != $default_product_attribute_value) {
            continue 2;
          }
        }
        $default_products[$matching_product_id] = $matching_product;
      }
      $matching_products = $default_products;
    }
  }
  return $matching_products;
}