You are here

productfield.inc in Commerce Webform 8

Same filename and directory in other branches
  1. 7.2 productfield.inc
  2. 7 productfield.inc

File

productfield.inc
View source
<?php

/**
 * @file
 * This defines the webform callbacks for the productfield
 * webform component.
 */
require_once drupal_get_path('module', 'webform') . '/components/select.inc';

/**
 * Implements _webform_defaults_component().
 */
function _webform_defaults_productfield() {
  return array(
    'name' => '',
    'form_key' => NULL,
    'mandatory' => 0,
    'pid' => 0,
    'weight' => 0,
    'value' => '',
    'extra' => array(
      'items' => '',
      'product_type' => '',
      'multiple' => NULL,
      'choose_quantity' => NULL,
      'aslist' => NULL,
      'optrand' => 0,
      'other_option' => NULL,
      'other_text' => t('Other...'),
      'title_display' => 0,
      'description' => '',
      'custom_keys' => FALSE,
      'options_source' => '',
      'private' => FALSE,
    ),
  );
}

/**
 * Implements _webform_edit_component().
 */
function _webform_edit_productfield($component) {
  $form = array();
  $items = isset($component['extra']['items']) && is_array($component['extra']['items']) ? $component['extra']['items'] : array();
  $product_ids = array();
  $skus = array();

  // Build an array of product IDs from this field's values.
  foreach ($items as $item) {
    $product_ids[] = $item['product_id'];
    $skus[] = $item['sku'];
  }
  $form['extra']['product_type'] = array(
    '#type' => 'select',
    '#multiple' => TRUE,
    '#options' => commerce_product_type_options_list(),
    '#title' => t('Product type'),
    '#default_value' => $component['extra']['product_type'],
    '#description' => t('Use either this OR the product skus field below. By selecting a product type here, all products of this type will be available for selection on the webform.'),
    '#weight' => 4,
  );
  $form['extra']['items'] = array(
    '#type' => 'textfield',
    '#title' => t('Product skus'),
    '#description' => t('Use this instead of setting a product type above. List the product skus you would like to offer as options on this webform. When the webform is saved, the user has that product added to thier basket.'),
    '#default_value' => implode(', ', $skus),
    '#autocomplete_path' => 'commerce_webform/autocomplete',
    '#size' => 128,
    '#maxlength' => 2048,
    '#element_validate' => array(
      '_webform_edit_validate_productfield',
    ),
    '#weight' => 5,
  );
  $form['value'] = array(
    '#type' => 'textfield',
    '#title' => t('Default sku'),
    '#default_value' => $component['value'],
    '#description' => t('Enter the product sku which should be selected by default or leave blank for no default. A token can be used here, e.g. [current-page:query:sku] to retrieve it from the URL query parameter sku.'),
    '#size' => 60,
    '#maxlength' => 1024,
    '#weight' => 3,
  );
  $form['extra']['choose_quantity'] = array(
    '#type' => 'checkbox',
    '#title' => t('Allow the user to set the quantity.'),
    '#default_value' => empty($component['extra']['choose_quantity']) ? 0 : $component['extra']['choose_quantity'],
    '#description' => t('Check this option if the user should be allowed to set the number of products selected. The default is 1 for single selections and 0 if it is possbile to select multiple products.'),
    '#weight' => 0,
  );
  $form['extra']['multiple'] = array(
    '#type' => 'checkbox',
    '#title' => t('Multiple'),
    '#default_value' => $component['extra']['multiple'],
    '#description' => t('Check this option if the user should be allowed to choose multiple values.'),
    '#weight' => 0,
  );
  $form['display']['aslist'] = array(
    '#type' => 'checkbox',
    '#title' => t('Listbox'),
    '#default_value' => $component['extra']['aslist'],
    '#description' => t('Check this option if you want the select component to be of listbox type instead of radio buttons or checkboxes.'),
    '#weight' => 0,
    '#parents' => array(
      'extra',
      'aslist',
    ),
  );
  return $form;
}

/**
 * Element validation callback. Ensure keys are not duplicated.
 */
