Projet

Général

Profil

Paste
Télécharger (18,5 ko) Statistiques
| Branche: | Révision:

root / drupal7 / sites / all / modules / date / date_views / date_views.module @ db9ffd17

1
<?php
2

    
3

    
4
/**
5
 * Implements hook_menu().
6
 */
7
function date_views_menu() {
8
  // Used to import files from a local filesystem into Drupal.
9
  $items['admin/config/regional/date-time/date-views'] = array(
10
    'title' => 'Date views',
11
    'description' => 'Configure settings for date views.',
12
    'page callback' => 'drupal_get_form',
13
    'page arguments' => array('date_views_settings'),
14
    'access arguments' => array('administer site configuration '),
15
    'type' => MENU_LOCAL_TASK,
16
  );
17

    
18
  return $items;
19
}
20

    
21
/**
22
 * Form callback for date views settings.
23
 */
24
function date_views_settings($form, &$form_state) {
25

    
26
  $form['date_views_month_format_with_year'] = array(
27
    '#type' => 'textfield',
28
    '#title' => t('Date views month format with year'),
29
    '#size' => 10,
30
    '#default_value' => variable_get('date_views_month_format_with_year', 'F Y'),
31
    '#description' => t('Date views month format with year, default value : F Y'),
32
  );
33

    
34
  $form['date_views_month_format_without_year'] = array(
35
    '#type' => 'textfield',
36
    '#title' => t('Date views month format without year'),
37
    '#size' => 10,
38
    '#default_value' => variable_get('date_views_month_format_without_year', 'F'),
39
    '#description' => t('Date views month format without year, default value : F'),
40
  );
41

    
42
  $form['date_views_day_format_with_year'] = array(
43
    '#type' => 'textfield',
44
    '#title' => t('Date views day format with year'),
45
    '#size' => 10,
46
    '#default_value' => variable_get('date_views_day_format_with_year', 'l, F j, Y'),
47
    '#description' => t('Date views day format with year, default value : l, F j, Y'),
48
  );
49

    
50
  $form['date_views_day_format_without_year'] = array(
51
    '#type' => 'textfield',
52
    '#title' => t('Date views day format without year'),
53
    '#size' => 10,
54
    '#default_value' => variable_get('date_views_day_format_without_year', 'l, F j'),
55
    '#description' => t('Date views day format without year, default value : l, F j'),
56
  );
57

    
58
  $form['date_views_week_format_with_year'] = array(
59
    '#type' => 'textfield',
60
    '#title' => t('Date views week format with year'),
61
    '#size' => 10,
62
    '#default_value' => variable_get('date_views_week_format_with_year', 'F j, Y'),
63
    '#description' => t('Date views week format with year, default value : F j, Y'),
64
  );
65

    
66
  $form['date_views_week_format_without_year'] = array(
67
    '#type' => 'textfield',
68
    '#title' => t('Date views week format without year'),
69
    '#size' => 10,
70
    '#default_value' => variable_get('date_views_week_format_without_year', 'F j'),
71
    '#description' => t('Date views week format without year, default value : F j'),
72
  );
73

    
74
  return system_settings_form($form);
75

    
76
}
77

    
78
/**
79
 * Implements hook_views_api().
80
 *
81
 * This one is used as the base to reduce errors when updating.
82
 */
83
function date_views_theme() {
84
  $path = drupal_get_path('module', 'date_views');
85
  $base = array(
86
    'file' => 'theme.inc',
87
    'path' => "$path/theme",
88
  );
89
  return array(
90
    'date_nav_title' => $base + array('variables' => array('granularity' => NULL, 'view' => NULL, 'link' => NULL, 'format' => NULL)),
91
    'date_views_filter_form' => $base + array('template' => 'date-views-filter-form', 'render element' => 'form'),
92
    'date_calendar_day' => $base + array('variables' => array('date' => NULL)),
93

    
94
    'date_views_pager' => $base + array(
95
      'variables' => array('plugin' => NULL, 'input' => NULL),
96
      // Register a pattern so that it can work like all views templates.
97
      'pattern' => 'date_views_pager__',
98
      'template' => 'date-views-pager',
99
    ),
100
  );
101
}
102

    
103
function date_views_views_api() {
104
  return array(
105
    'api' => 3,
106
    'path' => drupal_get_path('module', 'date_views') . '/includes',
107
  );
108
}
109

    
110
/**
111
 * Wrapper function to make sure this function will always work.
112
 */
