You are here

uc_dropdown_attributes.module in Dropdown Attributes 6

Same filename and directory in other branches
  1. 8 uc_dropdown_attributes.module
  2. 7 uc_dropdown_attributes.module

Show/hide attributes based on the values of other attributes.

Some attributes may not be applicable depending upon the value of another attribute. It may be desireable to hide the attribute unless an appropriate value is selected for the other attribute to avoid confusing users. This module has an administrative interface for specifying the dependencies and Javascript code for hiding and showing the attributes.

File

uc_dropdown_attributes.module
View source
<?php

/**
 * @file
 * Show/hide attributes based on the values of other attributes.
 *
 * Some attributes may not be applicable depending upon the value of another
 * attribute.  It may be desireable to hide the attribute unless an appropriate
 * value is selected for the other attribute to avoid confusing users.  This
 * module has an administrative interface for specifying the dependencies
 * and Javascript code for hiding and showing the attributes.
 */

/**
 * Implement hook_menu().
 */
function uc_dropdown_attributes_menu() {
  $items = array();
  $items['node/%node/edit/dependencies'] = array(
    'title' => 'Dependencies',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'uc_dropdown_attributes_product',
      1,
    ),
    'access callback' => 'uc_attribute_product_access',
    'access arguments' => array(
      1,
    ),
    'type' => MENU_LOCAL_TASK,
    'weight' => 1,
    'file' => 'dependent_dropdown.inc',
  );
  $items['dropdown/dependencies/%/callback'] = array(
    'type' => MENU_CALLBACK,
    'page callback' => 'uc_dropdown_attributes_edit_callback',
    'page arguments' => array(
      2,
    ),
    'access callback' => TRUE,
    'file' => 'dependent_dropdown.inc',
  );
  $items['node/%/dependencies/%/dependency'] = array(
    'type' => MENU_CALLBACK,
    'page callback' => 'uc_dropdown_attributes_dependency',
    'page arguments' => array(
      1,
      3,
    ),
    'access callback' => TRUE,
  );
  $items['node/%/dependencies/%/activate'] = array(
    'type' => MENU_CALLBACK,
    'page callback' => 'uc_dropdown_attributes_activate',
    'page arguments' => array(
      1,
      3,
    ),
    'access callback' => TRUE,
  );
  $items['admin/store/products/classes/%/dependencies'] = array(
    'title' => 'Dependencies',
    'description' => 'Product class attribute dependency administration.',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'uc_dropdown_attributes_class',
      4,
    ),
    'access arguments' => array(
      'administer product classes',
    ),
    'type' => MENU_LOCAL_TASK,
    'weight' => 1,
    'file' => 'dependent_dropdown.inc',
  );
  return $items;
}

/**
 * Implement hook_init().
 */
function uc_dropdown_attributes_init() {
  drupal_add_css(drupal_get_path('module', 'uc_dropdown_attributes') . '/uc_dropdown_attributes.css');
}

/**
 * Implements hook_form_alter().
 */
function uc_dropdown_attributes_form_alter(&$form, &$form_state, $form_id) {
  if (preg_match('/^uc_product_kit_add_to_cart_form.*/', $form_id)) {
    foreach ($form['products'] as $key => $value) {
      if (is_numeric($key)) {
        $type = uc_dropdown_attributes_dependency_type($key);
        if (!is_null($type)) {
          uc_dropdown_attributes_product_alter($key, $form['products'][$key]['attributes'], $type);

          // Make sure these have not been added more than once.
          if (!isset($form['#validate']) || !in_array('uc_dropdown_attributes_validate', $form['#validate'])) {
            $form['#validate'][] = 'uc_dropdown_attributes_validate';
          }
          if (!isset($form['#after_build']) || !in_array('uc_dropdown_attributes_build', $form['#after_build'])) {
            $form['#after_build'][] = 'uc_dropdown_attributes_build';
          }
        }
      }
    }
  }
  if (preg_match('/^uc_product_add_to_cart_form.*/', $form_id)) {
    $nid = $form['nid']['#value'];
    $type = uc_dropdown_attributes_dependency_type($nid);
    if (!is_null($type)) {
      uc_dropdown_attributes_product_alter($nid, $form['attributes'], $type);
      $form['node_id'] = array(
        '#type' => 'hidden',
        '#value' => $nid,
      );
      $form['#after_build'][] = 'uc_dropdown_attributes_build';
      $form['#validate'][] = 'uc_dropdown_attributes_validate';
    }
  }
}

