Projet

Général

Profil

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

root / drupal7 / sites / all / modules / date / date_views / includes / date_views_argument_handler_simple.inc @ db9ffd17

1
<?php
2
/**
3
 * @file
4
 * Date API views argument handler.
5
 */
6

    
7
/**
8
 * Date API argument handler.
9
 */
10
class date_views_argument_handler_simple extends views_handler_argument_date {
11

    
12
  /**
13
   * Get granularity and use it to create the formula and a format
14
   * for the results.
15
   */
16
  function init(&$view, &$options) {
17
    parent::init($view, $options);
18

    
19
    // Add a date handler.
20
    module_load_include('inc', 'date_api', 'date_api_sql');
21
    $this->date_handler = new date_sql_handler(DATE_UNIX);
22
    if (!empty($this->definition['field_name'])) {
23
      $field = field_info_field($this->definition['field_name']);
24
      if (!empty($field) && !empty($field['type'])) {
25
        $this->date_handler->date_type = $field['type'];
26
        $this->original_table = $this->definition['table'];
27
      }
28
      $this->date_handler->db_timezone = date_get_timezone_db($field['settings']['tz_handling']);
29
      $this->date_handler->local_timezone = date_get_timezone($field['settings']['tz_handling']);
30
    }
31
    $this->date_handler->granularity = $this->options['granularity'];
32
    // This value needs to be initialized so it exists even if the query doesn't run.
33
    $this->date_handler->placeholders = array();
34

    
35
    $this->format = $this->date_handler->views_formats($this->date_handler->granularity, 'display');
36
    $this->sql_format = $this->date_handler->views_formats($this->date_handler->granularity, 'sql');
37
    // $this->arg_format is the format the parent date handler will use to create a default argument.
38
    $this->arg_format = $this->format();
39

    
40
    // Identify the base table for this field.
41
    // It will be used to call for the right query field options.
42
    $this->base_table = $this->table;
43

    
44
  }
45

    
46
  function format() {
47
    if (!empty($this->options['granularity'])) {
48
      return $this->date_handler->views_formats($this->options['granularity']);
49
    }
50
    else {
51
      return !empty($this->options[$this->option_name]) ? $this->options[$this->option_name] : 'Y-m';
52
    }
53
  }
54

    
55
  /**
56
   * Set the empty argument value to the current date,
57
   * formatted appropriately for this argument.
58
   */
59
  function get_default_argument($raw = FALSE) {
60
    $is_default = FALSE;
61

    
62
    if (!$raw && $this->options['default_argument_type'] == 'date') {
63
      $granularity = $this->options['granularity'];
64
      if ($granularity == 'week') {
65
        $now = date_now();
66
        $week = date_week(date_format($now, 'Y-m-d'));
67
        $value = date_format($now, 'o') . '-W' . date_pad($week);
68
      }
69
      else {
70
        $value = date($this->arg_format, REQUEST_TIME);
71
      }
72
      drupal_alter('date_default_argument', $this, $value);
73

    
74
      return $value;
75
    }
76

    
77
    // Let the parent argument handle options like node created date.
78
    return parent::get_default_argument($raw);
79
  }
80

    
81
  /**
82
   * Default value for the date_fields option.
83
   */
84
  function option_definition() {
85
    $options = parent::option_definition();
86
    $options['year_range'] = array('default' => '-3:+3');
87
    $options['granularity'] = array('default' => 'month');
88
    $options['default_argument_type']['default'] = 'date';
89
    $options['add_delta'] = array('default' => '');
90
    $options['use_fromto'] = array('default' => '');
91
    $options['title_format'] = array('default' => '');
92
    $options['title_format_custom'] = array('default' => '');
93
    return $options;
94
  }
95

    
96
  /**
97
   * Add a form element to select date_fields for this argument.
98
   */
99
  function options_form(&$form, &$form_state) {
100
    parent::options_form($form, $form_state);
101

    
102
    // Add an option to control the format of the summary.
103
    $options = array(
104
      '' => t('Default format'),
105
      'custom' => t('Custom format'),
106
    );
107
    $example_month = date_format_date(date_example_date(), 'custom', $this->date_handler->views_formats('month', 'display'));
108
    $example_day = date_format_date(date_example_date(), 'custom', $this->date_handler->views_formats('day', 'display'));
109

    
110
    $form['title_format'] = array(
111
      '#type' => 'select',
112
      '#title' => t('Date format options'),
113
      '#default_value' => $this->options['title_format'],
114
      '#options' => $options,
115
      '#description' => t('The date format used in titles and summary links for this argument. The default format is based on the granularity of the filter, i.e. month: @example_month, day: @example_day.', array('@example_month' => $example_month, '@example_day' => $example_day)),
116
      '#attributes' => array('class' => array('dependent-options')),
117
      '#states' => array(
118
        'visible' => array(
119
          ':input[name="options[default_action]"]' => array('value' => 'summary')
120
        ),
121
      ),
122
    );
123

    
124
    $form['title_format_custom'] = array(
125
      '#type' => 'textfield',
126
      '#title' => t('Custom summary date format'),
127
      '#default_value' => $this->options['title_format_custom'],
128
      '#description' => t("A custom format for the title and summary date format. Define a php date format string like 'm-d-Y H:i' (see <a href=\"@link\">http://php.net/date</a> for more details).", array('@link' => 'http://php.net/date')),
129
      '#attributes' => array('class' => array('dependent-options')),
130
      '#states' => array(
131
        'visible' => array(
132
          ':input[name="options[title_format]"]' => array('value' => 'custom')
133
        ),
134
      ),
135
    );
136

    
137
    $options = $this->date_handler->date_parts();
138
    unset($options['second'], $options['minute']);
139
    $options += array('week' => t('Week', array(), array('context' => 'datetime')));
140
    $form['granularity'] = array(
141
      '#title' => t('Granularity'),
142
      '#type' => 'radios',
143
      '#options' => $options,
144
      '#default_value' => $this->options['granularity'],
145
      '#multiple' => TRUE,
146
      '#description' => t("Select the type of date value to be used in defaults, summaries, and navigation. For example, a granularity of 'month' will set the default date to the current month, summarize by month in summary views, and link to the next and previous month when using date navigation."),
147
    );
148

    
149
    $form['year_range'] = array(
150
      '#title' => t('Date year range'),
151
      '#type' => 'textfield',
152
      '#default_value' => $this->options['year_range'],
153
      '#description' => t("Set the allowable minimum and maximum year range for this argument, either a -X:+X offset from the current year, like '-3:+3' or an absolute minimum and maximum year, like '2005:2010' . When the argument is set to a date outside the range, the page will be returned as 'Page not found (404)' ."),
154
    );
155

    
156
    $form['use_fromto'] = array(
157
      '#type' => 'radios',
158
      '#title' => t('Dates to compare'),
159
      '#default_value' => $this->options['use_fromto'],
160
      '#options' => array('' => t('Start/End date range'), 'no' => t('Only this field')),
161
      '#description' => t("If selected the view will check if any value starting with the 'Start' date and ending with the 'End' date matches the view criteria. Otherwise the view will be limited to the specifically selected fields. Comparing to the whole Start/End range is the recommended setting when using this filter in a Calendar. When using the Start/End option, it is not necessary to add both the Start and End fields to the filter, either one will do."),
162
    );
163

    
164
    $access = TRUE;
165
    if (!empty($this->definition['field_name'])) {
166
      $field = field_info_field($this->definition['field_name']);
167
      $access = $field['cardinality'] != 1;
168
    }
169
    $form['add_delta'] = array(
170
      '#type' => 'radios',
171
      '#title' => t('Add multiple value identifier'),
172
      '#default_value' => $this->options['add_delta'],
173
      '#options' => array('' => t('No'), 'yes' => t('Yes')),
174
      '#description' => t('Add an identifier to the view to show which multiple value date fields meet the filter criteria. Note: This option may introduce duplicate values into the view. Required when using multiple value fields in a Calendar or any time you want the node view of multiple value dates to display only the values that match the view filters.'),
175
      // Only let mere mortals tweak this setting for multi-value fields
176
      '#access' => $access,
177
    );
178

    
179
  }
180

    
181
  function options_validate(&$form, &$form_state) {
182
    // It is very important to call the parent function here:
183
    parent::options_validate($form, $form_state);
184
    if (!preg_match('/^(?:\-[0-9]{1,4}|[0-9]{4}):(?:[\+|\-][0-9]{1,4}|[0-9]{4})$/', $form_state['values']['options']['year_range'])) {
185
      form_error($form['year_range'], t('Date year range must be in the format -9:+9, 2005:2010, -9:2010, or 2005:+9'));
186
    }
187
  }
188

    
189
  /**
190
   * Provide a link to the next level of the view from the summary.
191
   */
192
  function summary_name($data) {
193
    $value = $data->{$this->name_alias};
194
    if (empty($value) && !empty($this->definition['empty field name'])) {
195
      return $this->definition['empty field name'];
196
    }
197
    elseif (empty($value)) {
198
      return $this->options['wildcard_substitution'];
199
    }
200
    $format = !empty($this->options['title_format_custom']) && !empty($this->options['title_format_custom']) ? $this->options['title_format_custom'] : $this->date_handler->views_formats($this->options['granularity'], 'display');
201
    $range = $this->date_handler->arg_range($value);
202
    return date_format_date($range[0], 'custom', $format);
203
  }
204

    
205
  /**
206
   * Provide a title for the view based on the argument value.
207
   */
208
  function title() {
209
    $format = !empty($this->options['title_format_custom']) && !empty($this->options['title_format_custom']) ? $this->options['title_format_custom'] : $this->date_handler->views_formats($this->options['granularity'], 'display');
210
    $range = $this->date_handler->arg_range($this->argument);
211
    return date_format_date($range[0], 'custom', $format);
212
 }
213

    
214
  /**
215
   * Provide the argument to use to link from the summary to the next level;
216
   * this will be called once per row of a summary, and used as part of
217
   * $view->get_url().
218
   *
219
   * @param $data
220
   *   The query results for the row.
221
   */
222
  function summary_argument($data) {
223
    $format = $this->date_handler->views_formats($this->options['granularity'], 'sql');
224
    $value = $data->{$this->name_alias};
225
    if (empty($value)) {
226
      return $this->options['exception']['value'];
227
    }
228
    $range = $this->date_handler->arg_range($value);
229
    return date_format_date($range[0], 'custom', $format);
230
  }
231

    
232
  /**
233
   * Inject a test for valid date range before the summary query.
234
   */
235
  function summary_query() {
236

    
237
    // @TODO The summary values are computed by the database. Unless the database has
238
    // built-in timezone handling it will use a fixed offset, which will not be
239
    // right for all dates. The only way I can see to make this work right is to
240
    // store the offset for each date in the database so it can be added to the base
241
    // date value before the database formats the result. Because this is a huge
242
    // architectural change, it won't go in until we start a new branch.
243
    $this->formula = $this->date_handler->sql_format($this->sql_format, $this->date_handler->sql_field("***table***.$this->real_field"));
244
    $this->ensure_my_table();
245
    // Now that our table is secure, get our formula.
246
    $formula = $this->get_formula();
247

    
248
    // Add the field, give it an alias that does NOT match the actual field name or grouping won't work right.
249
    $this->base_alias = $this->name_alias = $this->query->add_field(NULL, $formula, $this->field . '_summary');
250
    $this->query->set_count_field(NULL, $formula, $this->field);
251

    
252
    return $this->summary_basics(FALSE);
253
  }
254

    
255
  /**
256
   * Inject a test for valid date range before the regular query.
257
   * Override the parent query to be able to control the $group.
258
   */
259
  function query($group_by = FALSE) {
260

    
261
    // @TODO Not doing anything with $group_by yet, need to figure out what has to be done.
262

    
263
    if ($this->date_forbid()) {
264
      return;
265
    }
266

    
267
    // See if we need to reset granularity based on an argument value.
268
    // Make sure we don't try to reset to some bogus value if someone has typed in an unexpected argument.
269
    $granularity = $this->date_handler->arg_granularity($this->argument);
270
    if (!empty($granularity)) {
271
      $this->date_handler->granularity = $granularity;
272
      $this->format = $this->date_handler->views_formats($this->date_handler->granularity, 'display');
273
      $this->sql_format = $this->date_handler->views_formats($this->date_handler->granularity, 'sql');
274
    }
275
    $this->granularity = $this->date_handler->granularity;
276
    $this->ensure_my_table();
277
    $group = !empty($this->options['date_group']) ? $this->options['date_group'] : 0;
278

    
279
    // If requested, add the delta field to the view so we can later find the value that matched our query.
280
    if (!empty($this->options['add_delta']) && (substr($this->real_field, -6) == '_value' || substr($this->real_field, -7) == '_value2')) {
281
      $this->query->add_field($this->table_alias, 'delta');
282
      $real_field_name = str_replace(array('_value', '_value2'), '', $this->real_field);
283
      $this->query->add_field($this->table_alias, 'entity_id', 'date_id_' . $real_field_name);
284
      $this->query->add_field($this->table_alias, 'delta', 'date_delta_' . $real_field_name);
285
    }
286

    
287
    $format = $this->date_handler->granularity == 'week' ? DATE_FORMAT_DATETIME : $this->sql_format;
288
    $view_min = date_format($this->min_date, $format);
289
    $view_max = date_format($this->max_date, $format);
290
    $view_min_placeholder = $this->placeholder();
291
    $view_max_placeholder = $this->placeholder();
292
    $this->date_handler->placeholders = array($view_min_placeholder => $view_min, $view_max_placeholder => $view_max);
293

    
294
    // Are we comparing this field only or the Start/End date range to the view criteria?
295
    if (!empty($this->options['use_fromto'])) {
296

    
297
      // The simple case, match the field to the view range.
298
      $field = $this->date_handler->sql_field($this->table_alias . '.' . $this->real_field, NULL, $this->min_date);
299
      $field = $this->date_handler->sql_format($format, $field);
300
      $this->query->add_where_expression($group, "$field >= $view_min_placeholder AND $field <= $view_max_placeholder", array($view_min_placeholder => $view_min, $view_max_placeholder => $view_max));
301

    
302
    }
303
    else {
304

    
305
      // Look for the intersection of the range of the date field with the range of the view.
306
      // Get the Start/End values for this field. Retrieve using the original table name.
307
      // Swap the current table name (adjusted for relationships) into the query.
308
      // @TODO We may be able to use Views substitutions here, investigate that later.
309
      $fields = date_views_fields($this->base_table);
310
      $fields = $fields['name'];
311
      $fromto = $fields[$this->original_table . '.' . $this->real_field]['fromto'];
312

    
313
      $value_min = str_replace($this->original_table, $this->table_alias, $fromto[0]);
314
      $value_max = str_replace($this->original_table, $this->table_alias, $fromto[1]);
315
      $field_min = $this->date_handler->sql_field($value_min, NULL, $this->min_date);
316
      $field_min = $this->date_handler->sql_format($format, $field_min);
317
      $field_max = $this->date_handler->sql_field($value_max, NULL, $this->max_date);
318
      $field_max = $this->date_handler->sql_format($format, $field_max);
319
      $this->query->add_where_expression($group, "$field_max >= $view_min_placeholder AND $field_min <= $view_max_placeholder", array($view_min_placeholder => $view_min, $view_max_placeholder => $view_max));
320
    }
321
  }
322

    
323
  /**
324
   * Add a callback to determine if we have moved outside the valid date range for this argument.
325
   */
326
  function date_forbid() {
327
    if (empty($this->argument)) {
328
      return TRUE;
329
    }
330
    $this->date_range = $this->date_handler->arg_range($this->argument);
331
    $this->min_date = $this->date_range[0];
332
    $this->max_date = $this->date_range[1];
333
    $this->limit = date_range_years($this->options['year_range']);
334
    $group = !empty($this->options['date_group']) ? $this->options['date_group'] : 0;
335

    
336
    // See if we're outside the allowed date range for our argument.
337
    if (date_format($this->min_date, 'Y') < $this->limit[0] || date_format($this->max_date, 'Y') > $this->limit[1]) {
338
      $this->forbid = TRUE;
339
      $this->view->build_info['fail'] = TRUE;
340
      return TRUE;
341
    }
342
    return FALSE;
343
  }
344

    
345
}