113
function date_views_views_fetch_fields($base, $type) {
114
  if (!module_exists('views')) {
115
    return array();
116
  }
117
  module_load_include('inc', 'views', 'includes/admin');
118
  return views_fetch_fields($base, $type);
119
}
120

    
121
/**
122
 *  Identify all potential date/timestamp fields and cache the data.
123
 */
124
function date_views_fields($base = 'node', $reset = FALSE) {
125
  static $fields = array();
126
  $empty = array('name' => array(), 'alias' => array());
127
  module_load_include('inc', 'date_views', 'includes/date_views_fields');
128

    
129
  if (empty($fields[$base]) || $reset) {
130
    $cid = 'date_views_fields_' . $base;
131
    if (!$reset && $cached = cache_get($cid, 'cache_views')) {
132
      $fields[$base] = $cached->data;
133
    }
134
    else {
135
      $fields[$base] = _date_views_fields($base);
136
    }
137
  }
138
  // Make sure that empty values will be arrays in he expected format.
139
  return !empty($fields) && !empty($fields[$base]) ? $fields[$base] : $empty;
140
}
141

    
142
/**
143
 * Implements hook_date_views_entities().
144
 * Map extra Views tables to the entity that holds its date fields,
145
 * needed for Views tables other than the primary tables identified in entity_info().
146
 */
147
function date_views_date_views_extra_tables() {
148
  return array(
149
    'node_revision' => 'node',
150
  );
151
}
152

    
153
/**
154
 * Helper function to map entity types to the Views base table they use,
155
 * to make it easier to infer the entity type from a base table.
156
 *
157
 * Views has a new handler called views_handler_field_entity() that loads
158
 * entities, and you can use something like the following to get the
159
 * entity type from a view, but not all our base tables contain the
160
 * entity information we need, (i.e. revisions) so it won't work here
161
 * and we resort to creating information from entity_get_info().
162
 *
163
 *   // A method to get the entity type for a base table.
164
 *   $table_data = views_fetch_data($base_table);
165
 *   if (!isset($table_data['table']['base']['entity type'])) {
166
 *     return FALSE;
167
 *   }
168
 *   $entity_type = $table_data['table']['base']['entity type'];
169
 */
170
function date_views_base_tables() {
171
  $base_tables = &drupal_static(__FILE__, array());
172

    
173
  if (empty($base_tables)) {
174

    
175
    // First we get the base tables we can learn about from entity_info.
176
    $entity_info = entity_get_info();
177
    foreach ($entity_info as $entity_type => $info) {
178
      if (!empty($info['base table'])) {
179
        $base_tables[$info['base table']] = $entity_type;
180
      }
181
      if (!empty($info['revision table'])) {
182
        $base_tables[$info['revision table']] = $entity_type;
183
      }
184
    }
185

    
186
    // Then we let other modules tell us about other entity tables that hold date fields.
187
    $base_tables += module_invoke_all('date_views_extra_tables');
188
  }
189

    
190
  return $base_tables;
191
}
192

    
193
/**
194
 * Implements hook_date_views_fields().
195
 *
196
 * All modules that create custom fields that use the
197
 * 'views_handler_field_date' handler can provide
198
 * additional information here about the type of
199
 * date they create so the date can be used by
200
 * the Date API views date argument and date filter.
201
 */
