diff --git a/commerce_order_types.admin.inc b/commerce_order_types.admin.inc new file mode 100644 index 0000000..d518985 --- /dev/null +++ b/commerce_order_types.admin.inc @@ -0,0 +1,83 @@ +name .= ' (cloned)'; + $commerce_order_type->type = ''; + } + + $form['name'] = array( + '#title' => t('Label'), + '#type' => 'textfield', + '#default_value' => isset($commerce_order_type->name) ? $commerce_order_type->name : '', + '#description' => t('The human-readable name of this commerce order type.'), + '#required' => TRUE, + '#size' => 30, + ); + // Machine-readable type name. + $form['type'] = array( + '#type' => 'machine_name', + '#default_value' => isset($commerce_order_type->type) ? $commerce_order_type->type : '', + '#maxlength' => 32, + '#disabled' => $commerce_order_type->isLocked() && $op != 'clone', + '#machine_name' => array( + 'exists' => 'commerce_order_types_order_types', + 'source' => array('name'), + ), + '#description' => t('A unique machine-readable name for this commerce order type. It must only contain lowercase letters, numbers, and underscores.'), + ); + + $form['help'] = array( + '#type' => 'textarea', + '#default_value' => isset($commerce_order_type->help) ? $commerce_order_type->help : '', + '#description' => t('Description about the commerce order type.'), + ); + + $form['actions'] = array('#type' => 'actions'); + $form['actions']['submit'] = array( + '#type' => 'submit', + '#value' => t('Save Order Type'), + '#weight' => 40, + ); + + if (!$commerce_order_type->isLocked() && $op != 'add') { + $form['actions']['delete'] = array( + '#type' => 'submit', + '#value' => t('Delete Order Type'), + '#weight' => 45, + '#limit_validation_errors' => array(), + '#submit' => array('commerce_order_type_form_submit_delete'), + ); + } + + return $form; +} + +/** + * Submit handler for creating/editing commerce_order_type. + */ +function commerce_order_type_form_submit(&$form, &$form_state) { + $commerce_order_type = entity_ui_form_submit_build_entity($form, $form_state); + // Save and go back. + $commerce_order_type->save(); + commerce_order_configure_order_type($commerce_order_type->type); + + // Redirect user back to list of commerce order types. + $form_state['redirect'] = 'admin/commerce/config/order-types'; +} + +/** + * Submit handler for deletion button for commerce_order_type. + */ +function commerce_order_type_form_submit_delete(&$form, &$form_state) { + $form_state['redirect'] = 'admin/commerce/config/order-types/manage/' . $form_state['commerce_order_type']->type . '/delete'; +} diff --git a/commerce_order_types.entity.inc b/commerce_order_types.entity.inc new file mode 100644 index 0000000..690c2db --- /dev/null +++ b/commerce_order_types.entity.inc @@ -0,0 +1,27 @@ +id); + } + +} diff --git a/commerce_order_types.info b/commerce_order_types.info index 36ebbe6..bbc10bd 100644 --- a/commerce_order_types.info +++ b/commerce_order_types.info @@ -4,3 +4,5 @@ package = Commerce (contrib) dependencies[] = commerce_order core = 7.x configure = admin/commerce/config/order-types +files[] = commerce_order_types.admin.inc +files[] = commerce_order_types.entity.inc diff --git a/commerce_order_types.install b/commerce_order_types.install index 274fa14..d7a21d4 100644 --- a/commerce_order_types.install +++ b/commerce_order_types.install @@ -8,9 +8,18 @@ * Implements hook_schema(). */ function commerce_order_types_schema() { - $schema['commerce_order_types_order_types'] = array( + $schema['commerce_order_types'] = array( 'description' => 'Stores information about Commerce Order item types created via UI.', + 'primary key' => array('id'), + 'unique keys' => array( + 'type' => array('type'), + ), 'fields' => array( + 'id' => array( + 'type' => 'serial', + 'not null' => TRUE, + 'description' => 'Primary Key: Unique order type id.', + ), 'type' => array( 'description' => 'The machine-readable name of this type.', 'type' => 'varchar', @@ -31,9 +40,58 @@ function commerce_order_types_schema() { 'not null' => FALSE, 'size' => 'medium', ), - ), - 'primary key' => array('type'), + 'data' => array( + 'type' => 'text', + 'not null' => FALSE, + 'size' => 'big', + 'serialize' => TRUE, + 'description' => 'A serialized array of additional data related to this order type.', + ), + ) + entity_exportable_schema_fields(), ); return $schema; } + +/** + * Rename commerce_order_types_order_types_table + */ +function commerce_order_types_update_7001() { + db_rename_table('commerce_order_types_order_types', 'commerce_order_types'); + // Add our primary key. + db_drop_primary_key('commerce_order_types'); + $spec = array( + 'type' => 'serial', + 'not null' => TRUE, + 'description' => 'Primary Key: Unique order type id.', + ); + $keys = array( + 'primary key' => array('id'), + ); + db_add_field('commerce_order_types', 'id', $spec, $keys); + // Add our unique keys. + db_add_unique_key('commerce_order_types', 'type', array('type')); + // Get an array of all the field definitions. + $fields = array( + 'id' => array( + 'type' => 'serial', + 'not null' => TRUE, + 'description' => 'Primary Key: Unique order type id.', + ), + 'data' => array( + 'type' => 'text', + 'not null' => FALSE, + 'size' => 'big', + 'serialize' => TRUE, + 'description' => 'A serialized array of additional data related to this order type.', + ), + ) + entity_exportable_schema_fields(); + // Add all our fields to the table. + foreach ($fields as $field => $spec) { + db_add_field('commerce_order_types', $field, $spec); + } + // We have changed the name of the table, so let's clear the schema cache. + drupal_get_complete_schema(TRUE); + // The exportable entity changes also need to clear the caches. + drupal_flush_all_caches(); +} diff --git a/commerce_order_types.module b/commerce_order_types.module index ebc180a..7e64512 100644 --- a/commerce_order_types.module +++ b/commerce_order_types.module @@ -11,40 +11,19 @@ */ function commerce_order_types_menu() { $items = array(); - - $items['admin/commerce/config/order-types'] = array( - 'title' => 'Order Types', - 'description' => 'Manage and create order types', - 'page callback' => 'commerce_order_types_order_types_overview', - 'access arguments' => array('administer order types'), - ); - - $items['admin/commerce/config/order-types/add'] = array( - 'title' => 'Add order type', - 'description' => 'Add additional commerce order types', - 'page callback' => 'drupal_get_form', - 'page arguments' => array('commerce_order_types_order_type_form', array()), - 'access arguments' => array('administer order types'), - 'type' => MENU_LOCAL_ACTION, - ); - - foreach (commerce_order_types_order_types(TRUE) as $type => $order_type) { - if (isset($order_type['module']) && $order_type['module'] == 'commerce_order_types') { - // Convert underscores to hyphens for the menu item argument. - $type_arg = strtr($type, '_', '-'); - - $items['admin/commerce/config/order-types/' . $type_arg . '/edit'] = array( - 'title' => 'Edit', - 'access arguments' => array('administer order types'), - 'type' => MENU_DEFAULT_LOCAL_TASK, - ); - $items['admin/commerce/config/order-types/' . $type_arg . '/delete'] = array( - 'title' => 'Delete', - 'page callback' => 'commerce_order_types_order_type_delete_form_wrapper', - 'page arguments' => array($type), - 'access arguments' => array('administer order types'), - 'type' => MENU_LOCAL_TASK, - 'weight' => 10, + if (module_exists('commerce_order_ui')) { + foreach (commerce_order_types_order_types() as $type => $info) { + $items['admin/commerce/orders/add/' . $type] = array( + 'title' => 'Add order @type', + 'title arguments' => array('@type' => $info->name), + 'description' => $info->help, + 'page callback' => 'commerce_order_ui_order_form_wrapper', + 'page arguments' => array(commerce_order_new(0, NULL, $type)), //type + 'access callback' => 'commerce_order_access', + 'access arguments' => array('create'), + 'type' => MENU_NORMAL_ITEM, + 'file' => 'includes/commerce_order_ui.orders.inc', + 'file path' => drupal_get_path('module', 'commerce_order_ui'), ); } } @@ -52,40 +31,6 @@ function commerce_order_types_menu() { } /** - * Implements hook_menu_alter(). - */ -function commerce_order_types_menu_alter(&$items) { - foreach (commerce_order_types_order_types() as $type => $order_type) { - if (isset($order_type['module']) && $order_type['module'] == 'commerce_order_types') { - // Convert underscores to hyphens for the menu item argument. - $type_arg = strtr($type, '_', '-'); - // Add the order admin screens. - if (module_exists('commerce_order_ui')) { - $items['admin/commerce/orders/add/' . $type_arg] = array( - 'title' => $order_type['name'], - 'page callback' => 'commerce_order_ui_order_form_wrapper', - 'page arguments' => array(commerce_order_new(0, NULL, $type)), - 'access callback' => 'commerce_order_access', - 'access arguments' => array('create'), - 'file' => 'includes/commerce_order_ui.orders.inc', - 'file path' => drupal_get_path('module', 'commerce_order_ui'), - ); - } - - $items['admin/commerce/config/order-types/' . $type_arg] = array( - 'title' => $order_type['name'], - 'page callback' => 'commerce_order_types_order_type_form_wrapper', - 'page arguments' => array($type), - 'access arguments' => array('administer order types'), - ); - - $items['admin/commerce/config/order-types/' . $type_arg . '/fields']['context'] = MENU_CONTEXT_PAGE | MENU_CONTEXT_INLINE; - $items['admin/commerce/config/order-types/' . $type_arg . '/display']['context'] = MENU_CONTEXT_PAGE | MENU_CONTEXT_INLINE; - } - } -} - -/** * Implements hook_menu_local_tasks_alter(). */ function commerce_order_types_menu_local_tasks_alter(&$data, $router_item, $root_path) { @@ -95,6 +40,7 @@ function commerce_order_types_menu_local_tasks_alter(&$data, $router_item, $root $type_arg = strtr($type, '_', '-'); $item = menu_get_item('admin/commerce/orders/add/' . $type_arg); if ($item['access']) { + $item['title'] = 'Create ' . $order_type->name . ' order'; $data['actions']['output'][] = array( '#theme' => 'menu_local_action', '#link' => $item, @@ -105,15 +51,48 @@ function commerce_order_types_menu_local_tasks_alter(&$data, $router_item, $root } /** + * Implements hook_entity_info(). + */ +function commerce_order_types_entity_info() { + $info['commerce_order_type'] = array( + 'label' => t('Order type'), + 'plural label' => t('Order types'), + 'description' => t('Types of commerce order.'), + 'entity class' => 'CommerceOrderType', + 'controller class' => 'EntityAPIControllerExportable', + 'base table' => 'commerce_order_types', + 'fieldable' => FALSE, + 'bundle of' => 'commerce_order', + 'exportable' => TRUE, + 'entity keys' => array( + 'id' => 'id', + 'name' => 'type', + 'label' => 'name', + ), + 'access callback' => 'commerce_order_type_access', + 'module' => 'commerce_order_types', + // Enable the entity API's admin UI. + 'admin ui' => array( + 'path' => 'admin/commerce/config/order-types', + 'file' => 'commerce_order_types.admin.inc', + 'controller class' => 'EntityDefaultUIController', + ), + ); + + return $info; +} + +/** * Implements hook_entity_info_alter(). */ function commerce_order_types_entity_info_alter(&$entity_info) { - foreach (commerce_order_types_order_types() as $type => $order_type) { - $type_arg = strtr($type, '_', '-'); + foreach (commerce_order_types_order_types() as $type => $info) { $entity_info['commerce_order']['bundles'][$type] = array( - 'label' => $order_type['name'], + 'label' => $info->name, 'admin' => array( - 'path' => 'admin/commerce/config/order-types/' . $type_arg, + 'path' => 'admin/commerce/config/order-types/manage/%commerce_order_type', + 'real path' => 'admin/commerce/config/order-types/manage/' . $type, + 'bundle argument' => 5, 'access arguments' => array('administer order types'), ), ); @@ -125,10 +104,10 @@ function commerce_order_types_entity_info_alter(&$entity_info) { */ function commerce_order_types_help($path, $arg) { // Display the order type's help on the order add page. - if (strpos($path, 'admin/commerce/orders/add') === 0) { - $type = $arg[4]; - $order_type = commerce_order_types_order_type_load($type); - $help = $order_type['help']; + if (strpos($path, 'admin/commerce/orders/add') === 0 && !empty($arg[5])) { + $type = $arg[5]; + $order_type = commerce_order_types_order_types($type); + $help = $order_type->help; if (!empty($help)) { return '

