1<?php
2
3namespace Drupal\views;
4
5use Drupal\Component\Render\FormattableMarkup;
6use Drupal\Component\Utility\Html;
7use Drupal\Component\Utility\Tags;
8use Drupal\Core\Routing\RouteProviderInterface;
9use Drupal\Core\Session\AccountInterface;
10use Drupal\views\Plugin\views\display\DisplayRouterInterface;
11use Symfony\Component\HttpFoundation\Request;
12use Symfony\Component\HttpFoundation\Response;
13use 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 */
27class 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->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 ($this->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->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 long run, 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->getBaseThemeExtensions());
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 that the user has access to.
1726      if ($display_handler->isEnabled() && $display_handler->access()) {
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 gets 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 a 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}
2548