You are here

node_registration.module in Node registration 7

File

node_registration.module
View source
<?php

/**
 * @file
 * Main module file. Contains most hooks.
 *
 * Other important hooks reside in node_registration.entity.inc.
 */
require_once __DIR__ . '/includes/node_registration.entity.inc';
require_once __DIR__ . '/includes/node_registration.api.inc';
require_once __DIR__ . '/includes/node_registration.forms.inc';
require_once __DIR__ . '/includes/node_registration.defaults.inc';
require_once __DIR__ . '/includes/node_registration.actions.inc';

/**
 * Implements hook_field_extra_fields().
 */
function node_registration_field_extra_fields() {
  $fields = array();
  foreach (_node_registration_bundles() as $type => $name) {

    // Registration: e-mail.
    _node_registration_extra_field($fields, $type, 'email', t('E-mail address'), t('Your e-mail address.'));

    // Registration: account.
    _node_registration_extra_field($fields, $type, 'account', t('Account'), t('Some users get to see a user autocomplete.'));

    // Registration: slots.
    _node_registration_extra_field($fields, $type, 'slots', t('Slots'), t('The number of slots dropdown.'));

    // Registration: attended.
    _node_registration_extra_field($fields, $type, 'attended', t('Attended'), t('Whether the registree attended.'));

    // Registration: author.
    $fields['node_registration'][$type]['display']['author'] = array(
      'label' => t('Author'),
      'description' => t('The author of this registration.'),
      'weight' => 0,
    );

    // Registration: event_node.
    $fields['node_registration'][$type]['display']['event_node'] = array(
      'label' => t('Link to event node'),
      'description' => t('Name of and link to the event node.'),
      'weight' => 0,
    );

    // Registration: event_node_content.
    $fields['node_registration'][$type]['display']['event_node_content'] = array(
      'label' => t('Rendered event node'),
      'description' => t('Rendered event node.'),
      'weight' => 0,
    );

    // Registration: cancel_link.
    $fields['node_registration'][$type]['display']['cancel_link'] = array(
      'label' => t('Cancel link'),
      'description' => t('Link to cancel page/form IF you have access.'),
      'weight' => 0,
    );

    // Node: registration link.
    $fields['node'][$type]['display']['registration_link'] = array(
      'label' => t('Registration link'),
      'description' => t('A link to the registration page.'),
      'weight' => 1,
    );

    // Node: registration form.
    $fields['node'][$type]['display']['registration_form'] = array(
      'label' => t('Registration form'),
      'description' => t('The full registration form.'),
      'weight' => 1,
    );

    // Node: slots left.
    $fields['node'][$type]['display']['registration_slots_left'] = array(
      'label' => t('Open slots'),
      'description' => t('The number of registrable slots left.'),
      'weight' => 1,
    );

    // Node: reason for unregistrable.
    $fields['node'][$type]['display']['registration_unregistrable_reason'] = array(
      'label' => t('Reason for unregistrable (requires devel or ?debug)'),
      'description' => t("The reason you don't see a register form/tab. For debugging!"),
      'weight' => 1,
    );
  }
  return $fields;
}

/**
 * Helper to add extra fields.
 */
function _node_registration_extra_field(&$fields, $type, $machine_name, $label, $description) {
  $fields['node_registration'][$type]['form'][$machine_name] = array(
    'label' => $label,
    'description' => $description,
    'weight' => 0,
  );
  $fields['node_registration'][$type]['display'][$machine_name] = array(
    'label' => $label,
    'description' => $description,
    'weight' => 0,
  );
}

/**
 * Implements hook_entity_view().
 */
function node_registration_entity_view($entity, $entity_type, $view_mode, $langcode) {
  if ('node' == $entity_type && _node_registration_node_type_enabled($entity->type) && !empty($entity->nid)) {
    global $user;

    // Find which fields to show. Unfortunately this is necessary for new extra fields, which are
    // VISIBLE by default. Crazy Drupal...
    $bundle_settings = field_bundle_settings('node', $entity->type);
    $use_view_mode = !empty($bundle_settings['view_modes'][$view_mode]['custom_settings']) ? $view_mode : 'default';
    $show_field = function ($name) use ($bundle_settings, $use_view_mode) {
      return !empty($bundle_settings['extra_fields']['display'][$name][$use_view_mode]['visible']);
    };

    // Add link to registration page.
    $path = 'node/' . $entity->nid . '/register';
    $item = menu_get_item($path);
    $entity->content['registration_link'] = array(
      '#type' => 'container',
      '#attributes' => array(
        'class' => array(
          'registration-link',
        ),
      ),
      '#access' => $item && !empty($item['access']),
      'link' => array(
        '#type' => 'link',
        '#title' => t('Register for this event'),
        '#href' => $path,
      ),
    );

    // Add slots left.
    $capacity = $entity->registration
      ->capacity();
    $open = $capacity - node_registration_event_count($entity);
    $entity->content['registration_slots_left'] = array(
      '#type' => 'container',
      '#attributes' => array(
        'class' => array(
          'registration-slots-left',
        ),
      ),
      'content' => array(
        '#markup' => $capacity ? t('@num slots left.', array(
          '@num' => $open,
        )) : t('Unlimited slots left.'),
      ),
    );

    // Add reason for unregistrable.
    $access = node_registration_node_access($entity, 'register', $user, $reason);
    $entity->content['registration_unregistrable_reason'] = array(
      '#type' => 'container',
      '#attributes' => array(
        'class' => array(
          'registration-unregistrable-reason',
        ),
      ),
      'content' => array(
        '#markup' => t('Reason for unregistrable: @reason', array(
          '@reason' => $reason ?: '?',
        )),
      ),
      '#access' => !$access && (user_access('access devel information') || isset($_GET['debug'])),
    );

    // Add link to log in to register.
    $entity->content['log_in_to_register'] = array(
      '#type' => 'container',
      '#attributes' => array(
        'class' => array(
          'log-in-to-register',
        ),
      ),
      'content' => array(
        '#markup' => 'Bla bla bla',
      ),
      '#access' => $show_field('log_in_to_register'),
    );

    // Add registration form.
    if ($show_field('registration_form')) {

      // Create empty registration (for form).
      $registration = entity_get_controller('node_registration')
        ->create(array(
        'nid' => $entity->nid,
        'node' => $entity,
      ));

      // Check form submission access.
      $access = node_registration_access($registration, 'add');
      if ($access) {

        // Get & add form
        $form = drupal_get_form('node_registration_form', $registration);
        $entity->content['registration_form'] = array(
          '#type' => 'container',
          '#attributes' => array(
            'class' => array(
              'registration-form',
            ),
          ),
          'form' => $form,
        );
      }
    }
  }
}