/**
 * Alter products in preparation for drop down attributes.
 */
function uc_dropdown_attributes_product_alter($nid, &$form_attributes, $type) {
  switch ($type) {
    case 'node':
      $sql = 'SELECT aid, required FROM {uc_dropdown_attributes} WHERE nid=%d';
      $attributes = db_query($sql, $nid);
      break;
    case 'class':
      $sql = 'SELECT aid, required FROM {uc_dropdown_classes} WHERE pcid=%d';
      $pcid = uc_dropdown_attributes_get_type($nid);
      $attributes = db_query($sql, $pcid);
      break;
  }
  while ($attribute = db_fetch_object($attributes)) {
    if ($attribute->required) {
      switch ($form_attributes[$attribute->aid]['#type']) {
        case 'select':
          if (count($form_attributes[$attribute->aid]['#options'])) {
            $form_attributes[$attribute->aid]['#options'] = array(
              '' => t('Please select'),
            ) + $form_attributes[$attribute->aid]['#options'];
            unset($form_attributes[$attribute->aid]['#default_value']);
          }
          break;
        case 'radios':
          if (count($form_attributes[$attribute->aid]['#options'])) {
            unset($form_attributes[$attribute->aid]['#default_value']);
          }
          break;
        case 'textfield':
          unset($form_attributes[$attribute->aid]['#default_value']);
          break;
        default:
      }
    }
  }
}

/**
 * Adds Javascript to the product pages.
 */
function uc_dropdown_attributes_build($form, &$form_state) {
  drupal_add_js(array(
    'uc_dropdown_attributes' => array(
      'cleanUrl' => variable_get('clean_url', 0),
    ),
  ), 'setting');
  drupal_add_js(drupal_get_path('module', 'uc_dropdown_attributes') . '/displayfields.js');
  return $form;
}

/**
 * Retrieves the attribute dependencies.
 */
function uc_dropdown_attributes_dependency($nid, $aid) {
  $result = new stdClass();
  $type = uc_dropdown_attributes_dependency_type($nid);
  if (is_null($type)) {
    $result->status = FALSE;
    drupal_json($result);
    return;
  }
  switch ($type) {
    case 'node':
      $query = 'SELECT parent_aid, parent_values, required
        FROM {uc_dropdown_attributes} WHERE nid=%d && aid=%d';
      $item = db_fetch_object(db_query($query, $nid, $aid));
      break;
    case 'class':
      $pcid = uc_dropdown_attributes_get_type($nid);
      $query = 'SELECT parent_aid, parent_values, required
        FROM {uc_dropdown_classes} WHERE pcid=%d && aid=%d';
      $item = db_fetch_object(db_query($query, $pcid, $aid));
      break;
  }
  if (!$item) {
    $result->status = FALSE;
    drupal_json($result);
  }
  else {
    $result->status = TRUE;
    $result->aid = $aid;
    $result->parent_aid = $item->parent_aid;
    $result->parent_values = unserialize($item->parent_values);
    $result->required = $item->required;
    drupal_json($result);
  }
}

/**
 * Retrieves the attribute dependencies.
 */
function uc_dropdown_attributes_activate($nid, $aid) {
  $response = new stdClass();
  $response->aid = array();
  $response->parent_aid = $aid;
  $response->nid = $nid;
  $query = 'SELECT aid FROM {uc_dropdown_attributes}
    WHERE nid=%d && parent_aid=%d';
  $result = db_query($query, $nid, $aid);
  while ($item = db_fetch_object($result)) {
    $response->aid[] = $item->aid;
  }
  if (count($response->aid) > 0) {
    $response->status = TRUE;
    drupal_json($response);
    return;
  }
  $pcid = uc_dropdown_attributes_get_type($nid);
  $query = 'SELECT aid FROM {uc_dropdown_classes}
    WHERE pcid=%d && parent_aid=%d';
  $result = db_query($query, $pcid, $aid);
  while ($item = db_fetch_object($result)) {
    $response->aid[] = $item->aid;
  }
  if (count($response->aid) > 0) {
    $response->status = TRUE;
    drupal_json($response);
    return;
  }
  $response->status = FALSE;
  drupal_json($response);
}

