le * 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(array &$form, array &$form_state, string $form_id): void { 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((int) $key); if (!is_null($type)) { $values = $form_state['values'] ?? []; uc_dropdown_attributes_product_alter((int) $key, $form['products'][$key], $values, $type, $form_state['rebuild']); 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((int) $nid); if (!is_null($type)) { $values = $form_state['values'] ?? []; uc_dropdown_attributes_product_alter((int) $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(int $nid, array &$form, array $form_values, string $type, bool $rebuild): void { 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; default: $attributes = new stdClass(); 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 (is_array($values) && 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(array $form, array $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(array $form, array &$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((int) $parent_aid, $parent_value, (int) $nid, 'node', $form_state['values']); } foreach ($attributes as $attribute) { if (!isset($form_state['values']['attributes'][$attribute->parent_aid])) { continue; } $parent_value = $form_state['values']['attributes'][$attribute->parent_aid]; if ($form['attributes'][$attribute->parent_aid]['#type'] == 'checkboxes') { $parent_values = array_diff((array) $parent_value, array(0)); $values = unserialize($attribute->parent_values); if (is_array($values) && 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'; // Bug fix: Always clear hidden attribute values, regardless of 'required' status. uc_dropdown_attributes_clear_input($form, $form_state, (int) $attribute->aid); } } else { if ($parent_value) { // A value has been entered in parent attribute. $values = unserialize($attribute->parent_values); if (is_array($values) && 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'; // Bug fix: Always clear hidden attribute values, regardless of 'required' status. uc_dropdown_attributes_clear_input($form, $form_state, (int) $attribute->aid); } } else { $form['attributes'][$attribute->aid]['#post_render'][] = 'uc_dropdown_attributes_post_render'; // Bug fix: Always clear hidden attribute values, regardless of 'required' status. uc_dropdown_attributes_clear_input($form, $form_state, (int) $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(array &$form, array &$form_state, int $aid): void { // Use nullsafe operator and null coalescing for PHP 8.0 compatibility $attributes_input = $form_state['input']['attributes'] ?? null; if ($attributes_input === null || !isset($form['attributes'][$aid])) { return; } $type = $form['attributes'][$aid]['#type'] ?? null; if ($type === null) { return; } switch ($type) { case 'checkboxes': if (isset($attributes_input[$aid])) { foreach ($attributes_input[$aid] as $oid => $value) { $form_state['input']['attributes'][$aid][$oid] = NULL; } } break; case 'radios': case 'select': $form_state['input']['attributes'][$aid] = ''; 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(array $form, array &$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((int) $parent_aid, $parent_value, $pcid, 'class', $form_state['values']); } $parent_value = null; // Initialize parent_value before the loop foreach ($attributes as $attribute) { if (isset($form_state['values']['attributes'])) { $parent_value = $form_state['values']['attributes'][$attribute->parent_aid]; } if ($parent_value) { $values = unserialize($attribute->parent_values); if ($form['attributes'][$attribute->parent_aid]['#type'] == 'checkboxes') { $parent_values = array_diff((array) $parent_value, array(0)); if (is_array($values) && count(array_intersect($parent_values, $values))) { if ($attribute->required) { $form['attributes'][$attribute->aid]['#required'] = TRUE; } } else { $form['attributes'][$attribute->aid]['#post_render'][] = 'uc_dropdown_attributes_post_render'; // Bug fix: Always clear hidden attribute values. if (count($form['attributes'][$attribute->aid]['#value']) > 0) { $form['attributes'][$attribute->aid]['#value'] = array(); } } } else { if (is_array($values) && array_key_exists($parent_value, $values)) { if ($attribute->required) { $form['attributes'][$attribute->aid]['#required'] = TRUE; } } else { $form['attributes'][$attribute->aid]['#post_render'][] = 'uc_dropdown_attributes_post_render'; // Bug fix: Always clear hidden attribute values. if ($form['attributes'][$attribute->aid]['#value'] != '') { $form['attributes'][$attribute->aid]['#value'] = ''; } } } } else { $form['attributes'][$attribute->aid]['#post_render'][] = 'uc_dropdown_attributes_post_render'; // Bug fix: Always clear hidden attribute values. if (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(array $form, array &$form_state) { foreach ($form['products'] as $key => $value) { if (is_numeric($key)) { $type = uc_dropdown_attributes_dependency_type((int) $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((int) $key); $id = $pcid; $attributes = db_query($sql, array(':pcid' => $pcid)); break; default: $attributes = array(); break; } 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((int) $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) { $values = unserialize($attribute->parent_values); if (is_array($values) && array_key_exists($parent_value, $values)) { if ($attribute->required) { $form['products'][$key]['attributes'][$aid]['#required'] = TRUE; } } else { $form['products'][$key]['attributes'][$aid]['#post_render'][] = 'uc_dropdown_attributes_post_render'; // Bug fix: Always clear hidden attribute values. if ($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'; // Bug fix: Always clear hidden attribute values. if ($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 mixed $parent_value * Option ID of the value of the triggering element. * @param mixed $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(int $parent_aid, $parent_value, $id, string $type, array &$form_values): void { 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) { if (isset($form_values['attributes'][$child->aid])) { $value = $form_values['attributes'][$child->aid]; $form_values['attributes'][$child->aid] = ''; if ($value) { $values = unserialize($child->parent_values); if (is_array($values) && !in_array($parent_value, $values)) { uc_dropdown_attributes_remove_values((int) $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(string $html): string { $pos = strpos($html, '>'); if ($pos !== false) { $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(int $nid, string $id, string $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(int $nid, int $aid, int $parent_aid, array $options, bool $required): void { $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(int $pcid, int $aid, int $parent_aid, array $options, bool $required): void { $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(): array { 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(int $nid): string { $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|null * 'node' for dependencies defined on the node level; * 'class' for dependencies defined on the product class; otherwise, NULL. */ function uc_dropdown_attributes_dependency_type(int $nid): ?string { $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(): string { if (variable_get('node_admin_theme', 0) == 1) { return (string)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(array &$form, array &$form_state): void { 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((int) $nid); if (!is_null($type)) { uc_dropdown_attributes_order_product_alter((int) $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((int) $nid); if (!is_null($type)) { uc_dropdown_attributes_order_product_alter((int) $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(int $nid, array &$form_attributes, string $type): void { 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(array $form, array $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(array $form, array &$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((int) $parent_aid, $parent_value, (int) $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(array $form, array &$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((int) $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(array $form, array &$form_state) { foreach ($form['product_controls']['sub_products'] as $nid => $product) { if (is_numeric($nid)) { $type = uc_dropdown_attributes_dependency_type((int) $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((int) $parent_aid, $parent_value, (int) $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((int) $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((int) $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(array $attributes, array &$form_attributes, array $form_state_attributes): void { foreach ($attributes as $attribute) { if (!isset($form_state_attributes[$attribute->parent_aid])) { continue; } $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 (is_array($values) && 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'; // Bug fix: Always clear hidden attribute values. if (isset($form_attributes[$attribute->aid]['#value']) && $form_attributes[$attribute->aid]['#value'] != '') { $form_attributes[$attribute->aid]['#value'] = ''; } } } else { $form_attributes[$attribute->aid]['#post_render'][] = 'uc_dropdown_attributes_post_render'; // Bug fix: Always clear hidden attribute values. if (isset($form_attributes[$attribute->aid]['#value']) && $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(array $form, array &$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((int) $parent_aid, $parent_value, $pcid, 'class', $form_state['values']['product_controls']); } $parent_value = null; foreach ($attributes as $attribute) { if (isset($form_state['values']['product_controls']['attributes'][$attribute->parent_aid])) { $parent_value = $form_state['values']['product_controls']['attributes'][$attribute->parent_aid]; } if ($parent_value) { $values = unserialize($attribute->parent_values); if (is_array($values) && array_key_exists($parent_value, $values)) { if ($attribute->required) { $form['product_controls']['attributes'][$attribute->aid]['#required'] = TRUE; } } else { $form['product_controls']['attributes'][$attribute->aid]['#post_render'][] = 'uc_dropdown_attributes_post_render'; // Bug fix: Always clear hidden attribute values. if (isset($form['product_controls']['attributes'][$attribute->aid]['#value']) && $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'; // Bug fix: Always clear hidden attribute values. if (isset($form['product_controls']['attributes'][$attribute->aid]['#value']) && $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(array $nodes): void { foreach ($nodes as $node) { if (uc_product_is_product($node)) { if (empty($node->attributes)) { $node->attributes = uc_class_get_attributes($node->type); } } } }Sealcoating, Line Striping and Asphalt Contractors in California | Asphalt Sealcoating Direct

You are here

Sealcoating, Line Striping and Asphalt Contractors in California

Asphalt Driveway Contractor Directory:

We know that you may have landed at this website looking for information on maintaining your own Asphalt Driveway, and if you are like most, you're probably feeling a little overwhelmed because of all of the information.

If you have decided to hire a contractor, we invite you to use our free on-line Contractor Directory by choosing your state below. If your state is not available, we do not currently have any contractors listed in your area but we are working to update the list to provide you with the best choice of asphalt related contractors.

This is a list of Asphalt Driveway Contractors who claim to have the skill and experience to handle your Asphalt maintenance and repair needs. Please note, these companies are not endorsed or screened by us, so make sure you do your part to check on them before committing to do business. We provide the contractor directory as an easy way to find sealcoaters and asphalt pavement contractors in your area.

Note: Starting 2024, we are no longer accepting new business registrations for the contractor directory, and will sunset this feature completely, sometime in the future.

Aliso Viejo

Anaheim

Antioch

Apache Junction

Auburn

AZ

Bakersfield

Brentwood

Broomfield

burbank

Cajon

Camarillo

Cameron Park

Carlsbad

Carmichael

Cerritos

Chino

Chino Hills

Chula Vista

Concord

Coolidge

Corona

Costa Mesa

Cupertino

Cypress

Dana Point

Danville

Diamond

Downey

Dr Temecula

El Cajon

Elk Grove

Encinitas

Escondido

Eureka

Fillmore

Florence

Folsom

Fontana

Fremont

Fresno

Fullerton

Glendale

Granada Hills

Hayward

Hemet

Huntington Beach

Inland Empire

Irvine

La Mesa

Laguna Niguel

Lake Arrowhead

Lake Forest

Lakeside

Livermore

long beach

Los Angeles

Manteca

Mentawai island

Mission Viejo

Modesto

Moreno Valley

Mountain View

Newark

Newport Beach

North Hollywood

Northridge

Novato

Oceanside

Orange

Orange County

Oxnard

Panorama City

Pico Rivera

Pleasanton

Pollock Pines

Rancho Cordova

Rancho Cucamonga

Redondo Beach

Redwood City

Rialto

Riverside

Rocklin

Rohnert Park

Rosamond

Roseville

Sacramento

San Bernardino

San Clemente

San Diego

San Francisco

San Gabriel

San Jose

San Leandro

San Pedro

San Ramon

San Tan Valley AZ

San Ysidro

Santa Ana

Santa Monica

Santa Paula

Santa Rosa

Santee

Simi Valley

Stockton

Sunnyvale

torrance

Tracy

Tustin

Union City

Upland

Venice

Victorville

Visalia

Walnut Creek

wthor

Yorba Linda