/**
 * Implements hook_init().
 */
function node_registration_init() {
  $module_path = _node_registration_type_to_uri('node_registration');
  if ('admin' == arg(0) || preg_match('#^node/\\d+/' . $module_path . '#', $_GET['q'])) {
    drupal_add_css(drupal_get_path('module', 'node_registration') . '/node_registration.admin.css');
    drupal_add_js(drupal_get_path('module', 'node_registration') . '/node_registration.admin.js');
  }
}

/**
 * Implements hook_views_api().
 */
function node_registration_views_api() {
  return array(
    'api' => 3,
    'path' => drupal_get_path('module', 'node_registration') . '/includes',
  );
}

/**
 * Implements hook_node_load().
 */
function node_registration_node_load($nodes, $types) {
  module_load_include('inc', 'node_registration', 'includes/node_registration.node_settings');
  foreach ($nodes as $node) {
    if (empty($node->registration)) {
      $node->registration = new NodeRegistrationNodeSettings($node);
    }
  }
}

/**
 * Implements hook_field_attach_submit().
 */
function node_registration_field_attach_submit($entity_type, $entity, $form, $form_state) {
  if ($entity_type == 'node') {
    if (empty($entity->registration)) {
      module_load_include('inc', 'node_registration', 'includes/node_registration.node_settings');
      $entity->registration = new NodeRegistrationNodeSettings($entity);
    }
  }
}

/**
 * Implements hook_menu().
 */
function node_registration_menu() {
  $module_path = _node_registration_type_to_uri('node_registration');

  // Admin pages.
  $items['admin/structure/' . $module_path] = array(
    'title' => 'Node registration',
    'description' => 'Manage Registration structure',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'node_registration_types_form',
    ),
    'access arguments' => array(
      'administer node registration',
    ),
    'file' => 'includes/node_registration.forms.inc',
  );
  $items['admin/structure/' . $module_path . '/manage/%node_registration_type'] = array(
    'title' => 'Type settings',
    'title callback' => 'node_registration_type_settings_page_title',
    'title arguments' => array(
      4,
    ),
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'node_registration_type_settings',
      4,
    ),
    'access arguments' => array(
      'administer node registration',
    ),
    'file' => 'includes/node_registration.forms.inc',
    'type' => MENU_NORMAL_ITEM,
  );
  $items['admin/structure/' . $module_path . '/manage/%node_registration_type/settings'] = array(
    'title callback' => 'node_registration_type_settings_page_title',
    'title arguments' => array(
      4,
    ),
    'type' => MENU_DEFAULT_LOCAL_TASK,
  );

  // Registration entity pages.
  $items['registration/%node_registration'] = array(
    'title callback' => 'node_registration_page_title',
    'title arguments' => array(
      1,
    ),
    'page callback' => 'node_registration_view',
    'page arguments' => array(
      1,
    ),
    'access callback' => 'node_registration_access',
    'access arguments' => array(
      1,
      'view',
    ),
  );
  $items['registration/%node_registration/view'] = array(
    'title' => 'View',
    'type' => MENU_DEFAULT_LOCAL_TASK,
  );
  $items['registration/%node_registration/edit'] = array(
    'title' => 'Edit',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'node_registration_form',
      1,
    ),
    'access callback' => 'node_registration_access',
    'access arguments' => array(
      1,
      'edit',
    ),
    'file' => 'includes/node_registration.forms.inc',
    'weight' => 10,
    'type' => MENU_LOCAL_TASK,
  );
  $items['registration/%node_registration/cancel'] = array(
    'title' => 'Cancel',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'node_registration_cancel_confirm',
      1,
    ),
    'access callback' => 'node_registration_access',
    'access arguments' => array(
      1,
      'cancel',
    ),
    'file' => 'includes/node_registration.forms.inc',
    'weight' => 11,
    'type' => MENU_LOCAL_TASK,
  );
  $items['registration/%node_registration/delete'] = array(
    'title' => 'Delete',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'node_registration_delete_confirm',
      1,
    ),
    'access callback' => 'node_registration_access',
    'access arguments' => array(
      1,
      'delete',
    ),
    'file' => 'includes/node_registration.forms.inc',
    'weight' => 12,
    'type' => MENU_LOCAL_TASK,
  );

  // Registration edit/toggle/ajax.
  $items['registration/%node_registration/toggle/nojs/%/%'] = array(
    'title' => 'Toggle NR flag',
    'page callback' => 'node_registration_toggle_flag',
    'page arguments' => array(
      1,
      3,
      4,
      5,
    ),
    'access callback' => 'node_registration_access_toggle_with_token',
    'access arguments' => array(
      1,
      4,
      5,
    ),
    'file' => 'includes/node_registration.forms.inc',
    'type' => MENU_CALLBACK,
  );
  $items['registration/%node_registration/toggle/ajax/%/%'] = $items['registration/%node_registration/toggle/nojs/%/%'];

  // Registration devel.
  if (module_exists('devel')) {
    $devel_path = drupal_get_path('module', 'devel');
    $items['registration/%node_registration/devel'] = array(
      'title' => 'Devel',
      'page callback' => 'devel_load_object',
      'page arguments' => array(
        'node_registration',
        1,
      ),
      'access arguments' => array(
        'access devel information',
      ),
      'type' => MENU_LOCAL_TASK,
      'file' => 'devel.pages.inc',
      'file path' => $devel_path,
      'weight' => 100,
    );
    $items['registration/%node_registration/devel/load'] = array(
      'title' => 'Load',
      'type' => MENU_DEFAULT_LOCAL_TASK,
    );
    $items['registration/%node_registration/devel/render'] = array(
      'title' => 'Render',
      'page callback' => 'devel_render_object',
      'page arguments' => array(
        'node_registration',
        1,
      ),
      'access arguments' => array(
        'access devel information',
      ),
      'file' => 'devel.pages.inc',
      'file path' => $devel_path,
      'type' => MENU_LOCAL_TASK,
      'weight' => 100,
    );
  }

  // Node local tasks.
  $items['node/%node/register'] = array(
    'title' => 'Register',
    'page callback' => 'node_registration_register_page',
    'page arguments' => array(
      1,
    ),
    'access callback' => 'node_registration_register_page_access',
    'access arguments' => array(
      1,
    ),
    'file' => 'includes/node_registration.forms.inc',
    'type' => MENU_LOCAL_TASK,
    'weight' => 9,
  );
  $items['node/%node/register/%user'] = array(
    'title' => 'Register',
    'page callback' => 'node_registration_register_page',
    'page arguments' => array(
      1,
      3,
    ),
    'access callback' => 'node_registration_register_other_access',
    'access arguments' => array(
      1,
      3,
    ),
    'file' => 'includes/node_registration.forms.inc',
    'weight' => 10,
  );
  $items['node/%node/' . $module_path . '/list'] = array(
    'title' => 'Registrations',
    'type' => MENU_DEFAULT_LOCAL_TASK,
    'tab_parent' => 'node/%/node_registration',
  );
  $items['node/%node/' . $module_path . '/settings'] = array(
    'title' => 'Settings',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'node_registration_registrations_settings_form',
      1,
    ),
    'access callback' => 'node_registration_node_access',
    'access arguments' => array(
      1,
      'registration settings',
    ),
    'file' => 'includes/node_registration.forms.inc',
    'weight' => 9,
    'type' => MENU_LOCAL_TASK,
  );
  $items['node/%node/' . $module_path . '/broadcast'] = array(
    'title' => 'E-mail registrees',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'node_registration_registrations_broadcast_form',
      1,
    ),
    'access callback' => 'node_registration_node_access',
    'access arguments' => array(
      1,
      'registration settings',
    ),
    'file' => 'includes/node_registration.forms.inc',
    'weight' => 10,
    'type' => MENU_LOCAL_TASK,
  );
  return $items;
}