' . filter_xss_admin($help) . '

'; @@ -137,334 +116,80 @@ function commerce_order_types_help($path, $arg) { } /** - * Implements hook_permission(). + * Implements hook_admin_menu_map(). */ -function commerce_order_types_permission() { - return array( - 'administer order types' => array( - 'title' => t('Administer order types'), - 'description' => t('Create new order types and configure fields for them.'), - 'restrict access' => TRUE, - ), - ); -} - -/** - * Implements hook_form_FORM_ID_alter(). - */ -function commerce_order_types_form_commerce_order_settings_form_alter(&$form, &$form_state) { - // Change the description of the order settings form for accuracy. - $form['commerce_order_help_text']['#description'] = t('Supply an optional help message to be displayed above the order add form on all order types.'); -} - -/** - * Menu callback. - * - * Displays the order type admin overview page. - */ -function commerce_order_types_order_types_overview() { - $types = commerce_order_types_order_types(); - $field_ui = module_exists('field_ui'); - $header = array(t('Name'), array( - 'data' => t('Operations'), - 'colspan' => $field_ui ? '4' : '2', - )); - $rows = array(); - - foreach ($types as $type => $order_type) { - $row = array(); - $row[] = check_plain($order_type['name']); - $type_arg = strtr($type, '_', '-'); - $row[] = array('data' => l(t('edit'), 'admin/commerce/config/order-types/' . $type_arg . '/edit')); - - if ($field_ui) { - $row[] = array('data' => l(t('manage fields'), 'admin/commerce/config/order-types/' . $type_arg . '/fields')); - $row[] = array('data' => l(t('manage display'), 'admin/commerce/config/order-types/' . $type_arg . '/display')); - } - $row[] = array('data' => l(t('delete'), 'admin/commerce/config/order-types/' . $type_arg . '/delete')); - - $rows[] = $row; - } - - // Output a render array. - $build['order_types'] = array( - '#theme' => 'table', - '#header' => $header, - '#rows' => $rows, - '#empty' => t('No custom order types available. Add order type.', array('@link' => url('admin/commerce/config/order-types/add'))), - ); - - return $build; -} - -/** - * Return a blank, new commerce order type. - */ -function commerce_order_types_order_type_new() { - return array( - 'type' => '', - 'name' => '', - 'help' => '', - ); -} - -/** - * Form callback wrapper: create or edit an order type. - * - * @param string $type - * The machine-name of the order type being created or edited by this form - * or a full order type array. - */ -function commerce_order_types_order_type_form_wrapper($type) { - if (is_array($type)) { - $order_type = $type; - } - else { - $order_type = commerce_order_types_order_type_load($type); - } - - // Not allow to alter any code provided order type. - if (!isset($order_type['module']) || $order_type['module'] <> 'commerce_order_types') { - return t('This order type cannot be edited because it is not defined by the Custom Order Types module.'); - } - - return drupal_get_form('commerce_order_types_order_type_form', $order_type); -} - -/** - * Form callback - comfirmation form for deleting an order type. - * - * @param string $type - * The machine-readable name of the order type - */ -function commerce_order_types_order_type_delete_form_wrapper($type) { - if (is_array($type)) { - $order_type = $type; - } - else { - $order_type = commerce_order_types_order_type_load($type); - } - - // Not allowed to delete any code provided order type. - if (!isset($order_type['module']) || $order_type['module'] <> 'commerce_order_types') { - return t('This order type cannot be deleted because it is not defined by the Commerce Order Types module.'); +function commerce_order_types_admin_menu_map() { + $map = $arguments = array(); + $commerce_order_types = array_keys(commerce_order_types_order_types()); + foreach ($commerce_order_types as $type) { + $arguments[] = array( + '%commerce_order_type' => array($type), + '%entity_object' => array($type), + ); } - // Don't allow deletion of order types that have orders. - if (($count = db_query("SELECT order_id FROM {commerce_order} WHERE type = :order_type", array(':order_type' => $order_type['type']))->rowCount()) > 0) { - drupal_set_title(t('Cannot delete the %name order type', array('%name' => $order_type['name'])), PASS_THROUGH); - return format_plural($count, - 'There is 1 order of this type. It cannot be deleted.', - 'There are @count orders of this type. It cannot be deleted.' + if ($arguments) { + $map['admin/commerce/config/order-types/manage/%commerce_order_type'] = array( + // Link generated items directly to the "commerce order types" item. + 'parent' => 'admin/commerce/config/order-types', + // Hide the "List" item, as this expansion will expose all available + // options. + 'hide' => 'admin/commerce/config/order-types/list', + // Create expansion arguments for the '%commerce_order_type' placeholder. + 'arguments' => $arguments, ); } - return drupal_get_form('commerce_order_types_order_type_delete_form', $order_type); + return $map; } /** - * Form callback: confirmation form for deleting a line item type. - * - * @param array $order_type - * The order type array to be deleted. - * - * @see confirm_form() + * Implements hook_permission(). */ -function commerce_order_types_order_type_delete_form($form, &$form_state, $order_type) { - $form_state['order_type'] = $order_type; - - $form['#submit'][] = 'commerce_order_types_order_type_delete_form_submit'; - - $form = confirm_form($form, - t('Are you sure you want to delete the %name order type?', array('%name' => $order_type['name'])), - 'admin/commerce/config/order-types', - '

