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