function _webform_edit_validate_productfield($element, &$form_state) {

  // If a value was entered into the autocomplete...
  if (!empty($element['#value'])) {

    // Translate SKUs into product IDs.
    $typed_skus = drupal_explode_tags($element['#value']);
    $value = array();

    // Loop through all the entered SKUs...
    foreach ($typed_skus as $typed_sku) {

      // To see if the product actually exists...
      if ($product = commerce_product_load_by_sku(trim($typed_sku))) {

        // And store its product ID for later validation.
        $value[$product->product_id] = array(
          'product_id' => $product->product_id,
          'title' => $product->title,
          'sku' => $product->sku,
          'type' => $product->type,
        );
      }
    }
  }
  else {
    $value = array();
  }

  // Update the value of this element so the field can validate the product IDs.
  form_set_value($element, $value, $form_state);
}

/**
 * Implements _webform_render_component().
 */
function _webform_render_productfield($component, $value = NULL, $filter = TRUE) {
  $node = isset($component['nid']) ? node_load($component['nid']) : NULL;
  $product_ids = _webform_productfield_product_ids($component);
  return array(
    '#type' => 'webform_productfield',
    '#choose_quantity' => !empty($component['extra']['choose_quantity']),
    '#multiple' => !empty($component['extra']['multiple']),
    '#productids' => $product_ids,
    '#required' => !empty($component['required']),
    '#default_value' => isset($value) ? $value : _webform_filter_values($component['value'], NULL, NULL, NULL, FALSE),
    '#weight' => $component['weight'],
    '#aslist' => !empty($component['extra']['aslist']),
    '#name' => $filter ? _webform_filter_xss($component['name']) : $component['name'],
    '#description' => $filter ? _webform_filter_descriptions($component['extra']['description'], $node) : $component['extra']['description'],
    '#title_display' => $component['extra']['title_display'],
    '#theme_wrappers' => array(
      'webform_element',
    ),
    '#attached' => array(
      'js' => array(
        drupal_get_path('module', 'commerce_webform') . '/commerce_webform.js',
      ),
    ),
  );
}

/**
 * Form API #process function to expand a productfield.
 */
