You are here

date_field.module in Date 8

File

date_field/date_field.module
View source
<?php

use Drupal\Core\Datetime\DrupalDateTime;
use Drupal\date_api\DateGranularity;

/**
 * Implements hook_date_field_date_callbacks().
 *
 * Returns an array of available callbacks for the date element of the datepicker widget.
 */
function date_field_date_field_date_callbacks() {
  return array(
    'datetime_jquery_datepicker' => t('jQuery popup datepicker'),
  );
}

/**
 * Implements hook_date_field_time_callbacks().
 *
 * Returns an array of available callbacks for the time element of the datepicker widget.
 */
function date_field_date_field_time_callbacks() {
  return array(
    'date_field_all_day_toggle_callback' => t('All day checkbox toggle'),
  );
}

/**
 * A callback for the time element to add an 'All day' checkbox to
 * the form.
 */
function date_field_all_day_toggle_callback(&$element, &$form_state, $date) {
  if (!empty($element['#date_all_day_toggle'])) {
    $parents = $element['#parents'];
    array_pop($parents);
    $first_parent = array_shift($parents);
    $all_day_id = $first_parent . '[' . implode('][', $parents) . '][all_day]';
    $element['time']['#states'] = array(
      'visible' => array(
        'input[name="' . $all_day_id . '"]' => array(
          'checked' => FALSE,
        ),
      ),
    );
  }
}

/**
 * Timezone handling options.
 *
 * The 'none' option will do no timezone conversions and will store and display
 * dates exactly as entered useful in locales or situations where timezone
 * conversions are not working reliably, for dates with no times, for historical
 * dates where timezones are irrelevant, or anytime conversion is unnecessary or
 * undesirable.
 */
function date_timezone_handling_options() {
  return array(
    'site' => t("Site's time zone"),
    'date' => t("Date's time zone"),
    'user' => t("User's time zone"),
    'utc' => 'UTC',
    'none' => t('No time zone conversion'),
  );
}

/**
 * Implements hook_field_is_empty().
 */
function date_field_field_is_empty($item, $field) {
  if (empty($item['value'])) {
    return TRUE;
  }
  elseif ($field['settings']['todate'] == 'required' && empty($item['value2'])) {
    return TRUE;
  }
  return FALSE;
}

/**
 * Implements hook_field_info().
 */
function date_field_field_info() {
  return array(
    'date' => array(
      'label' => 'Date Range',
      'description' => t('Store a start and optional end date in the database as ISO dates.'),
      'settings' => array(
        'todate' => '',
        'granularity' => drupal_map_assoc(array(
          'year',
          'month',
          'day',
          'hour',
          'minute',
        )),
        'tz_handling' => 'site',
        'timezone_db' => 'UTC',
      ),
      'instance_settings' => array(
        'default_value' => 'now',
        'default_value_code' => '',
        'default_value2' => 'same',
        'default_value_code2' => '',
      ),
      'default_widget' => 'date_select',
      'default_formatter' => 'date_default',
      'default_token_formatter' => 'date_plain',
      'field item class' => '\\Drupal\\date\\Type\\DateItem',
    ),
  );
}

/**
 * Implements hook_field_load().
 */
function date_field_field_load($entity_type, $entities, $field, $instances, $langcode, &$items, $age) {
  $timezone_db = date_get_timezone_db($field['settings']['tz_handling']);
  $db_format = date_type_format($field['type']);
  $keys = date_available_values($field);
  foreach ($entities as $id => $entity) {
    foreach ($items[$id] as $delta => &$item) {

      // If the file does not exist, mark the entire item as empty.
      if (is_array($item)) {
        $item['data'] = isset($item['data']) ? unserialize($item['data']) : array();
        $item['timezone_db'] = $timezone_db;
        $item['date_type'] = $field['type'];
        if (!empty($field['settings']['cache_enabled']) && ($delta < $field['settings']['cache_count'] || $field['settings']['cache_count'] == 0)) {
          foreach ($keys as $key) {
            if (!empty($item[$key])) {
              $item['db'][$key] = $date;
            }
          }
        }
      }
    }
  }
}

/**
 * Implements hook_field_insert().
 */
function date_field_field_presave($entity_type, $entity, $field, $instance, $langcode, &$items) {
  $field_name = $field['field_name'];
  if (empty($items)) {
    return;
  }

  // Add some information needed to interpret token values.
  $values = $items;
  foreach ($values as $delta => $item) {
    $timezone = isset($item['timezone']) ? $item['timezone'] : '';
    if (is_array($item)) {
      $items[$delta]['timezone'] = date_get_timezone($field['settings']['tz_handling'], $timezone);
      $items[$delta]['timezone_db'] = date_get_timezone_db($field['settings']['tz_handling']);
      $items[$delta]['date_type'] = $field['type'];
      $data = array();
      foreach (date_data_keys() as $key) {
        if (isset($item[$key])) {
          $data[$delta][$key] = $item[$key];
          unset($items[$delta][$key]);
        }
      }
      $items[$delta]['data'] = serialize($data);
    }
  }
  $entity->{$field['field_name']}[$langcode] = $items;
}