' . t('This action cannot be undone.') . '

', - t('Delete'), - t('Cancel'), - 'confirm' +function commerce_order_types_permission() { + return array( + 'administer order types' => array( + 'title' => t('Administer order types'), + 'description' => t('Create new order types and configure fields for them.'), + 'restrict access' => TRUE, + ), ); - - return $form; } /** - * Submit callback for commerce_order_types_order_type_delete_form(). - */ -function commerce_order_types_order_type_delete_form_submit($form, &$form_state) { - $order_type = $form_state['order_type']; - - commerce_order_types_order_type_delete($order_type['type']); - - drupal_set_message(t('The order type %name has been deleted.', array('%name' => $order_type['name']))); - watchdog('commerce_order', 'Deleted order type %name.', array('%name' => $order_type['name']), WATCHDOG_NOTICE); - - $form_state['redirect'] = 'admin/commerce/config/order-types'; -} - -/** - * Order type create/edit form. + * Implements hook_module_implements_alter(). * - * @param array $order_type - * The order type array to edit or for a create for an empty type - * array with properties instantiated but not populated. - */ -function commerce_order_types_order_type_form($form, &$form_state, $order_type = array()) { - if (empty($order_type)) { - $order_type = commerce_order_types_order_type_new(); - } - - $form_state['order_type'] = $order_type; - - $form['order_type'] = array( - '#tree' => TRUE, - ); - - $form['order_type']['name'] = array( - '#type' => 'textfield', - '#title' => t('Order type name'), - '#default_value' => $order_type['name'], - '#description' => t('The human-readable name of this order type. It is recommended that this name begin with a capital letter and contain only letters, numbers, and spaces. This name must be unique.'), - '#required' => TRUE, - '#size' => 32, - ); - - if (empty($order_type['type'])) { - $form['order_type']['type'] = array( - '#type' => 'machine_name', - '#title' => t('Machine name'), - '#default_value' => $order_type['type'], - '#maxlength' => 32, - '#required' => TRUE, - '#machine_name' => array( - 'exists' => 'commerce_order_types_order_type_load', - 'source' => array('order_type', 'name'), - ), - '#description' => t('The machine-readable name of this order type. This name must contain only lowercase letters, numbers, and underscores, it must be unique.'), - ); - } - - $form['order_type']['help'] = array( - '#type' => 'textarea', - '#title' => t('Order creation help text'), - '#description' => t('Supply an optional help message to be displayed above the order add form.'), - '#default_value' => $order_type['help'], - '#rows' => 5, - ); - - $form['actions'] = array( - '#type' => 'container', - '#attributes' => array('class' => array('form-actions')), - '#weight' => 40, - ); - - $form['actions']['submit'] = array( - '#type' => 'submit', - '#value' => t('Save order type'), - '#submit' => array('commerce_order_types_order_type_form_submit'), - ); - - return $form; -} - -/** - * Form submit handler: save an order type. + * Make sure our entity info hook runs after commerce_order. */ -function commerce_order_types_order_type_form_submit(&$form, &$form_state) { - $order_type = $form_state['order_type']; - $updated = !empty($order_type['type']); - - // If a type is set, we should still check to see if a row for the type exists - // in the database; this is done to accomodate types defined by Features. - if ($updated) { - $updated = db_query('SELECT 1 FROM {commerce_order_types_order_types} WHERE type = :type', array(':type' => $order_type['type']))->fetchField(); +function commerce_order_types_module_implements_alter(&$implementations, $hook) { + if ($hook == 'entity_info_alter') { + $group = $implementations['commerce_order_types']; + unset($implementations['commerce_order_types']); + $implementations['commerce_order_types'] = $group; } - - foreach ($form_state['values']['order_type'] as $key => $value) { - $order_type[$key] = $value; - } - - // Write the order type to the database. - $order_type['is_new'] = !$updated; - commerce_order_types_commerce_order_type_save($order_type); - - // Add default fields to the order type. - commerce_order_configure_order_type($order_type['type']); - - drupal_set_message(t('Order type saved.')); - - $form_state['redirect'] = 'admin/commerce/config/order-types'; - - } /** - * Checks to see if a given order type already exists. - * - * @param string $type - * The string to match against existing types. - * - * @return bool - * TRUE or FALSE indicating whether or not the order type exists. + * Access callback for commerce order types. */ -function commerce_order_types_order_type_unique($type) { - // Look for a match of the type. - if ($match_id = db_query('SELECT type FROM {commerce_order_types_order_types} WHERE type = :type', array(':type' => $type))->fetchField()) { - return FALSE; - } - return TRUE; +function commerce_order_type_access($op, $commerce_order_type, $account = NULL) { + return user_access('administer order types', $account); } -/** - * Save an order type. - * - * @param array $order_type - * The order type to be saved. - */ -function commerce_order_types_commerce_order_type_save($order_type, $skip_reset = FALSE) { - $op = drupal_write_record('commerce_order_types_order_types', $order_type, empty($order_type['is_new']) ? 'type' : array()); - - // If this is a new type and the insert did not fail... - if (!empty($order_type['is_new']) && $op !== FALSE) { - // Notify the field API that a new bundle has been created. - field_attach_create_bundle('commerce_order', $order_type['type']); - } - // Rebuild the menu to get add this type's order add menu items. - if (!$skip_reset) { - menu_rebuild(); - } - - variable_set('menu_rebuild_needed', TRUE); - - return $op; -} /** - * Loads an order type. - * - * @param string $type - * The machine-readable name of the order type; accepts normal machine names - * and URL prepared machine names with underscores replaced by hyphens. + * Load commerce order Type. */ -function commerce_order_types_order_type_load($type) { - $type = strtr($type, array('-' => '_')); - $order_types = commerce_order_types_order_types(); - return !empty($order_types[$type]) ? $order_types[$type] : FALSE; +function commerce_order_type_load($type) { + return commerce_order_types_order_types($type); } /** * Returns an array of commerce order types as defined by this module. */ -function commerce_order_types_order_types($reset = FALSE) { - $order_types = &drupal_static(__FUNCTION__); - - - if (!isset($order_types) || $reset) { - $order_types = db_query('SELECT * FROM {commerce_order_types_order_types}')->fetchAllAssoc('type', PDO::FETCH_ASSOC); - foreach ($order_types as $type => $order_type) { - $order_types[$type]['module'] = 'commerce_order_types'; - } - } - return $order_types; +function commerce_order_types_order_types($type = FALSE) { + $types = entity_load_multiple_by_name('commerce_order_type', !empty($type) ? array($type) : FALSE); + return !empty($type) ? reset($types) : $types; } /** @@ -479,7 +204,7 @@ function commerce_order_types_order_types($reset = FALSE) { * is very costly in terms of performance. */ function commerce_order_types_order_type_delete($type, $skip_reset = FALSE) { - $order_type = commerce_order_types_order_type_load($type); + $order_type = commerce_order_types_order_types($type); db_delete('commerce_order_types_order_types') ->condition('type', $type)