function _commerce_webform_productfield_expand($element) {
  $element += element_info('webform_productfield');
  $product_ids = empty($element['#productids']) ? array() : $element['#productids'];
  $choose_quantity = !empty($element['#choose_quantity']);
  $required = !empty($element['#required']);
  $value = $element['#default_value'];
  $aslist = !empty($element['#aslist']);
  $multiple = !empty($element['#multiple']);
  $name = $element['#name'];
  $description = $element['#description'];
  $title_display = !empty($element['#title_display']) ? $element['#title_display'] : 'before';

  // Each product should have a hidden element which describes it which allows
  // js to identify the products for possible dynamic total field.
  // @TODO Replace with RDFa.
  $hidden_elements_html = '';
  $options = array();
  if (!$multiple) {
    $options[''] = ' - ' . ($required ? t('Select') : t('None')) . ' - ';
  }
  $products = commerce_product_load_multiple($product_ids);
  foreach ($products as $product) {

    // Check if the product is active.
    if ($product->status == 1) {
      $price = commerce_product_calculate_sell_price($product);
      $options[$product->product_id] = theme('commerce_webform_product_display', array(
        'product' => $product,
        'price' => $price,
        'element' => $element,
      ));
      $hidden_elements_html .= "<input type='hidden' name='commerce_webform_product[{$product->product_id}]' value='{$price['amount']}' />\n";
    }
  }
  $default_product_ids = $multiple ? array() : 0;
  $default_quantities = $multiple ? array() : 1;
  $disabled = FALSE;
  if (is_array($value)) {

    // Load a previously saved value.
    foreach ($value as $id => $encoded_details) {
      $details = json_decode($encoded_details);
      if ($details->paid && !user_access('alter product field on paid webform')) {
        $disabled = TRUE;
      }
      if ($multiple) {
        $default_product_ids[] = $details->product_id;
        if ($choose_quantity) {
          $default_quantities[$details->product_id] = $details->quantity;
        }
        else {
          $default_quantities = $details->quantity;
        }
      }
      else {
        $default_product_ids = $details->product_id;
        $default_quantities = $details->quantity;
      }
    }
  }
  elseif (!empty($value)) {
    $defaults = explode(',', $value);
    foreach ($defaults as $default) {
      $product = commerce_product_load_by_sku(trim($default));
      if (!empty($product) && array_key_exists($product->product_id, $options)) {
        if ($multiple) {
          $default_product_ids[] = $product->product_id;
          $default_quantities[$product->product_id] = 1;
        }
        else {
          $default_product_ids = $product->product_id;
        }
      }
    }
  }
  if (!$multiple || !$choose_quantity) {

    // Single quantity options.
    if ($disabled) {

      // The product has been paid for so should not be able to change it.
      $rows = array();
      $element[] = array(
        '#type' => 'value',
        '#value' => $default_product_ids,
      );
      $element[] = array(
        '#type' => 'value',
        '#value' => $default_quantities,
      );
      if (is_array($default_product_ids)) {
        foreach ($default_product_ids as $product_id) {
          $rows[] = array(
            $product_id,
            $options[$product_id],
            $default_quantities,
          );
        }
      }
      elseif ($default_product_ids > 0) {
        $rows[] = array(
          $default_product_ids,
          $options[$default_product_ids],
          $default_quantities,
        );
      }

      // @TODO - put this in a theme function.
      $element['#markup'] = '<strong>' . $name . '</strong>';
      $element['#markup'] .= theme('table', array(
        'header' => array(
          t('Product ID'),
          t('Product name'),
          t('Quantity'),
        ),
        'rows' => $rows,
      ));
      $element['#markup'] .= '<p>' . t('This order has been completed and products choices cannot be edited online.') . '</p>';
    }
    else {
      $element[] = array(
        '#type' => $aslist ? 'select' : ($multiple ? 'checkboxes' : 'radios'),
        '#multiple' => $multiple,
        '#size' => $aslist && $multiple ? 4 : 0,
        '#title' => $name,
        '#title_display' => $title_display,
        '#required' => $required,
        '#description' => $description,
        '#translatable' => array(
          'title',
          'description',
          'options',
        ),
        '#options' => $options,
        '#default_value' => $default_product_ids,
        '#suffix' => $hidden_elements_html,
        '#pre_render' => array(),
        '#element_validate' => array(
          '_webform_productfield_selection_validate',
        ),
      );
      $editable = empty($multiple) && !empty($choose_quantity);
      $element[] = array(
        '#type' => $editable ? 'textfield' : 'value',
        '#title' => t('@product quantity', array(
          '@product' => $name,
        )),
        '#default_value' => $choose_quantity ? is_array($default_quantities) ? 1 : $default_quantities : 1,
        '#element_validate' => array(
          '_webform_productfield_quantity_validate',
        ),
        '#required' => $required,
        '#weight' => 1,
        '#attributes' => array(
          'class' => array(
            'productfield-quantity',
          ),
        ),
      );
    }
  }
  else {

    // Product field is multiple and user can choose quantity.
    $i = 1;
    if ($disabled) {
      $rows = array();
      foreach ($default_quantities as $product_id => $quantity) {
        $element[$product_id] = array(
          '#type' => 'value',
          '#value' => $quantity,
        );
        $rows[] = array(
          $product_id,
          $options[$product_id],
          $quantity,
        );
      }

      // @TODO - put this in a theme function.
      $element['#markup'] = '<strong>' . $name . '</strong>';
      $element['#markup'] .= theme('table', array(
        'header' => array(
          t('Product ID'),
          t('Product name'),
          t('Quantity'),
        ),
        'rows' => $rows,
      ));
      $element['#markup'] .= '<p>' . t('This order has been completed and products choices cannot be edited online.') . '</p>';
    }
    else {
      $element['multiple_product_quantities'] = array(
        '#type' => 'fieldset',
        '#title' => $name,
        '#title_display' => $title_display,
        '#element_validate' => array(
          '_webform_productfield_required_multiple_quantities_validate',
        ),
        '#required' => $required,
        '#weight' => 0,
        // Hide title as fieldsets don't support #title_display.
        '#pre_render' => array(
          'webform_element_title_display',
        ),
      );
      foreach ($options as $product_id => $product_name) {
        $element['multiple_product_quantities'][$product_id] = array(
          '#type' => 'textfield',
          '#title' => $product_name,
          '#title_display' => 'after',
          '#size' => 2,
          '#default_value' => isset($default_quantities[$product_id]) ? $default_quantities[$product_id] : 0,
          '#element_validate' => array(
            '_webform_productfield_quantity_validate',
          ),
          '#weight' => $i++,
        );
      }
    }
  }
  return $element;
}