/**
 * Implements hook_menu_alter().
 */
function node_registration_menu_alter(&$items) {
  $item_fields =& $items['admin/structure/node_registration/manage/%node_registration_type/fields'];
  $item_display =& $items['admin/structure/node_registration/manage/%node_registration_type/display'];
  $item_fields['tab_parent'] = $item_display['tab_parent'] = 'admin/structure/node_registration/manage/%';
  $item_view =& $items['node/%/node_registration'];
  $item_view['access callback'] = 'node_registration_node_access';
  $item_view['access arguments'] = array(
    1,
    'registration settings',
  );
}

/**
 * Access callback for registration/%node_registration/toggle/ajax/%/%.
 */
function node_registration_access_toggle_with_token($registration, $field, $new_value) {

  // Node and NR edit access.
  $node = node_load($registration->nid);
  if (!node_access('update', $node) || !node_registration_access($registration, 'update')) {
    return FALSE;
  }

  // Valid togglable flag.
  if (!in_array($field, array(
    'cancelled',
    'verified',
    'attended',
  ))) {
    return FALSE;
  }

  // Valid csrf token.
  return isset($_GET['token']) && drupal_valid_token($_GET['token'], "nr_toggle_{$field}_{$new_value}");
}

/**
 * Access callback for node/%node/register.
 */
function node_registration_register_page_access($node) {

  // Has register access.
  if (node_registration_node_access($node, 'register')) {

    // Register page enabled or admin.
    $settings = _node_registration_node_type_settings($node->type);
    return user_access('administer node registration') || empty($settings->no_register_page);
  }
}

/**
 * Implements hook_module_implements_alter().
 */
function node_registration_module_implements_alter(&$implementations, $hook) {
  if ($hook == 'menu_alter') {
    $module = 'node_registration';
    if (isset($implementations[$module])) {
      $group = $implementations[$module];
      unset($implementations[$module]);
      $implementations[$module] = $group;
    }
  }
}

/**
 * Access callback to check if current user can register other user.
 */
function node_registration_register_other_access($node, $account) {

  // Account must not already be registered.
  if (_node_registration_user_registered($node, $account)) {
    return FALSE;
  }

  // Acting user must have permissions.
  return node_registration_node_access($node, 'register others');
}

/**
 * Implements hook_preprocess_page().
 *
 * @TODO Find a better way for this? Whatever this is...
 */
function node_registration_preprocess_page(&$vars) {
  if (!($node = menu_get_object()) || !_node_registration_node_type_enabled($node->type)) {
    if (isset($vars['tabs']['#primary']) && is_array($vars['tabs']['#primary'])) {
      foreach ($vars['tabs']['#primary'] as $i => $tab) {
        if ($tab['#link']['path'] == 'node/%/node_registration') {
          if (!isset($tab['#link']['access_callback']) || $tab['#link']['access_callback'] != 'node_registration_node_access') {
            unset($vars['tabs']['#primary'][$i]);
          }
        }
      }
    }
  }
}

/**
 * Implements hook_permission().
 */
