You are here

availability_calendar_booking_formlet.module in Availability Calendars 7.3

Availability Calendar booking formlet module. This submdule of the Availability Calendar module defines a field that shows a small booking form that interacts with a calendar field. The form only has an arraival and departure date field and a submit button that is supposed to post the values to a webform where the visitor can enter its personal details and other requested information.

@author Erwin Derksen (http://drupal.org/user/750928)

@todo:

  • allow to disable booking form on a per node basis and an instance setting to disallow this.
  • allow to overide the url on a per node basis.
  • disable "Number of values" on field instance setting form.
  • check the setting interactive on calendar fields when this fields get added
  • can I reuse something from node reference or linkit module to select URL?
  • what more information to send in hidden fields? field name, delta, language
  • label and help text for departure date in full day mode is incorrect (last day of your stay, not departure date)

File

booking_formlet/availability_calendar_booking_formlet.module
View source
<?php

/**
 * @file
 * Availability Calendar booking formlet module. This submdule of the
 * Availability Calendar module defines a field that shows a small booking form
 * that interacts with a calendar field. The form only has an arraival and
 * departure date field and a submit button that is supposed to post the values
 * to a webform where the visitor can enter its personal details and other
 * requested information.
 *
 * @author Erwin Derksen (http://drupal.org/user/750928)
 *
 * @todo:
 * - allow to disable booking form on a per node basis and an instance setting
 *   to disallow this.
 * - allow to overide the url on a per node basis.
 * - disable "Number of values" on field instance setting form.
 * - check the setting interactive on calendar fields when this fields get added
 * - can I reuse something from node reference or linkit module to select URL?
 * - what more information to send in hidden fields? field name, delta, language
 * - label and help text for departure date in full day mode is incorrect (last
 *   day of your stay, not departure date)
 */

/***************************************************************
 * Field Type API hooks
 ***************************************************************/

/**
 * Implements hook_field_info().
 * @link http://api.drupal.org/api/drupal/modules--field--field.api.php/function/hook_field_info/7
 *
 * Provides the descriptions of the fields offered by this module.
 */
function availability_calendar_booking_formlet_field_info() {
  module_load_include('inc', 'availability_calendar', 'availability_calendar');
  $states = availability_calendar_get_states();
  if (!empty($states[4]) && $states[4]['css_class'] == 'cal-opt') {

    // State "Provisionally booked" exists, make this the defaulkt for the
    // "booked_state".
    $booked_state = 4;
  }
  else {
    $booked_state = NULL;
  }
  return array(
    'availability_calendar_booking_formlet' => array(
      'label' => t('Availability Calendar Booking formlet'),
      'description' => t('Allows to show a booking formlet for entities with an availability calendar.'),
      'settings' => array(
        'define_per_language' => 0,
        'post_url' => array(
          LANGUAGE_NONE => '',
        ),
        'booked_state' => $booked_state,
      ),
      'instance_settings' => array(),
      'default_widget' => 'availability_calendar_booking_formlet',
      'default_formatter' => 'availability_calendar_booking_formlet',
    ),
  );
}

/**
 * Implements hook_field_settings_form().
 * @link http://api.drupal.org/api/drupal/modules--field_ui--field_ui.api.php/function/hook_field_settings_form/7
 */
function availability_calendar_booking_formlet_field_settings_form($field, $instance, $has_data) {
  module_load_include('inc', 'availability_calendar', 'availability_calendar');
  $settings = $field['settings'];
  $form = array();
  $form['url_2_continue'] = array(
    '#type' => 'markup',
    '#markup' => '<fieldset class="form-wrapper"><legend><span class="fieldset-legend">' . t("URL to continue the booking") . '</span></legend><div class="fieldset-wrapper">',
    '#weight' => 10,
  );
  $form['define_per_language'] = array(
    '#type' => 'checkbox',
    '#title' => t('Define the URL to continue the booking per language'),
    '#description' => t("Webforms are not language aware. Check this option if you want to continue the booking with a different URL (webform) per language."),
    '#default_value' => $settings['define_per_language'],
    '#required' => FALSE,
    '#weight' => 11,
  );
  $form['post_url'] = array(
    '#type' => 'item',
    '#description' => t("These URL's typically point to a webform.") . ' ' . t("Do not start internal URL's with a '/'. You can use the system URL, it wil be replaced by its alias. See the help for more instructions about setting up the target page or webform."),
    '#suffix' => '</div></fieldset>',
    '#weight' => 12,
  );
  $form['post_url'][LANGUAGE_NONE] = array(
    '#type' => 'textfield',
    '#title' => t('All languages') . '/' . t('Language neutral'),
    '#default_value' => isset($settings['post_url'][LANGUAGE_NONE]) ? $settings['post_url'][LANGUAGE_NONE] : (is_array($settings['post_url']) ? reset($settings['post_url']) : ''),
    '#required' => FALSE,
    '#states' => array(
      'visible' => array(
        ':input[name="field[settings][define_per_language]"]' => array(
          'checked' => FALSE,
        ),
      ),
    ),
  );
  $language_list = function_exists('locale_language_list') ? locale_language_list() : array_combine(array_keys($settings['post_url']), array_keys($settings['post_url']));
  foreach ($language_list as $language_code => $language_name) {
    $form['post_url'][$language_code] = array(
      array(
        '#type' => 'textfield',
        '#title' => $language_name,
        '#default_value' => isset($settings['post_url'][$language_code]) ? $settings['post_url'][$language_code] : $settings['post_url'][LANGUAGE_NONE],
        '#required' => FALSE,
        '#states' => array(
          'visible' => array(
            ':input[name="field[settings][define_per_language]"]' => array(
              'checked' => TRUE,
            ),
          ),
        ),
      ),
    );
  }
  $form['booked_state'] = array(
    '#type' => 'select',
    '#title' => t('Change state to'),
    '#description' => t("The state to change the calendar to after the user has selected the arrival and departure dates. Note that the state is only visually changed in the browser, not stored."),
    '#default_value' => $settings['booked_state'],
    '#options' => availability_calendar_get_states('label'),
    '#required' => TRUE,
    '#weight' => 13,
  );
  return $form;
}

/**
 * Implements hook_field_instance_settings_form().
 * @link http://api.drupal.org/api/drupal/modules--field_ui--field_ui.api.php/function/hook_field_instance_settings_form/7
 */
function availability_calendar_booking_formlet_field_instance_settings_form($field, $instance) {
  $settings = $instance['settings'];
  $form = array();
  return $form;
}

/**
 * Implements hook_field_is_empty().
 * @link http://api.drupal.org/api/drupal/modules--field--field.api.php/function/hook_field_is_empty/7
 *
 * A booking formlet is always considered empty, it is a display only field.
 */
function availability_calendar_booking_formlet_field_is_empty($item, $field) {
  return TRUE;
}

/**
 * Implements hook_field_validate().
 * @link http://api.drupal.org/api/drupal/modules--field--field.api.php/function/hook_field_validate/7
 *
 * Verifies that the booking formlet is valid. The booking formlet is a display
 * only field and thus does not need to be validated.
 */
function availability_calendar_booking_formlet_field_validate($entity_type, $entity, $field, $instance, $langcode, $items, &$errors) {
}

/**************************************************************************
 * Field Type API: Widget
 *
 * The widget is the form element used to receive input from the user
 * when the field is being populated.
 **************************************************************************/

/**
 * Implements hook_field_widget_info.
 * @link http://api.drupal.org/api/drupal/modules--field--field.api.php/function/hook_field_widget_info/7
 *
 * For now, this module defines 1 widget. Other widgets may be defined in the
 * future or by other modules.
 */
function availability_calendar_booking_formlet_field_widget_info() {
  return array(
    'availability_calendar_booking_formlet' => array(
      'label' => t('- None -'),
      'description' => '',
      'field types' => array(
        'availability_calendar_booking_formlet',
      ),
      'settings' => array(),
      'behaviors' => array(
        'multiple values' => FIELD_BEHAVIOR_CUSTOM,
        'default value' => FIELD_BEHAVIOR_NONE,
      ),
    ),
  );
}

/**
 * Implements hook_field_widget_settings_form
 * @link http://api.drupal.org/api/drupal/modules--field_ui--field_ui.api.php/function/hook_field_widget_settings_form/7
 */
function availability_calendar_booking_formlet_field_widget_settings_form($field, $instance) {
  $form = array();
  return $form;
}

/**
 * Implements hook_field_widget_form().
 * @link http://api.drupal.org/api/drupal/modules--field--field.api.php/function/hook_field_widget_form/7
 */
function availability_calendar_booking_formlet_field_widget_form(&$form, &$form_state, $field, $instance, $langcode, $items, $delta, $element) {
  $element['#access'] = FALSE;
  return $element;
}

/******************************************************************************
 *  Field Type API: Formatter
 *
 *  These are the api hooks that present formatted (themed) output to the user.
 *****************************************************************************/

/**
 * Implements hook_field_formatter_info().
 * @link http://api.drupal.org/api/drupal/modules--field--field.api.php/function/hook_field_formatter_info/7
 */
function availability_calendar_booking_formlet_field_formatter_info() {
  return array(
    'availability_calendar_booking_formlet' => array(
      'label' => t('Show booking formlet'),
      'field types' => array(
        'availability_calendar_booking_formlet',
      ),
      'settings' => array(
        'submit_only' => FALSE,
        'single_day_only' => FALSE,
        'preset_begin_date_source' => 'none',
        'preset_begin_date_key' => '',
        'preset_end_date_source' => 'none',
        'preset_end_date_key' => '',
      ),
    ),
  );
}

/**
 * Implements hook_field_formatter_settings_form().
 * @link http://api.drupal.org/api/drupal/modules--field_ui--field_ui.api.php/function/hook_field_formatter_settings_form/7
 */
function availability_calendar_booking_formlet_field_formatter_settings_form($field, $instance, $view_mode, $form, &$form_state) {
  $element = array();
  $display = $instance['display'][$view_mode];
  $type = $display['type'];
  $settings = $display['settings'];
  $name_prefix = 'fields[' . $field['field_name'] . '][settings_edit_form][settings]';
  $element = array();
  $element['submit_only'] = array(
    '#type' => 'checkbox',
    '#title' => t('Only show the "Book now" button'),
    '#default_value' => $settings['submit_only'],
    '#description' => t('This will hide the date fields and their reset buttons, effectively disabling any interaction between the calendar, user and this booking formlet. You should only check this option if the dates will be prefilled as per the settings below and you do not want the user to change that selection anymore.'),
  );
  $element['single_day_only'] = array(
    '#type' => 'checkbox',
    '#title' => t('Only allow single day bookings'),
    '#default_value' => $settings['submit_only'],
    '#description' => t('This will hide the departure date field, turning the form into a single day booking formlet. You should check this option if you only accept single day bookings and want to optimize the UI for that.'),
  );
  $element['description'] = array(
    '#type' => 'item',
    '#description' => t('Below you can specify default values for the begin and end date. These can come from dynamic sources like $_GET or $_POST and may contain angle brackets ("[" and "]") to access an array value. Note that these values will only be set if an accompanying calendar is indeed "available". This option will typically be used in combination with a "view" that filters on availability.'),
  );
  $element['preset_begin_date_source'] = array(
    '#type' => 'select',
    '#title' => t('Source for the begin date'),
    '#default_value' => $settings['preset_begin_date_source'],
    '#options' => array(
      'none' => t('None'),
      'today' => t('Today'),
      'get' => t('GET value'),
      'post' => t('POST value'),
    ),
    '#required' => FALSE,
  );
  $name_begin = $name_prefix . '[preset_begin_date_source]';
  $element['preset_begin_date_key'] = array(
    '#type' => 'textfield',
    '#title' => t('Key for the begin date value'),
    '#default_value' => $settings['preset_begin_date_key'],
    '#required' => $settings['preset_begin_date_source'] === 'get' || $settings['preset_begin_date_source'] === 'post',
    '#size' => 36,
    '#states' => array(
      'visible' => array(
        ":input[name='{$name_begin}']" => array(
          array(
            'value' => 'get',
          ),
          array(
            'value' => 'post',
          ),
        ),
      ),
      'required' => array(
        ":input[name='{$name_begin}']" => array(
          array(
            'value' => 'get',
          ),
          array(
            'value' => 'post',
          ),
        ),
      ),
    ),
  );
  $element['preset_end_date_source'] = array(
    '#type' => 'select',
    '#title' => t('Source for the end date'),
    '#default_value' => isset($settings['preset_end_date_source']) ? $settings['preset_end_date_source'] : 'none',
    '#options' => array(
      'none' => t('None'),
      'today' => t('Today'),
      'fixed_duration' => t('Fixed duration'),
      'get' => t('GET value as end date'),
      'post' => t('POST value as end date'),
      'get1' => t('GET value as departure date'),
      'post1' => t('POST value as departure date'),
      'get_duration' => t('GET value as duration'),
      'post_duration' => t('POST value as duration'),
    ),
    '#states' => array(
      'invisible' => array(
        ":input[name='{$name_begin}']" => array(
          'value' => 'none',
        ),
      ),
    ),
  );
  $name_end = $name_prefix . '[preset_end_date_source]';
  $element['preset_end_date_key'] = array(
    '#type' => 'textfield',
    '#title' => t('Key for the end date value or number of days'),
    '#default_value' => isset($settings['preset_end_date_key']) ? $settings['preset_end_date_key'] : '',
    '#required' => $settings['preset_end_date_source'] !== 'none' && $settings['preset_end_date_source'] !== 'today',
    '#size' => 36,
    '#states' => array(
      'invisible' => array(
        array(
          ":input[name='{$name_begin}']" => array(
            'value' => 'none',
          ),
        ),
        array(
          ":input[name='{$name_end}']" => array(
            array(
              'value' => 'none',
            ),
            array(
              'value' => 'today',
            ),
          ),
        ),
      ),
      'optional' => array(
        ":input[name='{$name_end}']" => array(
          array(
            'value' => 'none',
          ),
          array(
            'value' => 'today',
          ),
        ),
      ),
    ),
  );
  $element['#attached']['css'] = array(
    drupal_get_path('module', 'availability_calendar_booking_formlet') . '/availability_calendar_booking_formlet.admin.css',
  );
  return $element;
}

/**
 * Implements hook_field_formatter_settings_summary().
 * @link http://api.drupal.org/api/drupal/modules--field_ui--field_ui.api.php/function/hook_field_formatter_settings_summary/7
 */
function availability_calendar_booking_formlet_field_formatter_settings_summary($field, $instance, $view_mode) {
  $display = $instance['display'][$view_mode];
  $settings = $display['settings'];
  $summary = array();

  // Summary info about showing whole form or submit button only.
  $summary[] = $settings['submit_only'] ? t('Only show the submit button') : t('Show the complete booking formlet');

  // Summary info about the source of the begin date.
  switch ($settings['preset_begin_date_source']) {
    case 'today':
      $source = t('today');
      break;
    case 'get':
    case 'post':
      $key = availability_calendar_booking_formlet_format_key($settings['preset_begin_date_key']);
      $source = '$_' . strtoupper($settings['preset_begin_date_source']) . $key;
      break;
    case 'none':
    default:
      $source = t('blank');
      break;
  }
  $summary[] = t('Default begin date: @value', array(
    '@value' => $source,
  ));

  // Summary info about the source of the end date.
  switch ($settings['preset_end_date_source']) {
    case 'get':
    case 'post':
      $key = availability_calendar_booking_formlet_format_key($settings['preset_end_date_key']);
      $source = '$_' . strtoupper($settings['preset_end_date_source']) . $key;
      $line = t('Default end date: @value', array(
        '@value' => $source,
      ));
      break;
    case 'get1':
    case 'post1':
      $key = availability_calendar_booking_formlet_format_key($settings['preset_end_date_key']);
      $source = substr($settings['preset_end_date_source'], 0, strpos($settings['preset_end_date_source'], '_'));
      $source = '$_' . strtoupper($source) . $key;
      $line = t('Default departure date: @value', array(
        '@value' => $source,
      ));
      break;
    case 'get_duration':
    case 'post_duration':
      $key = availability_calendar_booking_formlet_format_key($settings['preset_end_date_key']);
      $global = $settings['preset_end_date_source'] === 'get_duration' ? 'GET' : 'POST';
      $source = '$_' . $global . $key;
      $line = t('Default end date: begin + @value days', array(
        '@value' => $source,
      ));
      break;
    case 'fixed_duration':
      $source = $settings['preset_end_date_key'];
      $line = t('Default end date: begin + @value days', array(
        '@value' => $source,
      ));
      break;
    case 'none':
    default:
      $source = t('blank');
      $line = t('Default end date: @value', array(
        '@value' => $source,
      ));
      break;
  }
  $summary[] = $line;
  return implode('<br/>', $summary);
}
function availability_calendar_booking_formlet_format_key($key) {
  $key = check_plain($key);

  // Put angle brackets around (first part of) the key.
  $pos = strpos($key, '[');
  if ($pos === FALSE) {
    $key = "[{$key}]";
  }
  else {
    $key = '[' . substr($key, 0, $pos) . ']' . substr($key, $pos);
  }
  return $key;
}

/**
 * Implements hook_field_formatter_view().
 * @link http://api.drupal.org/api/drupal/modules--field--field.api.php/function/hook_field_formatter_view/7
 */
function availability_calendar_booking_formlet_field_formatter_view($entity_type, $entity, $field, $instance, $langcode, &$items, $display) {
  $settings = $display['settings'] + $instance['settings'] + $field['settings'];

  // Get values for the begin and end date based on the field settings and
  // the context.
  $from = availability_calendar_booking_formlet_extract_date($settings, 'preset_begin_date');
  $to = $from !== NULL ? availability_calendar_booking_formlet_extract_date($settings, 'preset_end_date', $from) : NULL;

  // We need this function here only when from is set.
  if ($from !== NULL && !function_exists('availability_calendar_is_available')) {
    module_load_include('inc', 'availability_calendar', 'availability_calendar');
  }

  // Find all calendars in this entity that are enabled. If there is no enabled
  // calendar, we do not show the booking form.
  //
  // We also look for the first calendar that is "available" during the from-to
  // period (or just on the from date if no to date is set). This calendar will
  // be used as default selection, together with the from and to date.
  $cids = array();
  $calendar = NULL;
  $calendar_settings = NULL;
  $field_instance_info = field_info_instances($entity_type, $instance['bundle']);
  foreach ($field_instance_info as $field_name => $field_instance) {
    $field_info = field_info_field_by_id($field_instance['field_id']);
    if ($field_info['type'] === 'availability_calendar') {
      $calendar_field_items = field_get_items($entity_type, $entity, $field_name, $langcode);
      if ($calendar_field_items !== FALSE) {
        foreach ($calendar_field_items as $delta => $calendar_field_item) {
          if (isset($calendar_field_item['enabled']) && $calendar_field_item['enabled']) {
            $cids[] = $calendar_field_item['cid'];
            if ($from !== NULL && $calendar === NULL) {
              if (availability_calendar_is_available($calendar_field_item['cid'], $from, $to !== NULL ? $to : $from, $field_info['settings']['default_state'])) {
                $calendar = $calendar_field_item;
                $calendar_settings = $field_info['settings'];
              }
            }
          }
        }
      }
    }
  }
  $element = array();
  if (count($cids) > 0) {

    // $items will be empty because this is a display only field: fake 1 item.
    $delta = 0;
    $items[$delta] = array();

    // If we didn't find an available calendar we have to set the from and to
    // dates to null.
    if ($calendar === NULL) {
      $from = NULL;
      $to = NULL;
    }
    $element[$delta] = drupal_get_form('availability_calendar_booking_formlet_form', $entity_type, $entity, $settings, $cids, $calendar, $calendar_settings, $from, $to);
  }
  return $element;
}
function availability_calendar_booking_formlet_form($form_id, $form_state) {
  static $formlet_count = 0;
  module_load_include('inc', 'availability_calendar', 'availability_calendar');
  $formlet_count++;
  $entity_type = $form_state['build_info']['args'][0];
  $entity = $form_state['build_info']['args'][1];
  $entity_id = entity_extract_ids($entity_type, $entity);
  $entity_id = $entity_id[0];
  $entity_label = entity_label($entity_type, $entity);
  $settings = $form_state['build_info']['args'][2];
  $cids = $form_state['build_info']['args'][3];
  $calendar = $form_state['build_info']['args'][4];
  $calendar_settings = $form_state['build_info']['args'][5];
  $from = $form_state['build_info']['args'][6];
  $to = $form_state['build_info']['args'][7];
  $form = array();
  $form['#id'] = "availability-calendar-booking-formlet-form-{$formlet_count}";
  $form['cid'] = array(
    '#type' => 'hidden',
    '#value' => $calendar !== NULL ? $calendar['cid'] : '',
  );
  $form['calendar_label'] = array(
    '#type' => 'hidden',
    '#value' => $calendar !== NULL ? $calendar['name'] : '',
  );
  $form['entity_type'] = array(
    '#type' => 'hidden',
    '#value' => $entity_type,
  );
  $form['entity_id'] = array(
    '#type' => 'hidden',
    '#value' => $entity_id,
  );
  $form['entity_label'] = array(
    '#type' => 'hidden',
    '#value' => $entity_label,
  );
  $form['from_iso'] = array(
    '#type' => 'hidden',
    '#value' => !empty($from) ? $from
      ->format(AC_ISODATE) : '',
  );
  $form['to_iso'] = array(
    '#type' => 'hidden',
    '#value' => !empty($to) ? $to
      ->format(AC_ISODATE) : '',
  );
  if ($settings['submit_only']) {
    $form['from_display'] = array(
      '#type' => 'hidden',
      '#value' => $from instanceof DateTime ? availability_calendar_format_display_date($from) : '',
    );
    $form['to_display'] = array(
      '#type' => 'hidden',
      '#value' => $to instanceof DateTime ? availability_calendar_format_display_date($to) : '',
    );
  }
  else {
    $form['from_display'] = array(
      '#type' => 'textfield',
      '#title' => t('Arrival date'),
      '#default_value' => $from instanceof DateTime ? availability_calendar_format_display_date($from) : '',
      '#required' => TRUE,
      '#disabled' => TRUE,
      '#attributes' => array(
        'readonly' => 'readonly',
      ),
      '#prefix' => '<div class="acbf-date">',
      '#suffix' => '<input class="acbf-reset-from form-reset" type="reset" value="' . t('Clear selected arrival date') . '" /></div>',
    );
    if ($settings['single_day_only']) {
      $form['to_display'] = array(
        '#type' => 'hidden',
        '#value' => $to instanceof DateTime ? availability_calendar_format_display_date($to) : '',
      );
      $form['from_display']['#suffix'] = '<input class="acbf-reset-from form-reset" type="reset" value="' . t('Clear selected date') . '" /></div>';
    }
    else {
      $form['to_display'] = array(
        '#type' => 'textfield',
        '#title' => t('Departure date'),
        '#default_value' => $to instanceof DateTime ? availability_calendar_format_display_date($to) : '',
        '#required' => TRUE,
        '#disabled' => TRUE,
        '#attributes' => array(
          'readonly' => 'readonly',
        ),
        '#prefix' => '<div class="acbf-date">',
        '#suffix' => '<input class="acbf-reset-both form-reset" type="reset" value="' . t('Clear selected dates') . '" /></div>',
      );
    }
  }

  // Add form submit button.
  $form['actions'] = array(
    '#type' => 'actions',
    'submit' => array(
      '#type' => 'submit',
      '#value' => t('Book this resource ...'),
      '#disabled' => TRUE,
    ),
  );
  global $language;
  $post_url = '';
  if ($settings['define_per_language'] && isset($settings['post_url'][$language->language])) {
    $post_url = $settings['post_url'][$language->language];
  }
  else {
    if (isset($settings['post_url'][LANGUAGE_NONE])) {
      $post_url = $settings['post_url'][LANGUAGE_NONE];
    }
    else {
      if (is_array($settings['post_url'])) {
        $post_url = reset($settings['post_url']);
      }
    }
  }
  if (is_array($post_url)) {
    $post_url = reset($post_url);
  }
  $form['#action'] = url($post_url);
  $form['#method'] = 'POST';

  // Add js and css.
  if ($settings['submit_only'] && $calendar !== NULL && $calendar_settings !== NULL) {

    // If only the book now button is shown, the calendar might not be shown.
    // Make sure there is a javascript instance that represents the selected
    // calendar (and that can be queried by our javascript).
    availability_calendar_add_calendar_js($calendar['cid'], $calendar['name'], $calendar_settings['allocation_type']);
  }
  availability_calendar_booking_formlet_add_js($formlet_count, $form['#id'], $cids, $settings);
  $form['#attached']['css'] = array(
    drupal_get_path('module', 'availability_calendar_booking_formlet') . '/availability_calendar_booking_formlet.css',
  );
  return $form;
}

/**
 * Returns a date based on the settings and global context.
 *
 * @param array $settings
 * @param string $date
 *   Either 'preset_begin_date' or 'preset_end_date'
 * @param null|DateTime $offset
 *   null or a date to use as offset if the source indicates a duration rather
 *   than a date on its own.
 *
 * @return null|DateTime
 */
function availability_calendar_booking_formlet_extract_date($settings, $date, $offset = null) {
  $source = $settings["{$date}_source"];
  $global = substr($source, 0, strlen('get')) === 'get' ? $_GET : $_POST;
  $key = $settings["{$date}_key"];
  $result = null;
  switch ($source) {
    case 'today':
      $result = new DateTime();
      break;
    case 'fixed_duration':
      if ($offset instanceof DateTime) {
        $result = clone $offset;
        $duration = (int) $key;

        // Adjust duration as to date is inclusive.
        $duration--;
        $result
          ->modify("+{$duration} days");
      }
      break;
    case 'get':
    case 'post':
    case 'get1':
    case 'post1':
      $date = availability_calendar_booking_formlet_get_nested_array_value($global, $key);
      if (is_string($date)) {
        $date = availability_calendar_parse_entry_date($date);
        if ($date instanceof DateTime) {
          $result = $date;

          // get1 and post1 are not inclusive: modify by 1 day.
          if (substr($source, -strlen('1')) === '1') {
            $result
              ->modify('-1 day');
          }
        }
      }
      break;
    case 'get_duration':
    case 'post_duration':
      if ($offset instanceof DateTime) {
        $duration = availability_calendar_booking_formlet_get_nested_array_value($global, $key);
        if (is_int($duration) || ctype_digit($duration)) {
          $result = clone $offset;
          $duration = (int) $duration;

          // Adjust duration as to date is inclusive.
          $duration--;
          $result
            ->modify("+{$duration} days");
        }
      }
      break;
    case 'none':
    default:
      break;
  }

  // Set time to noon to avoid timezone conversion rounding errors later.
  if ($result instanceof DateTime) {
    $result
      ->setTime(12, 0, 0);
  }
  return $result;
}

/**
 * Extracts a possibly multi-level key from an array.
 *
 * @param array $array
 *   The array to extract the value from.
 * @param string $key
 *   The key, something like 'key1' or key1[subkey1][subkey2].
 *
 * @return null|mixed
 *   Null when the key does not exist, the value of the array entry otherwise.
 */
function availability_calendar_booking_formlet_get_nested_array_value($array, $key) {
  $keys = explode('[', str_replace(']', '', $key));
  return drupal_array_get_nested_value($array, $keys);
}
function availability_calendar_booking_formlet_add_js($formlet_count, $form_id, $cids, $settings) {

  // Ensure that the base client side API loads as well including, optionally,
  // the date formatting functionality of datepicker
  availability_calendar_add_base_js();
  drupal_add_js(drupal_get_path('module', 'availability_calendar_booking_formlet') . '/availability_calendar_booking_formlet.js', array(
    'type' => 'file',
  ));
  $cids = implode(',', $cids);
  $booked_state = '"' . $settings['booked_state'] . '"';
  $single_day = $settings['single_day_only'] ? 'true' : 'false';
  drupal_add_js("Drupal.behaviors.availabilityCalendarBookingFormlet{$formlet_count} = {\n    attach: function(context, settings) {\n      Drupal.availabilityCalendar.getBookingFormlet('#{$form_id}', [{$cids}], {$booked_state}, {$single_day});\n    }\n  };", array(
    'type' => 'inline',
    'scope' => 'footer',
  ));
}

Functions

Namesort descending Description
availability_calendar_booking_formlet_add_js
availability_calendar_booking_formlet_extract_date Returns a date based on the settings and global context.
availability_calendar_booking_formlet_field_formatter_info Implements hook_field_formatter_info(). @link http://api.drupal.org/api/drupal/modules--field--field.api.php/function/...
availability_calendar_booking_formlet_field_formatter_settings_form Implements hook_field_formatter_settings_form(). @link http://api.drupal.org/api/drupal/modules--field_ui--field_ui.api.php/fun...
availability_calendar_booking_formlet_field_formatter_settings_summary Implements hook_field_formatter_settings_summary(). @link http://api.drupal.org/api/drupal/modules--field_ui--field_ui.api.php/fun...
availability_calendar_booking_formlet_field_formatter_view Implements hook_field_formatter_view(). @link http://api.drupal.org/api/drupal/modules--field--field.api.php/function/...
availability_calendar_booking_formlet_field_info Implements hook_field_info(). @link http://api.drupal.org/api/drupal/modules--field--field.api.php/function/...
availability_calendar_booking_formlet_field_instance_settings_form Implements hook_field_instance_settings_form(). @link http://api.drupal.org/api/drupal/modules--field_ui--field_ui.api.php/fun...
availability_calendar_booking_formlet_field_is_empty Implements hook_field_is_empty(). @link http://api.drupal.org/api/drupal/modules--field--field.api.php/function/...
availability_calendar_booking_formlet_field_settings_form Implements hook_field_settings_form(). @link http://api.drupal.org/api/drupal/modules--field_ui--field_ui.api.php/fun...
availability_calendar_booking_formlet_field_validate Implements hook_field_validate(). @link http://api.drupal.org/api/drupal/modules--field--field.api.php/function/...
availability_calendar_booking_formlet_field_widget_form Implements hook_field_widget_form(). @link http://api.drupal.org/api/drupal/modules--field--field.api.php/function/...
availability_calendar_booking_formlet_field_widget_info Implements hook_field_widget_info. @link http://api.drupal.org/api/drupal/modules--field--field.api.php/function/...
availability_calendar_booking_formlet_field_widget_settings_form Implements hook_field_widget_settings_form @link http://api.drupal.org/api/drupal/modules--field_ui--field_ui.api.php/fun...
availability_calendar_booking_formlet_form
availability_calendar_booking_formlet_format_key
availability_calendar_booking_formlet_get_nested_array_value Extracts a possibly multi-level key from an array.