=== modified file 'uc_attribute/uc_attribute.admin.inc' --- uc_attribute/uc_attribute.admin.inc 2009-06-09 15:01:27 +0000 +++ uc_attribute/uc_attribute.admin.inc 2009-06-11 07:32:06 +0000 @@ -499,6 +499,10 @@ function uc_object_attributes_form($form ); $form['attributes'][$attribute->aid] = array( + 'aid' => array( + '#type' => 'hidden', + '#default_value' => $attribute->aid, + ), 'remove' => array( '#type' => 'checkbox', '#default_value' => 0, @@ -623,78 +627,58 @@ function theme_uc_object_attributes_form return $output; } +/** + * Submit handler for the product/class attributes form. + */ function uc_object_attributes_form_submit($form, &$form_state) { - if ($form_state['values']['type'] == 'product') { - $attr_table = '{uc_product_attributes}'; - $opt_table = '{uc_product_options}'; - $id = 'nid'; - $sql_type = '%d'; - } - elseif ($form_state['values']['type'] == 'class') { - $attr_table = '{uc_class_attributes}'; - $opt_table = '{uc_class_attribute_options}'; - $id = 'pcid'; - $sql_type = "'%s'"; - } - + $type = $form_state['values']['type']; + $id = $form_state['values']['id']; + + // The attribute edit form. if ($form_state['values']['view'] == 'overview' && is_array($form_state['values']['attributes'])) { + + $remove_count = 0; foreach ($form_state['values']['attributes'] as $aid => $attribute) { + // Remove was checked. if ($attribute['remove']) { - $remove_aids[] = $aid; + uc_attribute_subject_delete($aid, $id, $type); + $remove_count++; } + + // Update the attribute. else { - db_query("UPDATE $attr_table SET label = '%s', ordering = %d, required = %d, display = %d WHERE aid = %d AND $id = $sql_type", $attribute['label'], $attribute['ordering'], $attribute['required'], $attribute['display'], $aid, $form_state['values']['id']); + uc_attribute_subject_save($attribute, $id, $type); $changed = TRUE; } } - - if (count($remove_aids) > 0) { - $id_value = $form_state['values']['id']; - $remove_aids_value = implode(', ', $remove_aids); - - db_query("DELETE FROM $opt_table WHERE EXISTS (SELECT * FROM {uc_attribute_options} AS ao WHERE $opt_table.oid = ao.oid AND ao.aid IN (%s)) AND $opt_table.$id = $sql_type", $remove_aids_value, $id_value); - db_query("DELETE FROM $attr_table WHERE $id = $sql_type AND aid IN (%s)", $id_value, $remove_aids_value); - if ($form_state['values']['type'] == 'product') { - db_query("DELETE FROM {uc_product_adjustments} WHERE nid = %d", $id_value); - } - - drupal_set_message(format_plural(count($remove_aids), '@count attribute has been removed.', '@count attributes have been removed.')); + + if ($remove_count) { + drupal_set_message(format_plural($remove_count, '@count attribute has been removed.', '@count attributes have been removed.')); } - + if ($changed) { drupal_set_message(t('The changes have been saved.')); } } + + // The attribute add form. elseif ($form_state['values']['view'] == 'add') { foreach ($form_state['values']['add_attributes'] as $aid) { - // Enable all options for added attributes. + // Load the base attribute, and save it with all its options. $attribute = uc_attribute_load($aid); - foreach ($attribute->options as $option) { - db_query("INSERT INTO $opt_table ($id, oid, cost, price, weight, ordering) VALUES ($sql_type, %d, %f, %f, %f, %d)", $form_state['values']['id'], $option->oid, $option->cost, $option->price, $option->weight, $option->ordering); - } - // Make the first option (if any) the default. - $option = reset($attribute->options); - if ($option) { - $oid = $option->oid; - } - else { - $oid = 0; - } - db_query("INSERT INTO $attr_table ($id, aid, label, ordering, default_option, required, display) SELECT $sql_type, aid, label, ordering, %d, required, display FROM {uc_attributes} WHERE aid = %d", $form_state['values']['id'], $oid, $aid); + uc_attribute_subject_save($attribute, $id, $type, TRUE); } + if (count($form_state['values']['add_attributes']) > 0) { - if ($form_state['values']['type'] == 'product') { - db_query("DELETE FROM {uc_product_adjustments} WHERE nid = %d", $form_state['values']['id']); - } drupal_set_message(format_plural(count($form_state['values']['add_attributes']), '@count attribute has been added.', '@count attributes have been added.')); } } if ($form_state['values']['type'] == 'product') { - $form_state['redirect'] = 'node/'. $form_state['values']['id'] .'/edit/attributes'; + $form_state['redirect'] = 'node/'. $id .'/edit/attributes'; } else { - $form_state['redirect'] = 'admin/store/products/classes/'. $form_state['values']['id'] .'/attributes'; + $form_state['redirect'] = 'admin/store/products/classes/'. $id .'/attributes'; } } @@ -771,7 +755,7 @@ function uc_object_options_form($form_st ); } - $form['attributes'][$aid]['default'] = array( + $form['attributes'][$aid]['default_option'] = array( '#type' => 'radios', '#options' => $options, '#default_value' => /* $attribute->required ? NULL : */ $attribute->default_option, @@ -779,7 +763,7 @@ function uc_object_options_form($form_st ); } else { - $form['attributes'][$aid]['default'] = array( + $form['attributes'][$aid]['default_option'] = array( '#value' => t('This attribute does not have any options.'), ); } @@ -820,12 +804,12 @@ function theme_uc_object_options_form($f $rows = array(); - if (element_children($form['attributes'][$key]['default'])) { + if (element_children($form['attributes'][$key]['default_option'])) { - foreach (element_children($form['attributes'][$key]['default']) as $oid) { + foreach (element_children($form['attributes'][$key]['default_option']) as $oid) { $row = array( drupal_render($form['attributes'][$key]['options'][$oid]['select']), - drupal_render($form['attributes'][$key]['default'][$oid]), + drupal_render($form['attributes'][$key]['default_option'][$oid]), drupal_render($form['attributes'][$key]['options'][$oid]['cost']), drupal_render($form['attributes'][$key]['options'][$oid]['price']), drupal_render($form['attributes'][$key]['options'][$oid]['weight']), @@ -842,7 +826,7 @@ function theme_uc_object_options_form($f } else { $row = array(); - $row[] = array('data' => drupal_render($form['attributes'][$key]['default']), 'colspan' => 6); + $row[] = array('data' => drupal_render($form['attributes'][$key]['default_option']), 'colspan' => 6); $rows[] = $row; } @@ -883,8 +867,8 @@ function uc_object_options_form_validate } } } - if (!empty($selected_opts) && !$form['attributes'][$aid]['default']['#disabled'] && !in_array($attribute['default'], $selected_opts)) { - form_set_error($attribute['default']); + if (!empty($selected_opts) && !$form['attributes'][$aid]['default_option']['#disabled'] && !in_array($attribute['default_option'], $selected_opts)) { + form_set_error($attribute['default_option']); $error = TRUE; } } @@ -895,41 +879,36 @@ function uc_object_options_form_validate } } +/** + * Submit handler for the product/class attribute options form. + */ function uc_object_options_form_submit($form, &$form_state) { - if ($form_state['values']['type'] == 'product') { - $attr_table = '{uc_product_attributes}'; - $opt_table = '{uc_product_options}'; - $id = 'nid'; - $sql_type = '%d'; - } - elseif ($form_state['values']['type'] == 'class') { - $attr_table = '{uc_class_attributes}'; - $opt_table = '{uc_class_attribute_options}'; - $id = 'pcid'; - $sql_type = "'%s'"; - } - + $id = $form_state['values']['id']; + $type = $form_state['values']['type']; + foreach ($form_state['values']['attributes'] as $attribute) { - db_query("UPDATE $attr_table SET default_option = %d WHERE $id = $sql_type AND aid = %d", $attribute['default'], $form_state['values']['id'], $attribute['aid']); - + // Save the default option. + uc_attribute_subject_save($attribute, $id, $type); + + // Deal with options if they exist. if (is_array($attribute['options'])) { foreach ($attribute['options'] as $oid => $option) { - db_query("DELETE FROM $opt_table WHERE $id = $sql_type AND oid = %d", $form_state['values']['id'], $oid); - + + // Checked? if ($option['select']) { - db_query("INSERT INTO $opt_table ($id, oid, cost, price, weight, ordering) VALUES ($sql_type, %d, %f, %f, %f, %d)", - $form_state['values']['id'], $oid, $option['cost'], $option['price'], $option['weight'], $option['ordering']); + $option['oid'] = $oid; + uc_attribute_subject_option_save($option, $id, $type); } - elseif ($form_state['values']['type'] == 'product') { - $aid = $attribute['aid']; - $match = 'i:'. $aid .';s:'. strlen($oid) .':"'. $oid .'";'; - db_query("DELETE FROM {uc_product_adjustments} WHERE nid = %d AND combination LIKE '%%%s%%'", $form_state['values']['id'], $match); + + // Unchecked means delete the option. + else { + uc_attribute_subject_option_delete($oid, $id, $type); } } } } - drupal_set_message(t('The !type options have been saved.', array('!type' => $form_state['values']['type'] == 'product' ? t('product') : t('product class')))); + drupal_set_message(t('The !type options have been saved.', array('!type' => $type == 'product' ? t('product') : t('product class')))); } /** === modified file 'uc_attribute/uc_attribute.module' --- uc_attribute/uc_attribute.module 2009-06-10 20:28:03 +0000 +++ uc_attribute/uc_attribute.module 2009-06-11 07:59:07 +0000 @@ -773,3 +773,210 @@ function _uc_attribute_get_name($attribu return (empty($attribute->label) || ($attribute->label == '' && $title) ? $attribute->name : $attribute->label); } } + +/** + * Delete a product/class attribute. + * + * @param $aid + * The base attribute ID. + * @param $id + * The product/class ID. + * @param $type + * Is this a product or a class? + */ +function uc_attribute_subject_delete($aid, $id, $type) { + $sql = uc_attribute_type_info($type); + + // Delete all the options associated with this product/class attribute, and + // then the attribute itself. + $result = db_query("SELECT oid FROM {uc_attributes} WHERE aid = %d", $aid); + while ($oid = db_result($result)) { + // Don't delete the adjustments one at a time. We'll do it in bulk soon for + // efficiency. + uc_attribute_subject_option_delete($oid, $id, $type, FALSE); + } + db_query("DELETE FROM {$sql['attr_table']} WHERE {$sql['id']} = {$sql['placeholder']} AND aid = %d", $id, $aid); + + // If this is a product attribute, wipe any associated adjustments. + if ($type == 'product') { + db_query("DELETE FROM {uc_product_adjustments} WHERE nid = %d", $id); + } +} + +/** + * Save a product/class attribute. + * + * @param &$attribute + * The product/class attribute. + * @param $id + * The product/class ID. + * @param $type + * Is this a product or a class? + * @param $save_options + * Save the product/class attribute's options, too? + */ +function uc_attribute_subject_save(&$attribute, $id, $type, $save_options = FALSE) { + $sql = uc_attribute_type_info($type); + + // Convert to an array if needed. + if (is_object($attribute)) { + $attribute = (array) $attribute; + $object = TRUE; + } + else { + $object = FALSE; + } + + // Insert or update? + $key = uc_attribute_subject_exists($attribute['aid'], $id, $type) ? array('aid', $sql['id']) : NULL; + + // First, save the options. First because if this is an insert, we'll set + // a default option for the product/class attribute. + if ($save_options) { + foreach ($attribute['options'] as $option) { + uc_attribute_subject_option_save($option, $id, $type); + } + + // Is this an insert? If so, we'll set the default option. + if (empty($key)) { + $default_option = 0; + // Make the first option (if any) the default. + if (is_array($attribute['options'])) { + $option = (array) reset($attribute['options']); + $default_option = $option['oid']; + } + $attribute['default_option'] = $default_option; + } + } + + // Merge in the product/class attribute's ID and save. + $attribute = array($type == 'product' ? 'nid' : 'pcid' => $id) + $attribute; + drupal_write_record(trim($sql['attr_table'], '{}'), $attribute, $key); + + // Convert back if necessary, for the caller. + if ($object) { + $attribute = (object) $attribute; + } +} + +/** + * Delete a product/class attribute option. + * + * @param $oid + * The base attribute's option ID. + * @param $id + * The product/class ID. + * @param $type + * Is this a product or a class? + */ +function uc_attribute_subject_option_delete($oid, $id, $type, $adjustments = TRUE) { + $sql = uc_attribute_type_info($type); + + // Delete the option. + db_query("DELETE FROM {$sql['opt_table']} WHERE {$sql['id']} = {$sql['placeholder']} AND oid = %d", $id, $oid); + + // If this is a product, clean up the associated adjustments. + if ($adjustments && $type == 'product') { + $aid = db_result(db_query("SELECT aid FROM {uc_attribute_options} WHERE oid = %d", $oid)); + + $match = 'i:'. $aid .';s:'. strlen($oid) .':"'. $oid .'";'; + db_query("DELETE FROM {uc_product_adjustments} WHERE nid = %d AND combination LIKE '%%%s%%'", $form_state['values']['id'], $match); + } +} + +/** + * Save a product/class attribute option. + * + * @param &$option + * The product/class attribute option. + * @param $id + * The product/class ID. + * @param $type + * Is this a product or a class? + */ +function uc_attribute_subject_option_save(&$option, $id, $type) { + $sql = uc_attribute_type_info($type); + + // Convert to an array if needed. + if (is_object($option)) { + $option = (array) $option; + $object = TRUE; + } + else { + $object = FALSE; + } + + // Insert or update? + $key = uc_attribute_subject_option_exists($option['oid'], $id, $type) ? array('oid', $sql['id']) : NULL; + + // Merge in the product/class attribute option's ID, and save. + $option = array($type == 'product' ? 'nid' : 'pcid' => $id) + $option; + drupal_write_record(trim($sql['opt_table'], '{}'), $option, $key); + + // Convert back if necessary, for the caller. + if ($object) { + $option = (object) $option; + } +} + +/** + * Check if a product/class attribute exists. + * + * @param $aid + * The base attribute ID. + * @param $id + * The product/class attribute's ID. + * @param $type + * Is this a product or a class? + * @return (bool) + */ +function uc_attribute_subject_exists($aid, $id, $type) { + $sql = uc_attribute_type_info($type); + return FALSE !== db_result(db_query("SELECT aid FROM {$sql['attr_table']} WHERE aid = %d AND {$sql['id']} = {$sql['placeholder']}", $aid, $id)); +} + +/** + * Check if a product/class attribute option exists. + * + * @param $oid + * The base attribute option ID. + * @param $id + * The product/class attribute option's ID. + * @param $type + * Is this a product or a class? + * @return (bool) + */ +function uc_attribute_subject_option_exists($oid, $id, $type) { + $sql = uc_attribute_type_info($type); + return FALSE !== db_result(db_query("SELECT oid FROM {$sql['opt_table']} WHERE oid = %d AND {$sql['id']} = {$sql['placeholder']}", $oid, $id)); +} + +/** + * Return a list of db helpers to abstract the queries between products/classes. + * @param $type + * Is this a product or a class? + * @return (array) + */ +function uc_attribute_type_info($type) { + switch ($type) { + case 'product': + return array( + 'attr_table' => '{uc_product_attributes}', + 'opt_table' => '{uc_product_options}', + 'id' => 'nid', + 'placeholder' => '%d', + ); + break; + + case 'class': + return array( + 'attr_table' => '{uc_class_attributes}', + 'opt_table' => '{uc_class_attribute_options}', + 'id' => 'pcid', + 'placeholder' => "'%s'", + ); + break; + } +} + +