/**
 * Implements _webform_display_component().
 */
function _webform_display_productfield($component, $value, $format = 'html') {
  $options = array();
  foreach ($component['extra']['items'] as $product_id => $details) {
    $options[$product_id] = "{$details['sku']}: {$details['title']} ";
  }
  return array(
    '#title' => $component['name'],
    '#weight' => $component['weight'],
    '#theme' => 'webform_display_productfield',
    '#theme_wrappers' => $format == 'html' ? array(
      'webform_element',
    ) : array(
      'webform_element_text',
    ),
    '#format' => $format,
    '#options' => $options,
    '#value' => (array) $value,
    '#translatable' => array(
      'title',
      'options',
    ),
  );
}

/**
 * Implements _webform_submit_component().
 * This executes when the webform is submitted by the user.
 * Convert FAPI 0/1 values into something saveable.
 */
function _webform_submit_productfield($component, $value) {
  $return = array();
  $multiple = $component['extra']['multiple'];
  $choose_quantity = !empty($component['extra']['choose_quantity']);
  if ($multiple && $choose_quantity) {
    foreach ($value['multiple_product_quantities'] as $product_id => $quantity) {
      if ($quantity > 0) {
        $details = array(
          'product_id' => $product_id,
          'quantity' => $quantity,
          'order_id' => FALSE,
          'line_item_id' => FALSE,
          'paid' => FALSE,
        );
        $return[] = json_encode($details);
      }
    }
  }
  else {
    if (is_array($value[0])) {
      foreach ($value[0] as $id => $product_id) {
        $details = array(
          'product_id' => $product_id,
          'quantity' => 1,
          'order_id' => FALSE,
          'line_item_id' => FALSE,
          'paid' => FALSE,
        );
        $return[] = json_encode($details);
      }
    }
    else {
      $details = array(
        'product_id' => $value[0],
        'quantity' => empty($value[0]) ? '0' : $value[1],
        'order_id' => FALSE,
        'line_item_id' => FALSE,
        'paid' => FALSE,
      );
      $return[] = json_encode($details);
    }
  }
  return $return;
}

/**
 * Format the text output for this component.
 */
function theme_webform_display_productfield($variables) {
  $element = $variables['element'];

  // Flatten the list of options so we can get values easily. These options
  // may be translated by hook_webform_display_component_alter().
  $options = $element['#options'];
  $items = array();
  foreach ($element['#value'] as $value) {
    $value = json_decode($value);

    // Administer provided values.
    if (!empty($value->product_id)) {
      if (isset($options[$value->product_id])) {
        $paid_display_option = empty($value->paid) ? t('Unpaid') : t('Paid');
        $paid_display_option = empty($value->order_id) ? $paid_display_option : l($paid_display_option, "admin/commerce/orders/{$value->order_id}/view");
        $name = _webform_filter_xss($options[$value->product_id]);
        $items[] = "{$value->quantity} x {$name} (<strong>{$paid_display_option}</strong>)";
      }
      else {
        $items[] = check_plain($value->product_id);
      }
    }
  }
  if ($element['#format'] == 'html') {
    $output = count($items) > 1 ? theme('item_list', array(
      'items' => $items,
    )) : (isset($items[0]) ? $items[0] : t('Not selected'));
  }
  else {
    if (count($items) > 1) {
      foreach ($items as $key => $item) {
        $items[$key] = ' - ' . $item;
      }
      $output = implode("\n", $items);
    }
    else {
      $output = isset($items[0]) ? $items[0] : t('Not selected');
    }
  }
  return $output;
}

/**
 * Implements _webform_analysis_component().
 */
