Projet

Général

Profil

Paste
Télécharger (15,9 ko) Statistiques
| Branche: | Révision:

root / drupal7 / sites / all / modules / date_ical / includes / date_ical_plugin_row_ical_entity.inc @ 651307cd

1 85ad3d82 Assos Assos
<?php
2
3
/**
4
 * @file
5
 * Contains the iCal row style plugin.
6
 */
7
8
/**
9 8a7e43dd Florent Torregrosa
 * A Views plugin which builds an iCal VEVENT from a single node.
10 85ad3d82 Assos Assos
 */
11
class date_ical_plugin_row_ical_entity extends views_plugin_row {
12 204e4d33 Assos Assos
13 85ad3d82 Assos Assos
  // Basic properties that let the row style follow relationships.
14 8a7e43dd Florent Torregrosa
  protected $base_table = 'node';
15
  protected $base_field = 'nid';
16 204e4d33 Assos Assos
17 85ad3d82 Assos Assos
  // Stores the nodes loaded with pre_render.
18 8a7e43dd Florent Torregrosa
  protected $entities = array();
19 204e4d33 Assos Assos
20 8a7e43dd Florent Torregrosa
  /**
21
   * Initialize the row plugin.
22
   */
23
  public function init(&$view, &$display, $options = NULL) {
24 85ad3d82 Assos Assos
    parent::init($view, $display, $options);
25
    $this->base_table = $view->base_table;
26
    $this->base_field = $view->base_field;
27
  }
28 204e4d33 Assos Assos
29 8a7e43dd Florent Torregrosa
  /**
30
   * Set up the options for the row plugin.
31
   */
32
  public function option_definition() {
33 85ad3d82 Assos Assos
    $options = parent::option_definition();
34
    $options['date_field'] = array('default' => array());
35
    $options['summary_field'] = array('default' => array());
36
    $options['location_field'] = array('default' => array());
37
    return $options;
38
  }
39 204e4d33 Assos Assos
40 85ad3d82 Assos Assos
  /**
41 8a7e43dd Florent Torregrosa
   * Build the form for setting the row plugin's options.
42 85ad3d82 Assos Assos
   */
43 8a7e43dd Florent Torregrosa
  public function options_form(&$form, &$form_state) {
44 85ad3d82 Assos Assos
    parent::options_form($form, $form_state);
45 204e4d33 Assos Assos
46 8a7e43dd Florent Torregrosa
    // Build the select dropdown for the Date field that the user wants to use
47
    // to populate the date properties in VEVENTs.
48 85ad3d82 Assos Assos
    $data = date_views_fields($this->base_table);
49
    $options = array();
50
    foreach ($data['name'] as $item => $value) {
51 8a7e43dd Florent Torregrosa
      // We only want to see one value for each field, so we need to
52
      // skip '_value2' and other columns.
53 85ad3d82 Assos Assos
      if ($item == $value['fromto'][0]) {
54
        $options[$item] = $value['label'];
55
      }
56
    }
57
    $form['date_field'] = array(
58
      '#type' => 'select',
59
      '#title' => t('Date field'),
60
      '#options' => $options,
61
      '#default_value' => $this->options['date_field'],
62
      '#description' => t('Please identify the field to use as the iCal date for each item in this view.
63
          Add a Date Filter or a Date Argument to the view to limit results to content in a specified date range.'),
64
      '#required' => TRUE,
65
    );
66
    $form['instructions'] = array(
67 8a7e43dd Florent Torregrosa
      // The surrounding <div> ensures that the settings dialog expands.
68 85ad3d82 Assos Assos
      '#prefix' => '<div style="font-size: 90%">',
69
      '#suffix' => '</div>',
70 c7b88c87 Assos Assos
      '#markup' => t("Each item's Title will be the SUMMARY and the rendered iCal view mode will be the DESCRIPTION in the VEVENTs output by this View.
71 85ad3d82 Assos Assos
        <br>To change the iCal view mode, configure it on the 'Manage Display' page for each Content Type.
72 c7b88c87 Assos Assos
        Please note that all HTML will be stripped from the output, to comply with iCal standards."),
73 85ad3d82 Assos Assos
    );
74 204e4d33 Assos Assos
75 85ad3d82 Assos Assos
    // Build the select dropdown for the text/node_reference field that the user
76
    // wants to use to (optionally) populate the SUMMARY.
77
    $summary_fields = date_ical_get_summary_fields($this->base_table);
78
    $summary_options = array('default_title' => t('- Default Title -'));
79
    foreach ($summary_fields['name'] as $item => $value) {
80
      $summary_options[$item] = $value['label'];
81
    }
82
    $form['summary_field'] = array(
83
      '#type' => 'select',
84
      '#title' => t('SUMMARY field'),
85
      '#options' => $summary_options,
86
      '#default_value' => $this->options['summary_field'],
87
      '#description' => t('You may optionally change the SUMMARY component for each event in the iCal output.
88
        Choose which text, taxonomy term reference or Node Reference field you would like to be output as the SUMMARY.
89
        If using a Node Reference, the Title of the referenced node will be used.'),
90
    );
91 204e4d33 Assos Assos
92 85ad3d82 Assos Assos
    // Build the select dropdown for the text/node_reference field that the user
93
    // wants to use to (optionally) populate the LOCATION.
94
    $location_fields = date_ical_get_location_fields($this->base_table);
95
    $location_options = array('none' => t('- None -'));
96
    foreach ($location_fields['name'] as $item => $value) {
97
      $location_options[$item] = $value['label'];
98
    }
99
    $form['location_field'] = array(
100
      '#type' => 'select',
101
      '#title' => t('LOCATION field'),
102
      '#options' => $location_options,
103
      '#default_value' => $this->options['location_field'],
104
      '#description' => t('You may optionally include a LOCATION component for each event in the iCal output.
105
        Choose which text or Node Reference field you would like to be output as the LOCATION.
106
        If using a Node Reference, the Title of the referenced node will be used.'),
107
    );
108
  }
109 204e4d33 Assos Assos
110 8a7e43dd Florent Torregrosa
  /**
111
   * Preload the list of entities which will appear in the view.
112
   *
113
   * TODO: When the date is coming in through a relationship, the nid
114
   * of the view is not the right node to use: we need the related node.
115
   * Need to sort out how that should be handled.
116
   */
117
  public function pre_render($values) {
118 85ad3d82 Assos Assos
    // Preload each entity used in this view from the cache.
119
    // Provides all the entity values relatively cheaply, and we don't
120
    // need to do it repeatedly for the same entity if there are
121
    // multiple results for one entity.
122
    $ids = array();
123
    foreach ($values as $row) {
124 8a7e43dd Florent Torregrosa
      // Use the $id as the key so we create only value per entity.
125 85ad3d82 Assos Assos
      $id = $row->{$this->field_alias};
126 204e4d33 Assos Assos
127 85ad3d82 Assos Assos
      // Node revisions need special loading.
128
      if ($this->view->base_table == 'node_revision') {
129
        $this->entities[$id] = node_load(NULL, $id);
130
      }
131
      // For other entities we just create an array of ids to pass
132
      // to entity_load().
133
      else {
134
        $ids[$id] = $id;
135
      }
136
    }
137 204e4d33 Assos Assos
138 85ad3d82 Assos Assos
    $base_tables = date_views_base_tables();
139
    $this->entity_type = $base_tables[$this->view->base_table];
140
    if (!empty($ids)) {
141
      $this->entities = entity_load($this->entity_type, $ids);
142
    }
143 204e4d33 Assos Assos
144 85ad3d82 Assos Assos
    // Get the language for this view.
145
    $this->language = $this->display->handler->get_option('field_language');
146
    $substitutions = views_views_query_substitutions($this->view);
147
    if (array_key_exists($this->language, $substitutions)) {
148
      $this->language = $substitutions[$this->language];
149
    }
150
  }
151 204e4d33 Assos Assos
152 8a7e43dd Florent Torregrosa
  /**
153
   * Renders the entities returned by the view into event arrays.
154
   */
155
  public function render($row) {
156 85ad3d82 Assos Assos
    $id = $row->{$this->field_alias};
157
    if (!is_numeric($id)) {
158
      return NULL;
159
    }
160 204e4d33 Assos Assos
161 85ad3d82 Assos Assos
    // Load the specified entity:
162
    $entity = $this->entities[$id];
163
    if (empty($entity)) {
164
      // This can happen when an RRULE is involved.
165
      return NULL;
166
    }
167 204e4d33 Assos Assos
168 85ad3d82 Assos Assos
    $date_fields = date_views_fields($this->base_table);
169
    $date_info = $date_fields['name'][$this->options['date_field']];
170
    $field_name  = str_replace(array('_value', '_value2'), '', $date_info['real_field_name']);
171
    $delta_field = $date_info['delta_field'];
172
    $is_field    = $date_info['is_field'];
173 204e4d33 Assos Assos
174 8a7e43dd Florent Torregrosa
    // Sometimes the timestamp is actually the revision timestamp.
175 85ad3d82 Assos Assos
    if ($this->view->base_table == 'node_revision' && $field_name == 'timestamp') {
176
      $field_name = 'revision_timestamp';
177
    }
178 204e4d33 Assos Assos
179 85ad3d82 Assos Assos
    if (!isset($entity->$field_name)) {
180
      // This entity doesn't have the date property that the user configured
181 8a7e43dd Florent Torregrosa
      // our view to use. We can't do anything with it.
182 85ad3d82 Assos Assos
      return NULL;
183
    }
184
    $date_field = $entity->$field_name;
185 204e4d33 Assos Assos
186 85ad3d82 Assos Assos
    // Pull the date value from the specified field of the entity.
187
    $entity->date_id = array();
188
    $start = NULL;
189
    $end   = NULL;
190
    $delta = isset($row->$delta_field) ? $row->$delta_field : 0;
191
    if ($is_field) {
192
      $items = field_get_items($this->entity_type, $entity, $field_name);
193
      if (!$items) {
194
        // This entity doesn't have data in the date field that the user
195
        // configured our view to use. We can't do anything with it.
196
        return;
197
      }
198
      $date_field = $items[$delta];
199 8a7e43dd Florent Torregrosa
      global $base_url;
200
      $domain = preg_replace('#^https?://#', '', $base_url);
201 85ad3d82 Assos Assos
      $entity->date_id[] = "calendar.$id.$field_name.$delta@$domain";
202 204e4d33 Assos Assos
203 85ad3d82 Assos Assos
      if (!empty($date_field['value'])) {
204
        $start = new DateObject($date_field['value'], $date_field['timezone_db']);
205 8a7e43dd Florent Torregrosa
        if (!empty($date_field['value2'])) {
206 85ad3d82 Assos Assos
          $end = new DateObject($date_field['value2'], $date_field['timezone_db']);
207
        }
208
        else {
209
          $end = clone $start;
210
        }
211
      }
212
    }
213
    elseif (!$is_field && !empty($date_field)) {
214
      $start = new DateObject($date_field, $date_field['timezone_db']);
215
      $end   = new DateObject($date_field, $date_field['timezone_db']);
216
    }
217 204e4d33 Assos Assos
218 85ad3d82 Assos Assos
    // Set the item date to the proper display timezone.
219 8a7e43dd Florent Torregrosa
    $start->setTimezone(new DateTimeZone($date_field['timezone']));
220
    $end->setTimezone(new DateTimeZone($date_field['timezone']));
221 204e4d33 Assos Assos
222 85ad3d82 Assos Assos
    // Check if the start and end dates indicate that this is an All Day event.
223
    $all_day = date_is_all_day(
224
      date_format($start, DATE_FORMAT_DATETIME),
225
      date_format($end, DATE_FORMAT_DATETIME),
226
      date_granularity_precision($date_info['granularity'])
227
    );
228 204e4d33 Assos Assos
229 85ad3d82 Assos Assos
    if ($all_day) {
230
      // According to RFC 2445 (clarified in RFC 5545) the DTEND value is
231
      // non-inclusive. When dealing with All Day values, they're DATEs rather
232
      // than DATETIMEs, so we need to add a day to conform to RFC.
233
      $end->modify("+1 day");
234
    }
235 204e4d33 Assos Assos
236 85ad3d82 Assos Assos
    // If the user specified a LOCATION field, pull that data from the entity.
237
    $location = '';
238
    if (!empty($this->options['location_field']) && $this->options['location_field'] != 'none') {
239
      $location_fields = date_ical_get_location_fields($this->base_table);
240
      $location_info = $location_fields['name'][$this->options['location_field']];
241
      $location_field_name = $location_info['real_field_name'];
242 204e4d33 Assos Assos
243 85ad3d82 Assos Assos
      // Only attempt this is the entity actually has this field.
244
      $items = field_get_items($this->entity_type, $entity, $location_field_name);
245
      if ($items) {
246
        $location_field = $items[0];
247
        if ($location_info['type'] == 'node_reference') {
248
          // Make sure this Node Reference actually references a node.
249
          if ($location_field['nid']) {
250
            $node = node_load($location_field['nid']);
251 ca0757b9 Assos Assos
            $location = $node->title;
252 85ad3d82 Assos Assos
          }
253
        }
254
        elseif ($location_info['type'] == 'addressfield') {
255
          $locations = array();
256 204e4d33 Assos Assos
          // Get full country name
257
          if (!empty($location_field['country'])) {
258
            require_once DRUPAL_ROOT . '/includes/locale.inc';
259
            $countries = country_get_list();
260
            $location_field['country'] = $countries[$location_field['country']];
261
          }
262 8a7e43dd Florent Torregrosa
          foreach ($location_field as $key => $loc) {
263 85ad3d82 Assos Assos
            if ($loc && !in_array($key, array('first_name', 'last_name'))) {
264
              $locations[] = $loc;
265
            }
266
          }
267
          $location = implode(', ', array_reverse($locations));
268
        }
269 8a7e43dd Florent Torregrosa
        elseif ($location_info['type'] == 'location') {
270
          $included_fields = array(
271
            'name',
272
            'additional',
273
            'street',
274
            'city',
275
            'province_name',
276
            'postal_code',
277
            'country_name'
278
          );
279
          $location_data = array();
280
          foreach ($included_fields as $included_field) {
281
            if (!empty($location_field[$included_field])) {
282
              $location_data[] = $location_field[$included_field];
283
            }
284
          }
285 ca0757b9 Assos Assos
          $location = implode(', ', $location_data);
286 8a7e43dd Florent Torregrosa
        }
287 d756b39a Assos Assos
        elseif ($location_info['type'] == 'node_reference') {
288
        // Make sure this Node Reference actually references a node.
289
          if ($location_field['nid']) {
290
            $node = node_load($location_field['nid']);
291
            $location = $node->title;
292
          }
293
        }
294
        elseif ($location_info['type'] == 'taxonomy_term_reference') {
295
          $terms = taxonomy_term_load_multiple(array_column($items,'tid'));
296
          // Make sure that there are terms that were loaded.
297
          if ($terms) {
298
            $term_names = array();
299
            foreach ($terms as $term) {
300
              $term_names[] = $term->name;
301
            }
302
            $location = implode(', ', $term_names);
303
          }
304
        }
305 85ad3d82 Assos Assos
        else {
306 ca0757b9 Assos Assos
          $location = $location_field['value'];
307 85ad3d82 Assos Assos
        }
308
      }
309
    }
310 204e4d33 Assos Assos
311 8a7e43dd Florent Torregrosa
    // Create the rendered event using the display settings from the
312
    // iCal view mode.
313 85ad3d82 Assos Assos
    $rendered_array = entity_view($this->entity_type, array($entity), 'ical', $this->language, TRUE);
314
    $data = array(
315
      'description' => drupal_render($rendered_array),
316 8a7e43dd Florent Torregrosa
      'summary' => entity_label($this->entity_type, $entity),
317 85ad3d82 Assos Assos
    );
318
    if (!empty($this->options['summary_field']) && $this->options['summary_field'] != 'default_title') {
319
      $summary_fields = date_ical_get_summary_fields();
320
      $summary_info = $summary_fields['name'][$this->options['summary_field']];
321
      $summary_field_name = $summary_info['real_field_name'];
322
      // Only attempt this is the entity actually has this field.
323
      $items = field_get_items($this->entity_type, $entity, $summary_field_name);
324
      $summary = '';
325
      if ($items) {
326
        $summary_field = $items[0];
327
        if ($summary_info['type'] == 'node_reference') {
328
          // Make sure this Node Reference actually references a node.
329
          if ($summary_field['nid']) {
330
            $node = node_load($summary_field['nid']);
331
            $summary = $node->title;
332
          }
333
        }
334
        elseif ($summary_info['type'] == 'taxonomy_term_reference') {
335 d756b39a Assos Assos
          $terms = taxonomy_term_load_multiple(array_column($items,'tid'));
336 8a7e43dd Florent Torregrosa
          // Make sure that there are terms that were loaded.
337 85ad3d82 Assos Assos
          if ($terms) {
338
            $term_names = array();
339
            foreach ($terms as $term) {
340
              $term_names[] = $term->name;
341
            }
342
            $summary = implode(', ', $term_names);
343
          }
344
        }
345
        else {
346
          $summary = trim($summary_field['value']);
347
        }
348 8a7e43dd Florent Torregrosa
        $data['summary'] = $summary ? $summary : $data['summary'];
349 85ad3d82 Assos Assos
      }
350
    }
351
    // Allow other modules to alter the HTML of the Summary and Description,
352
    // before it gets converted to iCal-compliant plaintext. This allows users
353
    // to set up a newline between fields, for instance.
354
    $context = array(
355
      'entity' => $entity,
356
      'entity_type' => $this->entity_type,
357
      'language' => $this->language,
358
    );
359 8a7e43dd Florent Torregrosa
    drupal_alter('date_ical_export_html', $data, $this->view, $context);
360 204e4d33 Assos Assos
361 85ad3d82 Assos Assos
    $event = array();
362
    $event['summary'] = date_ical_sanitize_text($data['summary']);
363
    $event['description'] = date_ical_sanitize_text($data['description']);
364
    $event['all_day'] = $all_day;
365
    $event['start'] = $start;
366
    $event['end'] = $end;
367
    $uri = entity_uri($this->entity_type, $entity);
368
    $uri['options']['absolute'] = TRUE;
369
    $event['url'] = url($uri['path'], $uri['options']);
370 204e4d33 Assos Assos
    if ($is_field && !empty($date_field['rrule'])) {
371
      $event['rrule'] = $date_field['rrule'];
372
    }
373 85ad3d82 Assos Assos
    if ($location) {
374 ca0757b9 Assos Assos
      $event['location'] = date_ical_sanitize_text($location);
375 85ad3d82 Assos Assos
    }
376 204e4d33 Assos Assos
377 8a7e43dd Florent Torregrosa
    // For this event's UID, use either the date_id generated by the Date
378
    // module, or the event page's URL if the date_id isn't available.
379 85ad3d82 Assos Assos
    $event['uid'] = !empty($entity->date_id) ? $entity->date_id[0] : $event['url'];
380 204e4d33 Assos Assos
381 85ad3d82 Assos Assos
    // If we are using a repeat rule (and not just multi-day events) we
382
    // remove the item from the entities list so that its VEVENT won't be
383
    // re-created.
384 204e4d33 Assos Assos
    if (!empty($event['rrule'])) {
385 85ad3d82 Assos Assos
      $this->entities[$id] = NULL;
386
    }
387 204e4d33 Assos Assos
388 85ad3d82 Assos Assos
    // According to the iCal standard, CREATED and LAST-MODIFIED must be UTC.
389
    // Fortunately, Drupal stores timestamps in the DB as UTC, so we just need
390 8a7e43dd Florent Torregrosa
    // to tell DateObject to treat the timestamp as UTC from the start.
391 85ad3d82 Assos Assos
    if (isset($entity->created)) {
392 8a7e43dd Florent Torregrosa
      $event['created'] = new DateObject($entity->created, 'UTC');
393 85ad3d82 Assos Assos
    }
394
    // Pull the 'changed' date from the entity (if available), so that
395
    // subscription clients can tell if the event has been updated.
396
    if (isset($entity->changed)) {
397 8a7e43dd Florent Torregrosa
      $event['last-modified'] = new DateObject($entity->changed, 'UTC');
398 85ad3d82 Assos Assos
    }
399 8a7e43dd Florent Torregrosa
    elseif (isset($entity->created)) {
400 85ad3d82 Assos Assos
      // If changed is unset, but created is, use that for last-modified.
401 8a7e43dd Florent Torregrosa
      $event['last-modified'] = new DateObject($entity->created, 'UTC');
402 85ad3d82 Assos Assos
    }
403 204e4d33 Assos Assos
404 85ad3d82 Assos Assos
    // Allow other modules to alter the structured event object, before it gets
405 8a7e43dd Florent Torregrosa
    // passed to the style plugin to be converted into an iCalcreator vevent.
406
    drupal_alter('date_ical_export_raw_event', $event, $this->view, $context);
407 204e4d33 Assos Assos
408 85ad3d82 Assos Assos
    return $event;
409
  }
410
}