commerce_registration.module in Commerce Registration 7.3
Same filename and directory in other branches
Commerce Registration module code.
File
commerce_registration.moduleView source
<?php
/**
* @file
* Commerce Registration module code.
*/
/**
* Implements hook_menu().
*/
function commerce_registration_menu() {
$menu = array();
$menu['admin/commerce/registrations'] = array(
'title' => 'Registrations',
'description' => 'Manage product registrations that have been purchased.',
'access arguments' => array(
'administer registration',
),
'page callback' => 'commerce_registration_admin_overview',
'page arguments' => array(
'complete',
),
'file' => 'includes/commerce_registration.admin.inc',
);
$menu['admin/commerce/registrations/complete'] = array(
'title' => 'Completed Registrations',
'description' => 'Manage product registrations that have been purchased.',
'access arguments' => array(
'administer registration',
),
'page callback' => 'commerce_registration_admin_overview',
'page arguments' => array(
'complete',
),
'file' => 'includes/commerce_registration.admin.inc',
'type' => MENU_DEFAULT_LOCAL_TASK,
'weight' => -1,
);
$menu['admin/commerce/registrations/all'] = array(
'title' => 'All Registrations',
'description' => 'Manage product registrations that have been purchased.',
'access arguments' => array(
'administer registration',
),
'page callback' => 'commerce_registration_admin_overview',
'file' => 'includes/commerce_registration.admin.inc',
'type' => MENU_LOCAL_TASK,
'weight' => 0,
);
return $menu;
}
/**
* Implements hook_menu_alter().
*/
function commerce_registration_menu_alter(&$items) {
$items['node/%entity_object/registrations']['module'] = 'commerce_registration';
$items['node/%entity_object/registrations']['access callback'] = 'commerce_registration_administer_registrations_access';
$items['node/%entity_object/registrations']['file'] = 'includes/commerce_registration.admin.inc';
$items['node/%entity_object/registrations']['page callback'] = 'commerce_registration_registration_settings_tab';
}
/**
* Implements hook_theme().
*/
function commerce_registration_theme($existing, $type, $theme, $path) {
return array(
'commerce_registration_review_pane' => array(
'variables' => array(
'product' => NULL,
'registrations' => array(),
'line_item' => NULL,
),
'file' => 'includes/commerce_registration.theme.inc',
),
'commerce_registration_review_registration' => array(
'variables' => array(
'registration' => NULL,
),
'file' => 'includes/commerce_registration.theme.inc',
),
);
}
/**
* Access callback for modifying registration settings for a given product
* display (node).
*/
function commerce_registration_administer_registrations_access($entity_type, $entity) {
// Check if we want to hide the tab initially, if so we don't need to check
// anything else.
if (commerce_registration_hide_tab($entity_type, $entity)) {
return FALSE;
}
// Loop through each product on the node, and if it contains a registration
// type and the user can administer them, then we allow it.
$fields = field_read_fields(array(
'type' => 'commerce_product_reference',
));
foreach ($fields as $field) {
if (isset($entity->{$field['field_name']})) {
foreach ($entity->{$field['field_name']} as $product) {
$product = commerce_product_load($product[0]['product_id']);
if ($type = registration_get_entity_registration_type('commerce_product', $product)) {
if (user_access('administer registration') || user_access("administer {$type} registration")) {
return TRUE;
}
}
}
}
}
return registration_administer_registrations_access($entity_type, $entity);
}
/**
* Check if the node has set to hide the manage registrations tab.
*/
function commerce_registration_hide_tab($entity_type, $entity) {
$settings = commerce_registration_get_entity_settings($entity_type, $entity);
if (isset($settings['hide_manage_tab'])) {
return $settings['hide_manage_tab'];
}
return FALSE;
}
/**
* Implements hook_commerce_checkout_pane_info().
*/
function commerce_registration_commerce_checkout_pane_info() {
$panes = array();
$panes['registration_information'] = array(
'title' => t('Registration information'),
'base' => 'commerce_registration_information',
'page' => 'checkout',
'enabled' => TRUE,
'weight' => -50,
'review' => TRUE,
'file' => 'includes/commerce_registration.checkout_pane.inc',
);
return $panes;
}
/**
* Implements hook_commerce_line_item_type_info_alter().
*/
function commerce_registration_commerce_line_item_type_info_alter(&$line_item_types) {
$line_item_types['product']['callbacks']['title'] = 'commerce_registration_product_title';
}
/**
* Product title line item callback.
*
* We alter the title of the default line item to show available slots if the
* product is register enabled.
*
* @param CommerceLineItem $line_item
* The line item to get the title for.
*
* @return string
* Title of the line item product plus available slots, if applicable.
*/
function commerce_registration_product_title($line_item) {
$wrapper = entity_metadata_wrapper('commerce_line_item', $line_item);
if (commerce_registration_product_has_registration_field($wrapper->commerce_product->product_id
->value())) {
return commerce_registration_get_product_title($wrapper->commerce_product
->value(), TRUE);
}
}
/**
* Returns a product title.
*
* @param CommerceProduct $product
* Fully formed Commerce Product object.
*
* @return string
* Product title with remaining capacity if available.
*/
function commerce_registration_get_product_title($product, $showavail = TRUE) {
// @TODO: Clean up this code, include options to show availability and capacity.
$settings = registration_entity_settings('commerce_product', $product->product_id);
if (!empty($settings) && $settings['status'] == 1 && $showavail) {
$capacity = (int) $settings['capacity'];
$filled = (int) registration_event_count('commerce_product', $product->product_id);
$avail = $capacity - $filled;
$availtext = $avail > 0 ? format_plural($avail, '1 slot available', '@count slots available') : 'No slots available';
$capacitytext = $capacity == 0 ? 'Unlimited slots available' : $availtext;
return t('@title (%capacity)', array(
'@title' => $product->title,
'%capacity' => $capacitytext,
));
}
return $product->title;
}
/**
* Implements hook_entity_property_info_alter().
*/
function commerce_registration_entity_property_info_alter(&$info) {
$info['registration']['properties']['lineitem_id'] = array(
'label' => t('Line Item ID'),
'type' => 'integer',
'schema field' => 'lineitem_id',
'setter callback' => 'entity_property_verbatim_set',
'getter callback' => 'entity_property_verbatim_get',
'description' => t('The line item ID to which this registration belongs.'),
);
$info['commerce_line_item']['properties']['registrations'] = array(
'label' => t('Registrations'),
'type' => 'entities',
'schema field' => 'registrations',
'description' => t('A collection of registration entities associated with this line item.'),
'setter callback' => 'entity_property_verbatim_set',
'getter callback' => 'commerce_registration_registrations_property_get',
);
}
/**
* Entity getter callback to unserialize our registration property.
*/
function commerce_registration_registrations_property_get($data, array $options, $name, $type, $info) {
$name = isset($info['schema field']) ? $info['schema field'] : $name;
if ((is_array($data) || is_object($data) && $data instanceof ArrayAccess) && isset($data[$name])) {
if (is_string($data[$name])) {
return unserialize($data[$name]);
}
return $data[$name];
}
elseif (is_object($data) && isset($data->{$name})) {
// Incorporate i18n_string translations. We may rely on the entity class
// here as its usage is required by the i18n integration.
if (isset($options['language']) && !empty($info['i18n string'])) {
return $data
->getTranslation($name, $options['language']->language);
}
else {
if (is_string($data->{$name})) {
return unserialize($data->{$name});
}
return $data->{$name};
}
}
return NULL;
}
/**
* Implements hook_views_api().
*/
function commerce_registration_views_api() {
return array(
'api' => 3,
'path' => drupal_get_path('module', 'commerce_registration') . '/includes/views',
);
}
/**
* Implements hook_field_extra_fields().
*/
function commerce_registration_field_extra_fields() {
$items = array();
// Add registration availability display option to each commerce product type.
foreach (field_info_instances('commerce_product') as $product_bundle_name => $product_fields) {
foreach ($product_fields as $product_field_name => $product_field) {
if ($product_field['widget']['module'] == 'registration') {
$items['commerce_product'][$product_bundle_name]['display']['registration_available'] = array(
'label' => t('Registration Availability'),
'description' => t('The Registration availability text next to the product.'),
'weight' => -1,
);
}
}
}
return $items;
}
/**
* Implements hook_field_extra_fields_alter().
*/
function commerce_registration_field_extra_fields_alter(&$info) {
// Loop through the product reference fields.
foreach (commerce_info_fields('commerce_product_reference') as $field_name => $field) {
foreach ($field['bundles'] as $entity_type => $bundles) {
if ($entity_type == 'commerce_line_item' || $entity_type == 'commerce_product') {
// Skip line items and products, don't want to remove these fields.
continue;
}
foreach ($bundles as $bundle_name) {
$product_fields = commerce_product_field_extra_fields();
if (empty($product_fields['commerce_product'])) {
// Skip if there are no commerce product extra fields.
continue;
}
// Loop through each field on the product, and if it's a Registration,
// hide it.
foreach ($product_fields['commerce_product'] as $key => $value) {
foreach ($value['display'] as $product_extra_field_name => $product_extra_field) {
if ($product_extra_field['label'] == t('Registration')) {
$tempfield =& $info[$entity_type][$bundle_name]['display']['product:' . $product_extra_field_name]['display'];
foreach ($tempfield as $display => $settings) {
$tempfield[$display]['visible'] = FALSE;
}
}
}
}
// Loop through all field instances on products, and if each field is a
// registration, hide it.
foreach (field_info_instances('commerce_product') as $product_bundle_name => $product_fields) {
foreach ($product_fields as $product_field_name => $product_field) {
if ($product_field['label'] == t('Registration')) {
$info[$entity_type][$bundle_name]['display']['product:' . $product_field_name]['configurable'] = FALSE;
$info[$entity_type][$bundle_name]['display']['product:' . $product_field_name]['visible'] = FALSE;
$info[$entity_type][$bundle_name]['display']['product:' . $product_field_name]['weight'] = 0;
}
}
}
}
}
}
}
/**
* Implements hook_entity_info_alter().
*/
function commerce_registration_entity_info_alter(&$info) {
$info['registration']['view modes']['review_pane'] = array(
'label' => t('Commerce Checkout Review Pane'),
'custom settings' => TRUE,
);
}
/**
* Checks if a product has a registration field attached.
*
* @param int $product_id The product id.
*
* @return boolean
* Whether a product has a registration field attached.
*/
function commerce_registration_product_has_registration_field($product_id) {
$product = commerce_product_load($product_id);
$fields = field_read_fields(array(
'type' => 'registration',
));
foreach ($fields as $field) {
if (isset($product->{$field['field_name']}) && !empty($product->{$field['field_name']}[LANGUAGE_NONE]['0']['registration_type'])) {
return TRUE;
}
}
return FALSE;
}
/**
* Helper function that returns the registration field name on the given entity.
*
* @param string $entity_type The type of entity.
* @param object $entity The entity object.
* @return
* The registration field name, or FALSE if none exist on the entity.
*/
function commerce_registration_registration_field_instance($entity_type, $entity) {
list(, , $bundle) = entity_extract_ids($entity_type, $entity);
$fields = field_read_fields(array(
'type' => 'registration',
));
foreach ($fields as $field) {
$options = array(
'field_name' => $field['field_name'],
'entity_type' => $entity_type,
'bundle' => $bundle,
);
$instance = reset(field_read_instances($options));
if (count($instance) > 0) {
return $instance;
}
}
return FALSE;
}
/**
* Implements hook_form_FORM_ID_alter().
*/
function commerce_registration_form_commerce_product_ui_product_form_alter(&$form, &$form_state) {
commerce_registration_modify_entity_registration_form($form, $form_state);
}
/**
* Implements hook_inline_entity_form_entity_form_alter().
*/
function commerce_registration_inline_entity_form_entity_form_alter(&$form, &$form_state) {
commerce_registration_modify_entity_registration_form($form, $form_state);
}
/**
* Implements hook_form_FORM_ID_alter().
*/
function commerce_registration_form_node_form_alter(&$form, &$form_state) {
$settings = commerce_registration_get_entity_settings('node', $form['#node']);
$form['#submit'][] = 'commerce_registration_node_form_submit';
$form['commerce_registration'] = array(
'#type' => 'fieldset',
'#group' => 'additional_settings',
'#title' => t('Commerce Registration settings'),
'#help' => t('Stuff'),
'#weight' => '-1',
'#tree' => TRUE,
'#attributes' => array(
'class' => array(
'commerce-registration-settings-form',
),
),
'#attached' => array(
'js' => array(
drupal_get_path('module', 'commerce_registration') . '/includes/js/commerce_registration.form.js',
),
),
);
$form['commerce_registration']['hide_manage_tab'] = array(
'#type' => 'checkbox',
'#title' => t('Hide %manage tab', array(
'%manage' => 'Manage Registrations',
)),
'#default_value' => isset($settings['hide_manage_tab']) ? $settings['hide_manage_tab'] : 0,
);
}
/**
* Node form submit handler to update our entity settings.
*/
function commerce_registration_node_form_submit($form, $form_state) {
$settings = $form_state['values']['commerce_registration'];
commerce_registration_update_entity_settings('node', $form['#node'], $settings);
}
/**
* Update settings for the given entity.
*/
function commerce_registration_update_entity_settings($entity_type, $entity, $settings) {
$default_settings = module_invoke_all('commerce_registration_entity_settings', $entity_type, $entity);
list($entity_id, , $bundle) = entity_extract_ids($entity_type, $entity);
$settings = array_unique(array_merge($default_settings, $settings));
db_merge('commerce_registration_settings')
->key(array(
'entity_type' => $entity_type,
'entity_id' => $entity_id,
'entity_bundle' => $bundle,
))
->fields(array(
'entity_type' => $entity_type,
'entity_id' => $entity_id,
'entity_bundle' => $bundle,
'settings' => serialize($settings),
))
->execute();
}
/**
* Returns the entity settings for the given entity.
*/
function commerce_registration_get_entity_settings($entity_type, $entity, $reset = FALSE) {
$settings =& drupal_static(__FUNCTION__, NULL, $reset);
list($entity_id, , $bundle) = entity_extract_ids($entity_type, $entity);
if (!isset($settings[$entity_type][$entity_id]) || $reset) {
$default_settings = module_invoke_all('commerce_registration_entity_default_settings', $entity_type, $entity);
$db_settings = db_select('commerce_registration_settings', 'crs')
->fields('crs', array(
'settings',
))
->condition('entity_type', $entity_type)
->condition('entity_id', $entity_id)
->condition('entity_bundle', $bundle)
->execute()
->fetchCol();
if (!empty($db_settings)) {
$db_settings = $db_settings[0];
if (!is_array($db_settings)) {
$db_settings = unserialize($db_settings);
}
}
else {
$db_settings = array();
}
$settings[$entity_type][$entity_id] = array_unique(array_merge($default_settings, $db_settings));
}
return $settings[$entity_type][$entity_id];
}
/**
* Implements hook_commerce_registration_entity_settings().
*/
function commerce_registration_commerce_registration_entity_default_settings($type, $entity) {
if ($type == 'node') {
return array(
'hide_manage_tab' => FALSE,
);
}
}
/**
* Helper function that adds registration settings to the form.
*/
function commerce_registration_modify_entity_registration_form(&$form, &$form_state) {
if ($form['#entity_type'] == 'commerce_product') {
$field_instance = commerce_registration_registration_field_instance($form['#entity_type'], $form['#entity']);
if ($field_instance !== FALSE) {
$empty = array();
$settings = array();
list($entity_id) = entity_extract_ids($form['#entity_type'], $form['#entity']);
if (!empty($entity_id)) {
$settings = registration_entity_settings($form['#entity_type'], $entity_id);
}
if (empty($settings)) {
$settings = $field_instance['settings']['default_registration_settings'];
}
$weight = $form[$field_instance['field_name']]['#weight'] + 1;
$settings_form = registration_entity_settings_form(array(), $empty, $settings, 'commerce_product', $entity_id);
unset($settings_form['save']);
$form[$field_instance['field_name'] . '_settings'] = array(
'#tree' => TRUE,
'#title' => t('Registration Settings'),
'#type' => 'fieldset',
'#collapsible' => TRUE,
'#collapsed' => TRUE,
'#element_validate' => array(
'commerce_registration_entity_registration_form_submit',
),
'#weight' => $weight,
) + $settings_form;
// Add our additional settings to the form.
drupal_alter('commerce_registration_registration_settings_form', $form[$field_instance['field_name'] . '_settings']['settings'], $form_state, $settings);
}
}
}
/**
* Submit handler to save registration settings.
*/
function commerce_registration_entity_registration_form_submit($form, $form_state) {
if (isset($form_state['inline_entity_form'])) {
if ($form_state['triggering_element']['#value'] != 'Cancel') {
// We came from an IEF form, and the user didn't hit 'cancel'.
foreach ($form_state['values']['field_products'][LANGUAGE_NONE]['entities'] as $product) {
if (isset($product['form'])) {
// There is form data to process, so process it and update settings.
$product_id = commerce_product_load_by_sku($product['form']['sku']);
$field_instance = commerce_registration_registration_field_instance('commerce_product', $product_id);
$product_id = $product_id->product_id;
$settings = $product['form'][$field_instance['field_name'] . '_settings'];
$fields = registration_convert_form_settings($settings);
registration_update_entity_settings('commerce_product', $product_id, $fields);
}
}
}
}
else {
// We came from a normal form, so find settings in the form state.
$product = $form_state['commerce_product'];
$field_instance = commerce_registration_registration_field_instance('commerce_product', $product);
$settings = $form_state['values'][$field_instance['field_name'] . '_settings'];
$fields = registration_convert_form_settings($settings);
registration_update_entity_settings('commerce_product', $product->product_id, $fields);
}
}
/**
* Implements hook_commerce_registration_registration_settings_form_alter().
*/
function commerce_registration_commerce_registration_registration_settings_form_alter(&$form, &$form_state, $settings) {
$form['limit_registrations'] = array(
'#type' => 'radios',
'#title' => t('Limit registrations by number of'),
'#options' => array(
'slots' => t('slots per product'),
'registrations' => t('registrations per product'),
),
'#default_value' => isset($settings['limit_registrations']) ? $settings['limit_registrations'] : 'slots',
'#required' => TRUE,
);
$form['registrations_per_product'] = array(
'#type' => 'textfield',
'#title' => t('Number of unique registrations per product'),
'#description' => t('The number of registrations that are required for a single product purchase. For example, a single product may require 5 registrations.'),
'#default_value' => isset($settings['registrations_per_product']) ? $settings['registrations_per_product'] : 1,
'#states' => array(
'visible' => array(
':input[name*="limit_registrations"]' => array(
'value' => 'registrations',
),
),
),
'#required' => TRUE,
);
$form['slots_per_product'] = array(
'#type' => 'textfield',
'#title' => t('Number of slots per product'),
'#description' => t('The number of registration slots that a single registration per product purchase will take. For example, a single product may fill 5 slots.'),
'#default_value' => isset($settings['slots_per_product']) ? $settings['slots_per_product'] : 1,
'#states' => array(
'visible' => array(
':input[name*="limit_registrations"]' => array(
'value' => 'slots',
),
),
),
'#required' => TRUE,
);
$form['allow_user_slots_entry'] = array(
'#type' => 'checkbox',
'#title' => t('Allow the user to select the number of slots'),
'#description' => t('If checked, the user will be able to choose how many slots their registration will fill, up to the maximum amount configured.'),
'#default_value' => isset($settings['allow_user_slots_entry']) ? $settings['allow_user_slots_entry'] : 0,
'#states' => array(
'visible' => array(
':input[name*="limit_registrations"]' => array(
'value' => 'slots',
),
),
),
);
$form['user_slots_maximum'] = array(
'#type' => 'textfield',
'#title' => t('Maximum number of slots per registration'),
'#description' => t('The maximum number of slots a user can select for their registration to fill. Enter 0 for no maximum.'),
'#default_value' => isset($settings['user_slots_maximum']) ? $settings['user_slots_maximum'] : 1,
'#states' => array(
'visible' => array(
':input[name*="allow_user_slots_entry"]' => array(
'checked' => TRUE,
),
),
),
);
}
/**
* Implements hook_commerce_checkout_complete().
*/
function commerce_registration_commerce_checkout_complete($order) {
$order_wrapper = entity_metadata_wrapper('commerce_order', $order);
foreach ($order_wrapper->commerce_line_items as $delta => $line_item_wrapper) {
if (!in_array($line_item_wrapper->type
->value(), commerce_product_line_item_types())) {
continue;
}
$id = (int) $line_item_wrapper->commerce_product->product_id
->value();
if (commerce_registration_product_has_registration_field($id)) {
commerce_registration_update_line_item_registrations($line_item_wrapper);
}
}
}
/**
* Delete any 'unused' registrations on all line items on the order. An
* 'unused' registration is any registration data that doesn't belong to a
* specific product quantity, ie: if there are 5 registrations, but the line
* item only has a quantity of 4. This would be a remnant of changing the
* quantity after already filling out registration information. This will
* free up any registration space for the associated event.
*/
function commerce_registration_update_line_item_registrations($line_item_wrapper) {
if (!in_array($line_item_wrapper->type
->value(), commerce_product_line_item_types())) {
return;
}
$product_id = $line_item_wrapper->commerce_product->product_id
->value();
if (commerce_registration_product_has_registration_field($product_id)) {
$quantity = $line_item_wrapper->quantity
->value();
$registrations = $line_item_wrapper->registrations
->value();
if (count($registrations) > $quantity) {
// Only need to do this if there are more registration quantities than
// the line item quantity.
$registration_new = array_slice($registrations, 0, $quantity);
$registration_trim = array_slice($registrations, $quantity);
foreach ($registration_trim as $registration) {
registration_delete_multiple(array(
$registration->registration_id,
));
}
$line_item_wrapper->registrations = $registration_new;
$line_item_wrapper
->save();
}
}
}