function _webform_analysis_productfield($component, $sids = array(), $single = FALSE) {
  $query = db_select('webform_submitted_data', 'wsd', array(
    'fetch' => PDO::FETCH_ASSOC,
  ))
    ->fields('wsd', array(
    'data',
  ))
    ->condition('nid', $component['nid'])
    ->condition('cid', $component['cid'])
    ->condition('data', '', '<>')
    ->groupBy('data');
  if (count($sids)) {
    $query
      ->condition('sid', $sids, 'IN');
  }
  $results = $query
    ->execute();
  $rows = array();
  foreach ($results as $result) {
    $submission = json_decode($result['data']);
    if (isset($component['extra']['items'][$submission->product_id])) {
      $display_option = _webform_filter_xss($component['extra']['items'][$submission->product_id]['title']);

      // Update the paid count.
      $paid_display_option = !empty($submission->paid) ? 'Paid' : 'Unpaid';
      if (isset($rows[$submission->product_id . '_' . $paid_display_option])) {
        $rows[$submission->product_id . '_' . $paid_display_option]++;
      }
      else {
        $rows[$submission->product_id . '_' . $paid_display_option] = array(
          $display_option . ' (' . _webform_filter_xss(t($paid_display_option)) . ')',
          1,
        );
      }
    }
  }
  return $rows;
}

/**
 * Implements _webform_table_component().
 */
function _webform_table_productfield($component, $value) {

  // Convert submitted 'safe' values to un-edited, original form.
  $options = $component['extra']['items'];
  $value = (array) $value;
  $items = array();

  // Set the value as a single string.
  foreach ($value as $option_value) {
    $option_value = json_decode($option_value);
    if (!empty($option_value->product_id)) {
      if (isset($options[$option_value->product_id])) {
        $item = $option_value->quantity . ' x ' . _webform_filter_xss($options[$option_value->product_id]['title']);
      }
      else {
        $item = check_plain($option_value->product_id);
      }
      $paid_display_option = empty($option_value->paid) ? t('Unpaid') : t('Paid');
      $paid_display_option = empty($option_value->order_id) ? $paid_display_option : l($paid_display_option, "admin/commerce/orders/{$option_value->order_id}/view");
      $item .= " (<strong>{$paid_display_option}</strong>)";
      $items[] = $item;
    }
  }
  return implode('<br />', $items);
}

/**
 * Implements _webform_csv_headers_component().
 */
function _webform_csv_headers_productfield($component, $export_options) {
  $options = $component['extra']['items'];
  $headers = array(
    0 => array(),
    1 => array(),
    2 => array(),
  );
  $headers[0][] = '';
  $headers[1][] = '';
  foreach ($options as $product_id => $details) {
    $headers[2][] = $details['sku'] . ': PAID';
    $headers[2][] = $details['sku'] . ': UNPAID';
  }
  return $headers;
}

/**
 * Implements _webform_csv_data_component().
 */
function _webform_csv_data_productfield($component, $export_options, $values) {
  $options = $component['extra']['items'];
  foreach ($values as $id => $value) {
    $values[$id] = json_decode($value);
  }
  $return = array();
  foreach ($options as $key => $item) {
    $index = FALSE;
    foreach ($values as $value) {
      if ($value->product_id == $key) {
        $index = $value;
      }
    }
    if ($index !== FALSE) {
      if (!empty($index->paid)) {
        $return[] = $index->quantity;
        $return[] = '0';
      }
      else {
        $return[] = '0';
        $return[] = $index->quantity;
      }
    }
    else {
      $return[] = '0';
      $return[] = '0';
    }
  }
  return $return;
}

/**
 * Validate the user entered value in the quantity field.
 */
function _webform_productfield_quantity_validate($element, &$form_state, $form) {
  $value = $form_state['values'];
  foreach ($element['#parents'] as $parent) {
    $value = $value[$parent];
  }
  $name = implode('][', $element['#parents']);
  if (!isset($value) || empty($value)) {
    $value = 0;
  }
  if (!is_numeric($value)) {
    form_set_error($name, 'Quantity must be a number.');
  }
  elseif ($element['#required'] && $value < 1) {
    form_set_error($name, 'Quantity must be greater than 0.');
  }
  elseif ($element['#required'] && $value < 0) {
    form_set_error($name, 'Quantity must be a positive number or 0.');
  }
}

/**
 * Validate the user entered value in the quantity field.
 */
