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