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