function node_registration_permission() {
  $permissions = array(
    'administer node registration' => array(
      'title' => t('Administer registration'),
      'description' => t('Perform administration tasks for Node registrations.'),
      'restrict access' => TRUE,
    ),
    'other node registration' => array(
      'title' => t('Register for others'),
      'description' => t('Create Node registrations with other user as subject.'),
    ),
  );
  foreach (_node_registration_node_types() as $type => $name) {
    $params = array(
      '%type' => $name,
    );
    $permissions += array(
      'add ' . $type . ' node registration' => array(
        'title' => t('%type: add registration', $params),
      ),
      'view ' . $type . ' node registration' => array(
        'title' => t('%type: view registration', $params),
      ),
      'view own ' . $type . ' node registration' => array(
        'title' => t('%type: view own registration', $params),
      ),
      'edit own ' . $type . ' node registration' => array(
        'title' => t('%type: edit own registration', $params),
      ),
      'cancel own ' . $type . ' node registration' => array(
        'title' => t('%type: cancel own registration', $params),
      ),
      'delete own ' . $type . ' node registration' => array(
        'title' => t('%type: delete own registration', $params),
      ),
    );
  }
  return $permissions;
}

/**
 * Implements hook_admin_paths().
 */
function node_registration_admin_paths() {
  $paths = array(
    'node/*/node_registration' => TRUE,
    'node/*/node_registration/*' => TRUE,
  );
  if (module_exists('devel')) {
    $paths['registration/*/devel'] = TRUE;
    $paths['registration/*/devel/*'] = TRUE;
  }
  return $paths;
}

/**
 * Implements hook_block_info().
 */
function node_registration_block_info() {
  $blocks = array();
  $blocks['node_registration_link'] = array(
    'info' => "Node registration: link to this page's form",
    'cache' => DRUPAL_NO_CACHE,
  );
  $blocks['node_registration_form'] = array(
    'info' => "Node registration: this page's form",
    'cache' => DRUPAL_NO_CACHE,
  );
  $blocks['node_registration_cancel'] = array(
    'info' => "Node registration: the cancel registration form for this page",
    'cache' => DRUPAL_NO_CACHE,
  );
  return $blocks;
}

/**
 * Implements hook_block_view().
 */
function node_registration_block_view($delta = '') {
  global $user;
  switch ($delta) {
    case 'node_registration_cancel':
      if ($node = menu_get_object('node')) {
        $settings = $node->registration;

        // Extensive access check for this node & user.
        $access = node_registration_node_access($node, 'register', $user, $reason);

        // The default block title.
        $title = t('Unregister for %title', array(
          '%title' => $node->title,
        ));

        // Alter title depending on scenario.
        drupal_alter('registration_block_unsubscribe_title', $title, $reason);
        if (!$access && $reason == 'registered') {
          $registration = _node_registration_user_registered($node, $user);

          // Create form.
          module_load_include('inc', 'node_registration', 'includes/node_registration.forms');
          $form = drupal_get_form('node_registration_cancel', $registration);

          // Show form via template.
          $content = theme('node_registration_cancel_block', array(
            'form' => $form,
            'node' => $node,
            'registration' => $registration,
          ));
          return array(
            'subject' => $title,
            'content' => $content,
          );
        }
      }
      break;
    case 'node_registration_form':
    case 'node_registration_link':
      if ($node = menu_get_object('node')) {
        $settings = $node->registration;

        // Extensive access check for this node & user.
        $access = node_registration_node_access($node, 'register', $user, $reason);

        // The default block title.
        $title = t('Register for %title', array(
          '%title' => $node->title,
        ));

        // Alter title depending on scenario.
        drupal_alter('registration_block_title', $title, $reason);
        if ($access) {

          // All access!
          switch ($delta) {
            case 'node_registration_link':

              // Show link via template.
              $content = theme('node_registration_link', array(
                'node' => $node,
              ));
              break;
            case 'node_registration_form':

              // Create empty registration for empty form.
              $registration = entity_get_controller('node_registration')
                ->create(array(
                'nid' => $node->nid,
                'node' => $node,
              ));

              // Create form
              module_load_include('inc', 'node_registration', 'includes/node_registration.forms');
              $form = drupal_get_form('node_registration_form', $registration);

              // Show form via template.
              $content = theme('node_registration_form_block', array(
                'form' => $form,
                'node' => $node,
                'registration' => $registration,
              ));
              break;
          }
          return array(
            'subject' => $title,
            'content' => $content,
          );
        }
        else {

          // No access.
          $message_key = 'show_message_' . $reason;
          $show_message = $settings->{$message_key};
          if ($show_message) {

            // Possibly a Registration exists.
            $registration = NULL;
            if ('registered' == $reason) {
              $registration = _node_registration_user_registered($node, $user);
            }
            $theme_key = 'node_registration_block_message_' . $reason;
            $content = theme($theme_key, array(
              'user' => $user,
              'node' => $node,
              'registration' => $registration,
            ));
            return array(
              'subject' => $title,
              'content' => $content,
            );
          }
        }
      }
      break;
  }
}

/**
 * Alias for node_registration_view().
 */
function node_registration_page_view($registration, $view_mode = 'full') {
  return node_registration_view($registration, $view_mode);
}

/**
 * Page callback for viewing a single Node registration.
 */
function node_registration_view($registration, $view_mode = 'full') {
  return entity_build_content('node_registration', $registration, $view_mode);
}

/**
 * Page title callback for a single Node registration.
 */
function node_registration_page_title($registration) {

  // Use the node title in the registration page title.
  $node = $registration->node ?: node_load($registration->nid);
  if ($node && !empty($node->title)) {

    // Complete $title will be check_plain()ed by set_title or some shit later. No way
    // to change that from here?
    $title = t('Registration !num for !title', array(
      '!title' => $node->title,
      '!num' => $registration->registration_id,
    ));
    return $title;
  }
}

/**
 * Title callback for Node registration type settings page.
 */
function node_registration_type_settings_page_title($registration_type) {
  return $registration_type->name;
}

/**
 * Implements hook_form_FORM_ID_alter() for node_type_form().
 *
 * Add registration options to node type form.
 */