202
function date_views_date_views_fields($field) {
203
  $values = array(
204
    // The type of date: DATE_UNIX, DATE_ISO, DATE_DATETIME.
205
    'sql_type' => DATE_UNIX,
206
    // Timezone handling options: 'none', 'site', 'date', 'utc' .
207
    'tz_handling' => 'site',
208
    // Needed only for dates that use 'date' tz_handling.
209
    'timezone_field' => '',
210
    // Needed only for dates that use 'date' tz_handling.
211
    'offset_field' => '',
212
    // Array of "table.field" values for related fields that should be
213
    // loaded automatically in the Views SQL.
214
    'related_fields' => array(),
215
    // Granularity of this date field's db data.
216
    'granularity' => array('year', 'month', 'day', 'hour', 'minute', 'second'),
217
  );
218

    
219
  switch ($field) {
220
    case 'users.created':
221
    case 'users.access':
222
    case 'users.login':
223
    case 'node.created':
224
    case 'node.changed':
225
    case 'node_revision.timestamp':
226
    case 'file_managed.timestamp':
227
    case 'comment.timestamp':
228
      return $values;
229
  }
230
}
231

    
232
/**
233
 * A version of date_real_url that formats links correctly for the new Date pager.
234
 */
235
function date_pager_url($view, $date_type = NULL, $date_arg = NULL, $force_view_url = FALSE, $absolute = TRUE) {
236

    
237
  // If someone adds a pager without a matching argument, there is not date information to work with.
238
  if (empty($view->date_info) || !isset($view->date_info->date_arg_pos)) {
239
    return '';
240
  }
241

    
242
  $args = $view->args;
243
  $pos = $view->date_info->date_arg_pos;
244

    
245
  // The View arguments array is indexed numerically but is not necessarily
246
  // in numerical order. Sort the arguments to ensure the correct order.
247
  ksort($args);
248

    
249
  // If there are empty arguments before the date argument,
250
  // pad them with the wildcard so the date argument will be in
251
  // the right position.
252
  if (count($args) < $pos) {
253
    foreach ($view->argument as $name => $argument) {
254
      if ($argument->position == $pos) {
255
        break;
256
      }
257
      $args[] = $argument->options['exception']['value'];
258
    }
259
  }
260

    
261
  if (!empty($date_type)) {
262
    switch ($date_type) {
263
      case 'year':
264
        $args[$pos] = date_pad($view->date_info->year, 4);
265
        break;
266
      case 'week':
267
        $args[$pos] = date_pad($view->date_info->year, 4) . '-W' . date_pad($view->date_info->week);
268
        break;
269
      case 'day':
270
        $args[$pos] = date_pad($view->date_info->year, 4) . '-' . date_pad($view->date_info->month) . '-' . date_pad($view->date_info->day);
271
        break;
272
      default:
273
        $args[$pos] = date_pad($view->date_info->year, 4) . '-' . date_pad($view->date_info->month);
274
        break;
275
    }
276
  }
277
  elseif (!empty($date_arg)) {
278
    $args[$pos] = $date_arg;
279
  }
280
  else {
281
    $args = $view->args;
282
  }
283
  // Is this an embedded or a block view?
284
  // Return the pager query value.
285
  if (!$force_view_url &&
286
  (!empty($view->preview) || !empty($view->date_info->block_identifier))) {
287

    
288
    $url = $args[$pos];
289
    $key = date_block_identifier($view);
290
    if (!empty($key)) {
291
      return url($_GET['q'], array(
292
        'query' => date_views_querystring($view, array($key => $url)),
293
        'absolute' => $absolute));
294
    }
295
  }
296

    
297
  // Normal views may need querystrings appended to them
298
  // if they use exposed filters.
299
  return url($view->get_url($args), array(
300
    'query' => date_views_querystring($view),
301
    'absolute' => $absolute));
302
}
303

    
304
function date_block_identifier($view) {
305
  if (!empty($view->block_identifier)) {
306
    return $view->block_identifier;
307
  }
308
  return isset($view->date_info->block_identifier) ? $view->date_info->block_identifier : NULL;
309
}
310

    
311
/**
312
 * Implements hook_field_views_data_alter().
313
 *
314
 * Create a Views field for each date column we care about
315
 * to supplement the generic 'entity_id' and 'revision_id'
316
 * fields that are automatically created.
317
 *
318
 * Also use friendlier labels to distinguish the start date
319
 * and end date in listings (for fields that use both).
320
 */
