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@0
|
334 * Does this view already have loaded it's 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
|
Chris@0
|
623 // If the pager is already initialized, pass it through to the pager.
|
Chris@0
|
624 if (!empty($this->pager)) {
|
Chris@0
|
625 $this->pager->setOffset($offset);
|
Chris@0
|
626 }
|
Chris@0
|
627 }
|
Chris@0
|
628
|
Chris@0
|
629 /**
|
Chris@0
|
630 * Determines if the view uses a pager.
|
Chris@0
|
631 *
|
Chris@0
|
632 * @return bool
|
Chris@0
|
633 * TRUE if the view uses a pager, FALSE otherwise.
|
Chris@0
|
634 */
|
Chris@0
|
635 public function usePager() {
|
Chris@0
|
636 if (!empty($this->pager)) {
|
Chris@0
|
637 return $this->pager->usePager();
|
Chris@0
|
638 }
|
Chris@0
|
639 }
|
Chris@0
|
640
|
Chris@0
|
641 /**
|
Chris@0
|
642 * Sets whether or not AJAX should be used.
|
Chris@0
|
643 *
|
Chris@0
|
644 * If AJAX is used, paging, table sorting, and exposed filters will be fetched
|
Chris@0
|
645 * via an AJAX call rather than a page refresh.
|
Chris@0
|
646 *
|
Chris@0
|
647 * @param bool $ajax_enabled
|
Chris@0
|
648 * TRUE if AJAX should be used, FALSE otherwise.
|
Chris@0
|
649 */
|
Chris@0
|
650 public function setAjaxEnabled($ajax_enabled) {
|
Chris@0
|
651 $this->ajaxEnabled = (bool) $ajax_enabled;
|
Chris@0
|
652 }
|
Chris@0
|
653
|
Chris@0
|
654 /**
|
Chris@0
|
655 * Determines whether or not AJAX should be used.
|
Chris@0
|
656 *
|
Chris@0
|
657 * @return bool
|
Chris@0
|
658 * TRUE if AJAX is enabled, FALSE otherwise.
|
Chris@0
|
659 */
|
Chris@0
|
660 public function ajaxEnabled() {
|
Chris@0
|
661 return $this->ajaxEnabled;
|
Chris@0
|
662 }
|
Chris@0
|
663
|
Chris@0
|
664 /**
|
Chris@0
|
665 * Sets the exposed filters input to an array.
|
Chris@0
|
666 *
|
Chris@0
|
667 * @param string[] $filters
|
Chris@0
|
668 * The values taken from the view's exposed filters and sorts.
|
Chris@0
|
669 */
|
Chris@0
|
670 public function setExposedInput($filters) {
|
Chris@0
|
671 $this->exposed_input = $filters;
|
Chris@0
|
672 }
|
Chris@0
|
673
|
Chris@0
|
674 /**
|
Chris@0
|
675 * Figures out what the exposed input for this view is.
|
Chris@0
|
676 *
|
Chris@0
|
677 * They will be taken from \Drupal::request()->query or from
|
Chris@0
|
678 * something previously set on the view.
|
Chris@0
|
679 *
|
Chris@0
|
680 * @return string[]
|
Chris@0
|
681 * An array containing the exposed input values keyed by the filter and sort
|
Chris@0
|
682 * name.
|
Chris@0
|
683 *
|
Chris@0
|
684 * @see self::setExposedInput()
|
Chris@0
|
685 */
|
Chris@0
|
686 public function getExposedInput() {
|
Chris@0
|
687 // Fill our input either from \Drupal::request()->query or from something
|
Chris@0
|
688 // previously set on the view.
|
Chris@0
|
689 if (empty($this->exposed_input)) {
|
Chris@0
|
690 // Ensure that we can call the method at any point in time.
|
Chris@0
|
691 $this->initDisplay();
|
Chris@0
|
692
|
Chris@0
|
693 $this->exposed_input = \Drupal::request()->query->all();
|
Chris@0
|
694 // unset items that are definitely not our input:
|
Chris@0
|
695 foreach (['page', 'q'] as $key) {
|
Chris@0
|
696 if (isset($this->exposed_input[$key])) {
|
Chris@0
|
697 unset($this->exposed_input[$key]);
|
Chris@0
|
698 }
|
Chris@0
|
699 }
|
Chris@0
|
700
|
Chris@0
|
701 // If we have no input at all, check for remembered input via session.
|
Chris@0
|
702
|
Chris@0
|
703 // If filters are not overridden, store the 'remember' settings on the
|
Chris@0
|
704 // default display. If they are, store them on this display. This way,
|
Chris@0
|
705 // multiple displays in the same view can share the same filters and
|
Chris@0
|
706 // remember settings.
|
Chris@0
|
707 $display_id = ($this->display_handler->isDefaulted('filters')) ? 'default' : $this->current_display;
|
Chris@0
|
708
|
Chris@0
|
709 if (empty($this->exposed_input) && !empty($_SESSION['views'][$this->storage->id()][$display_id])) {
|
Chris@0
|
710 $this->exposed_input = $_SESSION['views'][$this->storage->id()][$display_id];
|
Chris@0
|
711 }
|
Chris@0
|
712 }
|
Chris@0
|
713
|
Chris@0
|
714 return $this->exposed_input;
|
Chris@0
|
715 }
|
Chris@0
|
716
|
Chris@0
|
717 /**
|
Chris@0
|
718 * Sets the display for this view and initializes the display handler.
|
Chris@0
|
719 *
|
Chris@0
|
720 * @return true
|
Chris@0
|
721 * Always returns TRUE.
|
Chris@0
|
722 */
|
Chris@0
|
723 public function initDisplay() {
|
Chris@0
|
724 if (isset($this->current_display)) {
|
Chris@0
|
725 return TRUE;
|
Chris@0
|
726 }
|
Chris@0
|
727
|
Chris@0
|
728 // Initialize the display cache array.
|
Chris@0
|
729 $this->displayHandlers = new DisplayPluginCollection($this, Views::pluginManager('display'));
|
Chris@0
|
730
|
Chris@0
|
731 $this->current_display = 'default';
|
Chris@0
|
732 $this->display_handler = $this->displayHandlers->get('default');
|
Chris@0
|
733
|
Chris@0
|
734 return TRUE;
|
Chris@0
|
735 }
|
Chris@0
|
736
|
Chris@0
|
737 /**
|
Chris@0
|
738 * Gets the first display that is accessible to the user.
|
Chris@0
|
739 *
|
Chris@0
|
740 * @param array|string $displays
|
Chris@0
|
741 * Either a single display id or an array of display ids.
|
Chris@0
|
742 *
|
Chris@0
|
743 * @return string
|
Chris@0
|
744 * The first accessible display id, at least default.
|
Chris@0
|
745 */
|
Chris@0
|
746 public function chooseDisplay($displays) {
|
Chris@0
|
747 if (!is_array($displays)) {
|
Chris@0
|
748 return $displays;
|
Chris@0
|
749 }
|
Chris@0
|
750
|
Chris@0
|
751 $this->initDisplay();
|
Chris@0
|
752
|
Chris@0
|
753 foreach ($displays as $display_id) {
|
Chris@0
|
754 if ($this->displayHandlers->get($display_id)->access($this->user)) {
|
Chris@0
|
755 return $display_id;
|
Chris@0
|
756 }
|
Chris@0
|
757 }
|
Chris@0
|
758
|
Chris@0
|
759 return 'default';
|
Chris@0
|
760 }
|
Chris@0
|
761
|
Chris@0
|
762 /**
|
Chris@0
|
763 * Gets the current display plugin.
|
Chris@0
|
764 *
|
Chris@0
|
765 * @return \Drupal\views\Plugin\views\display\DisplayPluginBase
|
Chris@0
|
766 * The current display plugin.
|
Chris@0
|
767 */
|
Chris@0
|
768 public function getDisplay() {
|
Chris@0
|
769 if (!isset($this->display_handler)) {
|
Chris@0
|
770 $this->initDisplay();
|
Chris@0
|
771 }
|
Chris@0
|
772
|
Chris@0
|
773 return $this->display_handler;
|
Chris@0
|
774 }
|
Chris@0
|
775
|
Chris@0
|
776 /**
|
Chris@0
|
777 * Sets the current display.
|
Chris@0
|
778 *
|
Chris@0
|
779 * @param string $display_id
|
Chris@0
|
780 * The ID of the display to mark as current.
|
Chris@0
|
781 *
|
Chris@0
|
782 * @return bool
|
Chris@0
|
783 * TRUE if the display was correctly set, FALSE otherwise.
|
Chris@0
|
784 */
|
Chris@0
|
785 public function setDisplay($display_id = NULL) {
|
Chris@0
|
786 // If we have not already initialized the display, do so.
|
Chris@0
|
787 if (!isset($this->current_display)) {
|
Chris@0
|
788 // This will set the default display and instantiate the default display
|
Chris@0
|
789 // plugin.
|
Chris@0
|
790 $this->initDisplay();
|
Chris@0
|
791 }
|
Chris@0
|
792
|
Chris@0
|
793 // If no display ID is passed, we either have initialized the default or
|
Chris@0
|
794 // already have a display set.
|
Chris@0
|
795 if (!isset($display_id)) {
|
Chris@0
|
796 return TRUE;
|
Chris@0
|
797 }
|
Chris@0
|
798
|
Chris@0
|
799 $display_id = $this->chooseDisplay($display_id);
|
Chris@0
|
800
|
Chris@0
|
801 // Ensure the requested display exists.
|
Chris@0
|
802 if (!$this->displayHandlers->has($display_id)) {
|
Chris@0
|
803 trigger_error(new FormattableMarkup('setDisplay() called with invalid display ID "@display".', ['@display' => $display_id]), E_USER_WARNING);
|
Chris@0
|
804 return FALSE;
|
Chris@0
|
805 }
|
Chris@0
|
806
|
Chris@0
|
807 // Reset if the display has changed. It could be called multiple times for
|
Chris@0
|
808 // the same display, especially in the UI.
|
Chris@0
|
809 if ($this->current_display != $display_id) {
|
Chris@0
|
810 // Set the current display.
|
Chris@0
|
811 $this->current_display = $display_id;
|
Chris@0
|
812
|
Chris@0
|
813 // Reset the style and row plugins.
|
Chris@0
|
814 $this->style_plugin = NULL;
|
Chris@0
|
815 $this->plugin_name = NULL;
|
Chris@0
|
816 $this->rowPlugin = NULL;
|
Chris@0
|
817 }
|
Chris@0
|
818
|
Chris@0
|
819 if ($display = $this->displayHandlers->get($display_id)) {
|
Chris@0
|
820 // Set a shortcut.
|
Chris@0
|
821 $this->display_handler = $display;
|
Chris@0
|
822 return TRUE;
|
Chris@0
|
823 }
|
Chris@0
|
824
|
Chris@0
|
825 return FALSE;
|
Chris@0
|
826 }
|
Chris@0
|
827
|
Chris@0
|
828 /**
|
Chris@0
|
829 * Creates a new display and a display handler instance for it.
|
Chris@0
|
830 *
|
Chris@0
|
831 * @param string $plugin_id
|
Chris@0
|
832 * (optional) The plugin type from the Views plugin annotation. Defaults to
|
Chris@0
|
833 * 'page'.
|
Chris@0
|
834 * @param string $title
|
Chris@0
|
835 * (optional) The title of the display. Defaults to NULL.
|
Chris@0
|
836 * @param string $id
|
Chris@0
|
837 * (optional) The ID to use, e.g., 'default', 'page_1', 'block_2'. Defaults
|
Chris@0
|
838 * to NULL.
|
Chris@0
|
839 *
|
Chris@0
|
840 * @return \Drupal\views\Plugin\views\display\DisplayPluginBase
|
Chris@0
|
841 * A new display plugin instance if executable is set, the new display ID
|
Chris@0
|
842 * otherwise.
|
Chris@0
|
843 */
|
Chris@0
|
844 public function newDisplay($plugin_id = 'page', $title = NULL, $id = NULL) {
|
Chris@0
|
845 $this->initDisplay();
|
Chris@0
|
846
|
Chris@0
|
847 $id = $this->storage->addDisplay($plugin_id, $title, $id);
|
Chris@0
|
848 $this->displayHandlers->addInstanceId($id);
|
Chris@0
|
849
|
Chris@0
|
850 $display = $this->displayHandlers->get($id);
|
Chris@0
|
851 $display->newDisplay();
|
Chris@0
|
852 return $display;
|
Chris@0
|
853 }
|
Chris@0
|
854
|
Chris@0
|
855 /**
|
Chris@0
|
856 * Gets the current style plugin.
|
Chris@0
|
857 *
|
Chris@0
|
858 * @return \Drupal\views\Plugin\views\style\StylePluginBase
|
Chris@0
|
859 * The current style plugin.
|
Chris@0
|
860 */
|
Chris@0
|
861 public function getStyle() {
|
Chris@0
|
862 if (!isset($this->style_plugin)) {
|
Chris@0
|
863 $this->initStyle();
|
Chris@0
|
864 }
|
Chris@0
|
865
|
Chris@0
|
866 return $this->style_plugin;
|
Chris@0
|
867 }
|
Chris@0
|
868
|
Chris@0
|
869 /**
|
Chris@0
|
870 * Finds and initializes the style plugin.
|
Chris@0
|
871 *
|
Chris@0
|
872 * Note that arguments may have changed which style plugin we use, so
|
Chris@0
|
873 * check the view object first, then ask the display handler.
|
Chris@0
|
874 *
|
Chris@0
|
875 * @return bool
|
Chris@0
|
876 * TRUE if the style plugin was or could be initialized, FALSE otherwise.
|
Chris@0
|
877 */
|
Chris@0
|
878 public function initStyle() {
|
Chris@0
|
879 if (isset($this->style_plugin)) {
|
Chris@0
|
880 return TRUE;
|
Chris@0
|
881 }
|
Chris@0
|
882
|
Chris@0
|
883 $this->style_plugin = $this->display_handler->getPlugin('style');
|
Chris@0
|
884
|
Chris@0
|
885 if (empty($this->style_plugin)) {
|
Chris@0
|
886 return FALSE;
|
Chris@0
|
887 }
|
Chris@0
|
888
|
Chris@0
|
889 return TRUE;
|
Chris@0
|
890 }
|
Chris@0
|
891
|
Chris@0
|
892 /**
|
Chris@0
|
893 * Acquires and attaches all of the handlers.
|
Chris@0
|
894 */
|
Chris@0
|
895 public function initHandlers() {
|
Chris@0
|
896 $this->initDisplay();
|
Chris@0
|
897 if (empty($this->inited)) {
|
Chris@0
|
898 foreach ($this::getHandlerTypes() as $key => $info) {
|
Chris@0
|
899 $this->_initHandler($key, $info);
|
Chris@0
|
900 }
|
Chris@0
|
901 $this->inited = TRUE;
|
Chris@0
|
902 }
|
Chris@0
|
903 }
|
Chris@0
|
904
|
Chris@0
|
905 /**
|
Chris@0
|
906 * Gets the current pager plugin.
|
Chris@0
|
907 *
|
Chris@0
|
908 * @return \Drupal\views\Plugin\views\pager\PagerPluginBase
|
Chris@0
|
909 * The current pager plugin.
|
Chris@0
|
910 */
|
Chris@0
|
911 public function getPager() {
|
Chris@0
|
912 if (!isset($this->pager)) {
|
Chris@0
|
913 $this->initPager();
|
Chris@0
|
914 }
|
Chris@0
|
915
|
Chris@0
|
916 return $this->pager;
|
Chris@0
|
917 }
|
Chris@0
|
918
|
Chris@0
|
919 /**
|
Chris@0
|
920 * Initializes the pager.
|
Chris@0
|
921 *
|
Chris@0
|
922 * Like style initialization, pager initialization is held until late to allow
|
Chris@0
|
923 * for overrides.
|
Chris@0
|
924 */
|
Chris@0
|
925 public function initPager() {
|
Chris@0
|
926 if (!isset($this->pager)) {
|
Chris@0
|
927 $this->pager = $this->display_handler->getPlugin('pager');
|
Chris@0
|
928
|
Chris@0
|
929 if ($this->pager->usePager()) {
|
Chris@0
|
930 $this->pager->setCurrentPage($this->current_page);
|
Chris@0
|
931 }
|
Chris@0
|
932
|
Chris@0
|
933 // These overrides may have been set earlier via $view->set_*
|
Chris@0
|
934 // functions.
|
Chris@0
|
935 if (isset($this->items_per_page)) {
|
Chris@0
|
936 $this->pager->setItemsPerPage($this->items_per_page);
|
Chris@0
|
937 }
|
Chris@0
|
938
|
Chris@0
|
939 if (isset($this->offset)) {
|
Chris@0
|
940 $this->pager->setOffset($this->offset);
|
Chris@0
|
941 }
|
Chris@0
|
942 }
|
Chris@0
|
943 }
|
Chris@0
|
944
|
Chris@0
|
945 /**
|
Chris@0
|
946 * Renders the pager, if necessary.
|
Chris@0
|
947 *
|
Chris@0
|
948 * @param string[] $exposed_input
|
Chris@0
|
949 * The input values from the exposed forms and sorts of the view.
|
Chris@0
|
950 *
|
Chris@0
|
951 * @return array|string
|
Chris@0
|
952 * The render array of the pager if it's set, blank string otherwise.
|
Chris@0
|
953 */
|
Chris@0
|
954 public function renderPager($exposed_input) {
|
Chris@0
|
955 if (!empty($this->pager) && $this->pager->usePager()) {
|
Chris@0
|
956 return $this->pager->render($exposed_input);
|
Chris@0
|
957 }
|
Chris@0
|
958
|
Chris@0
|
959 return '';
|
Chris@0
|
960 }
|
Chris@0
|
961
|
Chris@0
|
962 /**
|
Chris@0
|
963 * Creates a list of base tables to be used by the view.
|
Chris@0
|
964 *
|
Chris@0
|
965 * This is used primarily for the UI. The display must be already initialized.
|
Chris@0
|
966 *
|
Chris@0
|
967 * @return array
|
Chris@0
|
968 * An array of base tables to be used by the view.
|
Chris@0
|
969 */
|
Chris@0
|
970 public function getBaseTables() {
|
Chris@0
|
971 $base_tables = [
|
Chris@0
|
972 $this->storage->get('base_table') => TRUE,
|
Chris@0
|
973 '#global' => TRUE,
|
Chris@0
|
974 ];
|
Chris@0
|
975
|
Chris@0
|
976 foreach ($this->display_handler->getHandlers('relationship') as $handler) {
|
Chris@0
|
977 $base_tables[$handler->definition['base']] = TRUE;
|
Chris@0
|
978 }
|
Chris@0
|
979 return $base_tables;
|
Chris@0
|
980 }
|
Chris@0
|
981
|
Chris@0
|
982 /**
|
Chris@0
|
983 * Returns the entity type of the base table, if available.
|
Chris@0
|
984 *
|
Chris@0
|
985 * @return \Drupal\Core\Entity\EntityType|false
|
Chris@0
|
986 * The entity type of the base table, or FALSE if none exists.
|
Chris@0
|
987 */
|
Chris@0
|
988 public function getBaseEntityType() {
|
Chris@0
|
989 if (!isset($this->baseEntityType)) {
|
Chris@0
|
990 $view_base_table = $this->storage->get('base_table');
|
Chris@0
|
991 $views_data = $this->viewsData->get($view_base_table);
|
Chris@0
|
992 if (!empty($views_data['table']['entity type'])) {
|
Chris@0
|
993 $entity_type_id = $views_data['table']['entity type'];
|
Chris@0
|
994 $this->baseEntityType = \Drupal::entityTypeManager()->getDefinition($entity_type_id);
|
Chris@0
|
995 }
|
Chris@0
|
996 else {
|
Chris@0
|
997 $this->baseEntityType = FALSE;
|
Chris@0
|
998 }
|
Chris@0
|
999 }
|
Chris@0
|
1000 return $this->baseEntityType;
|
Chris@0
|
1001 }
|
Chris@0
|
1002
|
Chris@0
|
1003 /**
|
Chris@0
|
1004 * Runs the preQuery() on all active handlers.
|
Chris@0
|
1005 */
|
Chris@0
|
1006 protected function _preQuery() {
|
Chris@0
|
1007 foreach ($this::getHandlerTypes() as $key => $info) {
|
Chris@0
|
1008 $handlers = &$this->$key;
|
Chris@0
|
1009 $position = 0;
|
Chris@0
|
1010 foreach ($handlers as $id => $handler) {
|
Chris@0
|
1011 $handlers[$id]->position = $position;
|
Chris@0
|
1012 $handlers[$id]->preQuery();
|
Chris@0
|
1013 $position++;
|
Chris@0
|
1014 }
|
Chris@0
|
1015 }
|
Chris@0
|
1016 }
|
Chris@0
|
1017
|
Chris@0
|
1018 /**
|
Chris@0
|
1019 * Runs the postExecute() on all active handlers.
|
Chris@0
|
1020 */
|
Chris@0
|
1021 protected function _postExecute() {
|
Chris@0
|
1022 foreach ($this::getHandlerTypes() as $key => $info) {
|
Chris@0
|
1023 $handlers = &$this->$key;
|
Chris@0
|
1024 foreach ($handlers as $id => $handler) {
|
Chris@0
|
1025 $handlers[$id]->postExecute($this->result);
|
Chris@0
|
1026 }
|
Chris@0
|
1027 }
|
Chris@0
|
1028 }
|
Chris@0
|
1029
|
Chris@0
|
1030 /**
|
Chris@0
|
1031 * Attaches the views handler for the specific type.
|
Chris@0
|
1032 *
|
Chris@0
|
1033 * @param string $key
|
Chris@0
|
1034 * One of 'argument', 'field', 'sort', 'filter', 'relationship'.
|
Chris@0
|
1035 * @param array $info
|
Chris@0
|
1036 * An array of views handler types use in the view with additional
|
Chris@0
|
1037 * information about them.
|
Chris@0
|
1038 */
|
Chris@0
|
1039 protected function _initHandler($key, $info) {
|
Chris@0
|
1040 // Load the requested items from the display onto the object.
|
Chris@0
|
1041 $this->$key = &$this->display_handler->getHandlers($key);
|
Chris@0
|
1042
|
Chris@0
|
1043 // This reference deals with difficult PHP indirection.
|
Chris@0
|
1044 $handlers = &$this->$key;
|
Chris@0
|
1045
|
Chris@0
|
1046 // Run through and test for accessibility.
|
Chris@0
|
1047 foreach ($handlers as $id => $handler) {
|
Chris@0
|
1048 if (!$handler->access($this->user)) {
|
Chris@0
|
1049 unset($handlers[$id]);
|
Chris@0
|
1050 }
|
Chris@0
|
1051 }
|
Chris@0
|
1052 }
|
Chris@0
|
1053
|
Chris@0
|
1054 /**
|
Chris@0
|
1055 * Builds all the arguments.
|
Chris@0
|
1056 *
|
Chris@0
|
1057 * @return bool
|
Chris@0
|
1058 * TRUE if the arguments were built successfully, FALSE otherwise.
|
Chris@0
|
1059 */
|
Chris@0
|
1060 protected function _buildArguments() {
|
Chris@0
|
1061 // Initially, we want to build sorts and fields. This can change, though,
|
Chris@0
|
1062 // if we get a summary view.
|
Chris@0
|
1063 if (empty($this->argument)) {
|
Chris@0
|
1064 return TRUE;
|
Chris@0
|
1065 }
|
Chris@0
|
1066
|
Chris@0
|
1067 // build arguments.
|
Chris@0
|
1068 $position = -1;
|
Chris@0
|
1069 $substitutions = [];
|
Chris@0
|
1070 $status = TRUE;
|
Chris@0
|
1071
|
Chris@0
|
1072 // Get the title.
|
Chris@0
|
1073 $title = $this->display_handler->getOption('title');
|
Chris@0
|
1074
|
Chris@0
|
1075 // Iterate through each argument and process.
|
Chris@0
|
1076 foreach ($this->argument as $id => $arg) {
|
Chris@0
|
1077 $position++;
|
Chris@0
|
1078 $argument = $this->argument[$id];
|
Chris@0
|
1079
|
Chris@0
|
1080 if ($argument->broken()) {
|
Chris@0
|
1081 continue;
|
Chris@0
|
1082 }
|
Chris@0
|
1083
|
Chris@0
|
1084 $argument->setRelationship();
|
Chris@0
|
1085
|
Chris@0
|
1086 $arg = isset($this->args[$position]) ? $this->args[$position] : NULL;
|
Chris@0
|
1087 $argument->position = $position;
|
Chris@0
|
1088
|
Chris@0
|
1089 if (isset($arg) || $argument->hasDefaultArgument()) {
|
Chris@0
|
1090 if (!isset($arg)) {
|
Chris@0
|
1091 $arg = $argument->getDefaultArgument();
|
Chris@0
|
1092 // make sure default args get put back.
|
Chris@0
|
1093 if (isset($arg)) {
|
Chris@0
|
1094 $this->args[$position] = $arg;
|
Chris@0
|
1095 }
|
Chris@0
|
1096 // remember that this argument was computed, not passed on the URL.
|
Chris@0
|
1097 $argument->is_default = TRUE;
|
Chris@0
|
1098 }
|
Chris@0
|
1099
|
Chris@0
|
1100 // Set the argument, which will also validate that the argument can be set.
|
Chris@0
|
1101 if (!$argument->setArgument($arg)) {
|
Chris@0
|
1102 $status = $argument->validateFail($arg);
|
Chris@0
|
1103 break;
|
Chris@0
|
1104 }
|
Chris@0
|
1105
|
Chris@0
|
1106 if ($argument->isException()) {
|
Chris@0
|
1107 $arg_title = $argument->exceptionTitle();
|
Chris@0
|
1108 }
|
Chris@0
|
1109 else {
|
Chris@0
|
1110 $arg_title = $argument->getTitle();
|
Chris@0
|
1111 $argument->query($this->display_handler->useGroupBy());
|
Chris@0
|
1112 }
|
Chris@0
|
1113
|
Chris@0
|
1114 // Add this argument's substitution
|
Chris@0
|
1115 $substitutions["{{ arguments.$id }}"] = $arg_title;
|
Chris@0
|
1116 $substitutions["{{ raw_arguments.$id }}"] = strip_tags(Html::decodeEntities($arg));
|
Chris@0
|
1117
|
Chris@0
|
1118 // Test to see if we should use this argument's title
|
Chris@0
|
1119 if (!empty($argument->options['title_enable']) && !empty($argument->options['title'])) {
|
Chris@0
|
1120 $title = $argument->options['title'];
|
Chris@0
|
1121 }
|
Chris@0
|
1122 }
|
Chris@0
|
1123 else {
|
Chris@0
|
1124 // determine default condition and handle.
|
Chris@0
|
1125 $status = $argument->defaultAction();
|
Chris@0
|
1126 break;
|
Chris@0
|
1127 }
|
Chris@0
|
1128
|
Chris@0
|
1129 // Be safe with references and loops:
|
Chris@0
|
1130 unset($argument);
|
Chris@0
|
1131 }
|
Chris@0
|
1132
|
Chris@0
|
1133 // set the title in the build info.
|
Chris@0
|
1134 if (!empty($title)) {
|
Chris@0
|
1135 $this->build_info['title'] = $title;
|
Chris@0
|
1136 }
|
Chris@0
|
1137
|
Chris@0
|
1138 // Store the arguments for later use.
|
Chris@0
|
1139 $this->build_info['substitutions'] = $substitutions;
|
Chris@0
|
1140
|
Chris@0
|
1141 return $status;
|
Chris@0
|
1142 }
|
Chris@0
|
1143
|
Chris@0
|
1144 /**
|
Chris@0
|
1145 * Gets the current query plugin.
|
Chris@0
|
1146 *
|
Chris@0
|
1147 * @return \Drupal\views\Plugin\views\query\QueryPluginBase
|
Chris@0
|
1148 * The current query plugin.
|
Chris@0
|
1149 */
|
Chris@0
|
1150 public function getQuery() {
|
Chris@0
|
1151 if (!isset($this->query)) {
|
Chris@0
|
1152 $this->initQuery();
|
Chris@0
|
1153 }
|
Chris@0
|
1154
|
Chris@0
|
1155 return $this->query;
|
Chris@0
|
1156 }
|
Chris@0
|
1157
|
Chris@0
|
1158 /**
|
Chris@0
|
1159 * Initializes the query object for the view.
|
Chris@0
|
1160 *
|
Chris@0
|
1161 * @return true
|
Chris@0
|
1162 * Always returns TRUE.
|
Chris@0
|
1163 */
|
Chris@0
|
1164 public function initQuery() {
|
Chris@0
|
1165 if (!empty($this->query)) {
|
Chris@0
|
1166 $class = get_class($this->query);
|
Chris@0
|
1167 if ($class && $class != 'stdClass') {
|
Chris@0
|
1168 // return if query is already initialized.
|
Chris@0
|
1169 return TRUE;
|
Chris@0
|
1170 }
|
Chris@0
|
1171 }
|
Chris@0
|
1172
|
Chris@0
|
1173 // Create and initialize the query object.
|
Chris@0
|
1174 $views_data = Views::viewsData()->get($this->storage->get('base_table'));
|
Chris@0
|
1175 $this->storage->set('base_field', !empty($views_data['table']['base']['field']) ? $views_data['table']['base']['field'] : '');
|
Chris@0
|
1176 if (!empty($views_data['table']['base']['database'])) {
|
Chris@0
|
1177 $this->base_database = $views_data['table']['base']['database'];
|
Chris@0
|
1178 }
|
Chris@0
|
1179
|
Chris@0
|
1180 $this->query = $this->display_handler->getPlugin('query');
|
Chris@0
|
1181 return TRUE;
|
Chris@0
|
1182 }
|
Chris@0
|
1183
|
Chris@0
|
1184 /**
|
Chris@0
|
1185 * Builds the query for the view.
|
Chris@0
|
1186 *
|
Chris@0
|
1187 * @param string $display_id
|
Chris@0
|
1188 * The display ID of the view.
|
Chris@0
|
1189 *
|
Chris@0
|
1190 * @return bool|null
|
Chris@0
|
1191 * TRUE if the view build process was successful, FALSE if setting the
|
Chris@0
|
1192 * display fails or NULL if the view has been built already.
|
Chris@0
|
1193 */
|
Chris@0
|
1194 public function build($display_id = NULL) {
|
Chris@0
|
1195 if (!empty($this->built)) {
|
Chris@0
|
1196 return;
|
Chris@0
|
1197 }
|
Chris@0
|
1198
|
Chris@0
|
1199 if (empty($this->current_display) || $display_id) {
|
Chris@0
|
1200 if (!$this->setDisplay($display_id)) {
|
Chris@0
|
1201 return FALSE;
|
Chris@0
|
1202 }
|
Chris@0
|
1203 }
|
Chris@0
|
1204
|
Chris@0
|
1205 // Let modules modify the view just prior to building it.
|
Chris@0
|
1206 $module_handler = \Drupal::moduleHandler();
|
Chris@0
|
1207 $module_handler->invokeAll('views_pre_build', [$this]);
|
Chris@0
|
1208
|
Chris@0
|
1209 // Attempt to load from cache.
|
Chris@0
|
1210 // @todo Load a build_info from cache.
|
Chris@0
|
1211
|
Chris@0
|
1212 $start = microtime(TRUE);
|
Chris@0
|
1213 // If that fails, let's build!
|
Chris@0
|
1214 $this->build_info = [
|
Chris@0
|
1215 'query' => '',
|
Chris@0
|
1216 'count_query' => '',
|
Chris@0
|
1217 'query_args' => [],
|
Chris@0
|
1218 ];
|
Chris@0
|
1219
|
Chris@0
|
1220 $this->initQuery();
|
Chris@0
|
1221
|
Chris@0
|
1222 // Call a module hook and see if it wants to present us with a
|
Chris@0
|
1223 // pre-built query or instruct us not to build the query for
|
Chris@0
|
1224 // some reason.
|
Chris@0
|
1225 // @todo: Implement this. Use the same mechanism Panels uses.
|
Chris@0
|
1226
|
Chris@0
|
1227 // Run through our handlers and ensure they have necessary information.
|
Chris@0
|
1228 $this->initHandlers();
|
Chris@0
|
1229
|
Chris@0
|
1230 // Let the handlers interact with each other if they really want.
|
Chris@0
|
1231 $this->_preQuery();
|
Chris@0
|
1232
|
Chris@0
|
1233 if ($this->display_handler->usesExposed()) {
|
Chris@0
|
1234 /** @var \Drupal\views\Plugin\views\exposed_form\ExposedFormPluginInterface $exposed_form */
|
Chris@0
|
1235 $exposed_form = $this->display_handler->getPlugin('exposed_form');
|
Chris@0
|
1236 $this->exposed_widgets = $exposed_form->renderExposedForm();
|
Chris@0
|
1237 if (!empty($this->build_info['abort'])) {
|
Chris@0
|
1238 $this->built = TRUE;
|
Chris@0
|
1239 // Don't execute the query, $form_state, but rendering will still be executed to display the empty text.
|
Chris@0
|
1240 $this->executed = TRUE;
|
Chris@0
|
1241 return empty($this->build_info['fail']);
|
Chris@0
|
1242 }
|
Chris@0
|
1243 }
|
Chris@0
|
1244
|
Chris@0
|
1245 // Build all the relationships first thing.
|
Chris@0
|
1246 $this->_build('relationship');
|
Chris@0
|
1247
|
Chris@0
|
1248 // Set the filtering groups.
|
Chris@0
|
1249 if (!empty($this->filter)) {
|
Chris@0
|
1250 $filter_groups = $this->display_handler->getOption('filter_groups');
|
Chris@0
|
1251 if ($filter_groups) {
|
Chris@0
|
1252 $this->query->setGroupOperator($filter_groups['operator']);
|
Chris@0
|
1253 foreach ($filter_groups['groups'] as $id => $operator) {
|
Chris@0
|
1254 $this->query->setWhereGroup($operator, $id);
|
Chris@0
|
1255 }
|
Chris@0
|
1256 }
|
Chris@0
|
1257 }
|
Chris@0
|
1258
|
Chris@0
|
1259 // Build all the filters.
|
Chris@0
|
1260 $this->_build('filter');
|
Chris@0
|
1261
|
Chris@0
|
1262 $this->build_sort = TRUE;
|
Chris@0
|
1263
|
Chris@0
|
1264 // Arguments can, in fact, cause this whole thing to abort.
|
Chris@0
|
1265 if (!$this->_buildArguments()) {
|
Chris@0
|
1266 $this->build_time = microtime(TRUE) - $start;
|
Chris@0
|
1267 $this->attachDisplays();
|
Chris@0
|
1268 return $this->built;
|
Chris@0
|
1269 }
|
Chris@0
|
1270
|
Chris@0
|
1271 // Initialize the style; arguments may have changed which style we use,
|
Chris@0
|
1272 // so waiting as long as possible is important. But we need to know
|
Chris@0
|
1273 // about the style when we go to build fields.
|
Chris@0
|
1274 if (!$this->initStyle()) {
|
Chris@0
|
1275 $this->build_info['fail'] = TRUE;
|
Chris@0
|
1276 return FALSE;
|
Chris@0
|
1277 }
|
Chris@0
|
1278
|
Chris@0
|
1279 if ($this->style_plugin->usesFields()) {
|
Chris@0
|
1280 $this->_build('field');
|
Chris@0
|
1281 }
|
Chris@0
|
1282
|
Chris@0
|
1283 // Build our sort criteria if we were instructed to do so.
|
Chris@0
|
1284 if (!empty($this->build_sort)) {
|
Chris@0
|
1285 // Allow the style handler to deal with sorting.
|
Chris@0
|
1286 if ($this->style_plugin->buildSort()) {
|
Chris@0
|
1287 $this->_build('sort');
|
Chris@0
|
1288 }
|
Chris@0
|
1289 // allow the plugin to build second sorts as well.
|
Chris@0
|
1290 $this->style_plugin->buildSortPost();
|
Chris@0
|
1291 }
|
Chris@0
|
1292
|
Chris@0
|
1293 // Allow area handlers to affect the query.
|
Chris@0
|
1294 $this->_build('header');
|
Chris@0
|
1295 $this->_build('footer');
|
Chris@0
|
1296 $this->_build('empty');
|
Chris@0
|
1297
|
Chris@0
|
1298 // Allow display handler to affect the query:
|
Chris@0
|
1299 $this->display_handler->query($this->display_handler->useGroupBy());
|
Chris@0
|
1300
|
Chris@0
|
1301 // Allow style handler to affect the query:
|
Chris@0
|
1302 $this->style_plugin->query($this->display_handler->useGroupBy());
|
Chris@0
|
1303
|
Chris@0
|
1304 // Allow exposed form to affect the query:
|
Chris@0
|
1305 if (isset($exposed_form)) {
|
Chris@0
|
1306 $exposed_form->query();
|
Chris@0
|
1307 }
|
Chris@0
|
1308
|
Chris@0
|
1309 if (\Drupal::config('views.settings')->get('sql_signature')) {
|
Chris@0
|
1310 $this->query->addSignature($this);
|
Chris@0
|
1311 }
|
Chris@0
|
1312
|
Chris@0
|
1313 // Let modules modify the query just prior to finalizing it.
|
Chris@0
|
1314 $this->query->alter($this);
|
Chris@0
|
1315
|
Chris@0
|
1316 // Only build the query if we weren't interrupted.
|
Chris@0
|
1317 if (empty($this->built)) {
|
Chris@0
|
1318 // Build the necessary info to execute the query.
|
Chris@0
|
1319 $this->query->build($this);
|
Chris@0
|
1320 }
|
Chris@0
|
1321
|
Chris@0
|
1322 $this->built = TRUE;
|
Chris@0
|
1323 $this->build_time = microtime(TRUE) - $start;
|
Chris@0
|
1324
|
Chris@0
|
1325 // Attach displays
|
Chris@0
|
1326 $this->attachDisplays();
|
Chris@0
|
1327
|
Chris@0
|
1328 // Let modules modify the view just after building it.
|
Chris@0
|
1329 $module_handler->invokeAll('views_post_build', [$this]);
|
Chris@0
|
1330
|
Chris@0
|
1331 return TRUE;
|
Chris@0
|
1332 }
|
Chris@0
|
1333
|
Chris@0
|
1334 /**
|
Chris@0
|
1335 * Builds an individual set of handlers.
|
Chris@0
|
1336 *
|
Chris@0
|
1337 * This is an internal method.
|
Chris@0
|
1338 *
|
Chris@0
|
1339 * @todo Some filter needs this function, even it is internal.
|
Chris@0
|
1340 *
|
Chris@0
|
1341 * @param string $key
|
Chris@0
|
1342 * The type of handlers (filter etc.) which should be iterated over to build
|
Chris@0
|
1343 * the relationship and query information.
|
Chris@0
|
1344 */
|
Chris@0
|
1345 public function _build($key) {
|
Chris@0
|
1346 $handlers = &$this->$key;
|
Chris@0
|
1347 foreach ($handlers as $id => $data) {
|
Chris@0
|
1348
|
Chris@0
|
1349 if (!empty($handlers[$id]) && is_object($handlers[$id])) {
|
Chris@0
|
1350 $multiple_exposed_input = [0 => NULL];
|
Chris@0
|
1351 if ($handlers[$id]->multipleExposedInput()) {
|
Chris@0
|
1352 $multiple_exposed_input = $handlers[$id]->groupMultipleExposedInput($this->exposed_data);
|
Chris@0
|
1353 }
|
Chris@0
|
1354 foreach ($multiple_exposed_input as $group_id) {
|
Chris@0
|
1355 // Give this handler access to the exposed filter input.
|
Chris@0
|
1356 if (!empty($this->exposed_data)) {
|
Chris@0
|
1357 if ($handlers[$id]->isAGroup()) {
|
Chris@0
|
1358 $converted = $handlers[$id]->convertExposedInput($this->exposed_data, $group_id);
|
Chris@0
|
1359 $handlers[$id]->storeGroupInput($this->exposed_data, $converted);
|
Chris@0
|
1360 if (!$converted) {
|
Chris@0
|
1361 continue;
|
Chris@0
|
1362 }
|
Chris@0
|
1363 }
|
Chris@0
|
1364 $rc = $handlers[$id]->acceptExposedInput($this->exposed_data);
|
Chris@0
|
1365 $handlers[$id]->storeExposedInput($this->exposed_data, $rc);
|
Chris@0
|
1366 if (!$rc) {
|
Chris@0
|
1367 continue;
|
Chris@0
|
1368 }
|
Chris@0
|
1369 }
|
Chris@0
|
1370 $handlers[$id]->setRelationship();
|
Chris@0
|
1371 $handlers[$id]->query($this->display_handler->useGroupBy());
|
Chris@0
|
1372 }
|
Chris@0
|
1373 }
|
Chris@0
|
1374 }
|
Chris@0
|
1375 }
|
Chris@0
|
1376
|
Chris@0
|
1377 /**
|
Chris@0
|
1378 * Executes the view's query.
|
Chris@0
|
1379 *
|
Chris@0
|
1380 * @param string $display_id
|
Chris@0
|
1381 * The machine name of the display, which should be executed.
|
Chris@0
|
1382 *
|
Chris@0
|
1383 * @return bool
|
Chris@0
|
1384 * TRUE if the view execution was successful, FALSE otherwise. For example,
|
Chris@0
|
1385 * an argument could stop the process.
|
Chris@0
|
1386 */
|
Chris@0
|
1387 public function execute($display_id = NULL) {
|
Chris@0
|
1388 if (empty($this->built)) {
|
Chris@0
|
1389 if (!$this->build($display_id)) {
|
Chris@0
|
1390 return FALSE;
|
Chris@0
|
1391 }
|
Chris@0
|
1392 }
|
Chris@0
|
1393
|
Chris@0
|
1394 if (!empty($this->executed)) {
|
Chris@0
|
1395 return TRUE;
|
Chris@0
|
1396 }
|
Chris@0
|
1397
|
Chris@0
|
1398 // Don't allow to use deactivated displays, but display them on the live preview.
|
Chris@0
|
1399 if (!$this->display_handler->isEnabled() && empty($this->live_preview)) {
|
Chris@0
|
1400 $this->build_info['fail'] = TRUE;
|
Chris@0
|
1401 return FALSE;
|
Chris@0
|
1402 }
|
Chris@0
|
1403
|
Chris@0
|
1404 // Let modules modify the view just prior to executing it.
|
Chris@0
|
1405 $module_handler = \Drupal::moduleHandler();
|
Chris@0
|
1406 $module_handler->invokeAll('views_pre_execute', [$this]);
|
Chris@0
|
1407
|
Chris@0
|
1408 // Check for already-cached results.
|
Chris@0
|
1409 /** @var \Drupal\views\Plugin\views\cache\CachePluginBase $cache */
|
Chris@0
|
1410 if (!empty($this->live_preview)) {
|
Chris@0
|
1411 $cache = Views::pluginManager('cache')->createInstance('none');
|
Chris@0
|
1412 }
|
Chris@0
|
1413 else {
|
Chris@0
|
1414 $cache = $this->display_handler->getPlugin('cache');
|
Chris@0
|
1415 }
|
Chris@0
|
1416
|
Chris@0
|
1417 if ($cache->cacheGet('results')) {
|
Chris@0
|
1418 if ($this->pager->usePager()) {
|
Chris@0
|
1419 $this->pager->total_items = $this->total_rows;
|
Chris@0
|
1420 $this->pager->updatePageInfo();
|
Chris@0
|
1421 }
|
Chris@0
|
1422 }
|
Chris@0
|
1423 else {
|
Chris@0
|
1424 $this->query->execute($this);
|
Chris@0
|
1425 // Enforce the array key rule as documented in
|
Chris@0
|
1426 // views_plugin_query::execute().
|
Chris@0
|
1427 $this->result = array_values($this->result);
|
Chris@0
|
1428 $this->_postExecute();
|
Chris@0
|
1429 $cache->cacheSet('results');
|
Chris@0
|
1430 }
|
Chris@0
|
1431
|
Chris@0
|
1432 // Let modules modify the view just after executing it.
|
Chris@0
|
1433 $module_handler->invokeAll('views_post_execute', [$this]);
|
Chris@0
|
1434
|
Chris@0
|
1435 return $this->executed = TRUE;
|
Chris@0
|
1436 }
|
Chris@0
|
1437
|
Chris@0
|
1438 /**
|
Chris@0
|
1439 * Renders this view for a certain display.
|
Chris@0
|
1440 *
|
Chris@0
|
1441 * Note: You should better use just the preview function if you want to
|
Chris@0
|
1442 * render a view.
|
Chris@0
|
1443 *
|
Chris@0
|
1444 * @param string $display_id
|
Chris@0
|
1445 * The machine name of the display, which should be rendered.
|
Chris@0
|
1446 *
|
Chris@0
|
1447 * @return array|null
|
Chris@0
|
1448 * A renderable array containing the view output or NULL if the build
|
Chris@0
|
1449 * process failed.
|
Chris@0
|
1450 */
|
Chris@0
|
1451 public function render($display_id = NULL) {
|
Chris@0
|
1452 $this->execute($display_id);
|
Chris@0
|
1453
|
Chris@0
|
1454 // Check to see if the build failed.
|
Chris@0
|
1455 if (!empty($this->build_info['fail'])) {
|
Chris@0
|
1456 return;
|
Chris@0
|
1457 }
|
Chris@0
|
1458 if (!empty($this->build_info['denied'])) {
|
Chris@0
|
1459 return;
|
Chris@0
|
1460 }
|
Chris@0
|
1461
|
Chris@0
|
1462 /** @var \Drupal\views\Plugin\views\exposed_form\ExposedFormPluginInterface $exposed_form */
|
Chris@0
|
1463 $exposed_form = $this->display_handler->getPlugin('exposed_form');
|
Chris@0
|
1464 $exposed_form->preRender($this->result);
|
Chris@0
|
1465
|
Chris@0
|
1466 $module_handler = \Drupal::moduleHandler();
|
Chris@0
|
1467
|
Chris@0
|
1468 // @TODO In the longrun, it would be great to execute a view without
|
Chris@0
|
1469 // the theme system at all. See https://www.drupal.org/node/2322623.
|
Chris@0
|
1470 $active_theme = \Drupal::theme()->getActiveTheme();
|
Chris@0
|
1471 $themes = array_keys($active_theme->getBaseThemes());
|
Chris@0
|
1472 $themes[] = $active_theme->getName();
|
Chris@0
|
1473
|
Chris@0
|
1474 // Check for already-cached output.
|
Chris@0
|
1475 /** @var \Drupal\views\Plugin\views\cache\CachePluginBase $cache */
|
Chris@0
|
1476 if (!empty($this->live_preview)) {
|
Chris@0
|
1477 $cache = Views::pluginManager('cache')->createInstance('none');
|
Chris@0
|
1478 }
|
Chris@0
|
1479 else {
|
Chris@0
|
1480 $cache = $this->display_handler->getPlugin('cache');
|
Chris@0
|
1481 }
|
Chris@0
|
1482
|
Chris@0
|
1483 // Run preRender for the pager as it might change the result.
|
Chris@0
|
1484 if (!empty($this->pager)) {
|
Chris@0
|
1485 $this->pager->preRender($this->result);
|
Chris@0
|
1486 }
|
Chris@0
|
1487
|
Chris@0
|
1488 // Initialize the style plugin.
|
Chris@0
|
1489 $this->initStyle();
|
Chris@0
|
1490
|
Chris@0
|
1491 if (!isset($this->response)) {
|
Chris@0
|
1492 // Set the response so other parts can alter it.
|
Chris@0
|
1493 $this->response = new Response('', 200);
|
Chris@0
|
1494 }
|
Chris@0
|
1495
|
Chris@0
|
1496 // Give field handlers the opportunity to perform additional queries
|
Chris@0
|
1497 // using the entire resultset prior to rendering.
|
Chris@0
|
1498 if ($this->style_plugin->usesFields()) {
|
Chris@0
|
1499 foreach ($this->field as $id => $handler) {
|
Chris@0
|
1500 if (!empty($this->field[$id])) {
|
Chris@0
|
1501 $this->field[$id]->preRender($this->result);
|
Chris@0
|
1502 }
|
Chris@0
|
1503 }
|
Chris@0
|
1504 }
|
Chris@0
|
1505
|
Chris@0
|
1506 $this->style_plugin->preRender($this->result);
|
Chris@0
|
1507
|
Chris@0
|
1508 // Let each area handler have access to the result set.
|
Chris@0
|
1509 $areas = ['header', 'footer'];
|
Chris@0
|
1510 // Only call preRender() on the empty handlers if the result is empty.
|
Chris@0
|
1511 if (empty($this->result)) {
|
Chris@0
|
1512 $areas[] = 'empty';
|
Chris@0
|
1513 }
|
Chris@0
|
1514 foreach ($areas as $area) {
|
Chris@0
|
1515 foreach ($this->{$area} as $handler) {
|
Chris@0
|
1516 $handler->preRender($this->result);
|
Chris@0
|
1517 }
|
Chris@0
|
1518 }
|
Chris@0
|
1519
|
Chris@0
|
1520 // Let modules modify the view just prior to rendering it.
|
Chris@0
|
1521 $module_handler->invokeAll('views_pre_render', [$this]);
|
Chris@0
|
1522
|
Chris@0
|
1523 // Let the themes play too, because pre render is a very themey thing.
|
Chris@0
|
1524 foreach ($themes as $theme_name) {
|
Chris@0
|
1525 $function = $theme_name . '_views_pre_render';
|
Chris@0
|
1526 if (function_exists($function)) {
|
Chris@0
|
1527 $function($this);
|
Chris@0
|
1528 }
|
Chris@0
|
1529 }
|
Chris@0
|
1530
|
Chris@0
|
1531 $this->display_handler->output = $this->display_handler->render();
|
Chris@0
|
1532
|
Chris@0
|
1533 $exposed_form->postRender($this->display_handler->output);
|
Chris@0
|
1534
|
Chris@0
|
1535 $cache->postRender($this->display_handler->output);
|
Chris@0
|
1536
|
Chris@0
|
1537 // Let modules modify the view output after it is rendered.
|
Chris@0
|
1538 $module_handler->invokeAll('views_post_render', [$this, &$this->display_handler->output, $cache]);
|
Chris@0
|
1539
|
Chris@0
|
1540 // Let the themes play too, because post render is a very themey thing.
|
Chris@0
|
1541 foreach ($themes as $theme_name) {
|
Chris@0
|
1542 $function = $theme_name . '_views_post_render';
|
Chris@0
|
1543 if (function_exists($function)) {
|
Chris@0
|
1544 $function($this, $this->display_handler->output, $cache);
|
Chris@0
|
1545 }
|
Chris@0
|
1546 }
|
Chris@0
|
1547
|
Chris@0
|
1548 return $this->display_handler->output;
|
Chris@0
|
1549 }
|
Chris@0
|
1550
|
Chris@0
|
1551 /**
|
Chris@0
|
1552 * Gets the cache tags associated with the executed view.
|
Chris@0
|
1553 *
|
Chris@0
|
1554 * Note: The cache plugin controls the used tags, so you can override it, if
|
Chris@0
|
1555 * needed.
|
Chris@0
|
1556 *
|
Chris@0
|
1557 * @return string[]
|
Chris@0
|
1558 * An array of cache tags.
|
Chris@0
|
1559 */
|
Chris@0
|
1560 public function getCacheTags() {
|
Chris@0
|
1561 $this->initDisplay();
|
Chris@0
|
1562 /** @var \Drupal\views\Plugin\views\cache\CachePluginBase $cache */
|
Chris@0
|
1563 $cache = $this->display_handler->getPlugin('cache');
|
Chris@0
|
1564 return $cache->getCacheTags();
|
Chris@0
|
1565 }
|
Chris@0
|
1566
|
Chris@0
|
1567 /**
|
Chris@0
|
1568 * Builds the render array outline for the given display.
|
Chris@0
|
1569 *
|
Chris@0
|
1570 * This render array has a #pre_render callback which will call
|
Chris@0
|
1571 * ::executeDisplay in order to actually execute the view and then build the
|
Chris@0
|
1572 * final render array structure.
|
Chris@0
|
1573 *
|
Chris@0
|
1574 * @param string $display_id
|
Chris@0
|
1575 * The display ID.
|
Chris@0
|
1576 * @param array $args
|
Chris@0
|
1577 * An array of arguments passed along to the view.
|
Chris@0
|
1578 * @param bool $cache
|
Chris@0
|
1579 * (optional) Should the result be render cached.
|
Chris@0
|
1580 *
|
Chris@0
|
1581 * @return array|null
|
Chris@0
|
1582 * A renderable array with #type 'view' or NULL if the display ID was
|
Chris@0
|
1583 * invalid.
|
Chris@0
|
1584 */
|
Chris@0
|
1585 public function buildRenderable($display_id = NULL, $args = [], $cache = TRUE) {
|
Chris@0
|
1586 // @todo Extract that into a generic method.
|
Chris@0
|
1587 if (empty($this->current_display) || $this->current_display != $this->chooseDisplay($display_id)) {
|
Chris@0
|
1588 if (!$this->setDisplay($display_id)) {
|
Chris@0
|
1589 return NULL;
|
Chris@0
|
1590 }
|
Chris@0
|
1591 }
|
Chris@0
|
1592
|
Chris@0
|
1593 return $this->display_handler->buildRenderable($args, $cache);
|
Chris@0
|
1594 }
|
Chris@0
|
1595
|
Chris@0
|
1596 /**
|
Chris@0
|
1597 * Executes the given display, with the given arguments.
|
Chris@0
|
1598 *
|
Chris@0
|
1599 * To be called externally by whatever mechanism invokes the view,
|
Chris@0
|
1600 * such as a page callback, hook_block, etc.
|
Chris@0
|
1601 *
|
Chris@0
|
1602 * This function should NOT be used by anything external as this
|
Chris@0
|
1603 * returns data in the format specified by the display. It can also
|
Chris@0
|
1604 * have other side effects that are only intended for the 'proper'
|
Chris@0
|
1605 * use of the display, such as setting page titles.
|
Chris@0
|
1606 *
|
Chris@0
|
1607 * If you simply want to view the display, use View::preview() instead.
|
Chris@0
|
1608 *
|
Chris@0
|
1609 * @param string $display_id
|
Chris@0
|
1610 * The display ID of the view to be executed.
|
Chris@0
|
1611 * @param string[] $args
|
Chris@0
|
1612 * The arguments to be passed to the view.
|
Chris@0
|
1613 *
|
Chris@0
|
1614 * @return array|null
|
Chris@0
|
1615 * A renderable array containing the view output or NULL if the display ID
|
Chris@0
|
1616 * of the view to be executed doesn't exist.
|
Chris@0
|
1617 */
|
Chris@0
|
1618 public function executeDisplay($display_id = NULL, $args = []) {
|
Chris@0
|
1619 if (empty($this->current_display) || $this->current_display != $this->chooseDisplay($display_id)) {
|
Chris@0
|
1620 if (!$this->setDisplay($display_id)) {
|
Chris@0
|
1621 return NULL;
|
Chris@0
|
1622 }
|
Chris@0
|
1623 }
|
Chris@0
|
1624
|
Chris@0
|
1625 $this->preExecute($args);
|
Chris@0
|
1626
|
Chris@0
|
1627 // Execute the view
|
Chris@0
|
1628 $output = $this->display_handler->execute();
|
Chris@0
|
1629
|
Chris@0
|
1630 $this->postExecute();
|
Chris@0
|
1631 return $output;
|
Chris@0
|
1632 }
|
Chris@0
|
1633
|
Chris@0
|
1634 /**
|
Chris@0
|
1635 * Previews the given display, with the given arguments.
|
Chris@0
|
1636 *
|
Chris@0
|
1637 * To be called externally, probably by an AJAX handler of some flavor.
|
Chris@0
|
1638 * Can also be called when views are embedded, as this guarantees
|
Chris@0
|
1639 * normalized output.
|
Chris@0
|
1640 *
|
Chris@0
|
1641 * This function does not do any access checks on the view. It is the
|
Chris@0
|
1642 * responsibility of the caller to check $view->access() or implement other
|
Chris@0
|
1643 * access logic. To render the view normally with access checks, use
|
Chris@0
|
1644 * views_embed_view() instead.
|
Chris@0
|
1645 *
|
Chris@0
|
1646 * @return array|null
|
Chris@0
|
1647 * A renderable array containing the view output or NULL if the display ID
|
Chris@0
|
1648 * of the view to be executed doesn't exist.
|
Chris@0
|
1649 */
|
Chris@0
|
1650 public function preview($display_id = NULL, $args = []) {
|
Chris@0
|
1651 if (empty($this->current_display) || ((!empty($display_id)) && $this->current_display != $display_id)) {
|
Chris@0
|
1652 if (!$this->setDisplay($display_id)) {
|
Chris@0
|
1653 return FALSE;
|
Chris@0
|
1654 }
|
Chris@0
|
1655 }
|
Chris@0
|
1656
|
Chris@0
|
1657 $this->preview = TRUE;
|
Chris@0
|
1658 $this->preExecute($args);
|
Chris@0
|
1659 // Preview the view.
|
Chris@0
|
1660 $output = $this->display_handler->preview();
|
Chris@0
|
1661
|
Chris@0
|
1662 $this->postExecute();
|
Chris@0
|
1663 return $output;
|
Chris@0
|
1664 }
|
Chris@0
|
1665
|
Chris@0
|
1666 /**
|
Chris@0
|
1667 * Runs attachments and lets the display do what it needs to before running.
|
Chris@0
|
1668 *
|
Chris@0
|
1669 * @param array $args
|
Chris@0
|
1670 * An array of arguments from the URL that can be used by the view.
|
Chris@0
|
1671 */
|
Chris@0
|
1672 public function preExecute($args = []) {
|
Chris@0
|
1673 $this->old_view[] = views_get_current_view();
|
Chris@0
|
1674 views_set_current_view($this);
|
Chris@0
|
1675 $display_id = $this->current_display;
|
Chris@0
|
1676
|
Chris@0
|
1677 // Prepare the view with the information we have, but only if we were
|
Chris@0
|
1678 // passed arguments, as they may have been set previously.
|
Chris@0
|
1679 if ($args) {
|
Chris@0
|
1680 $this->setArguments($args);
|
Chris@0
|
1681 }
|
Chris@0
|
1682
|
Chris@0
|
1683 // Let modules modify the view just prior to executing it.
|
Chris@0
|
1684 \Drupal::moduleHandler()->invokeAll('views_pre_view', [$this, $display_id, &$this->args]);
|
Chris@0
|
1685
|
Chris@0
|
1686 // Allow hook_views_pre_view() to set the dom_id, then ensure it is set.
|
Chris@0
|
1687 $this->dom_id = !empty($this->dom_id) ? $this->dom_id : hash('sha256', $this->storage->id() . REQUEST_TIME . mt_rand());
|
Chris@0
|
1688
|
Chris@0
|
1689 // Allow the display handler to set up for execution
|
Chris@0
|
1690 $this->display_handler->preExecute();
|
Chris@0
|
1691 }
|
Chris@0
|
1692
|
Chris@0
|
1693 /**
|
Chris@0
|
1694 * Unsets the current view, mostly.
|
Chris@0
|
1695 */
|
Chris@0
|
1696 public function postExecute() {
|
Chris@0
|
1697 // unset current view so we can be properly destructed later on.
|
Chris@0
|
1698 // Return the previous value in case we're an attachment.
|
Chris@0
|
1699
|
Chris@0
|
1700 if ($this->old_view) {
|
Chris@0
|
1701 $old_view = array_pop($this->old_view);
|
Chris@0
|
1702 }
|
Chris@0
|
1703
|
Chris@0
|
1704 views_set_current_view(isset($old_view) ? $old_view : FALSE);
|
Chris@0
|
1705 }
|
Chris@0
|
1706
|
Chris@0
|
1707 /**
|
Chris@0
|
1708 * Runs attachment displays for the view.
|
Chris@0
|
1709 */
|
Chris@0
|
1710 public function attachDisplays() {
|
Chris@0
|
1711 if (!empty($this->is_attachment)) {
|
Chris@0
|
1712 return;
|
Chris@0
|
1713 }
|
Chris@0
|
1714
|
Chris@0
|
1715 if (!$this->display_handler->acceptAttachments()) {
|
Chris@0
|
1716 return;
|
Chris@0
|
1717 }
|
Chris@0
|
1718
|
Chris@0
|
1719 $this->is_attachment = TRUE;
|
Chris@0
|
1720 // Find out which other displays attach to the current one.
|
Chris@0
|
1721 foreach ($this->display_handler->getAttachedDisplays() as $id) {
|
Chris@0
|
1722 $display_handler = $this->displayHandlers->get($id);
|
Chris@0
|
1723 // Only attach enabled attachments.
|
Chris@0
|
1724 if ($display_handler->isEnabled()) {
|
Chris@0
|
1725 $cloned_view = Views::executableFactory()->get($this->storage);
|
Chris@0
|
1726 $display_handler->attachTo($cloned_view, $this->current_display, $this->element);
|
Chris@0
|
1727 }
|
Chris@0
|
1728 }
|
Chris@0
|
1729 $this->is_attachment = FALSE;
|
Chris@0
|
1730 }
|
Chris@0
|
1731
|
Chris@0
|
1732 /**
|
Chris@0
|
1733 * Determines if the given user has access to the view.
|
Chris@0
|
1734 *
|
Chris@0
|
1735 * Note that this sets the display handler if it hasn't been set.
|
Chris@0
|
1736 *
|
Chris@0
|
1737 * @param string $displays
|
Chris@0
|
1738 * The machine name of the display.
|
Chris@0
|
1739 * @param \Drupal\Core\Session\AccountInterface $account
|
Chris@0
|
1740 * The user object.
|
Chris@0
|
1741 *
|
Chris@0
|
1742 * @return bool
|
Chris@0
|
1743 * TRUE if the user has access to the view, FALSE otherwise.
|
Chris@0
|
1744 */
|
Chris@0
|
1745 public function access($displays = NULL, $account = NULL) {
|
Chris@0
|
1746 // No one should have access to disabled views.
|
Chris@0
|
1747 if (!$this->storage->status()) {
|
Chris@0
|
1748 return FALSE;
|
Chris@0
|
1749 }
|
Chris@0
|
1750
|
Chris@0
|
1751 if (!isset($this->current_display)) {
|
Chris@0
|
1752 $this->initDisplay();
|
Chris@0
|
1753 }
|
Chris@0
|
1754
|
Chris@0
|
1755 if (!$account) {
|
Chris@0
|
1756 $account = $this->user;
|
Chris@0
|
1757 }
|
Chris@0
|
1758
|
Chris@0
|
1759 // We can't use choose_display() here because that function
|
Chris@0
|
1760 // calls this one.
|
Chris@0
|
1761 $displays = (array) $displays;
|
Chris@0
|
1762 foreach ($displays as $display_id) {
|
Chris@0
|
1763 if ($this->displayHandlers->has($display_id)) {
|
Chris@0
|
1764 if (($display = $this->displayHandlers->get($display_id)) && $display->access($account)) {
|
Chris@0
|
1765 return TRUE;
|
Chris@0
|
1766 }
|
Chris@0
|
1767 }
|
Chris@0
|
1768 }
|
Chris@0
|
1769
|
Chris@0
|
1770 return FALSE;
|
Chris@0
|
1771 }
|
Chris@0
|
1772
|
Chris@0
|
1773 /**
|
Chris@0
|
1774 * Sets the used response object of the view.
|
Chris@0
|
1775 *
|
Chris@0
|
1776 * @param \Symfony\Component\HttpFoundation\Response $response
|
Chris@0
|
1777 * The response object which should be set.
|
Chris@0
|
1778 */
|
Chris@0
|
1779 public function setResponse(Response $response) {
|
Chris@0
|
1780 $this->response = $response;
|
Chris@0
|
1781 }
|
Chris@0
|
1782
|
Chris@0
|
1783 /**
|
Chris@0
|
1784 * Gets the response object used by the view.
|
Chris@0
|
1785 *
|
Chris@0
|
1786 * @return \Symfony\Component\HttpFoundation\Response
|
Chris@0
|
1787 * The response object of the view.
|
Chris@0
|
1788 */
|
Chris@0
|
1789 public function getResponse() {
|
Chris@0
|
1790 if (!isset($this->response)) {
|
Chris@0
|
1791 $this->response = new Response();
|
Chris@0
|
1792 }
|
Chris@0
|
1793 return $this->response;
|
Chris@0
|
1794 }
|
Chris@0
|
1795
|
Chris@0
|
1796 /**
|
Chris@0
|
1797 * Sets the request object.
|
Chris@0
|
1798 *
|
Chris@0
|
1799 * @param \Symfony\Component\HttpFoundation\Request $request
|
Chris@0
|
1800 * The request object.
|
Chris@0
|
1801 */
|
Chris@0
|
1802 public function setRequest(Request $request) {
|
Chris@0
|
1803 $this->request = $request;
|
Chris@0
|
1804 }
|
Chris@0
|
1805
|
Chris@0
|
1806 /**
|
Chris@0
|
1807 * Gets the request object.
|
Chris@0
|
1808 *
|
Chris@0
|
1809 * @return \Symfony\Component\HttpFoundation\Request
|
Chris@0
|
1810 * The request object.
|
Chris@0
|
1811 */
|
Chris@0
|
1812 public function getRequest() {
|
Chris@0
|
1813 return $this->request;
|
Chris@0
|
1814 }
|
Chris@0
|
1815
|
Chris@0
|
1816 /**
|
Chris@0
|
1817 * Gets the view's current title.
|
Chris@0
|
1818 *
|
Chris@0
|
1819 * This can change depending upon how it was built.
|
Chris@0
|
1820 *
|
Chris@0
|
1821 * @return string|false
|
Chris@0
|
1822 * The view title, FALSE if the display is not set.
|
Chris@0
|
1823 */
|
Chris@0
|
1824 public function getTitle() {
|
Chris@0
|
1825 if (empty($this->display_handler)) {
|
Chris@0
|
1826 if (!$this->setDisplay('default')) {
|
Chris@0
|
1827 return FALSE;
|
Chris@0
|
1828 }
|
Chris@0
|
1829 }
|
Chris@0
|
1830
|
Chris@0
|
1831 // During building, we might find a title override. If so, use it.
|
Chris@0
|
1832 if (!empty($this->build_info['title'])) {
|
Chris@0
|
1833 $title = $this->build_info['title'];
|
Chris@0
|
1834 }
|
Chris@0
|
1835 else {
|
Chris@0
|
1836 $title = $this->display_handler->getOption('title');
|
Chris@0
|
1837 }
|
Chris@0
|
1838
|
Chris@0
|
1839 // Allow substitutions from the first row.
|
Chris@0
|
1840 if ($this->initStyle()) {
|
Chris@0
|
1841 $title = $this->style_plugin->tokenizeValue($title, 0);
|
Chris@0
|
1842 }
|
Chris@0
|
1843 return $title;
|
Chris@0
|
1844 }
|
Chris@0
|
1845
|
Chris@0
|
1846 /**
|
Chris@0
|
1847 * Overrides the view's current title.
|
Chris@0
|
1848 *
|
Chris@0
|
1849 * The tokens in the title get's replaced before rendering.
|
Chris@0
|
1850 *
|
Chris@0
|
1851 * @return true
|
Chris@0
|
1852 * Always returns TRUE.
|
Chris@0
|
1853 */
|
Chris@0
|
1854 public function setTitle($title) {
|
Chris@0
|
1855 $this->build_info['title'] = $title;
|
Chris@0
|
1856 return TRUE;
|
Chris@0
|
1857 }
|
Chris@0
|
1858
|
Chris@0
|
1859 /**
|
Chris@0
|
1860 * Forces the view to build a title.
|
Chris@0
|
1861 */
|
Chris@0
|
1862 public function buildTitle() {
|
Chris@0
|
1863 $this->initDisplay();
|
Chris@0
|
1864
|
Chris@0
|
1865 if (empty($this->built)) {
|
Chris@0
|
1866 $this->initQuery();
|
Chris@0
|
1867 }
|
Chris@0
|
1868
|
Chris@0
|
1869 $this->initHandlers();
|
Chris@0
|
1870
|
Chris@0
|
1871 $this->_buildArguments();
|
Chris@0
|
1872 }
|
Chris@0
|
1873
|
Chris@0
|
1874 /**
|
Chris@0
|
1875 * Determines whether you can link to the view or a particular display.
|
Chris@0
|
1876 *
|
Chris@0
|
1877 * Some displays (e.g. block displays) do not have their own route, but may
|
Chris@0
|
1878 * optionally provide a link to another display that does have a route.
|
Chris@0
|
1879 *
|
Chris@0
|
1880 * @param array $args
|
Chris@0
|
1881 * (optional) The arguments.
|
Chris@0
|
1882 * @param string $display_id
|
Chris@0
|
1883 * (optional) The display ID. The current display will be used by default.
|
Chris@0
|
1884 *
|
Chris@0
|
1885 * @return bool
|
Chris@0
|
1886 * TRUE if the current display has a valid route available, FALSE otherwise.
|
Chris@0
|
1887 */
|
Chris@0
|
1888 public function hasUrl($args = NULL, $display_id = NULL) {
|
Chris@0
|
1889 if (!empty($this->override_url)) {
|
Chris@0
|
1890 return TRUE;
|
Chris@0
|
1891 }
|
Chris@0
|
1892
|
Chris@0
|
1893 // If the display has a valid route available (either its own or for a
|
Chris@0
|
1894 // linked display), then we can provide a URL for it.
|
Chris@0
|
1895 $display_handler = $this->displayHandlers->get($display_id ?: $this->current_display)->getRoutedDisplay();
|
Chris@0
|
1896 if (!$display_handler instanceof DisplayRouterInterface) {
|
Chris@0
|
1897 return FALSE;
|
Chris@0
|
1898 }
|
Chris@0
|
1899
|
Chris@0
|
1900 // Look up the route name to make sure it exists. The name may exist, but
|
Chris@0
|
1901 // not be available yet in some instances when editing a view and doing
|
Chris@0
|
1902 // a live preview.
|
Chris@0
|
1903 $provider = \Drupal::service('router.route_provider');
|
Chris@0
|
1904 try {
|
Chris@0
|
1905 $provider->getRouteByName($display_handler->getRouteName());
|
Chris@0
|
1906 }
|
Chris@0
|
1907 catch (RouteNotFoundException $e) {
|
Chris@0
|
1908 return FALSE;
|
Chris@0
|
1909 }
|
Chris@0
|
1910
|
Chris@0
|
1911 return TRUE;
|
Chris@0
|
1912 }
|
Chris@0
|
1913
|
Chris@0
|
1914 /**
|
Chris@0
|
1915 * Gets the URL for the current view.
|
Chris@0
|
1916 *
|
Chris@0
|
1917 * This URL will be adjusted for arguments.
|
Chris@0
|
1918 *
|
Chris@0
|
1919 * @param array $args
|
Chris@0
|
1920 * (optional) Passed in arguments.
|
Chris@0
|
1921 * @param string $display_id
|
Chris@0
|
1922 * (optional) Specify the display ID to link to, fallback to the current ID.
|
Chris@0
|
1923 *
|
Chris@0
|
1924 * @return \Drupal\Core\Url
|
Chris@0
|
1925 * The URL of the current view.
|
Chris@0
|
1926 *
|
Chris@0
|
1927 * @throws \InvalidArgumentException
|
Chris@0
|
1928 * Thrown when the current view doesn't have a route available.
|
Chris@0
|
1929 */
|
Chris@0
|
1930 public function getUrl($args = NULL, $display_id = NULL) {
|
Chris@0
|
1931 if (!empty($this->override_url)) {
|
Chris@0
|
1932 return $this->override_url;
|
Chris@0
|
1933 }
|
Chris@0
|
1934
|
Chris@0
|
1935 $display_handler = $this->displayHandlers->get($display_id ?: $this->current_display)->getRoutedDisplay();
|
Chris@0
|
1936 if (!$display_handler instanceof DisplayRouterInterface) {
|
Chris@0
|
1937 throw new \InvalidArgumentException('You cannot create a URL to a display without routes.');
|
Chris@0
|
1938 }
|
Chris@0
|
1939
|
Chris@0
|
1940 if (!isset($args)) {
|
Chris@0
|
1941 $args = $this->args;
|
Chris@0
|
1942
|
Chris@0
|
1943 // Exclude arguments that were computed, not passed on the URL.
|
Chris@0
|
1944 $position = 0;
|
Chris@0
|
1945 if (!empty($this->argument)) {
|
Chris@0
|
1946 foreach ($this->argument as $argument) {
|
Chris@0
|
1947 if (!empty($argument->is_default) && !empty($argument->options['default_argument_skip_url'])) {
|
Chris@0
|
1948 unset($args[$position]);
|
Chris@0
|
1949 }
|
Chris@0
|
1950 $position++;
|
Chris@0
|
1951 }
|
Chris@0
|
1952 }
|
Chris@0
|
1953 }
|
Chris@0
|
1954
|
Chris@0
|
1955 $path = $this->getPath();
|
Chris@0
|
1956
|
Chris@0
|
1957 // Don't bother working if there's nothing to do:
|
Chris@0
|
1958 if (empty($path) || (empty($args) && strpos($path, '%') === FALSE)) {
|
Chris@0
|
1959 return $display_handler->getUrlInfo();
|
Chris@0
|
1960 }
|
Chris@0
|
1961
|
Chris@0
|
1962 $argument_keys = isset($this->argument) ? array_keys($this->argument) : [];
|
Chris@0
|
1963 $id = current($argument_keys);
|
Chris@0
|
1964
|
Chris@0
|
1965 /** @var \Drupal\Core\Url $url */
|
Chris@0
|
1966 $url = $display_handler->getUrlInfo();
|
Chris@0
|
1967 $route = $this->routeProvider->getRouteByName($url->getRouteName());
|
Chris@0
|
1968
|
Chris@0
|
1969 $variables = $route->compile()->getVariables();
|
Chris@0
|
1970 $parameters = $url->getRouteParameters();
|
Chris@0
|
1971
|
Chris@0
|
1972 foreach ($variables as $variable_name) {
|
Chris@0
|
1973 if (empty($args)) {
|
Chris@0
|
1974 // Try to never put % in a URL; use the wildcard instead.
|
Chris@0
|
1975 if ($id && !empty($this->argument[$id]->options['exception']['value'])) {
|
Chris@0
|
1976 $parameters[$variable_name] = $this->argument[$id]->options['exception']['value'];
|
Chris@0
|
1977 }
|
Chris@0
|
1978 else {
|
Chris@0
|
1979 // Provide some fallback in case no exception value could be found.
|
Chris@0
|
1980 $parameters[$variable_name] = '*';
|
Chris@0
|
1981 }
|
Chris@0
|
1982 }
|
Chris@0
|
1983 else {
|
Chris@0
|
1984 $parameters[$variable_name] = array_shift($args);
|
Chris@0
|
1985 }
|
Chris@0
|
1986
|
Chris@0
|
1987 if ($id) {
|
Chris@0
|
1988 $id = next($argument_keys);
|
Chris@0
|
1989 }
|
Chris@0
|
1990 }
|
Chris@0
|
1991
|
Chris@0
|
1992 $url->setRouteParameters($parameters);
|
Chris@0
|
1993 return $url;
|
Chris@0
|
1994 }
|
Chris@0
|
1995
|
Chris@0
|
1996 /**
|
Chris@0
|
1997 * Gets the Url object associated with the display handler.
|
Chris@0
|
1998 *
|
Chris@0
|
1999 * @param string $display_id
|
Chris@0
|
2000 * (optional) The display ID (used only to detail an exception).
|
Chris@0
|
2001 *
|
Chris@0
|
2002 * @return \Drupal\Core\Url
|
Chris@0
|
2003 * The display handlers URL object.
|
Chris@0
|
2004 *
|
Chris@0
|
2005 * @throws \InvalidArgumentException
|
Chris@0
|
2006 * Thrown when the display plugin does not have a URL to return.
|
Chris@0
|
2007 */
|
Chris@0
|
2008 public function getUrlInfo($display_id = '') {
|
Chris@0
|
2009 $this->initDisplay();
|
Chris@0
|
2010 if (!$this->display_handler instanceof DisplayRouterInterface) {
|
Chris@0
|
2011 throw new \InvalidArgumentException("You cannot generate a URL for the display '$display_id'");
|
Chris@0
|
2012 }
|
Chris@0
|
2013 return $this->display_handler->getUrlInfo();
|
Chris@0
|
2014 }
|
Chris@0
|
2015
|
Chris@0
|
2016 /**
|
Chris@0
|
2017 * Gets the base path used for this view.
|
Chris@0
|
2018 *
|
Chris@0
|
2019 * @return string|false
|
Chris@0
|
2020 * The base path used for the view or FALSE if setting the display fails.
|
Chris@0
|
2021 */
|
Chris@0
|
2022 public function getPath() {
|
Chris@0
|
2023 if (!empty($this->override_path)) {
|
Chris@0
|
2024 return $this->override_path;
|
Chris@0
|
2025 }
|
Chris@0
|
2026
|
Chris@0
|
2027 if (empty($this->display_handler)) {
|
Chris@0
|
2028 if (!$this->setDisplay('default')) {
|
Chris@0
|
2029 return FALSE;
|
Chris@0
|
2030 }
|
Chris@0
|
2031 }
|
Chris@0
|
2032 return $this->display_handler->getPath();
|
Chris@0
|
2033 }
|
Chris@0
|
2034
|
Chris@0
|
2035 /**
|
Chris@0
|
2036 * Gets the current user.
|
Chris@0
|
2037 *
|
Chris@0
|
2038 * Views plugins can receive the current user in order to not need dependency
|
Chris@0
|
2039 * injection.
|
Chris@0
|
2040 *
|
Chris@0
|
2041 * @return \Drupal\Core\Session\AccountInterface
|
Chris@0
|
2042 * The current user.
|
Chris@0
|
2043 */
|
Chris@0
|
2044 public function getUser() {
|
Chris@0
|
2045 return $this->user;
|
Chris@0
|
2046 }
|
Chris@0
|
2047
|
Chris@0
|
2048 /**
|
Chris@0
|
2049 * Creates a duplicate ViewExecutable object.
|
Chris@0
|
2050 *
|
Chris@0
|
2051 * Makes a copy of this view that has been sanitized of handlers, any runtime
|
Chris@0
|
2052 * data, ID, and UUID.
|
Chris@0
|
2053 */
|
Chris@0
|
2054 public function createDuplicate() {
|
Chris@0
|
2055 return $this->storage->createDuplicate()->getExecutable();
|
Chris@0
|
2056 }
|
Chris@0
|
2057
|
Chris@0
|
2058 /**
|
Chris@0
|
2059 * Unsets references so that a $view object may be properly garbage collected.
|
Chris@0
|
2060 */
|
Chris@0
|
2061 public function destroy() {
|
Chris@0
|
2062 foreach ($this::getHandlerTypes() as $type => $info) {
|
Chris@0
|
2063 if (isset($this->$type)) {
|
Chris@0
|
2064 foreach ($this->{$type} as $handler) {
|
Chris@0
|
2065 $handler->destroy();
|
Chris@0
|
2066 }
|
Chris@0
|
2067 }
|
Chris@0
|
2068 }
|
Chris@0
|
2069
|
Chris@0
|
2070 if (isset($this->style_plugin)) {
|
Chris@0
|
2071 $this->style_plugin->destroy();
|
Chris@0
|
2072 }
|
Chris@0
|
2073
|
Chris@0
|
2074 $reflection = new \ReflectionClass($this);
|
Chris@0
|
2075 $defaults = $reflection->getDefaultProperties();
|
Chris@0
|
2076 // The external dependencies should not be reset. This is not generated by
|
Chris@0
|
2077 // the execution of a view.
|
Chris@0
|
2078 unset(
|
Chris@0
|
2079 $defaults['storage'],
|
Chris@0
|
2080 $defaults['user'],
|
Chris@0
|
2081 $defaults['request'],
|
Chris@0
|
2082 $defaults['routeProvider'],
|
Chris@0
|
2083 $defaults['viewsData']
|
Chris@0
|
2084 );
|
Chris@0
|
2085
|
Chris@0
|
2086 foreach ($defaults as $property => $default) {
|
Chris@0
|
2087 $this->{$property} = $default;
|
Chris@0
|
2088 }
|
Chris@0
|
2089 }
|
Chris@0
|
2090
|
Chris@0
|
2091 /**
|
Chris@0
|
2092 * Makes sure the view is completely valid.
|
Chris@0
|
2093 *
|
Chris@0
|
2094 * @return array
|
Chris@0
|
2095 * An array of error strings. This will be empty if there are no validation
|
Chris@0
|
2096 * errors.
|
Chris@0
|
2097 */
|
Chris@0
|
2098 public function validate() {
|
Chris@0
|
2099 $errors = [];
|
Chris@0
|
2100
|
Chris@0
|
2101 $this->initDisplay();
|
Chris@0
|
2102 $current_display = $this->current_display;
|
Chris@0
|
2103
|
Chris@0
|
2104 foreach ($this->displayHandlers as $id => $display) {
|
Chris@0
|
2105 if (!empty($display)) {
|
Chris@0
|
2106 if (!empty($display->display['deleted'])) {
|
Chris@0
|
2107 continue;
|
Chris@0
|
2108 }
|
Chris@0
|
2109
|
Chris@0
|
2110 $result = $this->displayHandlers->get($id)->validate();
|
Chris@0
|
2111 if (!empty($result) && is_array($result)) {
|
Chris@0
|
2112 $errors[$id] = $result;
|
Chris@0
|
2113 }
|
Chris@0
|
2114 }
|
Chris@0
|
2115 }
|
Chris@0
|
2116
|
Chris@0
|
2117 $this->setDisplay($current_display);
|
Chris@0
|
2118
|
Chris@0
|
2119 return $errors;
|
Chris@0
|
2120 }
|
Chris@0
|
2121
|
Chris@0
|
2122 /**
|
Chris@0
|
2123 * Provides a list of views handler types used in a view.
|
Chris@0
|
2124 *
|
Chris@0
|
2125 * This also provides some information about the views handler types.
|
Chris@0
|
2126 *
|
Chris@0
|
2127 * @return array
|
Chris@0
|
2128 * An array of associative arrays containing:
|
Chris@0
|
2129 * - title: The title of the handler type.
|
Chris@0
|
2130 * - ltitle: The lowercase title of the handler type.
|
Chris@0
|
2131 * - stitle: A singular title of the handler type.
|
Chris@0
|
2132 * - lstitle: A singular lowercase title of the handler type.
|
Chris@0
|
2133 * - plural: Plural version of the handler type.
|
Chris@0
|
2134 * - (optional) type: The actual internal used handler type. This key is
|
Chris@0
|
2135 * just used for header,footer,empty to link to the internal type: area.
|
Chris@0
|
2136 */
|
Chris@0
|
2137 public static function getHandlerTypes() {
|
Chris@0
|
2138 return Views::getHandlerTypes();
|
Chris@0
|
2139 }
|
Chris@0
|
2140
|
Chris@0
|
2141 /**
|
Chris@0
|
2142 * Returns the valid types of plugins that can be used.
|
Chris@0
|
2143 *
|
Chris@0
|
2144 * @return array
|
Chris@0
|
2145 * An array of plugin type strings.
|
Chris@0
|
2146 */
|
Chris@0
|
2147 public static function getPluginTypes($type = NULL) {
|
Chris@0
|
2148 return Views::getPluginTypes($type);
|
Chris@0
|
2149 }
|
Chris@0
|
2150
|
Chris@0
|
2151 /**
|
Chris@0
|
2152 * Adds an instance of a handler to the view.
|
Chris@0
|
2153 *
|
Chris@0
|
2154 * Items may be fields, filters, sort criteria, or arguments.
|
Chris@0
|
2155 *
|
Chris@0
|
2156 * @param string $display_id
|
Chris@0
|
2157 * The machine name of the display.
|
Chris@0
|
2158 * @param string $type
|
Chris@0
|
2159 * The type of handler being added.
|
Chris@0
|
2160 * @param string $table
|
Chris@0
|
2161 * The name of the table this handler is from.
|
Chris@0
|
2162 * @param string $field
|
Chris@0
|
2163 * The name of the field this handler is from.
|
Chris@0
|
2164 * @param array $options
|
Chris@0
|
2165 * (optional) Extra options for this instance. Defaults to an empty array.
|
Chris@0
|
2166 * @param string $id
|
Chris@0
|
2167 * (optional) A unique ID for this handler instance. Defaults to NULL, in
|
Chris@0
|
2168 * which case one will be generated.
|
Chris@0
|
2169 *
|
Chris@0
|
2170 * @return string
|
Chris@0
|
2171 * The unique ID for this handler instance.
|
Chris@0
|
2172 */
|
Chris@0
|
2173 public function addHandler($display_id, $type, $table, $field, $options = [], $id = NULL) {
|
Chris@0
|
2174 $types = $this::getHandlerTypes();
|
Chris@0
|
2175 $this->setDisplay($display_id);
|
Chris@0
|
2176
|
Chris@0
|
2177 $data = $this->viewsData->get($table);
|
Chris@0
|
2178 $fields = $this->displayHandlers->get($display_id)->getOption($types[$type]['plural']);
|
Chris@0
|
2179
|
Chris@0
|
2180 if (empty($id)) {
|
Chris@0
|
2181 $id = $this->generateHandlerId($field, $fields);
|
Chris@0
|
2182 }
|
Chris@0
|
2183
|
Chris@0
|
2184 // If the desired type is not found, use the original value directly.
|
Chris@0
|
2185 $handler_type = !empty($types[$type]['type']) ? $types[$type]['type'] : $type;
|
Chris@0
|
2186
|
Chris@0
|
2187 $fields[$id] = [
|
Chris@0
|
2188 'id' => $id,
|
Chris@0
|
2189 'table' => $table,
|
Chris@0
|
2190 'field' => $field,
|
Chris@0
|
2191 ] + $options;
|
Chris@0
|
2192
|
Chris@0
|
2193 if (isset($data['table']['entity type'])) {
|
Chris@0
|
2194 $fields[$id]['entity_type'] = $data['table']['entity type'];
|
Chris@0
|
2195 }
|
Chris@0
|
2196 if (isset($data[$field]['entity field'])) {
|
Chris@0
|
2197 $fields[$id]['entity_field'] = $data[$field]['entity field'];
|
Chris@0
|
2198 }
|
Chris@0
|
2199
|
Chris@0
|
2200 // Load the plugin ID if available.
|
Chris@0
|
2201 if (isset($data[$field][$handler_type]['id'])) {
|
Chris@0
|
2202 $fields[$id]['plugin_id'] = $data[$field][$handler_type]['id'];
|
Chris@0
|
2203 }
|
Chris@0
|
2204
|
Chris@0
|
2205 $this->displayHandlers->get($display_id)->setOption($types[$type]['plural'], $fields);
|
Chris@0
|
2206
|
Chris@0
|
2207 return $id;
|
Chris@0
|
2208 }
|
Chris@0
|
2209
|
Chris@0
|
2210 /**
|
Chris@0
|
2211 * Generates a unique ID for an handler instance.
|
Chris@0
|
2212 *
|
Chris@0
|
2213 * These handler instances are typically fields, filters, sort criteria, or
|
Chris@0
|
2214 * arguments.
|
Chris@0
|
2215 *
|
Chris@0
|
2216 * @param string $requested_id
|
Chris@0
|
2217 * The requested ID for the handler instance.
|
Chris@0
|
2218 * @param array $existing_items
|
Chris@0
|
2219 * An array of existing handler instances, keyed by their IDs.
|
Chris@0
|
2220 *
|
Chris@0
|
2221 * @return string
|
Chris@0
|
2222 * A unique ID. This will be equal to $requested_id if no handler instance
|
Chris@0
|
2223 * with that ID already exists. Otherwise, it will be appended with an
|
Chris@0
|
2224 * integer to make it unique, e.g., "{$requested_id}_1",
|
Chris@0
|
2225 * "{$requested_id}_2", etc.
|
Chris@0
|
2226 */
|
Chris@0
|
2227 public static function generateHandlerId($requested_id, $existing_items) {
|
Chris@0
|
2228 $count = 0;
|
Chris@0
|
2229 $id = $requested_id;
|
Chris@0
|
2230 while (!empty($existing_items[$id])) {
|
Chris@0
|
2231 $id = $requested_id . '_' . ++$count;
|
Chris@0
|
2232 }
|
Chris@0
|
2233 return $id;
|
Chris@0
|
2234 }
|
Chris@0
|
2235
|
Chris@0
|
2236 /**
|
Chris@0
|
2237 * Gets an array of handler instances for the current display.
|
Chris@0
|
2238 *
|
Chris@0
|
2239 * @param string $type
|
Chris@0
|
2240 * The type of handlers to retrieve.
|
Chris@0
|
2241 * @param string $display_id
|
Chris@0
|
2242 * (optional) A specific display machine name to use. If NULL, the current
|
Chris@0
|
2243 * display will be used.
|
Chris@0
|
2244 *
|
Chris@0
|
2245 * @return array
|
Chris@0
|
2246 * An array of handler instances of a given type for this display.
|
Chris@0
|
2247 */
|
Chris@0
|
2248 public function getHandlers($type, $display_id = NULL) {
|
Chris@0
|
2249 $old_display_id = !empty($this->current_display) ? $this->current_display : 'default';
|
Chris@0
|
2250
|
Chris@0
|
2251 $this->setDisplay($display_id);
|
Chris@0
|
2252
|
Chris@0
|
2253 if (!isset($display_id)) {
|
Chris@0
|
2254 $display_id = $this->current_display;
|
Chris@0
|
2255 }
|
Chris@0
|
2256
|
Chris@0
|
2257 // Get info about the types so we can get the right data.
|
Chris@0
|
2258 $types = static::getHandlerTypes();
|
Chris@0
|
2259
|
Chris@0
|
2260 $handlers = $this->displayHandlers->get($display_id)->getOption($types[$type]['plural']);
|
Chris@0
|
2261
|
Chris@0
|
2262 // Restore initial display id (if any) or set to 'default'.
|
Chris@0
|
2263 if ($display_id != $old_display_id) {
|
Chris@0
|
2264 $this->setDisplay($old_display_id);
|
Chris@0
|
2265 }
|
Chris@0
|
2266 return $handlers;
|
Chris@0
|
2267 }
|
Chris@0
|
2268
|
Chris@0
|
2269 /**
|
Chris@0
|
2270 * Gets the configuration of a handler instance on a given display.
|
Chris@0
|
2271 *
|
Chris@0
|
2272 * @param string $display_id
|
Chris@0
|
2273 * The machine name of the display.
|
Chris@0
|
2274 * @param string $type
|
Chris@0
|
2275 * The type of handler to retrieve.
|
Chris@0
|
2276 * @param string $id
|
Chris@0
|
2277 * The ID of the handler to retrieve.
|
Chris@0
|
2278 *
|
Chris@0
|
2279 * @return array|null
|
Chris@0
|
2280 * Either the handler instance's configuration, or NULL if the handler is
|
Chris@0
|
2281 * not used on the display.
|
Chris@0
|
2282 */
|
Chris@0
|
2283 public function getHandler($display_id, $type, $id) {
|
Chris@0
|
2284 // Get info about the types so we can get the right data.
|
Chris@0
|
2285 $types = static::getHandlerTypes();
|
Chris@0
|
2286 // Initialize the display
|
Chris@0
|
2287 $this->setDisplay($display_id);
|
Chris@0
|
2288
|
Chris@0
|
2289 // Get the existing configuration
|
Chris@0
|
2290 $fields = $this->displayHandlers->get($display_id)->getOption($types[$type]['plural']);
|
Chris@0
|
2291
|
Chris@0
|
2292 return isset($fields[$id]) ? $fields[$id] : NULL;
|
Chris@0
|
2293 }
|
Chris@0
|
2294
|
Chris@0
|
2295 /**
|
Chris@0
|
2296 * Sets the configuration of a handler instance on a given display.
|
Chris@0
|
2297 *
|
Chris@0
|
2298 * @param string $display_id
|
Chris@0
|
2299 * The machine name of the display.
|
Chris@0
|
2300 * @param string $type
|
Chris@0
|
2301 * The type of handler being set.
|
Chris@0
|
2302 * @param string $id
|
Chris@0
|
2303 * The ID of the handler being set.
|
Chris@0
|
2304 * @param array|null $item
|
Chris@0
|
2305 * An array of configuration for a handler, or NULL to remove this instance.
|
Chris@0
|
2306 *
|
Chris@0
|
2307 * @see set_item_option()
|
Chris@0
|
2308 */
|
Chris@0
|
2309 public function setHandler($display_id, $type, $id, $item) {
|
Chris@0
|
2310 // Get info about the types so we can get the right data.
|
Chris@0
|
2311 $types = static::getHandlerTypes();
|
Chris@0
|
2312 // Initialize the display.
|
Chris@0
|
2313 $this->setDisplay($display_id);
|
Chris@0
|
2314
|
Chris@0
|
2315 // Get the existing configuration.
|
Chris@0
|
2316 $fields = $this->displayHandlers->get($display_id)->getOption($types[$type]['plural']);
|
Chris@0
|
2317 if (isset($item)) {
|
Chris@0
|
2318 $fields[$id] = $item;
|
Chris@0
|
2319 }
|
Chris@0
|
2320
|
Chris@0
|
2321 // Store.
|
Chris@0
|
2322 $this->displayHandlers->get($display_id)->setOption($types[$type]['plural'], $fields);
|
Chris@0
|
2323 }
|
Chris@0
|
2324
|
Chris@0
|
2325 /**
|
Chris@0
|
2326 * Removes configuration for a handler instance on a given display.
|
Chris@0
|
2327 *
|
Chris@0
|
2328 * @param string $display_id
|
Chris@0
|
2329 * The machine name of the display.
|
Chris@0
|
2330 * @param string $type
|
Chris@0
|
2331 * The type of handler being removed.
|
Chris@0
|
2332 * @param string $id
|
Chris@0
|
2333 * The ID of the handler being removed.
|
Chris@0
|
2334 */
|
Chris@0
|
2335 public function removeHandler($display_id, $type, $id) {
|
Chris@0
|
2336 // Get info about the types so we can get the right data.
|
Chris@0
|
2337 $types = static::getHandlerTypes();
|
Chris@0
|
2338 // Initialize the display.
|
Chris@0
|
2339 $this->setDisplay($display_id);
|
Chris@0
|
2340
|
Chris@0
|
2341 // Get the existing configuration.
|
Chris@0
|
2342 $fields = $this->displayHandlers->get($display_id)->getOption($types[$type]['plural']);
|
Chris@0
|
2343 // Unset the item.
|
Chris@0
|
2344 unset($fields[$id]);
|
Chris@0
|
2345
|
Chris@0
|
2346 // Store.
|
Chris@0
|
2347 $this->displayHandlers->get($display_id)->setOption($types[$type]['plural'], $fields);
|
Chris@0
|
2348 }
|
Chris@0
|
2349
|
Chris@0
|
2350 /**
|
Chris@0
|
2351 * Sets an option on a handler instance.
|
Chris@0
|
2352 *
|
Chris@0
|
2353 * Use this only if you have just 1 or 2 options to set; if you have many,
|
Chris@0
|
2354 * consider getting the handler instance, adding the options and using
|
Chris@0
|
2355 * set_item() directly.
|
Chris@0
|
2356 *
|
Chris@0
|
2357 * @param string $display_id
|
Chris@0
|
2358 * The machine name of the display.
|
Chris@0
|
2359 * @param string $type
|
Chris@0
|
2360 * The type of handler being set.
|
Chris@0
|
2361 * @param string $id
|
Chris@0
|
2362 * The ID of the handler being set.
|
Chris@0
|
2363 * @param string $option
|
Chris@0
|
2364 * The configuration key for the value being set.
|
Chris@0
|
2365 * @param mixed $value
|
Chris@0
|
2366 * The value being set.
|
Chris@0
|
2367 *
|
Chris@0
|
2368 * @see set_item()
|
Chris@0
|
2369 */
|
Chris@0
|
2370 public function setHandlerOption($display_id, $type, $id, $option, $value) {
|
Chris@0
|
2371 $item = $this->getHandler($display_id, $type, $id);
|
Chris@0
|
2372 $item[$option] = $value;
|
Chris@0
|
2373 $this->setHandler($display_id, $type, $id, $item);
|
Chris@0
|
2374 }
|
Chris@0
|
2375
|
Chris@0
|
2376 /**
|
Chris@0
|
2377 * Enables admin links on the rendered view.
|
Chris@0
|
2378 *
|
Chris@0
|
2379 * @param bool $show_admin_links
|
Chris@0
|
2380 * TRUE if the admin links should be shown.
|
Chris@0
|
2381 */
|
Chris@0
|
2382 public function setShowAdminLinks($show_admin_links) {
|
Chris@0
|
2383 $this->showAdminLinks = (bool) $show_admin_links;
|
Chris@0
|
2384 }
|
Chris@0
|
2385
|
Chris@0
|
2386 /**
|
Chris@0
|
2387 * Returns whether admin links should be rendered on the view.
|
Chris@0
|
2388 *
|
Chris@0
|
2389 * @return bool
|
Chris@0
|
2390 * TRUE if admin links should be rendered, else FALSE.
|
Chris@0
|
2391 */
|
Chris@0
|
2392 public function getShowAdminLinks() {
|
Chris@0
|
2393 if (!isset($this->showAdminLinks)) {
|
Chris@0
|
2394 return $this->getDisplay()->getOption('show_admin_links');
|
Chris@0
|
2395 }
|
Chris@0
|
2396 return $this->showAdminLinks;
|
Chris@0
|
2397 }
|
Chris@0
|
2398
|
Chris@0
|
2399 /**
|
Chris@0
|
2400 * Merges all plugin default values for each display.
|
Chris@0
|
2401 */
|
Chris@0
|
2402 public function mergeDefaults() {
|
Chris@0
|
2403 $this->initDisplay();
|
Chris@0
|
2404 // Initialize displays and merge all plugin defaults.
|
Chris@0
|
2405 foreach ($this->displayHandlers as $display) {
|
Chris@0
|
2406 $display->mergeDefaults();
|
Chris@0
|
2407 }
|
Chris@0
|
2408 }
|
Chris@0
|
2409
|
Chris@0
|
2410 /**
|
Chris@0
|
2411 * Provides a full array of possible theme functions to try for a given hook.
|
Chris@0
|
2412 *
|
Chris@0
|
2413 * @param string $hook
|
Chris@0
|
2414 * The hook to use. This is the base theme/template name.
|
Chris@0
|
2415 *
|
Chris@0
|
2416 * @return array
|
Chris@0
|
2417 * An array of theme hook suggestions.
|
Chris@0
|
2418 */
|
Chris@0
|
2419 public function buildThemeFunctions($hook) {
|
Chris@0
|
2420 $themes = [];
|
Chris@0
|
2421 $display = isset($this->display_handler) ? $this->display_handler->display : NULL;
|
Chris@0
|
2422 $id = $this->storage->id();
|
Chris@0
|
2423
|
Chris@0
|
2424 if ($display) {
|
Chris@0
|
2425 $themes[] = $hook . '__' . $id . '__' . $display['id'];
|
Chris@0
|
2426 $themes[] = $hook . '__' . $display['id'];
|
Chris@0
|
2427 // Add theme suggestions for each single tag.
|
Chris@0
|
2428 foreach (Tags::explode($this->storage->get('tag')) as $tag) {
|
Chris@0
|
2429 $themes[] = $hook . '__' . preg_replace('/[^a-z0-9]/', '_', strtolower($tag));
|
Chris@0
|
2430 }
|
Chris@0
|
2431
|
Chris@0
|
2432 if ($display['id'] != $display['display_plugin']) {
|
Chris@0
|
2433 $themes[] = $hook . '__' . $id . '__' . $display['display_plugin'];
|
Chris@0
|
2434 $themes[] = $hook . '__' . $display['display_plugin'];
|
Chris@0
|
2435 }
|
Chris@0
|
2436 }
|
Chris@0
|
2437 $themes[] = $hook . '__' . $id;
|
Chris@0
|
2438 $themes[] = $hook;
|
Chris@0
|
2439
|
Chris@0
|
2440 return $themes;
|
Chris@0
|
2441 }
|
Chris@0
|
2442
|
Chris@0
|
2443 /**
|
Chris@0
|
2444 * Determines if this view has form elements.
|
Chris@0
|
2445 *
|
Chris@0
|
2446 * @return bool
|
Chris@0
|
2447 * TRUE if this view contains handlers with views form implementations,
|
Chris@0
|
2448 * FALSE otherwise.
|
Chris@0
|
2449 */
|
Chris@0
|
2450 public function hasFormElements() {
|
Chris@0
|
2451 foreach ($this->field as $field) {
|
Chris@0
|
2452 if (property_exists($field, 'views_form_callback') || method_exists($field, 'viewsForm')) {
|
Chris@0
|
2453 return TRUE;
|
Chris@0
|
2454 }
|
Chris@0
|
2455 }
|
Chris@0
|
2456 $area_handlers = array_merge(array_values($this->header), array_values($this->footer));
|
Chris@0
|
2457 $empty = empty($this->result);
|
Chris@0
|
2458 foreach ($area_handlers as $area) {
|
Chris@0
|
2459 if (method_exists($area, 'viewsForm') && !$area->viewsFormEmpty($empty)) {
|
Chris@0
|
2460 return TRUE;
|
Chris@0
|
2461 }
|
Chris@0
|
2462 }
|
Chris@0
|
2463
|
Chris@0
|
2464 return FALSE;
|
Chris@0
|
2465 }
|
Chris@0
|
2466
|
Chris@0
|
2467 /**
|
Chris@0
|
2468 * Gets dependencies for the view.
|
Chris@0
|
2469 *
|
Chris@0
|
2470 * @see \Drupal\views\Entity\View::calculateDependencies()
|
Chris@0
|
2471 * @see \Drupal\views\Entity\View::getDependencies()
|
Chris@0
|
2472 *
|
Chris@0
|
2473 * @return array
|
Chris@0
|
2474 * An array of dependencies grouped by type (module, theme, entity).
|
Chris@0
|
2475 */
|
Chris@0
|
2476 public function getDependencies() {
|
Chris@0
|
2477 return $this->storage->calculateDependencies()->getDependencies();
|
Chris@0
|
2478 }
|
Chris@0
|
2479
|
Chris@0
|
2480 /**
|
Chris@0
|
2481 * Magic method implementation to serialize the view executable.
|
Chris@0
|
2482 *
|
Chris@0
|
2483 * @return array
|
Chris@0
|
2484 * The names of all variables that should be serialized.
|
Chris@0
|
2485 */
|
Chris@0
|
2486 public function __sleep() {
|
Chris@0
|
2487 // Limit to only the required data which is needed to properly restore the
|
Chris@0
|
2488 // state during unserialization.
|
Chris@0
|
2489 $this->serializationData = [
|
Chris@0
|
2490 'storage' => $this->storage->id(),
|
Chris@0
|
2491 'views_data' => $this->viewsData->_serviceId,
|
Chris@0
|
2492 'route_provider' => $this->routeProvider->_serviceId,
|
Chris@0
|
2493 'current_display' => $this->current_display,
|
Chris@0
|
2494 'args' => $this->args,
|
Chris@0
|
2495 'current_page' => $this->current_page,
|
Chris@0
|
2496 'exposed_input' => $this->exposed_input,
|
Chris@0
|
2497 'exposed_raw_input' => $this->exposed_raw_input,
|
Chris@0
|
2498 'exposed_data' => $this->exposed_data,
|
Chris@0
|
2499 'dom_id' => $this->dom_id,
|
Chris@0
|
2500 'executed' => $this->executed,
|
Chris@0
|
2501 ];
|
Chris@0
|
2502 return ['serializationData'];
|
Chris@0
|
2503 }
|
Chris@0
|
2504
|
Chris@0
|
2505 /**
|
Chris@0
|
2506 * Magic method implementation to unserialize the view executable.
|
Chris@0
|
2507 */
|
Chris@0
|
2508 public function __wakeup() {
|
Chris@0
|
2509 // There are cases, like in testing where we don't have a container
|
Chris@0
|
2510 // available.
|
Chris@0
|
2511 if (\Drupal::hasContainer() && !empty($this->serializationData)) {
|
Chris@0
|
2512 // Load and reference the storage.
|
Chris@0
|
2513 $this->storage = \Drupal::entityTypeManager()->getStorage('view')
|
Chris@0
|
2514 ->load($this->serializationData['storage']);
|
Chris@0
|
2515 $this->storage->set('executable', $this);
|
Chris@0
|
2516
|
Chris@0
|
2517 // Attach all necessary services.
|
Chris@0
|
2518 $this->user = \Drupal::currentUser();
|
Chris@0
|
2519 $this->viewsData = \Drupal::service($this->serializationData['views_data']);
|
Chris@0
|
2520 $this->routeProvider = \Drupal::service($this->serializationData['route_provider']);
|
Chris@0
|
2521
|
Chris@0
|
2522 // Restore the state of this executable.
|
Chris@0
|
2523 if ($request = \Drupal::request()) {
|
Chris@0
|
2524 $this->setRequest($request);
|
Chris@0
|
2525 }
|
Chris@0
|
2526 $this->setDisplay($this->serializationData['current_display']);
|
Chris@0
|
2527 $this->setArguments($this->serializationData['args']);
|
Chris@0
|
2528 $this->setCurrentPage($this->serializationData['current_page']);
|
Chris@0
|
2529 $this->setExposedInput($this->serializationData['exposed_input']);
|
Chris@0
|
2530 $this->exposed_data = $this->serializationData['exposed_data'];
|
Chris@0
|
2531 $this->exposed_raw_input = $this->serializationData['exposed_raw_input'];
|
Chris@0
|
2532 $this->dom_id = $this->serializationData['dom_id'];
|
Chris@0
|
2533
|
Chris@0
|
2534 $this->initHandlers();
|
Chris@0
|
2535
|
Chris@0
|
2536 // If the display was previously executed, execute it now.
|
Chris@0
|
2537 if ($this->serializationData['executed']) {
|
Chris@0
|
2538 $this->execute($this->current_display);
|
Chris@0
|
2539 }
|
Chris@0
|
2540 }
|
Chris@0
|
2541 // Unset serializationData since it serves no further purpose.
|
Chris@0
|
2542 unset($this->serializationData);
|
Chris@0
|
2543 }
|
Chris@0
|
2544
|
Chris@0
|
2545 }
|