function node_registration_form_node_type_form_alter(&$form, &$form_state, $form_id = 'node_type_form') {
  $type = $form['#node_type']->type;
  if (!$type) {
    return;
  }
  $form['#attached']['js'][] = drupal_get_path('module', 'node_registration') . '/node_registration.admin.js';
  $form['#attributes']['class'][] = 'node-type-form';
  $fields = db_query("SELECT c.field_name, ci.data FROM {field_config} c, {field_config_instance} ci WHERE ci.field_id = c.id AND c.type IN ('date', 'datetime', 'datestamp') AND ci.entity_type = ? AND bundle = ? AND c.deleted = 0 AND ci.deleted = 0", array(
    'node',
    $type,
  ));
  $date_fields = array();
  foreach ($fields as $field) {

    // Add from field.
    $data = unserialize($field->data);
    $date_fields[$field->field_name] = $data['label'];

    // Maybe there's a to field too.
    $field_info = field_info_field($field->field_name);
    $todate = !empty($field_info['settings']['todate']);
    $value2 = isset($field_info['columns']['value2']);
    if ($todate && $value2) {
      $date_fields[$field->field_name . ':value2'] = $data['label'] . t(' (end date)');
    }
  }
  $fields = db_query("SELECT c.field_name, ci.data FROM {field_config} c, {field_config_instance} ci WHERE ci.field_id = c.id AND c.type IN ('number_integer') AND ci.entity_type = ? AND bundle = ? AND c.deleted = 0 AND ci.deleted = 0", array(
    'node',
    $type,
  ));
  $number_fields = array();
  foreach ($fields as $field) {
    $data = unserialize($field->data);
    $number_fields[$field->field_name] = $data['label'];
  }
  $enabled = _node_registration_node_type_settings($type);
  $form['registration'] = array(
    '#type' => 'fieldset',
    '#title' => t('Registration settings'),
    '#group' => 'additional_settings',
    '#collapsible' => TRUE,
    '#collapsed' => FALSE,
  );
  $form['registration']['registration_node_status'] = array(
    '#type' => 'select',
    '#title' => t('Enable registrations for this content type'),
    '#options' => array(
      '0' => t('Disabled'),
      '1' => t('Enabled, on by default'),
      '2' => t('Enabled, off by default'),
    ),
    '#required' => TRUE,
    '#default_value' => $enabled ? (int) $enabled->status : 0,
    '#description' => t('If enabled, users will be allowed to register for this content type unless an administrator disables registrations on specific posts.'),
    '#attributes' => array(
      'class' => array(
        'node-registration-status',
      ),
    ),
  );
  $form['registration']['registration_node_date_field'] = array(
    '#type' => 'select',
    '#title' => t('Field for event start date (and time)'),
    '#options' => array(
      '0' => '-- ' . t('None'),
    ) + $date_fields,
    '#default_value' => $enabled ? $enabled->date_field : 0,
    '#description' => t('Which field will be used to indicate start date (and time)? If empty, no automatic e-mails will be sent.'),
  );
  $form['registration']['registration_node_min_registration_date_field'] = array(
    '#type' => 'select',
    '#title' => t('Field for registration start date (and time)'),
    '#options' => array(
      '0' => '-- ' . t('None'),
    ) + $date_fields,
    '#default_value' => $enabled ? $enabled->min_registration_date_field : 0,
    '#description' => t('Which <strong>node field</strong> will be used as registration start date.'),
  );
  $form['registration']['registration_node_max_registration_date_field'] = array(
    '#type' => 'select',
    '#title' => t('Field for registration end date (and time)'),
    '#options' => array(
      '0' => '-- ' . t('None'),
    ) + $date_fields,
    '#default_value' => $enabled ? $enabled->max_registration_date_field : 0,
    '#description' => t('Which <strong>node field</strong> will be used as registration end date, instead of the variable .'),
  );
  $form['registration']['registration_node_capacity_field'] = array(
    '#type' => 'select',
    '#title' => t('Field for capacity'),
    '#options' => array(
      '0' => '-- ' . t('None'),
    ) + $number_fields,
    '#default_value' => $enabled ? $enabled->capacity_field : 0,
    '#description' => t('Which node field will be used as Capacity source, <strong>instead of the node settings field Capacity</strong>.'),
  );
  array_unshift($form['#submit'], 'node_registration_node_type_form_submit');
}

/**
 * Submit handler for node_registration_form_node_type_form_alter().
 */
function node_registration_node_type_form_submit($form, &$form_state) {
  $values =& $form_state['values'];
  $nt = $form['#node_type'];
  $type = $nt->type;

  // Fetch old settings.
  $old_node_status = _node_registration_node_type_enabled($type);

  // Extract new settings.
  $node_status = (int) $values['registration_node_status'];
  $date_field = $values['registration_node_date_field'];
  $max_registration_date_field = $values['registration_node_max_registration_date_field'];
  $min_registration_date_field = $values['registration_node_min_registration_date_field'];
  $capacity_field = $values['registration_node_capacity_field'];

  // Unset 'settings' from form_state so they're not automatically saved as variables.
  unset($values['registration_node_status'], $values['registration_node_date_field'], $values['registration_node_max_registration_date_field'], $values['registration_node_min_registration_date_field'], $values['registration_node_capacity_field']);

  // Check if the settings have actually changed.
  $settings_changed = $node_status != $old_node_status;

  // Save settings.
  if ($node_status) {
    _node_registration_node_type_enable($type, $node_status, array(
      'date_field' => $date_field,
      'max_registration_date_field' => $max_registration_date_field,
      'min_registration_date_field' => $min_registration_date_field,
      'capacity_field' => $capacity_field,
    ));
  }
  else {
    node_registration_node_type_delete($nt);
  }

  // Reset entities & menu routes.
  if ($settings_changed) {
    entity_info_cache_clear();
    menu_rebuild();
  }
}

/**
 * Implements hook_node_type_update().
 */
function node_registration_node_type_update($info) {
  if (!empty($info->old_type) && $info->old_type != $info->type) {
    $old_type = $info->old_type;
    $new_type = $info->type;

    // Update registration variables.
    $old_var_name = 'node_registration_type_settings_' . $old_type;
    $new_var_name = 'node_registration_type_settings_' . $new_type;
    db_update('variable')
      ->fields(array(
      'name' => $new_var_name,
    ))
      ->condition('name', $old_var_name)
      ->execute();

    // Update node_registration.type.
    db_update('node_registration')
      ->fields(array(
      'type' => $new_type,
    ))
      ->condition('type', $old_type)
      ->execute();

    // Update node_registration.node_type.
    db_update('node_registration')
      ->fields(array(
      'node_type' => $new_type,
    ))
      ->condition('node_type', $old_type)
      ->execute();
    drupal_flush_all_caches();
  }
}