function _webform_productfield_selection_validate($element, &$form_state, $form) {
  if ($element['#required'] && $element['#multiple'] == '0') {
    $value = $form_state['values'];
    $name = '';
    foreach ($element['#parents'] as $index => $container) {
      $value = $value[$container];
      $name .= !empty($name) ? '][' : '';
      $name .= $element['#parents'][$index];
    }
    if (!isset($value[0]) || $value[0] < 1) {
      form_set_error($name, t('!name field is required', array(
        '!name' => $element['#title'],
      )));
    }
  }
}

/**
 * Validate a required multiple selection with quantity selection control.
 * At least one sub element must have a positivie quantity set.
 */
function _webform_productfield_required_multiple_quantities_validate($element, &$form_state, $form) {
  if ($element['#required']) {
    $value = $form_state['values'];
    foreach ($element['#parents'] as $parent) {
      $value = $value[$parent];
    }
    foreach ($value as $product_id => $quantity) {
      if ($quantity > 0) {

        // At least one element has a quantity set.
        return;
      }
    }
    $name = implode('][', $element['#parents']);
    form_set_error($name, t('You must choose at least one product from this selection by setting its quantity to something greater than 1'));
  }
}

/**
 * Theme of the product selection on the webform.
 */
function theme_commerce_webform_product_display($variables) {
  $product = $variables['product'];
  $price = $variables['price'];
  return filter_xss($product->title) . ' [' . commerce_currency_format($price['amount'], $price['currency_code'], $product) . ']';
}

/**
 * Get a list of all product ids of a given type(s).
 *
 * @param string|array $product_type
 *   A product_type string or an array of product type strings
 *
 * @return array
 *   An array of product ids.
 */
function _webform_productfield_product_ids_from_type($product_type) {
  $products_ids = array();
  $query = new EntityFieldQuery();
  $result = $query
    ->entityCondition('entity_type', 'commerce_product')
    ->entityCondition('bundle', $product_type)
    ->execute();
  if (!empty($result['commerce_product'])) {
    $product_ids = array_keys($result['commerce_product']);
  }
  return $product_ids;
}

/**
 * Get a list of all the product_ids available to choose from on a productfield.
 *
 * @param array $component
 *   A webform productfield component
 *
 * @return array
 *   An array of product ids. Note that if a product type is
 *   specified only, this will return an empty array.
 */
function _webform_productfield_product_ids($component) {
  $items = isset($component['extra']['items']) ? $component['extra']['items'] : array();
  $product_type = isset($component['extra']['product_type']) ? $component['extra']['product_type'] : '';
  $product_ids = array();

  // If a product type is set, load all the products for
  // that type.
  if (!empty($product_type)) {
    $product_ids = _webform_productfield_product_ids_from_type($product_type);
  }
  else {
    foreach ($items as $item) {
      $product_ids[] = $item['product_id'];
    }
  }
  return $product_ids;
}

/**
 * Define conditional operators for productfields.
 */
function _commerce_webform_conditional_operator_info() {
  $operators = array();
  $operators['productfield']['product_is'] = array(
    'label' => t('is a product'),
    'comparison callback' => 'webform_conditional_operator_product_is',
    'js comparison callback' => 'conditionalOperatorProductEqual',
    'form callback' => 'commerce_webform_conditional_product_select',
  );
  $operators['productfield']['product_is_not'] = array(
    'label' => t('is not a product'),
    'comparison callback' => 'webform_conditional_operator_product_is_not',
    'js comparison callback' => 'conditionalOperatorProductNotEqual',
    'form callback' => 'commerce_webform_conditional_product_select',
  );
  $operators['productfield']['product_is_of_type'] = array(
    'label' => t('is a product of type'),
    'comparison callback' => 'webform_conditional_operator_product_is_of_type',
    'js comparison callback' => 'conditionalOperatorProductOfType',
    'form callback' => 'commerce_webform_conditional_product_type_select',
    'comparison prepare js' => 'webform_conditional_prepare_productfield_type_js',
  );
  $operators['productfield']['product_is_not_of_type'] = array(
    'label' => t('is not a product of type'),
    'comparison callback' => 'webform_conditional_operator_product_is_not_of_type',
    'js comparison callback' => 'conditionalOperatorProductNotOfType',
    'form callback' => 'commerce_webform_conditional_product_type_select',
    'comparison prepare js' => 'webform_conditional_prepare_productfield_type_js',
  );
  $operators['productfield']['quantity_equals'] = array(
    'label' => t('total quantity is equal to'),
    'comparison callback' => 'webform_conditional_operator_product_quantity_equals',
    'js comparison callback' => 'conditionalOperatorProductQuantityEquals',
  );
  $operators['productfield']['quantity_less_than'] = array(
    'label' => t('total quantity is less than'),
    'comparison callback' => 'webform_conditional_operator_product_quantity_less_than',
    'js comparison callback' => 'conditionalOperatorProductQuantityLessThan',
  );
  $operators['productfield']['quantity_greater_than'] = array(
    'label' => t('total quantity is greater than'),
    'comparison callback' => 'webform_conditional_operator_product_quantity_greater_than',
    'js comparison callback' => 'conditionalOperatorProductQuantityGreaterThan',
  );
  return $operators;
}

