Skip to content
date_views.module 11.4 KiB
Newer Older
<?php
/**
 * Implement hook_views_api().
 *
 * This one is used as the base to reduce errors when updating.
 */
  $path = drupal_get_path('module', 'date_views');
  $base = array(
    'file' => 'theme.inc',
    'path' => "$path/theme",
  );
  return array(
    'date_nav_title' => $base + array('variables' => array('granularity' => NULL, 'view' => NULL, 'link' => NULL, 'format' => NULL)),
    'date_vcalendar' => $base + array('variables' => array('events' => NULL, 'calname' => NULL)),
    'date_vevent' => $base + array('variables' => array('event' => NULL)),
    'date_valarm' => $base + array('variables' => array('alarm' => NULL)),
    'date_views_filter_form' => $base + array('template' => 'date-views-filter-form', 'render element' => 'form'),
    'date_calendar_day' => $base + array('variables' => array('date' => NULL)),

    'date_views_pager' => $base + array(
      'variables' => array('plugin' => NULL, 'input' => NULL),
      // Register a pattern so that it can work like all views templates.
      'pattern' => 'date_views_pager__',
      'template' => 'date-views-pager',
    ),
  );
}

function date_views_views_api() {
  return array(
    'api' => 3,
    'path' => drupal_get_path('module', 'date_views') . '/includes',
  );
}

/**
 * Wrapper function to make sure this function will always work.
 */
function date_views_views_fetch_fields($base, $type) {
  if (!module_exists('views')) {
    return array();
  }
  module_load_include('inc', 'views', 'includes/admin');
  return views_fetch_fields($base, $type);
}

/**
 * Implement hook_date_api_tables().
 */
function date_views_date_views_tables() {
  return array('node', 'comments', 'users', 'files');
}

/**
 * Implement hook_date_views_fields().
 *
 * All modules that create custom fields that use the
 * 'views_handler_field_date' handler can provide
 * additional information here about the type of
 * date they create so the date can be used by
 * the Date API views date argument and date filter.
 */