/**
 * Implements hook_node_type_delete().
 */
function node_registration_node_type_delete($info) {
  variable_del('node_registration_type_settings_' . $info->type);
}

/**
 * Page callback for adding a registration.
 */
function node_registration_register_page($node, $account = NULL) {
  drupal_set_title(t('Register for @title', array(
    '@title' => $node->title,
  )), PASS_THROUGH);

  // Create empty registration.
  $registration = entity_get_controller('node_registration')
    ->create(array(
    'nid' => $node->nid,
    'node' => $node,
  ));
  return drupal_get_form('node_registration_form', $registration, $account);
}

/**
 * Page callback for viewing registrations.
 *
 * DEPRECATED & UNUSED, but left here for backward compatibility.
 */
function node_registration_registrations_page($node) {
  $module_path = _node_registration_type_to_uri('node_registration');
  $registrations = node_registration_load_multiple(FALSE, array(
    'nid' => $node->nid,
    'cancelled' => 0,
  ));
  if ($registrations) {
    $rows = array();
    foreach ($registrations as $registration) {
      $user = '';
      if ($registration->uid) {
        $user = user_load($registration->uid);
        $users[] = $user;
        $user = l($user->name, 'user/' . $user->uid);
      }
      else {
        $users[] = NULL;
      }
      $actions = array(
        l(t('view'), 'registration/' . $registration->registration_id),
        l(t('edit'), 'registration/' . $registration->registration_id . '/edit'),
        l(t('cancel'), 'registration/' . $registration->registration_id . '/cancel'),
      );
      $rows[] = array(
        'data' => array(
          l($registration->registration_id, 'registration/' . $registration->registration_id),
          l($registration->email, 'mailto:' . $registration->email),
          $user,
          $registration->slots,
          format_date($registration->created),
          implode(' | ', $actions),
        ),
      );
    }
    $table = array(
      'header' => array(
        t('id'),
        t('Email'),
        t('User'),
        t('Slots'),
        t('Created'),
        t('Actions'),
      ),
      'rows' => $rows,
      'attributes' => array(
        'class' => array(
          'registrations',
        ),
      ),
    );
    $context = array(
      'node' => $node,
      'users' => $users,
      'registrations' => array_values($registrations),
    );
    drupal_alter('node_registration_table_registrations', $table, $context);
    $out = theme('table', $table);
  }
  else {
    $out = t('There are no registrees for %name.', array(
      '%name' => $node->title,
    ));
  }
  return $out;
}

/**
 * Implements hook_node_delete().
 *
 * Delete registrations and settings for this node.
 */
function node_registration_node_delete($node) {
  db_delete('node_registration')
    ->condition('nid', $node->nid)
    ->execute();
  db_delete('node_registration_node')
    ->condition('nid', $node->nid)
    ->execute();
}

/**
 * Implements hook_theme().
 */
function node_registration_theme() {
  return array(
    // Admin: the registration types overview.
    'node_registration_types_form' => array(
      'render element' => 'form',
    ),
    // The registration entity.
    'node_registration' => array(
      'variables' => array(
        'node' => NULL,
        'registration' => NULL,
        'content' => NULL,
      ),
      'template' => 'templates/node-registration',
    ),
    // Block: error messages.
    'node_registration_block_message_access' => array(
      'variables' => array(
        'user' => NULL,
        'node' => NULL,
        'registration' => NULL,
      ),
      'template' => 'templates/node-registration-message-access',
    ),
    'node_registration_block_message_date' => array(
      'variables' => array(
        'user' => NULL,
        'node' => NULL,
        'registration' => NULL,
      ),
      'template' => 'templates/node-registration-message-date',
    ),
    'node_registration_block_message_capacity' => array(
      'variables' => array(
        'user' => NULL,
        'node' => NULL,
        'registration' => NULL,
      ),
      'template' => 'templates/node-registration-message-capacity',
    ),
    'node_registration_block_message_registered' => array(
      'variables' => array(
        'user' => NULL,
        'node' => NULL,
        'registration' => NULL,
      ),
      'template' => 'templates/node-registration-message-registered',
    ),
    // Block: link.
    'node_registration_link' => array(
      'variables' => array(
        'node' => NULL,
        'content' => NULL,
      ),
      'template' => 'templates/node-registration-link',
    ),
    // Block: registration form.
    'node_registration_form_block' => array(
      'variables' => array(
        'form' => NULL,
        'node' => NULL,
        'registration' => NULL,
      ),
      'template' => 'templates/node-registration-form-block',
    ),
    // Block: cancel form.
    'node_registration_cancel_block' => array(
      'variables' => array(
        'form' => NULL,
        'node' => NULL,
        'registration' => NULL,
      ),
      'template' => 'templates/node-registration-cancel-block',
    ),
  );
}

/**
 * Theme function for node_registration_types_form().
 */
function theme_node_registration_types_form($variables) {
  $help_message = '<p>' . t('The following table lists the registration status for each content type. You can enable/disable registrations from the content type settings page.') . '</p>';
  $form = $variables['form'];
  $rows = array();
  foreach (element_children($form['types']) as $type) {
    $element = $form['types'][$type];
    $enabled = $element['#enabled'];
    $operations = array();
    foreach ($element['#operations'] as $op_name => $op) {
      if ($html = render($op)) {
        $operations[] = $html;
      }
    }
    $rows[] = array(
      'class' => array(
        $enabled ? 'enabled' : 'disabled',
      ),
      'data' => array(
        array(
          'data' => l($element['#name'], 'admin/structure/types/manage/' . $type),
        ),
        array(
          'class' => 'registration-status',
          'data' => $enabled ? t('Enabled') : t('Disabled'),
        ),
        implode(' | ', $operations),
      ),
    );
  }
  $table = array(
    'header' => array(
      t('Content type'),
      t('Registration status'),
      t('Operations'),
    ),
    'rows' => $rows,
    'attributes' => array(
      'class' => array(
        'node-registration',
      ),
    ),
  );
  $table = theme('table', $table);
  return $help_message . "\n" . $table . "\n" . drupal_render_children($form);
}