321
function date_views_field_views_data_alter(&$result, $field, $module) {
322
  if ($module == 'date') {
323
    $has_end_date = !empty($field['settings']['todate']);
324
    if ($has_end_date) {
325
      $labels = field_views_field_label($field['field_name']);
326
      $label = array_shift($labels);
327
    }
328
    foreach ($result as $table => $data) {
329
      $additional = array();
330
      $field_name = $field['field_name'];
331
      foreach ($data as $column => $value) {
332

    
333
        // The old 'entity_id' and 'revision_id' values got rewritten in Views.
334
        // The old values are still there with a 'moved to' key, so ignore them.
335
        if (array_key_exists('field', $value) && !array_key_exists('moved to', $value['field'])) {
336
          $result[$table][$column]['field']['is date'] = TRUE;
337
          // Not sure yet if we still need a custom field handler in D7 now that custom formatters are available.
338
          // Might still need it to handle grouping of multiple value dates.
339
          //$result[$table][$column]['field']['handler'] = 'date_handler_field_date';
340
          //$result[$table][$column]['field']['add fields to query'] = TRUE;
341
        }
342

    
343
        // For filters, arguments, and sorts, determine if this column is for
344
        // the start date ('value') or the end date ('value2').
345
        $this_column = NULL;
346
        foreach (array_keys($field['columns']) as $candidate_column) {
347
          if ($column == $field['field_name'] . '_' . $candidate_column) {
348
            $this_column = $candidate_column;
349
            break;
350
          }
351
        }
352

    
353
        // Only alter the date fields, not timezone, rrule, offset, etc.
354
        if ($this_column != 'value' && $this_column != 'value2') {
355
          continue;
356
        }
357

    
358
        // We will replace the label with a friendlier name in the case of
359
        // arguments, filters, and sorts (but only if this field uses an end
360
        // date).
361
        $replace_label = FALSE;
362
        if (array_key_exists('argument', $value)) {
363
          $result[$table][$column]['argument']['handler'] = 'date_views_argument_handler_simple';
364
          $result[$table][$column]['argument']['empty field name'] = t('Undated');
365
          $result[$table][$column]['argument']['is date'] = TRUE;
366
          $replace_label = $has_end_date;
367
        }
368
        if (array_key_exists('filter', $value)) {
369
          $result[$table][$column]['filter']['handler'] = 'date_views_filter_handler_simple';
370
          $result[$table][$column]['filter']['empty field name'] = t('Undated');
371
          $result[$table][$column]['filter']['is date'] = TRUE;
372
          $replace_label = $has_end_date;
373
        }
374
        if (array_key_exists('sort', $value)) {
375
          $result[$table][$column]['sort']['is date'] = TRUE;
376
          $replace_label = $has_end_date;
377
        }
378
        if ($replace_label) {
379
          // Determine if this column is for the start date ('value') or the
380
          // end date ('value2').
381
          $this_column = NULL;
382
          foreach (array_keys($field['columns']) as $candidate_column) {
383
            if ($column == $field['field_name'] . '_' . $candidate_column) {
384
              $this_column = $candidate_column;
385
              break;
386
            }
387
          }
388
          // Insert the phrase "start date" or "end date" after the label, so
389
          // users can distinguish them in listings (compared to the default
390
          // behavior of field_views_field_default_views_data(), which only
391
          // uses the 'value2' column name to distinguish them).
392
          switch ($this_column) {
393
            case 'value':
394
              // Insert a deliberate double space before 'start date' in the
395
              // translatable string. This is a hack to get it to appear right
396
              // before 'end date' in the listing (i.e., in a non-alphabetical,
397
              // but more user friendly, order).
398
              $result[$table][$column]['title'] = t('@label -  start date (!name)', array('@label' => $label, '!name' => $field['field_name']));
399
              $result[$table][$column]['title short'] = t('@label -  start date', array('@label' => $label));
400
              break;
401
            case 'value2':
402
              $result[$table][$column]['title'] = t('@label - end date (!name:!column)', array('@label' => $label, '!name' => $field['field_name'], '!column' => $this_column));
403
              $result[$table][$column]['title short'] = t('@label - end date:!column', array('@label' => $label, '!column' => $this_column));
404
              break;
405
          }
406
        }
407
      }
408
    }
409
  }
410
}
411

    
412
/**
413
 * Implements hook_form_FORM_ID_alter() for views_ui_edit_form().
414
 */