/**
 * Helper function for date_field_instance_settings_form().
 *
 * @see date_field_instance_settings_form_validate()
 */
function date_field_field_instance_settings_form($field, $instance) {
  $widget = $instance['widget'];
  $settings = $instance['settings'];
  $widget_settings = $instance['widget']['settings'];
  $form['default_value'] = array(
    '#type' => 'select',
    '#title' => t('Default date'),
    '#default_value' => $settings['default_value'],
    '#options' => array(
      'blank' => t('No default value'),
      'now' => t('Now'),
      'strtotime' => t('Relative'),
    ),
    '#weight' => 1,
    '#fieldset' => 'default_values',
  );
  $description = t("Describe a time by reference to the current day, like '+90 days' (90 days from the day the field is created) or '+1 Saturday' (the next Saturday). See !strtotime for more details.", array(
    '!strtotime' => l(t('strtotime'), 'http://www.php.net/manual/en/function.strtotime.php'),
  ));
  $form['default_value_code'] = array(
    '#type' => 'textfield',
    '#title' => t('Relative default value'),
    '#description' => $description,
    '#default_value' => $settings['default_value_code'],
    '#states' => array(
      'visible' => array(
        ':input[name="instance[settings][default_value]"]' => array(
          'value' => 'strtotime',
        ),
      ),
    ),
    '#weight' => 1.1,
    '#fieldset' => 'default_values',
  );
  $form['default_value2'] = array(
    '#type' => !empty($field['settings']['todate']) ? 'select' : 'hidden',
    '#title' => t('Default end date'),
    '#default_value' => $settings['default_value2'],
    '#options' => array(
      'same' => t('Same as Default date'),
      'blank' => t('No default value'),
      'now' => t('Now'),
      'strtotime' => t('Relative'),
    ),
    '#weight' => 2,
    '#fieldset' => 'default_values',
  );
  $form['default_value_code2'] = array(
    '#type' => !empty($field['settings']['todate']) ? 'textfield' : 'hidden',
    '#title' => t('Relative default value for end date'),
    '#description' => $description,
    '#default_value' => $settings['default_value_code2'],
    '#states' => array(
      'visible' => array(
        ':input[name="instance[settings][default_value2]"]' => array(
          'value' => 'strtotime',
        ),
      ),
    ),
    '#weight' => 2.1,
    '#fieldset' => 'default_values',
  );
  $form['#element_validate'] = array(
    'date_field_instance_settings_form_validate',
  );
  $context = array(
    'field' => $field,
    'instance' => $instance,
  );
  drupal_alter('date_field_instance_settings_form', $form, $context);
  return $form;
}

/**
 * Form validation handler for _date_field_instance_settings_form().
 */
function date_field_field_instance_settings_form_validate(&$form, &$form_state) {
  $settings = $form_state['values']['instance']['settings'];
  if ($settings['default_value'] == 'strtotime') {
    $is_strtotime = @strtotime($settings['default_value_code']);
    if (!$is_strtotime) {
      form_set_error('instance][settings][default_value_code', t('The Strtotime default value is invalid.'));
    }
  }
  if (isset($settings['default_value2']) && $settings['default_value2'] == 'strtotime') {
    $is_strtotime = @strtotime($settings['default_value_code2']);
    if (!$is_strtotime) {
      form_set_error('instance][settings][default_value_code2', t('The Strtotime default value for the End Date is invalid.'));
    }
  }
}

/**
 * Helper function for date_field_settings_form().
 *
 * @see date_field_settings_validate()
 */
