Projet

Général

Profil

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

root / drupal7 / sites / all / modules / date / date_views / date_views.module @ 74f6bef0

1
<?php
2

    
3
/**
4
 * Implements hook_views_api().
5
 *
6
 * This one is used as the base to reduce errors when updating.
7
 */
8
function date_views_theme() {
9
  $path = drupal_get_path('module', 'date_views');
10
  $base = array(
11
    'file' => 'theme.inc',
12
    'path' => "$path/theme",
13
  );
14
  return array(
15
    'date_nav_title' => $base + array('variables' => array('granularity' => NULL, 'view' => NULL, 'link' => NULL, 'format' => NULL)),
16
    'date_views_filter_form' => $base + array('template' => 'date-views-filter-form', 'render element' => 'form'),
17
    'date_calendar_day' => $base + array('variables' => array('date' => NULL)),
18

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

    
28
function date_views_views_api() {
29
  return array(
30
    'api' => 3,
31
    'path' => drupal_get_path('module', 'date_views') . '/includes',
32
  );
33
}
34

    
35
/**
36
 * Wrapper function to make sure this function will always work.
37
 */
38
function date_views_views_fetch_fields($base, $type) {
39
  if (!module_exists('views')) {
40
    return array();
41
  }
42
  module_load_include('inc', 'views', 'includes/admin');
43
  return views_fetch_fields($base, $type);
44
}
45

    
46
/**
47
 *  Identify all potential date/timestamp fields and cache the data.
48
 */
49
function date_views_fields($base = 'node', $reset = FALSE) {
50
  static $fields = array();
51
  $empty = array('name' => array(), 'alias' => array());
52
  module_load_include('inc', 'date_views', 'includes/date_views_fields');
53

    
54
  if (empty($fields[$base]) || $reset) {
55
    $cid = 'date_views_fields_' . $base;
56
    if (!$reset && $cached = cache_get($cid, 'cache_views')) {
57
      $fields[$base] = $cached->data;
58
    }
59
    else {
60
      $fields[$base] = _date_views_fields($base);
61
    }
62
  }
63
  // Make sure that empty values will be arrays in he expected format.
64
  return !empty($fields) && !empty($fields[$base]) ? $fields[$base] : $empty;
65
}
66

    
67
/**
68
 * Implements hook_date_views_entities().
69
 * Map extra Views tables to the entity that holds its date fields,
70
 * needed for Views tables other than the primary tables identified in entity_info().
71
 */
72
function date_views_date_views_extra_tables() {
73
  return array(
74
    'node_revision' => 'node',
75
  );
76
}
77

    
78
/**
79
 * Helper function to map entity types to the Views base table they use,
80
 * to make it easier to infer the entity type from a base table.
81
 *
82
 * Views has a new handler called views_handler_field_entity() that loads
83
 * entities, and you can use something like the following to get the
84
 * entity type from a view, but not all our base tables contain the
85
 * entity information we need, (i.e. revisions) so it won't work here
86
 * and we resort to creating information from entity_get_info().
87
 *
88
 *   // A method to get the entity type for a base table.
89
 *   $table_data = views_fetch_data($base_table);
90
 *   if (!isset($table_data['table']['base']['entity type'])) {
91
 *     return FALSE;
92
 *   }
93
 *   $entity_type = $table_data['table']['base']['entity type'];
94
 */
95
function date_views_base_tables() {
96
  $base_tables = &drupal_static(__FILE__, array());
97

    
98
  if (empty($base_tables)) {
99

    
100
    // First we get the base tables we can learn about from entity_info.
101
    $entity_info = entity_get_info();
102
    foreach ($entity_info as $entity_type => $info) {
103
      if (!empty($info['base table'])) {
104
        $base_tables[$info['base table']] = $entity_type;
105
      }
106
      if (!empty($info['revision table'])) {
107
        $base_tables[$info['revision table']] = $entity_type;
108
      }
109
    }
110

    
111
    // Then we let other modules tell us about other entity tables that hold date fields.
112
    $base_tables += module_invoke_all('date_views_extra_tables');
113
  }
114

    
115
  return $base_tables;
116
}
117

    
118
/**
119
 * Implements hook_date_views_fields().
120
 *
121
 * All modules that create custom fields that use the
122
 * 'views_handler_field_date' handler can provide
123
 * additional information here about the type of
124
 * date they create so the date can be used by
125
 * the Date API views date argument and date filter.
126
 */
127
function date_views_date_views_fields($field) {
128
  $values = array(
129
    // The type of date: DATE_UNIX, DATE_ISO, DATE_DATETIME.
130
    'sql_type' => DATE_UNIX,
131
    // Timezone handling options: 'none', 'site', 'date', 'utc' .
132
    'tz_handling' => 'site',
133
    // Needed only for dates that use 'date' tz_handling.
134
    'timezone_field' => '',
135
    // Needed only for dates that use 'date' tz_handling.
136
    'offset_field' => '',
137
    // Array of "table.field" values for related fields that should be
138
    // loaded automatically in the Views SQL.
139
    'related_fields' => array(),
140
    // Granularity of this date field's db data.
141
    'granularity' => array('year', 'month', 'day', 'hour', 'minute', 'second'),
142
  );
143

    
144
  switch ($field) {
145
    case 'users.created':
146
    case 'users.access':
147
    case 'users.login':
148
    case 'node.created':
149
    case 'node.changed':
150
    case 'node_revision.timestamp':
151
    case 'file_managed.timestamp':
152
    case 'comment.timestamp':
153
      return $values;
154
  }
155
}
156

    
157
/**
158
 * A version of date_real_url that formats links correctly for the new Date pager.
159
 */
160
function date_pager_url($view, $date_type = NULL, $date_arg = NULL, $force_view_url = FALSE, $absolute = TRUE) {
161

    
162
  // If someone adds a pager without a matching argument, there is not date information to work with.
163
  if (empty($view->date_info) || !isset($view->date_info->date_arg_pos)) {
164
    return '';
165
  }
166

    
167
  $args = $view->args;
168
  $pos = $view->date_info->date_arg_pos;
169

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

    
174
  // If there are empty arguments before the date argument,
175
  // pad them with the wildcard so the date argument will be in
176
  // the right position.
177
  if (count($args) < $pos) {
178
    foreach ($view->argument as $name => $argument) {
179
      if ($argument->position == $pos) {
180
        break;
181
      }
182
      $args[] = $argument->options['exception']['value'];
183
    }
184
  }
185

    
186
  if (!empty($date_type)) {
187
    switch ($date_type) {
188
      case 'year':
189
        $args[$pos] = date_pad($view->date_info->year, 4);
190
        break;
191
      case 'week':
192
        $args[$pos] = date_pad($view->date_info->year, 4) . '-W' . date_pad($view->date_info->week);
193
        break;
194
      case 'day':
195
        $args[$pos] = date_pad($view->date_info->year, 4) . '-' . date_pad($view->date_info->month) . '-' . date_pad($view->date_info->day);
196
        break;
197
      default:
198
        $args[$pos] = date_pad($view->date_info->year, 4) . '-' . date_pad($view->date_info->month);
199
        break;
200
    }
201
  }
202
  elseif (!empty($date_arg)) {
203
    $args[$pos] = $date_arg;
204
  }
205
  else {
206
    $args = $view->args;
207
  }
208
  // Is this an embedded or a block view?
209
  // Return the pager query value.
210
  if (!$force_view_url &&
211
  (!empty($view->preview) || !empty($view->date_info->block_identifier))) {
212

    
213
    $url = $args[$pos];
214
    $key = date_block_identifier($view);
215
    if (!empty($key)) {
216
      return url($_GET['q'], array(
217
        'query' => date_views_querystring($view, array($key => $url)),
218
        'absolute' => $absolute));
219
    }
220
  }
221

    
222
  // Normal views may need querystrings appended to them
223
  // if they use exposed filters.
224
  return url($view->get_url($args), array(
225
    'query' => date_views_querystring($view),
226
    'absolute' => $absolute));
227
}
228

    
229
function date_block_identifier($view) {
230
  if (!empty($view->block_identifier)) {
231
    return $view->block_identifier;
232
  }
233
  return isset($view->date_info->block_identifier) ? $view->date_info->block_identifier : NULL;
234
}
235

    
236
/**
237
 * Implements hook_field_views_data_alter().
238
 *
239
 * Create a Views field for each date column we care about
240
 * to supplement the generic 'entity_id' and 'revision_id'
241
 * fields that are automatically created.
242
 *
243
 * Also use friendlier labels to distinguish the start date
244
 * and end date in listings (for fields that use both).
245
 */
246
function date_views_field_views_data_alter(&$result, $field, $module) {
247
  if ($module == 'date') {
248
    $has_end_date = !empty($field['settings']['todate']);
249
    if ($has_end_date) {
250
      $labels = field_views_field_label($field['field_name']);
251
      $label = array_shift($labels);
252
    }
253
    foreach ($result as $table => $data) {
254
      $additional = array();
255
      $field_name = $field['field_name'];
256
      foreach ($data as $column => $value) {
257

    
258
        // The old 'entity_id' and 'revision_id' values got rewritten in Views.
259
        // The old values are still there with a 'moved to' key, so ignore them.
260
        if (array_key_exists('field', $value) && !array_key_exists('moved to', $value['field'])) {
261
          $result[$table][$column]['field']['is date'] = TRUE;
262
          // Not sure yet if we still need a custom field handler in D7 now that custom formatters are available.
263
          // Might still need it to handle grouping of multiple value dates.
264
          //$result[$table][$column]['field']['handler'] = 'date_handler_field_date';
265
          //$result[$table][$column]['field']['add fields to query'] = TRUE;
266
        }
267

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

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

    
283
        // We will replace the label with a friendlier name in the case of
284
        // arguments, filters, and sorts (but only if this field uses an end
285
        // date).
286
        $replace_label = FALSE;
287
        if (array_key_exists('argument', $value)) {
288
          $result[$table][$column]['argument']['handler'] = 'date_views_argument_handler_simple';
289
          $result[$table][$column]['argument']['empty field name'] = t('Undated');
290
          $result[$table][$column]['argument']['is date'] = TRUE;
291
          $replace_label = $has_end_date;
292
        }
293
        if (array_key_exists('filter', $value)) {
294
          $result[$table][$column]['filter']['handler'] = 'date_views_filter_handler_simple';
295
          $result[$table][$column]['filter']['empty field name'] = t('Undated');
296
          $result[$table][$column]['filter']['is date'] = TRUE;
297
          $replace_label = $has_end_date;
298
        }
299
        if (array_key_exists('sort', $value)) {
300
          $result[$table][$column]['sort']['is date'] = TRUE;
301
          $replace_label = $has_end_date;
302
        }
303
        if ($replace_label) {
304
          // Determine if this column is for the start date ('value') or the
305
          // end date ('value2').
306
          $this_column = NULL;
307
          foreach (array_keys($field['columns']) as $candidate_column) {
308
            if ($column == $field['field_name'] . '_' . $candidate_column) {
309
              $this_column = $candidate_column;
310
              break;
311
            }
312
          }
313
          // Insert the phrase "start date" or "end date" after the label, so
314
          // users can distinguish them in listings (compared to the default
315
          // behavior of field_views_field_default_views_data(), which only
316
          // uses the 'value2' column name to distinguish them).
317
          switch ($this_column) {
318
            case 'value':
319
              // Insert a deliberate double space before 'start date' in the
320
              // translatable string. This is a hack to get it to appear right
321
              // before 'end date' in the listing (i.e., in a non-alphabetical,
322
              // but more user friendly, order).
323
              $result[$table][$column]['title'] = t('@label -  start date (!name)', array('@label' => $label, '!name' => $field['field_name']));
324
              $result[$table][$column]['title short'] = t('@label -  start date', array('@label' => $label));
325
              break;
326
            case 'value2':
327
              $result[$table][$column]['title'] = t('@label - end date (!name:!column)', array('@label' => $label, '!name' => $field['field_name'], '!column' => $this_column));
328
              $result[$table][$column]['title short'] = t('@label - end date:!column', array('@label' => $label, '!column' => $this_column));
329
              break;
330
          }
331
        }
332
      }
333
    }
334
  }
335
}
336

    
337
/**
338
 * Implements hook_form_FORM_ID_alter() for views_ui_edit_form().
339
 */
340
function date_views_form_views_ui_edit_form_alter(&$form, &$form_state, $form_id) {
341
  // This CSS is needed for the configuration form provided by the Date filter
342
  // (date_views_filter_handler_simple), but we have to add it here so that
343
  // it's already on the edit form the first time a Date filter is being added
344
  // to the View. See http://drupal.org/node/1239228#comment-4885288.
345
  $form['#attached']['css'][] = drupal_get_path('module', 'date_views') . '/css/date_views.css';
346
}
347

    
348
/**
349
 * The instanceof function makes this work for any handler that was derived
350
 * from 'views_handler_filter_date' or 'views_handler_argument_date',
351
 * which includes core date fields like the node updated field.
352
 *
353
 * The test for $handler->min_date tells us that this is an argument that
354
 * not only is derived from the views date handler but also has been processed
355
 * by the Date Views filter or argument code.
356
*/
357
function date_views_handler_is_date($handler, $type = 'argument') {
358
  switch ($type) {
359
    case 'filter':
360
      return $handler instanceof views_handler_filter_date && !empty($handler->min_date);
361
    case 'argument':
362
      return $handler instanceof views_handler_argument_date && !empty($handler->min_date);
363
  }
364
  return FALSE;
365
}
366

    
367
/**
368
 * Validation hook for exposed filters that use the select widget.
369
 * This is to ensure the the user completes all parts of the date
370
 * not just some parts. Only needed for the select widget.
371
 */
372
function date_views_select_validate(&$form, &$form_state) {
373
  // If there are no values just return.
374
  if (empty($form['value']) && empty($form['min'])) {
375
    return;
376
  }
377
  $granularity = (!empty($form['min']['#date_format'])) ? date_format_order($form['min']['#date_format']) : date_format_order($form['value']['#date_format']);
378
  $filled = array();
379
  $value = drupal_array_get_nested_value($form_state['input'], $form['#parents']);
380
  foreach ($granularity as $part) {
381
    if (!empty($value['value'][$part])) {
382
      $filled[] = $part;
383
    }
384
  }
385
  if (!empty($filled) && count($filled) != count($granularity)) {
386
    $unfilled = array_diff($granularity, $filled);
387
    foreach ($unfilled as $part) {
388
      switch ($part) {
389
        case 'year':
390
          form_error($form['value'][$part], t('Please choose a year.'), $form_state);
391
          break;
392
        case 'month':
393
          form_error($form['value'][$part], t('Please choose a month.'), $form_state);
394
          break;
395
        case 'day':
396
          form_error($form['value'][$part], t('Please choose a day.'), $form_state);
397
          break;
398
        case 'hour':
399
          form_error($form['value'][$part], t('Please choose an hour.'), $form_state);
400
          break;
401
        case 'minute':
402
          form_error($form['value'][$part], t('Please choose a minute.'), $form_state);
403
          break;
404
        case 'second':
405
          form_error($form['value'][$part], t('Please choose a second.'), $form_state);
406
          break;
407
      }
408
    }
409
  }
410
}
411

    
412
/**
413
 * Implements hook_date_formatter_view_alter().
414
 *
415
 * If we are displaying a date from a view, see if we have information about
416
 * which multiple value to display. If so, set the date_id in the entity.
417
 */
418
function date_views_date_formatter_pre_view_alter(&$entity, &$variables) {
419
  // Some views have no row index.
420
  if (!empty($entity->view) && isset($entity->view->row_index)) {
421
    $field = $variables['field'];
422
    $date_id = 'date_id_' . $field['field_name'];
423
    $date_delta = 'date_delta_' . $field['field_name'];
424
    $date_item = $entity->view->result[$entity->view->row_index];
425
    if (!empty($date_item->$date_id)) {
426
      $entity->date_id = 'date.' . $date_item->$date_id . '.' . $field['field_name'] . '.' . $date_item->$date_delta . '.0';
427
    }
428
  }
429
}