/**
 * Handles the validation of required fields.
 */
function uc_dropdown_attributes_validate($form, &$form_state) {
  if (preg_match('/^uc-product-kit-add-to-cart-form.*/', $form['#id'])) {
    foreach ($form['products'] as $key => $value) {
      if (is_numeric($key)) {
        $sql = 'SELECT aid, parent_aid, parent_values FROM {uc_dropdown_attributes}
          WHERE required=1 AND nid=%d';
        $result = db_query($sql, $key);
        while ($item = db_fetch_object($result)) {
          $values = unserialize($item->parent_values);
          if (is_array($form_state['values']['products'][$key]['attributes'][$item->parent_aid])) {
            if (count(array_intersect($values, $form_state['values']['products'][$key]['attributes'][$item->parent_aid])) > 0) {
              uc_dropdown_attributes_attribute_value_check($item->aid, $form_state['values']['products'][$key]['attributes'][$item->aid]);
            }
          }
          else {
            if (in_array($form_state['values']['products'][$key]['attributes'][$item->parent_aid], $values)) {
              uc_dropdown_attributes_attribute_value_check($item->aid, $form_state['values']['products'][$key]['attributes'][$item->aid]);
            }
          }
        }
      }
    }
  }
  else {
    $sql = 'SELECT aid, parent_aid, parent_values FROM {uc_dropdown_attributes}
      WHERE required=1 AND nid=%d';
    $result = db_query($sql, $form_state['values']['nid']);
    while ($item = db_fetch_object($result)) {
      $values = unserialize($item->parent_values);
      if (is_array($form_state['values']['attributes'][$item->parent_aid])) {
        if (count(array_intersect($values, $form_state['values']['attributes'][$item->parent_aid])) > 0) {
          uc_dropdown_attributes_attribute_value_check($item->aid, $form_state['values']['attributes'][$item->aid]);
        }
      }
      else {
        if (in_array($form_state['values']['attributes'][$item->parent_aid], $values)) {
          uc_dropdown_attributes_attribute_value_check($item->aid, $form_state['values']['attributes'][$item->aid]);
        }
      }
    }
  }
}
function uc_dropdown_attributes_attribute_value_check($aid, $values) {
  if (is_array($values)) {
    if (count(array_filter($values, 'nonzero')) == 0) {
      $attribute = uc_attribute_load($aid);
      form_set_error('attributes][' . $aid, $attribute->label . ' ' . t('field is required'));
    }
  }
  else {
    if ($values == '') {
      $attribute = uc_attribute_load($aid);
      form_set_error('attributes][' . $aid, $attribute->label . ' ' . t('field is required'));
    }
  }
}
function nonzero($var) {
  return $var != 0;
}

/**
 * Create an attribute dependency.
 *
 * A public function that creates and stores an attribute dependency for a
 * product.
 *
 * @param $nid
 *   Node ID.
 * @param $aid
 *   Attribute ID of the dependent (child) attribute.
 * @param $parent_aid
 *   Attribute ID of the parent attribute.
 * @param array $options
 *   Array of the Option IDs that trigger the dependent attribute.
 * @param bool $required
 *   TRUE if the dependent (child) attribute is required when it appears and
 *   FALSE if it is not required.
 *
 * @return boolean
 *   TRUE if attribute dependency is saved; otherwise, FALSE.
 */
function uc_dropdown_attributes_product_create_dependency($nid, $aid, $parent_aid, $options, $required) {
  $record = new stdClass();
  $record->nid = $nid;
  $record->aid = $aid;
  $record->parent_aid = $parent_aid;
  $record->parent_values = serialize($options);
  $record->required = $required;
  $success = drupal_write_record('uc_dropdown_attributes', $record);

  // Need to check to make sure attribute is not required all the time
  $query = 'SELECT nid, aid, required FROM {uc_product_attributes}
    WHERE nid=%d AND aid=%d';
  $result = db_query($query, $nid, $aid);
  $item = db_fetch_object($result);
  if ($item->required == 1) {
    $record = new stdClass();
    $record->nid = $item->nid;
    $record->aid = $item->aid;
    $record->required = 0;
    drupal_write_record('uc_product_attributes', $record, array(
      'nid',
      'aid',
    ));
  }
  return $success;
}