/**
 * Default preprocess for theme node_registration_form_block.
 */
function template_preprocess_node_registration_form_block(&$variables) {
  $variables['content']['form'] = $variables['form'];
}

/**
 * Default preprocess for theme node_registration_cancel_block.
 */
function template_preprocess_node_registration_cancel_block(&$variables) {
  $variables['content']['form'] = $variables['form'];
}

/**
 * Default preprocess for theme node_registration_link.
 */
function template_preprocess_node_registration_link(&$variables) {
  $node = $variables['node'];
  $variables['content']['link'] = array(
    '#type' => 'link',
    '#title' => t('To registration form'),
    '#href' => 'node/' . $node->nid . '/register',
    '#attributes' => array(
      'class' => array(
        'block-node-register-link',
      ),
    ),
    '#prefix' => '<p class="block-node-register-link-outer">',
    '#suffix' => '</p>',
  );
}

/**
 * Default preprocess for theme node_registration.
 */
function template_preprocess_node_registration(&$variables) {
  $registration = $variables['registration'];
  $node = $variables['node'];
  $variables['classes_array'][] = 'node-registration-' . drupal_html_class($node->type);
  if ($registration->cancelled) {
    $variables['classes_array'][] = 'cancelled';
  }
}

/**
 * Implements hook_mail().
 */
function node_registration_mail($key, &$message, $params) {
  $subject = $params['subject'];
  $body = $params['message'];
  $message['subject'] .= str_replace(array(
    "\r",
    "\n",
  ), '', $subject);
  $message['body'][] = $body;
  if (!empty($params['bcc'])) {
    $message['headers']['Bcc'] = $params['bcc'];
  }
}

/**
 * Implements hook_cron().
 */
function node_registration_cron() {

  // Find event nodes.
  $nodes = _node_registration_event_nodes();

  // Find registrations with no reminder sent.
  $registrations = node_registration_load_multiple(FALSE, array(
    'reminder_sent' => 0,
    'cancelled' => 0,
  ));
  $reminders_sent = array();
  foreach ($registrations as $registration) {
    if (isset($nodes[$registration->nid])) {
      $node = $nodes[$registration->nid];
      $settings = $node->registration;
      $send = $settings->send_reminder_mail_to_registrees;
      $subject = $settings->reminder_mail_to_registrees_subject;
      $message = $settings->reminder_mail_to_registrees_body;
      if ($send && $subject && $message) {
        if ($settings
          ->reminder_time_passed()) {

          // Send e-mail.
          $registration->node = $node;
          node_registration_send_broadcast($node, $subject, $message, array(
            $registration,
          ));

          // Save it, so the registree doesn't get another e-mail next cron run.
          $updated = db_update('node_registration')
            ->fields(array(
            'reminder_sent' => REQUEST_TIME,
          ))
            ->condition('registration_id', $registration->registration_id)
            ->execute();
          $reminders_sent[] = l($node->title, 'node/' . $node->nid);
        }
      }
    }
  }
  if ($reminders_sent) {
    watchdog('node_registration', 'Reminders sent: !links', array(
      '!links' => implode(', ', $reminders_sent),
    ));
  }
}

/**
 * Implements hook_url_outbound_alter().
 */
function node_registration_url_outbound_alter(&$path, &$options, $original_path) {
  if (isset($_GET['secret'])) {
    $module_path = _node_registration_type_to_uri('node_registration');

    // Only pass this secret on to other Registration pages.
    if (is_int(strpos($path, 'register')) || is_int(strpos($path, $module_path)) || is_int(strpos($path, 'registration'))) {
      $options['query']['secret'] = $_GET['secret'];
    }
  }
}

/**
 * Helper to make static caching prettier.
 *
 * $cache_key is how this cache item is unique in drupal_static.
 * $callback will be executed to get the cacheable if the cache item doesn't exist.
 * $post_process will be called after the $callback is executed.
 *
 * $callback doesn't take any arguments. All info needed should be included with
 * <code>use ($var1, $var2, ...)</code>. It should return the cacheable.
 *
 * $post_process takes the $cacheable and the $cache_key. It should **return** the
 * cacheable by default. If alteration is required, return that. This argument
 * is **not** by-reference.
 */
function _node_registration_cache($cache_key, $callback, $post_process = null) {
  $cache =& drupal_static($cache_key);
  if (!isset($cache)) {
    $cache = $callback();
    if (is_callable($post_process)) {
      $cache = $post_process($cache, $cache_key);
    }
  }
  return $cache;
}

/**
 * Implements hook_node_registration_update().
 */
function node_registration_node_registration_update($registration) {
  $now_cancelled = (bool) $registration->cancelled;
  $was_cancelled = (bool) $registration->original->cancelled;

  // Cancelled status changed.
  if ($now_cancelled != $was_cancelled) {
    $action = $now_cancelled ? 'cancel' : 'uncancel';
    $node = $registration->node ?: node_load($registration->nid);
    $new_waitinglist = _node_registration_reset_waitinglist($node);
  }
  $now_waitinglist = (bool) $registration->waitinglist;
  $was_waitinglist = (bool) $registration->original->waitinglist;

  // Waitinglist status changed.
  if ($now_waitinglist != $was_waitinglist) {
    $action = $now_waitinglist ? 'waitinglist' : 'unwaitinglist';
    $node = $registration->node ?: node_load($registration->nid);
    $settings = $node->registration;

    // Moved from waitinglist to normal.
    if (!$now_waitinglist) {
      $send = $settings->send_unwaitinglist_mail_to_registree;
      $subject = $settings->unwaitinglist_mail_to_registree_subject;
      $message = $settings->unwaitinglist_mail_to_registree_body;

      // Send mail to registree
      if ($send && $subject && $message) {
        $registration->node = $node;
        node_registration_send_broadcast($node, $subject, $message, array(
          $registration,
        ));
      }
    }
  }
}

