Upgraded drupal core with security updates
[yaffs-website] / web / core / modules / views / views.api.php
1 <?php
2
3 /**
4  * @file
5  * Describes hooks and plugins provided by the Views module.
6  */
7
8 use Drupal\Core\Language\LanguageInterface;
9 use Drupal\views\Plugin\views\cache\CachePluginBase;
10 use Drupal\views\Plugin\views\PluginBase;
11 use Drupal\views\ViewExecutable;
12
13 /**
14  * @defgroup views_overview Views overview
15  * @{
16  * Overview of the Views module API
17  *
18  * The Views module is a generalized query and display engine, which can be used
19  * to make views (formatted lists, grids, feeds, and other output) of items
20  * (often entities, but can be other types of data). Developers can interact
21  * with Views in several ways:
22  * - Provide plugins: Views plugins govern nearly every aspect of views,
23  *   including querying (sorting, filtering, etc.) and display (at several
24  *   levels of granularity, ranging from the entire view to the details of a
25  *   field). See the @link views_plugins Views plugins topic @endlink for
26  *   more information.
27  * - Provide data: Data types can be provided to Views by implementing
28  *   hook_views_data(), and data types provided by other modules can be altered
29  *   by implementing hook_views_data_alter(). To provide views data for an
30  *   entity, create a class implementing
31  *   \Drupal\views\EntityViewsDataInterface and reference this in the
32  *   "views_data" annotation in the entity class. You can autogenerate big parts
33  *   of the integration if you extend the \Drupal\views\EntityViewsData base
34  *   class. See the @link entity_api Entity API topic @endlink for more
35  *   information about entities.
36  * - Implement hooks: A few operations in Views can be influenced by hooks.
37  *   See the @link views_hooks Views hooks topic @endlink for a list.
38  * - Theming: See the @link views_templates Views templates topic @endlink
39  *   for more information.
40  *
41  * @see \Drupal\views\ViewExecutable
42  * @see \Drupal\views\Views
43  * @}
44  */
45
46 /**
47  * @defgroup views_plugins Views plugins
48  * @{
49  * Overview of views plugins
50  *
51  * Views plugins are objects that are used to build and render the view.
52  * See individual views plugin topics for more information about the
53  * specifics of each plugin type, and the
54  * @link plugin_api Plugin API topic @endlink for more information about
55  * plugins in general.
56  *
57  * Some Views plugins are known as handlers. Handler plugins help build the
58  * view query object: filtering, contextual filtering, sorting, relationships,
59  * etc.
60  *
61  * @todo Document specific options on the appropriate plugin base classes.
62  * @todo Add examples.
63  *
64  * @ingroup views_overview
65  * @see \Drupal\views\Plugin\views\PluginBase
66  * @see \Drupal\views\Plugin\views\HandlerBase
67  * @see plugin_api
68  * @see annotation
69  * @}
70  */
71
72 /**
73  * @defgroup views_hooks Views hooks
74  * @{
75  * Hooks that allow other modules to implement the Views API.
76  * @ingroup views_overview
77  * @}
78  */
79
80 /**
81  * @addtogroup hooks
82  * @{
83  */
84
85 /**
86  * Analyze a view to provide warnings about its configuration.
87  *
88  * @param \Drupal\views\ViewExecutable $view
89  *   The view being executed.
90  *
91  * @return array
92  *   Array of warning messages built by Analyzer::formatMessage to be displayed
93  *   to the user following analysis of the view.
94  */
95 function hook_views_analyze(Drupal\views\ViewExecutable $view) {
96   $messages = [];
97
98   if ($view->display_handler->options['pager']['type'] == 'none') {
99     $messages[] = Drupal\views\Analyzer::formatMessage(t('This view has no pager. This could cause performance issues when the view contains many items.'), 'warning');
100   }
101
102   return $messages;
103 }
104
105 /**
106  * Describe data tables and fields (or the equivalent) to Views.
107  *
108  * The table and fields are processed in Views using various plugins. See
109  * the @link views_plugins Views plugins topic @endlink for more information.
110  *
111  * To provide views data for an entity, instead of implementing this hook,
112  * create a class implementing \Drupal\views\EntityViewsDataInterface and
113  * reference this in the "views" annotation in the entity class. The return
114  * value of the getViewsData() method on the interface is the same as this hook,
115  * and base class in \Drupal\views\EntityViewsData will take care of adding the
116  * basic Views tables and fields for your entity. See the
117  * @link entity_api Entity API topic @endlink for more information about
118  * entities.
119  *
120  * The data described with this hook is fetched and retrieved by
121  * \Drupal\views\Views::viewsData()->get().
122  *
123  * @return array
124  *   An associative array describing the structure of database tables and fields
125  *   (and their equivalents) provided for use in Views. At the outermost level,
126  *   the keys are the names used internally by Views for the tables (usually the
127  *   actual table name). Each table's array describes the table itself, how to
128  *   join to other tables, and the fields that are part of the table. The sample
129  *   function body provides documentation of the details.
130  *
131  * @see hook_views_data_alter()
132  */
133 function hook_views_data() {
134   // This example describes how to write hook_views_data() for a table defined
135   // like this:
136   // CREATE TABLE example_table (
137   //   nid INT(11) NOT NULL         COMMENT 'Primary key: {node}.nid.',
138   //   plain_text_field VARCHAR(32) COMMENT 'Just a plain text field.',
139   //   numeric_field INT(11)        COMMENT 'Just a numeric field.',
140   //   boolean_field INT(1)         COMMENT 'Just an on/off field.',
141   //   timestamp_field INT(8)       COMMENT 'Just a timestamp field.',
142   //   langcode VARCHAR(12)         COMMENT 'Language code field.',
143   //   PRIMARY KEY(nid)
144   // );
145
146   // Define the return array.
147   $data = [];
148
149   // The outermost keys of $data are Views table names, which should usually
150   // be the same as the hook_schema() table names.
151   $data['example_table'] = [];
152
153   // The value corresponding to key 'table' gives properties of the table
154   // itself.
155   $data['example_table']['table'] = [];
156
157   // Within 'table', the value of 'group' (translated string) is used as a
158   // prefix in Views UI for this table's fields, filters, etc. When adding
159   // a field, filter, etc. you can also filter by the group.
160   $data['example_table']['table']['group'] = t('Example table');
161
162   // Within 'table', the value of 'provider' is the module that provides schema
163   // or the entity type that causes the table to exist. Setting this ensures
164   // that views have the correct dependencies. This is automatically set to the
165   // module that implements hook_views_data().
166   $data['example_table']['table']['provider'] = 'example_module';
167
168   // Some tables are "base" tables, meaning that they can be the base tables
169   // for views. Non-base tables can only be brought in via relationships in
170   // views based on other tables. To define a table to be a base table, add
171   // key 'base' to the 'table' array:
172   $data['example_table']['table']['base'] = [
173     // Identifier (primary) field in this table for Views.
174     'field' => 'nid',
175     // Label in the UI.
176     'title' => t('Example table'),
177     // Longer description in the UI. Required.
178     'help' => t('Example table contains example content and can be related to nodes.'),
179     'weight' => -10,
180   ];
181
182   // Some tables have an implicit, automatic relationship to other tables,
183   // meaning that when the other table is available in a view (either as the
184   // base table or through a relationship), this table's fields, filters, etc.
185   // are automatically made available without having to add an additional
186   // relationship. To define an implicit relationship that will make your
187   // table automatically available when another table is present, add a 'join'
188   // section to your 'table' section. Note that it is usually only a good idea
189   // to do this for one-to-one joins, because otherwise your automatic join
190   // will add more rows to the view. It is also not a good idea to do this if
191   // most views won't need your table -- if that is the case, define a
192   // relationship instead (see below).
193   //
194   // If you've decided an automatic join is a good idea, here's how to do it;
195   // the resulting SQL query will look something like this:
196   //   ... FROM example_table et ... JOIN node_field_data nfd
197   //   ON et.nid = nfd.nid AND ('extra' clauses will be here) ...
198   // although the table aliases will be different.
199   $data['example_table']['table']['join'] = [
200     // Within the 'join' section, list one or more tables to automatically
201     // join to. In this example, every time 'node_field_data' is available in
202     // a view, 'example_table' will be too. The array keys here are the array
203     // keys for the other tables, given in their hook_views_data()
204     // implementations. If the table listed here is from another module's
205     // hook_views_data() implementation, make sure your module depends on that
206     // other module.
207     'node_field_data' => [
208       // Primary key field in node_field_data to use in the join.
209       'left_field' => 'nid',
210       // Foreign key field in example_table to use in the join.
211       'field' => 'nid',
212       // 'extra' is an array of additional conditions on the join.
213       'extra' => [
214         0 => [
215           // Adds AND node_field_data.published = TRUE to the join.
216           'field' => 'published',
217           'value' => TRUE,
218         ],
219         1 => [
220           // Adds AND example_table.numeric_field = 1 to the join.
221           'left_field' => 'numeric_field',
222           'value' => 1,
223           // If true, the value will not be surrounded in quotes.
224           'numeric' => TRUE,
225         ],
226         2 => [
227           // Adds AND example_table.boolean_field <>
228           // node_field_data.published to the join.
229           'field' => 'published',
230           'left_field' => 'boolean_field',
231           // The operator used, Defaults to "=".
232           'operator' => '!=',
233         ],
234       ],
235     ],
236   ];
237
238   // You can also do a more complex join, where in order to get to a certain
239   // base table defined in a hook_views_data() implementation, you will join
240   // to a different table that Views knows how to auto-join to the base table.
241   // For instance, if another module that your module depends on had
242   // defined a table 'foo' with an automatic join to 'node_field_table' (as
243   // shown above), you could join to 'node_field_table' via the 'foo' table.
244   // Here's how to do this, and the resulting SQL query would look something
245   // like this:
246   //   ... FROM example_table et ... JOIN foo foo
247   //   ON et.nid = foo.nid AND ('extra' clauses will be here) ...
248   //   JOIN node_field_data nfd ON (definition of the join from the foo
249   //   module goes here) ...
250   // although the table aliases will be different.
251   $data['example_table']['table']['join']['node_field_data'] = [
252     // 'node_field_data' above is the base we're joining to in Views.
253     // 'left_table' is the table we're actually joining to, in order to get to
254     // 'node_field_data'. It has to be something that Views knows how to join
255     // to 'node_field_data'.
256     'left_table' => 'foo',
257     'left_field' => 'nid',
258     'field' => 'nid',
259     // 'extra' is an array of additional conditions on the join.
260     'extra' => [
261       // This syntax matches additional fields in the two tables:
262       // ... AND foo.langcode = example_table.langcode ...
263       ['left_field' => 'langcode', 'field' => 'langcode'],
264       // This syntax adds a condition on our table. 'operator' defaults to
265       // '=' for non-array values, or 'IN' for array values.
266       // ... AND example_table.numeric_field > 0 ...
267       ['field' => 'numeric_field', 'value' => 0, 'numeric' => TRUE, 'operator' => '>'],
268     ],
269   ];
270
271   // Other array elements at the top level of your table's array describe
272   // individual database table fields made available to Views. The array keys
273   // are the names (unique within the table) used by Views for the fields,
274   // usually equal to the database field names.
275   //
276   // Each field entry must have the following elements:
277   // - title: Translated label for the field in the UI.
278   // - help: Description of the field in the UI.
279   //
280   // Each field entry may also have one or more of the following elements,
281   // describing "handlers" (plugins) for the field:
282   // - relationship: Specifies a handler that allows this field to be used
283   //   to define a relationship to another table in Views.
284   // - field: Specifies a handler to make it available to Views as a field.
285   // - filter: Specifies a handler to make it available to Views as a filter.
286   // - sort: Specifies a handler to make it available to Views as a sort.
287   // - argument: Specifies a handler to make it available to Views as an
288   //   argument, or contextual filter as it is known in the UI.
289   // - area: Specifies a handler to make it available to Views to add content
290   //   to the header, footer, or as no result behavior.
291   //
292   // Note that when specifying handlers, you must give the handler plugin ID
293   // and you may also specify overrides for various settings that make up the
294   // plugin definition. See examples below; the Boolean example demonstrates
295   // setting overrides.
296
297   // Node ID field, exposed as relationship only, since it is a foreign key
298   // in this table.
299   $data['example_table']['nid'] = [
300     'title' => t('Example content'),
301     'help' => t('Relate example content to the node content'),
302
303     // Define a relationship to the node_field_data table, so views whose
304     // base table is example_table can add a relationship to nodes. To make a
305     // relationship in the other direction, you can:
306     // - Use hook_views_data_alter() -- see the function body example on that
307     //   hook for details.
308     // - Use the implicit join method described above.
309     'relationship' => [
310       // Views name of the table to join to for the relationship.
311       'base' => 'node_field_data',
312       // Database field name in the other table to join on.
313       'base field' => 'nid',
314       // ID of relationship handler plugin to use.
315       'id' => 'standard',
316       // Default label for relationship in the UI.
317       'label' => t('Example node'),
318     ],
319   ];
320
321   // Plain text field, exposed as a field, sort, filter, and argument.
322   $data['example_table']['plain_text_field'] = [
323     'title' => t('Plain text field'),
324     'help' => t('Just a plain text field.'),
325
326     'field' => [
327       // ID of field handler plugin to use.
328       'id' => 'standard',
329     ],
330
331     'sort' => [
332       // ID of sort handler plugin to use.
333       'id' => 'standard',
334     ],
335
336     'filter' => [
337       // ID of filter handler plugin to use.
338       'id' => 'string',
339     ],
340
341     'argument' => [
342       // ID of argument handler plugin to use.
343       'id' => 'string',
344     ],
345   ];
346
347   // Numeric field, exposed as a field, sort, filter, and argument.
348   $data['example_table']['numeric_field'] = [
349     'title' => t('Numeric field'),
350     'help' => t('Just a numeric field.'),
351
352     'field' => [
353       // ID of field handler plugin to use.
354       'id' => 'numeric',
355     ],
356
357     'sort' => [
358       // ID of sort handler plugin to use.
359       'id' => 'standard',
360     ],
361
362     'filter' => [
363       // ID of filter handler plugin to use.
364       'id' => 'numeric',
365     ],
366
367     'argument' => [
368       // ID of argument handler plugin to use.
369       'id' => 'numeric',
370     ],
371   ];
372
373   // Boolean field, exposed as a field, sort, and filter. The filter section
374   // illustrates overriding various settings.
375   $data['example_table']['boolean_field'] = [
376     'title' => t('Boolean field'),
377     'help' => t('Just an on/off field.'),
378
379     'field' => [
380       // ID of field handler plugin to use.
381       'id' => 'boolean',
382     ],
383
384     'sort' => [
385       // ID of sort handler plugin to use.
386       'id' => 'standard',
387     ],
388
389     'filter' => [
390       // ID of filter handler plugin to use.
391       'id' => 'boolean',
392       // Override the generic field title, so that the filter uses a different
393       // label in the UI.
394       'label' => t('Published'),
395       // Override the default BooleanOperator filter handler's 'type' setting,
396       // to display this as a "Yes/No" filter instead of a "True/False" filter.
397       'type' => 'yes-no',
398       // Override the default Boolean filter handler's 'use_equal' setting, to
399       // make the query use 'boolean_field = 1' instead of 'boolean_field <> 0'.
400       'use_equal' => TRUE,
401     ],
402   ];
403
404   // Integer timestamp field, exposed as a field, sort, and filter.
405   $data['example_table']['timestamp_field'] = [
406     'title' => t('Timestamp field'),
407     'help' => t('Just a timestamp field.'),
408
409     'field' => [
410       // ID of field handler plugin to use.
411       'id' => 'date',
412     ],
413
414     'sort' => [
415       // ID of sort handler plugin to use.
416       'id' => 'date',
417     ],
418
419     'filter' => [
420       // ID of filter handler plugin to use.
421       'id' => 'date',
422     ],
423   ];
424
425   // Area example. Areas are not generally associated with actual data
426   // tables and fields. This example is from views_views_data(), which defines
427   // the "Global" table (not really a table, but a group of Fields, Filters,
428   // etc. that are grouped into section "Global" in the UI). Here's the
429   // definition of the generic "Text area":
430   $data['views']['area'] = [
431     'title' => t('Text area'),
432     'help' => t('Provide markup text for the area.'),
433     'area' => [
434       // ID of the area handler plugin to use.
435       'id' => 'text',
436     ],
437   ];
438
439   return $data;
440 }
441
442 /**
443  * Alter the table and field information from hook_views_data().
444  *
445  * @param array $data
446  *   An array of all information about Views tables and fields, collected from
447  *   hook_views_data(), passed by reference.
448  *
449  * @see hook_views_data()
450  */
451 function hook_views_data_alter(array &$data) {
452   // Alter the title of the node_field_data:nid field in the Views UI.
453   $data['node_field_data']['nid']['title'] = t('Node-Nid');
454
455   // Add an additional field to the users_field_data table.
456   $data['users_field_data']['example_field'] = [
457     'title' => t('Example field'),
458     'help' => t('Some example content that references a user'),
459
460     'field' => [
461       // ID of the field handler to use.
462       'id' => 'example_field',
463     ],
464   ];
465
466   // Change the handler of the node title field, presumably to a handler plugin
467   // you define in your module. Give the ID of this plugin.
468   $data['node_field_data']['title']['field']['id'] = 'node_title';
469
470   // Add a relationship that will allow a view whose base table is 'foo' (from
471   // another module) to have a relationship to 'example_table' (from my module),
472   // via joining foo.fid to example_table.eid.
473   //
474   // This relationship has to be added to the 'foo' Views data, which my module
475   // does not control, so it must be done in hook_views_data_alter(), not
476   // hook_views_data().
477   //
478   // In Views data definitions, each field can have only one relationship. So
479   // rather than adding this relationship directly to the $data['foo']['fid']
480   // field entry, which could overwrite an existing relationship, we define
481   // a dummy field key to handle the relationship.
482   $data['foo']['unique_dummy_name'] = [
483     'title' => t('Title seen while adding relationship'),
484     'help' => t('More information about the relationship'),
485
486     'relationship' => [
487       // Views name of the table being joined to from foo.
488       'base' => 'example_table',
489       // Database field name in example_table for the join.
490       'base field' => 'eid',
491       // Real database field name in foo for the join, to override
492       // 'unique_dummy_name'.
493       'field' => 'fid',
494       // ID of relationship handler plugin to use.
495       'id' => 'standard',
496       'label' => t('Default label for relationship'),
497     ],
498   ];
499
500   // Note that the $data array is not returned â€“ it is modified by reference.
501 }
502
503 /**
504  * Override the default Views data for a Field API field.
505  *
506  * The field module's implementation of hook_views_data() invokes this for each
507  * field storage, in the module that defines the field type. It is not invoked
508  * in other modules.
509  *
510  * If no hook implementation exists, hook_views_data() falls back to
511  * views_field_default_views_data().
512  *
513  * @param \Drupal\field\FieldStorageConfigInterface $field_storage
514  *   The field storage config entity.
515  *
516  * @return array
517  *   An array of views data, in the same format as the return value of
518  *   hook_views_data().
519  *
520  * @see views_views_data()
521  * @see hook_field_views_data_alter()
522  * @see hook_field_views_data_views_data_alter()
523  */
524 function hook_field_views_data(\Drupal\field\FieldStorageConfigInterface $field_storage) {
525   $data = views_field_default_views_data($field_storage);
526   foreach ($data as $table_name => $table_data) {
527     // Add the relationship only on the target_id field.
528     $data[$table_name][$field_storage->getName() . '_target_id']['relationship'] = [
529       'id' => 'standard',
530       'base' => 'file_managed',
531       'base field' => 'target_id',
532       'label' => t('image from @field_name', ['@field_name' => $field_storage->getName()]),
533     ];
534   }
535
536   return $data;
537 }
538
539 /**
540  * Alter the Views data for a single Field API field.
541  *
542  * This is called on all modules even if there is no hook_field_views_data()
543  * implementation for the field, and therefore may be used to alter the
544  * default data that views_field_default_views_data() supplies for the
545  * field storage.
546  *
547  *  @param array $data
548  *    The views data for the field storage. This has the same format as the
549  *    return value of hook_views_data().
550  *  @param \Drupal\field\FieldStorageConfigInterface $field_storage
551  *    The field storage config entity.
552  *
553  * @see views_views_data()
554  * @see hook_field_views_data()
555  * @see hook_field_views_data_views_data_alter()
556  */
557 function hook_field_views_data_alter(array &$data, \Drupal\field\FieldStorageConfigInterface $field_storage) {
558   $entity_type_id = $field_storage->getTargetEntityTypeId();
559   $field_name = $field_storage->getName();
560   $entity_type = \Drupal::entityManager()->getDefinition($entity_type_id);
561   $pseudo_field_name = 'reverse_' . $field_name . '_' . $entity_type_id;
562   $table_mapping = \Drupal::entityManager()->getStorage($entity_type_id)->getTableMapping();
563
564   list($label) = views_entity_field_label($entity_type_id, $field_name);
565
566   $data['file_managed'][$pseudo_field_name]['relationship'] = [
567     'title' => t('@entity using @field', ['@entity' => $entity_type->getLabel(), '@field' => $label]),
568     'help' => t('Relate each @entity with a @field set to the image.', ['@entity' => $entity_type->getLabel(), '@field' => $label]),
569     'id' => 'entity_reverse',
570     'field_name' => $field_name,
571     'entity_type' => $entity_type_id,
572     'field table' => $table_mapping->getDedicatedDataTableName($field_storage),
573     'field field' => $field_name . '_target_id',
574     'base' => $entity_type->getBaseTable(),
575     'base field' => $entity_type->getKey('id'),
576     'label' => $field_name,
577     'join_extra' => [
578       0 => [
579         'field' => 'deleted',
580         'value' => 0,
581         'numeric' => TRUE,
582       ],
583     ],
584   ];
585 }
586
587 /**
588  * Alter the Views data on a per field basis.
589  *
590  * The field module's implementation of hook_views_data_alter() invokes this for
591  * each field storage, in the module that defines the field type. It is not
592  * invoked in other modules.
593  *
594  * Unlike hook_field_views_data_alter(), this operates on the whole of the views
595  * data. This allows a field type to add data that concerns its fields in
596  * other tables, which would not yet be defined at the point when
597  * hook_field_views_data() and hook_field_views_data_alter() are invoked. For
598  * example, entityreference adds reverse relationships on the tables for the
599  * entities which are referenced by entityreference fields.
600  *
601  * (Note: this is weirdly named so as not to conflict with
602  * hook_field_views_data_alter().)
603  *
604  * @param array $data
605  *   The views data.
606  * @param \Drupal\field\FieldStorageConfigInterface $field
607  *   The field storage config entity.
608  *
609  * @see hook_field_views_data()
610  * @see hook_field_views_data_alter()
611  * @see views_views_data_alter()
612  */
613 function hook_field_views_data_views_data_alter(array &$data, \Drupal\field\FieldStorageConfigInterface $field) {
614   $field_name = $field->getName();
615   $data_key = 'field_data_' . $field_name;
616   $entity_type_id = $field->entity_type;
617   $entity_type = \Drupal::entityManager()->getDefinition($entity_type_id);
618   $pseudo_field_name = 'reverse_' . $field_name . '_' . $entity_type_id;
619   list($label) = views_entity_field_label($entity_type_id, $field_name);
620   $table_mapping = \Drupal::entityManager()->getStorage($entity_type_id)->getTableMapping();
621
622   // Views data for this field is in $data[$data_key].
623   $data[$data_key][$pseudo_field_name]['relationship'] = [
624     'title' => t('@entity using @field', ['@entity' => $entity_type->getLabel(), '@field' => $label]),
625     'help' => t('Relate each @entity with a @field set to the term.', ['@entity' => $entity_type->getLabel(), '@field' => $label]),
626     'id' => 'entity_reverse',
627     'field_name' => $field_name,
628     'entity_type' => $entity_type_id,
629     'field table' => $table_mapping->getDedicatedDataTableName($field),
630     'field field' => $field_name . '_target_id',
631     'base' => $entity_type->getBaseTable(),
632     'base field' => $entity_type->getKey('id'),
633     'label' => $field_name,
634     'join_extra' => [
635       0 => [
636         'field' => 'deleted',
637         'value' => 0,
638         'numeric' => TRUE,
639       ],
640     ],
641   ];
642 }
643
644 /**
645  * Replace special strings in the query before it is executed.
646  *
647  * The idea is that certain dynamic values can be placed in a query when it is
648  * built, and substituted at run-time, allowing the query to be cached and
649  * still work correctly when executed.
650  *
651  * @param \Drupal\views\ViewExecutable $view
652  *   The View being executed.
653  *
654  * @return array
655  *   An associative array where each key is a string to be replaced, and the
656  *   corresponding value is its replacement. The strings to replace are often
657  *   surrounded with '***', as illustrated in the example implementation, to
658  *   avoid collisions with other values in the query.
659  */
660 function hook_views_query_substitutions(ViewExecutable $view) {
661   // Example from views_views_query_substitutions().
662   return [
663     '***CURRENT_VERSION***' => \Drupal::VERSION,
664     '***CURRENT_TIME***' => REQUEST_TIME,
665     '***LANGUAGE_language_content***' => \Drupal::languageManager()->getCurrentLanguage(LanguageInterface::TYPE_CONTENT)->getId(),
666     PluginBase::VIEWS_QUERY_LANGUAGE_SITE_DEFAULT => \Drupal::languageManager()->getDefaultLanguage()->getId(),
667   ];
668 }
669
670 /**
671  * Replace special strings when processing a view with form elements.
672  *
673  * @return array
674  *   An associative array where each key is a string to be replaced, and the
675  *   corresponding value is its replacement. The value will be escaped unless it
676  *   is already marked safe.
677  */
678 function hook_views_form_substitutions() {
679   return [
680     '<!--views-form-example-substitutions-->' => 'Example Substitution',
681   ];
682 }
683
684 /**
685  * Alter a view at the very beginning of Views processing.
686  *
687  * Output can be added to the view by setting $view->attachment_before
688  * and $view->attachment_after.
689  *
690  * @param \Drupal\views\ViewExecutable $view
691  *   The view object about to be processed.
692  * @param string $display_id
693  *   The machine name of the active display.
694  * @param array $args
695  *   An array of arguments passed into the view.
696  *
697  * @see \Drupal\views\ViewExecutable
698  */
699 function hook_views_pre_view(ViewExecutable $view, $display_id, array &$args) {
700
701   // Modify contextual filters for my_special_view if user has 'my special permission'.
702   $account = \Drupal::currentUser();
703
704   if ($view->id() == 'my_special_view' && $account->hasPermission('my special permission') && $display_id == 'public_display') {
705     $args[0] = 'custom value';
706   }
707 }
708
709 /**
710  * Act on the view before the query is built, but after displays are attached.
711  *
712  * Output can be added to the view by setting $view->attachment_before
713  * and $view->attachment_after.
714  *
715  * @param \Drupal\views\ViewExecutable $view
716  *   The view object about to be processed.
717  *
718  * @see \Drupal\views\ViewExecutable
719  */
720 function hook_views_pre_build(ViewExecutable $view) {
721   // Because of some inexplicable business logic, we should remove all
722   // attachments from all views on Mondays.
723   // (This alter could be done later in the execution process as well.)
724   if (date('D') == 'Mon') {
725     unset($view->attachment_before);
726     unset($view->attachment_after);
727   }
728 }
729
730 /**
731  * Act on the view immediately after the query is built.
732  *
733  * Output can be added to the view by setting $view->attachment_before
734  * and $view->attachment_after.
735  *
736  * @param \Drupal\views\ViewExecutable $view
737  *   The view object about to be processed.
738  *
739  * @see \Drupal\views\ViewExecutable
740  */
741 function hook_views_post_build(ViewExecutable $view) {
742   // If the exposed field 'type' is set, hide the column containing the content
743   // type. (Note that this is a solution for a particular view, and makes
744   // assumptions about both exposed filter settings and the fields in the view.
745   // Also note that this alter could be done at any point before the view being
746   // rendered.)
747   if ($view->id() == 'my_view' && isset($view->exposed_raw_input['type']) && $view->exposed_raw_input['type'] != 'All') {
748     // 'Type' should be interpreted as content type.
749     if (isset($view->field['type'])) {
750       $view->field['type']->options['exclude'] = TRUE;
751     }
752   }
753 }
754
755 /**
756  * Act on the view after the query is built and just before it is executed.
757  *
758  * Output can be added to the view by setting $view->attachment_before
759  * and $view->attachment_after.
760  *
761  * @param \Drupal\views\ViewExecutable $view
762  *   The view object about to be processed.
763  *
764  * @see \Drupal\views\ViewExecutable
765  */
766 function hook_views_pre_execute(ViewExecutable $view) {
767   // Whenever a view queries more than two tables, show a message that notifies
768   // view administrators that the query might be heavy.
769   // (This action could be performed later in the execution process, but not
770   // earlier.)
771   $account = \Drupal::currentUser();
772
773   if (count($view->query->tables) > 2 && $account->hasPermission('administer views')) {
774     drupal_set_message(t('The view %view may be heavy to execute.', ['%view' => $view->id()]), 'warning');
775   }
776 }
777
778 /**
779  * Act on the view immediately after the query has been executed.
780  *
781  * At this point the query has been executed, but the preRender() phase has
782  * not yet happened for handlers.
783  *
784  * Output can be added to the view by setting $view->attachment_before
785  * and $view->attachment_after.
786  *
787  * @param \Drupal\views\ViewExecutable $view
788  *   The view object about to be processed.
789  *
790  * @see \Drupal\views\ViewExecutable
791  */
792 function hook_views_post_execute(ViewExecutable $view) {
793   // If there are more than 100 results, show a message that encourages the user
794   // to change the filter settings.
795   // (This action could be performed later in the execution process, but not
796   // earlier.)
797   if ($view->total_rows > 100) {
798     drupal_set_message(t('You have more than 100 hits. Use the filter settings to narrow down your list.'));
799   }
800 }
801
802 /**
803  * Act on the view immediately before rendering it.
804  *
805  * At this point the query has been executed, and the preRender() phase has
806  * already happened for handlers, so all data should be available. This hook
807  * can be used by themes.
808  *
809  * Output can be added to the view by setting $view->attachment_before
810  * and $view->attachment_after.
811  *
812  * @param \Drupal\views\ViewExecutable $view
813  *   The view object about to be processed.
814  *
815  * @see \Drupal\views\ViewExecutable
816  */
817 function hook_views_pre_render(ViewExecutable $view) {
818   // Scramble the order of the rows shown on this result page.
819   // Note that this could be done earlier, but not later in the view execution
820   // process.
821   shuffle($view->result);
822 }
823
824 /**
825  * Post-process any rendered data.
826  *
827  * This can be valuable to be able to cache a view and still have some level of
828  * dynamic output. In an ideal world, the actual output will include HTML
829  * comment-based tokens, and then the post process can replace those tokens.
830  * This hook can be used by themes.
831  *
832  * Example usage. If it is known that the view is a node view and that the
833  * primary field will be a nid, you can do something like this:
834  * @code
835  *   <!--post-FIELD-NID-->
836  * @endcode
837  * And then in the post-render, create an array with the text that should
838  * go there:
839  * @code
840  *   strtr($output, array('<!--post-FIELD-1-->' => 'output for FIELD of nid 1');
841  * @endcode
842  * All of the cached result data will be available in $view->result, as well,
843  * so all ids used in the query should be discoverable.
844  *
845  * @param \Drupal\views\ViewExecutable $view
846  *   The view object about to be processed.
847  * @param string $output
848  *   A flat string with the rendered output of the view.
849  * @param \Drupal\views\Plugin\views\cache\CachePluginBase $cache
850  *   The cache settings.
851  *
852  * @see \Drupal\views\ViewExecutable
853  */
854 function hook_views_post_render(ViewExecutable $view, &$output, CachePluginBase $cache) {
855   // When using full pager, disable any time-based caching if there are fewer
856   // than 10 results.
857   if ($view->pager instanceof Drupal\views\Plugin\views\pager\Full && $cache instanceof Drupal\views\Plugin\views\cache\Time && count($view->result) < 10) {
858     $cache->options['results_lifespan'] = 0;
859     $cache->options['output_lifespan'] = 0;
860   }
861 }
862
863 /**
864  * Alter the query before it is executed.
865  *
866  * @param \Drupal\views\ViewExecutable $view
867  *   The view object about to be processed.
868  * @param QueryPluginBase $query
869  *   The query plugin object for the query.
870  *
871  * @see hook_views_query_substitutions()
872  * @see \Drupal\views\Plugin\views\query\Sql
873  */
874 function hook_views_query_alter(ViewExecutable $view, QueryPluginBase $query) {
875   // (Example assuming a view with an exposed filter on node title.)
876   // If the input for the title filter is a positive integer, filter against
877   // node ID instead of node title.
878   if ($view->id() == 'my_view' && is_numeric($view->exposed_raw_input['title']) && $view->exposed_raw_input['title'] > 0) {
879     // Traverse through the 'where' part of the query.
880     foreach ($query->where as &$condition_group) {
881       foreach ($condition_group['conditions'] as &$condition) {
882         // If this is the part of the query filtering on title, chang the
883         // condition to filter on node ID.
884         if ($condition['field'] == 'node.title') {
885           $condition = [
886             'field' => 'node.nid',
887             'value' => $view->exposed_raw_input['title'],
888             'operator' => '=',
889           ];
890         }
891       }
892     }
893   }
894 }
895
896 /**
897  * Alter the view preview information.
898  *
899  * The view preview information is optionally displayed when a view is
900  * previewed in the administrative UI. It includes query and performance
901  * statistics.
902  *
903  * @param array $rows
904  *   An associative array with two keys:
905  *   - query: An array of rows suitable for '#type' => 'table', containing
906  *     information about the query and the display title and path.
907  *   - statistics: An array of rows suitable for '#type' => 'table',
908  *     containing performance statistics.
909  * @param \Drupal\views\ViewExecutable $view
910  *   The view object.
911  *
912  * @see \Drupal\views_ui\ViewUI
913  * @see table.html.twig
914  */
915 function hook_views_preview_info_alter(array &$rows, ViewExecutable $view) {
916   // Adds information about the tables being queried by the view to the query
917   // part of the info box.
918   $rows['query'][] = [
919     t('<strong>Table queue</strong>'),
920     count($view->query->table_queue) . ': (' . implode(', ', array_keys($view->query->table_queue)) . ')',
921   ];
922 }
923
924 /**
925  * Alter the links displayed at the top of the view edit form.
926  *
927  * @param array $links
928  *   A renderable array of links which will be displayed at the top of the
929  *   view edit form. Each entry will be in a form suitable for
930  *   '#theme' => 'links'.
931  * @param \Drupal\views\ViewExecutable $view
932  *   The view object being edited.
933  * @param string $display_id
934  *   The ID of the display being edited, e.g. 'default' or 'page_1'.
935  *
936  * @see \Drupal\views_ui\ViewUI::renderDisplayTop()
937  */
938 function hook_views_ui_display_top_links_alter(array &$links, ViewExecutable $view, $display_id) {
939   // Put the export link first in the list.
940   if (isset($links['export'])) {
941     $links = ['export' => $links['export']] + $links;
942   }
943 }
944
945 // @todo Describe how to alter a view ajax response with event listeners.
946
947 /**
948  * Allow modules to respond to the invalidation of the Views cache.
949  *
950  * This hook will fire whenever a view is enabled, disabled, created,
951  * updated, or deleted.
952  *
953  * @see views_invalidate_cache()
954  */
955 function hook_views_invalidate_cache() {
956   \Drupal\Core\Cache\Cache::invalidateTags(['views']);
957 }
958
959 /**
960  * Modify the list of available views access plugins.
961  *
962  * This hook may be used to modify plugin properties after they have been
963  * specified by other modules.
964  *
965  * @param array $plugins
966  *   An array of all the existing plugin definitions, passed by reference.
967  *
968  * @see \Drupal\views\Plugin\ViewsPluginManager
969  */
970 function hook_views_plugins_access_alter(array &$plugins) {
971   // Remove the available plugin because the users should not have access to it.
972   unset($plugins['role']);
973 }
974
975 /**
976  * Modify the list of available views default argument plugins.
977  *
978  * This hook may be used to modify plugin properties after they have been
979  * specified by other modules.
980  *
981  * @param array $plugins
982  *   An array of all the existing plugin definitions, passed by reference.
983  *
984  * @see \Drupal\views\Plugin\ViewsPluginManager
985  */
986 function hook_views_plugins_argument_default_alter(array &$plugins) {
987   // Remove the available plugin because the users should not have access to it.
988   unset($plugins['php']);
989 }
990
991 /**
992  * Modify the list of available views argument validation plugins.
993  *
994  * This hook may be used to modify plugin properties after they have been
995  * specified by other modules.
996  *
997  * @param array $plugins
998  *   An array of all the existing plugin definitions, passed by reference.
999  *
1000  * @see \Drupal\views\Plugin\ViewsPluginManager
1001  */
1002 function hook_views_plugins_argument_validator_alter(array &$plugins) {
1003   // Remove the available plugin because the users should not have access to it.
1004   unset($plugins['php']);
1005 }
1006
1007 /**
1008  * Modify the list of available views cache plugins.
1009  *
1010  * This hook may be used to modify plugin properties after they have been
1011  * specified by other modules.
1012  *
1013  * @param array $plugins
1014  *   An array of all the existing plugin definitions, passed by reference.
1015  *
1016  * @see \Drupal\views\Plugin\ViewsPluginManager
1017  */
1018 function hook_views_plugins_cache_alter(array &$plugins) {
1019   // Change the title.
1020   $plugins['time']['title'] = t('Custom title');
1021 }
1022
1023 /**
1024  * Modify the list of available views display extender plugins.
1025  *
1026  * This hook may be used to modify plugin properties after they have been
1027  * specified by other modules.
1028  *
1029  * @param array $plugins
1030  *   An array of all the existing plugin definitions, passed by reference.
1031  *
1032  * @see \Drupal\views\Plugin\ViewsPluginManager
1033  */
1034 function hook_views_plugins_display_extenders_alter(array &$plugins) {
1035   // Alter the title of an existing plugin.
1036   $plugins['time']['title'] = t('Custom title');
1037 }
1038
1039 /**
1040  * Modify the list of available views display plugins.
1041  *
1042  * This hook may be used to modify plugin properties after they have been
1043  * specified by other modules.
1044  *
1045  * @param array $plugins
1046  *   An array of all the existing plugin definitions, passed by reference.
1047  *
1048  * @see \Drupal\views\Plugin\ViewsPluginManager
1049  */
1050 function hook_views_plugins_display_alter(array &$plugins) {
1051   // Alter the title of an existing plugin.
1052   $plugins['rest_export']['title'] = t('Export');
1053 }
1054
1055 /**
1056  * Modify the list of available views exposed form plugins.
1057  *
1058  * This hook may be used to modify plugin properties after they have been
1059  * specified by other modules.
1060  *
1061  * @param array $plugins
1062  *   An array of all the existing plugin definitions, passed by reference.
1063  *
1064  * @see \Drupal\views\Plugin\ViewsPluginManager
1065  */
1066 function hook_views_plugins_exposed_form_alter(array &$plugins) {
1067   // Remove the available plugin because the users should not have access to it.
1068   unset($plugins['input_required']);
1069 }
1070
1071 /**
1072  * Modify the list of available views join plugins.
1073  *
1074  * This hook may be used to modify plugin properties after they have been
1075  * specified by other modules.
1076  *
1077  * @param array $plugins
1078  *   An array of all the existing plugin definitions, passed by reference.
1079  *
1080  * @see \Drupal\views\Plugin\ViewsPluginManager
1081  */
1082 function hook_views_plugins_join_alter(array &$plugins) {
1083   // Print out all join plugin names for debugging purposes.
1084   debug($plugins);
1085 }
1086
1087 /**
1088  * Modify the list of available views pager plugins.
1089  *
1090  * This hook may be used to modify plugin properties after they have been
1091  * specified by other modules.
1092  *
1093  * @param array $plugins
1094  *   An array of all the existing plugin definitions, passed by reference.
1095  *
1096  * @see \Drupal\views\Plugin\ViewsPluginManager
1097  */
1098 function hook_views_plugins_pager_alter(array &$plugins) {
1099   // Remove the sql based plugin to force good performance.
1100   unset($plugins['full']);
1101 }
1102
1103 /**
1104  * Modify the list of available views query plugins.
1105  *
1106  * This hook may be used to modify plugin properties after they have been
1107  * specified by other modules.
1108  *
1109  * @param array $plugins
1110  *   An array of all the existing plugin definitions, passed by reference.
1111  *
1112  * @see \Drupal\views\Plugin\ViewsPluginManager
1113  */
1114 function hook_views_plugins_query_alter(array &$plugins) {
1115   // Print out all query plugin names for debugging purposes.
1116   debug($plugins);
1117 }
1118
1119 /**
1120  * Modify the list of available views row plugins.
1121  *
1122  * This hook may be used to modify plugin properties after they have been
1123  * specified by other modules.
1124  *
1125  * @param array $plugins
1126  *   An array of all the existing plugin definitions, passed by reference.
1127  *
1128  * @see \Drupal\views\Plugin\ViewsPluginManager
1129  */
1130 function hook_views_plugins_row_alter(array &$plugins) {
1131   // Change the used class of a plugin.
1132   $plugins['entity:node']['class'] = 'Drupal\node\Plugin\views\row\NodeRow';
1133   $plugins['entity:node']['module'] = 'node';
1134 }
1135
1136 /**
1137  * Modify the list of available views style plugins.
1138  *
1139  * This hook may be used to modify plugin properties after they have been
1140  * specified by other modules.
1141  *
1142  * @param array $plugins
1143  *   An array of all the existing plugin definitions, passed by reference.
1144  *
1145  * @see \Drupal\views\Plugin\ViewsPluginManager
1146  */
1147 function hook_views_plugins_style_alter(array &$plugins) {
1148   // Change the theme hook of a plugin.
1149   $plugins['html_list']['theme'] = 'custom_views_view_list';
1150 }
1151
1152 /**
1153  * Modify the list of available views wizard plugins.
1154  *
1155  * This hook may be used to modify plugin properties after they have been
1156  * specified by other modules.
1157  *
1158  * @param array $plugins
1159  *   An array of all the existing plugin definitions, passed by reference.
1160  *
1161  * @see \Drupal\views\Plugin\ViewsPluginManager
1162  */
1163 function hook_views_plugins_wizard_alter(array &$plugins) {
1164   // Change the title of a plugin.
1165   $plugins['node_revision']['title'] = t('Node revision wizard');
1166 }
1167
1168 /**
1169  * Modify the list of available views area handler plugins.
1170  *
1171  * This hook may be used to modify handler properties after they have been
1172  * specified by other modules.
1173  *
1174  * @param array $plugins
1175  *   An array of all the existing handler definitions, passed by reference.
1176  *
1177  * @see \Drupal\views\Plugin\ViewsHandlerManager
1178  */
1179 function hook_views_plugins_area_alter(array &$plugins) {
1180   // Change the 'title' handler class.
1181   $plugins['title']['class'] = 'Drupal\\example\\ExampleClass';
1182 }
1183
1184 /**
1185  * Modify the list of available views argument handler plugins.
1186  *
1187  * This hook may be used to modify handler properties after they have been
1188  * specified by other modules.
1189  *
1190  * @param array $plugins
1191  *   An array of all the existing handler definitions, passed by reference.
1192  *
1193  * @see \Drupal\views\Plugin\ViewsHandlerManager
1194  */
1195 function hook_views_plugins_argument_alter(array &$plugins) {
1196   // Change the 'title' handler class.
1197   $plugins['title']['class'] = 'Drupal\\example\\ExampleClass';
1198 }
1199
1200 /**
1201  * Modify the list of available views field handler plugins.
1202  *
1203  * This hook may be used to modify handler properties after they have been
1204  * specified by other modules.
1205  *
1206  * @param array $plugins
1207  *   An array of all the existing handler definitions, passed by reference.
1208  *
1209  * @see \Drupal\views\Plugin\ViewsHandlerManager
1210  */
1211 function hook_views_plugins_field_alter(array &$plugins) {
1212   // Change the 'title' handler class.
1213   $plugins['title']['class'] = 'Drupal\\example\\ExampleClass';
1214 }
1215
1216 /**
1217  * Modify the list of available views filter handler plugins.
1218  *
1219  * This hook may be used to modify handler properties after they have been
1220  * specified by other modules.
1221  *
1222  * @param array $plugins
1223  *   An array of all the existing handler definitions, passed by reference.
1224  *
1225  * @see \Drupal\views\Plugin\ViewsHandlerManager
1226  */
1227 function hook_views_plugins_filter_alter(array &$plugins) {
1228   // Change the 'title' handler class.
1229   $plugins['title']['class'] = 'Drupal\\example\\ExampleClass';
1230 }
1231
1232 /**
1233  * Modify the list of available views relationship handler plugins.
1234  *
1235  * This hook may be used to modify handler properties after they have been
1236  * specified by other modules.
1237  *
1238  * @param array $plugins
1239  *   An array of all the existing handler definitions, passed by reference.
1240  *
1241  * @see \Drupal\views\Plugin\ViewsHandlerManager
1242  */
1243 function hook_views_plugins_relationship_alter(array &$plugins) {
1244   // Change the 'title' handler class.
1245   $plugins['title']['class'] = 'Drupal\\example\\ExampleClass';
1246 }
1247
1248 /**
1249  * Modify the list of available views sort handler plugins.
1250  *
1251  * This hook may be used to modify handler properties after they have been
1252  * specified by other modules.
1253  *
1254  * @param array $plugins
1255  *   An array of all the existing handler definitions, passed by reference.
1256  *
1257  * @see \Drupal\views\Plugin\ViewsHandlerManager
1258  */
1259 function hook_views_plugins_sort_alter(array &$plugins) {
1260   // Change the 'title' handler class.
1261   $plugins['title']['class'] = 'Drupal\\example\\ExampleClass';
1262 }
1263
1264 /**
1265  * @} End of "addtogroup hooks".
1266  */
1267
1268 /**
1269  * @}
1270  */