415
function date_views_form_views_ui_edit_form_alter(&$form, &$form_state, $form_id) {
416
  // This CSS is needed for the configuration form provided by the Date filter
417
  // (date_views_filter_handler_simple), but we have to add it here so that
418
  // it's already on the edit form the first time a Date filter is being added
419
  // to the View. See http://drupal.org/node/1239228#comment-4885288.
420
  $form['#attached']['css'][] = drupal_get_path('module', 'date_views') . '/css/date_views.css';
421
}
422

    
423
/**
424
 * The instanceof function makes this work for any handler that was derived
425
 * from 'views_handler_filter_date' or 'views_handler_argument_date',
426
 * which includes core date fields like the node updated field.
427
 *
428
 * The test for $handler->min_date tells us that this is an argument that
429
 * not only is derived from the views date handler but also has been processed
430
 * by the Date Views filter or argument code.
431
*/
432
function date_views_handler_is_date($handler, $type = 'argument') {
433
  switch ($type) {
434
    case 'filter':
435
      return $handler instanceof views_handler_filter_date && !empty($handler->min_date);
436
    case 'argument':
437
      return $handler instanceof views_handler_argument_date && !empty($handler->min_date);
438
  }
439
  return FALSE;
440
}
441

    
442
/**
443
 * Validation hook for exposed filters that use the select widget.
444
 * This is to ensure the the user completes all parts of the date
445
 * not just some parts. Only needed for the select widget.
446
 */
447
function date_views_select_validate(&$form, &$form_state) {
448
  // If there are no values just return.
449
  if (empty($form['value']) && empty($form['min'])) {
450
    return;
451
  }
452
  $granularity = (!empty($form['min']['#date_format'])) ? date_format_order($form['min']['#date_format']) : date_format_order($form['value']['#date_format']);
453
  $filled = array();
454
  $value = drupal_array_get_nested_value($form_state['input'], $form['#parents']);
455
  foreach ($granularity as $part) {
456
    if (!empty($value['value'][$part])) {
457
      $filled[] = $part;
458
    }
459
  }
460
  if (!empty($filled) && count($filled) != count($granularity)) {
461
    $unfilled = array_diff($granularity, $filled);
462
    foreach ($unfilled as $part) {
463
      switch ($part) {
464
        case 'year':
465
          form_error($form['value'][$part], t('Please choose a year.'), $form_state);
466
          break;
467
        case 'month':
468
          form_error($form['value'][$part], t('Please choose a month.'), $form_state);
469
          break;
470
        case 'day':
471
          form_error($form['value'][$part], t('Please choose a day.'), $form_state);
472
          break;
473
        case 'hour':
474
          form_error($form['value'][$part], t('Please choose an hour.'), $form_state);
475
          break;
476
        case 'minute':
477
          form_error($form['value'][$part], t('Please choose a minute.'), $form_state);
478
          break;
479
        case 'second':
480
          form_error($form['value'][$part], t('Please choose a second.'), $form_state);
481
          break;
482
      }
483
    }
484
  }
485
}
486

    
487
/**
488
 * Implements hook_date_formatter_view_alter().
489
 *
490
 * If we are displaying a date from a view, see if we have information about
491
 * which multiple value to display. If so, set the date_id in the entity.
492
 */
493
function date_views_date_formatter_pre_view_alter(&$entity, &$variables) {
494
  // Some views have no row index.
495
  if (!empty($entity->view) && isset($entity->view->row_index)) {
496
    $field = $variables['field'];
497
    $date_id = 'date_id_' . $field['field_name'];
498
    $date_delta = 'date_delta_' . $field['field_name'];
499
    $date_item = $entity->view->result[$entity->view->row_index];
500
    if (!empty($date_item->$date_id)) {
501
      $entity->date_id = 'date.' . $date_item->$date_id . '.' . $field['field_name'] . '.' . $date_item->$date_delta . '.0';
502
    }
503
  }
504
}