/**
 * Prepare a conditional value for adding as a JavaScript setting.
 *
 * @param string $rule_value
 *   The rule value will be a product type (bundle).
 *
 * @return array
 *   An array of product ids which can be set on the productfield
 *   for this rule to trigger.
 */
function webform_conditional_prepare_productfield_type_js($rule_value) {
  return _webform_productfield_product_ids_from_type($rule_value);
}

/**
 * Webform conditional form callback.
 */
function commerce_webform_conditional_product_select($node) {
  $forms = array();
  webform_component_include('productfield');
  foreach ($node->webform['components'] as $cid => $component) {
    if (webform_component_property($component['type'], 'conditional_type') == 'productfield') {
      $options = array();
      $product_ids = _webform_productfield_product_ids($component);
      $products = commerce_product_load_multiple($product_ids);
      foreach ($products as $id => $product) {
        $options[$product->product_id] = $product->title;
      }
      $element = array(
        '#type' => 'select',
        '#multiple' => FALSE,
        '#size' => NULL,
        '#attributes' => array(),
        '#id' => NULL,
        '#name' => NULL,
        '#options' => $options,
        '#parents' => array(),
      );
      $forms[$cid] = drupal_render($element);
    }
  }
  return $forms;
}

/**
 * Webform conditional form callback.
 */
function commerce_webform_conditional_product_type_select($node) {
  $forms = array();
  webform_component_include('productfield');
  foreach ($node->webform['components'] as $cid => $component) {
    if (webform_component_property($component['type'], 'conditional_type') == 'productfield') {
      $options = commerce_product_type_options_list();
      $element = array(
        '#type' => 'select',
        '#multiple' => FALSE,
        '#size' => NULL,
        '#attributes' => array(),
        '#id' => NULL,
        '#name' => NULL,
        '#options' => $options,
        '#parents' => array(),
      );
      $forms[$cid] = drupal_render($element);
    }
  }
  return $forms;
}

/**
 * Webform conditionals comparison callback for product fields.
 */
function webform_conditional_operator_product_is($input_values, $rule_value) {
  $selected_products = _commerce_webform_get_selected_products_from_input_values($input_values);
  foreach ($selected_products as $product_id => $quantity) {
    if ($quantity > 0 && $product_id == $rule_value) {
      return TRUE;
    }
  }
  return FALSE;
}

/**
 * Webform conditionals comparison callback for product fields.
 */
function webform_conditional_operator_product_is_not($input_values, $rule_value) {
  return !webform_conditional_operator_product_is($input_values, $rule_value);
}

/**
 * Webform conditionals comparison callback for product fields.
 */
function webform_conditional_operator_product_quantity_equals($input_values, $rule_value) {
  return _commerce_webform_get_total_quantity_from_input_values($input_values) == $rule_value;
}

/**
 * Webform conditionals comparison callback for product fields.
 */
function webform_conditional_operator_product_quantity_less_than($input_values, $rule_value) {
  return _commerce_webform_get_total_quantity_from_input_values($input_values) < $rule_value;
}

/**
 * Webform conditionals comparison callback for product fields.
 */
function webform_conditional_operator_product_quantity_greater_than($input_values, $rule_value) {
  return _commerce_webform_get_total_quantity_from_input_values($input_values) > $rule_value;
}

/**
 * Webform conditionals comparison callback for product fields.
 */
