Révision b720ea3e
Ajouté par Assos Assos il y a plus de 8 ans
drupal7/sites/all/modules/date/date_views/includes/date_views_plugin_pager.inc | ||
---|---|---|
2 | 2 |
/** |
3 | 3 |
* @file |
4 | 4 |
* Date pager. |
5 |
* Works with a Date argument, the argument filters the view and the pager provides back/next navigation. |
|
5 |
* Works with a Date argument, the argument filters |
|
6 |
* the view and the pager provides back/next navigation. |
|
6 | 7 |
* |
7 | 8 |
* USER NOTES: |
8 | 9 |
* |
9 | 10 |
* To use this, add a pager to a view, and choose the option to 'Page by date'. |
10 | 11 |
* There are several settings: |
11 |
* - The pager id: Set an id to be used as the identifier in the url for pager values, defaults to 'date'. |
|
12 |
* - Pager position: Choose whether to display the date pager above, below, or both above and below the content. |
|
13 |
* - Link format: Choose whether the pager links will be in the simple 'calendar/2011-12' format or the |
|
14 |
* more complex 'calendar/?date=2011-12' pager format. The second one is more likely to work correctly |
|
15 |
* if the pager is used in blocks and panels. |
|
12 |
* - The pager id: Set an id to be used as the identifier |
|
13 |
* in the url for pager values, defaults to 'date'. |
|
14 |
* - Pager position: Choose whether to display the date |
|
15 |
* pager above, below, or both above and below the content. |
|
16 |
* - Link format: Choose whether the pager links will be in t |
|
17 |
* he simple 'calendar/2011-12' format or the |
|
18 |
* more complex 'calendar/?date=2011-12' pager format. |
|
19 |
* The second one is more likely to work correctly |
|
20 |
* if the pager is used in blocks and panels. |
|
16 | 21 |
* |
17 |
* The pager works in combination with a Date argument and it will use the date fields and granularity |
|
18 |
* set in that argument to create its back/next links. If the view has no Date argument, the pager can |
|
19 |
* do nothing. The argument can either be a 'Date' argument that lets you select one or more date fields |
|
20 |
* in the argument, or the simple 'Content' argument for an individual date field. It must be an |
|
22 |
* The pager works in combination with a Date argument |
|
23 |
* and it will use the date fields and granularity |
|
24 |
* set in that argument to create its back/next links. |
|
25 |
* If the view has no Date argument, the pager can |
|
26 |
* do nothing. The argument can either be a 'Date' argument |
|
27 |
* that lets you select one or more date fields |
|
28 |
* in the argument, or the simple 'Content' argument for an |
|
29 |
* individual date field. It must be an |
|
21 | 30 |
* argument that uses the date argument handler. |
22 | 31 |
* |
23 | 32 |
* DEVELOPER NOTES |
24 | 33 |
* |
25 |
* The pager could technically create a query of its own rather than depending on the date argument to |
|
26 |
* set the query, but it has only a limited set of tools to work with because it is a plugin, not a handler: |
|
27 |
* it has no knowledge about relationships, it cannot use the ensure_my_table() function, |
|
28 |
* plugins are not even invoked in pre_query(), so can't do anything there. |
|
34 |
* The pager could technically create a query of its own rather |
|
35 |
* than depending on the date argument to |
|
36 |
* set the query, but it has only a limited set of tools to work |
|
37 |
* with because it is a plugin, not a handler: |
|
38 |
* it has no knowledge about relationships, it cannot use the |
|
39 |
* ensure_my_table() function, plugins are not even invoked in pre_query(), |
|
40 |
* so can't do anything there. |
|
29 | 41 |
* |
30 |
* My conclusion was that the date pager simply is not powerful enough to create its own queries for |
|
31 |
* date fields, which require very complex queries. Instead, we can combine this with a date argument and |
|
32 |
* let the argument create the query and let the pager just provide the back/next links. If there is no |
|
42 |
* My conclusion was that the date pager simply |
|
43 |
* is not powerful enough to create its own queries for |
|
44 |
* date fields, which require very complex queries. |
|
45 |
* Instead, we can combine this with a date argument and |
|
46 |
* let the argument create the query and let the pager |
|
47 |
* just provide the back/next links. If there is no |
|
33 | 48 |
* date argument, the pager will do nothing. |
34 | 49 |
* |
35 |
* There are still other problems. The pager is not even initialized until after all the handlers |
|
36 |
* have created their queries, so it has no chance to alter values ahead of that. And the argument |
|
37 |
* has no knowledge of the pager, so it can't check for pager values before the query is created. |
|
50 |
* There are still other problems. The pager is not even |
|
51 |
* initialized until after all the handlers |
|
52 |
* have created their queries, so it has no chance |
|
53 |
* to alter values ahead of that. And the argument |
|
54 |
* has no knowledge of the pager, so it can't check |
|
55 |
* for pager values before the query is created. |
|
38 | 56 |
* |
39 |
* The solution used here is to let the argument create the original query. The pager query |
|
40 |
* runs after that, so the pager checks to see if there is a pager value that needs to be used in the query. |
|
41 |
* The date argument has identified the placeholders it used in the query. So if a change is needed, |
|
42 |
* we can swap the pager value into the query created by the date argument and adjust the |
|
43 |
* $view->date_info values set by the argument accordingly so the theme will pick up the new information. |
|
57 |
* The solution used here is to let the argument create |
|
58 |
* the original query. The pager query |
|
59 |
* runs after that, so the pager checks to see |
|
60 |
* if there is a pager value that needs to be used in the query. |
|
61 |
* The date argument has identified the placeholders |
|
62 |
* it used in the query. So if a change is needed, |
|
63 |
* we can swap the pager value into the query created |
|
64 |
* by the date argument and adjust the |
|
65 |
* $view->date_info values set by the argument accordingly |
|
66 |
* so the theme will pick up the new information. |
|
44 | 67 |
*/ |
45 | 68 |
|
46 | 69 |
/** |
47 | 70 |
* Example plugin to handle paging by month. |
48 | 71 |
*/ |
72 |
// @codingStandardsIgnoreStart |
|
49 | 73 |
class date_views_plugin_pager extends views_plugin_pager { |
50 | 74 |
|
51 | 75 |
/** |
... | ... | |
79 | 103 |
$options['link_format'] = array('default' => 'pager'); |
80 | 104 |
$options['date_argument'] = array('default' => 'Unknown'); |
81 | 105 |
$options['granularity'] = array('default' => 'Unknown'); |
106 |
$options['skip_empty_pages'] = array('default' => FALSE); |
|
82 | 107 |
return $options; |
83 | 108 |
} |
84 | 109 |
|
... | ... | |
110 | 135 |
'#default_value' => $this->options['link_format'], |
111 | 136 |
'#required' => TRUE, |
112 | 137 |
); |
138 |
$form['skip_empty_pages'] = array( |
|
139 |
'#title' => t('Skip empty pages'), |
|
140 |
'#type' => 'checkbox', |
|
141 |
'#description' => t('When selected, the pager will not display pages with no result for the given date. This causes a slight performance degradation because two additional queries need to be executed.'), |
|
142 |
'#default_value' => $this->options['skip_empty_pages'], |
|
143 |
); |
|
113 | 144 |
$form['date_argument']['#type'] = 'hidden'; |
114 | 145 |
$form['date_argument']['#value'] = $this->options['date_argument']; |
115 | 146 |
$form['granularity']['#type'] = 'hidden'; |
... | ... | |
150 | 181 |
|
151 | 182 |
// Reset values set by argument if pager requires it. |
152 | 183 |
if (!empty($value)) { |
153 |
$argument->argument = $value; |
|
154 |
$argument->date_range = $argument->date_handler->arg_range($value); |
|
155 |
$argument->min_date = $argument->date_range[0]; |
|
156 |
$argument->max_date = $argument->date_range[1]; |
|
157 |
// $argument->is_default works correctly for normal arguments, but does not |
|
158 |
// work correctly if we are swapping in a new value from the pager. |
|
159 |
$argument->is_default = FALSE; |
|
184 |
$this->set_argument_value($argument, $value); |
|
160 | 185 |
} |
161 | 186 |
|
162 | 187 |
// The pager value might move us into a forbidden range, so test it. |
... | ... | |
164 | 189 |
$this->view->build_info['fail'] = TRUE; |
165 | 190 |
return; |
166 | 191 |
} |
167 |
|
|
168 |
if (empty($this->view->date_info)) $this->view->date_info = new stdClass(); |
|
192 |
// Write date_info to store information to be used |
|
193 |
// in the theming functions. |
|
194 |
if (empty($this->view->date_info)) { |
|
195 |
$this->view->date_info = new stdClass(); |
|
196 |
} |
|
169 | 197 |
$this->view->date_info->granularity = $argument->date_handler->granularity; |
170 | 198 |
$format = $this->view->date_info->granularity == 'week' ? DATE_FORMAT_DATETIME : $argument->sql_format; |
171 | 199 |
$this->view->date_info->placeholders = isset($argument->placeholders) ? $argument->placeholders : $argument->date_handler->placeholders; |
172 | 200 |
$this->view->date_info->date_arg = $argument->argument; |
173 | 201 |
$this->view->date_info->date_arg_pos = $i; |
202 |
$this->view->date_info->limit = $argument->limit; |
|
203 |
$this->view->date_info->url = $this->view->get_url(); |
|
204 |
$this->view->date_info->pager_id = $this->options['date_id']; |
|
205 |
$this->view->date_info->date_pager_position = $this->options['pager_position']; |
|
206 |
$this->view->date_info->date_pager_format = $this->options['link_format']; |
|
207 |
$this->view->date_info->skip_empty_pages = $this->options['skip_empty_pages'] == 1; |
|
208 |
// Execute two additional queries to find |
|
209 |
// the previous and next page with values. |
|
210 |
if ($this->view->date_info->skip_empty_pages) { |
|
211 |
$q = clone $argument->query; |
|
212 |
$field = $argument->table_alias . '.' . $argument->real_field; |
|
213 |
$fieldsql = $date_handler->sql_field($field); |
|
214 |
$fieldsql = $date_handler->sql_format($format, $fieldsql); |
|
215 |
$q->clear_fields(); |
|
216 |
$q->orderby = array(); |
|
217 |
$q->set_distinct(TRUE, TRUE); |
|
218 |
// Date limits of this argument. |
|
219 |
$datelimits = $argument->date_handler->arg_range($argument->limit[0] . '--' . $argument->limit[1]); |
|
220 |
// Find the first two dates between the minimum date |
|
221 |
// and the upper bound of the current value. |
|
222 |
$q->add_orderby(NULL, $fieldsql, 'DESC', 'date'); |
|
223 |
$this->set_argument_placeholders($this->view->date_info->placeholders, $datelimits[0], $argument->max_date, $q, $format); |
|
224 |
|
|
225 |
$compiledquery = $q->query(); |
|
226 |
$compiledquery->range(0, 2); |
|
227 |
$results = $compiledquery->execute()->fetchCol(0); |
|
228 |
|
|
229 |
$prevdate = array_shift($results); |
|
230 |
$prevdatealt = array_shift($results); |
|
231 |
// Find the first two dates between the lower bound |
|
232 |
// of the current value and the maximum date. |
|
233 |
$q->add_orderby(NULL, $fieldsql, 'ASC', 'date'); |
|
234 |
$this->set_argument_placeholders($this->view->date_info->placeholders, $argument->min_date, $datelimits[1], $q, $format); |
|
235 |
|
|
236 |
$compiledquery = $q->query(); |
|
237 |
$compiledquery->range(0, 2); |
|
238 |
$results = $compiledquery->execute()->fetchCol(0); |
|
239 |
|
|
240 |
$nextdate = array_shift($results); |
|
241 |
$nextdatealt = array_shift($results); |
|
242 |
|
|
243 |
// Set the default value of the query to $prevfirst or $nextfirst |
|
244 |
// when there is no value and $prevsecond or $nextsecond is set. |
|
245 |
if (empty($value)) { |
|
246 |
// @Todo find out which of $prevdate or $nextdate is closest to the |
|
247 |
// default argument date value and choose that one. |
|
248 |
if ($prevdate && $prevdatealt) { |
|
249 |
$this->set_argument_value($argument, $prevdate); |
|
250 |
$value = $prevdate; |
|
251 |
$prevdate = $prevdatealt; |
|
252 |
// If the first next date is the same as the first previous date, |
|
253 |
// move to the following next date. |
|
254 |
if ($value == $nextdate) { |
|
255 |
$nextdate = $nextdatealt; |
|
256 |
$nextdatealt = NULL; |
|
257 |
} |
|
258 |
} |
|
259 |
elseif ($nextdate && $nextdatealt) { |
|
260 |
$this->set_argument_value($argument, $nextdate); |
|
261 |
$value = $nextdate; |
|
262 |
$nextdate = $nextdatealt; |
|
263 |
// If the first previous date is the same as the first next date, |
|
264 |
// move to the following previous date. |
|
265 |
if ($value == $prevdate) { |
|
266 |
$prevdate = $prevdatealt; |
|
267 |
$prevdatealt = NULL; |
|
268 |
} |
|
269 |
} |
|
270 |
} |
|
271 |
else { |
|
272 |
// $prevdate and $nextdate are the same as $value, so move to |
|
273 |
// the next values. |
|
274 |
$prevdate = $prevdatealt; |
|
275 |
$nextdate = $nextdatealt; |
|
276 |
} |
|
277 |
|
|
278 |
$this->view->date_info->prev_date = $prevdate ? new DateObject($prevdate, NULL, $format) : NULL; |
|
279 |
$this->view->date_info->next_date = $nextdate ? new DateObject($nextdate, NULL, $format) : NULL; |
|
280 |
} |
|
281 |
else { |
|
282 |
$this->view->date_info->prev_date = clone($argument->min_date); |
|
283 |
date_modify($this->view->date_info->prev_date, '-1 ' . $argument->date_handler->granularity); |
|
284 |
$this->view->date_info->next_date = clone($argument->max_date); |
|
285 |
date_modify($this->view->date_info->next_date, '+1 ' . $argument->date_handler->granularity); |
|
286 |
} |
|
287 |
// Write the date_info properties that depend on the current value. |
|
174 | 288 |
$this->view->date_info->year = date_format($argument->min_date, 'Y'); |
175 | 289 |
$this->view->date_info->month = date_format($argument->min_date, 'n');; |
176 | 290 |
$this->view->date_info->day = date_format($argument->min_date, 'j'); |
... | ... | |
178 | 292 |
$this->view->date_info->date_range = $argument->date_range; |
179 | 293 |
$this->view->date_info->min_date = $argument->min_date; |
180 | 294 |
$this->view->date_info->max_date = $argument->max_date; |
181 |
$this->view->date_info->limit = $argument->limit; |
|
182 |
$this->view->date_info->url = $this->view->get_url(); |
|
183 |
$this->view->date_info->pager_id = $this->options['date_id']; |
|
184 |
$this->view->date_info->date_pager_position = $this->options['pager_position']; |
|
185 |
$this->view->date_info->date_pager_format = $this->options['link_format']; |
|
186 | 295 |
} |
187 | 296 |
$i++; |
188 | 297 |
} |
... | ... | |
191 | 300 |
// If there is pager input and the argument has set the placeholders, |
192 | 301 |
// swap the pager value in for the placeholder set by the argument. |
193 | 302 |
if (!empty($value) && !empty($this->view->date_info->placeholders)) { |
194 |
$placeholders = $this->view->date_info->placeholders; |
|
195 |
$count = count($placeholders); |
|
196 |
foreach ($this->view->query->where as $group => $data) { |
|
197 |
foreach ($data['conditions'] as $delta => $condition) { |
|
198 |
if (array_key_exists('value', $condition) && is_array($condition['value'])) { |
|
199 |
foreach ($condition['value'] as $placeholder => $placeholder_value) { |
|
200 |
if (array_key_exists($placeholder, $placeholders)) { |
|
201 |
// If we didn't get a match, this is a > $min < $max query that uses the view |
|
202 |
// min and max dates as placeholders. |
|
203 |
$date = ($count == 2) ? $this->view->date_info->min_date : $this->view->date_info->max_date; |
|
204 |
$next_placeholder = array_shift($placeholders); |
|
205 |
$this->view->query->where[$group]['conditions'][$delta]['value'][$placeholder] = $date->format($format); |
|
206 |
$count--; |
|
207 |
} |
|
303 |
$this->set_argument_placeholders($this->view->date_info->placeholders, $this->view->date_info->min_date, $this->view->date_info->max_date, $this->view->query, $format); |
|
304 |
} |
|
305 |
} |
|
306 |
|
|
307 |
function set_argument_value($argument, $value) { |
|
308 |
$argument->argument = $value; |
|
309 |
$argument->date_range = $argument->date_handler->arg_range($value); |
|
310 |
$argument->min_date = $argument->date_range[0]; |
|
311 |
$argument->max_date = $argument->date_range[1]; |
|
312 |
// $argument->is_default works correctly for normal arguments, but does not |
|
313 |
// work correctly if we are swapping in a new value from the pager. |
|
314 |
$argument->is_default = FALSE; |
|
315 |
} |
|
316 |
|
|
317 |
function set_argument_placeholders($placeholders, $mindate, $maxdate, $query, $format) { |
|
318 |
$count = count($placeholders); |
|
319 |
foreach ($query->where as $group => $data) { |
|
320 |
foreach ($data['conditions'] as $delta => $condition) { |
|
321 |
if (array_key_exists('value', $condition) && is_array($condition['value'])) { |
|
322 |
foreach ($condition['value'] as $placeholder => $placeholder_value) { |
|
323 |
if (array_key_exists($placeholder, $placeholders)) { |
|
324 |
// If we didn't get a match, this is a > $min < $max query that uses the view |
|
325 |
// min and max dates as placeholders. |
|
326 |
$date = ($count == 2) ? $mindate : $maxdate; |
|
327 |
$next_placeholder = array_shift($placeholders); |
|
328 |
$query->where[$group]['conditions'][$delta]['value'][$placeholder] = $date->format($format); |
|
329 |
$count--; |
|
208 | 330 |
} |
209 | 331 |
} |
210 | 332 |
} |
... | ... | |
230 | 352 |
$pager_theme = views_theme_functions('date_views_pager', $this->view, $this->display); |
231 | 353 |
return theme($pager_theme, array('plugin' => $this, 'input' => $input)); |
232 | 354 |
} |
233 |
} |
|
355 |
} |
|
356 |
// @codingStandardsIgnoreEnd |
Formats disponibles : Unified diff
Weekly update of contrib modules