Chris@0
|
1 <?php
|
Chris@0
|
2
|
Chris@0
|
3 namespace Drupal\views;
|
Chris@0
|
4
|
Chris@0
|
5 use Drupal\Component\Render\FormattableMarkup;
|
Chris@0
|
6 use Drupal\Component\Utility\Html;
|
Chris@0
|
7 use Drupal\Component\Utility\Tags;
|
Chris@0
|
8 use Drupal\Core\Routing\RouteProviderInterface;
|
Chris@0
|
9 use Drupal\Core\Session\AccountInterface;
|
Chris@0
|
10 use Drupal\views\Plugin\views\display\DisplayRouterInterface;
|
Chris@0
|
11 use Symfony\Component\HttpFoundation\Request;
|
Chris@0
|
12 use Symfony\Component\HttpFoundation\Response;
|
Chris@0
|
13 use Symfony\Component\Routing\Exception\RouteNotFoundException;
|
Chris@0
|
14
|
Chris@0
|
15 /**
|
Chris@0
|
16 * Represents a view as a whole.
|
Chris@0
|
17 *
|
Chris@0
|
18 * An object to contain all of the data to generate a view, plus the member
|
Chris@0
|
19 * functions to build the view query, execute the query and render the output.
|
Chris@0
|
20 *
|
Chris@0
|
21 * This class does not implement the Serializable interface since problems
|
Chris@0
|
22 * occurred when using the serialize method.
|
Chris@0
|
23 *
|
Chris@0
|
24 * @see https://www.drupal.org/node/2849674
|
Chris@0
|
25 * @see https://bugs.php.net/bug.php?id=66052
|
Chris@0
|
26 */
|
Chris@0
|
27 class ViewExecutable {
|
Chris@0
|
28
|
Chris@0
|
29 /**
|
Chris@0
|
30 * The config entity in which the view is stored.
|
Chris@0
|
31 *
|
Chris@0
|
32 * @var \Drupal\views\Entity\View
|
Chris@0
|
33 */
|
Chris@0
|
34 public $storage;
|
Chris@0
|
35
|
Chris@0
|
36 /**
|
Chris@0
|
37 * Whether or not the view has been built.
|
Chris@0
|
38 *
|
Chris@0
|
39 * @todo Group with other static properties.
|
Chris@0
|
40 *
|
Chris@0
|
41 * @var bool
|
Chris@0
|
42 */
|
Chris@0
|
43 public $built = FALSE;
|
Chris@0
|
44
|
Chris@0
|
45 /**
|
Chris@0
|
46 * Whether the view has been executed/query has been run.
|
Chris@0
|
47 *
|
Chris@0
|
48 * @todo Group with other static properties.
|
Chris@0
|
49 *
|
Chris@0
|
50 * @var bool
|
Chris@0
|
51 */
|
Chris@0
|
52 public $executed = FALSE;
|
Chris@0
|
53
|
Chris@0
|
54 /**
|
Chris@0
|
55 * Any arguments that have been passed into the view.
|
Chris@0
|
56 *
|
Chris@0
|
57 * @var array
|
Chris@0
|
58 */
|
Chris@0
|
59 public $args = [];
|
Chris@0
|
60
|
Chris@0
|
61 /**
|
Chris@0
|
62 * An array of build info.
|
Chris@0
|
63 *
|
Chris@0
|
64 * @var array
|
Chris@0
|
65 */
|
Chris@0
|
66 public $build_info = [];
|
Chris@0
|
67
|
Chris@0
|
68 /**
|
Chris@0
|
69 * Whether this view uses AJAX.
|
Chris@0
|
70 *
|
Chris@0
|
71 * @var bool
|
Chris@0
|
72 */
|
Chris@0
|
73 protected $ajaxEnabled = FALSE;
|
Chris@0
|
74
|
Chris@0
|
75 /**
|
Chris@0
|
76 * Where the results of a query will go.
|
Chris@0
|
77 *
|
Chris@0
|
78 * The array must use a numeric index starting at 0.
|
Chris@0
|
79 *
|
Chris@0
|
80 * @var \Drupal\views\ResultRow[]
|
Chris@0
|
81 */
|
Chris@0
|
82 public $result = [];
|
Chris@0
|
83
|
Chris@0
|
84 // May be used to override the current pager info.
|
Chris@0
|
85
|
Chris@0
|
86 /**
|
Chris@0
|
87 * The current page. If the view uses pagination.
|
Chris@0
|
88 *
|
Chris@0
|
89 * @var int
|
Chris@0
|
90 */
|
Chris@0
|
91 protected $current_page = NULL;
|
Chris@0
|
92
|
Chris@0
|
93 /**
|
Chris@0
|
94 * The number of items per page.
|
Chris@0
|
95 *
|
Chris@0
|
96 * @var int
|
Chris@0
|
97 */
|
Chris@0
|
98 protected $items_per_page = NULL;
|
Chris@0
|
99
|
Chris@0
|
100 /**
|
Chris@0
|
101 * The pager offset.
|
Chris@0
|
102 *
|
Chris@0
|
103 * @var int
|
Chris@0
|
104 */
|
Chris@0
|
105 protected $offset = NULL;
|
Chris@0
|
106
|
Chris@0
|
107 /**
|
Chris@0
|
108 * The total number of rows returned from the query.
|
Chris@0
|
109 *
|
Chris@0
|
110 * @var int
|
Chris@0
|
111 */
|
Chris@0
|
112 public $total_rows = NULL;
|
Chris@0
|
113
|
Chris@0
|
114 /**
|
Chris@0
|
115 * Attachments to place before the view.
|
Chris@0
|
116 *
|
Chris@17
|
117 * @var array
|
Chris@0
|
118 */
|
Chris@0
|
119 public $attachment_before = [];
|
Chris@0
|
120
|
Chris@0
|
121 /**
|
Chris@0
|
122 * Attachments to place after the view.
|
Chris@0
|
123 *
|
Chris@0
|
124 * @var array
|
Chris@0
|
125 */
|
Chris@0
|
126 public $attachment_after = [];
|
Chris@0
|
127
|
Chris@0
|
128 /**
|
Chris@0
|
129 * Feed icons attached to the view.
|
Chris@0
|
130 *
|
Chris@0
|
131 * @var array
|
Chris@0
|
132 */
|
Chris@0
|
133 public $feedIcons = [];
|
Chris@0
|
134
|
Chris@0
|
135 // Exposed widget input
|
Chris@0
|
136
|
Chris@0
|
137 /**
|
Chris@0
|
138 * All the form data from $form_state->getValues().
|
Chris@0
|
139 *
|
Chris@0
|
140 * @var array
|
Chris@0
|
141 */
|
Chris@0
|
142 public $exposed_data = [];
|
Chris@0
|
143
|
Chris@0
|
144 /**
|
Chris@0
|
145 * An array of input values from exposed forms.
|
Chris@0
|
146 *
|
Chris@0
|
147 * @var array
|
Chris@0
|
148 */
|
Chris@0
|
149 protected $exposed_input = [];
|
Chris@0
|
150
|
Chris@0
|
151 /**
|
Chris@0
|
152 * Exposed widget input directly from the $form_state->getValues().
|
Chris@0
|
153 *
|
Chris@0
|
154 * @var array
|
Chris@0
|
155 */
|
Chris@0
|
156 public $exposed_raw_input = [];
|
Chris@0
|
157
|
Chris@0
|
158 /**
|
Chris@0
|
159 * Used to store views that were previously running if we recurse.
|
Chris@0
|
160 *
|
Chris@0
|
161 * @var \Drupal\views\ViewExecutable[]
|
Chris@0
|
162 */
|
Chris@0
|
163 public $old_view = [];
|
Chris@0
|
164
|
Chris@0
|
165 /**
|
Chris@0
|
166 * To avoid recursion in views embedded into areas.
|
Chris@0
|
167 *
|
Chris@0
|
168 * @var \Drupal\views\ViewExecutable[]
|
Chris@0
|
169 */
|
Chris@0
|
170 public $parent_views = [];
|
Chris@0
|
171
|
Chris@0
|
172 /**
|
Chris@0
|
173 * Whether this view is an attachment to another view.
|
Chris@0
|
174 *
|
Chris@0
|
175 * @var bool
|
Chris@0
|
176 */
|
Chris@0
|
177 public $is_attachment = NULL;
|
Chris@0
|
178
|
Chris@0
|
179 /**
|
Chris@0
|
180 * Identifier of the current display.
|
Chris@0
|
181 *
|
Chris@0
|
182 * @var string
|
Chris@0
|
183 */
|
Chris@0
|
184 public $current_display;
|
Chris@0
|
185
|
Chris@0
|
186 /**
|
Chris@0
|
187 * Where the $query object will reside.
|
Chris@0
|
188 *
|
Chris@0
|
189 * @var \Drupal\views\Plugin\views\query\QueryPluginBase
|
Chris@0
|
190 */
|
Chris@0
|
191 public $query = NULL;
|
Chris@0
|
192
|
Chris@0
|
193 /**
|
Chris@0
|
194 * The used pager plugin used by the current executed view.
|
Chris@0
|
195 *
|
Chris@0
|
196 * @var \Drupal\views\Plugin\views\pager\PagerPluginBase
|
Chris@0
|
197 */
|
Chris@0
|
198 public $pager = NULL;
|
Chris@0
|
199
|
Chris@0
|
200 /**
|
Chris@0
|
201 * The current used display plugin.
|
Chris@0
|
202 *
|
Chris@0
|
203 * @var \Drupal\views\Plugin\views\display\DisplayPluginBase
|
Chris@0
|
204 */
|
Chris@0
|
205 public $display_handler;
|
Chris@0
|
206
|
Chris@0
|
207 /**
|
Chris@0
|
208 * The list of used displays of the view.
|
Chris@0
|
209 *
|
Chris@0
|
210 * An array containing Drupal\views\Plugin\views\display\DisplayPluginBase
|
Chris@0
|
211 * objects.
|
Chris@0
|
212 *
|
Chris@0
|
213 * @var \Drupal\views\DisplayPluginCollection
|
Chris@0
|
214 */
|
Chris@0
|
215 public $displayHandlers;
|
Chris@0
|
216
|
Chris@0
|
217 /**
|
Chris@0
|
218 * The current used style plugin.
|
Chris@0
|
219 *
|
Chris@0
|
220 * @var \Drupal\views\Plugin\views\style\StylePluginBase
|
Chris@0
|
221 */
|
Chris@0
|
222 public $style_plugin;
|
Chris@0
|
223
|
Chris@0
|
224 /**
|
Chris@0
|
225 * The current used row plugin, if the style plugin supports row plugins.
|
Chris@0
|
226 *
|
Chris@0
|
227 * @var \Drupal\views\Plugin\views\row\RowPluginBase
|
Chris@0
|
228 */
|
Chris@0
|
229 public $rowPlugin;
|
Chris@0
|
230
|
Chris@0
|
231 /**
|
Chris@0
|
232 * Stores the current active row while rendering.
|
Chris@0
|
233 *
|
Chris@0
|
234 * @var int
|
Chris@0
|
235 */
|
Chris@0
|
236 public $row_index;
|
Chris@0
|
237
|
Chris@0
|
238 /**
|
Chris@0
|
239 * Allow to override the url of the current view.
|
Chris@0
|
240 *
|
Chris@0
|
241 * @var \Drupal\Core\Url
|
Chris@0
|
242 */
|
Chris@0
|
243 public $override_url;
|
Chris@0
|
244
|
Chris@0
|
245 /**
|
Chris@0
|
246 * Allow to override the path used for generated urls.
|
Chris@0
|
247 *
|
Chris@0
|
248 * @var string
|
Chris@0
|
249 */
|
Chris@0
|
250 public $override_path = NULL;
|
Chris@0
|
251
|
Chris@0
|
252 /**
|
Chris@0
|
253 * Allow to override the used database which is used for this query.
|
Chris@0
|
254 *
|
Chris@0
|
255 * @var bool
|
Chris@0
|
256 */
|
Chris@0
|
257 public $base_database = NULL;
|
Chris@0
|
258
|
Chris@0
|
259 // Handlers which are active on this view.
|
Chris@0
|
260
|
Chris@0
|
261 /**
|
Chris@0
|
262 * Stores the field handlers which are initialized on this view.
|
Chris@0
|
263 *
|
Chris@0
|
264 * @var \Drupal\views\Plugin\views\field\FieldPluginBase[]
|
Chris@0
|
265 */
|
Chris@0
|
266 public $field;
|
Chris@0
|
267
|
Chris@0
|
268 /**
|
Chris@0
|
269 * Stores the argument handlers which are initialized on this view.
|
Chris@0
|
270 *
|
Chris@0
|
271 * @var \Drupal\views\Plugin\views\argument\ArgumentPluginBase[]
|
Chris@0
|
272 */
|
Chris@0
|
273 public $argument;
|
Chris@0
|
274
|
Chris@0
|
275 /**
|
Chris@0
|
276 * Stores the sort handlers which are initialized on this view.
|
Chris@0
|
277 *
|
Chris@0
|
278 * @var \Drupal\views\Plugin\views\sort\SortPluginBase[]
|
Chris@0
|
279 */
|
Chris@0
|
280 public $sort;
|
Chris@0
|
281
|
Chris@0
|
282 /**
|
Chris@0
|
283 * Stores the filter handlers which are initialized on this view.
|
Chris@0
|
284 *
|
Chris@0
|
285 * @var \Drupal\views\Plugin\views\filter\FilterPluginBase[]
|
Chris@0
|
286 */
|
Chris@0
|
287 public $filter;
|
Chris@0
|
288
|
Chris@0
|
289 /**
|
Chris@0
|
290 * Stores the relationship handlers which are initialized on this view.
|
Chris@0
|
291 *
|
Chris@0
|
292 * @var \Drupal\views\Plugin\views\relationship\RelationshipPluginBase[]
|
Chris@0
|
293 */
|
Chris@0
|
294 public $relationship;
|
Chris@0
|
295
|
Chris@0
|
296 /**
|
Chris@0
|
297 * Stores the area handlers for the header which are initialized on this view.
|
Chris@0
|
298 *
|
Chris@0
|
299 * @var \Drupal\views\Plugin\views\area\AreaPluginBase[]
|
Chris@0
|
300 */
|
Chris@0
|
301 public $header;
|
Chris@0
|
302
|
Chris@0
|
303 /**
|
Chris@0
|
304 * Stores the area handlers for the footer which are initialized on this view.
|
Chris@0
|
305 *
|
Chris@0
|
306 * @var \Drupal\views\Plugin\views\area\AreaPluginBase[]
|
Chris@0
|
307 */
|
Chris@0
|
308 public $footer;
|
Chris@0
|
309
|
Chris@0
|
310 /**
|
Chris@0
|
311 * Stores the area handlers for the empty text which are initialized on this view.
|
Chris@0
|
312 *
|
Chris@0
|
313 * An array containing Drupal\views\Plugin\views\area\AreaPluginBase objects.
|
Chris@0
|
314 *
|
Chris@0
|
315 * @var \Drupal\views\Plugin\views\area\AreaPluginBase[]
|
Chris@0
|
316 */
|
Chris@0
|
317 public $empty;
|
Chris@0
|
318
|
Chris@0
|
319 /**
|
Chris@0
|
320 * Stores the current response object.
|
Chris@0
|
321 *
|
Chris@0
|
322 * @var \Symfony\Component\HttpFoundation\Response
|
Chris@0
|
323 */
|
Chris@0
|
324 protected $response = NULL;
|
Chris@0
|
325
|
Chris@0
|
326 /**
|
Chris@0
|
327 * Stores the current request object.
|
Chris@0
|
328 *
|
Chris@0
|
329 * @var \Symfony\Component\HttpFoundation\Request
|
Chris@0
|
330 */
|
Chris@0
|
331 protected $request;
|
Chris@0
|
332
|
Chris@0
|
333 /**
|
Chris@14
|
334 * Does this view already have loaded its handlers.
|
Chris@0
|
335 *
|
Chris@0
|
336 * @todo Group with other static properties.
|
Chris@0
|
337 *
|
Chris@0
|
338 * @var bool
|
Chris@0
|
339 */
|
Chris@0
|
340 public $inited;
|
Chris@0
|
341
|
Chris@0
|
342 /**
|
Chris@0
|
343 * The rendered output of the exposed form.
|
Chris@0
|
344 *
|
Chris@0
|
345 * @var string
|
Chris@0
|
346 */
|
Chris@0
|
347 public $exposed_widgets;
|
Chris@0
|
348
|
Chris@0
|
349 /**
|
Chris@0
|
350 * If this view has been previewed.
|
Chris@0
|
351 *
|
Chris@0
|
352 * @var bool
|
Chris@0
|
353 */
|
Chris@0
|
354 public $preview;
|
Chris@0
|
355
|
Chris@0
|
356 /**
|
Chris@0
|
357 * Force the query to calculate the total number of results.
|
Chris@0
|
358 *
|
Chris@0
|
359 * @todo Move to the query.
|
Chris@0
|
360 *
|
Chris@0
|
361 * @var bool
|
Chris@0
|
362 */
|
Chris@0
|
363 public $get_total_rows;
|
Chris@0
|
364
|
Chris@0
|
365 /**
|
Chris@0
|
366 * Indicates if the sorts have been built.
|
Chris@0
|
367 *
|
Chris@0
|
368 * @todo Group with other static properties.
|
Chris@0
|
369 *
|
Chris@0
|
370 * @var bool
|
Chris@0
|
371 */
|
Chris@0
|
372 public $build_sort;
|
Chris@0
|
373
|
Chris@0
|
374 /**
|
Chris@0
|
375 * Stores the many-to-one tables for performance.
|
Chris@0
|
376 *
|
Chris@0
|
377 * @var array
|
Chris@0
|
378 */
|
Chris@0
|
379 public $many_to_one_tables;
|
Chris@0
|
380
|
Chris@0
|
381 /**
|
Chris@0
|
382 * A unique identifier which allows to update multiple views output via js.
|
Chris@0
|
383 *
|
Chris@0
|
384 * @var string
|
Chris@0
|
385 */
|
Chris@0
|
386 public $dom_id;
|
Chris@0
|
387
|
Chris@0
|
388 /**
|
Chris@0
|
389 * A render array container to store render related information.
|
Chris@0
|
390 *
|
Chris@0
|
391 * For example you can alter the array and attach some asset library or JS
|
Chris@0
|
392 * settings via the #attached key. This is the required way to add custom
|
Chris@0
|
393 * CSS or JS.
|
Chris@0
|
394 *
|
Chris@0
|
395 * @var array
|
Chris@0
|
396 *
|
Chris@0
|
397 * @see \Drupal\Core\Render\AttachmentsResponseProcessorInterface::processAttachments()
|
Chris@0
|
398 */
|
Chris@0
|
399 public $element = [
|
Chris@0
|
400 '#attached' => [
|
Chris@0
|
401 'library' => ['views/views.module'],
|
Chris@0
|
402 'drupalSettings' => [],
|
Chris@0
|
403 ],
|
Chris@0
|
404 '#cache' => [],
|
Chris@0
|
405 ];
|
Chris@0
|
406
|
Chris@0
|
407 /**
|
Chris@0
|
408 * The current user.
|
Chris@0
|
409 *
|
Chris@0
|
410 * @var \Drupal\Core\Session\AccountInterface
|
Chris@0
|
411 */
|
Chris@0
|
412 protected $user;
|
Chris@0
|
413
|
Chris@0
|
414 /**
|
Chris@0
|
415 * Should the admin links be shown on the rendered view.
|
Chris@0
|
416 *
|
Chris@0
|
417 * @var bool
|
Chris@0
|
418 */
|
Chris@0
|
419 protected $showAdminLinks;
|
Chris@0
|
420
|
Chris@0
|
421 /**
|
Chris@0
|
422 * The views data.
|
Chris@0
|
423 *
|
Chris@0
|
424 * @var \Drupal\views\ViewsData
|
Chris@0
|
425 */
|
Chris@0
|
426 protected $viewsData;
|
Chris@0
|
427
|
Chris@0
|
428 /**
|
Chris@0
|
429 * The route provider.
|
Chris@0
|
430 *
|
Chris@0
|
431 * @var \Drupal\Core\Routing\RouteProviderInterface
|
Chris@0
|
432 */
|
Chris@0
|
433 protected $routeProvider;
|
Chris@0
|
434
|
Chris@0
|
435 /**
|
Chris@0
|
436 * The entity type of the base table, if available.
|
Chris@0
|
437 *
|
Chris@0
|
438 * @var \Drupal\Core\Entity\EntityTypeInterface|false
|
Chris@0
|
439 */
|
Chris@0
|
440 protected $baseEntityType;
|
Chris@0
|
441
|
Chris@0
|
442 /**
|
Chris@0
|
443 * Holds all necessary data for proper unserialization.
|
Chris@0
|
444 *
|
Chris@0
|
445 * @var array
|
Chris@0
|
446 */
|
Chris@0
|
447 protected $serializationData;
|
Chris@0
|
448
|
Chris@0
|
449 /**
|
Chris@0
|
450 * Constructs a new ViewExecutable object.
|
Chris@0
|
451 *
|
Chris@0
|
452 * @param \Drupal\views\ViewEntityInterface $storage
|
Chris@0
|
453 * The view config entity the actual information is stored on.
|
Chris@0
|
454 * @param \Drupal\Core\Session\AccountInterface $user
|
Chris@0
|
455 * The current user.
|
Chris@0
|
456 * @param \Drupal\views\ViewsData $views_data
|
Chris@0
|
457 * The views data.
|
Chris@0
|
458 * @param \Drupal\Core\Routing\RouteProviderInterface $route_provider
|
Chris@0
|
459 * The route provider.
|
Chris@0
|
460 */
|
Chris@0
|
461 public function __construct(ViewEntityInterface $storage, AccountInterface $user, ViewsData $views_data, RouteProviderInterface $route_provider) {
|
Chris@0
|
462 // Reference the storage and the executable to each other.
|
Chris@0
|
463 $this->storage = $storage;
|
Chris@0
|
464 $this->storage->set('executable', $this);
|
Chris@0
|
465 $this->user = $user;
|
Chris@0
|
466 $this->viewsData = $views_data;
|
Chris@0
|
467 $this->routeProvider = $route_provider;
|
Chris@0
|
468 }
|
Chris@0
|
469
|
Chris@0
|
470 /**
|
Chris@0
|
471 * Returns the identifier.
|
Chris@0
|
472 *
|
Chris@0
|
473 * @return string|null
|
Chris@0
|
474 * The entity identifier, or NULL if the object does not yet have an
|
Chris@0
|
475 * identifier.
|
Chris@0
|
476 */
|
Chris@0
|
477 public function id() {
|
Chris@0
|
478 return $this->storage->id();
|
Chris@0
|
479 }
|
Chris@0
|
480
|
Chris@0
|
481 /**
|
Chris@0
|
482 * Saves the view.
|
Chris@0
|
483 */
|
Chris@0
|
484 public function save() {
|
Chris@0
|
485 $this->storage->save();
|
Chris@0
|
486 }
|
Chris@0
|
487
|
Chris@0
|
488 /**
|
Chris@0
|
489 * Sets the arguments for the view.
|
Chris@0
|
490 *
|
Chris@0
|
491 * @param array $args
|
Chris@0
|
492 * The arguments passed to the view.
|
Chris@0
|
493 */
|
Chris@0
|
494 public function setArguments(array $args) {
|
Chris@0
|
495 // The array keys of the arguments will be incorrect if set by
|
Chris@0
|
496 // views_embed_view() or \Drupal\views\ViewExecutable:preview().
|
Chris@0
|
497 $this->args = array_values($args);
|
Chris@0
|
498 }
|
Chris@0
|
499
|
Chris@0
|
500 /**
|
Chris@0
|
501 * Expands the list of used cache contexts for the view.
|
Chris@0
|
502 *
|
Chris@0
|
503 * @param string $cache_context
|
Chris@0
|
504 * The additional cache context.
|
Chris@0
|
505 *
|
Chris@0
|
506 * @return $this
|
Chris@0
|
507 */
|
Chris@0
|
508 public function addCacheContext($cache_context) {
|
Chris@0
|
509 $this->element['#cache']['contexts'][] = $cache_context;
|
Chris@0
|
510
|
Chris@0
|
511 return $this;
|
Chris@0
|
512 }
|
Chris@0
|
513
|
Chris@0
|
514 /**
|
Chris@0
|
515 * Sets the current page for the pager.
|
Chris@0
|
516 *
|
Chris@0
|
517 * @param int $page
|
Chris@0
|
518 * The current page.
|
Chris@0
|
519 */
|
Chris@0
|
520 public function setCurrentPage($page) {
|
Chris@0
|
521 $this->current_page = $page;
|
Chris@0
|
522
|
Chris@0
|
523 // Calls like ::unserialize() might call this method without a proper $page.
|
Chris@0
|
524 // Also check whether the element is pre rendered. At that point, the cache
|
Chris@0
|
525 // keys cannot longer be manipulated.
|
Chris@0
|
526 if ($page !== NULL && empty($this->element['#pre_rendered'])) {
|
Chris@0
|
527 $this->element['#cache']['keys'][] = 'page:' . $page;
|
Chris@0
|
528 }
|
Chris@0
|
529
|
Chris@0
|
530 // If the pager is already initialized, pass it through to the pager.
|
Chris@0
|
531 if (!empty($this->pager)) {
|
Chris@0
|
532 return $this->pager->setCurrentPage($page);
|
Chris@0
|
533 }
|
Chris@0
|
534 }
|
Chris@0
|
535
|
Chris@0
|
536 /**
|
Chris@0
|
537 * Gets the current page from the pager.
|
Chris@0
|
538 *
|
Chris@0
|
539 * @return int
|
Chris@0
|
540 * The current page.
|
Chris@0
|
541 */
|
Chris@0
|
542 public function getCurrentPage() {
|
Chris@0
|
543 // If the pager is already initialized, pass it through to the pager.
|
Chris@0
|
544 if (!empty($this->pager)) {
|
Chris@0
|
545 return $this->pager->getCurrentPage();
|
Chris@0
|
546 }
|
Chris@0
|
547
|
Chris@0
|
548 if (isset($this->current_page)) {
|
Chris@0
|
549 return $this->current_page;
|
Chris@0
|
550 }
|
Chris@0
|
551 }
|
Chris@0
|
552
|
Chris@0
|
553 /**
|
Chris@0
|
554 * Gets the items per page from the pager.
|
Chris@0
|
555 *
|
Chris@0
|
556 * @return int
|
Chris@0
|
557 * The items per page.
|
Chris@0
|
558 */
|
Chris@0
|
559 public function getItemsPerPage() {
|
Chris@0
|
560 // If the pager is already initialized, pass it through to the pager.
|
Chris@0
|
561 if (!empty($this->pager)) {
|
Chris@0
|
562 return $this->pager->getItemsPerPage();
|
Chris@0
|
563 }
|
Chris@0
|
564
|
Chris@0
|
565 if (isset($this->items_per_page)) {
|
Chris@0
|
566 return $this->items_per_page;
|
Chris@0
|
567 }
|
Chris@0
|
568 }
|
Chris@0
|
569
|
Chris@0
|
570 /**
|
Chris@0
|
571 * Sets the items per page on the pager.
|
Chris@0
|
572 *
|
Chris@0
|
573 * @param int $items_per_page
|
Chris@0
|
574 * The items per page.
|
Chris@0
|
575 */
|
Chris@0
|
576 public function setItemsPerPage($items_per_page) {
|
Chris@0
|
577 // Check whether the element is pre rendered. At that point, the cache keys
|
Chris@0
|
578 // cannot longer be manipulated.
|
Chris@0
|
579 if (empty($this->element['#pre_rendered'])) {
|
Chris@0
|
580 $this->element['#cache']['keys'][] = 'items_per_page:' . $items_per_page;
|
Chris@0
|
581 }
|
Chris@0
|
582 $this->items_per_page = $items_per_page;
|
Chris@0
|
583
|
Chris@0
|
584 // If the pager is already initialized, pass it through to the pager.
|
Chris@0
|
585 if (!empty($this->pager)) {
|
Chris@0
|
586 $this->pager->setItemsPerPage($items_per_page);
|
Chris@0
|
587 }
|
Chris@0
|
588 }
|
Chris@0
|
589
|
Chris@0
|
590 /**
|
Chris@0
|
591 * Gets the pager offset from the pager.
|
Chris@0
|
592 *
|
Chris@0
|
593 * @return int
|
Chris@0
|
594 * The pager offset.
|
Chris@0
|
595 */
|
Chris@0
|
596 public function getOffset() {
|
Chris@0
|
597 // If the pager is already initialized, pass it through to the pager.
|
Chris@0
|
598 if (!empty($this->pager)) {
|
Chris@0
|
599 return $this->pager->getOffset();
|
Chris@0
|
600 }
|
Chris@0
|
601
|
Chris@0
|
602 if (isset($this->offset)) {
|
Chris@0
|
603 return $this->offset;
|
Chris@0
|
604 }
|
Chris@0
|
605 }
|
Chris@0
|
606
|
Chris@0
|
607 /**
|
Chris@0
|
608 * Sets the offset on the pager.
|
Chris@0
|
609 *
|
Chris@0
|
610 * @param int $offset
|
Chris@0
|
611 * The pager offset.
|
Chris@0
|
612 */
|
Chris@0
|
613 public function setOffset($offset) {
|
Chris@0
|
614 // Check whether the element is pre rendered. At that point, the cache keys
|
Chris@0
|
615 // cannot longer be manipulated.
|
Chris@0
|
616 if (empty($this->element['#pre_rendered'])) {
|
Chris@0
|
617 $this->element['#cache']['keys'][] = 'offset:' . $offset;
|
Chris@0
|
618 }
|
Chris@0
|
619
|
Chris@0
|
620 $this->offset = $offset;
|
Chris@0
|
621
|
Chris@0
|
622 // If the pager is already initialized, pass it through to the pager.
|
Chris@0
|
623 if (!empty($this->pager)) {
|
Chris@0
|
624 $this->pager->setOffset($offset);
|
Chris@0
|
625 }
|
Chris@0
|
626 }
|
Chris@0
|
627
|
Chris@0
|
628 /**
|
Chris@0
|
629 * Determines if the view uses a pager.
|
Chris@0
|
630 *
|
Chris@0
|
631 * @return bool
|
Chris@0
|
632 * TRUE if the view uses a pager, FALSE otherwise.
|
Chris@0
|
633 */
|
Chris@0
|
634 public function usePager() {
|
Chris@0
|
635 if (!empty($this->pager)) {
|
Chris@0
|
636 return $this->pager->usePager();
|
Chris@0
|
637 }
|
Chris@0
|
638 }
|
Chris@0
|
639
|
Chris@0
|
640 /**
|
Chris@0
|
641 * Sets whether or not AJAX should be used.
|
Chris@0
|
642 *
|
Chris@0
|
643 * If AJAX is used, paging, table sorting, and exposed filters will be fetched
|
Chris@0
|
644 * via an AJAX call rather than a page refresh.
|
Chris@0
|
645 *
|
Chris@0
|
646 * @param bool $ajax_enabled
|
Chris@0
|
647 * TRUE if AJAX should be used, FALSE otherwise.
|
Chris@0
|
648 */
|
Chris@0
|
649 public function setAjaxEnabled($ajax_enabled) {
|
Chris@0
|
650 $this->ajaxEnabled = (bool) $ajax_enabled;
|
Chris@0
|
651 }
|
Chris@0
|
652
|
Chris@0
|
653 /**
|
Chris@0
|
654 * Determines whether or not AJAX should be used.
|
Chris@0
|
655 *
|
Chris@0
|
656 * @return bool
|
Chris@0
|
657 * TRUE if AJAX is enabled, FALSE otherwise.
|
Chris@0
|
658 */
|
Chris@0
|
659 public function ajaxEnabled() {
|
Chris@0
|
660 return $this->ajaxEnabled;
|
Chris@0
|
661 }
|
Chris@0
|
662
|
Chris@0
|
663 /**
|
Chris@0
|
664 * Sets the exposed filters input to an array.
|
Chris@0
|
665 *
|
Chris@0
|
666 * @param string[] $filters
|
Chris@0
|
667 * The values taken from the view's exposed filters and sorts.
|
Chris@0
|
668 */
|
Chris@0
|
669 public function setExposedInput($filters) {
|
Chris@0
|
670 $this->exposed_input = $filters;
|
Chris@0
|
671 }
|
Chris@0
|
672
|
Chris@0
|
673 /**
|
Chris@0
|
674 * Figures out what the exposed input for this view is.
|
Chris@0
|
675 *
|
Chris@0
|
676 * They will be taken from \Drupal::request()->query or from
|
Chris@0
|
677 * something previously set on the view.
|
Chris@0
|
678 *
|
Chris@0
|
679 * @return string[]
|
Chris@0
|
680 * An array containing the exposed input values keyed by the filter and sort
|
Chris@0
|
681 * name.
|
Chris@0
|
682 *
|
Chris@0
|
683 * @see self::setExposedInput()
|
Chris@0
|
684 */
|
Chris@0
|
685 public function getExposedInput() {
|
Chris@0
|
686 // Fill our input either from \Drupal::request()->query or from something
|
Chris@0
|
687 // previously set on the view.
|
Chris@0
|
688 if (empty($this->exposed_input)) {
|
Chris@0
|
689 // Ensure that we can call the method at any point in time.
|
Chris@0
|
690 $this->initDisplay();
|
Chris@0
|
691
|
Chris@0
|
692 $this->exposed_input = \Drupal::request()->query->all();
|
Chris@0
|
693 // unset items that are definitely not our input:
|
Chris@0
|
694 foreach (['page', 'q'] as $key) {
|
Chris@0
|
695 if (isset($this->exposed_input[$key])) {
|
Chris@0
|
696 unset($this->exposed_input[$key]);
|
Chris@0
|
697 }
|
Chris@0
|
698 }
|
Chris@0
|
699
|
Chris@0
|
700 // If we have no input at all, check for remembered input via session.
|
Chris@0
|
701
|
Chris@0
|
702 // If filters are not overridden, store the 'remember' settings on the
|
Chris@0
|
703 // default display. If they are, store them on this display. This way,
|
Chris@0
|
704 // multiple displays in the same view can share the same filters and
|
Chris@0
|
705 // remember settings.
|
Chris@0
|
706 $display_id = ($this->display_handler->isDefaulted('filters')) ? 'default' : $this->current_display;
|
Chris@0
|
707
|
Chris@0
|
708 if (empty($this->exposed_input) && !empty($_SESSION['views'][$this->storage->id()][$display_id])) {
|
Chris@0
|
709 $this->exposed_input = $_SESSION['views'][$this->storage->id()][$display_id];
|
Chris@0
|
710 }
|
Chris@0
|
711 }
|
Chris@0
|
712
|
Chris@0
|
713 return $this->exposed_input;
|
Chris@0
|
714 }
|
Chris@0
|
715
|
Chris@0
|
716 /**
|
Chris@0
|
717 * Sets the display for this view and initializes the display handler.
|
Chris@0
|
718 *
|
Chris@0
|
719 * @return true
|
Chris@0
|
720 * Always returns TRUE.
|
Chris@0
|
721 */
|
Chris@0
|
722 public function initDisplay() {
|
Chris@0
|
723 if (isset($this->current_display)) {
|
Chris@0
|
724 return TRUE;
|
Chris@0
|
725 }
|
Chris@0
|
726
|
Chris@0
|
727 // Initialize the display cache array.
|
Chris@0
|
728 $this->displayHandlers = new DisplayPluginCollection($this, Views::pluginManager('display'));
|
Chris@0
|
729
|
Chris@0
|
730 $this->current_display = 'default';
|
Chris@0
|
731 $this->display_handler = $this->displayHandlers->get('default');
|
Chris@0
|
732
|
Chris@0
|
733 return TRUE;
|
Chris@0
|
734 }
|
Chris@0
|
735
|
Chris@0
|
736 /**
|
Chris@0
|
737 * Gets the first display that is accessible to the user.
|
Chris@0
|
738 *
|
Chris@0
|
739 * @param array|string $displays
|
Chris@0
|
740 * Either a single display id or an array of display ids.
|
Chris@0
|
741 *
|
Chris@0
|
742 * @return string
|
Chris@0
|
743 * The first accessible display id, at least default.
|
Chris@0
|
744 */
|
Chris@0
|
745 public function chooseDisplay($displays) {
|
Chris@0
|
746 if (!is_array($displays)) {
|
Chris@0
|
747 return $displays;
|
Chris@0
|
748 }
|
Chris@0
|
749
|
Chris@0
|
750 $this->initDisplay();
|
Chris@0
|
751
|
Chris@0
|
752 foreach ($displays as $display_id) {
|
Chris@0
|
753 if ($this->displayHandlers->get($display_id)->access($this->user)) {
|
Chris@0
|
754 return $display_id;
|
Chris@0
|
755 }
|
Chris@0
|
756 }
|
Chris@0
|
757
|
Chris@0
|
758 return 'default';
|
Chris@0
|
759 }
|
Chris@0
|
760
|
Chris@0
|
761 /**
|
Chris@0
|
762 * Gets the current display plugin.
|
Chris@0
|
763 *
|
Chris@0
|
764 * @return \Drupal\views\Plugin\views\display\DisplayPluginBase
|
Chris@0
|
765 * The current display plugin.
|
Chris@0
|
766 */
|
Chris@0
|
767 public function getDisplay() {
|
Chris@0
|
768 if (!isset($this->display_handler)) {
|
Chris@0
|
769 $this->initDisplay();
|
Chris@0
|
770 }
|
Chris@0
|
771
|
Chris@0
|
772 return $this->display_handler;
|
Chris@0
|
773 }
|
Chris@0
|
774
|
Chris@0
|
775 /**
|
Chris@0
|
776 * Sets the current display.
|
Chris@0
|
777 *
|
Chris@0
|
778 * @param string $display_id
|
Chris@0
|
779 * The ID of the display to mark as current.
|
Chris@0
|
780 *
|
Chris@0
|
781 * @return bool
|
Chris@0
|
782 * TRUE if the display was correctly set, FALSE otherwise.
|
Chris@0
|
783 */
|
Chris@0
|
784 public function setDisplay($display_id = NULL) {
|
Chris@0
|
785 // If we have not already initialized the display, do so.
|
Chris@0
|
786 if (!isset($this->current_display)) {
|
Chris@0
|
787 // This will set the default display and instantiate the default display
|
Chris@0
|
788 // plugin.
|
Chris@0
|
789 $this->initDisplay();
|
Chris@0
|
790 }
|
Chris@0
|
791
|
Chris@0
|
792 // If no display ID is passed, we either have initialized the default or
|
Chris@0
|
793 // already have a display set.
|
Chris@0
|
794 if (!isset($display_id)) {
|
Chris@0
|
795 return TRUE;
|
Chris@0
|
796 }
|
Chris@0
|
797
|
Chris@0
|
798 $display_id = $this->chooseDisplay($display_id);
|
Chris@0
|
799
|
Chris@0
|
800 // Ensure the requested display exists.
|
Chris@0
|
801 if (!$this->displayHandlers->has($display_id)) {
|
Chris@0
|
802 trigger_error(new FormattableMarkup('setDisplay() called with invalid display ID "@display".', ['@display' => $display_id]), E_USER_WARNING);
|
Chris@0
|
803 return FALSE;
|
Chris@0
|
804 }
|
Chris@0
|
805
|
Chris@0
|
806 // Reset if the display has changed. It could be called multiple times for
|
Chris@0
|
807 // the same display, especially in the UI.
|
Chris@0
|
808 if ($this->current_display != $display_id) {
|
Chris@0
|
809 // Set the current display.
|
Chris@0
|
810 $this->current_display = $display_id;
|
Chris@0
|
811
|
Chris@0
|
812 // Reset the style and row plugins.
|
Chris@0
|
813 $this->style_plugin = NULL;
|
Chris@0
|
814 $this->plugin_name = NULL;
|
Chris@0
|
815 $this->rowPlugin = NULL;
|
Chris@0
|
816 }
|
Chris@0
|
817
|
Chris@0
|
818 if ($display = $this->displayHandlers->get($display_id)) {
|
Chris@0
|
819 // Set a shortcut.
|
Chris@0
|
820 $this->display_handler = $display;
|
Chris@0
|
821 return TRUE;
|
Chris@0
|
822 }
|
Chris@0
|
823
|
Chris@0
|
824 return FALSE;
|
Chris@0
|
825 }
|
Chris@0
|
826
|
Chris@0
|
827 /**
|
Chris@0
|
828 * Creates a new display and a display handler instance for it.
|
Chris@0
|
829 *
|
Chris@0
|
830 * @param string $plugin_id
|
Chris@0
|
831 * (optional) The plugin type from the Views plugin annotation. Defaults to
|
Chris@0
|
832 * 'page'.
|
Chris@0
|
833 * @param string $title
|
Chris@0
|
834 * (optional) The title of the display. Defaults to NULL.
|
Chris@0
|
835 * @param string $id
|
Chris@0
|
836 * (optional) The ID to use, e.g., 'default', 'page_1', 'block_2'. Defaults
|
Chris@0
|
837 * to NULL.
|
Chris@0
|
838 *
|
Chris@0
|
839 * @return \Drupal\views\Plugin\views\display\DisplayPluginBase
|
Chris@0
|
840 * A new display plugin instance if executable is set, the new display ID
|
Chris@0
|
841 * otherwise.
|
Chris@0
|
842 */
|
Chris@0
|
843 public function newDisplay($plugin_id = 'page', $title = NULL, $id = NULL) {
|
Chris@0
|
844 $this->initDisplay();
|
Chris@0
|
845
|
Chris@0
|
846 $id = $this->storage->addDisplay($plugin_id, $title, $id);
|
Chris@0
|
847 $this->displayHandlers->addInstanceId($id);
|
Chris@0
|
848
|
Chris@0
|
849 $display = $this->displayHandlers->get($id);
|
Chris@0
|
850 $display->newDisplay();
|
Chris@0
|
851 return $display;
|
Chris@0
|
852 }
|
Chris@0
|
853
|
Chris@0
|
854 /**
|
Chris@0
|
855 * Gets the current style plugin.
|
Chris@0
|
856 *
|
Chris@0
|
857 * @return \Drupal\views\Plugin\views\style\StylePluginBase
|
Chris@0
|
858 * The current style plugin.
|
Chris@0
|
859 */
|
Chris@0
|
860 public function getStyle() {
|
Chris@0
|
861 if (!isset($this->style_plugin)) {
|
Chris@0
|
862 $this->initStyle();
|
Chris@0
|
863 }
|
Chris@0
|
864
|
Chris@0
|
865 return $this->style_plugin;
|
Chris@0
|
866 }
|
Chris@0
|
867
|
Chris@0
|
868 /**
|
Chris@0
|
869 * Finds and initializes the style plugin.
|
Chris@0
|
870 *
|
Chris@0
|
871 * Note that arguments may have changed which style plugin we use, so
|
Chris@0
|
872 * check the view object first, then ask the display handler.
|
Chris@0
|
873 *
|
Chris@0
|
874 * @return bool
|
Chris@0
|
875 * TRUE if the style plugin was or could be initialized, FALSE otherwise.
|
Chris@0
|
876 */
|
Chris@0
|
877 public function initStyle() {
|
Chris@0
|
878 if (isset($this->style_plugin)) {
|
Chris@0
|
879 return TRUE;
|
Chris@0
|
880 }
|
Chris@0
|
881
|
Chris@0
|
882 $this->style_plugin = $this->display_handler->getPlugin('style');
|
Chris@0
|
883
|
Chris@0
|
884 if (empty($this->style_plugin)) {
|
Chris@0
|
885 return FALSE;
|
Chris@0
|
886 }
|
Chris@0
|
887
|
Chris@0
|
888 return TRUE;
|
Chris@0
|
889 }
|
Chris@0
|
890
|
Chris@0
|
891 /**
|
Chris@0
|
892 * Acquires and attaches all of the handlers.
|
Chris@0
|
893 */
|
Chris@0
|
894 public function initHandlers() {
|
Chris@0
|
895 $this->initDisplay();
|
Chris@0
|
896 if (empty($this->inited)) {
|
Chris@0
|
897 foreach ($this::getHandlerTypes() as $key => $info) {
|
Chris@0
|
898 $this->_initHandler($key, $info);
|
Chris@0
|
899 }
|
Chris@0
|
900 $this->inited = TRUE;
|
Chris@0
|
901 }
|
Chris@0
|
902 }
|
Chris@0
|
903
|
Chris@0
|
904 /**
|
Chris@0
|
905 * Gets the current pager plugin.
|
Chris@0
|
906 *
|
Chris@0
|
907 * @return \Drupal\views\Plugin\views\pager\PagerPluginBase
|
Chris@0
|
908 * The current pager plugin.
|
Chris@0
|
909 */
|
Chris@0
|
910 public function getPager() {
|
Chris@0
|
911 if (!isset($this->pager)) {
|
Chris@0
|
912 $this->initPager();
|
Chris@0
|
913 }
|
Chris@0
|
914
|
Chris@0
|
915 return $this->pager;
|
Chris@0
|
916 }
|
Chris@0
|
917
|
Chris@0
|
918 /**
|
Chris@0
|
919 * Initializes the pager.
|
Chris@0
|
920 *
|
Chris@0
|
921 * Like style initialization, pager initialization is held until late to allow
|
Chris@0
|
922 * for overrides.
|
Chris@0
|
923 */
|
Chris@0
|
924 public function initPager() {
|
Chris@0
|
925 if (!isset($this->pager)) {
|
Chris@0
|
926 $this->pager = $this->display_handler->getPlugin('pager');
|
Chris@0
|
927
|
Chris@18
|
928 if ($this->usePager()) {
|
Chris@0
|
929 $this->pager->setCurrentPage($this->current_page);
|
Chris@0
|
930 }
|
Chris@0
|
931
|
Chris@0
|
932 // These overrides may have been set earlier via $view->set_*
|
Chris@0
|
933 // functions.
|
Chris@0
|
934 if (isset($this->items_per_page)) {
|
Chris@0
|
935 $this->pager->setItemsPerPage($this->items_per_page);
|
Chris@0
|
936 }
|
Chris@0
|
937
|
Chris@0
|
938 if (isset($this->offset)) {
|
Chris@0
|
939 $this->pager->setOffset($this->offset);
|
Chris@0
|
940 }
|
Chris@0
|
941 }
|
Chris@0
|
942 }
|
Chris@0
|
943
|
Chris@0
|
944 /**
|
Chris@0
|
945 * Renders the pager, if necessary.
|
Chris@0
|
946 *
|
Chris@0
|
947 * @param string[] $exposed_input
|
Chris@0
|
948 * The input values from the exposed forms and sorts of the view.
|
Chris@0
|
949 *
|
Chris@0
|
950 * @return array|string
|
Chris@0
|
951 * The render array of the pager if it's set, blank string otherwise.
|
Chris@0
|
952 */
|
Chris@0
|
953 public function renderPager($exposed_input) {
|
Chris@18
|
954 if ($this->usePager()) {
|
Chris@0
|
955 return $this->pager->render($exposed_input);
|
Chris@0
|
956 }
|
Chris@0
|
957
|
Chris@0
|
958 return '';
|
Chris@0
|
959 }
|
Chris@0
|
960
|
Chris@0
|
961 /**
|
Chris@0
|
962 * Creates a list of base tables to be used by the view.
|
Chris@0
|
963 *
|
Chris@0
|
964 * This is used primarily for the UI. The display must be already initialized.
|
Chris@0
|
965 *
|
Chris@0
|
966 * @return array
|
Chris@0
|
967 * An array of base tables to be used by the view.
|
Chris@0
|
968 */
|
Chris@0
|
969 public function getBaseTables() {
|
Chris@0
|
970 $base_tables = [
|
Chris@0
|
971 $this->storage->get('base_table') => TRUE,
|
Chris@0
|
972 '#global' => TRUE,
|
Chris@0
|
973 ];
|
Chris@0
|
974
|
Chris@0
|
975 foreach ($this->display_handler->getHandlers('relationship') as $handler) {
|
Chris@0
|
976 $base_tables[$handler->definition['base']] = TRUE;
|
Chris@0
|
977 }
|
Chris@0
|
978 return $base_tables;
|
Chris@0
|
979 }
|
Chris@0
|
980
|
Chris@0
|
981 /**
|
Chris@0
|
982 * Returns the entity type of the base table, if available.
|
Chris@0
|
983 *
|
Chris@0
|
984 * @return \Drupal\Core\Entity\EntityType|false
|
Chris@0
|
985 * The entity type of the base table, or FALSE if none exists.
|
Chris@0
|
986 */
|
Chris@0
|
987 public function getBaseEntityType() {
|
Chris@0
|
988 if (!isset($this->baseEntityType)) {
|
Chris@0
|
989 $view_base_table = $this->storage->get('base_table');
|
Chris@0
|
990 $views_data = $this->viewsData->get($view_base_table);
|
Chris@0
|
991 if (!empty($views_data['table']['entity type'])) {
|
Chris@0
|
992 $entity_type_id = $views_data['table']['entity type'];
|
Chris@0
|
993 $this->baseEntityType = \Drupal::entityTypeManager()->getDefinition($entity_type_id);
|
Chris@0
|
994 }
|
Chris@0
|
995 else {
|
Chris@0
|
996 $this->baseEntityType = FALSE;
|
Chris@0
|
997 }
|
Chris@0
|
998 }
|
Chris@0
|
999 return $this->baseEntityType;
|
Chris@0
|
1000 }
|
Chris@0
|
1001
|
Chris@0
|
1002 /**
|
Chris@0
|
1003 * Runs the preQuery() on all active handlers.
|
Chris@0
|
1004 */
|
Chris@0
|
1005 protected function _preQuery() {
|
Chris@0
|
1006 foreach ($this::getHandlerTypes() as $key => $info) {
|
Chris@0
|
1007 $handlers = &$this->$key;
|
Chris@0
|
1008 $position = 0;
|
Chris@0
|
1009 foreach ($handlers as $id => $handler) {
|
Chris@0
|
1010 $handlers[$id]->position = $position;
|
Chris@0
|
1011 $handlers[$id]->preQuery();
|
Chris@0
|
1012 $position++;
|
Chris@0
|
1013 }
|
Chris@0
|
1014 }
|
Chris@0
|
1015 }
|
Chris@0
|
1016
|
Chris@0
|
1017 /**
|
Chris@0
|
1018 * Runs the postExecute() on all active handlers.
|
Chris@0
|
1019 */
|
Chris@0
|
1020 protected function _postExecute() {
|
Chris@0
|
1021 foreach ($this::getHandlerTypes() as $key => $info) {
|
Chris@0
|
1022 $handlers = &$this->$key;
|
Chris@0
|
1023 foreach ($handlers as $id => $handler) {
|
Chris@0
|
1024 $handlers[$id]->postExecute($this->result);
|
Chris@0
|
1025 }
|
Chris@0
|
1026 }
|
Chris@0
|
1027 }
|
Chris@0
|
1028
|
Chris@0
|
1029 /**
|
Chris@0
|
1030 * Attaches the views handler for the specific type.
|
Chris@0
|
1031 *
|
Chris@0
|
1032 * @param string $key
|
Chris@0
|
1033 * One of 'argument', 'field', 'sort', 'filter', 'relationship'.
|
Chris@0
|
1034 * @param array $info
|
Chris@0
|
1035 * An array of views handler types use in the view with additional
|
Chris@0
|
1036 * information about them.
|
Chris@0
|
1037 */
|
Chris@0
|
1038 protected function _initHandler($key, $info) {
|
Chris@0
|
1039 // Load the requested items from the display onto the object.
|
Chris@0
|
1040 $this->$key = &$this->display_handler->getHandlers($key);
|
Chris@0
|
1041
|
Chris@0
|
1042 // This reference deals with difficult PHP indirection.
|
Chris@0
|
1043 $handlers = &$this->$key;
|
Chris@0
|
1044
|
Chris@0
|
1045 // Run through and test for accessibility.
|
Chris@0
|
1046 foreach ($handlers as $id => $handler) {
|
Chris@0
|
1047 if (!$handler->access($this->user)) {
|
Chris@0
|
1048 unset($handlers[$id]);
|
Chris@0
|
1049 }
|
Chris@0
|
1050 }
|
Chris@0
|
1051 }
|
Chris@0
|
1052
|
Chris@0
|
1053 /**
|
Chris@0
|
1054 * Builds all the arguments.
|
Chris@0
|
1055 *
|
Chris@0
|
1056 * @return bool
|
Chris@0
|
1057 * TRUE if the arguments were built successfully, FALSE otherwise.
|
Chris@0
|
1058 */
|
Chris@0
|
1059 protected function _buildArguments() {
|
Chris@0
|
1060 // Initially, we want to build sorts and fields. This can change, though,
|
Chris@0
|
1061 // if we get a summary view.
|
Chris@0
|
1062 if (empty($this->argument)) {
|
Chris@0
|
1063 return TRUE;
|
Chris@0
|
1064 }
|
Chris@0
|
1065
|
Chris@0
|
1066 // build arguments.
|
Chris@0
|
1067 $position = -1;
|
Chris@0
|
1068 $substitutions = [];
|
Chris@0
|
1069 $status = TRUE;
|
Chris@0
|
1070
|
Chris@0
|
1071 // Get the title.
|
Chris@0
|
1072 $title = $this->display_handler->getOption('title');
|
Chris@0
|
1073
|
Chris@0
|
1074 // Iterate through each argument and process.
|
Chris@0
|
1075 foreach ($this->argument as $id => $arg) {
|
Chris@0
|
1076 $position++;
|
Chris@0
|
1077 $argument = $this->argument[$id];
|
Chris@0
|
1078
|
Chris@0
|
1079 if ($argument->broken()) {
|
Chris@0
|
1080 continue;
|
Chris@0
|
1081 }
|
Chris@0
|
1082
|
Chris@0
|
1083 $argument->setRelationship();
|
Chris@0
|
1084
|
Chris@0
|
1085 $arg = isset($this->args[$position]) ? $this->args[$position] : NULL;
|
Chris@0
|
1086 $argument->position = $position;
|
Chris@0
|
1087
|
Chris@0
|
1088 if (isset($arg) || $argument->hasDefaultArgument()) {
|
Chris@0
|
1089 if (!isset($arg)) {
|
Chris@0
|
1090 $arg = $argument->getDefaultArgument();
|
Chris@0
|
1091 // make sure default args get put back.
|
Chris@0
|
1092 if (isset($arg)) {
|
Chris@0
|
1093 $this->args[$position] = $arg;
|
Chris@0
|
1094 }
|
Chris@0
|
1095 // remember that this argument was computed, not passed on the URL.
|
Chris@0
|
1096 $argument->is_default = TRUE;
|
Chris@0
|
1097 }
|
Chris@0
|
1098
|
Chris@16
|
1099 // Set the argument, which ensures that the argument is valid and
|
Chris@16
|
1100 // possibly transforms the value.
|
Chris@0
|
1101 if (!$argument->setArgument($arg)) {
|
Chris@0
|
1102 $status = $argument->validateFail($arg);
|
Chris@0
|
1103 break;
|
Chris@0
|
1104 }
|
Chris@0
|
1105
|
Chris@0
|
1106 if ($argument->isException()) {
|
Chris@0
|
1107 $arg_title = $argument->exceptionTitle();
|
Chris@0
|
1108 }
|
Chris@0
|
1109 else {
|
Chris@0
|
1110 $arg_title = $argument->getTitle();
|
Chris@0
|
1111 $argument->query($this->display_handler->useGroupBy());
|
Chris@0
|
1112 }
|
Chris@0
|
1113
|
Chris@16
|
1114 // Add this argument's substitution.
|
Chris@0
|
1115 $substitutions["{{ arguments.$id }}"] = $arg_title;
|
Chris@16
|
1116 // Since argument validator plugins can potentially transform the value,
|
Chris@16
|
1117 // use whatever value the argument handler now has, not the raw value.
|
Chris@16
|
1118 $substitutions["{{ raw_arguments.$id }}"] = strip_tags(Html::decodeEntities($argument->getValue()));
|
Chris@0
|
1119
|
Chris@0
|
1120 // Test to see if we should use this argument's title
|
Chris@0
|
1121 if (!empty($argument->options['title_enable']) && !empty($argument->options['title'])) {
|
Chris@0
|
1122 $title = $argument->options['title'];
|
Chris@0
|
1123 }
|
Chris@0
|
1124 }
|
Chris@0
|
1125 else {
|
Chris@0
|
1126 // determine default condition and handle.
|
Chris@0
|
1127 $status = $argument->defaultAction();
|
Chris@0
|
1128 break;
|
Chris@0
|
1129 }
|
Chris@0
|
1130
|
Chris@0
|
1131 // Be safe with references and loops:
|
Chris@0
|
1132 unset($argument);
|
Chris@0
|
1133 }
|
Chris@0
|
1134
|
Chris@0
|
1135 // set the title in the build info.
|
Chris@0
|
1136 if (!empty($title)) {
|
Chris@0
|
1137 $this->build_info['title'] = $title;
|
Chris@0
|
1138 }
|
Chris@0
|
1139
|
Chris@0
|
1140 // Store the arguments for later use.
|
Chris@0
|
1141 $this->build_info['substitutions'] = $substitutions;
|
Chris@0
|
1142
|
Chris@0
|
1143 return $status;
|
Chris@0
|
1144 }
|
Chris@0
|
1145
|
Chris@0
|
1146 /**
|
Chris@0
|
1147 * Gets the current query plugin.
|
Chris@0
|
1148 *
|
Chris@0
|
1149 * @return \Drupal\views\Plugin\views\query\QueryPluginBase
|
Chris@0
|
1150 * The current query plugin.
|
Chris@0
|
1151 */
|
Chris@0
|
1152 public function getQuery() {
|
Chris@0
|
1153 if (!isset($this->query)) {
|
Chris@0
|
1154 $this->initQuery();
|
Chris@0
|
1155 }
|
Chris@0
|
1156
|
Chris@0
|
1157 return $this->query;
|
Chris@0
|
1158 }
|
Chris@0
|
1159
|
Chris@0
|
1160 /**
|
Chris@0
|
1161 * Initializes the query object for the view.
|
Chris@0
|
1162 *
|
Chris@0
|
1163 * @return true
|
Chris@0
|
1164 * Always returns TRUE.
|
Chris@0
|
1165 */
|
Chris@0
|
1166 public function initQuery() {
|
Chris@0
|
1167 if (!empty($this->query)) {
|
Chris@0
|
1168 $class = get_class($this->query);
|
Chris@0
|
1169 if ($class && $class != 'stdClass') {
|
Chris@0
|
1170 // return if query is already initialized.
|
Chris@0
|
1171 return TRUE;
|
Chris@0
|
1172 }
|
Chris@0
|
1173 }
|
Chris@0
|
1174
|
Chris@0
|
1175 // Create and initialize the query object.
|
Chris@0
|
1176 $views_data = Views::viewsData()->get($this->storage->get('base_table'));
|
Chris@0
|
1177 $this->storage->set('base_field', !empty($views_data['table']['base']['field']) ? $views_data['table']['base']['field'] : '');
|
Chris@0
|
1178 if (!empty($views_data['table']['base']['database'])) {
|
Chris@0
|
1179 $this->base_database = $views_data['table']['base']['database'];
|
Chris@0
|
1180 }
|
Chris@0
|
1181
|
Chris@0
|
1182 $this->query = $this->display_handler->getPlugin('query');
|
Chris@0
|
1183 return TRUE;
|
Chris@0
|
1184 }
|
Chris@0
|
1185
|
Chris@0
|
1186 /**
|
Chris@0
|
1187 * Builds the query for the view.
|
Chris@0
|
1188 *
|
Chris@0
|
1189 * @param string $display_id
|
Chris@0
|
1190 * The display ID of the view.
|
Chris@0
|
1191 *
|
Chris@0
|
1192 * @return bool|null
|
Chris@0
|
1193 * TRUE if the view build process was successful, FALSE if setting the
|
Chris@0
|
1194 * display fails or NULL if the view has been built already.
|
Chris@0
|
1195 */
|
Chris@0
|
1196 public function build($display_id = NULL) {
|
Chris@0
|
1197 if (!empty($this->built)) {
|
Chris@0
|
1198 return;
|
Chris@0
|
1199 }
|
Chris@0
|
1200
|
Chris@0
|
1201 if (empty($this->current_display) || $display_id) {
|
Chris@0
|
1202 if (!$this->setDisplay($display_id)) {
|
Chris@0
|
1203 return FALSE;
|
Chris@0
|
1204 }
|
Chris@0
|
1205 }
|
Chris@0
|
1206
|
Chris@0
|
1207 // Let modules modify the view just prior to building it.
|
Chris@0
|
1208 $module_handler = \Drupal::moduleHandler();
|
Chris@0
|
1209 $module_handler->invokeAll('views_pre_build', [$this]);
|
Chris@0
|
1210
|
Chris@0
|
1211 // Attempt to load from cache.
|
Chris@0
|
1212 // @todo Load a build_info from cache.
|
Chris@0
|
1213
|
Chris@0
|
1214 $start = microtime(TRUE);
|
Chris@0
|
1215 // If that fails, let's build!
|
Chris@0
|
1216 $this->build_info = [
|
Chris@0
|
1217 'query' => '',
|
Chris@0
|
1218 'count_query' => '',
|
Chris@0
|
1219 'query_args' => [],
|
Chris@0
|
1220 ];
|
Chris@0
|
1221
|
Chris@0
|
1222 $this->initQuery();
|
Chris@0
|
1223
|
Chris@0
|
1224 // Call a module hook and see if it wants to present us with a
|
Chris@0
|
1225 // pre-built query or instruct us not to build the query for
|
Chris@0
|
1226 // some reason.
|
Chris@0
|
1227 // @todo: Implement this. Use the same mechanism Panels uses.
|
Chris@0
|
1228
|
Chris@0
|
1229 // Run through our handlers and ensure they have necessary information.
|
Chris@0
|
1230 $this->initHandlers();
|
Chris@0
|
1231
|
Chris@0
|
1232 // Let the handlers interact with each other if they really want.
|
Chris@0
|
1233 $this->_preQuery();
|
Chris@0
|
1234
|
Chris@0
|
1235 if ($this->display_handler->usesExposed()) {
|
Chris@0
|
1236 /** @var \Drupal\views\Plugin\views\exposed_form\ExposedFormPluginInterface $exposed_form */
|
Chris@0
|
1237 $exposed_form = $this->display_handler->getPlugin('exposed_form');
|
Chris@0
|
1238 $this->exposed_widgets = $exposed_form->renderExposedForm();
|
Chris@0
|
1239 if (!empty($this->build_info['abort'])) {
|
Chris@0
|
1240 $this->built = TRUE;
|
Chris@0
|
1241 // Don't execute the query, $form_state, but rendering will still be executed to display the empty text.
|
Chris@0
|
1242 $this->executed = TRUE;
|
Chris@0
|
1243 return empty($this->build_info['fail']);
|
Chris@0
|
1244 }
|
Chris@0
|
1245 }
|
Chris@0
|
1246
|
Chris@0
|
1247 // Build all the relationships first thing.
|
Chris@0
|
1248 $this->_build('relationship');
|
Chris@0
|
1249
|
Chris@0
|
1250 // Set the filtering groups.
|
Chris@0
|
1251 if (!empty($this->filter)) {
|
Chris@0
|
1252 $filter_groups = $this->display_handler->getOption('filter_groups');
|
Chris@0
|
1253 if ($filter_groups) {
|
Chris@0
|
1254 $this->query->setGroupOperator($filter_groups['operator']);
|
Chris@0
|
1255 foreach ($filter_groups['groups'] as $id => $operator) {
|
Chris@0
|
1256 $this->query->setWhereGroup($operator, $id);
|
Chris@0
|
1257 }
|
Chris@0
|
1258 }
|
Chris@0
|
1259 }
|
Chris@0
|
1260
|
Chris@0
|
1261 // Build all the filters.
|
Chris@0
|
1262 $this->_build('filter');
|
Chris@0
|
1263
|
Chris@0
|
1264 $this->build_sort = TRUE;
|
Chris@0
|
1265
|
Chris@0
|
1266 // Arguments can, in fact, cause this whole thing to abort.
|
Chris@0
|
1267 if (!$this->_buildArguments()) {
|
Chris@0
|
1268 $this->build_time = microtime(TRUE) - $start;
|
Chris@0
|
1269 $this->attachDisplays();
|
Chris@0
|
1270 return $this->built;
|
Chris@0
|
1271 }
|
Chris@0
|
1272
|
Chris@0
|
1273 // Initialize the style; arguments may have changed which style we use,
|
Chris@0
|
1274 // so waiting as long as possible is important. But we need to know
|
Chris@0
|
1275 // about the style when we go to build fields.
|
Chris@0
|
1276 if (!$this->initStyle()) {
|
Chris@0
|
1277 $this->build_info['fail'] = TRUE;
|
Chris@0
|
1278 return FALSE;
|
Chris@0
|
1279 }
|
Chris@0
|
1280
|
Chris@0
|
1281 if ($this->style_plugin->usesFields()) {
|
Chris@0
|
1282 $this->_build('field');
|
Chris@0
|
1283 }
|
Chris@0
|
1284
|
Chris@0
|
1285 // Build our sort criteria if we were instructed to do so.
|
Chris@0
|
1286 if (!empty($this->build_sort)) {
|
Chris@0
|
1287 // Allow the style handler to deal with sorting.
|
Chris@0
|
1288 if ($this->style_plugin->buildSort()) {
|
Chris@0
|
1289 $this->_build('sort');
|
Chris@0
|
1290 }
|
Chris@0
|
1291 // allow the plugin to build second sorts as well.
|
Chris@0
|
1292 $this->style_plugin->buildSortPost();
|
Chris@0
|
1293 }
|
Chris@0
|
1294
|
Chris@0
|
1295 // Allow area handlers to affect the query.
|
Chris@0
|
1296 $this->_build('header');
|
Chris@0
|
1297 $this->_build('footer');
|
Chris@0
|
1298 $this->_build('empty');
|
Chris@0
|
1299
|
Chris@0
|
1300 // Allow display handler to affect the query:
|
Chris@0
|
1301 $this->display_handler->query($this->display_handler->useGroupBy());
|
Chris@0
|
1302
|
Chris@0
|
1303 // Allow style handler to affect the query:
|
Chris@0
|
1304 $this->style_plugin->query($this->display_handler->useGroupBy());
|
Chris@0
|
1305
|
Chris@0
|
1306 // Allow exposed form to affect the query:
|
Chris@0
|
1307 if (isset($exposed_form)) {
|
Chris@0
|
1308 $exposed_form->query();
|
Chris@0
|
1309 }
|
Chris@0
|
1310
|
Chris@0
|
1311 if (\Drupal::config('views.settings')->get('sql_signature')) {
|
Chris@0
|
1312 $this->query->addSignature($this);
|
Chris@0
|
1313 }
|
Chris@0
|
1314
|
Chris@0
|
1315 // Let modules modify the query just prior to finalizing it.
|
Chris@0
|
1316 $this->query->alter($this);
|
Chris@0
|
1317
|
Chris@0
|
1318 // Only build the query if we weren't interrupted.
|
Chris@0
|
1319 if (empty($this->built)) {
|
Chris@0
|
1320 // Build the necessary info to execute the query.
|
Chris@0
|
1321 $this->query->build($this);
|
Chris@0
|
1322 }
|
Chris@0
|
1323
|
Chris@0
|
1324 $this->built = TRUE;
|
Chris@0
|
1325 $this->build_time = microtime(TRUE) - $start;
|
Chris@0
|
1326
|
Chris@0
|
1327 // Attach displays
|
Chris@0
|
1328 $this->attachDisplays();
|
Chris@0
|
1329
|
Chris@0
|
1330 // Let modules modify the view just after building it.
|
Chris@0
|
1331 $module_handler->invokeAll('views_post_build', [$this]);
|
Chris@0
|
1332
|
Chris@0
|
1333 return TRUE;
|
Chris@0
|
1334 }
|
Chris@0
|
1335
|
Chris@0
|
1336 /**
|
Chris@0
|
1337 * Builds an individual set of handlers.
|
Chris@0
|
1338 *
|
Chris@0
|
1339 * This is an internal method.
|
Chris@0
|
1340 *
|
Chris@0
|
1341 * @todo Some filter needs this function, even it is internal.
|
Chris@0
|
1342 *
|
Chris@0
|
1343 * @param string $key
|
Chris@0
|
1344 * The type of handlers (filter etc.) which should be iterated over to build
|
Chris@0
|
1345 * the relationship and query information.
|
Chris@0
|
1346 */
|
Chris@0
|
1347 public function _build($key) {
|
Chris@0
|
1348 $handlers = &$this->$key;
|
Chris@0
|
1349 foreach ($handlers as $id => $data) {
|
Chris@0
|
1350
|
Chris@0
|
1351 if (!empty($handlers[$id]) && is_object($handlers[$id])) {
|
Chris@0
|
1352 $multiple_exposed_input = [0 => NULL];
|
Chris@0
|
1353 if ($handlers[$id]->multipleExposedInput()) {
|
Chris@0
|
1354 $multiple_exposed_input = $handlers[$id]->groupMultipleExposedInput($this->exposed_data);
|
Chris@0
|
1355 }
|
Chris@0
|
1356 foreach ($multiple_exposed_input as $group_id) {
|
Chris@0
|
1357 // Give this handler access to the exposed filter input.
|
Chris@0
|
1358 if (!empty($this->exposed_data)) {
|
Chris@0
|
1359 if ($handlers[$id]->isAGroup()) {
|
Chris@0
|
1360 $converted = $handlers[$id]->convertExposedInput($this->exposed_data, $group_id);
|
Chris@0
|
1361 $handlers[$id]->storeGroupInput($this->exposed_data, $converted);
|
Chris@0
|
1362 if (!$converted) {
|
Chris@0
|
1363 continue;
|
Chris@0
|
1364 }
|
Chris@0
|
1365 }
|
Chris@0
|
1366 $rc = $handlers[$id]->acceptExposedInput($this->exposed_data);
|
Chris@0
|
1367 $handlers[$id]->storeExposedInput($this->exposed_data, $rc);
|
Chris@0
|
1368 if (!$rc) {
|
Chris@0
|
1369 continue;
|
Chris@0
|
1370 }
|
Chris@0
|
1371 }
|
Chris@0
|
1372 $handlers[$id]->setRelationship();
|
Chris@0
|
1373 $handlers[$id]->query($this->display_handler->useGroupBy());
|
Chris@0
|
1374 }
|
Chris@0
|
1375 }
|
Chris@0
|
1376 }
|
Chris@0
|
1377 }
|
Chris@0
|
1378
|
Chris@0
|
1379 /**
|
Chris@0
|
1380 * Executes the view's query.
|
Chris@0
|
1381 *
|
Chris@0
|
1382 * @param string $display_id
|
Chris@0
|
1383 * The machine name of the display, which should be executed.
|
Chris@0
|
1384 *
|
Chris@0
|
1385 * @return bool
|
Chris@0
|
1386 * TRUE if the view execution was successful, FALSE otherwise. For example,
|
Chris@0
|
1387 * an argument could stop the process.
|
Chris@0
|
1388 */
|
Chris@0
|
1389 public function execute($display_id = NULL) {
|
Chris@0
|
1390 if (empty($this->built)) {
|
Chris@0
|
1391 if (!$this->build($display_id)) {
|
Chris@0
|
1392 return FALSE;
|
Chris@0
|
1393 }
|
Chris@0
|
1394 }
|
Chris@0
|
1395
|
Chris@0
|
1396 if (!empty($this->executed)) {
|
Chris@0
|
1397 return TRUE;
|
Chris@0
|
1398 }
|
Chris@0
|
1399
|
Chris@0
|
1400 // Don't allow to use deactivated displays, but display them on the live preview.
|
Chris@0
|
1401 if (!$this->display_handler->isEnabled() && empty($this->live_preview)) {
|
Chris@0
|
1402 $this->build_info['fail'] = TRUE;
|
Chris@0
|
1403 return FALSE;
|
Chris@0
|
1404 }
|
Chris@0
|
1405
|
Chris@0
|
1406 // Let modules modify the view just prior to executing it.
|
Chris@0
|
1407 $module_handler = \Drupal::moduleHandler();
|
Chris@0
|
1408 $module_handler->invokeAll('views_pre_execute', [$this]);
|
Chris@0
|
1409
|
Chris@0
|
1410 // Check for already-cached results.
|
Chris@0
|
1411 /** @var \Drupal\views\Plugin\views\cache\CachePluginBase $cache */
|
Chris@0
|
1412 if (!empty($this->live_preview)) {
|
Chris@0
|
1413 $cache = Views::pluginManager('cache')->createInstance('none');
|
Chris@0
|
1414 }
|
Chris@0
|
1415 else {
|
Chris@0
|
1416 $cache = $this->display_handler->getPlugin('cache');
|
Chris@0
|
1417 }
|
Chris@0
|
1418
|
Chris@0
|
1419 if ($cache->cacheGet('results')) {
|
Chris@18
|
1420 if ($this->usePager()) {
|
Chris@0
|
1421 $this->pager->total_items = $this->total_rows;
|
Chris@0
|
1422 $this->pager->updatePageInfo();
|
Chris@0
|
1423 }
|
Chris@0
|
1424 }
|
Chris@0
|
1425 else {
|
Chris@0
|
1426 $this->query->execute($this);
|
Chris@0
|
1427 // Enforce the array key rule as documented in
|
Chris@0
|
1428 // views_plugin_query::execute().
|
Chris@0
|
1429 $this->result = array_values($this->result);
|
Chris@0
|
1430 $this->_postExecute();
|
Chris@0
|
1431 $cache->cacheSet('results');
|
Chris@0
|
1432 }
|
Chris@0
|
1433
|
Chris@0
|
1434 // Let modules modify the view just after executing it.
|
Chris@0
|
1435 $module_handler->invokeAll('views_post_execute', [$this]);
|
Chris@0
|
1436
|
Chris@0
|
1437 return $this->executed = TRUE;
|
Chris@0
|
1438 }
|
Chris@0
|
1439
|
Chris@0
|
1440 /**
|
Chris@0
|
1441 * Renders this view for a certain display.
|
Chris@0
|
1442 *
|
Chris@0
|
1443 * Note: You should better use just the preview function if you want to
|
Chris@0
|
1444 * render a view.
|
Chris@0
|
1445 *
|
Chris@0
|
1446 * @param string $display_id
|
Chris@0
|
1447 * The machine name of the display, which should be rendered.
|
Chris@0
|
1448 *
|
Chris@0
|
1449 * @return array|null
|
Chris@0
|
1450 * A renderable array containing the view output or NULL if the build
|
Chris@0
|
1451 * process failed.
|
Chris@0
|
1452 */
|
Chris@0
|
1453 public function render($display_id = NULL) {
|
Chris@0
|
1454 $this->execute($display_id);
|
Chris@0
|
1455
|
Chris@0
|
1456 // Check to see if the build failed.
|
Chris@0
|
1457 if (!empty($this->build_info['fail'])) {
|
Chris@0
|
1458 return;
|
Chris@0
|
1459 }
|
Chris@0
|
1460 if (!empty($this->build_info['denied'])) {
|
Chris@0
|
1461 return;
|
Chris@0
|
1462 }
|
Chris@0
|
1463
|
Chris@0
|
1464 /** @var \Drupal\views\Plugin\views\exposed_form\ExposedFormPluginInterface $exposed_form */
|
Chris@0
|
1465 $exposed_form = $this->display_handler->getPlugin('exposed_form');
|
Chris@0
|
1466 $exposed_form->preRender($this->result);
|
Chris@0
|
1467
|
Chris@0
|
1468 $module_handler = \Drupal::moduleHandler();
|
Chris@0
|
1469
|
Chris@0
|
1470 // @TODO In the longrun, it would be great to execute a view without
|
Chris@0
|
1471 // the theme system at all. See https://www.drupal.org/node/2322623.
|
Chris@0
|
1472 $active_theme = \Drupal::theme()->getActiveTheme();
|
Chris@18
|
1473 $themes = array_keys($active_theme->getBaseThemeExtensions());
|
Chris@0
|
1474 $themes[] = $active_theme->getName();
|
Chris@0
|
1475
|
Chris@0
|
1476 // Check for already-cached output.
|
Chris@0
|
1477 /** @var \Drupal\views\Plugin\views\cache\CachePluginBase $cache */
|
Chris@0
|
1478 if (!empty($this->live_preview)) {
|
Chris@0
|
1479 $cache = Views::pluginManager('cache')->createInstance('none');
|
Chris@0
|
1480 }
|
Chris@0
|
1481 else {
|
Chris@0
|
1482 $cache = $this->display_handler->getPlugin('cache');
|
Chris@0
|
1483 }
|
Chris@0
|
1484
|
Chris@0
|
1485 // Run preRender for the pager as it might change the result.
|
Chris@0
|
1486 if (!empty($this->pager)) {
|
Chris@0
|
1487 $this->pager->preRender($this->result);
|
Chris@0
|
1488 }
|
Chris@0
|
1489
|
Chris@0
|
1490 // Initialize the style plugin.
|
Chris@0
|
1491 $this->initStyle();
|
Chris@0
|
1492
|
Chris@0
|
1493 if (!isset($this->response)) {
|
Chris@0
|
1494 // Set the response so other parts can alter it.
|
Chris@0
|
1495 $this->response = new Response('', 200);
|
Chris@0
|
1496 }
|
Chris@0
|
1497
|
Chris@0
|
1498 // Give field handlers the opportunity to perform additional queries
|
Chris@0
|
1499 // using the entire resultset prior to rendering.
|
Chris@0
|
1500 if ($this->style_plugin->usesFields()) {
|
Chris@0
|
1501 foreach ($this->field as $id => $handler) {
|
Chris@0
|
1502 if (!empty($this->field[$id])) {
|
Chris@0
|
1503 $this->field[$id]->preRender($this->result);
|
Chris@0
|
1504 }
|
Chris@0
|
1505 }
|
Chris@0
|
1506 }
|
Chris@0
|
1507
|
Chris@0
|
1508 $this->style_plugin->preRender($this->result);
|
Chris@0
|
1509
|
Chris@0
|
1510 // Let each area handler have access to the result set.
|
Chris@0
|
1511 $areas = ['header', 'footer'];
|
Chris@0
|
1512 // Only call preRender() on the empty handlers if the result is empty.
|
Chris@0
|
1513 if (empty($this->result)) {
|
Chris@0
|
1514 $areas[] = 'empty';
|
Chris@0
|
1515 }
|
Chris@0
|
1516 foreach ($areas as $area) {
|
Chris@0
|
1517 foreach ($this->{$area} as $handler) {
|
Chris@0
|
1518 $handler->preRender($this->result);
|
Chris@0
|
1519 }
|
Chris@0
|
1520 }
|
Chris@0
|
1521
|
Chris@0
|
1522 // Let modules modify the view just prior to rendering it.
|
Chris@0
|
1523 $module_handler->invokeAll('views_pre_render', [$this]);
|
Chris@0
|
1524
|
Chris@17
|
1525 // Let the themes play too, because prerender is a very themey thing.
|
Chris@0
|
1526 foreach ($themes as $theme_name) {
|
Chris@0
|
1527 $function = $theme_name . '_views_pre_render';
|
Chris@0
|
1528 if (function_exists($function)) {
|
Chris@0
|
1529 $function($this);
|
Chris@0
|
1530 }
|
Chris@0
|
1531 }
|
Chris@0
|
1532
|
Chris@0
|
1533 $this->display_handler->output = $this->display_handler->render();
|
Chris@0
|
1534
|
Chris@0
|
1535 $exposed_form->postRender($this->display_handler->output);
|
Chris@0
|
1536
|
Chris@0
|
1537 $cache->postRender($this->display_handler->output);
|
Chris@0
|
1538
|
Chris@0
|
1539 // Let modules modify the view output after it is rendered.
|
Chris@0
|
1540 $module_handler->invokeAll('views_post_render', [$this, &$this->display_handler->output, $cache]);
|
Chris@0
|
1541
|
Chris@0
|
1542 // Let the themes play too, because post render is a very themey thing.
|
Chris@0
|
1543 foreach ($themes as $theme_name) {
|
Chris@0
|
1544 $function = $theme_name . '_views_post_render';
|
Chris@0
|
1545 if (function_exists($function)) {
|
Chris@0
|
1546 $function($this, $this->display_handler->output, $cache);
|
Chris@0
|
1547 }
|
Chris@0
|
1548 }
|
Chris@0
|
1549
|
Chris@0
|
1550 return $this->display_handler->output;
|
Chris@0
|
1551 }
|
Chris@0
|
1552
|
Chris@0
|
1553 /**
|
Chris@0
|
1554 * Gets the cache tags associated with the executed view.
|
Chris@0
|
1555 *
|
Chris@0
|
1556 * Note: The cache plugin controls the used tags, so you can override it, if
|
Chris@0
|
1557 * needed.
|
Chris@0
|
1558 *
|
Chris@0
|
1559 * @return string[]
|
Chris@0
|
1560 * An array of cache tags.
|
Chris@0
|
1561 */
|
Chris@0
|
1562 public function getCacheTags() {
|
Chris@0
|
1563 $this->initDisplay();
|
Chris@0
|
1564 /** @var \Drupal\views\Plugin\views\cache\CachePluginBase $cache */
|
Chris@0
|
1565 $cache = $this->display_handler->getPlugin('cache');
|
Chris@0
|
1566 return $cache->getCacheTags();
|
Chris@0
|
1567 }
|
Chris@0
|
1568
|
Chris@0
|
1569 /**
|
Chris@0
|
1570 * Builds the render array outline for the given display.
|
Chris@0
|
1571 *
|
Chris@0
|
1572 * This render array has a #pre_render callback which will call
|
Chris@0
|
1573 * ::executeDisplay in order to actually execute the view and then build the
|
Chris@0
|
1574 * final render array structure.
|
Chris@0
|
1575 *
|
Chris@0
|
1576 * @param string $display_id
|
Chris@0
|
1577 * The display ID.
|
Chris@0
|
1578 * @param array $args
|
Chris@0
|
1579 * An array of arguments passed along to the view.
|
Chris@0
|
1580 * @param bool $cache
|
Chris@0
|
1581 * (optional) Should the result be render cached.
|
Chris@0
|
1582 *
|
Chris@0
|
1583 * @return array|null
|
Chris@0
|
1584 * A renderable array with #type 'view' or NULL if the display ID was
|
Chris@0
|
1585 * invalid.
|
Chris@0
|
1586 */
|
Chris@0
|
1587 public function buildRenderable($display_id = NULL, $args = [], $cache = TRUE) {
|
Chris@0
|
1588 // @todo Extract that into a generic method.
|
Chris@0
|
1589 if (empty($this->current_display) || $this->current_display != $this->chooseDisplay($display_id)) {
|
Chris@0
|
1590 if (!$this->setDisplay($display_id)) {
|
Chris@0
|
1591 return NULL;
|
Chris@0
|
1592 }
|
Chris@0
|
1593 }
|
Chris@0
|
1594
|
Chris@0
|
1595 return $this->display_handler->buildRenderable($args, $cache);
|
Chris@0
|
1596 }
|
Chris@0
|
1597
|
Chris@0
|
1598 /**
|
Chris@0
|
1599 * Executes the given display, with the given arguments.
|
Chris@0
|
1600 *
|
Chris@0
|
1601 * To be called externally by whatever mechanism invokes the view,
|
Chris@0
|
1602 * such as a page callback, hook_block, etc.
|
Chris@0
|
1603 *
|
Chris@0
|
1604 * This function should NOT be used by anything external as this
|
Chris@0
|
1605 * returns data in the format specified by the display. It can also
|
Chris@0
|
1606 * have other side effects that are only intended for the 'proper'
|
Chris@0
|
1607 * use of the display, such as setting page titles.
|
Chris@0
|
1608 *
|
Chris@0
|
1609 * If you simply want to view the display, use View::preview() instead.
|
Chris@0
|
1610 *
|
Chris@0
|
1611 * @param string $display_id
|
Chris@0
|
1612 * The display ID of the view to be executed.
|
Chris@0
|
1613 * @param string[] $args
|
Chris@0
|
1614 * The arguments to be passed to the view.
|
Chris@0
|
1615 *
|
Chris@0
|
1616 * @return array|null
|
Chris@0
|
1617 * A renderable array containing the view output or NULL if the display ID
|
Chris@0
|
1618 * of the view to be executed doesn't exist.
|
Chris@0
|
1619 */
|
Chris@0
|
1620 public function executeDisplay($display_id = NULL, $args = []) {
|
Chris@0
|
1621 if (empty($this->current_display) || $this->current_display != $this->chooseDisplay($display_id)) {
|
Chris@0
|
1622 if (!$this->setDisplay($display_id)) {
|
Chris@0
|
1623 return NULL;
|
Chris@0
|
1624 }
|
Chris@0
|
1625 }
|
Chris@0
|
1626
|
Chris@0
|
1627 $this->preExecute($args);
|
Chris@0
|
1628
|
Chris@0
|
1629 // Execute the view
|
Chris@0
|
1630 $output = $this->display_handler->execute();
|
Chris@0
|
1631
|
Chris@0
|
1632 $this->postExecute();
|
Chris@0
|
1633 return $output;
|
Chris@0
|
1634 }
|
Chris@0
|
1635
|
Chris@0
|
1636 /**
|
Chris@0
|
1637 * Previews the given display, with the given arguments.
|
Chris@0
|
1638 *
|
Chris@0
|
1639 * To be called externally, probably by an AJAX handler of some flavor.
|
Chris@0
|
1640 * Can also be called when views are embedded, as this guarantees
|
Chris@0
|
1641 * normalized output.
|
Chris@0
|
1642 *
|
Chris@0
|
1643 * This function does not do any access checks on the view. It is the
|
Chris@0
|
1644 * responsibility of the caller to check $view->access() or implement other
|
Chris@0
|
1645 * access logic. To render the view normally with access checks, use
|
Chris@0
|
1646 * views_embed_view() instead.
|
Chris@0
|
1647 *
|
Chris@0
|
1648 * @return array|null
|
Chris@0
|
1649 * A renderable array containing the view output or NULL if the display ID
|
Chris@0
|
1650 * of the view to be executed doesn't exist.
|
Chris@0
|
1651 */
|
Chris@0
|
1652 public function preview($display_id = NULL, $args = []) {
|
Chris@0
|
1653 if (empty($this->current_display) || ((!empty($display_id)) && $this->current_display != $display_id)) {
|
Chris@0
|
1654 if (!$this->setDisplay($display_id)) {
|
Chris@0
|
1655 return FALSE;
|
Chris@0
|
1656 }
|
Chris@0
|
1657 }
|
Chris@0
|
1658
|
Chris@0
|
1659 $this->preview = TRUE;
|
Chris@0
|
1660 $this->preExecute($args);
|
Chris@0
|
1661 // Preview the view.
|
Chris@0
|
1662 $output = $this->display_handler->preview();
|
Chris@0
|
1663
|
Chris@0
|
1664 $this->postExecute();
|
Chris@0
|
1665 return $output;
|
Chris@0
|
1666 }
|
Chris@0
|
1667
|
Chris@0
|
1668 /**
|
Chris@0
|
1669 * Runs attachments and lets the display do what it needs to before running.
|
Chris@0
|
1670 *
|
Chris@0
|
1671 * @param array $args
|
Chris@0
|
1672 * An array of arguments from the URL that can be used by the view.
|
Chris@0
|
1673 */
|
Chris@0
|
1674 public function preExecute($args = []) {
|
Chris@0
|
1675 $this->old_view[] = views_get_current_view();
|
Chris@0
|
1676 views_set_current_view($this);
|
Chris@0
|
1677 $display_id = $this->current_display;
|
Chris@0
|
1678
|
Chris@0
|
1679 // Prepare the view with the information we have, but only if we were
|
Chris@0
|
1680 // passed arguments, as they may have been set previously.
|
Chris@0
|
1681 if ($args) {
|
Chris@0
|
1682 $this->setArguments($args);
|
Chris@0
|
1683 }
|
Chris@0
|
1684
|
Chris@0
|
1685 // Let modules modify the view just prior to executing it.
|
Chris@0
|
1686 \Drupal::moduleHandler()->invokeAll('views_pre_view', [$this, $display_id, &$this->args]);
|
Chris@0
|
1687
|
Chris@0
|
1688 // Allow hook_views_pre_view() to set the dom_id, then ensure it is set.
|
Chris@0
|
1689 $this->dom_id = !empty($this->dom_id) ? $this->dom_id : hash('sha256', $this->storage->id() . REQUEST_TIME . mt_rand());
|
Chris@0
|
1690
|
Chris@0
|
1691 // Allow the display handler to set up for execution
|
Chris@0
|
1692 $this->display_handler->preExecute();
|
Chris@0
|
1693 }
|
Chris@0
|
1694
|
Chris@0
|
1695 /**
|
Chris@0
|
1696 * Unsets the current view, mostly.
|
Chris@0
|
1697 */
|
Chris@0
|
1698 public function postExecute() {
|
Chris@0
|
1699 // unset current view so we can be properly destructed later on.
|
Chris@0
|
1700 // Return the previous value in case we're an attachment.
|
Chris@0
|
1701
|
Chris@0
|
1702 if ($this->old_view) {
|
Chris@0
|
1703 $old_view = array_pop($this->old_view);
|
Chris@0
|
1704 }
|
Chris@0
|
1705
|
Chris@0
|
1706 views_set_current_view(isset($old_view) ? $old_view : FALSE);
|
Chris@0
|
1707 }
|
Chris@0
|
1708
|
Chris@0
|
1709 /**
|
Chris@0
|
1710 * Runs attachment displays for the view.
|
Chris@0
|
1711 */
|
Chris@0
|
1712 public function attachDisplays() {
|
Chris@0
|
1713 if (!empty($this->is_attachment)) {
|
Chris@0
|
1714 return;
|
Chris@0
|
1715 }
|
Chris@0
|
1716
|
Chris@0
|
1717 if (!$this->display_handler->acceptAttachments()) {
|
Chris@0
|
1718 return;
|
Chris@0
|
1719 }
|
Chris@0
|
1720
|
Chris@0
|
1721 $this->is_attachment = TRUE;
|
Chris@0
|
1722 // Find out which other displays attach to the current one.
|
Chris@0
|
1723 foreach ($this->display_handler->getAttachedDisplays() as $id) {
|
Chris@0
|
1724 $display_handler = $this->displayHandlers->get($id);
|
Chris@0
|
1725 // Only attach enabled attachments.
|
Chris@0
|
1726 if ($display_handler->isEnabled()) {
|
Chris@0
|
1727 $cloned_view = Views::executableFactory()->get($this->storage);
|
Chris@0
|
1728 $display_handler->attachTo($cloned_view, $this->current_display, $this->element);
|
Chris@0
|
1729 }
|
Chris@0
|
1730 }
|
Chris@0
|
1731 $this->is_attachment = FALSE;
|
Chris@0
|
1732 }
|
Chris@0
|
1733
|
Chris@0
|
1734 /**
|
Chris@0
|
1735 * Determines if the given user has access to the view.
|
Chris@0
|
1736 *
|
Chris@0
|
1737 * Note that this sets the display handler if it hasn't been set.
|
Chris@0
|
1738 *
|
Chris@0
|
1739 * @param string $displays
|
Chris@0
|
1740 * The machine name of the display.
|
Chris@0
|
1741 * @param \Drupal\Core\Session\AccountInterface $account
|
Chris@0
|
1742 * The user object.
|
Chris@0
|
1743 *
|
Chris@0
|
1744 * @return bool
|
Chris@0
|
1745 * TRUE if the user has access to the view, FALSE otherwise.
|
Chris@0
|
1746 */
|
Chris@0
|
1747 public function access($displays = NULL, $account = NULL) {
|
Chris@0
|
1748 // No one should have access to disabled views.
|
Chris@0
|
1749 if (!$this->storage->status()) {
|
Chris@0
|
1750 return FALSE;
|
Chris@0
|
1751 }
|
Chris@0
|
1752
|
Chris@0
|
1753 if (!isset($this->current_display)) {
|
Chris@0
|
1754 $this->initDisplay();
|
Chris@0
|
1755 }
|
Chris@0
|
1756
|
Chris@0
|
1757 if (!$account) {
|
Chris@0
|
1758 $account = $this->user;
|
Chris@0
|
1759 }
|
Chris@0
|
1760
|
Chris@0
|
1761 // We can't use choose_display() here because that function
|
Chris@0
|
1762 // calls this one.
|
Chris@0
|
1763 $displays = (array) $displays;
|
Chris@0
|
1764 foreach ($displays as $display_id) {
|
Chris@0
|
1765 if ($this->displayHandlers->has($display_id)) {
|
Chris@0
|
1766 if (($display = $this->displayHandlers->get($display_id)) && $display->access($account)) {
|
Chris@0
|
1767 return TRUE;
|
Chris@0
|
1768 }
|
Chris@0
|
1769 }
|
Chris@0
|
1770 }
|
Chris@0
|
1771
|
Chris@0
|
1772 return FALSE;
|
Chris@0
|
1773 }
|
Chris@0
|
1774
|
Chris@0
|
1775 /**
|
Chris@0
|
1776 * Sets the used response object of the view.
|
Chris@0
|
1777 *
|
Chris@0
|
1778 * @param \Symfony\Component\HttpFoundation\Response $response
|
Chris@0
|
1779 * The response object which should be set.
|
Chris@0
|
1780 */
|
Chris@0
|
1781 public function setResponse(Response $response) {
|
Chris@0
|
1782 $this->response = $response;
|
Chris@0
|
1783 }
|
Chris@0
|
1784
|
Chris@0
|
1785 /**
|
Chris@0
|
1786 * Gets the response object used by the view.
|
Chris@0
|
1787 *
|
Chris@0
|
1788 * @return \Symfony\Component\HttpFoundation\Response
|
Chris@0
|
1789 * The response object of the view.
|
Chris@0
|
1790 */
|
Chris@0
|
1791 public function getResponse() {
|
Chris@0
|
1792 if (!isset($this->response)) {
|
Chris@0
|
1793 $this->response = new Response();
|
Chris@0
|
1794 }
|
Chris@0
|
1795 return $this->response;
|
Chris@0
|
1796 }
|
Chris@0
|
1797
|
Chris@0
|
1798 /**
|
Chris@0
|
1799 * Sets the request object.
|
Chris@0
|
1800 *
|
Chris@0
|
1801 * @param \Symfony\Component\HttpFoundation\Request $request
|
Chris@0
|
1802 * The request object.
|
Chris@0
|
1803 */
|
Chris@0
|
1804 public function setRequest(Request $request) {
|
Chris@0
|
1805 $this->request = $request;
|
Chris@0
|
1806 }
|
Chris@0
|
1807
|
Chris@0
|
1808 /**
|
Chris@0
|
1809 * Gets the request object.
|
Chris@0
|
1810 *
|
Chris@0
|
1811 * @return \Symfony\Component\HttpFoundation\Request
|
Chris@0
|
1812 * The request object.
|
Chris@0
|
1813 */
|
Chris@0
|
1814 public function getRequest() {
|
Chris@0
|
1815 return $this->request;
|
Chris@0
|
1816 }
|
Chris@0
|
1817
|
Chris@0
|
1818 /**
|
Chris@0
|
1819 * Gets the view's current title.
|
Chris@0
|
1820 *
|
Chris@0
|
1821 * This can change depending upon how it was built.
|
Chris@0
|
1822 *
|
Chris@0
|
1823 * @return string|false
|
Chris@0
|
1824 * The view title, FALSE if the display is not set.
|
Chris@0
|
1825 */
|
Chris@0
|
1826 public function getTitle() {
|
Chris@0
|
1827 if (empty($this->display_handler)) {
|
Chris@0
|
1828 if (!$this->setDisplay('default')) {
|
Chris@0
|
1829 return FALSE;
|
Chris@0
|
1830 }
|
Chris@0
|
1831 }
|
Chris@0
|
1832
|
Chris@0
|
1833 // During building, we might find a title override. If so, use it.
|
Chris@0
|
1834 if (!empty($this->build_info['title'])) {
|
Chris@0
|
1835 $title = $this->build_info['title'];
|
Chris@0
|
1836 }
|
Chris@0
|
1837 else {
|
Chris@0
|
1838 $title = $this->display_handler->getOption('title');
|
Chris@0
|
1839 }
|
Chris@0
|
1840
|
Chris@0
|
1841 // Allow substitutions from the first row.
|
Chris@0
|
1842 if ($this->initStyle()) {
|
Chris@0
|
1843 $title = $this->style_plugin->tokenizeValue($title, 0);
|
Chris@0
|
1844 }
|
Chris@0
|
1845 return $title;
|
Chris@0
|
1846 }
|
Chris@0
|
1847
|
Chris@0
|
1848 /**
|
Chris@0
|
1849 * Overrides the view's current title.
|
Chris@0
|
1850 *
|
Chris@0
|
1851 * The tokens in the title get's replaced before rendering.
|
Chris@0
|
1852 *
|
Chris@0
|
1853 * @return true
|
Chris@0
|
1854 * Always returns TRUE.
|
Chris@0
|
1855 */
|
Chris@0
|
1856 public function setTitle($title) {
|
Chris@0
|
1857 $this->build_info['title'] = $title;
|
Chris@0
|
1858 return TRUE;
|
Chris@0
|
1859 }
|
Chris@0
|
1860
|
Chris@0
|
1861 /**
|
Chris@0
|
1862 * Forces the view to build a title.
|
Chris@0
|
1863 */
|
Chris@0
|
1864 public function buildTitle() {
|
Chris@0
|
1865 $this->initDisplay();
|
Chris@0
|
1866
|
Chris@0
|
1867 if (empty($this->built)) {
|
Chris@0
|
1868 $this->initQuery();
|
Chris@0
|
1869 }
|
Chris@0
|
1870
|
Chris@0
|
1871 $this->initHandlers();
|
Chris@0
|
1872
|
Chris@0
|
1873 $this->_buildArguments();
|
Chris@0
|
1874 }
|
Chris@0
|
1875
|
Chris@0
|
1876 /**
|
Chris@0
|
1877 * Determines whether you can link to the view or a particular display.
|
Chris@0
|
1878 *
|
Chris@0
|
1879 * Some displays (e.g. block displays) do not have their own route, but may
|
Chris@0
|
1880 * optionally provide a link to another display that does have a route.
|
Chris@0
|
1881 *
|
Chris@0
|
1882 * @param array $args
|
Chris@0
|
1883 * (optional) The arguments.
|
Chris@0
|
1884 * @param string $display_id
|
Chris@0
|
1885 * (optional) The display ID. The current display will be used by default.
|
Chris@0
|
1886 *
|
Chris@0
|
1887 * @return bool
|
Chris@0
|
1888 * TRUE if the current display has a valid route available, FALSE otherwise.
|
Chris@0
|
1889 */
|
Chris@0
|
1890 public function hasUrl($args = NULL, $display_id = NULL) {
|
Chris@0
|
1891 if (!empty($this->override_url)) {
|
Chris@0
|
1892 return TRUE;
|
Chris@0
|
1893 }
|
Chris@0
|
1894
|
Chris@0
|
1895 // If the display has a valid route available (either its own or for a
|
Chris@0
|
1896 // linked display), then we can provide a URL for it.
|
Chris@0
|
1897 $display_handler = $this->displayHandlers->get($display_id ?: $this->current_display)->getRoutedDisplay();
|
Chris@0
|
1898 if (!$display_handler instanceof DisplayRouterInterface) {
|
Chris@0
|
1899 return FALSE;
|
Chris@0
|
1900 }
|
Chris@0
|
1901
|
Chris@0
|
1902 // Look up the route name to make sure it exists. The name may exist, but
|
Chris@0
|
1903 // not be available yet in some instances when editing a view and doing
|
Chris@0
|
1904 // a live preview.
|
Chris@0
|
1905 $provider = \Drupal::service('router.route_provider');
|
Chris@0
|
1906 try {
|
Chris@0
|
1907 $provider->getRouteByName($display_handler->getRouteName());
|
Chris@0
|
1908 }
|
Chris@0
|
1909 catch (RouteNotFoundException $e) {
|
Chris@0
|
1910 return FALSE;
|
Chris@0
|
1911 }
|
Chris@0
|
1912
|
Chris@0
|
1913 return TRUE;
|
Chris@0
|
1914 }
|
Chris@0
|
1915
|
Chris@0
|
1916 /**
|
Chris@0
|
1917 * Gets the URL for the current view.
|
Chris@0
|
1918 *
|
Chris@0
|
1919 * This URL will be adjusted for arguments.
|
Chris@0
|
1920 *
|
Chris@0
|
1921 * @param array $args
|
Chris@0
|
1922 * (optional) Passed in arguments.
|
Chris@0
|
1923 * @param string $display_id
|
Chris@0
|
1924 * (optional) Specify the display ID to link to, fallback to the current ID.
|
Chris@0
|
1925 *
|
Chris@0
|
1926 * @return \Drupal\Core\Url
|
Chris@0
|
1927 * The URL of the current view.
|
Chris@0
|
1928 *
|
Chris@0
|
1929 * @throws \InvalidArgumentException
|
Chris@0
|
1930 * Thrown when the current view doesn't have a route available.
|
Chris@0
|
1931 */
|
Chris@0
|
1932 public function getUrl($args = NULL, $display_id = NULL) {
|
Chris@0
|
1933 if (!empty($this->override_url)) {
|
Chris@0
|
1934 return $this->override_url;
|
Chris@0
|
1935 }
|
Chris@0
|
1936
|
Chris@0
|
1937 $display_handler = $this->displayHandlers->get($display_id ?: $this->current_display)->getRoutedDisplay();
|
Chris@0
|
1938 if (!$display_handler instanceof DisplayRouterInterface) {
|
Chris@0
|
1939 throw new \InvalidArgumentException('You cannot create a URL to a display without routes.');
|
Chris@0
|
1940 }
|
Chris@0
|
1941
|
Chris@0
|
1942 if (!isset($args)) {
|
Chris@0
|
1943 $args = $this->args;
|
Chris@0
|
1944
|
Chris@0
|
1945 // Exclude arguments that were computed, not passed on the URL.
|
Chris@0
|
1946 $position = 0;
|
Chris@0
|
1947 if (!empty($this->argument)) {
|
Chris@0
|
1948 foreach ($this->argument as $argument) {
|
Chris@0
|
1949 if (!empty($argument->is_default) && !empty($argument->options['default_argument_skip_url'])) {
|
Chris@0
|
1950 unset($args[$position]);
|
Chris@0
|
1951 }
|
Chris@0
|
1952 $position++;
|
Chris@0
|
1953 }
|
Chris@0
|
1954 }
|
Chris@0
|
1955 }
|
Chris@0
|
1956
|
Chris@0
|
1957 $path = $this->getPath();
|
Chris@0
|
1958
|
Chris@0
|
1959 // Don't bother working if there's nothing to do:
|
Chris@0
|
1960 if (empty($path) || (empty($args) && strpos($path, '%') === FALSE)) {
|
Chris@0
|
1961 return $display_handler->getUrlInfo();
|
Chris@0
|
1962 }
|
Chris@0
|
1963
|
Chris@0
|
1964 $argument_keys = isset($this->argument) ? array_keys($this->argument) : [];
|
Chris@0
|
1965 $id = current($argument_keys);
|
Chris@0
|
1966
|
Chris@0
|
1967 /** @var \Drupal\Core\Url $url */
|
Chris@0
|
1968 $url = $display_handler->getUrlInfo();
|
Chris@0
|
1969 $route = $this->routeProvider->getRouteByName($url->getRouteName());
|
Chris@0
|
1970
|
Chris@0
|
1971 $variables = $route->compile()->getVariables();
|
Chris@0
|
1972 $parameters = $url->getRouteParameters();
|
Chris@0
|
1973
|
Chris@0
|
1974 foreach ($variables as $variable_name) {
|
Chris@0
|
1975 if (empty($args)) {
|
Chris@0
|
1976 // Try to never put % in a URL; use the wildcard instead.
|
Chris@0
|
1977 if ($id && !empty($this->argument[$id]->options['exception']['value'])) {
|
Chris@0
|
1978 $parameters[$variable_name] = $this->argument[$id]->options['exception']['value'];
|
Chris@0
|
1979 }
|
Chris@0
|
1980 else {
|
Chris@0
|
1981 // Provide some fallback in case no exception value could be found.
|
Chris@0
|
1982 $parameters[$variable_name] = '*';
|
Chris@0
|
1983 }
|
Chris@0
|
1984 }
|
Chris@0
|
1985 else {
|
Chris@0
|
1986 $parameters[$variable_name] = array_shift($args);
|
Chris@0
|
1987 }
|
Chris@0
|
1988
|
Chris@0
|
1989 if ($id) {
|
Chris@0
|
1990 $id = next($argument_keys);
|
Chris@0
|
1991 }
|
Chris@0
|
1992 }
|
Chris@0
|
1993
|
Chris@0
|
1994 $url->setRouteParameters($parameters);
|
Chris@0
|
1995 return $url;
|
Chris@0
|
1996 }
|
Chris@0
|
1997
|
Chris@0
|
1998 /**
|
Chris@0
|
1999 * Gets the Url object associated with the display handler.
|
Chris@0
|
2000 *
|
Chris@0
|
2001 * @param string $display_id
|
Chris@0
|
2002 * (optional) The display ID (used only to detail an exception).
|
Chris@0
|
2003 *
|
Chris@0
|
2004 * @return \Drupal\Core\Url
|
Chris@0
|
2005 * The display handlers URL object.
|
Chris@0
|
2006 *
|
Chris@0
|
2007 * @throws \InvalidArgumentException
|
Chris@0
|
2008 * Thrown when the display plugin does not have a URL to return.
|
Chris@0
|
2009 */
|
Chris@0
|
2010 public function getUrlInfo($display_id = '') {
|
Chris@0
|
2011 $this->initDisplay();
|
Chris@0
|
2012 if (!$this->display_handler instanceof DisplayRouterInterface) {
|
Chris@0
|
2013 throw new \InvalidArgumentException("You cannot generate a URL for the display '$display_id'");
|
Chris@0
|
2014 }
|
Chris@0
|
2015 return $this->display_handler->getUrlInfo();
|
Chris@0
|
2016 }
|
Chris@0
|
2017
|
Chris@0
|
2018 /**
|
Chris@0
|
2019 * Gets the base path used for this view.
|
Chris@0
|
2020 *
|
Chris@0
|
2021 * @return string|false
|
Chris@0
|
2022 * The base path used for the view or FALSE if setting the display fails.
|
Chris@0
|
2023 */
|
Chris@0
|
2024 public function getPath() {
|
Chris@0
|
2025 if (!empty($this->override_path)) {
|
Chris@0
|
2026 return $this->override_path;
|
Chris@0
|
2027 }
|
Chris@0
|
2028
|
Chris@0
|
2029 if (empty($this->display_handler)) {
|
Chris@0
|
2030 if (!$this->setDisplay('default')) {
|
Chris@0
|
2031 return FALSE;
|
Chris@0
|
2032 }
|
Chris@0
|
2033 }
|
Chris@0
|
2034 return $this->display_handler->getPath();
|
Chris@0
|
2035 }
|
Chris@0
|
2036
|
Chris@0
|
2037 /**
|
Chris@0
|
2038 * Gets the current user.
|
Chris@0
|
2039 *
|
Chris@0
|
2040 * Views plugins can receive the current user in order to not need dependency
|
Chris@0
|
2041 * injection.
|
Chris@0
|
2042 *
|
Chris@0
|
2043 * @return \Drupal\Core\Session\AccountInterface
|
Chris@0
|
2044 * The current user.
|
Chris@0
|
2045 */
|
Chris@0
|
2046 public function getUser() {
|
Chris@0
|
2047 return $this->user;
|
Chris@0
|
2048 }
|
Chris@0
|
2049
|
Chris@0
|
2050 /**
|
Chris@0
|
2051 * Creates a duplicate ViewExecutable object.
|
Chris@0
|
2052 *
|
Chris@0
|
2053 * Makes a copy of this view that has been sanitized of handlers, any runtime
|
Chris@0
|
2054 * data, ID, and UUID.
|
Chris@0
|
2055 */
|
Chris@0
|
2056 public function createDuplicate() {
|
Chris@0
|
2057 return $this->storage->createDuplicate()->getExecutable();
|
Chris@0
|
2058 }
|
Chris@0
|
2059
|
Chris@0
|
2060 /**
|
Chris@0
|
2061 * Unsets references so that a $view object may be properly garbage collected.
|
Chris@0
|
2062 */
|
Chris@0
|
2063 public function destroy() {
|
Chris@0
|
2064 foreach ($this::getHandlerTypes() as $type => $info) {
|
Chris@0
|
2065 if (isset($this->$type)) {
|
Chris@0
|
2066 foreach ($this->{$type} as $handler) {
|
Chris@0
|
2067 $handler->destroy();
|
Chris@0
|
2068 }
|
Chris@0
|
2069 }
|
Chris@0
|
2070 }
|
Chris@0
|
2071
|
Chris@0
|
2072 if (isset($this->style_plugin)) {
|
Chris@0
|
2073 $this->style_plugin->destroy();
|
Chris@0
|
2074 }
|
Chris@0
|
2075
|
Chris@0
|
2076 $reflection = new \ReflectionClass($this);
|
Chris@0
|
2077 $defaults = $reflection->getDefaultProperties();
|
Chris@0
|
2078 // The external dependencies should not be reset. This is not generated by
|
Chris@0
|
2079 // the execution of a view.
|
Chris@0
|
2080 unset(
|
Chris@0
|
2081 $defaults['storage'],
|
Chris@0
|
2082 $defaults['user'],
|
Chris@0
|
2083 $defaults['request'],
|
Chris@0
|
2084 $defaults['routeProvider'],
|
Chris@0
|
2085 $defaults['viewsData']
|
Chris@0
|
2086 );
|
Chris@0
|
2087
|
Chris@0
|
2088 foreach ($defaults as $property => $default) {
|
Chris@0
|
2089 $this->{$property} = $default;
|
Chris@0
|
2090 }
|
Chris@0
|
2091 }
|
Chris@0
|
2092
|
Chris@0
|
2093 /**
|
Chris@0
|
2094 * Makes sure the view is completely valid.
|
Chris@0
|
2095 *
|
Chris@0
|
2096 * @return array
|
Chris@0
|
2097 * An array of error strings. This will be empty if there are no validation
|
Chris@0
|
2098 * errors.
|
Chris@0
|
2099 */
|
Chris@0
|
2100 public function validate() {
|
Chris@0
|
2101 $errors = [];
|
Chris@0
|
2102
|
Chris@0
|
2103 $this->initDisplay();
|
Chris@0
|
2104 $current_display = $this->current_display;
|
Chris@0
|
2105
|
Chris@0
|
2106 foreach ($this->displayHandlers as $id => $display) {
|
Chris@0
|
2107 if (!empty($display)) {
|
Chris@0
|
2108 if (!empty($display->display['deleted'])) {
|
Chris@0
|
2109 continue;
|
Chris@0
|
2110 }
|
Chris@0
|
2111
|
Chris@0
|
2112 $result = $this->displayHandlers->get($id)->validate();
|
Chris@0
|
2113 if (!empty($result) && is_array($result)) {
|
Chris@0
|
2114 $errors[$id] = $result;
|
Chris@0
|
2115 }
|
Chris@0
|
2116 }
|
Chris@0
|
2117 }
|
Chris@0
|
2118
|
Chris@0
|
2119 $this->setDisplay($current_display);
|
Chris@0
|
2120
|
Chris@0
|
2121 return $errors;
|
Chris@0
|
2122 }
|
Chris@0
|
2123
|
Chris@0
|
2124 /**
|
Chris@0
|
2125 * Provides a list of views handler types used in a view.
|
Chris@0
|
2126 *
|
Chris@0
|
2127 * This also provides some information about the views handler types.
|
Chris@0
|
2128 *
|
Chris@0
|
2129 * @return array
|
Chris@0
|
2130 * An array of associative arrays containing:
|
Chris@0
|
2131 * - title: The title of the handler type.
|
Chris@0
|
2132 * - ltitle: The lowercase title of the handler type.
|
Chris@0
|
2133 * - stitle: A singular title of the handler type.
|
Chris@0
|
2134 * - lstitle: A singular lowercase title of the handler type.
|
Chris@0
|
2135 * - plural: Plural version of the handler type.
|
Chris@0
|
2136 * - (optional) type: The actual internal used handler type. This key is
|
Chris@0
|
2137 * just used for header,footer,empty to link to the internal type: area.
|
Chris@0
|
2138 */
|
Chris@0
|
2139 public static function getHandlerTypes() {
|
Chris@0
|
2140 return Views::getHandlerTypes();
|
Chris@0
|
2141 }
|
Chris@0
|
2142
|
Chris@0
|
2143 /**
|
Chris@0
|
2144 * Returns the valid types of plugins that can be used.
|
Chris@0
|
2145 *
|
Chris@0
|
2146 * @return array
|
Chris@0
|
2147 * An array of plugin type strings.
|
Chris@0
|
2148 */
|
Chris@0
|
2149 public static function getPluginTypes($type = NULL) {
|
Chris@0
|
2150 return Views::getPluginTypes($type);
|
Chris@0
|
2151 }
|
Chris@0
|
2152
|
Chris@0
|
2153 /**
|
Chris@0
|
2154 * Adds an instance of a handler to the view.
|
Chris@0
|
2155 *
|
Chris@0
|
2156 * Items may be fields, filters, sort criteria, or arguments.
|
Chris@0
|
2157 *
|
Chris@0
|
2158 * @param string $display_id
|
Chris@0
|
2159 * The machine name of the display.
|
Chris@0
|
2160 * @param string $type
|
Chris@0
|
2161 * The type of handler being added.
|
Chris@0
|
2162 * @param string $table
|
Chris@0
|
2163 * The name of the table this handler is from.
|
Chris@0
|
2164 * @param string $field
|
Chris@0
|
2165 * The name of the field this handler is from.
|
Chris@0
|
2166 * @param array $options
|
Chris@0
|
2167 * (optional) Extra options for this instance. Defaults to an empty array.
|
Chris@0
|
2168 * @param string $id
|
Chris@0
|
2169 * (optional) A unique ID for this handler instance. Defaults to NULL, in
|
Chris@0
|
2170 * which case one will be generated.
|
Chris@0
|
2171 *
|
Chris@0
|
2172 * @return string
|
Chris@0
|
2173 * The unique ID for this handler instance.
|
Chris@0
|
2174 */
|
Chris@0
|
2175 public function addHandler($display_id, $type, $table, $field, $options = [], $id = NULL) {
|
Chris@0
|
2176 $types = $this::getHandlerTypes();
|
Chris@0
|
2177 $this->setDisplay($display_id);
|
Chris@0
|
2178
|
Chris@0
|
2179 $data = $this->viewsData->get($table);
|
Chris@0
|
2180 $fields = $this->displayHandlers->get($display_id)->getOption($types[$type]['plural']);
|
Chris@0
|
2181
|
Chris@0
|
2182 if (empty($id)) {
|
Chris@0
|
2183 $id = $this->generateHandlerId($field, $fields);
|
Chris@0
|
2184 }
|
Chris@0
|
2185
|
Chris@0
|
2186 // If the desired type is not found, use the original value directly.
|
Chris@0
|
2187 $handler_type = !empty($types[$type]['type']) ? $types[$type]['type'] : $type;
|
Chris@0
|
2188
|
Chris@0
|
2189 $fields[$id] = [
|
Chris@0
|
2190 'id' => $id,
|
Chris@0
|
2191 'table' => $table,
|
Chris@0
|
2192 'field' => $field,
|
Chris@0
|
2193 ] + $options;
|
Chris@0
|
2194
|
Chris@0
|
2195 if (isset($data['table']['entity type'])) {
|
Chris@0
|
2196 $fields[$id]['entity_type'] = $data['table']['entity type'];
|
Chris@0
|
2197 }
|
Chris@0
|
2198 if (isset($data[$field]['entity field'])) {
|
Chris@0
|
2199 $fields[$id]['entity_field'] = $data[$field]['entity field'];
|
Chris@0
|
2200 }
|
Chris@0
|
2201
|
Chris@0
|
2202 // Load the plugin ID if available.
|
Chris@0
|
2203 if (isset($data[$field][$handler_type]['id'])) {
|
Chris@0
|
2204 $fields[$id]['plugin_id'] = $data[$field][$handler_type]['id'];
|
Chris@0
|
2205 }
|
Chris@0
|
2206
|
Chris@0
|
2207 $this->displayHandlers->get($display_id)->setOption($types[$type]['plural'], $fields);
|
Chris@0
|
2208
|
Chris@0
|
2209 return $id;
|
Chris@0
|
2210 }
|
Chris@0
|
2211
|
Chris@0
|
2212 /**
|
Chris@0
|
2213 * Generates a unique ID for an handler instance.
|
Chris@0
|
2214 *
|
Chris@0
|
2215 * These handler instances are typically fields, filters, sort criteria, or
|
Chris@0
|
2216 * arguments.
|
Chris@0
|
2217 *
|
Chris@0
|
2218 * @param string $requested_id
|
Chris@0
|
2219 * The requested ID for the handler instance.
|
Chris@0
|
2220 * @param array $existing_items
|
Chris@0
|
2221 * An array of existing handler instances, keyed by their IDs.
|
Chris@0
|
2222 *
|
Chris@0
|
2223 * @return string
|
Chris@0
|
2224 * A unique ID. This will be equal to $requested_id if no handler instance
|
Chris@0
|
2225 * with that ID already exists. Otherwise, it will be appended with an
|
Chris@0
|
2226 * integer to make it unique, e.g., "{$requested_id}_1",
|
Chris@0
|
2227 * "{$requested_id}_2", etc.
|
Chris@0
|
2228 */
|
Chris@0
|
2229 public static function generateHandlerId($requested_id, $existing_items) {
|
Chris@0
|
2230 $count = 0;
|
Chris@0
|
2231 $id = $requested_id;
|
Chris@0
|
2232 while (!empty($existing_items[$id])) {
|
Chris@0
|
2233 $id = $requested_id . '_' . ++$count;
|
Chris@0
|
2234 }
|
Chris@0
|
2235 return $id;
|
Chris@0
|
2236 }
|
Chris@0
|
2237
|
Chris@0
|
2238 /**
|
Chris@0
|
2239 * Gets an array of handler instances for the current display.
|
Chris@0
|
2240 *
|
Chris@0
|
2241 * @param string $type
|
Chris@0
|
2242 * The type of handlers to retrieve.
|
Chris@0
|
2243 * @param string $display_id
|
Chris@0
|
2244 * (optional) A specific display machine name to use. If NULL, the current
|
Chris@0
|
2245 * display will be used.
|
Chris@0
|
2246 *
|
Chris@0
|
2247 * @return array
|
Chris@0
|
2248 * An array of handler instances of a given type for this display.
|
Chris@0
|
2249 */
|
Chris@0
|
2250 public function getHandlers($type, $display_id = NULL) {
|
Chris@0
|
2251 $old_display_id = !empty($this->current_display) ? $this->current_display : 'default';
|
Chris@0
|
2252
|
Chris@0
|
2253 $this->setDisplay($display_id);
|
Chris@0
|
2254
|
Chris@0
|
2255 if (!isset($display_id)) {
|
Chris@0
|
2256 $display_id = $this->current_display;
|
Chris@0
|
2257 }
|
Chris@0
|
2258
|
Chris@0
|
2259 // Get info about the types so we can get the right data.
|
Chris@0
|
2260 $types = static::getHandlerTypes();
|
Chris@0
|
2261
|
Chris@0
|
2262 $handlers = $this->displayHandlers->get($display_id)->getOption($types[$type]['plural']);
|
Chris@0
|
2263
|
Chris@0
|
2264 // Restore initial display id (if any) or set to 'default'.
|
Chris@0
|
2265 if ($display_id != $old_display_id) {
|
Chris@0
|
2266 $this->setDisplay($old_display_id);
|
Chris@0
|
2267 }
|
Chris@0
|
2268 return $handlers;
|
Chris@0
|
2269 }
|
Chris@0
|
2270
|
Chris@0
|
2271 /**
|
Chris@0
|
2272 * Gets the configuration of a handler instance on a given display.
|
Chris@0
|
2273 *
|
Chris@0
|
2274 * @param string $display_id
|
Chris@0
|
2275 * The machine name of the display.
|
Chris@0
|
2276 * @param string $type
|
Chris@0
|
2277 * The type of handler to retrieve.
|
Chris@0
|
2278 * @param string $id
|
Chris@0
|
2279 * The ID of the handler to retrieve.
|
Chris@0
|
2280 *
|
Chris@0
|
2281 * @return array|null
|
Chris@0
|
2282 * Either the handler instance's configuration, or NULL if the handler is
|
Chris@0
|
2283 * not used on the display.
|
Chris@0
|
2284 */
|
Chris@0
|
2285 public function getHandler($display_id, $type, $id) {
|
Chris@0
|
2286 // Get info about the types so we can get the right data.
|
Chris@0
|
2287 $types = static::getHandlerTypes();
|
Chris@0
|
2288 // Initialize the display
|
Chris@0
|
2289 $this->setDisplay($display_id);
|
Chris@0
|
2290
|
Chris@0
|
2291 // Get the existing configuration
|
Chris@0
|
2292 $fields = $this->displayHandlers->get($display_id)->getOption($types[$type]['plural']);
|
Chris@0
|
2293
|
Chris@0
|
2294 return isset($fields[$id]) ? $fields[$id] : NULL;
|
Chris@0
|
2295 }
|
Chris@0
|
2296
|
Chris@0
|
2297 /**
|
Chris@0
|
2298 * Sets the configuration of a handler instance on a given display.
|
Chris@0
|
2299 *
|
Chris@0
|
2300 * @param string $display_id
|
Chris@0
|
2301 * The machine name of the display.
|
Chris@0
|
2302 * @param string $type
|
Chris@0
|
2303 * The type of handler being set.
|
Chris@0
|
2304 * @param string $id
|
Chris@0
|
2305 * The ID of the handler being set.
|
Chris@0
|
2306 * @param array|null $item
|
Chris@0
|
2307 * An array of configuration for a handler, or NULL to remove this instance.
|
Chris@0
|
2308 *
|
Chris@0
|
2309 * @see set_item_option()
|
Chris@0
|
2310 */
|
Chris@0
|
2311 public function setHandler($display_id, $type, $id, $item) {
|
Chris@0
|
2312 // Get info about the types so we can get the right data.
|
Chris@0
|
2313 $types = static::getHandlerTypes();
|
Chris@0
|
2314 // Initialize the display.
|
Chris@0
|
2315 $this->setDisplay($display_id);
|
Chris@0
|
2316
|
Chris@0
|
2317 // Get the existing configuration.
|
Chris@0
|
2318 $fields = $this->displayHandlers->get($display_id)->getOption($types[$type]['plural']);
|
Chris@0
|
2319 if (isset($item)) {
|
Chris@0
|
2320 $fields[$id] = $item;
|
Chris@0
|
2321 }
|
Chris@0
|
2322
|
Chris@0
|
2323 // Store.
|
Chris@0
|
2324 $this->displayHandlers->get($display_id)->setOption($types[$type]['plural'], $fields);
|
Chris@0
|
2325 }
|
Chris@0
|
2326
|
Chris@0
|
2327 /**
|
Chris@0
|
2328 * Removes configuration for a handler instance on a given display.
|
Chris@0
|
2329 *
|
Chris@0
|
2330 * @param string $display_id
|
Chris@0
|
2331 * The machine name of the display.
|
Chris@0
|
2332 * @param string $type
|
Chris@0
|
2333 * The type of handler being removed.
|
Chris@0
|
2334 * @param string $id
|
Chris@0
|
2335 * The ID of the handler being removed.
|
Chris@0
|
2336 */
|
Chris@0
|
2337 public function removeHandler($display_id, $type, $id) {
|
Chris@0
|
2338 // Get info about the types so we can get the right data.
|
Chris@0
|
2339 $types = static::getHandlerTypes();
|
Chris@0
|
2340 // Initialize the display.
|
Chris@0
|
2341 $this->setDisplay($display_id);
|
Chris@0
|
2342
|
Chris@0
|
2343 // Get the existing configuration.
|
Chris@0
|
2344 $fields = $this->displayHandlers->get($display_id)->getOption($types[$type]['plural']);
|
Chris@0
|
2345 // Unset the item.
|
Chris@0
|
2346 unset($fields[$id]);
|
Chris@0
|
2347
|
Chris@0
|
2348 // Store.
|
Chris@0
|
2349 $this->displayHandlers->get($display_id)->setOption($types[$type]['plural'], $fields);
|
Chris@0
|
2350 }
|
Chris@0
|
2351
|
Chris@0
|
2352 /**
|
Chris@0
|
2353 * Sets an option on a handler instance.
|
Chris@0
|
2354 *
|
Chris@0
|
2355 * Use this only if you have just 1 or 2 options to set; if you have many,
|
Chris@0
|
2356 * consider getting the handler instance, adding the options and using
|
Chris@0
|
2357 * set_item() directly.
|
Chris@0
|
2358 *
|
Chris@0
|
2359 * @param string $display_id
|
Chris@0
|
2360 * The machine name of the display.
|
Chris@0
|
2361 * @param string $type
|
Chris@0
|
2362 * The type of handler being set.
|
Chris@0
|
2363 * @param string $id
|
Chris@0
|
2364 * The ID of the handler being set.
|
Chris@0
|
2365 * @param string $option
|
Chris@0
|
2366 * The configuration key for the value being set.
|
Chris@0
|
2367 * @param mixed $value
|
Chris@0
|
2368 * The value being set.
|
Chris@0
|
2369 *
|
Chris@0
|
2370 * @see set_item()
|
Chris@0
|
2371 */
|
Chris@0
|
2372 public function setHandlerOption($display_id, $type, $id, $option, $value) {
|
Chris@0
|
2373 $item = $this->getHandler($display_id, $type, $id);
|
Chris@0
|
2374 $item[$option] = $value;
|
Chris@0
|
2375 $this->setHandler($display_id, $type, $id, $item);
|
Chris@0
|
2376 }
|
Chris@0
|
2377
|
Chris@0
|
2378 /**
|
Chris@0
|
2379 * Enables admin links on the rendered view.
|
Chris@0
|
2380 *
|
Chris@0
|
2381 * @param bool $show_admin_links
|
Chris@0
|
2382 * TRUE if the admin links should be shown.
|
Chris@0
|
2383 */
|
Chris@0
|
2384 public function setShowAdminLinks($show_admin_links) {
|
Chris@0
|
2385 $this->showAdminLinks = (bool) $show_admin_links;
|
Chris@0
|
2386 }
|
Chris@0
|
2387
|
Chris@0
|
2388 /**
|
Chris@0
|
2389 * Returns whether admin links should be rendered on the view.
|
Chris@0
|
2390 *
|
Chris@0
|
2391 * @return bool
|
Chris@0
|
2392 * TRUE if admin links should be rendered, else FALSE.
|
Chris@0
|
2393 */
|
Chris@0
|
2394 public function getShowAdminLinks() {
|
Chris@0
|
2395 if (!isset($this->showAdminLinks)) {
|
Chris@0
|
2396 return $this->getDisplay()->getOption('show_admin_links');
|
Chris@0
|
2397 }
|
Chris@0
|
2398 return $this->showAdminLinks;
|
Chris@0
|
2399 }
|
Chris@0
|
2400
|
Chris@0
|
2401 /**
|
Chris@0
|
2402 * Merges all plugin default values for each display.
|
Chris@0
|
2403 */
|
Chris@0
|
2404 public function mergeDefaults() {
|
Chris@0
|
2405 $this->initDisplay();
|
Chris@0
|
2406 // Initialize displays and merge all plugin defaults.
|
Chris@0
|
2407 foreach ($this->displayHandlers as $display) {
|
Chris@0
|
2408 $display->mergeDefaults();
|
Chris@0
|
2409 }
|
Chris@0
|
2410 }
|
Chris@0
|
2411
|
Chris@0
|
2412 /**
|
Chris@0
|
2413 * Provides a full array of possible theme functions to try for a given hook.
|
Chris@0
|
2414 *
|
Chris@0
|
2415 * @param string $hook
|
Chris@0
|
2416 * The hook to use. This is the base theme/template name.
|
Chris@0
|
2417 *
|
Chris@0
|
2418 * @return array
|
Chris@0
|
2419 * An array of theme hook suggestions.
|
Chris@0
|
2420 */
|
Chris@0
|
2421 public function buildThemeFunctions($hook) {
|
Chris@0
|
2422 $themes = [];
|
Chris@0
|
2423 $display = isset($this->display_handler) ? $this->display_handler->display : NULL;
|
Chris@0
|
2424 $id = $this->storage->id();
|
Chris@0
|
2425
|
Chris@0
|
2426 if ($display) {
|
Chris@0
|
2427 $themes[] = $hook . '__' . $id . '__' . $display['id'];
|
Chris@0
|
2428 $themes[] = $hook . '__' . $display['id'];
|
Chris@0
|
2429 // Add theme suggestions for each single tag.
|
Chris@0
|
2430 foreach (Tags::explode($this->storage->get('tag')) as $tag) {
|
Chris@0
|
2431 $themes[] = $hook . '__' . preg_replace('/[^a-z0-9]/', '_', strtolower($tag));
|
Chris@0
|
2432 }
|
Chris@0
|
2433
|
Chris@0
|
2434 if ($display['id'] != $display['display_plugin']) {
|
Chris@0
|
2435 $themes[] = $hook . '__' . $id . '__' . $display['display_plugin'];
|
Chris@0
|
2436 $themes[] = $hook . '__' . $display['display_plugin'];
|
Chris@0
|
2437 }
|
Chris@0
|
2438 }
|
Chris@0
|
2439 $themes[] = $hook . '__' . $id;
|
Chris@0
|
2440 $themes[] = $hook;
|
Chris@0
|
2441
|
Chris@0
|
2442 return $themes;
|
Chris@0
|
2443 }
|
Chris@0
|
2444
|
Chris@0
|
2445 /**
|
Chris@0
|
2446 * Determines if this view has form elements.
|
Chris@0
|
2447 *
|
Chris@0
|
2448 * @return bool
|
Chris@0
|
2449 * TRUE if this view contains handlers with views form implementations,
|
Chris@0
|
2450 * FALSE otherwise.
|
Chris@0
|
2451 */
|
Chris@0
|
2452 public function hasFormElements() {
|
Chris@0
|
2453 foreach ($this->field as $field) {
|
Chris@0
|
2454 if (property_exists($field, 'views_form_callback') || method_exists($field, 'viewsForm')) {
|
Chris@0
|
2455 return TRUE;
|
Chris@0
|
2456 }
|
Chris@0
|
2457 }
|
Chris@0
|
2458 $area_handlers = array_merge(array_values($this->header), array_values($this->footer));
|
Chris@0
|
2459 $empty = empty($this->result);
|
Chris@0
|
2460 foreach ($area_handlers as $area) {
|
Chris@0
|
2461 if (method_exists($area, 'viewsForm') && !$area->viewsFormEmpty($empty)) {
|
Chris@0
|
2462 return TRUE;
|
Chris@0
|
2463 }
|
Chris@0
|
2464 }
|
Chris@0
|
2465
|
Chris@0
|
2466 return FALSE;
|
Chris@0
|
2467 }
|
Chris@0
|
2468
|
Chris@0
|
2469 /**
|
Chris@0
|
2470 * Gets dependencies for the view.
|
Chris@0
|
2471 *
|
Chris@0
|
2472 * @see \Drupal\views\Entity\View::calculateDependencies()
|
Chris@0
|
2473 * @see \Drupal\views\Entity\View::getDependencies()
|
Chris@0
|
2474 *
|
Chris@0
|
2475 * @return array
|
Chris@0
|
2476 * An array of dependencies grouped by type (module, theme, entity).
|
Chris@0
|
2477 */
|
Chris@0
|
2478 public function getDependencies() {
|
Chris@0
|
2479 return $this->storage->calculateDependencies()->getDependencies();
|
Chris@0
|
2480 }
|
Chris@0
|
2481
|
Chris@0
|
2482 /**
|
Chris@0
|
2483 * Magic method implementation to serialize the view executable.
|
Chris@0
|
2484 *
|
Chris@0
|
2485 * @return array
|
Chris@0
|
2486 * The names of all variables that should be serialized.
|
Chris@0
|
2487 */
|
Chris@0
|
2488 public function __sleep() {
|
Chris@0
|
2489 // Limit to only the required data which is needed to properly restore the
|
Chris@0
|
2490 // state during unserialization.
|
Chris@0
|
2491 $this->serializationData = [
|
Chris@0
|
2492 'storage' => $this->storage->id(),
|
Chris@0
|
2493 'views_data' => $this->viewsData->_serviceId,
|
Chris@0
|
2494 'route_provider' => $this->routeProvider->_serviceId,
|
Chris@0
|
2495 'current_display' => $this->current_display,
|
Chris@0
|
2496 'args' => $this->args,
|
Chris@0
|
2497 'current_page' => $this->current_page,
|
Chris@0
|
2498 'exposed_input' => $this->exposed_input,
|
Chris@0
|
2499 'exposed_raw_input' => $this->exposed_raw_input,
|
Chris@0
|
2500 'exposed_data' => $this->exposed_data,
|
Chris@0
|
2501 'dom_id' => $this->dom_id,
|
Chris@0
|
2502 'executed' => $this->executed,
|
Chris@0
|
2503 ];
|
Chris@0
|
2504 return ['serializationData'];
|
Chris@0
|
2505 }
|
Chris@0
|
2506
|
Chris@0
|
2507 /**
|
Chris@0
|
2508 * Magic method implementation to unserialize the view executable.
|
Chris@0
|
2509 */
|
Chris@0
|
2510 public function __wakeup() {
|
Chris@0
|
2511 // There are cases, like in testing where we don't have a container
|
Chris@0
|
2512 // available.
|
Chris@0
|
2513 if (\Drupal::hasContainer() && !empty($this->serializationData)) {
|
Chris@0
|
2514 // Load and reference the storage.
|
Chris@0
|
2515 $this->storage = \Drupal::entityTypeManager()->getStorage('view')
|
Chris@0
|
2516 ->load($this->serializationData['storage']);
|
Chris@0
|
2517 $this->storage->set('executable', $this);
|
Chris@0
|
2518
|
Chris@0
|
2519 // Attach all necessary services.
|
Chris@0
|
2520 $this->user = \Drupal::currentUser();
|
Chris@0
|
2521 $this->viewsData = \Drupal::service($this->serializationData['views_data']);
|
Chris@0
|
2522 $this->routeProvider = \Drupal::service($this->serializationData['route_provider']);
|
Chris@0
|
2523
|
Chris@0
|
2524 // Restore the state of this executable.
|
Chris@0
|
2525 if ($request = \Drupal::request()) {
|
Chris@0
|
2526 $this->setRequest($request);
|
Chris@0
|
2527 }
|
Chris@0
|
2528 $this->setDisplay($this->serializationData['current_display']);
|
Chris@0
|
2529 $this->setArguments($this->serializationData['args']);
|
Chris@0
|
2530 $this->setCurrentPage($this->serializationData['current_page']);
|
Chris@0
|
2531 $this->setExposedInput($this->serializationData['exposed_input']);
|
Chris@0
|
2532 $this->exposed_data = $this->serializationData['exposed_data'];
|
Chris@0
|
2533 $this->exposed_raw_input = $this->serializationData['exposed_raw_input'];
|
Chris@0
|
2534 $this->dom_id = $this->serializationData['dom_id'];
|
Chris@0
|
2535
|
Chris@0
|
2536 $this->initHandlers();
|
Chris@0
|
2537
|
Chris@0
|
2538 // If the display was previously executed, execute it now.
|
Chris@0
|
2539 if ($this->serializationData['executed']) {
|
Chris@0
|
2540 $this->execute($this->current_display);
|
Chris@0
|
2541 }
|
Chris@0
|
2542 }
|
Chris@0
|
2543 // Unset serializationData since it serves no further purpose.
|
Chris@0
|
2544 unset($this->serializationData);
|
Chris@0
|
2545 }
|
Chris@0
|
2546
|
Chris@0
|
2547 }
|