function date_field_field_settings_form($field, $instance, $has_data) {
  $settings = $field['settings'];
  $form = array(
    '#element_validate' => array(
      'date_field_settings_validate',
    ),
  );

  // Make sure granularity is in the right format and has no empty values.
  if (!empty($settings['granularity']) && is_array($settings['granularity'])) {
    $granularity = array_filter($settings['granularity']);
  }
  $tz_handling = $settings['tz_handling'];
  $description = t('Select the date attributes to collect and store.');
  $options = DateGranularity::granularityNames();
  $checkbox_year = array(
    '#type' => 'checkbox',
    '#title' => check_plain($options['year']),
    '#value' => 'year',
    '#return_value' => 'year',
    '#disabled' => TRUE,
  );
  unset($options['year']);
  $form['granularity'] = array(
    '#type' => 'checkboxes',
    '#title' => t('Date attributes to collect'),
    '#default_value' => $granularity,
    '#options' => $options,
    '#attributes' => array(
      'class' => array(
        'container-inline',
      ),
    ),
    '#description' => $description,
    '#disabled' => $has_data,
    'year' => $checkbox_year,
  );
  $description = t('End dates are used to collect duration. E.g., allow an event to start on September 15, and end on September 16.');
  $form['enddate_get'] = array(
    '#type' => 'checkbox',
    '#title' => t('Collect an end date'),
    '#description' => $description,
    '#default_value' => empty($settings['todate']) ? FALSE : TRUE,
    '#disabled' => $has_data,
  );
  $form['enddate_required'] = array(
    '#type' => 'checkbox',
    '#title' => t('Required'),
    '#default_value' => isset($settings['todate']) && $settings['todate'] === 'required' ? TRUE : FALSE,
    '#disabled' => $has_data,
    '#states' => array(
      'invisible' => array(
        'input[name="field[settings][enddate_get]"]' => array(
          'checked' => FALSE,
        ),
      ),
    ),
  );
  $description = t('Select the timezone handling method for this date field.');
  $form['tz_handling'] = array(
    '#type' => 'select',
    '#title' => t('Time zone handling'),
    '#default_value' => $tz_handling,
    '#options' => date_timezone_handling_options(),
    '#description' => $description,
    '#disabled' => $has_data,
    '#attached' => array(
      'js' => array(
        drupal_get_path('module', 'date') . '/date_admin.js',
      ),
    ),
  );

  // Force this value to hidden because we don't want to allow it to be changed
  // right now, but allow it to be a variable if needed.
  $form['timezone_db'] = array(
    '#type' => 'hidden',
    '#value' => date_get_timezone_db($tz_handling),
  );
  $form['cache_enabled'] = array(
    '#type' => 'checkbox',
    '#title' => t('Cache dates'),
    '#description' => t('Date objects can be created and cached as date fields are loaded rather than when they are displayed to improve performance.'),
    '#default_value' => !empty($settings['cache_enabled']),
    '#weight' => 10,
  );
  $form['cache_count'] = array(
    '#type' => 'textfield',
    '#title' => t('Maximum dates per field'),
    '#default_value' => isset($settings['cache_count']) ? $settings['cache_count'] : 4,
    '#description' => t("If set to '0', all date values on every entity will be cached. Note that caching every date on fields that may have a large number of multiple or repeating values may create a significant performance penalty when the cache is cleared. The suggested setting for multiple value and repeating fields is no more than 4 values per field."),
    '#size' => 3,
    '#weight' => 11,
    '#states' => array(
      'visible' => array(
        'input[name="field[settings][cache_enabled]"]' => array(
          'checked' => TRUE,
        ),
      ),
    ),
  );
  $context = array(
    'field' => $field,
    'instance' => $instance,
    'has_data' => $has_data,
  );
  drupal_alter('date_field_settings_form', $form, $context);
  return $form;
}

/**
 * Form validation handler for date_field_field_settings_form().
 */
function date_field_field_settings_validate(&$form, &$form_state) {
  $field =& $form_state['values']['field'];
  if ($field['settings']['tz_handling'] == 'none') {
    form_set_value($form['timezone_db'], '', $form_state);
  }
  else {
    form_set_value($form['timezone_db'], date_get_timezone_db($field['settings']['tz_handling']), $form_state);
  }
  if ($field['settings']['tz_handling'] != 'none' && !in_array('hour', array_filter($field['settings']['granularity']))) {
    form_set_error('field[settings][tz_handling]', t('Dates without hours granularity must not use any timezone handling.'));
  }

  // Extract the correct 'todate' value out of the two end date checkboxes.
  if ($field['settings']['enddate_get']) {
    if ($field['settings']['enddate_required']) {
      $field['settings']['todate'] = 'required';
    }
    else {
      $field['settings']['todate'] = 'optional';
    }
  }
  else {
    $field['settings']['todate'] = '';
  }

  // Don't save the pseudo values created in the UI.
  unset($field['settings']['enddate_get'], $field['settings']['enddate_required']);
  if (!empty($field['settings']['cache_enabled'])) {
    if (!is_numeric($field['settings']['cache_count'])) {
      form_set_error('field[settings][cache_count]', t('The number of cache values must be a number.'));
    }
    elseif ($field['settings']['cache_count'] < 0) {
      form_set_error('field[settings][cache_count]', t('The number of cache values must be a number 0 or greater.'));
    }
  }
}

Functions

Namesort descending Description
date_field_all_day_toggle_callback A callback for the time element to add an 'All day' checkbox to the form.
date_field_date_field_date_callbacks Implements hook_date_field_date_callbacks().
date_field_date_field_time_callbacks Implements hook_date_field_time_callbacks().
date_field_field_info Implements hook_field_info().
date_field_field_instance_settings_form Helper function for date_field_instance_settings_form().
date_field_field_instance_settings_form_validate Form validation handler for _date_field_instance_settings_form().
date_field_field_is_empty Implements hook_field_is_empty().
date_field_field_load Implements hook_field_load().
date_field_field_presave Implements hook_field_insert().
date_field_field_settings_form Helper function for date_field_settings_form().
date_field_field_settings_validate Form validation handler for date_field_field_settings_form().
date_timezone_handling_options Timezone handling options.