You are here

public function date_ical_plugin_row_ical_fields::render in Date iCal 7.3

Same name and namespace in other branches
  1. 7.2 includes/date_ical_plugin_row_ical_fields.inc \date_ical_plugin_row_ical_fields::render()

Returns an Event array row in the query with index: $row->index.

Overrides views_plugin_row::render

File

includes/date_ical_plugin_row_ical_fields.inc, line 117
Defines the iCal Fields row style plugin, which lets users map view fields to the components of the VEVENTs in the iCal feed.

Class

date_ical_plugin_row_ical_fields
A Views plugin which builds an iCal VEVENT from a views row with Fields.

Code

public function render($row) {
  $date_field_name = $this->options['date_field'];

  // If this view is set to use the first populated date field, check each
  // field in the row to find the first non-NULL Date field.
  if ($date_field_name == 'first_available') {
    foreach (get_object_vars($row) as $name => $value) {
      if (strpos($name, 'field_field') === 0) {

        // This property's name starts with "field_field", which means it's
        // the actual field data for a field in this view.
        if (!empty($value[0]['raw']['date_type'])) {

          // Cut off the first "field_" from $name to get the field name.
          $date_field_name = substr($name, 6);
          break;
        }
      }
    }
  }

  // Fetch the event's date information.
  try {
    if ($date_field_name == 'first_available') {

      // If $date_field_name is still 'first_available' at this point, we
      // couldn't find an available Date value. Processing cannot proceed.
      $title = strip_tags($this->view->style_plugin
        ->get_field($row->index, $this->options['title_field']));
      if (empty($title)) {
        $title = "Undetermined title";
      }
      throw new BlankDateFieldException(t('The row titled "@title" has no available Date value. An iCal entry cannot be created for it.', array(
        '@title' => $title,
      )));
    }
    $date = $this
      ->get_row_date($row, $date_field_name);
  } catch (BlankDateFieldException $e) {

    // Unless the user has specifically said that they want to skip rows
    // with blank dates, let this exception percolate.
    if ($this->options['additional_settings']['skip_blank_dates']) {
      return NULL;
    }
    else {
      throw $e;
    }
  }

  // Create the event by starting with the date array from this row.
  $event = $date;
  $entity = $row->_field_data[$this->view->base_field]['entity'];
  $entity_type = $row->_field_data[$this->view->base_field]['entity_type'];

  // Add the CREATED, LAST-MODIFIED, and URL components based on the entity.
  // According to the iCal standard, CREATED and LAST-MODIFIED must be UTC.
  // Fortunately, Drupal stores timestamps in the DB as UTC, so we just need
  // to specify that UTC be used rather than the server's local timezone.
  if (isset($entity->created)) {
    $event['created'] = new DateObject($entity->created, 'UTC');
  }
  if (isset($entity->changed)) {
    $event['last-modified'] = new DateObject($entity->changed, 'UTC');
  }
  elseif (isset($entity->created)) {

    // If changed is unset, but created is, use that for last-modified.
    $event['last-modified'] = new DateObject($entity->created, 'UTC');
  }
  $uri = entity_uri($entity_type, $entity);
  $uri['options']['absolute'] = TRUE;
  $event['url'] = url($uri['path'], $uri['options']);

  // Generate a unique ID for this event by emulating the way the Date module
  // creates a Date ID.
  $is_relationaship = FALSE;
  $date_field_delta = 0;
  if (isset($row->{"field_data_{$date_field_name}_delta"})) {
    $date_field_delta = $row->{"field_data_{$date_field_name}_delta"};
  }
  else {
    if (!empty($entity->{$date_field_name})) {

      // I'm not sure why the "field_data_{field_name}_delta" field is part of
      // the $row, so it's possible that it will sometimes be missing. If it
      // is, make an educated guess about the delta by comparing this row's
      // start date to each of the entity's dates.
      if (!empty($entity->{$date_field_name}['und'])) {
        foreach ($entity->{$date_field_name}['und'] as $ndx => $date_array) {
          if ($date['start']->originalTime == $date_array['value']) {
            $date_field_delta = $ndx;
            break;
          }
        }
      }
    }
    else {
      if (!empty($this->display->display_options['fields'][$date_field_name]['relationship'])) {

        // This block covers another potential situation where
        // "field_data_{field_name}_delta" is missing: dates gathered through a
        // relationship. We retrieve the name of the relationship through which
        // the date field is being gathered, and the delta of that relationship,
        // in case it's multi-delta.
        $rel_name = $this->display->display_options['fields'][$date_field_name]['relationship'];
        $rel_delta = $row->index;
        $is_relationaship = TRUE;
      }
      else {

        // We couldn't obtain enough info to determine the real $date_field_delta.
        // So we just leave it as 0. Hopefully this won't cause problems.
      }
    }
  }
  $entity_id = $row->{$this->view->base_field};
  global $base_url;
  $domain = preg_replace('#^https?://#', '', $base_url);
  if (!$is_relationaship) {
    $event['uid'] = "calendar.{$entity_id}.{$date_field_name}.{$date_field_delta}@{$domain}";
  }
  else {
    $event['uid'] = "calendar.{$entity_id}.{$rel_name}.{$rel_delta}.{$date_field_name}.{$date_field_delta}@{$domain}";
  }

  // Because of the way that Date implements repeating dates, we're going to
  // be given a separate view result for each repeat. We only want to
  // render a VEVENT (with an RRULE) for the first instance of that date, so
  // we need to record the entity ID and field name for each result that has
  // an RRULE, then skip any that we've already seen.
  if (!empty($date['rrule'])) {
    $repeat_id = "{$entity_id}.{$date_field_name}";
    if (!isset($this->repeated_dates[$repeat_id])) {
      $this->repeated_dates[$repeat_id] = $repeat_id;
    }
    else {
      return FALSE;
    }
  }

  // Retrieve the rendered text fields.
  $text_fields['summary'] = $this
    ->get_field($row->index, $this->options['title_field']);
  $text_fields['description'] = $this
    ->get_field($row->index, $this->options['description_field']);
  $text_fields['location'] = $this
    ->get_field($row->index, $this->options['location_field']);
  $text_fields['categories'] = $this
    ->get_field($row->index, $this->options['categories_field']);

  // Allow other modules to alter the rendered text fields before they get
  // sanitized for iCal-compliance. This is most useful for fields of type
  // "Content: Rendered Node", which are likely to have complex HTML.
  $context = array(
    'row' => $row,
    'row_index' => $row->index,
    'language' => $this->language,
    'options' => $this->options,
  );
  drupal_alter('date_ical_export_html', $text_fields, $this->view, $context);

  // Sanitize the text fields for iCal compliance, and add them to the event.
  $event['summary'] = date_ical_sanitize_text($text_fields['summary']);
  $event['location'] = date_ical_sanitize_text($text_fields['location']);
  $event['description'] = date_ical_sanitize_text($text_fields['description']);
  $event['categories'] = date_ical_sanitize_text($text_fields['categories']);

  // Allow other modules to alter the event object before it gets passed to
  // the style plugin to be converted into an iCal VEVENT.
  drupal_alter('date_ical_export_raw_event', $event, $this->view, $context);
  return $event;
}