function webform_conditional_operator_product_is_of_type($input_values, $rule_value) {
  $selected_products = _commerce_webform_get_selected_products_from_input_values($input_values);
  foreach ($selected_products as $product_id => $quantity) {
    if ($quantity > 0) {
      $product = commerce_product_load($product_id);
      if ($product->type == $rule_value) {
        return TRUE;
      }
    }
  }
  return FALSE;
}

/**
 * Webform conditionals comparison callback for product fields.
 */
function webform_conditional_operator_product_is_not_of_type($input_values, $rule_value) {
  return !webform_conditional_operator_product_is_of_type($input_values, $rule_value);
}

/**
 * Helper function for conditional callbacks.
 *
 * The input value format to a conditional callback changes depending
 * on the configuration of the component. This function normalises
 * the input to an array of selected product ids and quantities.
 *
 * @return array
 *   Keys are product ids, values are quantities.
 */
function _commerce_webform_get_selected_products_from_input_values(array $input_values) {
  if (!empty($input_values['multiple_product_quantities'])) {
    return $input_values['multiple_product_quantities'];
  }
  $selected_products = array();
  if (is_array($input_values[0])) {
    foreach ($input_values[0] as $product_id) {
      if ($product_id > 0) {
        $selected_products[$product_id] = 1;
      }
    }
  }
  else {
    $selected_products[$input_values[0]] = $input_values[1];
  }
  return $selected_products;
}

/**
 * Get the total quantity selected from input values.
 */
function _commerce_webform_get_total_quantity_from_input_values($input_values) {
  $selected_products = _commerce_webform_get_selected_products_from_input_values($input_values);
  $total = 0;
  foreach ($selected_products as $product_id => $quantity) {
    $total += $quantity;
  }
  return $total;
}

Functions

Namesort descending Description
commerce_webform_conditional_product_select Webform conditional form callback.
commerce_webform_conditional_product_type_select Webform conditional form callback.
theme_commerce_webform_product_display Theme of the product selection on the webform.
theme_webform_display_productfield Format the text output for this component.
webform_conditional_operator_product_is Webform conditionals comparison callback for product fields.
webform_conditional_operator_product_is_not Webform conditionals comparison callback for product fields.
webform_conditional_operator_product_is_not_of_type Webform conditionals comparison callback for product fields.
webform_conditional_operator_product_is_of_type Webform conditionals comparison callback for product fields.
webform_conditional_operator_product_quantity_equals Webform conditionals comparison callback for product fields.
webform_conditional_operator_product_quantity_greater_than Webform conditionals comparison callback for product fields.
webform_conditional_operator_product_quantity_less_than Webform conditionals comparison callback for product fields.
webform_conditional_prepare_productfield_type_js Prepare a conditional value for adding as a JavaScript setting.
_commerce_webform_conditional_operator_info Define conditional operators for productfields.
_commerce_webform_get_selected_products_from_input_values Helper function for conditional callbacks.
_commerce_webform_get_total_quantity_from_input_values Get the total quantity selected from input values.
_commerce_webform_productfield_expand Form API #process function to expand a productfield.
_webform_analysis_productfield Implements _webform_analysis_component().
_webform_csv_data_productfield Implements _webform_csv_data_component().
_webform_csv_headers_productfield Implements _webform_csv_headers_component().
_webform_defaults_productfield Implements _webform_defaults_component().
_webform_display_productfield Implements _webform_display_component().
_webform_edit_productfield Implements _webform_edit_component().
_webform_edit_validate_productfield Element validation callback. Ensure keys are not duplicated.
_webform_productfield_product_ids Get a list of all the product_ids available to choose from on a productfield.
_webform_productfield_product_ids_from_type Get a list of all product ids of a given type(s).
_webform_productfield_quantity_validate Validate the user entered value in the quantity field.
_webform_productfield_required_multiple_quantities_validate Validate a required multiple selection with quantity selection control. At least one sub element must have a positivie quantity set.
_webform_productfield_selection_validate Validate the user entered value in the quantity field.
_webform_render_productfield Implements _webform_render_component().
_webform_submit_productfield Implements _webform_submit_component(). This executes when the webform is submitted by the user. Convert FAPI 0/1 values into something saveable.
_webform_table_productfield Implements _webform_table_component().