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@0
|
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@0
|
928 if ($this->pager->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@0
|
954 if (!empty($this->pager) && $this->pager->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@0
|
1099 // Set the argument, which will also validate that the argument can be set.
|
Chris@0
|
1100 if (!$argument->setArgument($arg)) {
|
Chris@0
|
1101 $status = $argument->validateFail($arg);
|
Chris@0
|
1102 break;
|
Chris@0
|
1103 }
|
Chris@0
|
1104
|
Chris@0
|
1105 if ($argument->isException()) {
|
Chris@0
|
1106 $arg_title = $argument->exceptionTitle();
|
Chris@0
|
1107 }
|
Chris@0
|
1108 else {
|
Chris@0
|
1109 $arg_title = $argument->getTitle();
|
Chris@0
|
1110 $argument->query($this->display_handler->useGroupBy());
|
Chris@0
|
1111 }
|
Chris@0
|
1112
|
Chris@0
|
1113 // Add this argument's substitution
|
Chris@0
|
1114 $substitutions["{{ arguments.$id }}"] = $arg_title;
|
Chris@0
|
1115 $substitutions["{{ raw_arguments.$id }}"] = strip_tags(Html::decodeEntities($arg));
|
Chris@0
|
1116
|
Chris@0
|
1117 // Test to see if we should use this argument's title
|
Chris@0
|
1118 if (!empty($argument->options['title_enable']) && !empty($argument->options['title'])) {
|
Chris@0
|
1119 $title = $argument->options['title'];
|
Chris@0
|
1120 }
|
Chris@0
|
1121 }
|
Chris@0
|
1122 else {
|
Chris@0
|
1123 // determine default condition and handle.
|
Chris@0
|
1124 $status = $argument->defaultAction();
|
Chris@0
|
1125 break;
|
Chris@0
|
1126 }
|
Chris@0
|
1127
|
Chris@0
|
1128 // Be safe with references and loops:
|
Chris@0
|
1129 unset($argument);
|
Chris@0
|
1130 }
|
Chris@0
|
1131
|
Chris@0
|
1132 // set the title in the build info.
|
Chris@0
|
1133 if (!empty($title)) {
|
Chris@0
|
1134 $this->build_info['title'] = $title;
|
Chris@0
|
1135 }
|
Chris@0
|
1136
|
Chris@0
|
1137 // Store the arguments for later use.
|
Chris@0
|
1138 $this->build_info['substitutions'] = $substitutions;
|
Chris@0
|
1139
|
Chris@0
|
1140 return $status;
|
Chris@0
|
1141 }
|
Chris@0
|
1142
|
Chris@0
|
1143 /**
|
Chris@0
|
1144 * Gets the current query plugin.
|
Chris@0
|
1145 *
|
Chris@0
|
1146 * @return \Drupal\views\Plugin\views\query\QueryPluginBase
|
Chris@0
|
1147 * The current query plugin.
|
Chris@0
|
1148 */
|
Chris@0
|
1149 public function getQuery() {
|
Chris@0
|
1150 if (!isset($this->query)) {
|
Chris@0
|
1151 $this->initQuery();
|
Chris@0
|
1152 }
|
Chris@0
|
1153
|
Chris@0
|
1154 return $this->query;
|
Chris@0
|
1155 }
|
Chris@0
|
1156
|
Chris@0
|
1157 /**
|
Chris@0
|
1158 * Initializes the query object for the view.
|
Chris@0
|
1159 *
|
Chris@0
|
1160 * @return true
|
Chris@0
|
1161 * Always returns TRUE.
|
Chris@0
|
1162 */
|
Chris@0
|
1163 public function initQuery() {
|
Chris@0
|
1164 if (!empty($this->query)) {
|
Chris@0
|
1165 $class = get_class($this->query);
|
Chris@0
|
1166 if ($class && $class != 'stdClass') {
|
Chris@0
|
1167 // return if query is already initialized.
|
Chris@0
|
1168 return TRUE;
|
Chris@0
|
1169 }
|
Chris@0
|
1170 }
|
Chris@0
|
1171
|
Chris@0
|
1172 // Create and initialize the query object.
|
Chris@0
|
1173 $views_data = Views::viewsData()->get($this->storage->get('base_table'));
|
Chris@0
|
1174 $this->storage->set('base_field', !empty($views_data['table']['base']['field']) ? $views_data['table']['base']['field'] : '');
|
Chris@0
|
1175 if (!empty($views_data['table']['base']['database'])) {
|
Chris@0
|
1176 $this->base_database = $views_data['table']['base']['database'];
|
Chris@0
|
1177 }
|
Chris@0
|
1178
|
Chris@0
|
1179 $this->query = $this->display_handler->getPlugin('query');
|
Chris@0
|
1180 return TRUE;
|
Chris@0
|
1181 }
|
Chris@0
|
1182
|
Chris@0
|
1183 /**
|
Chris@0
|
1184 * Builds the query for the view.
|
Chris@0
|
1185 *
|
Chris@0
|
1186 * @param string $display_id
|
Chris@0
|
1187 * The display ID of the view.
|
Chris@0
|
1188 *
|
Chris@0
|
1189 * @return bool|null
|
Chris@0
|
1190 * TRUE if the view build process was successful, FALSE if setting the
|
Chris@0
|
1191 * display fails or NULL if the view has been built already.
|
Chris@0
|
1192 */
|
Chris@0
|
1193 public function build($display_id = NULL) {
|
Chris@0
|
1194 if (!empty($this->built)) {
|
Chris@0
|
1195 return;
|
Chris@0
|
1196 }
|
Chris@0
|
1197
|
Chris@0
|
1198 if (empty($this->current_display) || $display_id) {
|
Chris@0
|
1199 if (!$this->setDisplay($display_id)) {
|
Chris@0
|
1200 return FALSE;
|
Chris@0
|
1201 }
|
Chris@0
|
1202 }
|
Chris@0
|
1203
|
Chris@0
|
1204 // Let modules modify the view just prior to building it.
|
Chris@0
|
1205 $module_handler = \Drupal::moduleHandler();
|
Chris@0
|
1206 $module_handler->invokeAll('views_pre_build', [$this]);
|
Chris@0
|
1207
|
Chris@0
|
1208 // Attempt to load from cache.
|
Chris@0
|
1209 // @todo Load a build_info from cache.
|
Chris@0
|
1210
|
Chris@0
|
1211 $start = microtime(TRUE);
|
Chris@0
|
1212 // If that fails, let's build!
|
Chris@0
|
1213 $this->build_info = [
|
Chris@0
|
1214 'query' => '',
|
Chris@0
|
1215 'count_query' => '',
|
Chris@0
|
1216 'query_args' => [],
|
Chris@0
|
1217 ];
|
Chris@0
|
1218
|
Chris@0
|
1219 $this->initQuery();
|
Chris@0
|
1220
|
Chris@0
|
1221 // Call a module hook and see if it wants to present us with a
|
Chris@0
|
1222 // pre-built query or instruct us not to build the query for
|
Chris@0
|
1223 // some reason.
|
Chris@0
|
1224 // @todo: Implement this. Use the same mechanism Panels uses.
|
Chris@0
|
1225
|
Chris@0
|
1226 // Run through our handlers and ensure they have necessary information.
|
Chris@0
|
1227 $this->initHandlers();
|
Chris@0
|
1228
|
Chris@0
|
1229 // Let the handlers interact with each other if they really want.
|
Chris@0
|
1230 $this->_preQuery();
|
Chris@0
|
1231
|
Chris@0
|
1232 if ($this->display_handler->usesExposed()) {
|
Chris@0
|
1233 /** @var \Drupal\views\Plugin\views\exposed_form\ExposedFormPluginInterface $exposed_form */
|
Chris@0
|
1234 $exposed_form = $this->display_handler->getPlugin('exposed_form');
|
Chris@0
|
1235 $this->exposed_widgets = $exposed_form->renderExposedForm();
|
Chris@0
|
1236 if (!empty($this->build_info['abort'])) {
|
Chris@0
|
1237 $this->built = TRUE;
|
Chris@0
|
1238 // Don't execute the query, $form_state, but rendering will still be executed to display the empty text.
|
Chris@0
|
1239 $this->executed = TRUE;
|
Chris@0
|
1240 return empty($this->build_info['fail']);
|
Chris@0
|
1241 }
|
Chris@0
|
1242 }
|
Chris@0
|
1243
|
Chris@0
|
1244 // Build all the relationships first thing.
|
Chris@0
|
1245 $this->_build('relationship');
|
Chris@0
|
1246
|
Chris@0
|
1247 // Set the filtering groups.
|
Chris@0
|
1248 if (!empty($this->filter)) {
|
Chris@0
|
1249 $filter_groups = $this->display_handler->getOption('filter_groups');
|
Chris@0
|
1250 if ($filter_groups) {
|
Chris@0
|
1251 $this->query->setGroupOperator($filter_groups['operator']);
|
Chris@0
|
1252 foreach ($filter_groups['groups'] as $id => $operator) {
|
Chris@0
|
1253 $this->query->setWhereGroup($operator, $id);
|
Chris@0
|
1254 }
|
Chris@0
|
1255 }
|
Chris@0
|
1256 }
|
Chris@0
|
1257
|
Chris@0
|
1258 // Build all the filters.
|
Chris@0
|
1259 $this->_build('filter');
|
Chris@0
|
1260
|
Chris@0
|
1261 $this->build_sort = TRUE;
|
Chris@0
|
1262
|
Chris@0
|
1263 // Arguments can, in fact, cause this whole thing to abort.
|
Chris@0
|
1264 if (!$this->_buildArguments()) {
|
Chris@0
|
1265 $this->build_time = microtime(TRUE) - $start;
|
Chris@0
|
1266 $this->attachDisplays();
|
Chris@0
|
1267 return $this->built;
|
Chris@0
|
1268 }
|
Chris@0
|
1269
|
Chris@0
|
1270 // Initialize the style; arguments may have changed which style we use,
|
Chris@0
|
1271 // so waiting as long as possible is important. But we need to know
|
Chris@0
|
1272 // about the style when we go to build fields.
|
Chris@0
|
1273 if (!$this->initStyle()) {
|
Chris@0
|
1274 $this->build_info['fail'] = TRUE;
|
Chris@0
|
1275 return FALSE;
|
Chris@0
|
1276 }
|
Chris@0
|
1277
|
Chris@0
|
1278 if ($this->style_plugin->usesFields()) {
|
Chris@0
|
1279 $this->_build('field');
|
Chris@0
|
1280 }
|
Chris@0
|
1281
|
Chris@0
|
1282 // Build our sort criteria if we were instructed to do so.
|
Chris@0
|
1283 if (!empty($this->build_sort)) {
|
Chris@0
|
1284 // Allow the style handler to deal with sorting.
|
Chris@0
|
1285 if ($this->style_plugin->buildSort()) {
|
Chris@0
|
1286 $this->_build('sort');
|
Chris@0
|
1287 }
|
Chris@0
|
1288 // allow the plugin to build second sorts as well.
|
Chris@0
|
1289 $this->style_plugin->buildSortPost();
|
Chris@0
|
1290 }
|
Chris@0
|
1291
|
Chris@0
|
1292 // Allow area handlers to affect the query.
|
Chris@0
|
1293 $this->_build('header');
|
Chris@0
|
1294 $this->_build('footer');
|
Chris@0
|
1295 $this->_build('empty');
|
Chris@0
|
1296
|
Chris@0
|
1297 // Allow display handler to affect the query:
|
Chris@0
|
1298 $this->display_handler->query($this->display_handler->useGroupBy());
|
Chris@0
|
1299
|
Chris@0
|
1300 // Allow style handler to affect the query:
|
Chris@0
|
1301 $this->style_plugin->query($this->display_handler->useGroupBy());
|
Chris@0
|
1302
|
Chris@0
|
1303 // Allow exposed form to affect the query:
|
Chris@0
|
1304 if (isset($exposed_form)) {
|
Chris@0
|
1305 $exposed_form->query();
|
Chris@0
|
1306 }
|
Chris@0
|
1307
|
Chris@0
|
1308 if (\Drupal::config('views.settings')->get('sql_signature')) {
|
Chris@0
|
1309 $this->query->addSignature($this);
|
Chris@0
|
1310 }
|
Chris@0
|
1311
|
Chris@0
|
1312 // Let modules modify the query just prior to finalizing it.
|
Chris@0
|
1313 $this->query->alter($this);
|
Chris@0
|
1314
|
Chris@0
|
1315 // Only build the query if we weren't interrupted.
|
Chris@0
|
1316 if (empty($this->built)) {
|
Chris@0
|
1317 // Build the necessary info to execute the query.
|
Chris@0
|
1318 $this->query->build($this);
|
Chris@0
|
1319 }
|
Chris@0
|
1320
|
Chris@0
|
1321 $this->built = TRUE;
|
Chris@0
|
1322 $this->build_time = microtime(TRUE) - $start;
|
Chris@0
|
1323
|
Chris@0
|
1324 // Attach displays
|
Chris@0
|
1325 $this->attachDisplays();
|
Chris@0
|
1326
|
Chris@0
|
1327 // Let modules modify the view just after building it.
|
Chris@0
|
1328 $module_handler->invokeAll('views_post_build', [$this]);
|
Chris@0
|
1329
|
Chris@0
|
1330 return TRUE;
|
Chris@0
|
1331 }
|
Chris@0
|
1332
|
Chris@0
|
1333 /**
|
Chris@0
|
1334 * Builds an individual set of handlers.
|
Chris@0
|
1335 *
|
Chris@0
|
1336 * This is an internal method.
|
Chris@0
|
1337 *
|
Chris@0
|
1338 * @todo Some filter needs this function, even it is internal.
|
Chris@0
|
1339 *
|
Chris@0
|
1340 * @param string $key
|
Chris@0
|
1341 * The type of handlers (filter etc.) which should be iterated over to build
|
Chris@0
|
1342 * the relationship and query information.
|
Chris@0
|
1343 */
|
Chris@0
|
1344 public function _build($key) {
|
Chris@0
|
1345 $handlers = &$this->$key;
|
Chris@0
|
1346 foreach ($handlers as $id => $data) {
|
Chris@0
|
1347
|
Chris@0
|
1348 if (!empty($handlers[$id]) && is_object($handlers[$id])) {
|
Chris@0
|
1349 $multiple_exposed_input = [0 => NULL];
|
Chris@0
|
1350 if ($handlers[$id]->multipleExposedInput()) {
|
Chris@0
|
1351 $multiple_exposed_input = $handlers[$id]->groupMultipleExposedInput($this->exposed_data);
|
Chris@0
|
1352 }
|
Chris@0
|
1353 foreach ($multiple_exposed_input as $group_id) {
|
Chris@0
|
1354 // Give this handler access to the exposed filter input.
|
Chris@0
|
1355 if (!empty($this->exposed_data)) {
|
Chris@0
|
1356 if ($handlers[$id]->isAGroup()) {
|
Chris@0
|
1357 $converted = $handlers[$id]->convertExposedInput($this->exposed_data, $group_id);
|
Chris@0
|
1358 $handlers[$id]->storeGroupInput($this->exposed_data, $converted);
|
Chris@0
|
1359 if (!$converted) {
|
Chris@0
|
1360 continue;
|
Chris@0
|
1361 }
|
Chris@0
|
1362 }
|
Chris@0
|
1363 $rc = $handlers[$id]->acceptExposedInput($this->exposed_data);
|
Chris@0
|
1364 $handlers[$id]->storeExposedInput($this->exposed_data, $rc);
|
Chris@0
|
1365 if (!$rc) {
|
Chris@0
|
1366 continue;
|
Chris@0
|
1367 }
|
Chris@0
|
1368 }
|
Chris@0
|
1369 $handlers[$id]->setRelationship();
|
Chris@0
|
1370 $handlers[$id]->query($this->display_handler->useGroupBy());
|
Chris@0
|
1371 }
|
Chris@0
|
1372 }
|
Chris@0
|
1373 }
|
Chris@0
|
1374 }
|
Chris@0
|
1375
|
Chris@0
|
1376 /**
|
Chris@0
|
1377 * Executes the view's query.
|
Chris@0
|
1378 *
|
Chris@0
|
1379 * @param string $display_id
|
Chris@0
|
1380 * The machine name of the display, which should be executed.
|
Chris@0
|
1381 *
|
Chris@0
|
1382 * @return bool
|
Chris@0
|
1383 * TRUE if the view execution was successful, FALSE otherwise. For example,
|
Chris@0
|
1384 * an argument could stop the process.
|
Chris@0
|
1385 */
|
Chris@0
|
1386 public function execute($display_id = NULL) {
|
Chris@0
|
1387 if (empty($this->built)) {
|
Chris@0
|
1388 if (!$this->build($display_id)) {
|
Chris@0
|
1389 return FALSE;
|
Chris@0
|
1390 }
|
Chris@0
|
1391 }
|
Chris@0
|
1392
|
Chris@0
|
1393 if (!empty($this->executed)) {
|
Chris@0
|
1394 return TRUE;
|
Chris@0
|
1395 }
|
Chris@0
|
1396
|
Chris@0
|
1397 // Don't allow to use deactivated displays, but display them on the live preview.
|
Chris@0
|
1398 if (!$this->display_handler->isEnabled() && empty($this->live_preview)) {
|
Chris@0
|
1399 $this->build_info['fail'] = TRUE;
|
Chris@0
|
1400 return FALSE;
|
Chris@0
|
1401 }
|
Chris@0
|
1402
|
Chris@0
|
1403 // Let modules modify the view just prior to executing it.
|
Chris@0
|
1404 $module_handler = \Drupal::moduleHandler();
|
Chris@0
|
1405 $module_handler->invokeAll('views_pre_execute', [$this]);
|
Chris@0
|
1406
|
Chris@0
|
1407 // Check for already-cached results.
|
Chris@0
|
1408 /** @var \Drupal\views\Plugin\views\cache\CachePluginBase $cache */
|
Chris@0
|
1409 if (!empty($this->live_preview)) {
|
Chris@0
|
1410 $cache = Views::pluginManager('cache')->createInstance('none');
|
Chris@0
|
1411 }
|
Chris@0
|
1412 else {
|
Chris@0
|
1413 $cache = $this->display_handler->getPlugin('cache');
|
Chris@0
|
1414 }
|
Chris@0
|
1415
|
Chris@0
|
1416 if ($cache->cacheGet('results')) {
|
Chris@0
|
1417 if ($this->pager->usePager()) {
|
Chris@0
|
1418 $this->pager->total_items = $this->total_rows;
|
Chris@0
|
1419 $this->pager->updatePageInfo();
|
Chris@0
|
1420 }
|
Chris@0
|
1421 }
|
Chris@0
|
1422 else {
|
Chris@0
|
1423 $this->query->execute($this);
|
Chris@0
|
1424 // Enforce the array key rule as documented in
|
Chris@0
|
1425 // views_plugin_query::execute().
|
Chris@0
|
1426 $this->result = array_values($this->result);
|
Chris@0
|
1427 $this->_postExecute();
|
Chris@0
|
1428 $cache->cacheSet('results');
|
Chris@0
|
1429 }
|
Chris@0
|
1430
|
Chris@0
|
1431 // Let modules modify the view just after executing it.
|
Chris@0
|
1432 $module_handler->invokeAll('views_post_execute', [$this]);
|
Chris@0
|
1433
|
Chris@0
|
1434 return $this->executed = TRUE;
|
Chris@0
|
1435 }
|
Chris@0
|
1436
|
Chris@0
|
1437 /**
|
Chris@0
|
1438 * Renders this view for a certain display.
|
Chris@0
|
1439 *
|
Chris@0
|
1440 * Note: You should better use just the preview function if you want to
|
Chris@0
|
1441 * render a view.
|
Chris@0
|
1442 *
|
Chris@0
|
1443 * @param string $display_id
|
Chris@0
|
1444 * The machine name of the display, which should be rendered.
|
Chris@0
|
1445 *
|
Chris@0
|
1446 * @return array|null
|
Chris@0
|
1447 * A renderable array containing the view output or NULL if the build
|
Chris@0
|
1448 * process failed.
|
Chris@0
|
1449 */
|
Chris@0
|
1450 public function render($display_id = NULL) {
|
Chris@0
|
1451 $this->execute($display_id);
|
Chris@0
|
1452
|
Chris@0
|
1453 // Check to see if the build failed.
|
Chris@0
|
1454 if (!empty($this->build_info['fail'])) {
|
Chris@0
|
1455 return;
|
Chris@0
|
1456 }
|
Chris@0
|
1457 if (!empty($this->build_info['denied'])) {
|
Chris@0
|
1458 return;
|
Chris@0
|
1459 }
|
Chris@0
|
1460
|
Chris@0
|
1461 /** @var \Drupal\views\Plugin\views\exposed_form\ExposedFormPluginInterface $exposed_form */
|
Chris@0
|
1462 $exposed_form = $this->display_handler->getPlugin('exposed_form');
|
Chris@0
|
1463 $exposed_form->preRender($this->result);
|
Chris@0
|
1464
|
Chris@0
|
1465 $module_handler = \Drupal::moduleHandler();
|
Chris@0
|
1466
|
Chris@0
|
1467 // @TODO In the longrun, it would be great to execute a view without
|
Chris@0
|
1468 // the theme system at all. See https://www.drupal.org/node/2322623.
|
Chris@0
|
1469 $active_theme = \Drupal::theme()->getActiveTheme();
|
Chris@0
|
1470 $themes = array_keys($active_theme->getBaseThemes());
|
Chris@0
|
1471 $themes[] = $active_theme->getName();
|
Chris@0
|
1472
|
Chris@0
|
1473 // Check for already-cached output.
|
Chris@0
|
1474 /** @var \Drupal\views\Plugin\views\cache\CachePluginBase $cache */
|
Chris@0
|
1475 if (!empty($this->live_preview)) {
|
Chris@0
|
1476 $cache = Views::pluginManager('cache')->createInstance('none');
|
Chris@0
|
1477 }
|
Chris@0
|
1478 else {
|
Chris@0
|
1479 $cache = $this->display_handler->getPlugin('cache');
|
Chris@0
|
1480 }
|
Chris@0
|
1481
|
Chris@0
|
1482 // Run preRender for the pager as it might change the result.
|
Chris@0
|
1483 if (!empty($this->pager)) {
|
Chris@0
|
1484 $this->pager->preRender($this->result);
|
Chris@0
|
1485 }
|
Chris@0
|
1486
|
Chris@0
|
1487 // Initialize the style plugin.
|
Chris@0
|
1488 $this->initStyle();
|
Chris@0
|
1489
|
Chris@0
|
1490 if (!isset($this->response)) {
|
Chris@0
|
1491 // Set the response so other parts can alter it.
|
Chris@0
|
1492 $this->response = new Response('', 200);
|
Chris@0
|
1493 }
|
Chris@0
|
1494
|
Chris@0
|
1495 // Give field handlers the opportunity to perform additional queries
|
Chris@0
|
1496 // using the entire resultset prior to rendering.
|
Chris@0
|
1497 if ($this->style_plugin->usesFields()) {
|
Chris@0
|
1498 foreach ($this->field as $id => $handler) {
|
Chris@0
|
1499 if (!empty($this->field[$id])) {
|
Chris@0
|
1500 $this->field[$id]->preRender($this->result);
|
Chris@0
|
1501 }
|
Chris@0
|
1502 }
|
Chris@0
|
1503 }
|
Chris@0
|
1504
|
Chris@0
|
1505 $this->style_plugin->preRender($this->result);
|
Chris@0
|
1506
|
Chris@0
|
1507 // Let each area handler have access to the result set.
|
Chris@0
|
1508 $areas = ['header', 'footer'];
|
Chris@0
|
1509 // Only call preRender() on the empty handlers if the result is empty.
|
Chris@0
|
1510 if (empty($this->result)) {
|
Chris@0
|
1511 $areas[] = 'empty';
|
Chris@0
|
1512 }
|
Chris@0
|
1513 foreach ($areas as $area) {
|
Chris@0
|
1514 foreach ($this->{$area} as $handler) {
|
Chris@0
|
1515 $handler->preRender($this->result);
|
Chris@0
|
1516 }
|
Chris@0
|
1517 }
|
Chris@0
|
1518
|
Chris@0
|
1519 // Let modules modify the view just prior to rendering it.
|
Chris@0
|
1520 $module_handler->invokeAll('views_pre_render', [$this]);
|
Chris@0
|
1521
|
Chris@0
|
1522 // Let the themes play too, because pre render is a very themey thing.
|
Chris@0
|
1523 foreach ($themes as $theme_name) {
|
Chris@0
|
1524 $function = $theme_name . '_views_pre_render';
|
Chris@0
|
1525 if (function_exists($function)) {
|
Chris@0
|
1526 $function($this);
|
Chris@0
|
1527 }
|
Chris@0
|
1528 }
|
Chris@0
|
1529
|
Chris@0
|
1530 $this->display_handler->output = $this->display_handler->render();
|
Chris@0
|
1531
|
Chris@0
|
1532 $exposed_form->postRender($this->display_handler->output);
|
Chris@0
|
1533
|
Chris@0
|
1534 $cache->postRender($this->display_handler->output);
|
Chris@0
|
1535
|
Chris@0
|
1536 // Let modules modify the view output after it is rendered.
|
Chris@0
|
1537 $module_handler->invokeAll('views_post_render', [$this, &$this->display_handler->output, $cache]);
|
Chris@0
|
1538
|
Chris@0
|
1539 // Let the themes play too, because post render is a very themey thing.
|
Chris@0
|
1540 foreach ($themes as $theme_name) {
|
Chris@0
|
1541 $function = $theme_name . '_views_post_render';
|
Chris@0
|
1542 if (function_exists($function)) {
|
Chris@0
|
1543 $function($this, $this->display_handler->output, $cache);
|
Chris@0
|
1544 }
|
Chris@0
|
1545 }
|
Chris@0
|
1546
|
Chris@0
|
1547 return $this->display_handler->output;
|
Chris@0
|
1548 }
|
Chris@0
|
1549
|
Chris@0
|
1550 /**
|
Chris@0
|
1551 * Gets the cache tags associated with the executed view.
|
Chris@0
|
1552 *
|
Chris@0
|
1553 * Note: The cache plugin controls the used tags, so you can override it, if
|
Chris@0
|
1554 * needed.
|
Chris@0
|
1555 *
|
Chris@0
|
1556 * @return string[]
|
Chris@0
|
1557 * An array of cache tags.
|
Chris@0
|
1558 */
|
Chris@0
|
1559 public function getCacheTags() {
|
Chris@0
|
1560 $this->initDisplay();
|
Chris@0
|
1561 /** @var \Drupal\views\Plugin\views\cache\CachePluginBase $cache */
|
Chris@0
|
1562 $cache = $this->display_handler->getPlugin('cache');
|
Chris@0
|
1563 return $cache->getCacheTags();
|
Chris@0
|
1564 }
|
Chris@0
|
1565
|
Chris@0
|
1566 /**
|
Chris@0
|
1567 * Builds the render array outline for the given display.
|
Chris@0
|
1568 *
|
Chris@0
|
1569 * This render array has a #pre_render callback which will call
|
Chris@0
|
1570 * ::executeDisplay in order to actually execute the view and then build the
|
Chris@0
|
1571 * final render array structure.
|
Chris@0
|
1572 *
|
Chris@0
|
1573 * @param string $display_id
|
Chris@0
|
1574 * The display ID.
|
Chris@0
|
1575 * @param array $args
|
Chris@0
|
1576 * An array of arguments passed along to the view.
|
Chris@0
|
1577 * @param bool $cache
|
Chris@0
|
1578 * (optional) Should the result be render cached.
|
Chris@0
|
1579 *
|
Chris@0
|
1580 * @return array|null
|
Chris@0
|
1581 * A renderable array with #type 'view' or NULL if the display ID was
|
Chris@0
|
1582 * invalid.
|
Chris@0
|
1583 */
|
Chris@0
|
1584 public function buildRenderable($display_id = NULL, $args = [], $cache = TRUE) {
|
Chris@0
|
1585 // @todo Extract that into a generic method.
|
Chris@0
|
1586 if (empty($this->current_display) || $this->current_display != $this->chooseDisplay($display_id)) {
|
Chris@0
|
1587 if (!$this->setDisplay($display_id)) {
|
Chris@0
|
1588 return NULL;
|
Chris@0
|
1589 }
|
Chris@0
|
1590 }
|
Chris@0
|
1591
|
Chris@0
|
1592 return $this->display_handler->buildRenderable($args, $cache);
|
Chris@0
|
1593 }
|
Chris@0
|
1594
|
Chris@0
|
1595 /**
|
Chris@0
|
1596 * Executes the given display, with the given arguments.
|
Chris@0
|
1597 *
|
Chris@0
|
1598 * To be called externally by whatever mechanism invokes the view,
|
Chris@0
|
1599 * such as a page callback, hook_block, etc.
|
Chris@0
|
1600 *
|
Chris@0
|
1601 * This function should NOT be used by anything external as this
|
Chris@0
|
1602 * returns data in the format specified by the display. It can also
|
Chris@0
|
1603 * have other side effects that are only intended for the 'proper'
|
Chris@0
|
1604 * use of the display, such as setting page titles.
|
Chris@0
|
1605 *
|
Chris@0
|
1606 * If you simply want to view the display, use View::preview() instead.
|
Chris@0
|
1607 *
|
Chris@0
|
1608 * @param string $display_id
|
Chris@0
|
1609 * The display ID of the view to be executed.
|
Chris@0
|
1610 * @param string[] $args
|
Chris@0
|
1611 * The arguments to be passed to the view.
|
Chris@0
|
1612 *
|
Chris@0
|
1613 * @return array|null
|
Chris@0
|
1614 * A renderable array containing the view output or NULL if the display ID
|
Chris@0
|
1615 * of the view to be executed doesn't exist.
|
Chris@0
|
1616 */
|
Chris@0
|
1617 public function executeDisplay($display_id = NULL, $args = []) {
|
Chris@0
|
1618 if (empty($this->current_display) || $this->current_display != $this->chooseDisplay($display_id)) {
|
Chris@0
|
1619 if (!$this->setDisplay($display_id)) {
|
Chris@0
|
1620 return NULL;
|
Chris@0
|
1621 }
|
Chris@0
|
1622 }
|
Chris@0
|
1623
|
Chris@0
|
1624 $this->preExecute($args);
|
Chris@0
|
1625
|
Chris@0
|
1626 // Execute the view
|
Chris@0
|
1627 $output = $this->display_handler->execute();
|
Chris@0
|
1628
|
Chris@0
|
1629 $this->postExecute();
|
Chris@0
|
1630 return $output;
|
Chris@0
|
1631 }
|
Chris@0
|
1632
|
Chris@0
|
1633 /**
|
Chris@0
|
1634 * Previews the given display, with the given arguments.
|
Chris@0
|
1635 *
|
Chris@0
|
1636 * To be called externally, probably by an AJAX handler of some flavor.
|
Chris@0
|
1637 * Can also be called when views are embedded, as this guarantees
|
Chris@0
|
1638 * normalized output.
|
Chris@0
|
1639 *
|
Chris@0
|
1640 * This function does not do any access checks on the view. It is the
|
Chris@0
|
1641 * responsibility of the caller to check $view->access() or implement other
|
Chris@0
|
1642 * access logic. To render the view normally with access checks, use
|
Chris@0
|
1643 * views_embed_view() instead.
|
Chris@0
|
1644 *
|
Chris@0
|
1645 * @return array|null
|
Chris@0
|
1646 * A renderable array containing the view output or NULL if the display ID
|
Chris@0
|
1647 * of the view to be executed doesn't exist.
|
Chris@0
|
1648 */
|
Chris@0
|
1649 public function preview($display_id = NULL, $args = []) {
|
Chris@0
|
1650 if (empty($this->current_display) || ((!empty($display_id)) && $this->current_display != $display_id)) {
|
Chris@0
|
1651 if (!$this->setDisplay($display_id)) {
|
Chris@0
|
1652 return FALSE;
|
Chris@0
|
1653 }
|
Chris@0
|
1654 }
|
Chris@0
|
1655
|
Chris@0
|
1656 $this->preview = TRUE;
|
Chris@0
|
1657 $this->preExecute($args);
|
Chris@0
|
1658 // Preview the view.
|
Chris@0
|
1659 $output = $this->display_handler->preview();
|
Chris@0
|
1660
|
Chris@0
|
1661 $this->postExecute();
|
Chris@0
|
1662 return $output;
|
Chris@0
|
1663 }
|
Chris@0
|
1664
|
Chris@0
|
1665 /**
|
Chris@0
|
1666 * Runs attachments and lets the display do what it needs to before running.
|
Chris@0
|
1667 *
|
Chris@0
|
1668 * @param array $args
|
Chris@0
|
1669 * An array of arguments from the URL that can be used by the view.
|
Chris@0
|
1670 */
|
Chris@0
|
1671 public function preExecute($args = []) {
|
Chris@0
|
1672 $this->old_view[] = views_get_current_view();
|
Chris@0
|
1673 views_set_current_view($this);
|
Chris@0
|
1674 $display_id = $this->current_display;
|
Chris@0
|
1675
|
Chris@0
|
1676 // Prepare the view with the information we have, but only if we were
|
Chris@0
|
1677 // passed arguments, as they may have been set previously.
|
Chris@0
|
1678 if ($args) {
|
Chris@0
|
1679 $this->setArguments($args);
|
Chris@0
|
1680 }
|
Chris@0
|
1681
|
Chris@0
|
1682 // Let modules modify the view just prior to executing it.
|
Chris@0
|
1683 \Drupal::moduleHandler()->invokeAll('views_pre_view', [$this, $display_id, &$this->args]);
|
Chris@0
|
1684
|
Chris@0
|
1685 // Allow hook_views_pre_view() to set the dom_id, then ensure it is set.
|
Chris@0
|
1686 $this->dom_id = !empty($this->dom_id) ? $this->dom_id : hash('sha256', $this->storage->id() . REQUEST_TIME . mt_rand());
|
Chris@0
|
1687
|
Chris@0
|
1688 // Allow the display handler to set up for execution
|
Chris@0
|
1689 $this->display_handler->preExecute();
|
Chris@0
|
1690 }
|
Chris@0
|
1691
|
Chris@0
|
1692 /**
|
Chris@0
|
1693 * Unsets the current view, mostly.
|
Chris@0
|
1694 */
|
Chris@0
|
1695 public function postExecute() {
|
Chris@0
|
1696 // unset current view so we can be properly destructed later on.
|
Chris@0
|
1697 // Return the previous value in case we're an attachment.
|
Chris@0
|
1698
|
Chris@0
|
1699 if ($this->old_view) {
|
Chris@0
|
1700 $old_view = array_pop($this->old_view);
|
Chris@0
|
1701 }
|
Chris@0
|
1702
|
Chris@0
|
1703 views_set_current_view(isset($old_view) ? $old_view : FALSE);
|
Chris@0
|
1704 }
|
Chris@0
|
1705
|
Chris@0
|
1706 /**
|
Chris@0
|
1707 * Runs attachment displays for the view.
|
Chris@0
|
1708 */
|
Chris@0
|
1709 public function attachDisplays() {
|
Chris@0
|
1710 if (!empty($this->is_attachment)) {
|
Chris@0
|
1711 return;
|
Chris@0
|
1712 }
|
Chris@0
|
1713
|
Chris@0
|
1714 if (!$this->display_handler->acceptAttachments()) {
|
Chris@0
|
1715 return;
|
Chris@0
|
1716 }
|
Chris@0
|
1717
|
Chris@0
|
1718 $this->is_attachment = TRUE;
|
Chris@0
|
1719 // Find out which other displays attach to the current one.
|
Chris@0
|
1720 foreach ($this->display_handler->getAttachedDisplays() as $id) {
|
Chris@0
|
1721 $display_handler = $this->displayHandlers->get($id);
|
Chris@0
|
1722 // Only attach enabled attachments.
|
Chris@0
|
1723 if ($display_handler->isEnabled()) {
|
Chris@0
|
1724 $cloned_view = Views::executableFactory()->get($this->storage);
|
Chris@0
|
1725 $display_handler->attachTo($cloned_view, $this->current_display, $this->element);
|
Chris@0
|
1726 }
|
Chris@0
|
1727 }
|
Chris@0
|
1728 $this->is_attachment = FALSE;
|
Chris@0
|
1729 }
|
Chris@0
|
1730
|
Chris@0
|
1731 /**
|
Chris@0
|
1732 * Determines if the given user has access to the view.
|
Chris@0
|
1733 *
|
Chris@0
|
1734 * Note that this sets the display handler if it hasn't been set.
|
Chris@0
|
1735 *
|
Chris@0
|
1736 * @param string $displays
|
Chris@0
|
1737 * The machine name of the display.
|
Chris@0
|
1738 * @param \Drupal\Core\Session\AccountInterface $account
|
Chris@0
|
1739 * The user object.
|
Chris@0
|
1740 *
|
Chris@0
|
1741 * @return bool
|
Chris@0
|
1742 * TRUE if the user has access to the view, FALSE otherwise.
|
Chris@0
|
1743 */
|
Chris@0
|
1744 public function access($displays = NULL, $account = NULL) {
|
Chris@0
|
1745 // No one should have access to disabled views.
|
Chris@0
|
1746 if (!$this->storage->status()) {
|
Chris@0
|
1747 return FALSE;
|
Chris@0
|
1748 }
|
Chris@0
|
1749
|
Chris@0
|
1750 if (!isset($this->current_display)) {
|
Chris@0
|
1751 $this->initDisplay();
|
Chris@0
|
1752 }
|
Chris@0
|
1753
|
Chris@0
|
1754 if (!$account) {
|
Chris@0
|
1755 $account = $this->user;
|
Chris@0
|
1756 }
|
Chris@0
|
1757
|
Chris@0
|
1758 // We can't use choose_display() here because that function
|
Chris@0
|
1759 // calls this one.
|
Chris@0
|
1760 $displays = (array) $displays;
|
Chris@0
|
1761 foreach ($displays as $display_id) {
|
Chris@0
|
1762 if ($this->displayHandlers->has($display_id)) {
|
Chris@0
|
1763 if (($display = $this->displayHandlers->get($display_id)) && $display->access($account)) {
|
Chris@0
|
1764 return TRUE;
|
Chris@0
|
1765 }
|
Chris@0
|
1766 }
|
Chris@0
|
1767 }
|
Chris@0
|
1768
|
Chris@0
|
1769 return FALSE;
|
Chris@0
|
1770 }
|
Chris@0
|
1771
|
Chris@0
|
1772 /**
|
Chris@0
|
1773 * Sets the used response object of the view.
|
Chris@0
|
1774 *
|
Chris@0
|
1775 * @param \Symfony\Component\HttpFoundation\Response $response
|
Chris@0
|
1776 * The response object which should be set.
|
Chris@0
|
1777 */
|
Chris@0
|
1778 public function setResponse(Response $response) {
|
Chris@0
|
1779 $this->response = $response;
|
Chris@0
|
1780 }
|
Chris@0
|
1781
|
Chris@0
|
1782 /**
|
Chris@0
|
1783 * Gets the response object used by the view.
|
Chris@0
|
1784 *
|
Chris@0
|
1785 * @return \Symfony\Component\HttpFoundation\Response
|
Chris@0
|
1786 * The response object of the view.
|
Chris@0
|
1787 */
|
Chris@0
|
1788 public function getResponse() {
|
Chris@0
|
1789 if (!isset($this->response)) {
|
Chris@0
|
1790 $this->response = new Response();
|
Chris@0
|
1791 }
|
Chris@0
|
1792 return $this->response;
|
Chris@0
|
1793 }
|
Chris@0
|
1794
|
Chris@0
|
1795 /**
|
Chris@0
|
1796 * Sets the request object.
|
Chris@0
|
1797 *
|
Chris@0
|
1798 * @param \Symfony\Component\HttpFoundation\Request $request
|
Chris@0
|
1799 * The request object.
|
Chris@0
|
1800 */
|
Chris@0
|
1801 public function setRequest(Request $request) {
|
Chris@0
|
1802 $this->request = $request;
|
Chris@0
|
1803 }
|
Chris@0
|
1804
|
Chris@0
|
1805 /**
|
Chris@0
|
1806 * Gets the request object.
|
Chris@0
|
1807 *
|
Chris@0
|
1808 * @return \Symfony\Component\HttpFoundation\Request
|
Chris@0
|
1809 * The request object.
|
Chris@0
|
1810 */
|
Chris@0
|
1811 public function getRequest() {
|
Chris@0
|
1812 return $this->request;
|
Chris@0
|
1813 }
|
Chris@0
|
1814
|
Chris@0
|
1815 /**
|
Chris@0
|
1816 * Gets the view's current title.
|
Chris@0
|
1817 *
|
Chris@0
|
1818 * This can change depending upon how it was built.
|
Chris@0
|
1819 *
|
Chris@0
|
1820 * @return string|false
|
Chris@0
|
1821 * The view title, FALSE if the display is not set.
|
Chris@0
|
1822 */
|
Chris@0
|
1823 public function getTitle() {
|
Chris@0
|
1824 if (empty($this->display_handler)) {
|
Chris@0
|
1825 if (!$this->setDisplay('default')) {
|
Chris@0
|
1826 return FALSE;
|
Chris@0
|
1827 }
|
Chris@0
|
1828 }
|
Chris@0
|
1829
|
Chris@0
|
1830 // During building, we might find a title override. If so, use it.
|
Chris@0
|
1831 if (!empty($this->build_info['title'])) {
|
Chris@0
|
1832 $title = $this->build_info['title'];
|
Chris@0
|
1833 }
|
Chris@0
|
1834 else {
|
Chris@0
|
1835 $title = $this->display_handler->getOption('title');
|
Chris@0
|
1836 }
|
Chris@0
|
1837
|
Chris@0
|
1838 // Allow substitutions from the first row.
|
Chris@0
|
1839 if ($this->initStyle()) {
|
Chris@0
|
1840 $title = $this->style_plugin->tokenizeValue($title, 0);
|
Chris@0
|
1841 }
|
Chris@0
|
1842 return $title;
|
Chris@0
|
1843 }
|
Chris@0
|
1844
|
Chris@0
|
1845 /**
|
Chris@0
|
1846 * Overrides the view's current title.
|
Chris@0
|
1847 *
|
Chris@0
|
1848 * The tokens in the title get's replaced before rendering.
|
Chris@0
|
1849 *
|
Chris@0
|
1850 * @return true
|
Chris@0
|
1851 * Always returns TRUE.
|
Chris@0
|
1852 */
|
Chris@0
|
1853 public function setTitle($title) {
|
Chris@0
|
1854 $this->build_info['title'] = $title;
|
Chris@0
|
1855 return TRUE;
|
Chris@0
|
1856 }
|
Chris@0
|
1857
|
Chris@0
|
1858 /**
|
Chris@0
|
1859 * Forces the view to build a title.
|
Chris@0
|
1860 */
|
Chris@0
|
1861 public function buildTitle() {
|
Chris@0
|
1862 $this->initDisplay();
|
Chris@0
|
1863
|
Chris@0
|
1864 if (empty($this->built)) {
|
Chris@0
|
1865 $this->initQuery();
|
Chris@0
|
1866 }
|
Chris@0
|
1867
|
Chris@0
|
1868 $this->initHandlers();
|
Chris@0
|
1869
|
Chris@0
|
1870 $this->_buildArguments();
|
Chris@0
|
1871 }
|
Chris@0
|
1872
|
Chris@0
|
1873 /**
|
Chris@0
|
1874 * Determines whether you can link to the view or a particular display.
|
Chris@0
|
1875 *
|
Chris@0
|
1876 * Some displays (e.g. block displays) do not have their own route, but may
|
Chris@0
|
1877 * optionally provide a link to another display that does have a route.
|
Chris@0
|
1878 *
|
Chris@0
|
1879 * @param array $args
|
Chris@0
|
1880 * (optional) The arguments.
|
Chris@0
|
1881 * @param string $display_id
|
Chris@0
|
1882 * (optional) The display ID. The current display will be used by default.
|
Chris@0
|
1883 *
|
Chris@0
|
1884 * @return bool
|
Chris@0
|
1885 * TRUE if the current display has a valid route available, FALSE otherwise.
|
Chris@0
|
1886 */
|
Chris@0
|
1887 public function hasUrl($args = NULL, $display_id = NULL) {
|
Chris@0
|
1888 if (!empty($this->override_url)) {
|
Chris@0
|
1889 return TRUE;
|
Chris@0
|
1890 }
|
Chris@0
|
1891
|
Chris@0
|
1892 // If the display has a valid route available (either its own or for a
|
Chris@0
|
1893 // linked display), then we can provide a URL for it.
|
Chris@0
|
1894 $display_handler = $this->displayHandlers->get($display_id ?: $this->current_display)->getRoutedDisplay();
|
Chris@0
|
1895 if (!$display_handler instanceof DisplayRouterInterface) {
|
Chris@0
|
1896 return FALSE;
|
Chris@0
|
1897 }
|
Chris@0
|
1898
|
Chris@0
|
1899 // Look up the route name to make sure it exists. The name may exist, but
|
Chris@0
|
1900 // not be available yet in some instances when editing a view and doing
|
Chris@0
|
1901 // a live preview.
|
Chris@0
|
1902 $provider = \Drupal::service('router.route_provider');
|
Chris@0
|
1903 try {
|
Chris@0
|
1904 $provider->getRouteByName($display_handler->getRouteName());
|
Chris@0
|
1905 }
|
Chris@0
|
1906 catch (RouteNotFoundException $e) {
|
Chris@0
|
1907 return FALSE;
|
Chris@0
|
1908 }
|
Chris@0
|
1909
|
Chris@0
|
1910 return TRUE;
|
Chris@0
|
1911 }
|
Chris@0
|
1912
|
Chris@0
|
1913 /**
|
Chris@0
|
1914 * Gets the URL for the current view.
|
Chris@0
|
1915 *
|
Chris@0
|
1916 * This URL will be adjusted for arguments.
|
Chris@0
|
1917 *
|
Chris@0
|
1918 * @param array $args
|
Chris@0
|
1919 * (optional) Passed in arguments.
|
Chris@0
|
1920 * @param string $display_id
|
Chris@0
|
1921 * (optional) Specify the display ID to link to, fallback to the current ID.
|
Chris@0
|
1922 *
|
Chris@0
|
1923 * @return \Drupal\Core\Url
|
Chris@0
|
1924 * The URL of the current view.
|
Chris@0
|
1925 *
|
Chris@0
|
1926 * @throws \InvalidArgumentException
|
Chris@0
|
1927 * Thrown when the current view doesn't have a route available.
|
Chris@0
|
1928 */
|
Chris@0
|
1929 public function getUrl($args = NULL, $display_id = NULL) {
|
Chris@0
|
1930 if (!empty($this->override_url)) {
|
Chris@0
|
1931 return $this->override_url;
|
Chris@0
|
1932 }
|
Chris@0
|
1933
|
Chris@0
|
1934 $display_handler = $this->displayHandlers->get($display_id ?: $this->current_display)->getRoutedDisplay();
|
Chris@0
|
1935 if (!$display_handler instanceof DisplayRouterInterface) {
|
Chris@0
|
1936 throw new \InvalidArgumentException('You cannot create a URL to a display without routes.');
|
Chris@0
|
1937 }
|
Chris@0
|
1938
|
Chris@0
|
1939 if (!isset($args)) {
|
Chris@0
|
1940 $args = $this->args;
|
Chris@0
|
1941
|
Chris@0
|
1942 // Exclude arguments that were computed, not passed on the URL.
|
Chris@0
|
1943 $position = 0;
|
Chris@0
|
1944 if (!empty($this->argument)) {
|
Chris@0
|
1945 foreach ($this->argument as $argument) {
|
Chris@0
|
1946 if (!empty($argument->is_default) && !empty($argument->options['default_argument_skip_url'])) {
|
Chris@0
|
1947 unset($args[$position]);
|
Chris@0
|
1948 }
|
Chris@0
|
1949 $position++;
|
Chris@0
|
1950 }
|
Chris@0
|
1951 }
|
Chris@0
|
1952 }
|
Chris@0
|
1953
|
Chris@0
|
1954 $path = $this->getPath();
|
Chris@0
|
1955
|
Chris@0
|
1956 // Don't bother working if there's nothing to do:
|
Chris@0
|
1957 if (empty($path) || (empty($args) && strpos($path, '%') === FALSE)) {
|
Chris@0
|
1958 return $display_handler->getUrlInfo();
|
Chris@0
|
1959 }
|
Chris@0
|
1960
|
Chris@0
|
1961 $argument_keys = isset($this->argument) ? array_keys($this->argument) : [];
|
Chris@0
|
1962 $id = current($argument_keys);
|
Chris@0
|
1963
|
Chris@0
|
1964 /** @var \Drupal\Core\Url $url */
|
Chris@0
|
1965 $url = $display_handler->getUrlInfo();
|
Chris@0
|
1966 $route = $this->routeProvider->getRouteByName($url->getRouteName());
|
Chris@0
|
1967
|
Chris@0
|
1968 $variables = $route->compile()->getVariables();
|
Chris@0
|
1969 $parameters = $url->getRouteParameters();
|
Chris@0
|
1970
|
Chris@0
|
1971 foreach ($variables as $variable_name) {
|
Chris@0
|
1972 if (empty($args)) {
|
Chris@0
|
1973 // Try to never put % in a URL; use the wildcard instead.
|
Chris@0
|
1974 if ($id && !empty($this->argument[$id]->options['exception']['value'])) {
|
Chris@0
|
1975 $parameters[$variable_name] = $this->argument[$id]->options['exception']['value'];
|
Chris@0
|
1976 }
|
Chris@0
|
1977 else {
|
Chris@0
|
1978 // Provide some fallback in case no exception value could be found.
|
Chris@0
|
1979 $parameters[$variable_name] = '*';
|
Chris@0
|
1980 }
|
Chris@0
|
1981 }
|
Chris@0
|
1982 else {
|
Chris@0
|
1983 $parameters[$variable_name] = array_shift($args);
|
Chris@0
|
1984 }
|
Chris@0
|
1985
|
Chris@0
|
1986 if ($id) {
|
Chris@0
|
1987 $id = next($argument_keys);
|
Chris@0
|
1988 }
|
Chris@0
|
1989 }
|
Chris@0
|
1990
|
Chris@0
|
1991 $url->setRouteParameters($parameters);
|
Chris@0
|
1992 return $url;
|
Chris@0
|
1993 }
|
Chris@0
|
1994
|
Chris@0
|
1995 /**
|
Chris@0
|
1996 * Gets the Url object associated with the display handler.
|
Chris@0
|
1997 *
|
Chris@0
|
1998 * @param string $display_id
|
Chris@0
|
1999 * (optional) The display ID (used only to detail an exception).
|
Chris@0
|
2000 *
|
Chris@0
|
2001 * @return \Drupal\Core\Url
|
Chris@0
|
2002 * The display handlers URL object.
|
Chris@0
|
2003 *
|
Chris@0
|
2004 * @throws \InvalidArgumentException
|
Chris@0
|
2005 * Thrown when the display plugin does not have a URL to return.
|
Chris@0
|
2006 */
|
Chris@0
|
2007 public function getUrlInfo($display_id = '') {
|
Chris@0
|
2008 $this->initDisplay();
|
Chris@0
|
2009 if (!$this->display_handler instanceof DisplayRouterInterface) {
|
Chris@0
|
2010 throw new \InvalidArgumentException("You cannot generate a URL for the display '$display_id'");
|
Chris@0
|
2011 }
|
Chris@0
|
2012 return $this->display_handler->getUrlInfo();
|
Chris@0
|
2013 }
|
Chris@0
|
2014
|
Chris@0
|
2015 /**
|
Chris@0
|
2016 * Gets the base path used for this view.
|
Chris@0
|
2017 *
|
Chris@0
|
2018 * @return string|false
|
Chris@0
|
2019 * The base path used for the view or FALSE if setting the display fails.
|
Chris@0
|
2020 */
|
Chris@0
|
2021 public function getPath() {
|
Chris@0
|
2022 if (!empty($this->override_path)) {
|
Chris@0
|
2023 return $this->override_path;
|
Chris@0
|
2024 }
|
Chris@0
|
2025
|
Chris@0
|
2026 if (empty($this->display_handler)) {
|
Chris@0
|
2027 if (!$this->setDisplay('default')) {
|
Chris@0
|
2028 return FALSE;
|
Chris@0
|
2029 }
|
Chris@0
|
2030 }
|
Chris@0
|
2031 return $this->display_handler->getPath();
|
Chris@0
|
2032 }
|
Chris@0
|
2033
|
Chris@0
|
2034 /**
|
Chris@0
|
2035 * Gets the current user.
|
Chris@0
|
2036 *
|
Chris@0
|
2037 * Views plugins can receive the current user in order to not need dependency
|
Chris@0
|
2038 * injection.
|
Chris@0
|
2039 *
|
Chris@0
|
2040 * @return \Drupal\Core\Session\AccountInterface
|
Chris@0
|
2041 * The current user.
|
Chris@0
|
2042 */
|
Chris@0
|
2043 public function getUser() {
|
Chris@0
|
2044 return $this->user;
|
Chris@0
|
2045 }
|
Chris@0
|
2046
|
Chris@0
|
2047 /**
|
Chris@0
|
2048 * Creates a duplicate ViewExecutable object.
|
Chris@0
|
2049 *
|
Chris@0
|
2050 * Makes a copy of this view that has been sanitized of handlers, any runtime
|
Chris@0
|
2051 * data, ID, and UUID.
|
Chris@0
|
2052 */
|
Chris@0
|
2053 public function createDuplicate() {
|
Chris@0
|
2054 return $this->storage->createDuplicate()->getExecutable();
|
Chris@0
|
2055 }
|
Chris@0
|
2056
|
Chris@0
|
2057 /**
|
Chris@0
|
2058 * Unsets references so that a $view object may be properly garbage collected.
|
Chris@0
|
2059 */
|
Chris@0
|
2060 public function destroy() {
|
Chris@0
|
2061 foreach ($this::getHandlerTypes() as $type => $info) {
|
Chris@0
|
2062 if (isset($this->$type)) {
|
Chris@0
|
2063 foreach ($this->{$type} as $handler) {
|
Chris@0
|
2064 $handler->destroy();
|
Chris@0
|
2065 }
|
Chris@0
|
2066 }
|
Chris@0
|
2067 }
|
Chris@0
|
2068
|
Chris@0
|
2069 if (isset($this->style_plugin)) {
|
Chris@0
|
2070 $this->style_plugin->destroy();
|
Chris@0
|
2071 }
|
Chris@0
|
2072
|
Chris@0
|
2073 $reflection = new \ReflectionClass($this);
|
Chris@0
|
2074 $defaults = $reflection->getDefaultProperties();
|
Chris@0
|
2075 // The external dependencies should not be reset. This is not generated by
|
Chris@0
|
2076 // the execution of a view.
|
Chris@0
|
2077 unset(
|
Chris@0
|
2078 $defaults['storage'],
|
Chris@0
|
2079 $defaults['user'],
|
Chris@0
|
2080 $defaults['request'],
|
Chris@0
|
2081 $defaults['routeProvider'],
|
Chris@0
|
2082 $defaults['viewsData']
|
Chris@0
|
2083 );
|
Chris@0
|
2084
|
Chris@0
|
2085 foreach ($defaults as $property => $default) {
|
Chris@0
|
2086 $this->{$property} = $default;
|
Chris@0
|
2087 }
|
Chris@0
|
2088 }
|
Chris@0
|
2089
|
Chris@0
|
2090 /**
|
Chris@0
|
2091 * Makes sure the view is completely valid.
|
Chris@0
|
2092 *
|
Chris@0
|
2093 * @return array
|
Chris@0
|
2094 * An array of error strings. This will be empty if there are no validation
|
Chris@0
|
2095 * errors.
|
Chris@0
|
2096 */
|
Chris@0
|
2097 public function validate() {
|
Chris@0
|
2098 $errors = [];
|
Chris@0
|
2099
|
Chris@0
|
2100 $this->initDisplay();
|
Chris@0
|
2101 $current_display = $this->current_display;
|
Chris@0
|
2102
|
Chris@0
|
2103 foreach ($this->displayHandlers as $id => $display) {
|
Chris@0
|
2104 if (!empty($display)) {
|
Chris@0
|
2105 if (!empty($display->display['deleted'])) {
|
Chris@0
|
2106 continue;
|
Chris@0
|
2107 }
|
Chris@0
|
2108
|
Chris@0
|
2109 $result = $this->displayHandlers->get($id)->validate();
|
Chris@0
|
2110 if (!empty($result) && is_array($result)) {
|
Chris@0
|
2111 $errors[$id] = $result;
|
Chris@0
|
2112 }
|
Chris@0
|
2113 }
|
Chris@0
|
2114 }
|
Chris@0
|
2115
|
Chris@0
|
2116 $this->setDisplay($current_display);
|
Chris@0
|
2117
|
Chris@0
|
2118 return $errors;
|
Chris@0
|
2119 }
|
Chris@0
|
2120
|
Chris@0
|
2121 /**
|
Chris@0
|
2122 * Provides a list of views handler types used in a view.
|
Chris@0
|
2123 *
|
Chris@0
|
2124 * This also provides some information about the views handler types.
|
Chris@0
|
2125 *
|
Chris@0
|
2126 * @return array
|
Chris@0
|
2127 * An array of associative arrays containing:
|
Chris@0
|
2128 * - title: The title of the handler type.
|
Chris@0
|
2129 * - ltitle: The lowercase title of the handler type.
|
Chris@0
|
2130 * - stitle: A singular title of the handler type.
|
Chris@0
|
2131 * - lstitle: A singular lowercase title of the handler type.
|
Chris@0
|
2132 * - plural: Plural version of the handler type.
|
Chris@0
|
2133 * - (optional) type: The actual internal used handler type. This key is
|
Chris@0
|
2134 * just used for header,footer,empty to link to the internal type: area.
|
Chris@0
|
2135 */
|
Chris@0
|
2136 public static function getHandlerTypes() {
|
Chris@0
|
2137 return Views::getHandlerTypes();
|
Chris@0
|
2138 }
|
Chris@0
|
2139
|
Chris@0
|
2140 /**
|
Chris@0
|
2141 * Returns the valid types of plugins that can be used.
|
Chris@0
|
2142 *
|
Chris@0
|
2143 * @return array
|
Chris@0
|
2144 * An array of plugin type strings.
|
Chris@0
|
2145 */
|
Chris@0
|
2146 public static function getPluginTypes($type = NULL) {
|
Chris@0
|
2147 return Views::getPluginTypes($type);
|
Chris@0
|
2148 }
|
Chris@0
|
2149
|
Chris@0
|
2150 /**
|
Chris@0
|
2151 * Adds an instance of a handler to the view.
|
Chris@0
|
2152 *
|
Chris@0
|
2153 * Items may be fields, filters, sort criteria, or arguments.
|
Chris@0
|
2154 *
|
Chris@0
|
2155 * @param string $display_id
|
Chris@0
|
2156 * The machine name of the display.
|
Chris@0
|
2157 * @param string $type
|
Chris@0
|
2158 * The type of handler being added.
|
Chris@0
|
2159 * @param string $table
|
Chris@0
|
2160 * The name of the table this handler is from.
|
Chris@0
|
2161 * @param string $field
|
Chris@0
|
2162 * The name of the field this handler is from.
|
Chris@0
|
2163 * @param array $options
|
Chris@0
|
2164 * (optional) Extra options for this instance. Defaults to an empty array.
|
Chris@0
|
2165 * @param string $id
|
Chris@0
|
2166 * (optional) A unique ID for this handler instance. Defaults to NULL, in
|
Chris@0
|
2167 * which case one will be generated.
|
Chris@0
|
2168 *
|
Chris@0
|
2169 * @return string
|
Chris@0
|
2170 * The unique ID for this handler instance.
|
Chris@0
|
2171 */
|
Chris@0
|
2172 public function addHandler($display_id, $type, $table, $field, $options = [], $id = NULL) {
|
Chris@0
|
2173 $types = $this::getHandlerTypes();
|
Chris@0
|
2174 $this->setDisplay($display_id);
|
Chris@0
|
2175
|
Chris@0
|
2176 $data = $this->viewsData->get($table);
|
Chris@0
|
2177 $fields = $this->displayHandlers->get($display_id)->getOption($types[$type]['plural']);
|
Chris@0
|
2178
|
Chris@0
|
2179 if (empty($id)) {
|
Chris@0
|
2180 $id = $this->generateHandlerId($field, $fields);
|
Chris@0
|
2181 }
|
Chris@0
|
2182
|
Chris@0
|
2183 // If the desired type is not found, use the original value directly.
|
Chris@0
|
2184 $handler_type = !empty($types[$type]['type']) ? $types[$type]['type'] : $type;
|
Chris@0
|
2185
|
Chris@0
|
2186 $fields[$id] = [
|
Chris@0
|
2187 'id' => $id,
|
Chris@0
|
2188 'table' => $table,
|
Chris@0
|
2189 'field' => $field,
|
Chris@0
|
2190 ] + $options;
|
Chris@0
|
2191
|
Chris@0
|
2192 if (isset($data['table']['entity type'])) {
|
Chris@0
|
2193 $fields[$id]['entity_type'] = $data['table']['entity type'];
|
Chris@0
|
2194 }
|
Chris@0
|
2195 if (isset($data[$field]['entity field'])) {
|
Chris@0
|
2196 $fields[$id]['entity_field'] = $data[$field]['entity field'];
|
Chris@0
|
2197 }
|
Chris@0
|
2198
|
Chris@0
|
2199 // Load the plugin ID if available.
|
Chris@0
|
2200 if (isset($data[$field][$handler_type]['id'])) {
|
Chris@0
|
2201 $fields[$id]['plugin_id'] = $data[$field][$handler_type]['id'];
|
Chris@0
|
2202 }
|
Chris@0
|
2203
|
Chris@0
|
2204 $this->displayHandlers->get($display_id)->setOption($types[$type]['plural'], $fields);
|
Chris@0
|
2205
|
Chris@0
|
2206 return $id;
|
Chris@0
|
2207 }
|
Chris@0
|
2208
|
Chris@0
|
2209 /**
|
Chris@0
|
2210 * Generates a unique ID for an handler instance.
|
Chris@0
|
2211 *
|
Chris@0
|
2212 * These handler instances are typically fields, filters, sort criteria, or
|
Chris@0
|
2213 * arguments.
|
Chris@0
|
2214 *
|
Chris@0
|
2215 * @param string $requested_id
|
Chris@0
|
2216 * The requested ID for the handler instance.
|
Chris@0
|
2217 * @param array $existing_items
|
Chris@0
|
2218 * An array of existing handler instances, keyed by their IDs.
|
Chris@0
|
2219 *
|
Chris@0
|
2220 * @return string
|
Chris@0
|
2221 * A unique ID. This will be equal to $requested_id if no handler instance
|
Chris@0
|
2222 * with that ID already exists. Otherwise, it will be appended with an
|
Chris@0
|
2223 * integer to make it unique, e.g., "{$requested_id}_1",
|
Chris@0
|
2224 * "{$requested_id}_2", etc.
|
Chris@0
|
2225 */
|
Chris@0
|
2226 public static function generateHandlerId($requested_id, $existing_items) {
|
Chris@0
|
2227 $count = 0;
|
Chris@0
|
2228 $id = $requested_id;
|
Chris@0
|
2229 while (!empty($existing_items[$id])) {
|
Chris@0
|
2230 $id = $requested_id . '_' . ++$count;
|
Chris@0
|
2231 }
|
Chris@0
|
2232 return $id;
|
Chris@0
|
2233 }
|
Chris@0
|
2234
|
Chris@0
|
2235 /**
|
Chris@0
|
2236 * Gets an array of handler instances for the current display.
|
Chris@0
|
2237 *
|
Chris@0
|
2238 * @param string $type
|
Chris@0
|
2239 * The type of handlers to retrieve.
|
Chris@0
|
2240 * @param string $display_id
|
Chris@0
|
2241 * (optional) A specific display machine name to use. If NULL, the current
|
Chris@0
|
2242 * display will be used.
|
Chris@0
|
2243 *
|
Chris@0
|
2244 * @return array
|
Chris@0
|
2245 * An array of handler instances of a given type for this display.
|
Chris@0
|
2246 */
|
Chris@0
|
2247 public function getHandlers($type, $display_id = NULL) {
|
Chris@0
|
2248 $old_display_id = !empty($this->current_display) ? $this->current_display : 'default';
|
Chris@0
|
2249
|
Chris@0
|
2250 $this->setDisplay($display_id);
|
Chris@0
|
2251
|
Chris@0
|
2252 if (!isset($display_id)) {
|
Chris@0
|
2253 $display_id = $this->current_display;
|
Chris@0
|
2254 }
|
Chris@0
|
2255
|
Chris@0
|
2256 // Get info about the types so we can get the right data.
|
Chris@0
|
2257 $types = static::getHandlerTypes();
|
Chris@0
|
2258
|
Chris@0
|
2259 $handlers = $this->displayHandlers->get($display_id)->getOption($types[$type]['plural']);
|
Chris@0
|
2260
|
Chris@0
|
2261 // Restore initial display id (if any) or set to 'default'.
|
Chris@0
|
2262 if ($display_id != $old_display_id) {
|
Chris@0
|
2263 $this->setDisplay($old_display_id);
|
Chris@0
|
2264 }
|
Chris@0
|
2265 return $handlers;
|
Chris@0
|
2266 }
|
Chris@0
|
2267
|
Chris@0
|
2268 /**
|
Chris@0
|
2269 * Gets the configuration of a handler instance on a given display.
|
Chris@0
|
2270 *
|
Chris@0
|
2271 * @param string $display_id
|
Chris@0
|
2272 * The machine name of the display.
|
Chris@0
|
2273 * @param string $type
|
Chris@0
|
2274 * The type of handler to retrieve.
|
Chris@0
|
2275 * @param string $id
|
Chris@0
|
2276 * The ID of the handler to retrieve.
|
Chris@0
|
2277 *
|
Chris@0
|
2278 * @return array|null
|
Chris@0
|
2279 * Either the handler instance's configuration, or NULL if the handler is
|
Chris@0
|
2280 * not used on the display.
|
Chris@0
|
2281 */
|
Chris@0
|
2282 public function getHandler($display_id, $type, $id) {
|
Chris@0
|
2283 // Get info about the types so we can get the right data.
|
Chris@0
|
2284 $types = static::getHandlerTypes();
|
Chris@0
|
2285 // Initialize the display
|
Chris@0
|
2286 $this->setDisplay($display_id);
|
Chris@0
|
2287
|
Chris@0
|
2288 // Get the existing configuration
|
Chris@0
|
2289 $fields = $this->displayHandlers->get($display_id)->getOption($types[$type]['plural']);
|
Chris@0
|
2290
|
Chris@0
|
2291 return isset($fields[$id]) ? $fields[$id] : NULL;
|
Chris@0
|
2292 }
|
Chris@0
|
2293
|
Chris@0
|
2294 /**
|
Chris@0
|
2295 * Sets the configuration of a handler instance on a given display.
|
Chris@0
|
2296 *
|
Chris@0
|
2297 * @param string $display_id
|
Chris@0
|
2298 * The machine name of the display.
|
Chris@0
|
2299 * @param string $type
|
Chris@0
|
2300 * The type of handler being set.
|
Chris@0
|
2301 * @param string $id
|
Chris@0
|
2302 * The ID of the handler being set.
|
Chris@0
|
2303 * @param array|null $item
|
Chris@0
|
2304 * An array of configuration for a handler, or NULL to remove this instance.
|
Chris@0
|
2305 *
|
Chris@0
|
2306 * @see set_item_option()
|
Chris@0
|
2307 */
|
Chris@0
|
2308 public function setHandler($display_id, $type, $id, $item) {
|
Chris@0
|
2309 // Get info about the types so we can get the right data.
|
Chris@0
|
2310 $types = static::getHandlerTypes();
|
Chris@0
|
2311 // Initialize the display.
|
Chris@0
|
2312 $this->setDisplay($display_id);
|
Chris@0
|
2313
|
Chris@0
|
2314 // Get the existing configuration.
|
Chris@0
|
2315 $fields = $this->displayHandlers->get($display_id)->getOption($types[$type]['plural']);
|
Chris@0
|
2316 if (isset($item)) {
|
Chris@0
|
2317 $fields[$id] = $item;
|
Chris@0
|
2318 }
|
Chris@0
|
2319
|
Chris@0
|
2320 // Store.
|
Chris@0
|
2321 $this->displayHandlers->get($display_id)->setOption($types[$type]['plural'], $fields);
|
Chris@0
|
2322 }
|
Chris@0
|
2323
|
Chris@0
|
2324 /**
|
Chris@0
|
2325 * Removes configuration for a handler instance on a given display.
|
Chris@0
|
2326 *
|
Chris@0
|
2327 * @param string $display_id
|
Chris@0
|
2328 * The machine name of the display.
|
Chris@0
|
2329 * @param string $type
|
Chris@0
|
2330 * The type of handler being removed.
|
Chris@0
|
2331 * @param string $id
|
Chris@0
|
2332 * The ID of the handler being removed.
|
Chris@0
|
2333 */
|
Chris@0
|
2334 public function removeHandler($display_id, $type, $id) {
|
Chris@0
|
2335 // Get info about the types so we can get the right data.
|
Chris@0
|
2336 $types = static::getHandlerTypes();
|
Chris@0
|
2337 // Initialize the display.
|
Chris@0
|
2338 $this->setDisplay($display_id);
|
Chris@0
|
2339
|
Chris@0
|
2340 // Get the existing configuration.
|
Chris@0
|
2341 $fields = $this->displayHandlers->get($display_id)->getOption($types[$type]['plural']);
|
Chris@0
|
2342 // Unset the item.
|
Chris@0
|
2343 unset($fields[$id]);
|
Chris@0
|
2344
|
Chris@0
|
2345 // Store.
|
Chris@0
|
2346 $this->displayHandlers->get($display_id)->setOption($types[$type]['plural'], $fields);
|
Chris@0
|
2347 }
|
Chris@0
|
2348
|
Chris@0
|
2349 /**
|
Chris@0
|
2350 * Sets an option on a handler instance.
|
Chris@0
|
2351 *
|
Chris@0
|
2352 * Use this only if you have just 1 or 2 options to set; if you have many,
|
Chris@0
|
2353 * consider getting the handler instance, adding the options and using
|
Chris@0
|
2354 * set_item() directly.
|
Chris@0
|
2355 *
|
Chris@0
|
2356 * @param string $display_id
|
Chris@0
|
2357 * The machine name of the display.
|
Chris@0
|
2358 * @param string $type
|
Chris@0
|
2359 * The type of handler being set.
|
Chris@0
|
2360 * @param string $id
|
Chris@0
|
2361 * The ID of the handler being set.
|
Chris@0
|
2362 * @param string $option
|
Chris@0
|
2363 * The configuration key for the value being set.
|
Chris@0
|
2364 * @param mixed $value
|
Chris@0
|
2365 * The value being set.
|
Chris@0
|
2366 *
|
Chris@0
|
2367 * @see set_item()
|
Chris@0
|
2368 */
|
Chris@0
|
2369 public function setHandlerOption($display_id, $type, $id, $option, $value) {
|
Chris@0
|
2370 $item = $this->getHandler($display_id, $type, $id);
|
Chris@0
|
2371 $item[$option] = $value;
|
Chris@0
|
2372 $this->setHandler($display_id, $type, $id, $item);
|
Chris@0
|
2373 }
|
Chris@0
|
2374
|
Chris@0
|
2375 /**
|
Chris@0
|
2376 * Enables admin links on the rendered view.
|
Chris@0
|
2377 *
|
Chris@0
|
2378 * @param bool $show_admin_links
|
Chris@0
|
2379 * TRUE if the admin links should be shown.
|
Chris@0
|
2380 */
|
Chris@0
|
2381 public function setShowAdminLinks($show_admin_links) {
|
Chris@0
|
2382 $this->showAdminLinks = (bool) $show_admin_links;
|
Chris@0
|
2383 }
|
Chris@0
|
2384
|
Chris@0
|
2385 /**
|
Chris@0
|
2386 * Returns whether admin links should be rendered on the view.
|
Chris@0
|
2387 *
|
Chris@0
|
2388 * @return bool
|
Chris@0
|
2389 * TRUE if admin links should be rendered, else FALSE.
|
Chris@0
|
2390 */
|
Chris@0
|
2391 public function getShowAdminLinks() {
|
Chris@0
|
2392 if (!isset($this->showAdminLinks)) {
|
Chris@0
|
2393 return $this->getDisplay()->getOption('show_admin_links');
|
Chris@0
|
2394 }
|
Chris@0
|
2395 return $this->showAdminLinks;
|
Chris@0
|
2396 }
|
Chris@0
|
2397
|
Chris@0
|
2398 /**
|
Chris@0
|
2399 * Merges all plugin default values for each display.
|
Chris@0
|
2400 */
|
Chris@0
|
2401 public function mergeDefaults() {
|
Chris@0
|
2402 $this->initDisplay();
|
Chris@0
|
2403 // Initialize displays and merge all plugin defaults.
|
Chris@0
|
2404 foreach ($this->displayHandlers as $display) {
|
Chris@0
|
2405 $display->mergeDefaults();
|
Chris@0
|
2406 }
|
Chris@0
|
2407 }
|
Chris@0
|
2408
|
Chris@0
|
2409 /**
|
Chris@0
|
2410 * Provides a full array of possible theme functions to try for a given hook.
|
Chris@0
|
2411 *
|
Chris@0
|
2412 * @param string $hook
|
Chris@0
|
2413 * The hook to use. This is the base theme/template name.
|
Chris@0
|
2414 *
|
Chris@0
|
2415 * @return array
|
Chris@0
|
2416 * An array of theme hook suggestions.
|
Chris@0
|
2417 */
|
Chris@0
|
2418 public function buildThemeFunctions($hook) {
|
Chris@0
|
2419 $themes = [];
|
Chris@0
|
2420 $display = isset($this->display_handler) ? $this->display_handler->display : NULL;
|
Chris@0
|
2421 $id = $this->storage->id();
|
Chris@0
|
2422
|
Chris@0
|
2423 if ($display) {
|
Chris@0
|
2424 $themes[] = $hook . '__' . $id . '__' . $display['id'];
|
Chris@0
|
2425 $themes[] = $hook . '__' . $display['id'];
|
Chris@0
|
2426 // Add theme suggestions for each single tag.
|
Chris@0
|
2427 foreach (Tags::explode($this->storage->get('tag')) as $tag) {
|
Chris@0
|
2428 $themes[] = $hook . '__' . preg_replace('/[^a-z0-9]/', '_', strtolower($tag));
|
Chris@0
|
2429 }
|
Chris@0
|
2430
|
Chris@0
|
2431 if ($display['id'] != $display['display_plugin']) {
|
Chris@0
|
2432 $themes[] = $hook . '__' . $id . '__' . $display['display_plugin'];
|
Chris@0
|
2433 $themes[] = $hook . '__' . $display['display_plugin'];
|
Chris@0
|
2434 }
|
Chris@0
|
2435 }
|
Chris@0
|
2436 $themes[] = $hook . '__' . $id;
|
Chris@0
|
2437 $themes[] = $hook;
|
Chris@0
|
2438
|
Chris@0
|
2439 return $themes;
|
Chris@0
|
2440 }
|
Chris@0
|
2441
|
Chris@0
|
2442 /**
|
Chris@0
|
2443 * Determines if this view has form elements.
|
Chris@0
|
2444 *
|
Chris@0
|
2445 * @return bool
|
Chris@0
|
2446 * TRUE if this view contains handlers with views form implementations,
|
Chris@0
|
2447 * FALSE otherwise.
|
Chris@0
|
2448 */
|
Chris@0
|
2449 public function hasFormElements() {
|
Chris@0
|
2450 foreach ($this->field as $field) {
|
Chris@0
|
2451 if (property_exists($field, 'views_form_callback') || method_exists($field, 'viewsForm')) {
|
Chris@0
|
2452 return TRUE;
|
Chris@0
|
2453 }
|
Chris@0
|
2454 }
|
Chris@0
|
2455 $area_handlers = array_merge(array_values($this->header), array_values($this->footer));
|
Chris@0
|
2456 $empty = empty($this->result);
|
Chris@0
|
2457 foreach ($area_handlers as $area) {
|
Chris@0
|
2458 if (method_exists($area, 'viewsForm') && !$area->viewsFormEmpty($empty)) {
|
Chris@0
|
2459 return TRUE;
|
Chris@0
|
2460 }
|
Chris@0
|
2461 }
|
Chris@0
|
2462
|
Chris@0
|
2463 return FALSE;
|
Chris@0
|
2464 }
|
Chris@0
|
2465
|
Chris@0
|
2466 /**
|
Chris@0
|
2467 * Gets dependencies for the view.
|
Chris@0
|
2468 *
|
Chris@0
|
2469 * @see \Drupal\views\Entity\View::calculateDependencies()
|
Chris@0
|
2470 * @see \Drupal\views\Entity\View::getDependencies()
|
Chris@0
|
2471 *
|
Chris@0
|
2472 * @return array
|
Chris@0
|
2473 * An array of dependencies grouped by type (module, theme, entity).
|
Chris@0
|
2474 */
|
Chris@0
|
2475 public function getDependencies() {
|
Chris@0
|
2476 return $this->storage->calculateDependencies()->getDependencies();
|
Chris@0
|
2477 }
|
Chris@0
|
2478
|
Chris@0
|
2479 /**
|
Chris@0
|
2480 * Magic method implementation to serialize the view executable.
|
Chris@0
|
2481 *
|
Chris@0
|
2482 * @return array
|
Chris@0
|
2483 * The names of all variables that should be serialized.
|
Chris@0
|
2484 */
|
Chris@0
|
2485 public function __sleep() {
|
Chris@0
|
2486 // Limit to only the required data which is needed to properly restore the
|
Chris@0
|
2487 // state during unserialization.
|
Chris@0
|
2488 $this->serializationData = [
|
Chris@0
|
2489 'storage' => $this->storage->id(),
|
Chris@0
|
2490 'views_data' => $this->viewsData->_serviceId,
|
Chris@0
|
2491 'route_provider' => $this->routeProvider->_serviceId,
|
Chris@0
|
2492 'current_display' => $this->current_display,
|
Chris@0
|
2493 'args' => $this->args,
|
Chris@0
|
2494 'current_page' => $this->current_page,
|
Chris@0
|
2495 'exposed_input' => $this->exposed_input,
|
Chris@0
|
2496 'exposed_raw_input' => $this->exposed_raw_input,
|
Chris@0
|
2497 'exposed_data' => $this->exposed_data,
|
Chris@0
|
2498 'dom_id' => $this->dom_id,
|
Chris@0
|
2499 'executed' => $this->executed,
|
Chris@0
|
2500 ];
|
Chris@0
|
2501 return ['serializationData'];
|
Chris@0
|
2502 }
|
Chris@0
|
2503
|
Chris@0
|
2504 /**
|
Chris@0
|
2505 * Magic method implementation to unserialize the view executable.
|
Chris@0
|
2506 */
|
Chris@0
|
2507 public function __wakeup() {
|
Chris@0
|
2508 // There are cases, like in testing where we don't have a container
|
Chris@0
|
2509 // available.
|
Chris@0
|
2510 if (\Drupal::hasContainer() && !empty($this->serializationData)) {
|
Chris@0
|
2511 // Load and reference the storage.
|
Chris@0
|
2512 $this->storage = \Drupal::entityTypeManager()->getStorage('view')
|
Chris@0
|
2513 ->load($this->serializationData['storage']);
|
Chris@0
|
2514 $this->storage->set('executable', $this);
|
Chris@0
|
2515
|
Chris@0
|
2516 // Attach all necessary services.
|
Chris@0
|
2517 $this->user = \Drupal::currentUser();
|
Chris@0
|
2518 $this->viewsData = \Drupal::service($this->serializationData['views_data']);
|
Chris@0
|
2519 $this->routeProvider = \Drupal::service($this->serializationData['route_provider']);
|
Chris@0
|
2520
|
Chris@0
|
2521 // Restore the state of this executable.
|
Chris@0
|
2522 if ($request = \Drupal::request()) {
|
Chris@0
|
2523 $this->setRequest($request);
|
Chris@0
|
2524 }
|
Chris@0
|
2525 $this->setDisplay($this->serializationData['current_display']);
|
Chris@0
|
2526 $this->setArguments($this->serializationData['args']);
|
Chris@0
|
2527 $this->setCurrentPage($this->serializationData['current_page']);
|
Chris@0
|
2528 $this->setExposedInput($this->serializationData['exposed_input']);
|
Chris@0
|
2529 $this->exposed_data = $this->serializationData['exposed_data'];
|
Chris@0
|
2530 $this->exposed_raw_input = $this->serializationData['exposed_raw_input'];
|
Chris@0
|
2531 $this->dom_id = $this->serializationData['dom_id'];
|
Chris@0
|
2532
|
Chris@0
|
2533 $this->initHandlers();
|
Chris@0
|
2534
|
Chris@0
|
2535 // If the display was previously executed, execute it now.
|
Chris@0
|
2536 if ($this->serializationData['executed']) {
|
Chris@0
|
2537 $this->execute($this->current_display);
|
Chris@0
|
2538 }
|
Chris@0
|
2539 }
|
Chris@0
|
2540 // Unset serializationData since it serves no further purpose.
|
Chris@0
|
2541 unset($this->serializationData);
|
Chris@0
|
2542 }
|
Chris@0
|
2543
|
Chris@0
|
2544 }
|