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'),
array('data' => t('Operations'), 'colspan' => 3),
);
$display_types = _uc_attribute_display_types();
$query = db_select('uc_attributes', 'a')->extend('PagerDefault')->extend('TableSort')
->fields('a', array('aid', 'name', 'label', 'required', 'ordering', 'display'))
->orderByHeader($header)
->limit(30);
$rows = array();
$result = $query->execute();
foreach ($result as $attr) {
$attr->options = db_query('SELECT COUNT(*) FROM {uc_attribute_options} WHERE aid = :aid', array(':aid' => $attr->aid))->fetchField();
if (empty($attr->label)) {
$attr->label = $attr->name;
}
$rows[] = array(
check_plain($attr->name),
check_plain($attr->label),
$attr->required == 1 ? t('Yes') : t('No'),
$attr->ordering,
$attr->options,
$display_types[$attr->display],
l(t('edit'), 'admin/store/products/attributes/' . $attr->aid . '/edit'),
l(t('options'), 'admin/store/products/attributes/' . $attr->aid . '/options'),
l(t('delete'), 'admin/store/products/attributes/' . $attr->aid . '/delete'),
);
}
$build['attributes'] = array(
'#theme' => 'table',
'#header' => $header,
'#rows' => $rows,
'#empty' => t('No product attributes have been added yet.'),
);
$build['pager'] = array(
'#theme' => 'pager',
);
return $build;
}
/**
* Form builder for product attributes.
*
* @see uc_attribute_form_submit()
* @ingroup forms
*/
function uc_attribute_form($form, &$form_state, $attribute = NULL) {
// If an attribute specified, add its ID as a hidden value.
if (!empty($attribute)) {
$form['aid'] = array('#type' => 'value', '#value' => $attribute->aid);
drupal_set_title(t('Edit attribute: %name', array('%name' => $attribute->name)), PASS_THROUGH);
}
if (isset($attribute->name)) {
if (empty($attribute->label)) {
$attribute->label = $attribute->name;
}
$name = $attribute->name;
$label = $attribute->label;
}
else {
$name = $label = '';
}
$form['name'] = array(
'#type' => 'textfield',
'#title' => t('Name'),
'#description' => t('The name of the attribute used in administrative forms'),
'#default_value' => $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' => $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' => isset($attribute->description) ? $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' => isset($attribute->required) ? $attribute->required : 0,
);
$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',
'#delta' => 25,
'#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['actions'] = array('#type' => 'actions');
$form['actions']['submit'] = array(
'#type' => 'submit',
'#value' => t('Submit'),
'#suffix' => l(t('Cancel'), 'admin/store/products/attributes'),
);
return $form;
}
/**
* Form submission handler for uc_attribute_form().
*
* @see uc_attribute_form()
*/
function uc_attribute_form_submit($form, &$form_state) {
if (!empty($form_state['values']['aid'])) {
drupal_write_record('uc_attributes', $form_state['values'], 'aid');
$form_state['redirect'] = 'admin/store/products/attributes';
}
else {
drupal_write_record('uc_attributes', $form_state['values']);
$form_state['redirect'] = 'admin/store/products/attributes/' . $form_state['values']['aid'] . '/options';
}
}
/**
* Confirms the deletion of the given attribute.
*
* @see uc_attribute_delete_confirm_submit()
*/
function uc_attribute_delete_confirm($form, &$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/products/attributes');
}
$form['aid'] = array('#type' => 'value', '#value' => $attribute->aid);
$count = db_query("SELECT COUNT(*) FROM {uc_product_attributes} WHERE aid = :aid", array(':aid' => $attribute->aid))->fetchField();
$output = confirm_form($form, t('Are you sure you want to delete the attribute %name?', array('%name' => $attribute->name)),
'admin/store/products/attributes', format_plural($count, 'There is 1 product with this attribute.', 'There are @count products with this attribute.'),
t('Delete'), t('Cancel'));
return $output;
}
/**
* Form submission handler for uc_attribute_delete_confirm().
*
* @see uc_attribute_delete_confirm()
*/
function uc_attribute_delete_confirm_submit($form, &$form_state) {
if ($form_state['values']['confirm']) {
$attribute = uc_attribute_load($form_state['values']['aid']);
$options = array_keys($attribute->options);
if ($options) {
db_delete('uc_class_attribute_options')
->condition('oid', $options, 'IN')
->execute();
db_delete('uc_product_options')
->condition('oid', $options, 'IN')
->execute();
}
if ($nodes = db_query("SELECT nid FROM {uc_product_attributes} WHERE aid = :aid", array(':aid' => $attribute->aid))->fetchCol()) {
db_delete('uc_product_adjustments')
->condition('nid', $nodes, 'IN')
->execute();
}
db_delete('uc_class_attributes')
->condition('aid', $form_state['values']['aid'])
->execute();
db_delete('uc_product_attributes')
->condition('aid', $form_state['values']['aid'])
->execute();
db_delete('uc_attribute_options')
->condition('aid', $form_state['values']['aid'])
->execute();
db_delete('uc_attributes')
->condition('aid', $form_state['values']['aid'])
->execute();
drupal_set_message(t('Product attribute deleted.'));
$form_state['redirect'] = 'admin/store/products/attributes';
}
}
/**
* Displays options and the modifications to products they represent.
*
* @see uc_attribute_options_form_validate()
* @see uc_attribute_options_form_submit()
* @ingroup forms
*/
function uc_attribute_options_form($form, &$form_state, $attribute) {
// Set an appropriate title.
drupal_set_title(t('Options for %name', array('%name' => $attribute->name)), PASS_THROUGH);
// Store the attribute ID in the form array.
$form['aid'] = array(
'#type' => 'value',
'#value' => $attribute->aid,
);
$form['options'] = array();
// Loop through all the options on an attribute.
foreach ($attribute->options as $key => $data) {
$form['options'][$key] = array(
'name' => array(
'#markup' => check_plain($data->name),
),
'cost' => array(
'#theme' => 'uc_price',
'#price' => $data->cost,
),
'price' => array(
'#theme' => 'uc_price',
'#price' => $data->price,
),
'weight' => array(
'#markup' => (string)$data->weight,
),
'ordering' => array(
'#type' => 'weight',
'#delta' => 50,
'#default_value' => $data->ordering,
'#attributes' => array('class' => array('uc-attribute-option-table-ordering')),
),
'edit' => array('#markup' => l(t('edit'), 'admin/store/products/attributes/' . $attribute->aid . '/options/' . $key . '/edit')),
'delete' => array('#markup' => l(t('delete'), 'admin/store/products/attributes/' . $attribute->aid . '/options/' . $key . '/delete')),
);
}
if (count($form['options'])) {
$form['options']['#tree'] = TRUE;
$form['actions'] = array('#type' => 'actions');
$form['actions']['submit'] = array(
'#type' => 'submit',
'#value' => t('Save changes'),
'#weight' => 10,
);
}
return $form;
}
/**
* Form submission handler for uc_attribute_options_form().
*
* @see uc_attribute_options_form()
* @see uc_object_options_form_submit()
*/
function uc_attribute_options_form_submit($form, &$form_state) {
foreach ($form_state['values']['options'] as $oid => $option) {
db_update('uc_attribute_options')
->fields(array(
'ordering' => $option['ordering'],
))
->condition('oid', $oid)
->execute();
}
drupal_set_message(t('The changes have been saved.'));
}
/**
* Formats an attribute and its options.
*
* @param $variables
* An associative array containing:
* - form: A render element representing the form.
*
* @ingroup themeable
*/
function theme_uc_attribute_options_form($variables) {
$form = $variables['form'];
$header = array(t('Name'), t('Default cost'), t('Default price'), t('Default weight'), array('data' => t('List position'), 'sort' => 'asc'), array('data' => t('Operations'), 'colspan' => 2));
$rows = array();
foreach (element_children($form['options']) as $oid) {
$rows[] = array(
'data' => 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]['edit']),
drupal_render($form['options'][$oid]['delete']),
),
'class' => array('draggable'),
);
}
drupal_add_tabledrag('uc-attribute-option-table', 'order', 'sibling', 'uc-attribute-option-table-ordering');
$output = theme('table', array(
'header' => $header,
'rows' => $rows,
'attributes' => array('id' => 'uc-attribute-option-table'),
'empty' => t('No options for this attribute have been added yet.'),
));
$output .= drupal_render_children($form);
return $output;
}
/**
* Form builder for attribute options.
*
* @see uc_attribute_option_form_validate()
* @see uc_attribute_option_form_submit()
* @ingroup forms
*/
function uc_attribute_option_form($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/products/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)), PASS_THROUGH);
}
else {
$option = new stdClass();
$option->name = '';
$option->ordering = 0;
$option->cost = 0;
$option->price = 0;
$option->weight = 0;
drupal_set_title(t('Options for %name', array('%name' => $attribute->name)), PASS_THROUGH);
}
$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',
'#delta' => 50,
'#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' => $option->ordering,
'#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' => 'uc_price',
'#title' => t('Cost'),
'#default_value' => $option->cost,
'#weight' => 1,
'#allow_negative' => TRUE,
);
$form['adjustments']['price'] = array(
'#type' => 'uc_price',
'#title' => t('Price'),
'#default_value' => $option->price,
'#weight' => 2,
'#allow_negative' => TRUE,
);
$form['adjustments']['weight'] = array(
'#type' => 'textfield',
'#title' => t('Weight'),
'#default_value' => $option->weight,
'#weight' => 3,
);
$form['actions'] = array('#type' => 'actions');
$form['actions']['submit'] = array(
'#type' => 'submit',
'#value' => t('Submit'),
'#suffix' => l(t('Cancel'), 'admin/store/products/attributes/' . $aid . '/options'),
'#weight' => 10,
);
return $form;
}
/**
* Validates number formats.
*
* @see uc_attribute_option_form()
* @see uc_attribute_option_form_submit()
*/
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']['weight']) && !preg_match($pattern, $form_state['values']['weight'])) {
form_set_error('weight', $price_error);
}
}
/**
* Form submission handler for uc_attribute_option_form().
*
* @see uc_attribute_option_form()
* @see uc_attribute_option_form_validate()
*/
function uc_attribute_option_form_submit($form, &$form_state) {
if (!isset($form_state['values']['oid'])) {
drupal_write_record('uc_attribute_options', $form_state['values']);
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/products/attributes/' . $form_state['values']['aid'] . '/options/add');
$form_state['redirect'] = 'admin/store/products/attributes/' . $form_state['values']['aid'] . '/options/add';
}
else {
drupal_write_record('uc_attribute_options', $form_state['values'], array('aid', '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/products/attributes/' . $form_state['values']['aid'] . '/options/' . $form_state['values']['oid']);
$form_state['redirect'] = 'admin/store/products/attributes/' . $form_state['values']['aid'] . '/options';
}
}
/**
* Confirms deletion of the given attribute option.
*
* @see uc_attribute_option_delete_confirm_submit()
*/
function uc_attribute_option_delete_confirm($form, &$form_state, $attribute, $option) {
if (empty($option)) {
drupal_set_message(t('There is no option with that ID.'), 'error');
drupal_goto('admin/store/products/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/products/attributes/' . $aid . '/options', '', t('Delete'), t('Cancel'));
return $output;
}
/**
* Form submission handler for uc_attribute_option_delete_confirm().
*
* @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_delete('uc_product_adjustments')
->condition('combination', '%' . db_like($match) . '%', 'LIKE')
->execute();
$select = db_select('uc_attribute_options', 'ao')
->where('{uc_class_attribute_options}.oid = ao.oid')
->condition('ao.oid', $form_state['values']['oid']);
$select->addExpression('1');
db_delete('uc_class_attribute_options')
->condition('', $select, 'EXISTS')
->execute();
$select = db_select('uc_attribute_options', 'ao')
->where('{uc_product_options}.oid = ao.oid')
->condition('ao.oid', $form_state['values']['oid']);
$select->addExpression('1');
db_delete('uc_product_options')
->condition('', $select, 'EXISTS')
->execute();
db_delete('uc_attribute_options')
->condition('oid', $form_state['values']['oid'])
->execute();
}
$form_state['redirect'] = 'admin/store/products/attributes/' . $form_state['values']['aid'] . '/options';
}
/**
* Form to associate attributes with products or classes.
*
* @see uc_object_attributes_form_submit()
* @see theme_uc_object_attributes_form()
* @ingroup forms
*/
function uc_object_attributes_form($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($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($product->title);
$attributes = uc_product_get_attributes($id);
}
$used_aids = array();
foreach ($attributes as $attribute) {
$used_aids[] = $attribute->aid;
}
if ($view == 'overview') {
$form['#tree'] = TRUE;
$form['attributes'] = array();
if (count($attributes) > 0) {
foreach ($attributes as $attribute) {
$option = isset($attribute->options[$attribute->default_option]) ? $attribute->options[$attribute->default_option] : NULL;
$form['attributes'][$attribute->aid] = array(
'remove' => array(
'#type' => 'checkbox',
'#title' => t('Remove'),
'#title_display' => 'invisible',
'#default_value' => 0,
),
'name' => array(
'#markup' => check_plain($attribute->name),
),
'label' => array(
'#type' => 'textfield',
'#title' => t('Label'),
'#title_display' => 'invisible',
'#default_value' => empty($attribute->label) ? $attribute->name : $attribute->label,
'#size' => 20,
),
'option' => array(
'#markup' => $option ? (check_plain($option->name) . ' (' . theme('uc_price', array('price' => $option->price)) . ')' ) : t('n/a'),
),
'required' => array(
'#type' => 'checkbox',
'#title' => t('Required'),
'#title_display' => 'invisible',
'#default_value' => $attribute->required,
),
'ordering' => array(
'#type' => 'weight',
'#title' => t('List position'),
'#title_display' => 'invisible',
'#delta' => 25,
'#default_value' => $attribute->ordering,
'#attributes' => array('class' => array('uc-attribute-table-ordering')),
),
'display' => array(
'#type' => 'select',
'#title' => t('Display'),
'#title_display' => 'invisible',
'#default_value' => $attribute->display,
'#options' => _uc_attribute_display_types(),
),
);
}
$form['actions'] = array('#type' => 'actions');
$form['actions']['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} a LEFT JOIN {uc_attribute_options} ao ON a.aid = ao.aid GROUP BY a.aid, a.name, a.label ORDER BY a.name");
foreach ($result as $attribute) {
if (!in_array($attribute->aid, $used_aids)) {
$unused_attributes[$attribute->aid] = $attribute->name;
}
}
$form['add_attributes'] = array(
'#type' => 'checkboxes',
'#title' => t('Attributes'),
'#options' => count($unused_attributes) > 0 ? $unused_attributes : array(t('No attributes left to add.')),
'#disabled' => count($unused_attributes) == 0 ? TRUE : FALSE,
'#weight' => -1
);
$form['actions'] = array('#type' => 'actions');
$form['actions']['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;
}
/**
* Displays the formatted attribute form.
*
* @param $variables
* An associative array containing:
* - form: A render element representing the form.
*
* @see uc_object_attributes_form()
* @ingroup themeable
*/
function theme_uc_object_attributes_form($variables) {
$form = $variables['form'];
$output = '';
if ($form['view']['#value'] == 'overview') {
$header = array(t('Remove'), t('Name'), t('Label'), t('Default'), t('Required'), t('List position'), t('Display'));
$rows = array();
foreach (element_children($form['attributes']) as $aid) {
$rows[] = array(
'data' => 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']),
),
'class' => array('draggable'),
);
}
drupal_add_tabledrag('uc-attribute-table', 'order', 'sibling', 'uc-attribute-table-ordering');
if ($form['type']['#value'] == 'class') {
$path = url('admin/store/products/classes/' . $form['id']['#value'] . '/attributes/add');
}
elseif ($form['type']['#value'] == 'product') {
$path = url('node/' . $form['id']['#value'] . '/edit/attributes/add');
}
$output = theme('table', array(
'header' => $header,
'rows' => $rows,
'attributes' => array('id' => 'uc-attribute-table'),
'empty' => t('You must first add attributes to this !type.', array('!url' => $path, '!type' => $form['type']['#value'])),
));
}
else {
$output = '
' . t('Default product SKU: @sku', array('@sku' => $model)) . '
', ); $form['default'] = array( '#type' => 'value', '#value' => $model, ); $form['table'] = array( '#prefix' => '