/**
 * Create an attribute dependency for product classes.
 *
 * A public function that creates and stores an attribute dependency for
 * product classes.
 *
 * @param $pcid
 *   Product class ID.
 * @param $aid
 *  Attribute ID of the dependent (child) attribute.
 * @param $parent_aid
 *   Attribute ID of the parent attribute.
 * @param array $options
 *   Array of the Option IDs that trigger the dependent attribute.
 * @param bool $required
 *  TRUE if the dependent (child) attribute is required when it appears and
 *  FALSE if it is not required.
 */
function uc_dropdown_attributes_class_create_dependency($pcid, $aid, $parent_aid, $options, $required) {
  $record = new stdClass();
  $record->pcid = $pcid;
  $record->aid = $aid;
  $record->parent_aid = $parent_aid;
  $record->parent_values = serialize($options);
  $record->required = $required;
  $success = drupal_write_record('uc_dropdown_classes', $record);

  // Need to check to make sure attribute is not required all the time
  $query = 'SELECT pcid, aid, required FROM {uc_class_attributes}
    WHERE pcid="%s" AND aid=%d';
  $result = db_query($query, $pcid, $aid);
  $item = db_fetch_object($result);
  if ($item->required == 1) {
    $record = new stdClass();
    $record->pcid = $item->pcid;
    $record->aid = $item->aid;
    $record->required = 0;
    drupal_write_record('uc_class_attributes', $record, array(
      'pcid',
      'aid',
    ));
  }
  return $success;
}

/**
 * Retrieve product class from the node ID.
 */
function uc_dropdown_attributes_get_type($nid) {
  $sql = 'SELECT type FROM {node} WHERE nid=%d';
  $type = db_result(db_query($sql, $nid));
  return $type;
}

/**
 * Retrieve whether dependencies are defined by node or class.
 */
function uc_dropdown_attributes_dependency_type($nid) {
  $sql = 'SELECT COUNT(*) FROM {uc_dropdown_attributes} WHERE nid=%d';
  $count = db_result(db_query($sql, $nid));
  if ($count > 0) {
    return 'node';
  }
  $pcid = uc_dropdown_attributes_get_type($nid);
  $sql = 'SELECT COUNT(*) FROM {uc_dropdown_classes} WHERE pcid="%s"';
  $count = db_result(db_query($sql, $pcid));
  if ($count > 0) {
    return 'class';
  }
  return NULL;
}

/**
 * Implements hook_nodeapi().
 */
function uc_dropdown_attributes_nodeapi(&$node, $op, $a3 = NULL, $a4 = NULL) {
  switch ($op) {
    case 'load':
      if (isset($node->attributes)) {
        foreach ($node->attributes as $aid => $attribute) {
          $sql = 'SELECT required FROM {uc_dropdown_attributes}
            WHERE nid=%d AND aid=%d';
          $required = db_result(db_query($sql, $node->nid, $aid));
          if ($required) {
            $node->attributes[$aid]->default_option = '';
          }
        }
      }
      break;
  }
}

Functions

Namesort descending Description
nonzero
uc_dropdown_attributes_activate Retrieves the attribute dependencies.
uc_dropdown_attributes_attribute_value_check
uc_dropdown_attributes_build Adds Javascript to the product pages.
uc_dropdown_attributes_class_create_dependency Create an attribute dependency for product classes.
uc_dropdown_attributes_dependency Retrieves the attribute dependencies.
uc_dropdown_attributes_dependency_type Retrieve whether dependencies are defined by node or class.
uc_dropdown_attributes_form_alter Implements hook_form_alter().
uc_dropdown_attributes_get_type Retrieve product class from the node ID.
uc_dropdown_attributes_init Implement hook_init().
uc_dropdown_attributes_menu Implement hook_menu().
uc_dropdown_attributes_nodeapi Implements hook_nodeapi().
uc_dropdown_attributes_product_alter Alter products in preparation for drop down attributes.
uc_dropdown_attributes_product_create_dependency Create an attribute dependency.
uc_dropdown_attributes_validate Handles the validation of required fields.