You are here

function calendar_build_nodes in Calendar 7.2

Same name and namespace in other branches
  1. 5.2 calendar.inc \calendar_build_nodes()
  2. 6.2 calendar.module \calendar_build_nodes()
  3. 7 calendar.module \calendar_build_nodes()

Take the array of items and alter it to an array of calendar nodes that the theme can handle.

Iterate through each datefield in the view and each item returned by the query, and create pseudo date nodes.

If there is more than one date field in the node, this will create multiple nodes, one each with the right calendar date for that field's value. If a field value has a date range that covers more than one day, separate nodes will be created for each day in the field's day range, limited to the minimum and maximum dates for the view.

When we finish, we will have a distinct node for each distinct day and date field.

3 calls to calendar_build_nodes()
calendar_plugin_style_ical::render in calendar_ical/calendar_plugin_style_ical.inc
Render the display in this style.
template_preprocess_calendar in theme/theme.inc
Display a view as a calendar.
template_preprocess_calendar in calendar_multiday/theme/theme.inc
Display a view as a calendar.

File

./calendar.module, line 570
Adds calendar filtering and displays to Views.

Code

function calendar_build_nodes(&$view, &$items) {
  if (empty($view->date_info->min_date) || empty($view->date_info->max_date)) {
    return $items;
  }

  // Midnights are determined based on the same timezone as the View uses
  $display_timezone = date_timezone_get($view->date_info->min_date);
  $display_timezone_name = timezone_name_get($display_timezone);

  // Translate the view min and max dates to UTC values
  // so we can compare UTC dates to the view range.
  $min_utc = clone $view->date_info->min_date;
  date_timezone_set($min_utc, timezone_open('UTC'));
  $max_utc = clone $view->date_info->max_date;
  date_timezone_set($max_utc, timezone_open('UTC'));
  $min_zone_string = array();

  // Will cache $min_utc-strings in various timezones
  $max_zone_string = array();
  $view->date_info->nodes_per_page = 0;
  $type_names = node_type_get_names();
  $datefields = array();
  $fields = date_views_fields();
  foreach ($view->filter as $id => $handler) {
    if (date_views_handler_is_date($handler, 'filter')) {
      $date_filter = $handler;
      foreach ($handler->options['date_fields'] as $name) {
        $datefields[] = $fields['name'][$name]['query_name'];
      }
    }
  }
  foreach ($view->argument as $id => $handler) {
    if (date_views_handler_is_date($handler, 'argument')) {
      $date_filter = $handler;
      foreach ($handler->options['date_fields'] as $name) {
        $datefields[] = $fields['name'][$name]['query_name'];
      }
    }
  }
  $view_fields = date_views_views_fetch_fields('node', 'field');
  $field_names = (array) array_keys($fields['name']);
  $nodes = array();
  $i = 0;
  foreach ($date_filter->options['date_fields'] as $name) {
    $field = $fields['name'][$name];
    $field_type = strstr($field['type'], 'string') ? 'string' : 'timestamp';
    $alias = $field['query_name'];
    $field_name = $field['field_name'];
    $fromto = $field['fromto'];
    $tz_handling = $field['tz_handling'];
    $label = isset($view->field[$name]) ? $view->field[$name]['label'] : $field['field_name'];
    $tz_alias = str_replace('.', '_', $field['timezone_field']);
    $db_tz = date_get_timezone_db($field['tz_handling']);
    $local_tz = date_get_timezone($field['tz_handling'], 'date');
    $field_name = $field['field_name'];
    $real_field = $field['real_field_name'];

    // If there is no field for this item, just default to the site format.
    if (!isset($view->field[$field_name])) {
      $format = variable_get('date_format_short', 'm/d/Y - H:i');
    }
    else {
      if (strstr($field['type'], 'cck')) {
        $formatter = $view->field[$field_name]->options['type'];
        $format = date_formatter_format($formatter, $view->field[$field_name]->options['type']);
      }
      else {
        $format = $view->field[$field_name]->options['date_format'];
        switch ($format) {
          case 'long':
            $format = variable_get('date_format_long', 'l, F j, Y - H:i');
            break;
          case 'medium':
            $format = variable_get('date_format_medium', 'D, m/d/Y - H:i');
            break;
          case 'custom':
            $format = $view->field[$field_name]->options['custom_date_format'];
            break;
          case 'time ago':
            break;
          default:
            $format = variable_get('date_format_short', 'm/d/Y - H:i');
            break;
        }
      }
    }

    // set the domain part of the id
    $domain = check_plain($_SERVER['SERVER_NAME']);

    // If there are multiple date fields in this calendar we may get
    // duplicate items from the other date fields, so add a way to
    // make sure each individual date field only gets added to the
    // calendar one time.
    $processed = array();
    $rrule_processed = array();
    foreach ($items as $pos => $item) {
      $delta = !empty($field['delta_field']) && !empty($item->raw->{$field['delta_field']}) ? $item->raw->{$field['delta_field']} : 0;
      $id = 'calendar.' . $item->id . '.' . $real_field . '.' . $delta;

      // When creating iCal feeds for repeating dates we don't want all
      // the multiple values, send only the first value.
      if (strstr($view->current_display, '_ical')) {
        if (!isset($rrule_processed[$item->id])) {
          $rrule_processed[$item->id] = TRUE;
        }
        else {
          continue;
        }
      }
      if (!in_array($id, $processed) && isset($item->calendar_fields->{$alias})) {

        // Create from and to date values for each item, adjusted to
        // the correct timezone.
        $from = str_replace('.', '_', $fromto[0]);
        $to = str_replace('.', '_', $fromto[1]);
        $values[0] = $item->calendar_fields->{$from};
        $values[1] = $item->calendar_fields->{$to};
        $db_tz = date_get_timezone_db($tz_handling, isset($item->{$tz_alias}) ? $item->{$tz_alias} : $display_timezone_name);
        $to_zone = date_get_timezone($tz_handling, isset($item->{$tz_alias}) ? $item->{$tz_alias} : $display_timezone_name);

        // Now $display_timezone determines how $item is split into
        // one entry per day, while $to_zone determines how date is displayed.
        // For now, use the date fields's timezone for the day splitting.
        $display_timezone_name = $to_zone;
        $values_display = array();

        // Start date
        $date = new DateObject($values[0], $db_tz);
        if ($db_tz != $to_zone) {
          date_timezone_set($date, timezone_open($to_zone));
        }
        $values[0] = date_format($date, DATE_FORMAT_DATETIME);
        if ($display_timezone_name != $to_zone) {
          date_timezone_set($date, $display_timezone);
          $values_display[0] = date_format($date, DATE_FORMAT_DATETIME);
        }
        else {
          $values_display[0] = $values[0];
        }

        // End date
        $date = new DateObject($values[1], $db_tz);
        if ($db_tz != $to_zone) {
          date_timezone_set($date, timezone_open($to_zone));
        }
        $values[1] = date_format($date, DATE_FORMAT_DATETIME);
        if ($display_timezone_name != $to_zone) {
          date_timezone_set($date, $display_timezone);
          $values_display[1] = date_format($date, DATE_FORMAT_DATETIME);
        }
        else {
          $values_display[1] = $values[1];
        }

        // Now $values contain start and end date of a node,
        // expressed as strings in the display (local) timezone.
        // $values_utc does the same in UTC timezone.
        // Get calendar min and max day (not time) as strings in the
        // $display_timezone. Cache in $min_zone_string and $max_zone_string,
        // since many items or fields typically use the samee timezone.
        if (!isset($min_zone_string[$display_timezone_name])) {
          $date = clone $view->date_info->min_date;
          date_timezone_set($date, $display_timezone);
          $min_zone_string[$display_timezone_name] = date_format($date, DATE_FORMAT_DATE);
          $date = clone $view->date_info->max_date;
          date_timezone_set($date, $display_timezone);
          $max_zone_string[$display_timezone_name] = date_format($date, DATE_FORMAT_DATE);
        }

        // Create a node for each date within the field's date range,
        // limited to the view's date range (regarding only day, not time).
        $now = max($min_zone_string[$display_timezone_name], substr($values_display[0], 0, 10));
        $to = min($max_zone_string[$display_timezone_name], substr($values_display[1], 0, 10));
        $next = new DateObject($now, $display_timezone);
        if ($display_timezone_name != $to_zone) {

          // Make $start and $end (derived from $node) use the timezone $to_zone, just as $values[..] do
          date_timezone_set($next, timezone_open($to_zone));
        }
        if (empty($to) || $now > $to) {
          $to = $now;
        }
        if ($now) {

          // $now and $next are midnight (in display timezone) on the first day where node will occur.
          // $to is midnight on the last day where node will occur.
          // All three were limited by the min-max date range of the view.
          while ($now <= $to) {
            $node = clone $item;

            // Make sure the pseudo node has the same properties a
            // regular node would have.
            if (isset($node->node_title) && !isset($node->title)) {
              $node->title = $node->node_title;
            }
            if (isset($node->node_type) && !isset($node->type)) {
              $node->type = $node->node_type;
            }
            $exceptions = array(
              'format_interval',
              'time ago',
            );
            $node->label = $label;
            $node->format = $format;
            if (!in_array($node->format, $exceptions)) {
              if (!isset($formats[$format])) {
                $formats[$format] = date_limit_format($format, array(
                  'hour',
                  'minute',
                  'second',
                ));
                $node->format_time = $formats[$format];
              }
            }
            else {
              $node->format_time = '';
            }
            $node->url = calendar_get_node_link($node);

            //$node->$fromto[0] = $values[0];

            //$node->$fromto[1] = $values[1];

            // Flag which datefield this node is using, in case
            // there are multiple date fields in the view.
            $node->datefield = $alias;

            // If there are other datefields in the View, get rid
            // of them in this pseudo node. There should only be one
            // date in each calendar node.
            foreach ($node as $key => $val) {
              if ($key != $alias && in_array($key, $datefields)) {
                unset($node->{$key});
                foreach ($fields['name'] as $other_fields) {

                  // If the unused date has other fields, unset them, too.
                  if ($other_fields['query_name'] == $key) {
                    foreach ($other_fields['related_fields'] as $related_field) {
                      $key2 = str_replace('.', '_', $related_field);
                      unset($node->{$key2});
                    }
                  }
                }
              }
            }

            // Get start and end of current day
            $start = date_format($next, DATE_FORMAT_DATETIME);
            date_modify($next, '+1 day');
            date_modify($next, '-1 second');
            $end = date_format($next, DATE_FORMAT_DATETIME);

            // Get intersection of current day and the node value's duration (as strings in $to_zone timezone)
            $node->calendar_start = $values[0] < $start ? $start : $values[0];
            $node->calendar_end = !empty($values[1]) ? $values[1] > $end ? $end : $values[1] : $node->calendar_start;
            $node->date_start = date_create($values[0], timezone_open($to_zone));
            $node->date_end = date_create(!empty($values[1]) ? $values[1] : $values[0], timezone_open($to_zone));

            // Actual start and end date as set in the node object
            $node->date_start = date_create($values[0], timezone_open($to_zone));
            $node->date_end = date_create(!empty($values[1]) ? $values[1] : $values[0], timezone_open($to_zone));

            // Make date objects
            $node->calendar_start_date = date_create($node->calendar_start, timezone_open($to_zone));
            $node->calendar_end_date = date_create($node->calendar_end, timezone_open($to_zone));

            // Change string timezones into
            // calendar_start and calendar_end are UTC dates as formatted strings
            $node->calendar_start = date_format($node->calendar_start_date, DATE_FORMAT_DATETIME);
            $node->calendar_end = date_format($node->calendar_end_date, DATE_FORMAT_DATETIME);

            // @TODO We can't assume we have information about an entity type.
            // Probably need to make the increment a field setting so we can access it.
            $granularity = 'second';
            $increment = 1;
            if (substr($real_field, 0, 6) == 'field_') {
              $cck_field = field_info_field($real_field);

              //$instance = field_info_instance($view->base_table, $real_field, $node->type);
              $granularity = $cck_field['settings']['granularity'];

              //$increment = $instance['widget']['settings']['increment'];
            }
            $node->calendar_all_day = date_is_all_day($node->calendar_start, $node->calendar_end, $granularity, $increment);

            // Change string timezones into
            // calendar_start and calendar_end are UTC dates as formatted strings
            $node->calendar_start = date_format($node->calendar_start_date, DATE_FORMAT_DATETIME);
            $node->calendar_end = date_format($node->calendar_end_date, DATE_FORMAT_DATETIME);
            unset($node->calendar_fields);
            if (isset($node) && empty($node->calendar_start)) {

              // if no date for the node and no date in the item
              // there is no way to display it on the calendar
              unset($node);
            }
            else {
              calendar_node_stripe($view, $node, $alias, $alias);
              calendar_node_taxonomy_stripe($view, $node, $alias, $alias);
              calendar_node_group_stripe($view, $node, $alias, $alias);
              $node->date_id = $id . '.' . $pos;
              $nodes[] = $node;
              unset($node);
            }
            date_modify($next, '+1 second');
            $processed[] = $id;
            $now = date_format($next, DATE_FORMAT_DATE);
          }
        }
      }
    }
  }
  return $nodes;
}