Projet

Général

Profil

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

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

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
  
13
  // Basic properties that let the row style follow relationships.
14 8a7e43dd Florent Torregrosa
  protected $base_table = 'node';
15
  protected $base_field = 'nid';
16 85ad3d82 Assos Assos
  
17
  // Stores the nodes loaded with pre_render.
18 8a7e43dd Florent Torregrosa
  protected $entities = array();
19 85ad3d82 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
  
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
  
40
  /**
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
    
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
    
75
    // 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
    
92
    // 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
  
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
      
127
      // 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
    
138
    $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
    
144
    // 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
  
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
    
161
    // 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
    
168
    $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
    
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
    
179
    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
    
186
    // 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
      
203
      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
    
218
    // 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 85ad3d82 Assos Assos
    
222
    // 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
    
229
    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
    
236
    // 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
      
243
      // 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 8a7e43dd Florent Torregrosa
          foreach ($location_field as $key => $loc) {
257 85ad3d82 Assos Assos
            if ($loc && !in_array($key, array('first_name', 'last_name'))) {
258
              $locations[] = $loc;
259
            }
260
          }
261
          $location = implode(', ', array_reverse($locations));
262
        }
263 8a7e43dd Florent Torregrosa
        elseif ($location_info['type'] == 'location') {
264
          $included_fields = array(
265
            'name',
266
            'additional',
267
            'street',
268
            'city',
269
            'province_name',
270
            'postal_code',
271
            'country_name'
272
          );
273
          $location_data = array();
274
          foreach ($included_fields as $included_field) {
275
            if (!empty($location_field[$included_field])) {
276
              $location_data[] = $location_field[$included_field];
277
            }
278
          }
279 ca0757b9 Assos Assos
          $location = implode(', ', $location_data);
280 8a7e43dd Florent Torregrosa
        }
281 85ad3d82 Assos Assos
        else {
282 ca0757b9 Assos Assos
          $location = $location_field['value'];
283 85ad3d82 Assos Assos
        }
284
      }
285
    }
286
    
287 8a7e43dd Florent Torregrosa
    // Create the rendered event using the display settings from the
288
    // iCal view mode.
289 85ad3d82 Assos Assos
    $rendered_array = entity_view($this->entity_type, array($entity), 'ical', $this->language, TRUE);
290
    $data = array(
291
      'description' => drupal_render($rendered_array),
292 8a7e43dd Florent Torregrosa
      'summary' => entity_label($this->entity_type, $entity),
293 85ad3d82 Assos Assos
    );
294
    if (!empty($this->options['summary_field']) && $this->options['summary_field'] != 'default_title') {
295
      $summary_fields = date_ical_get_summary_fields();
296
      $summary_info = $summary_fields['name'][$this->options['summary_field']];
297
      $summary_field_name = $summary_info['real_field_name'];
298
      // Only attempt this is the entity actually has this field.
299
      $items = field_get_items($this->entity_type, $entity, $summary_field_name);
300
      $summary = '';
301
      if ($items) {
302
        $summary_field = $items[0];
303
        if ($summary_info['type'] == 'node_reference') {
304
          // Make sure this Node Reference actually references a node.
305
          if ($summary_field['nid']) {
306
            $node = node_load($summary_field['nid']);
307
            $summary = $node->title;
308
          }
309
        }
310
        elseif ($summary_info['type'] == 'taxonomy_term_reference') {
311
          $terms = taxonomy_term_load_multiple($items);
312 8a7e43dd Florent Torregrosa
          // Make sure that there are terms that were loaded.
313 85ad3d82 Assos Assos
          if ($terms) {
314
            $term_names = array();
315
            foreach ($terms as $term) {
316
              $term_names[] = $term->name;
317
            }
318
            $summary = implode(', ', $term_names);
319
          }
320
        }
321
        else {
322
          $summary = trim($summary_field['value']);
323
        }
324 8a7e43dd Florent Torregrosa
        $data['summary'] = $summary ? $summary : $data['summary'];
325 85ad3d82 Assos Assos
      }
326
    }
327
    // Allow other modules to alter the HTML of the Summary and Description,
328
    // before it gets converted to iCal-compliant plaintext. This allows users
329
    // to set up a newline between fields, for instance.
330
    $context = array(
331
      'entity' => $entity,
332
      'entity_type' => $this->entity_type,
333
      'language' => $this->language,
334
    );
335 8a7e43dd Florent Torregrosa
    drupal_alter('date_ical_export_html', $data, $this->view, $context);
336 85ad3d82 Assos Assos
    
337
    $event = array();
338
    $event['summary'] = date_ical_sanitize_text($data['summary']);
339
    $event['description'] = date_ical_sanitize_text($data['description']);
340
    $event['all_day'] = $all_day;
341
    $event['start'] = $start;
342
    $event['end'] = $end;
343
    $uri = entity_uri($this->entity_type, $entity);
344
    $uri['options']['absolute'] = TRUE;
345
    $event['url'] = url($uri['path'], $uri['options']);
346
    $event['rrule'] = $is_field && array_key_exists('rrule', $date_field) ? $date_field['rrule'] : '';
347
    if ($location) {
348 ca0757b9 Assos Assos
      $event['location'] = date_ical_sanitize_text($location);
349 85ad3d82 Assos Assos
    }
350
    
351 8a7e43dd Florent Torregrosa
    // For this event's UID, use either the date_id generated by the Date
352
    // module, or the event page's URL if the date_id isn't available.
353 85ad3d82 Assos Assos
    $event['uid'] = !empty($entity->date_id) ? $entity->date_id[0] : $event['url'];
354
    
355
    // If we are using a repeat rule (and not just multi-day events) we
356
    // remove the item from the entities list so that its VEVENT won't be
357
    // re-created.
358
    if ($event['rrule']) {
359
      $this->entities[$id] = NULL;
360
    }
361
    
362
    // According to the iCal standard, CREATED and LAST-MODIFIED must be UTC.
363
    // Fortunately, Drupal stores timestamps in the DB as UTC, so we just need
364 8a7e43dd Florent Torregrosa
    // to tell DateObject to treat the timestamp as UTC from the start.
365 85ad3d82 Assos Assos
    if (isset($entity->created)) {
366 8a7e43dd Florent Torregrosa
      $event['created'] = new DateObject($entity->created, 'UTC');
367 85ad3d82 Assos Assos
    }
368
    // Pull the 'changed' date from the entity (if available), so that
369
    // subscription clients can tell if the event has been updated.
370
    if (isset($entity->changed)) {
371 8a7e43dd Florent Torregrosa
      $event['last-modified'] = new DateObject($entity->changed, 'UTC');
372 85ad3d82 Assos Assos
    }
373 8a7e43dd Florent Torregrosa
    elseif (isset($entity->created)) {
374 85ad3d82 Assos Assos
      // If changed is unset, but created is, use that for last-modified.
375 8a7e43dd Florent Torregrosa
      $event['last-modified'] = new DateObject($entity->created, 'UTC');
376 85ad3d82 Assos Assos
    }
377
    
378
    // Allow other modules to alter the structured event object, before it gets
379 8a7e43dd Florent Torregrosa
    // passed to the style plugin to be converted into an iCalcreator vevent.
380
    drupal_alter('date_ical_export_raw_event', $event, $this->view, $context);
381 85ad3d82 Assos Assos
    
382
    return $event;
383
  }
384
}