uc_dropdown_attributes.module in Dropdown Attributes 7
Same filename and directory in other branches
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.moduleView 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.
*/
/**
* Implements hook_menu().
*/
function uc_dropdown_attributes_menu() {
$items = array();
$items['node/%node/edit/dependencies'] = array(
'title' => 'Dependencies',
'description' => 'Product attribute dependency administration.',
'page callback' => 'drupal_get_form',
'page arguments' => array(
'uc_dropdown_attributes_product',
1,
),
'access callback' => 'uc_attribute_product_access',
'access arguments' => array(
1,
),
'theme callback' => 'uc_dropdown_attributes_admin_theme',
'type' => MENU_LOCAL_TASK,
'weight' => 1,
'file' => 'dependent_dropdown.inc',
);
$items['node/%/dependencies/%/dependency/%'] = array(
'type' => MENU_CALLBACK,
'page callback' => 'uc_dropdown_attributes_dependency',
'page arguments' => array(
1,
3,
5,
),
'access callback' => TRUE,
);
$items['admin/store/products/classes/%/dependencies'] = array(
'title' => 'Dependencies',
'description' => 'Product class attribute dependency administration.',
'type' => MENU_LOCAL_TASK,
'page callback' => 'drupal_get_form',
'page arguments' => array(
'uc_dropdown_attributes_class',
4,
),
'access arguments' => array(
'administer product classes',
),
'file' => 'dependent_dropdown.inc',
);
return $items;
}
/**
* 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)) {
if (isset($form_state['values'])) {
$values = $form_state['values'];
}
else {
$values = array();
}
uc_dropdown_attributes_product_alter($key, $form['products'][$key], $values, $type, $form_state['rebuild']);
// Make sure these have not been added more than once.
if (!isset($form['#after_build']) || !in_array('_uc_dropdown_attributes_kit_build', $form['#after_build'])) {
$form['#after_build'][] = '_uc_dropdown_attributes_kit_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)) {
if (isset($form_state['values'])) {
$values = $form_state['values'];
}
else {
$values = array();
}
uc_dropdown_attributes_product_alter($nid, $form, $values, $type, $form_state['rebuild']);
$form['node_id'] = array(
'#type' => 'hidden',
'#value' => $nid,
);
switch ($type) {
case 'node':
$form['#after_build'][] = '_uc_dropdown_attributes_product_build';
break;
case 'class':
$form['#after_build'][] = '_uc_dropdown_attributes_class_build';
break;
}
}
}
}
/**
* Alter products in preparation for drop down attributes.
*
* Adds the 'Please select' and removes the default value. Ubercart does this
* for required attributes but since these attributes can no longer be required
* if the attributes are dependent then this reproduces the same thing.
*
* @param int $nid
* Node ID.
* @param array $form
* Product form.
* @param array $form_values
* Values from $form_state.
* @param string $type
* 'node' for dependencies defined on the node level; 'class' for dependencies
* defined on the product class.
* @param bool $rebuild
* Whether the form is being rebuilt.
*/
function uc_dropdown_attributes_product_alter($nid, &$form, $form_values, $type, $rebuild) {
switch ($type) {
case 'node':
$sql = 'SELECT aid, parent_aid, parent_values, required
FROM {uc_dropdown_attributes}
WHERE nid=:nid';
$attributes = db_query($sql, array(
':nid' => $nid,
));
break;
case 'class':
$sql = 'SELECT aid, parent_aid, parent_values, required
FROM {uc_dropdown_classes}
WHERE pcid=:pcid';
$pcid = uc_dropdown_attributes_get_type($nid);
$attributes = db_query($sql, array(
':pcid' => $pcid,
));
break;
}
$parent_aids = array();
if (!$rebuild) {
$data = $form['node']['#value']->data;
}
$load = FALSE;
foreach ($attributes as $attribute) {
$parent_aids[$attribute->parent_aid] = $attribute->parent_aid;
if (isset($form['attributes'][$attribute->aid]['#options']) && count($form['attributes'][$attribute->aid]['#options']) && $attribute->required) {
switch ($form['attributes'][$attribute->aid]['#type']) {
case 'select':
$form['attributes'][$attribute->aid]['#options'] = array(
'' => t('Please select'),
) + $form['attributes'][$attribute->aid]['#options'];
$form['attributes'][$attribute->aid]['#default_value'] = '';
if (!$rebuild && isset($data['attributes'][$attribute->aid])) {
$data['attributes'][$attribute->aid] = '';
$load = TRUE;
}
break;
case 'radios':
$form['attributes'][$attribute->aid]['#default_value'] = NULL;
if (!$rebuild && isset($data['attributes'][$attribute->aid])) {
$data['attributes'][$attribute->aid] = '';
$load = TRUE;
}
// Validation does not work if required set later.
if (isset($form_values['attributes'][$attribute->parent_aid])) {
$parent_value = $form_values['attributes'][$attribute->parent_aid];
$values = unserialize($attribute->parent_values);
$parent_aid = $attribute->parent_aid;
if (in_array($parent_value, $values)) {
$form['attributes'][$attribute->aid]['#required'] = TRUE;
}
}
break;
case 'checkboxes':
$form['attributes'][$attribute->aid]['#default_value'] = array();
if (!$rebuild && isset($data['attributes'][$attribute->aid])) {
$data['attributes'][$attribute->aid] = array();
$load = TRUE;
}
break;
}
}
}
if ($load) {
$form['node']['#value'] = uc_product_load_variant($nid, $data);
}
$update_node = variable_get('uc_product_update_node_view', 0);
if (!$update_node) {
// If Ubercart update is not enabled then ajax needs to be attached to
// parent attributes.
foreach ($parent_aids as $aid) {
$form['attributes'][$aid]['#ajax'] = array(
'callback' => 'uc_dropdown_attributes_ajax_callback',
'wrapper' => $form['attributes']['#id'],
);
}
}
}
/**
* Ajax callback for attribute selection form elements.
*/
function uc_dropdown_attributes_ajax_callback($form, $form_state) {
if (count($form_state['triggering_element']['#parents']) == 4) {
// This is a product kit.
$key = $form_state['triggering_element']['#parents'][1];
return $form['products'][$key]['attributes'];
}
return $form['attributes'];
}
/**
* Form build for products.
*
* Callback for $form['#after_build'] for products. Adds the CSS to hide
* the dependent attributes.
*/
function _uc_dropdown_attributes_product_build($form, &$form_state) {
$nid = $form['nid']['#value'];
$sql = 'SELECT aid, parent_aid, parent_values, required
FROM {uc_dropdown_attributes} WHERE nid=:nid';
$attributes = db_query($sql, array(
':nid' => $nid,
));
if (isset($form_state['triggering_element'])) {
$parents = $form_state['triggering_element']['#parents'];
$parent_aid = $parents[count($parents) - 1];
$parent_value = $form_state['triggering_element']['#value'];
uc_dropdown_attributes_remove_values($parent_aid, $parent_value, $nid, 'node', $form_state['values']);
}
foreach ($attributes as $attribute) {
$parent_value = $form_state['values']['attributes'][$attribute->parent_aid];
if ($form['attributes'][$attribute->parent_aid]['#type'] == 'checkboxes') {
$parent_values = array_diff($parent_value, array(
0,
));
$values = unserialize($attribute->parent_values);
if (count(array_intersect($parent_values, $values))) {
// Show dependent attribute.
if ($attribute->required) {
$form['attributes'][$attribute->aid]['#required'] = TRUE;
}
}
else {
// Hide dependent attribute.
$form['attributes'][$attribute->aid]['#post_render'][] = 'uc_dropdown_attributes_post_render';
if ($attribute->required) {
uc_dropdown_attributes_clear_input($form, $form_state, $attribute->aid);
}
}
}
else {
if ($parent_value) {
// A value has been entered in parent attribute.
$values = unserialize($attribute->parent_values);
if (array_key_exists($parent_value, $values)) {
// Show dependent attribute.
if ($attribute->required) {
$form['attributes'][$attribute->aid]['#required'] = TRUE;
}
}
else {
// Hide dependent attribute.
$form['attributes'][$attribute->aid]['#post_render'][] = 'uc_dropdown_attributes_post_render';
if ($attribute->required) {
uc_dropdown_attributes_clear_input($form, $form_state, $attribute->aid);
}
}
}
else {
$form['attributes'][$attribute->aid]['#post_render'][] = 'uc_dropdown_attributes_post_render';
if ($attribute->required) {
uc_dropdown_attributes_clear_input($form, $form_state, $attribute->aid);
}
}
}
}
return $form;
}
/**
* Clear inputs for attribute.
*
* @param array $form
* Form array.
* @param array $form_state
* Form state array.
* @param int $aid
* Attribute ID.
*/
function uc_dropdown_attributes_clear_input(&$form, &$form_state, $aid) {
switch ($form['attributes'][$aid]['#type']) {
case 'checkboxes':
if (isset($form_state['input']['attributes'])) {
foreach ($form_state['input']['attributes'][$aid] as $oid => $value) {
$form_state['input']['attributes'][$aid][$oid] = NULL;
}
}
break;
case 'radios':
$form_state['input']['attributes'][$aid] = NULL;
break;
case 'select':
if ($form['attributes'][$aid]['#value'] != '') {
$form['attributes'][$aid]['#value'] = '';
}
break;
case 'textfield':
$form_state['input']['attributes'][$aid] = '';
break;
default:
break;
}
}
/**
* Form build for classes.
*
* Callback for $form['#after_build'] for product classes. Adds
* the CSS to hide the dependent attributes.
*/
function _uc_dropdown_attributes_class_build($form, &$form_state) {
$sql = 'SELECT aid, parent_aid, parent_values, required
FROM {uc_dropdown_classes} WHERE pcid=:pcid';
$pcid = uc_dropdown_attributes_get_type($form['nid']['#value']);
$attributes = db_query($sql, array(
':pcid' => $pcid,
));
if (isset($form_state['triggering_element'])) {
$parents = $form_state['triggering_element']['#parents'];
$parent_aid = $parents[count($parents) - 1];
$parent_value = $form_state['triggering_element']['#value'];
uc_dropdown_attributes_remove_values($parent_aid, $parent_value, $pcid, 'class', $form_state['values']);
}
foreach ($attributes as $attribute) {
if (isset($form_state['values']['attributes'])) {
$parent_value = $form_state['values']['attributes'][$attribute->parent_aid];
}
if ($parent_value) {
// A value has been entered in parent attribute.
$values = unserialize($attribute->parent_values);
if ($form['attributes'][$attribute->parent_aid]['#type'] == 'checkboxes') {
$parent_values = array_diff($parent_value, array(
0,
));
if (count(array_intersect($parent_values, $values))) {
// Show dependent attribute.
if ($attribute->required) {
$form['attributes'][$attribute->aid]['#required'] = TRUE;
}
}
else {
// Hide dependent attribute.
$form['attributes'][$attribute->aid]['#post_render'][] = 'uc_dropdown_attributes_post_render';
if ($attribute->required && count($form['attributes'][$attribute->aid]['#value']) > 0) {
$form['attributes'][$attribute->aid]['#value'] = array();
}
}
}
else {
if (array_key_exists($parent_value, $values)) {
// Show dependent attribute.
if ($attribute->required) {
$form['attributes'][$attribute->aid]['#required'] = TRUE;
}
}
else {
// Hide dependent attribute.
$form['attributes'][$attribute->aid]['#post_render'][] = 'uc_dropdown_attributes_post_render';
if ($attribute->required && $form['attributes'][$attribute->aid]['#value'] != '') {
$form['attributes'][$attribute->aid]['#value'] = '';
}
}
}
}
else {
$form['attributes'][$attribute->aid]['#post_render'][] = 'uc_dropdown_attributes_post_render';
if ($attribute->required && isset($form['attributes'][$attribute->aid]['#value']) && $form['attributes'][$attribute->aid]['#value'] != '') {
$form['attributes'][$attribute->aid]['#value'] = '';
}
}
}
return $form;
}
/**
* Form build for product kits.
*
* Callback for $form['#after_build'] for product kits. Renders the dependent
* attributes and stores the html as a Javascript array.
*/
function _uc_dropdown_attributes_kit_build($form, &$form_state) {
foreach ($form['products'] as $key => $value) {
if (is_numeric($key)) {
$type = uc_dropdown_attributes_dependency_type($key);
switch ($type) {
case 'node':
$sql = 'SELECT aid, parent_aid, parent_values, required
FROM {uc_dropdown_attributes} WHERE nid=:nid';
$id = $key;
$attributes = db_query($sql, array(
':nid' => $key,
));
break;
case 'class':
$sql = 'SELECT aid, parent_aid, parent_values, required
FROM {uc_dropdown_classes} WHERE pcid=:pcid';
$pcid = uc_dropdown_attributes_get_type($key);
$id = $pcid;
$attributes = db_query($sql, array(
':pcid' => $pcid,
));
break;
default:
$attributes = array();
}
if (isset($form_state['triggering_element'])) {
$parents = $form_state['triggering_element']['#parents'];
$parent_aid = $parents[count($parents) - 1];
$parent_value = $form_state['triggering_element']['#value'];
uc_dropdown_attributes_remove_values($parent_aid, $parent_value, $id, $type, $form_state['values']['products'][$key]);
}
foreach ($attributes as $attribute) {
$aid = $attribute->aid;
$parent_aid = $attribute->parent_aid;
$parent_value = $form_state['values']['products'][$key]['attributes'][$parent_aid];
if ($parent_value) {
// A value has been entered in parent attribute.
$values = unserialize($attribute->parent_values);
if (array_key_exists($parent_value, $values)) {
// Show dependent attribute.
if ($attribute->required) {
$form['products'][$key]['attributes'][$aid]['#required'] = TRUE;
}
}
else {
// Hide dependent attribute.
$form['products'][$key]['attributes'][$aid]['#post_render'][] = 'uc_dropdown_attributes_post_render';
if ($form['products'][$key]['attributes'][$aid]['#required'] && $form['products'][$key]['attributes'][$aid]['#value'] != '') {
$form['products'][$key]['attributes'][$aid]['#value'] = '';
}
}
}
else {
$form['products'][$key]['attributes'][$aid]['#post_render'][] = 'uc_dropdown_attributes_post_render';
if ($form['products'][$key]['attributes'][$aid]['#required'] && $form['products'][$key]['attributes'][$aid]['#value'] != '') {
$form['products'][$key]['attributes'][$aid]['#value'] = '';
}
}
}
}
}
return $form;
}
/**
* Unset values of orphaned children.
*
* Called recursively to remove orphaned values from form_state.
*
* @param int $parent_aid
* Attribute ID of the triggering element.
* @param int $parent_value
* Option ID of the value of the triggering element.
* @param int $id
* Node ID or product class ID.
* @param string $type
* 'node' or 'class'.
* @param array $form_values
* Part of the form_state array containing the attributes.
*/
function uc_dropdown_attributes_remove_values($parent_aid, $parent_value, $id, $type, &$form_values) {
switch ($type) {
case 'node':
$sql = 'SELECT aid, required, parent_values FROM {uc_dropdown_attributes}
WHERE nid=:nid AND parent_aid=:parent_aid';
$children = db_query($sql, array(
':nid' => $id,
':parent_aid' => $parent_aid,
));
break;
case 'class':
$sql = 'SELECT aid, required, parent_values FROM {uc_dropdown_classes}
WHERE pcid=:pcid AND parent_aid=:parent_aid';
$children = db_query($sql, array(
':pcid' => $id,
':parent_aid' => $parent_aid,
));
break;
default:
$children = array();
break;
}
foreach ($children as $child) {
if ($child->required) {
$value = $form_values['attributes'][$child->aid];
$form_values['attributes'][$child->aid] = '';
if ($value) {
$values = unserialize($child->parent_values);
if (!array_key_exists($parent_value, $values)) {
uc_dropdown_attributes_remove_values($child->aid, $value, $id, $type, $form_values);
}
}
}
}
}
/**
* Add the style to hide the attribute.
*
* @param string $html
* HTML for the element.
*
* @return string
* Modified element HTML.
*/
function uc_dropdown_attributes_post_render($html) {
$pos = strpos($html, '>');
$html = substr_replace($html, ' style="display:none;">', $pos, 1);
return $html;
}
/**
* Retrieves the attribute dependencies.
*
* Callback to supply attribute dependencies to Javascript.
*
* @param int $nid
* Node ID.
* @param string $id
* String containing attribute ID.
*
* @return object
* JSON structure.
*/
function uc_dropdown_attributes_dependency($nid, $id, $parent_id) {
$temp = explode('-', $id);
if ($temp[1] == 'attributes') {
$aid = $temp[2];
}
else {
$aid = $temp[4];
}
$result = new stdClass();
$query = 'SELECT parent_values, required
FROM {uc_dropdown_attributes} WHERE nid=:nid && aid=:aid';
$db_result = db_query($query, array(
':nid' => $nid,
':aid' => $aid,
));
foreach ($db_result as $item) {
$result->status = TRUE;
$result->nid = $nid;
$result->id = $id;
$result->parent_id = $parent_id;
$result->parent_values = unserialize($item->parent_values);
$result->required = $item->required;
drupal_json_output($result);
return;
}
$pcid = uc_dropdown_attributes_get_type($nid);
$query = 'SELECT parent_values, required
FROM {uc_dropdown_classes} WHERE pcid=:pcid && aid=:aid';
$db_result = db_query($query, array(
':pcid' => $pcid,
':aid' => $aid,
));
foreach ($db_result as $item) {
$result->status = TRUE;
$result->nid = $nid;
$result->id = $id;
$result->parent_id = $parent_id;
$result->parent_values = unserialize($item->parent_values);
$result->required = $item->required;
drupal_json_output($result);
return;
}
$result->status = FALSE;
drupal_json_output($result);
}
/**
* Create an attribute dependency.
*
* A public function that creates and stores an attribute dependency for a
* product.
*
* @param int $nid
* Node ID.
* @param int $aid
* Attribute ID of the dependent (child) attribute.
* @param int $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_product_create_dependency($nid, $aid, $parent_aid, $options, $required) {
$attribute = uc_attribute_load($aid);
$dep = db_insert('uc_dropdown_attributes')
->fields(array(
'nid' => $nid,
'aid' => $aid,
'parent_aid' => $parent_aid,
'parent_values' => serialize($options),
'required' => $required,
))
->execute();
// Need to check to make sure attribute is not required all the time.
$sql = 'SELECT nid, aid, required FROM {uc_product_attributes}
WHERE nid=:nid && aid=:aid';
$result = db_query($sql, array(
':nid' => $nid,
':aid' => $aid,
));
foreach ($result as $item) {
if ($item->required == 1) {
$dep = db_update('uc_product_attributes')
->fields(array(
'required' => 0,
))
->condition('nid', $item->nid)
->condition('aid', $item->aid)
->execute();
}
}
}
/**
* Create an attribute dependency for product classes.
*
* A public function that creates and stores an attribute dependency for
* product classes.
*
* @param int $pcid
* Product class ID.
* @param int $aid
* Attribute ID of the dependent (child) attribute.
* @param int $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) {
$attribute = uc_attribute_load($aid);
$dep = db_insert('uc_dropdown_classes')
->fields(array(
'pcid' => $pcid,
'aid' => $aid,
'parent_aid' => $parent_aid,
'parent_values' => serialize($options),
'required' => $required,
))
->execute();
// Need to check to make sure attribute is not required all the time.
$sql = 'SELECT pcid, aid, required FROM {uc_class_attributes}
WHERE pcid=:pcid && aid=:aid';
$result = db_query($sql, array(
':pcid' => $pcid,
':aid' => $aid,
));
foreach ($result as $item) {
if ($item->required == 1) {
$dep = db_update('uc_class_attributes')
->fields(array(
'required' => 0,
))
->condition('pcid', $item->pcid)
->condition('aid', $item->aid)
->execute();
}
}
}
/**
* Implements hook_theme().
*/
function uc_dropdown_attributes_theme() {
return array(
'uc_dropdown_attributes_product' => array(
'render element' => 'form',
),
'uc_dropdown_attributes_class' => array(
'render element' => 'form',
),
);
}
/**
* Retrieve product class from the node ID.
*
* @param int $nid
* Node id.
*
* @return string
* The type field from the node object.
*/
function uc_dropdown_attributes_get_type($nid) {
$sql = 'SELECT type FROM {node} WHERE nid=:nid';
$type = db_query($sql, array(
':nid' => $nid,
))
->fetchField();
return $type;
}
/**
* Retrieve whether dependencies are defined by node or class.
*
* @param int $nid
* Node id.
*
* @return string
* 'node' for dependencies defined on the node level; 'class' for dependencies
* defined on the product class; otherwise, NULL.
*/
function uc_dropdown_attributes_dependency_type($nid) {
$sql = 'SELECT COUNT(*) FROM {uc_dropdown_attributes} WHERE nid=:nid';
$count = db_query($sql, array(
':nid' => $nid,
))
->fetchField();
if ($count > 0) {
return 'node';
}
$pcid = uc_dropdown_attributes_get_type($nid);
$sql = 'SELECT COUNT(*) FROM {uc_dropdown_classes} WHERE pcid=:pcid';
$count = db_query($sql, array(
':pcid' => $pcid,
))
->fetchField();
if ($count > 0) {
return 'class';
}
return NULL;
}
/**
* Determine the correct theme to use for dependencies admin page.
*
* @return string
* theme to use or empty string if default theme.
*/
function uc_dropdown_attributes_admin_theme() {
if (variable_get('node_admin_theme', 0) == 1) {
return variable_get('admin_theme', '');
}
return '';
}
/**
* Implements hook_form_FORM_ID_alter() for uc_order_edit_form().
*/
function uc_dropdown_attributes_form_uc_order_edit_form_alter(&$form, &$form_state) {
if (isset($form_state['products_action']) && $form_state['products_action'] == 'add_product') {
$product_type = $form['product_controls']['node']['#value']->type;
if ($product_type == 'product_kit') {
foreach ($form['product_controls']['sub_products'] as $nid => $product) {
if (is_numeric($nid)) {
$type = uc_dropdown_attributes_dependency_type($nid);
if (!is_null($type)) {
uc_dropdown_attributes_order_product_alter($nid, $form['product_controls']['sub_products'][$nid]['attributes'], $type);
if (!in_array('_uc_dropdown_attributes_order_product_kit_build', $form['#after_build'])) {
$form['#after_build'][] = '_uc_dropdown_attributes_order_product_kit_build';
}
}
}
}
}
else {
$nid = $form['product_controls']['node']['#value']->nid;
$type = uc_dropdown_attributes_dependency_type($nid);
if (!is_null($type)) {
uc_dropdown_attributes_order_product_alter($nid, $form['product_controls']['attributes'], $type);
$form['nid'] = array(
'#type' => 'hidden',
'#value' => $nid,
);
switch ($type) {
case 'node':
$form['#after_build'][] = '_uc_dropdown_attributes_order_product_build';
break;
case 'class':
$form['#after_build'][] = '_uc_dropdown_attributes_order_class_build';
break;
}
}
}
}
}
/**
* Alter products on oder page in preparation for drop down attributes.
*
* Adds the 'Please select' and removes the default value. Ubercart does this
* for required attributes but since these attributes can no longer be required
* if the attributes are dependent then this reproduces the same thing.
*
* @param int $nid
* Node ID.
* @param array $form_attributes
* Attributes part of the product form.
* @param string $type
* 'node' for dependencies defined on the node level; 'class' for dependencies
* defined on the product class.
*/
function uc_dropdown_attributes_order_product_alter($nid, &$form_attributes, $type) {
switch ($type) {
case 'node':
$sql = 'SELECT aid, parent_aid, required FROM {uc_dropdown_attributes}
WHERE nid=:nid';
$attributes = db_query($sql, array(
':nid' => $nid,
));
break;
case 'class':
$sql = 'SELECT aid, parent_aid, required FROM {uc_dropdown_classes}
WHERE pcid=:pcid';
$pcid = uc_dropdown_attributes_get_type($nid);
$attributes = db_query($sql, array(
':pcid' => $pcid,
));
break;
}
$parent_aids = array();
foreach ($attributes as $attribute) {
$parent_aids[$attribute->parent_aid] = $attribute->parent_aid;
if (isset($form_attributes[$attribute->aid]['#options']) && count($form_attributes[$attribute->aid]['#options']) && $attribute->required) {
switch ($form_attributes[$attribute->aid]['#type']) {
case 'select':
$form_attributes[$attribute->aid]['#options'] = array(
'' => t('Please select'),
) + $form_attributes[$attribute->aid]['#options'];
$form_attributes[$attribute->aid]['#default_value'] = '';
break;
case 'radios':
$form_attributes[$attribute->aid]['#default_value'] = '';
break;
case 'checkboxes':
$form_attributes[$attribute->aid]['#default_value'] = array();
break;
}
}
}
foreach ($parent_aids as $aid) {
$form_attributes[$aid]['#ajax'] = array(
'callback' => 'uc_dropdown_attributes_order_ajax_callback',
'wrapper' => $form_attributes['#id'],
);
}
}
/**
* Ajax callback for order attribute selection form elements.
*/
function uc_dropdown_attributes_order_ajax_callback($form, $form_state) {
if (in_array('sub_products', $form_state['triggering_element']['#parents'])) {
// This is a product kit.
$nid = $form_state['triggering_element']['#parents'][2];
return $form['product_controls']['sub_products'][$nid]['attributes'];
}
return $form['product_controls']['attributes'];
}
/**
* Form build for products for the order page.
*
* Callback for $form['#after_build'] for products. Adds the CSS to hide
* the dependent attributes.
*/
function _uc_dropdown_attributes_order_product_build($form, &$form_state) {
$nid = $form['nid']['#value'];
$sql = 'SELECT aid, parent_aid, parent_values, required
FROM {uc_dropdown_attributes} WHERE nid=:nid';
$attributes = db_query($sql, array(
':nid' => $nid,
));
if (isset($form_state['triggering_element'])) {
$parents = $form_state['triggering_element']['#parents'];
$parent_aid = $parents[count($parents) - 1];
$parent_value = $form_state['triggering_element']['#value'];
uc_dropdown_attributes_remove_values($parent_aid, $parent_value, $nid, 'node', $form_state['values']['product_controls']);
}
uc_dropdown_attributes_order_attribute_display($attributes, $form['product_controls']['attributes'], $form_state['values']['product_controls']['attributes']);
return $form;
}
/**
* Form build for classes for the order page.
*
* Callback for $form['#after_build'] for product classes. Adds
* the CSS to hide the dependent attributes.
*/
function _uc_dropdown_attributes_order_class_build($form, &$form_state) {
$sql = 'SELECT aid, parent_aid, parent_values, required
FROM {uc_dropdown_classes} WHERE pcid=:pcid';
$pcid = uc_dropdown_attributes_get_type($form['nid']['#value']);
$attributes = db_query($sql, array(
':pcid' => $pcid,
));
if (isset($form_state['triggering_element'])) {
$parents = $form_state['triggering_element']['#parents'];
$parent_aid = $parents[count($parents) - 1];
$parent_value = $form_state['triggering_element']['#value'];
// Note that values are stored in input, not values.
uc_dropdown_attributes_remove_values($parent_aid, $parent_value, $pcid, 'class', $form_state['input']['product_controls']);
}
uc_dropdown_attributes_order_attribute_display($attributes, $form['product_controls']['attributes'], $form_state['values']['product_controls']['attributes']);
return $form;
}
/**
* Form build for product kits for the order page.
*
* Callback for $form['#after_build'] for products. Adds the CSS to hide
* the dependent attributes.
*/
function _uc_dropdown_attributes_order_product_kit_build($form, &$form_state) {
foreach ($form['product_controls']['sub_products'] as $nid => $product) {
if (is_numeric($nid)) {
$type = uc_dropdown_attributes_dependency_type($nid);
switch ($type) {
case 'node':
$sql = 'SELECT aid, parent_aid, parent_values, required
FROM {uc_dropdown_attributes} WHERE nid=:nid';
$attributes = db_query($sql, array(
':nid' => $nid,
));
if (isset($form_state['triggering_element']) && $nid == $form_state['triggering_element']['#parents'][2]) {
$parents = $form_state['triggering_element']['#parents'];
$parent_aid = $parents[count($parents) - 1];
$parent_value = $form_state['triggering_element']['#value'];
uc_dropdown_attributes_remove_values($parent_aid, $parent_value, $nid, 'node', $form_state['values']['product_controls']['sub_products'][$nid]);
}
uc_dropdown_attributes_order_attribute_display($attributes, $form['product_controls']['sub_products'][$nid]['attributes'], $form_state['values']['product_controls']['sub_products'][$nid]['attributes']);
break;
case 'class':
$sql = 'SELECT aid, parent_aid, parent_values, required
FROM {uc_dropdown_classes} WHERE pcid=:pcid';
$pcid = uc_dropdown_attributes_get_type($nid);
$attributes = db_query($sql, array(
':pcid' => $pcid,
));
if (isset($form_state['triggering_element']) && $nid == $form_state['triggering_element']['#parents'][2]) {
$parents = $form_state['triggering_element']['#parents'];
$parent_aid = $parents[count($parents) - 1];
$parent_value = $form_state['triggering_element']['#value'];
// Note that values are stored in input, not values.
uc_dropdown_attributes_remove_values($parent_aid, $parent_value, $pcid, 'class', $form_state['input']['product_controls']['sub_products'][$nid]);
}
uc_dropdown_attributes_order_attribute_display($attributes, $form['product_controls']['sub_products'][$nid]['attributes'], $form_state['values']['product_controls']['sub_products'][$nid]['attributes']);
break;
}
}
}
return $form;
}
/**
* Alter display of attributes on the oder page.
*
* @param array $attributes
* Array of attribute dependency objects.
* @param array &$form_attributes
* Attributes part of the product form.
* @param array $form_state_attributes
* Attributes part of the product form_state.
*/
function uc_dropdown_attributes_order_attribute_display($attributes, &$form_attributes, $form_state_attributes) {
foreach ($attributes as $attribute) {
$parent_value = $form_state_attributes[$attribute->parent_aid];
if ($parent_value) {
// A value has been entered in parent attribute.
$values = unserialize($attribute->parent_values);
if (array_key_exists($parent_value, $values)) {
// Show dependent attribute.
if ($attribute->required) {
$form_attributes[$attribute->aid]['#required'] = TRUE;
}
}
else {
// Hide dependent attribute.
$form_attributes[$attribute->aid]['#post_render'][] = 'uc_dropdown_attributes_post_render';
if ($attribute->required && $form_attributes[$attribute->aid]['#value'] != '') {
$form_attributes[$attribute->aid]['#value'] = '';
}
}
}
else {
$form_attributes[$attribute->aid]['#post_render'][] = 'uc_dropdown_attributes_post_render';
if ($attribute->required && $form_attributes[$attribute->aid]['#value'] != '') {
$form_attributes[$attribute->aid]['#value'] = '';
}
}
}
}
/**
* Form build for classes in product kits for the order page.
*
* Callback for $form['#after_build'] for product classes. Adds
* the CSS to hide the dependent attributes.
*/
function _uc_dropdown_attributes_order_class_kit_build($form, &$form_state) {
$sql = 'SELECT aid, parent_aid, parent_values, required
FROM {uc_dropdown_classes} WHERE pcid=:pcid';
$pcid = uc_dropdown_attributes_get_type($form['nid']['#value']);
$attributes = db_query($sql, array(
':pcid' => $pcid,
));
if (isset($form_state['triggering_element'])) {
$parents = $form_state['triggering_element']['#parents'];
$parent_aid = $parents[count($parents) - 1];
$parent_value = $form_state['triggering_element']['#value'];
uc_dropdown_attributes_remove_values($parent_aid, $parent_value, $pcid, 'class', $form_state['values']['product_controls']);
}
foreach ($attributes as $attribute) {
$parent_value = $form_state['values']['product_controls']['attributes'][$attribute->parent_aid];
if ($parent_value) {
// A value has been entered in parent attribute.
$values = unserialize($attribute->parent_values);
if (array_key_exists($parent_value, $values)) {
// Show dependent attribute.
if ($attribute->required) {
$form['product_controls']['attributes'][$attribute->aid]['#required'] = TRUE;
}
}
else {
// Hide dependent attribute.
$form['product_controls']['attributes'][$attribute->aid]['#post_render'][] = 'uc_dropdown_attributes_post_render';
if ($form['product_controls']['attributes'][$attribute->aid]['#required'] && $form['product_controls']['attributes'][$attribute->aid]['#value'] != '') {
$form['product_controls']['attributes'][$attribute->aid]['#value'] = '';
}
}
}
else {
$form['product_controls']['attributes'][$attribute->aid]['#post_render'][] = 'uc_dropdown_attributes_post_render';
if ($form['product_controls']['attributes'][$attribute->aid]['#required'] && $form['product_controls']['attributes'][$attribute->aid]['#value'] != '') {
$form['product_controls']['attributes'][$attribute->aid]['#value'] = '';
}
}
}
return $form;
}
/**
* Implements hook_node_load().
*
* Ubercart fails to load attributes for product classes.
*/
function uc_dropdown_attributes_node_load($nodes) {
foreach ($nodes as $node) {
if (uc_product_is_product($node)) {
if (empty($node->attributes)) {
$node->attributes = uc_class_get_attributes($node->type);
}
}
}
}