function date_views_date_views_fields($field) {
  $values = array(
    // The type of date: DATE_UNIX, DATE_ISO, DATE_DATETIME.
    'sql_type' => DATE_UNIX,
    // Timezone handling options: 'none', 'site', 'date', 'utc' .
    'tz_handling' => 'site',
    // Needed only for dates that use 'date' tz_handling.
    'timezone_field' => '',
    // Needed only for dates that use 'date' tz_handling.
    'offset_field' => '',
    // Array of "table.field" values for related fields that should be
    // loaded automatically in the Views SQL.
    'related_fields' => array(),
    // Granularity of this date field's db data.
    'granularity' => array('year', 'month', 'day', 'hour', 'minute', 'second'),
  );
  switch ($field) {
    case 'users.created':
    case 'users.access':
    case 'users.login':
    case 'node.created':
    case 'node.changed':
    case 'node_revisions.timestamp':
    case 'files.timestamp':
    case 'node_counter.timestamp':
    case 'accesslog.timestamp':
    case 'comments.timestamp':
    case 'node_comment_statistics.last_comment_timestamp':
/**
 * A version of date_real_url that formats links correctly for the new Date pager.
 */
function date_pager_url($view, $date_type = NULL, $date_arg = NULL, $force_view_url = FALSE, $absolute = TRUE) {
  $args = $view->args;
  $pos = $view->date_info->date_arg_pos;

  // The View arguments array is indexed numerically but is not necessarily
  // in numerical order. Sort the arguments to ensure the correct order.
  ksort($args);

  // If there are empty arguments before the date argument,
  // pad them with the wildcard so the date argument will be in
  // the right position.
  if (count($args) < $pos) {
    foreach ($view->argument as $name => $argument) {
      if ($argument->position == $pos) {
        break;
      }
      $args[] = $argument->options['exception']['value'];
  }

  if (!empty($date_type)) {
    switch ($date_type) {
      case 'year':
        $args[$pos] = date_pad($view->date_info->year, 4);
        break;
      case 'week':
        $args[$pos] = date_pad($view->date_info->year, 4) . '-W' . date_pad($view->date_info->week);
        break;
      case 'day':
        $args[$pos] = date_pad($view->date_info->year, 4) . '-' . date_pad($view->date_info->month) . '-' . date_pad($view->date_info->day);
        break;
      default:
        $args[$pos] = date_pad($view->date_info->year, 4) . '-' . date_pad($view->date_info->month);
        break;
  }
  elseif (!empty($date_arg)) {
    $args[$pos] = $date_arg;
  }
  else {
    $args = $view->args;
  }
  // Is this an embedded or a block view?
  // Return the pager query value.
  if (!$force_view_url &&
  (!empty($view->preview) || !empty($view->date_info->block_identifier))) {

    $url = $args[$pos];
    $key = date_block_identifier($view);
    if (!empty($key)) {
        'query' => date_views_querystring($view, array($key => $url)),
  // Normal views may need querystrings appended to them
  // if they use exposed filters.
  return url($view->get_url($args), array(
    'query' => date_views_querystring($view),
function date_block_identifier($view) {
  if (!empty($view->block_identifier)) {
    return $view->block_identifier;
  }
  return isset($view->date_info->block_identifier) ? $view->date_info->block_identifier : NULL;
}

/**
 * Implements hook_field_views_data_alter().
 *
 * Create a Views field for each date column we care about
 * to supplement the generic 'entity_id' and 'revision_id'
 * fields that are automatically created.
 *
 * Also use friendlier labels to distinguish the start date
 * and end date in listings (for fields that use both).
function date_views_field_views_data_alter(&$result, $field, $module) {
    $has_end_date = !empty($field['settings']['todate']);
    if ($has_end_date) {
      $labels = field_views_field_label($field['field_name']);
      $label = array_shift($labels);
    }
    foreach ($result as $table => $data) {
      $additional = array();
      foreach ($data as $column => $value) {
        // The old 'entity_id' and 'revision_id' values got rewritten in Views.
        // The old values are still there with a 'moved to' key, so ignore them.
        if (array_key_exists('field', $value) && !array_key_exists('moved to', $value['field'])) {
          $result[$table][$column]['field']['is date'] = TRUE;
          // Not sure yet if we still need a custom field handler in D7 now that custom formatters are available.
          // Might still need it to handle grouping of multiple value dates.
          //$result[$table][$column]['field']['handler'] = 'date_handler_field_date';
          //$result[$table][$column]['field']['add fields to query'] = TRUE;
        }

        // For filters, arguments, and sorts, determine if this column is for
        // the start date ('value') or the end date ('value2').
        $this_column = NULL;
        foreach (array_keys($field['columns']) as $candidate_column) {
          if ($column == $field['field_name'] . '_' . $candidate_column) {
            $this_column = $candidate_column;
            break;
          }
        }

        // Only alter the date fields, not timezone, rrule, offset, etc.
        if ($this_column != 'value' && $this_column != 'value2') {
          continue;
        }

        // We will replace the label with a friendlier name in the case of
        // arguments, filters, and sorts (but only if this field uses an end
        // date).
        $replace_label = FALSE;
        if (array_key_exists('argument', $value)) {
          $result[$table][$column]['argument']['handler'] = 'date_views_argument_handler_simple';
          $result[$table][$column]['argument']['empty field name'] = t('Undated');
          $result[$table][$column]['argument']['is date'] = TRUE;
        if (array_key_exists('filter', $value)) {
          $result[$table][$column]['filter']['handler'] = 'date_views_filter_handler_simple';
          $result[$table][$column]['filter']['empty field name'] = t('Undated');
          $result[$table][$column]['filter']['is date'] = TRUE;
        if (array_key_exists('sort', $value)) {
          $result[$table][$column]['sort']['is date'] = TRUE;
          $replace_label = $has_end_date;
        }
        if ($replace_label) {
          // Determine if this column is for the start date ('value') or the
          // end date ('value2').
          $this_column = NULL;
          foreach (array_keys($field['columns']) as $candidate_column) {
            if ($column == $field['field_name'] . '_' . $candidate_column) {
              $this_column = $candidate_column;
              break;
            }
          }
          // Insert the phrase "start date" or "end date" after the label, so
          // users can distinguish them in listings (compared to the default
          // behavior of field_views_field_default_views_data(), which only
          // uses the 'value2' column name to distinguish them).
          switch ($this_column) {
            case 'value':
              // Insert a deliberate double space before 'start date' in the
              // translatable string. This is a hack to get it to appear right
              // before 'end date' in the listing (i.e., in a non-alphabetical,
              // but more user friendly, order).
              $result[$table][$column]['title'] = t('@label -  start date (!name)', array('@label' => $label, '!name' => $field['field_name']));
              $result[$table][$column]['title short'] = t('@label -  start date', array('@label' => $label));
              break;
            case 'value2':
              $result[$table][$column]['title'] = t('@label - end date (!name:!column)', array('@label' => $label, '!name' => $field['field_name'], '!column' => $this_column));
              $result[$table][$column]['title short'] = t('@label - end date:!column', array('@label' => $label, '!column' => $this_column));
              break;
          }
/**
 * Implements hook_form_FORM_ID_alter().
 */
function date_views_form_views_ui_edit_form_alter(&$form, &$form_state) {
  // This CSS is needed for the configuration form provided by the Date filter
  // (date_views_filter_handler_simple), but we have to add it here so that
  // it's already on the edit form the first time a Date filter is being added
  // to the View. See http://drupal.org/node/1239228#comment-4885288.
  $form['#attached']['css'][] = drupal_get_path('module', 'date_views') . '/css/date_views.css';
}

 * The instanceof function makes this work for any handler that was derived
 * from 'views_handler_filter_date' or 'views_handler_argument_date',
 * which includes core date fields like the node updated field.
 *
 * The test for $handler->min_date tells us that this is an argument that
 * not only is derived from the views date handler but also has been processed
 * by the Date Views filter or argument code.
*/
function date_views_handler_is_date($handler, $type = 'argument') {
  switch ($type) {
    case 'filter':
      return $handler instanceof views_handler_filter_date && !empty($handler->min_date);
      return $handler instanceof views_handler_argument_date && !empty($handler->min_date);