t('Name'), 'field' => 'a.name', 'sort' => 'asc'),
array('data' => t('Label'), 'field' => 'a.label'),
t('Required'),
array('data' => t('List position'), 'field' => 'a.ordering'),
t('Number of options'),
t('Display type'),
t('Operations'),
);
$display_types = _uc_attribute_display_types();
$result = pager_query("SELECT a.aid, a.name, a.label, a.required, a.ordering, a.display, COUNT(ao.oid) AS options FROM {uc_attributes} AS a LEFT JOIN {uc_attribute_options} AS ao ON a.aid = ao.aid GROUP BY a.aid, a.name, a.label, a.ordering, a.required, a.display". tablesort_sql($header), 30, 0, "SELECT COUNT(aid) FROM {uc_attributes}");
while ($attr = db_fetch_object($result)) {
if (empty($attr->label)) {
$attr->label = $attr->name;
}
$ops = array(
l(t('edit'), 'admin/store/attributes/'. $attr->aid .'/edit'),
l(t('options'), 'admin/store/attributes/'. $attr->aid .'/options'),
l(t('delete'), 'admin/store/attributes/'. $attr->aid .'/delete'),
);
$rows[] = array(
check_plain($attr->name),
check_plain($attr->label),
$attr->required == 1 ? t('Yes') : t('No'),
array('data' => $attr->ordering, 'align' => 'center'),
array('data' => $attr->options, 'align' => 'center'),
$display_types[$attr->display],
implode(' ', $ops),
);
}
if (count($rows) == 0) {
$rows[] = array(
array('data' => t('No product attributes have been added yet.'), 'colspan' => '6')
);
}
$output = theme('table', $header, $rows) . theme('pager', NULL, 30)
. l(t('Add an attribute'), 'admin/store/attributes/add');
return $output;
}
/**
* Form builder for product attributes.
*
* @ingroup forms
* @see uc_attribute_form_submit()
*/
function uc_attribute_form($form_state, $attribute = NULL) {
// If an attribute specified, add its ID as a hidden value.
if (!empty($attribute)) {
$form['aid'] = array('#type' => 'hidden', '#value' => $attribute->aid);
drupal_set_title(t('Edit attribute: %name', array('%name' => $attribute->name)));
}
$form['name'] = array(
'#type' => 'textfield',
'#title' => t('Name'),
'#description' => t('The name of the attribute used in administrative forms'),
'#default_value' => $attribute->name,
'#required' => TRUE,
);
$form['label'] = array(
'#type' => 'textfield',
'#title' => t('Label'),
'#description' => t("Enter a label that customers will see instead of the attribute name. Use <none> if you don't want a title to appear at all."),
'#default_value' => empty($attribute->label) ? $attribute->name : $attribute->label,
);
$form['description'] = array(
'#type' => 'textfield',
'#title' => t('Help text'),
'#description' => t('Optional. Enter the help text that will display beneath the attribute on product add to cart forms.'),
'#default_value' => $attribute->description,
'#maxlength' => 255,
);
$form['required'] = array(
'#type' => 'checkbox',
'#title' => t('Make this attribute required, forcing the customer to choose an option.'),
'#description' => t('Selecting this for an attribute will disregard any default option you specify.
May be overridden at the product level.'),
'#default_value' => $attribute->required,
);
$form['display'] = array(
'#type' => 'select',
'#title' => t('Display type'),
'#description' => t('This specifies how the options for this attribute will be presented.
May be overridden at the product level.'),
'#options' => _uc_attribute_display_types(),
'#default_value' => isset($attribute->display) ? $attribute->display : 1,
);
$form['ordering'] = array(
'#type' => 'weight',
'#title' => t('List position'),
'#description' => t('Multiple attributes on an add to cart form are sorted by this value and then by their name.
May be overridden at the product level.'),
'#default_value' => isset($attribute->ordering) ? $attribute->ordering : 0,
);
$form['submit'] = array(
'#type' => 'submit',
'#value' => t('Submit'),
'#suffix' => l(t('Cancel'), 'admin/store/attributes'),
);
return $form;
}
/**
* @see uc_attribute_add_form()
*/
function uc_attribute_form_submit($form, &$form_state) {
if (!empty($form_state['values']['aid'])) {
db_query("UPDATE {uc_attributes} SET name = '%s', label = '%s', ordering = %d, required = %d, display = %d, description = '%s' WHERE aid = %d", $form_state['values']['name'], $form_state['values']['label'], $form_state['values']['ordering'], $form_state['values']['required'], $form_state['values']['display'], $form_state['values']['description'], $form_state['values']['aid']);
}
else {
db_query("INSERT INTO {uc_attributes} (name, label, ordering, required, display, description) VALUES ('%s', '%s', %d, %d, %d, '%s')", $form_state['values']['name'], $form_state['values']['label'], $form_state['values']['ordering'], $form_state['values']['required'], $form_state['values']['display'], $form_state['values']['description']);
$form_state['values']['aid'] = db_last_insert_id('uc_attributes', 'aid');
}
$form_state['redirect'] = 'admin/store/attributes';
}
/**
* Confirm the deletion of the given attribute.
*
* @see uc_attribute_delete_confirm_submit()
*/
function uc_attribute_delete_confirm($form_state, $attribute) {
// If we got a bunk attribute, kick out an error message.
if (empty($attribute)) {
drupal_set_message(t('There is no attribute with that ID.'), 'error');
drupal_goto('admin/store/attributes');
}
$form['aid'] = array('#type' => 'value', '#value' => $attribute->aid);
$form['#redirect'] = 'admin/store/attributes';
$count = db_result(db_query("SELECT COUNT(*) FROM {uc_product_attributes} WHERE aid = %d", $attribute->aid));
$output = confirm_form($form, t('Are you sure you want to delete the attribute %name?', array('%name' => $attribute->name)),
'admin/store/attributes', format_plural($count, 'There is @count product with this attribute.', 'There are @count products with this attribute.'),
t('Delete'), t('Cancel'));
return $output;
}
/**
* @see uc_attribute_delete_confirm()
*/
function uc_attribute_delete_confirm_submit($form, &$form_state) {
if ($form_state['values']['confirm']) {
db_query("DELETE FROM {uc_class_attribute_options} WHERE EXISTS (SELECT * FROM {uc_attribute_options} AS ao WHERE {uc_class_attribute_options}.oid = ao.oid AND ao.aid = %d)", $form_state['values']['aid']);
db_query("DELETE FROM {uc_class_attributes} WHERE aid = %d", $form_state['values']['aid']);
db_query("DELETE FROM {uc_product_options} WHERE EXISTS (SELECT * FROM {uc_attribute_options} AS ao WHERE {uc_product_options}.oid = ao.oid AND ao.aid = %d)", $form_state['values']['aid']);
db_query("DELETE FROM {uc_product_adjustments} WHERE EXISTS (SELECT * FROM {uc_product_attributes} AS pa WHERE {uc_product_adjustments}.nid = pa.nid AND pa.aid = %d)", $form_state['values']['aid']);
db_query("DELETE FROM {uc_product_attributes} WHERE aid = %d", $form_state['values']['aid']);
db_query("DELETE FROM {uc_attribute_options} WHERE aid = %d", $form_state['values']['aid']);
db_query("DELETE FROM {uc_attributes} WHERE aid = %d", $form_state['values']['aid']);
drupal_set_message(t('Product attribute deleted.'));
}
}
/**
* Change the display of attribute option prices.
*
* @ingroup forms
*/
function uc_attribute_admin_settings() {
$form = array();
$form['uc_attribute_option_price_format'] = array('#type' => 'radios',
'#title' => t('Option price format'),
'#default_value' => variable_get('uc_attribute_option_price_format', 'adjustment'),
'#options' => array('none' => t('Do not display'),
'adjustment' => t('Display price adjustment'),
'total' => t('Display total price'),
),
'#description' => t('Determines how price variations are displayed to the customer. Prices may be displayed directly next to each attribute option in the attribute selection form either as a total price for the product with that option or as an adjustment (+ or -) showing how that option affects the product base price. However, the total price will not be displayed if a product has more than one attribute that can affect the price.'),
);
return system_settings_form($form);
}
/**
* Display options and the modifications to products they represent.
*
* @ingroup forms
* @see
* uc_attribute_options_form_validate()
* uc_attribute_options_form_submit()
*/
function uc_attribute_options_form($form_state, $attribute) {
$form = array();
// Set an appropriate title.
drupal_set_title(t('Options for %name', array('%name' => $attribute->name)));
// Store the attribute ID in the form array.
$form['aid'] = array(
'#type' => 'value',
'#value' => $attribute->aid,
);
$context = array(
'revision' => 'themed',
'type' => 'attribute_option',
'subject' => array(
'attribute' => $attribute,
),
);
// Loop through all the options on an attribute.
foreach ($attribute->options as $key => $data) {
$form['options'][$key] = array(
'name' => array(
'#value' => check_plain($data->name),
),
'cost' => array(
'#value' => $data->cost,
),
'price' => array(
'#value' => $data->price,
),
'weight' => array(
'#value' => $data->weight,
),
'ordering' => array(
'#type' => 'weight',
'#delta' => 50,
'#default_value' => $data->ordering,
'#attributes' => array('class' => 'uc-attribute-option-table-ordering'),
),
'ops' => array(
'#value' => l(t('edit'), 'admin/store/attributes/'. $attribute->aid .'/options/'. $key .'/edit') .' '.
l(t('delete'), 'admin/store/attributes/'. $attribute->aid .'/options/'. $key .'/delete'),
),
);
$context['subject']['option'] = $data;
$context['field'] = 'cost';
$form['options'][$key]['cost']['#value'] = uc_price($data->cost, $context);
$context['field'] = 'price';
$form['options'][$key]['price']['#value'] = uc_price($data->price, $context);
}
if (count($form['options'])) {
$form['options']['#tree'] = TRUE;
$form['submit'] = array(
'#type' => 'submit',
'#value' => t('Save changes'),
'#weight' => 10,
);
}
return $form;
}
function uc_attribute_options_form_submit($form, &$form_state) {
foreach ($form_state['values']['options'] as $oid => $option) {
db_query("UPDATE {uc_attribute_options} SET ordering = %d WHERE oid = %d", $option['ordering'], $oid);
}
drupal_set_message(t('The changes have been saved.'));
}
/**
* Format an attribute and its options.
*
* @ingroup themeable
*/
function theme_uc_attribute_options_form($form) {
$header = array(t('Name'), t('Default cost'), t('Default price'), t('Default weight'), array('data' => t('List position'), 'sort' => 'asc'), t('Operations'));
if (count(element_children($form['options'])) > 0) {
foreach (element_children($form['options']) as $oid) {
$row = array(
drupal_render($form['options'][$oid]['name']),
drupal_render($form['options'][$oid]['cost']),
drupal_render($form['options'][$oid]['price']),
drupal_render($form['options'][$oid]['weight']),
drupal_render($form['options'][$oid]['ordering']),
drupal_render($form['options'][$oid]['ops']),
);
$rows[] = array(
'data' => $row,
'class' => 'draggable',
);
}
}
else {
$rows[] = array(
array('data' => t('No options for this attribute have been added yet.'), 'colspan' => 6),
);
}
drupal_add_tabledrag('uc-attribute-option-table', 'order', 'sibling', 'uc-attribute-option-table-ordering');
$output = theme('table', $header, $rows, array('id' => 'uc-attribute-option-table'));
$output .= drupal_render($form);
$output .= l(t('Add an option'), 'admin/store/attributes/'. $form['aid']['#value'] .'/options/add');
return $output;
}
/**
* Form builder for attribute options.
*
* @ingroup forms
* @see uc_attribute_option_form_validate()
* @see uc_attribute_option_form_submit()
*/
function uc_attribute_option_form($form_state, $attribute, $option = NULL) {
// If we got a bunk attribute, kick out an error message.
if (empty($attribute)) {
drupal_set_message(t('There is no attribute with that ID.'), 'error');
drupal_goto('admin/store/attributes');
}
$aid = $attribute->aid;
$form['aid'] = array('#type' => 'hidden', '#value' => $aid);
if (!empty($option)) {
$form['oid'] = array('#type' => 'hidden', '#value' => $option->oid);
drupal_set_title(t('Edit option: %name', array('%name' => $option->name)));
}
else {
drupal_set_title(t('Options for %name', array('%name' => $attribute->name)));
}
$form['name'] = array(
'#type' => 'textfield',
'#title' => t('Name'),
'#description' => t('This name will appear to customers on product add to cart forms.'),
'#default_value' => $option->name,
'#required' => TRUE,
'#weight' => 0,
);
$form['ordering'] = array(
'#type' => 'weight',
'#title' => t('List position'),
'#description' => t('Options will be listed sorted by this value and then by their name.
May be overridden at the product level.'),
'#default_value' => isset($option->ordering) ? $option->ordering : 0,
'#weight' => 4,
);
$form['adjustments'] = array(
'#type' => 'fieldset',
'#title' => t('Default adjustments'),
'#description' => t('Enter a positive or negative value for each adjustment applied when this option is selected.
Any of these may be overriden at the product level.'),
'#collapsible' => FALSE,
'#weight' => 8,
);
$form['adjustments']['cost'] = array(
'#type' => 'textfield',
'#title' => t('Cost'),
'#default_value' => uc_store_format_price_field_value($option->cost),
'#weight' => 1,
);
$form['adjustments']['price'] = array(
'#type' => 'textfield',
'#title' => t('Price'),
'#default_value' => uc_store_format_price_field_value($option->price),
'#weight' => 2,
);
$form['adjustments']['weight'] = array(
'#type' => 'textfield',
'#title' => t('Weight'),
'#default_value' => $option->weight,
'#weight' => 3,
);
$form['submit'] = array(
'#type' => 'submit',
'#value' => t('Submit'),
'#suffix' => l(t('Cancel'), 'admin/store/attributes/'. $aid .'/options'),
'#weight' => 10,
);
return $form;
}
/**
* Validate number formats.
*
* @see uc_attribute_option_form()
*/
function uc_attribute_option_form_validate($form, &$form_state) {
$pattern = '/^-?\d*(\.\d*)?$/';
$price_error = t('This must be in a valid number format. No commas and only one decimal point.');
if (!is_numeric($form_state['values']['cost']['#value']) && !preg_match($pattern, $form_state['values']['cost']['#value'])) {
form_set_error('cost', $price_error);
}
if (!is_numeric($form_state['values']['price']['#value']) && !preg_match($pattern, $form_state['values']['price']['#value'])) {
form_set_error('price', $price_error);
}
if (!is_numeric($form_state['values']['weight']['#value']) && !preg_match($pattern, $form_state['values']['weight']['#value'])) {
form_set_error('weight', $price_error);
}
}
/**
* @see uc_attribute_option_form().
*/
function uc_attribute_option_form_submit($form, &$form_state) {
if (!isset($form_state['values']['oid'])) {
db_query("INSERT INTO {uc_attribute_options} (aid, name, cost, price, weight, ordering) VALUES (%d, '%s', %f, %f, %f, %d)",
$form_state['values']['aid'], $form_state['values']['name'], $form_state['values']['cost'], $form_state['values']['price'], $form_state['values']['weight'], $form_state['values']['ordering']);
$form_state['values']['oid'] = db_last_insert_id('uc_attribute_options','');
drupal_set_message(t('Created new option %option.', array('%option' => $form_state['values']['name'])));
watchdog('uc_attribute', 'Created new option %option.', array('%option' => $form_state['values']['name']), WATCHDOG_NOTICE, 'admin/store/attributes/'. $form_state['values']['aid'] .'/options/add');
$form_state['redirect'] = 'admin/store/attributes/'. $form_state['values']['aid'] .'/options/add';
}
else {
db_query("UPDATE {uc_attribute_options} SET name = '%s', cost = %f, price = %f, weight = %f, ordering = %d WHERE aid = %d AND oid = %d",
$form_state['values']['name'], $form_state['values']['cost'], $form_state['values']['price'], $form_state['values']['weight'], $form_state['values']['ordering'], $form_state['values']['aid'], $form_state['values']['oid']);
drupal_set_message(t('Updated option %option.', array('%option' => $form_state['values']['name'])));
watchdog('uc_attribute', 'Updated option %option.', array('%option' => $form_state['values']['name']), WATCHDOG_NOTICE, 'admin/store/attributes/'. $form_state['values']['aid'] .'/options/'. $form_state['values']['oid']);
$form_state['redirect'] = 'admin/store/attributes/'. $form_state['values']['aid'] .'/options';
}
}
/**
* Confirm deletion of the given attribute option.
*
* @see uc_attribute_option_delete_confirm_submit()
*/
function uc_attribute_option_delete_confirm($form_state, $attribute, $option) {
if (empty($option)) {
drupal_set_message(t('There is no option with that ID.'), 'error');
drupal_goto('admin/store/attributes/'. $attribute->aid .'/options');
}
$aid = $attribute->aid;
$oid = $option->oid;
$form['aid'] = array('#type' => 'value', '#value' => $aid);
$form['oid'] = array('#type' => 'value', '#value' => $oid);
$output = confirm_form($form, t('Are you sure you want to delete the option %name?', array('%name' => $option->name)),
'admin/store/attributes/'. $aid .'/options', '',
t('Delete'), t('Cancel'));
return $output;
}
/**
* @see uc_attribute_option_delete_confirm().
*/
function uc_attribute_option_delete_confirm_submit($form, &$form_state) {
if ($form_state['values']['confirm']) {
$match = 'i:'. $form_state['values']['aid'] .';s:'. strlen($form_state['values']['oid']) .':"'. $form_state['values']['oid'] .'";';
db_query("DELETE FROM {uc_product_adjustments} WHERE combination LIKE '%%%s%%'", $match);
db_query("DELETE FROM {uc_class_attribute_options} WHERE EXISTS (SELECT * FROM {uc_attribute_options} AS ao WHERE {uc_class_attribute_options}.oid = ao.oid AND ao.oid = %d)", $form_state['values']['oid']);
db_query("DELETE FROM {uc_product_options} WHERE EXISTS (SELECT * FROM {uc_attribute_options} AS ao WHERE {uc_product_options}.oid = ao.oid AND ao.oid = %d)", $form_state['values']['oid']);
db_query("DELETE FROM {uc_attribute_options} WHERE oid = %d", $form_state['values']['oid']);
}
$form_state['redirect'] = 'admin/store/attributes/'. $form_state['values']['aid'] .'/options';
}
/**
* Form to associate attributes with products or classes.
*
* @ingroup forms
* @see
* theme_uc_object_attributes_form()
* uc_object_attributes_form_submit()
*/
function uc_object_attributes_form($form_state, $object, $type, $view = 'overview') {
switch ($type) {
case 'class':
$class = $object;
$id = $class->pcid;
if (empty($class->name)) {
drupal_goto('admin/store/products/classes/'. $id);
}
drupal_set_title(check_plain($class->name));
$attributes = uc_class_get_attributes($id);
break;
case 'product':
default:
$product = $object;
$id = $product->nid;
if (empty($product->title)) {
drupal_goto('node/'. $id);
}
drupal_set_title(check_plain($product->title));
$attributes = uc_product_get_attributes($id);
}
$used_aids = array();
$used_labels = array();
foreach ($attributes as $attribute) {
$used_aids[] = $attribute->aid;
if (!empty($attribute->label)) {
$used_labels[] = $attribute->label;
}
}
if ($view == 'overview') {
$form['#tree'] = TRUE;
$context = array(
'revision' => 'themed',
'type' => 'attribute_option',
);
if (count($attributes) > 0) {
foreach ($attributes as $attribute) {
$option = $attribute->options[$attribute->default_option];
$context['subject'] = array(
'attribute' => $attribute,
'option' => $option,
);
$form['attributes'][$attribute->aid] = array(
'remove' => array(
'#type' => 'checkbox',
'#default_value' => 0,
),
'name' => array(
'#value' => check_plain($attribute->name),
),
'label' => array(
'#type' => 'textfield',
'#default_value' => empty($attribute->label) ? $attribute->name : $attribute->label,
'#size' => 6,
),
'option' => array(
'#value' => $option ? (check_plain($option->name) .' ('. uc_price($option->price, $context) .')' ) : t('n/a'),
),
'required' => array(
'#type' => 'checkbox',
'#default_value' => $attribute->required,
),
'ordering' => array(
'#type' => 'weight',
'#default_value' => $attribute->ordering,
'#attributes' => array('class' => 'uc-attribute-table-weight'),
),
'display' => array(
'#type' => 'select',
'#default_value' => $attribute->display,
'#options' => _uc_attribute_display_types(),
),
);
}
$form['save'] = array(
'#type' => 'submit',
'#value' => t('Save changes'),
'#weight' => -2,
);
}
}
elseif ($view == 'add') {
// Get list of attributes not already assigned to this node or class.
$unused_attributes = array();
$result = db_query("SELECT a.aid, a.name, a.label FROM {uc_attributes} AS a LEFT JOIN {uc_attribute_options} AS ao ON a.aid = ao.aid GROUP BY a.aid, a.name, a.label ORDER BY a.name");
while ($attribute = db_fetch_object($result)) {
if (!in_array($attribute->aid, $used_aids) && !in_array($attribute->label, $used_labels)) {
$unused_attributes[$attribute->aid] = $attribute->name;
}
}
$form['add_attributes'] = array(
'#type' => 'select',
'#title' => t('Attributes'),
'#description' => t('Hold Ctrl + click to select multiple attributes.'),
'#options' => count($unused_attributes) > 0 ? $unused_attributes : array(t('No attributes left to add.')),
'#disabled' => count($unused_attributes) == 0 ? TRUE : FALSE,
'#multiple' => TRUE,
'#weight' => -1
);
$form['add'] = array(
'#type' => 'submit',
'#value' => t('Add attributes'),
'#suffix' => l(t('Cancel'), $type == 'product' ? 'node/'. $id .'/edit/attributes' : 'admin/store/products/classes/'. $class->pcid .'/attributes'),
'#weight' => 0,
);
}
$form['id'] = array(
'#type' => 'value',
'#value' => $id,
);
$form['type'] = array(
'#type' => 'value',
'#value' => $type,
);
$form['view'] = array(
'#type' => 'value',
'#value' => $view,
);
return $form;
}
/**
* Display the formatted attribute form.
*
* @ingroup themeable
* @see uc_object_attributes_form()
*/
function theme_uc_object_attributes_form($form) {
$output = '';
if ($form['view']['#value'] == 'overview') {
$header = array(t('Remove'), t('Name'), t('Label'), t('Default'), t('Required'), t('List position'), t('Display'));
if (count(element_children($form['attributes'])) > 0) {
foreach (element_children($form['attributes']) as $aid) {
$row = array(
drupal_render($form['attributes'][$aid]['remove']),
drupal_render($form['attributes'][$aid]['name']),
drupal_render($form['attributes'][$aid]['label']),
drupal_render($form['attributes'][$aid]['option']),
drupal_render($form['attributes'][$aid]['required']),
drupal_render($form['attributes'][$aid]['ordering']),
drupal_render($form['attributes'][$aid]['display']),
);
$rows[] = array(
'data' => $row,
'class' => 'draggable',
);
}
}
else {
$rows[] = array(
array('data' => t('You must first add attributes to this !type.', array('!url' => request_uri() .'/add', '!type' => $form['type']['#value'])), 'colspan' => 6),
);
}
drupal_add_tabledrag('uc-attribute-table', 'order', 'sibling', 'uc-attribute-table-weight');
$output = theme('table', $header, $rows, array('id' => 'uc-attribute-table'));
}
else {
$output = '