/**
 * Implements hook_form_FORM_ID_alter() for views_form().
 */
function node_registration_form_views_form_alter(&$form, &$form_state) {

  // VBO settings form.
  if (isset($form_state['operation'])) {
    $op = $form_state['operation'];

    // Send mail action.
    if ($op->operationId == 'action::system_send_email_action' && $op->entityType == 'node_registration') {

      // Pre-fill the NR mail token.
      if (isset($form['recipient']['#type']) && empty($form['recipient']['#default_value'])) {
        $form['recipient']['#default_value'] = '[node-registration:mail]';
      }

      // Pre-fill mail text.
      if (isset($form['message']['#type']) && empty($form['message']['#default_value'])) {
        $form['message']['#default_value'] = "Hello [node-registration:user:name],\n" . "\n" . "Your registration ID is [node-registration:registration-id].";
      }

      // Add NR tokens.
      if (module_exists('token')) {
        $form['token_help'] = array(
          '#theme' => 'token_tree',
          '#dialog' => TRUE,
          '#token_types' => array(
            'node-registration',
          ),
          '#global_types' => variable_get('node_registration_token_tree_globals', FALSE),
        );
      }
    }
  }
}

/**
 * Implements hook_form_FORM_ID_alter() for node_form().
 */
function node_registration_form_node_form_alter(&$form, &$form_state) {
  $node = $form_state['node'];
  $type_enabled = _node_registration_node_type_enabled($node->type);

  // 2 = Enabled, off by default.
  if ($type_enabled) {
    isset($node->registration) or $node->registration = new NodeRegistrationNodeSettings($node);
    if (node_registration_node_access($node, 'registration settings')) {
      $type_settings = _node_registration_node_type_settings($node->type);
      $access = user_access('administer node registration') || $type_settings->toggle_enabled_in_node_form;
      $node_settings = $node->registration;
      $enabled = empty($node->nid) ? $type_enabled == 1 : $node_settings
        ->enabled();
      $form['#attached']['js'][] = drupal_get_path('module', 'node_registration') . '/node_registration.admin.js';
      $form['node_registration'] = array(
        '#weight' => 110,
        '#type' => 'fieldset',
        '#title' => t('Node registration'),
        '#group' => 'additional_settings',
        '#access' => $access,
        'node_registration_status' => array(
          '#type' => 'checkbox',
          '#title' => t('Enable registration'),
          '#default_value' => $enabled,
          '#attributes' => array(
            'class' => array(
              'node-registration-status',
            ),
          ),
        ),
      );
    }
  }
}

/**
 * Implements hook_node_update().
 */
function node_registration_node_update($node) {
  if (isset($node->registration, $node->node_registration_status)) {
    $status = $node->node_registration_status ? 1 : 0;
    $node->registration
      ->update(compact('status'));
  }
}

/**
 * Implements hook_node_insert().
 */
function node_registration_node_insert($node) {
  if (isset($node->registration)) {
    $node->registration->nid = $node->nid;

    // 'nid' is new in this fake settings object.
    $node->registration->node = $node;
    $node->registration
      ->update();
  }
}

Functions

Namesort descending Description
node_registration_access_toggle_with_token Access callback for registration/%node_registration/toggle/ajax/%/%.
node_registration_admin_paths Implements hook_admin_paths().
node_registration_block_info Implements hook_block_info().
node_registration_block_view Implements hook_block_view().
node_registration_cron Implements hook_cron().
node_registration_entity_view Implements hook_entity_view().
node_registration_field_attach_submit Implements hook_field_attach_submit().
node_registration_field_extra_fields Implements hook_field_extra_fields().
node_registration_form_node_form_alter Implements hook_form_FORM_ID_alter() for node_form().
node_registration_form_node_type_form_alter Implements hook_form_FORM_ID_alter() for node_type_form().
node_registration_form_views_form_alter Implements hook_form_FORM_ID_alter() for views_form().
node_registration_init Implements hook_init().
node_registration_mail Implements hook_mail().
node_registration_menu Implements hook_menu().
node_registration_menu_alter Implements hook_menu_alter().
node_registration_module_implements_alter Implements hook_module_implements_alter().
node_registration_node_delete Implements hook_node_delete().
node_registration_node_insert Implements hook_node_insert().
node_registration_node_load Implements hook_node_load().
node_registration_node_registration_update Implements hook_node_registration_update().
node_registration_node_type_delete Implements hook_node_type_delete().
node_registration_node_type_form_submit Submit handler for node_registration_form_node_type_form_alter().
node_registration_node_type_update Implements hook_node_type_update().
node_registration_node_update Implements hook_node_update().
node_registration_page_title Page title callback for a single Node registration.
node_registration_page_view Alias for node_registration_view().
node_registration_permission Implements hook_permission().
node_registration_preprocess_page Implements hook_preprocess_page().
node_registration_register_other_access Access callback to check if current user can register other user.
node_registration_register_page Page callback for adding a registration.
node_registration_register_page_access Access callback for node/%node/register.
node_registration_registrations_page Page callback for viewing registrations.
node_registration_theme Implements hook_theme().
node_registration_type_settings_page_title Title callback for Node registration type settings page.
node_registration_url_outbound_alter Implements hook_url_outbound_alter().
node_registration_view Page callback for viewing a single Node registration.
node_registration_views_api Implements hook_views_api().
template_preprocess_node_registration Default preprocess for theme node_registration.
template_preprocess_node_registration_cancel_block Default preprocess for theme node_registration_cancel_block.
template_preprocess_node_registration_form_block Default preprocess for theme node_registration_form_block.
template_preprocess_node_registration_link Default preprocess for theme node_registration_link.
theme_node_registration_types_form Theme function for node_registration_types_form().
_node_registration_cache Helper to make static caching prettier.
_node_registration_extra_field Helper to add extra fields.