views.api.php 24 KB
Newer Older
merlinofchaos's avatar
merlinofchaos committed
1 2 3 4
<?php

/**
 * @file
5
 * Describes hooks and plugins provided by the Views module.
merlinofchaos's avatar
merlinofchaos committed
6 7 8
 */

/**
9
 * @defgroup views_plugins Views plugins
merlinofchaos's avatar
merlinofchaos committed
10
 *
11
 * Views plugins are objects that are used to build and render the view.
12 13
 * Plugins are registered by extending one of the Views base plugin classes
 * and defining settings in the plugin annotation.
merlinofchaos's avatar
merlinofchaos committed
14
 *
15 16 17 18
 * Views has the following types of plugins:
 * - Access: Access plugins are responsible for controlling access to the
 *   view. Views includes plugins for checking user roles and individual
 *   permissions. Access plugins extend
19
 *   \Drupal\views\Plugin\views\access\AccessPluginBase.
20 21 22 23 24
 * - Argument default: Argument default plugins allow pluggable ways of
 *   providing default values for contextual filters. This is useful for
 *   blocks and other display types lacking a natural argument input.
 *   Examples are plugins to extract node and user IDs from the URL. Argument
 *   default plugins extend
25
 *   \Drupal\views\Plugin\views\argument_default\ArgumentDefaultPluginBase.
26 27 28 29 30 31
 * - Argument validator: Validator plugins can ensure arguments are valid,
 *   and even do transformations on the arguments. They can also provide
 *   replacement patterns for the view title. For example, the 'content'
 *   validator verifies verifies that the argument value corresponds to a
 *   node, loads that node and provides the node title as a replacement
 *   pattern. Argument validator plugins extend
32
 *   \Drupal\views\Plugin\views\argument_validator\ArgumentValidatorPluginBase.
33 34 35
 * - Cache: Cache plugins control the storage and loading of caches.
 *   Currently they can do both result and render caching. It might also be
 *   possible to cache the generated query. Cache plugins extend
36
 *   \Drupal\views\Plugin\views\cache\CachePluginBase.
37 38 39 40 41
 * - Display: Display plugins are responsible for controlling where a View is
 *   rendered; that is, how it is exposed to other parts of Drupal. 'Page'
 *   and 'block' are the most commonly used display plugins. Each View also
 *   has a 'master' (or 'default') display that includes information shared
 *   between all its displays. (See
42 43
 *   \Drupal\views\Plugin\views\display\DefaultDisplay.) Display plugins extend
 *   \Drupal\views\Plugin\views\display\DisplayPluginBase.
44 45 46 47 48
 * - Display extender: Display extender plugins allow additional options or
 *   configurations to added to views across all display types. For example,
 *   if you wanted to allow site users to add certain metadata to the rendered
 *   output of every view display regardless of display type, you could provide
 *   this option as a display extender. Display extender plugins extend
49
 *   \Drupal\views\Plugin\views\display_extender\DisplayExtenderPluginBase.
50 51
 * - Exposed form: Exposed form plugins are responsible for building,
 *   rendering, and controlling exposed forms. Exposed form plugins extend
52
 *   \Drupal\views\Plugin\views\display\DisplayPluginBase.
53 54 55
 * - Handlers: Handler plugins help build the view query object that the query
 *   plugin then executes to retrieve the data from the storage backend (see
 *   below). There are several types of handlers:
56
 *   - Area handlers: Extend \Drupal\views\Plugin\views\area\AreaHandlerBase
57
 *   - Argument handlers: Extend
58 59
 *     \Drupal\views\Plugin\views\argument\ArgumentHandlerBase
 *   - Field handlers: Extend \Drupal\views\Plugin\views\field\FieldHandlerBase
60
 *   - Filter handlers: Extend
61
 *     \Drupal\views\Plugin\views\filter\FilterHandlerBase
62
 *   - Relationship handlers:
63 64
 *     Extend \Drupal\views\Plugin\views\relationship\RelationshipHandlerBase
 *   - Sort handlers: Extend \Drupal\views\Plugin\views\sort:SortHandlerBase
65 66 67
 * - Pager: Pager plugins take care of everything regarding pagers, including
 *   getting setting the total number of items to render the pager and
 *   setting the global pager arrays. Pager plugins extend
68
 *   \Drupal\views\Plugin\views\pager\PagerPluginBase.
69 70 71 72
 * - Query: Query plugins generate and execute a built query object against a
 *   particular storage backend, converting the Views query object into an
 *   actual query. The only default implementation is SQL. (Note that most
 *   handler plugins currently rely on the SQL query plugin.) Query plugins
73
 *   extend \Drupal\views\Plugin\views\query\QueryPluginBase.
74 75 76
 * - Row style: Row styles handle rendering each individual record from the
 *   main view table. The two default implementations render the entire entity
 *   (nodes only), or selected fields. Row style plugins extend
77
 *   \Drupal\views\Plugin\views\row\RowPluginBase).
78 79 80
 * - Style: Style plugins control how a view is displayed. For the most part
 *   they are object wrappers around theme templates. Examples of styles
 *   include HTML lists, tables, etc. Style plugins extend
81
 *   \Drupal\views\Plugin\views\style\StylePluginBase.
82 83
 *
 * @todo Add an explanation for each type of handler.
84 85 86 87 88
 * @todo Document how to use annotations and what goes in them.
 * @todo Add @ingroup to all the base plugins for this group.
 * @todo Add a separate @ingroup for all plugins?
 * @todo Document specific options on the appropriate plugin base classes.
 * @todo Add examples.
merlinofchaos's avatar
merlinofchaos committed
89
 *
90 91
 * @see \Drupal\views\Plugin\views\PluginBase
 * @see \Drupal\views\Plugin\views\HandlerBase
merlinofchaos's avatar
merlinofchaos committed
92 93 94 95 96
 */

/**
 * @defgroup views_hooks Views hooks
 * @{
97
 * Hooks that allow other modules to implement the Views API.
merlinofchaos's avatar
merlinofchaos committed
98 99 100
 */

/**
101
 * Describe data tables (or the equivalent) to Views.
102
 *
103
 * The data described with this hook is fetched and retrieved by
104
 * drupal_container()->get('views.views_data')->get().
105
 *
106
 * @return array
merlinofchaos's avatar
merlinofchaos committed
107
 *   An associative array describing the data structure. Primary key is the
108
 *   name used internally by Views for the table(s) – usually the actual table
merlinofchaos's avatar
merlinofchaos committed
109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124
 *   name. The values for the key entries are described in detail below.
 */
function hook_views_data() {
  // This example describes how to write hook_views_data() for the following
  // table:
  //
  // CREATE TABLE example_table (
  //   nid INT(11) NOT NULL         COMMENT 'Primary key; refers to {node}.nid.',
  //   plain_text_field VARCHAR(32) COMMENT 'Just a plain text field.',
  //   numeric_field INT(11)        COMMENT 'Just a numeric field.',
  //   boolean_field INT(1)         COMMENT 'Just an on/off field.',
  //   timestamp_field INT(8)       COMMENT 'Just a timestamp field.',
  //   PRIMARY KEY(nid)
  // );

  // First, the entry $data['example_table']['table'] describes properties of
125
  // the actual table – not its content.
merlinofchaos's avatar
merlinofchaos committed
126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160

  // The 'group' index will be used as a prefix in the UI for any of this
  // table's fields, sort criteria, etc. so it's easy to tell where they came
  // from.
  $data['example_table']['table']['group'] = t('Example table');

  // Define this as a base table – a table that can be described in itself by
  // views (and not just being brought in as a relationship). In reality this
  // is not very useful for this table, as it isn't really a distinct object of
  // its own, but it makes a good example.
  $data['example_table']['table']['base'] = array(
    'field' => 'nid', // This is the identifier field for the view.
    'title' => t('Example table'),
    'help' => t('Example table contains example content and can be related to nodes.'),
    'weight' => -10,
  );

  // This table references the {node} table. The declaration below creates an
  // 'implicit' relationship to the node table, so that when 'node' is the base
  // table, the fields are automatically available.
  $data['example_table']['table']['join'] = array(
    // Index this array by the table name to which this table refers.
    // 'left_field' is the primary key in the referenced table.
    // 'field' is the foreign key in this table.
    'node' => array(
      'left_field' => 'nid',
      'field' => 'nid',
    ),
  );

  // Next, describe each of the individual fields in this table to Views. This
  // is done by describing $data['example_table']['FIELD_NAME']. This part of
  // the array may then have further entries:
  //   - title: The label for the table field, as presented in Views.
  //   - help: The description text for the table field.
161 162
  //   - relationship: A description of any relationship handler for the table
  //     field.
merlinofchaos's avatar
merlinofchaos committed
163 164 165 166 167 168 169 170 171 172 173 174 175
  //   - field: A description of any field handler for the table field.
  //   - sort: A description of any sort handler for the table field.
  //   - filter: A description of any filter handler for the table field.
  //   - argument: A description of any argument handler for the table field.
  //   - area: A description of any handler for adding content to header,
  //     footer or as no result behaviour.
  //
  // The handler descriptions are described with examples below.

  // Node ID table field.
  $data['example_table']['nid'] = array(
    'title' => t('Example content'),
    'help' => t('Some example content that references a node.'),
176 177 178 179
    // Define a relationship to the {node} table, so example_table views can
    // add a relationship to nodes. If you want to define a relationship the
    // other direction, use hook_views_data_alter(), or use the 'implicit' join
    // method described above.
merlinofchaos's avatar
merlinofchaos committed
180
    'relationship' => array(
dawehner's avatar
dawehner committed
181 182
      'base' => 'node', // The name of the table to join with
      'field' => 'nid', // The name of the field to join with
aspilicious's avatar
aspilicious committed
183
      'id' => 'standard',
dawehner's avatar
dawehner committed
184
      'label' => t('Example node'),
merlinofchaos's avatar
merlinofchaos committed
185 186 187 188 189 190 191 192
    ),
  );

  // Example plain text field.
  $data['example_table']['plain_text_field'] = array(
    'title' => t('Plain text field'),
    'help' => t('Just a plain text field.'),
    'field' => array(
aspilicious's avatar
aspilicious committed
193
      'id' => 'standard',
merlinofchaos's avatar
merlinofchaos committed
194 195 196
      'click sortable' => TRUE, // This is use by the table display plugin.
    ),
    'sort' => array(
aspilicious's avatar
aspilicious committed
197
      'id' => 'standard',
merlinofchaos's avatar
merlinofchaos committed
198 199
    ),
    'filter' => array(
aspilicious's avatar
aspilicious committed
200
      'id' => 'string',
merlinofchaos's avatar
merlinofchaos committed
201 202
    ),
    'argument' => array(
aspilicious's avatar
aspilicious committed
203
      'id' => 'string',
merlinofchaos's avatar
merlinofchaos committed
204 205 206 207 208 209 210 211
    ),
  );

  // Example numeric text field.
  $data['example_table']['numeric_field'] = array(
    'title' => t('Numeric field'),
    'help' => t('Just a numeric field.'),
    'field' => array(
aspilicious's avatar
aspilicious committed
212
      'id' => 'numeric',
merlinofchaos's avatar
merlinofchaos committed
213 214 215
      'click sortable' => TRUE,
     ),
    'filter' => array(
aspilicious's avatar
aspilicious committed
216
      'id' => 'numeric',
merlinofchaos's avatar
merlinofchaos committed
217 218
    ),
    'sort' => array(
aspilicious's avatar
aspilicious committed
219
      'id' => 'standard',
merlinofchaos's avatar
merlinofchaos committed
220 221 222 223 224 225 226 227
    ),
  );

  // Example boolean field.
  $data['example_table']['boolean_field'] = array(
    'title' => t('Boolean field'),
    'help' => t('Just an on/off field.'),
    'field' => array(
aspilicious's avatar
aspilicious committed
228
      'id' => 'boolean',
merlinofchaos's avatar
merlinofchaos committed
229 230 231
      'click sortable' => TRUE,
    ),
    'filter' => array(
aspilicious's avatar
aspilicious committed
232
      'id' => 'boolean',
merlinofchaos's avatar
merlinofchaos committed
233 234 235 236 237
      // Note that you can override the field-wide label:
      'label' => t('Published'),
      // This setting is used by the boolean filter handler, as possible option.
      'type' => 'yes-no',
      // use boolean_field = 1 instead of boolean_field <> 0 in WHERE statment.
238
      'use_equal' => TRUE,
merlinofchaos's avatar
merlinofchaos committed
239 240
    ),
    'sort' => array(
aspilicious's avatar
aspilicious committed
241
      'id' => 'standard',
merlinofchaos's avatar
merlinofchaos committed
242 243 244 245 246 247 248 249
    ),
  );

  // Example timestamp field.
  $data['example_table']['timestamp_field'] = array(
    'title' => t('Timestamp field'),
    'help' => t('Just a timestamp field.'),
    'field' => array(
aspilicious's avatar
aspilicious committed
250
      'id' => 'date',
merlinofchaos's avatar
merlinofchaos committed
251 252 253
      'click sortable' => TRUE,
    ),
    'sort' => array(
aspilicious's avatar
aspilicious committed
254
      'id' => 'date',
merlinofchaos's avatar
merlinofchaos committed
255 256
    ),
    'filter' => array(
aspilicious's avatar
aspilicious committed
257
      'id' => 'date',
merlinofchaos's avatar
merlinofchaos committed
258 259 260 261 262 263 264
    ),
  );

  return $data;
}

/**
265
 * Alter the table structure defined by hook_views_data().
merlinofchaos's avatar
merlinofchaos committed
266
 *
267
 * @param array $data
268 269
 *   An array of all Views data, passed by reference. See hook_views_data() for
 *   structure.
merlinofchaos's avatar
merlinofchaos committed
270 271 272
 *
 * @see hook_views_data()
 */
273
function hook_views_data_alter(array &$data) {
274
  // This example alters the title of the node:nid field in the Views UI.
merlinofchaos's avatar
merlinofchaos committed
275 276
  $data['node']['nid']['title'] = t('Node-Nid');

277
  // This example adds an example field to the users table.
merlinofchaos's avatar
merlinofchaos committed
278 279 280 281 282 283 284
  $data['users']['example_field'] = array(
    'title' => t('Example field'),
    'help' => t('Some example content that references a user'),
    'handler' => 'hook_handlers_field_example_field',
  );

  // This example changes the handler of the node title field.
285
  // In this handler you could do stuff, like preview of the node when clicking
merlinofchaos's avatar
merlinofchaos committed
286 287 288
  // the node title.
  $data['node']['title']['handler'] = 'modulename_handlers_field_node_title';

289 290 291 292 293 294 295 296 297 298 299
  // This example adds a relationship to table {foo}, so that 'foo' views can
  // add this table using a relationship. Because we don't want to write over
  // the primary key field definition for the {foo}.fid field, we use a dummy
  // field name as the key.
  $data['foo']['dummy_name'] = array(
    'title' => t('Example relationship'),
    'help' => t('Example help'),
    'relationship' => array(
      'base' => 'example_table', // Table we're joining to.
      'base field' => 'eid', // Field on the joined table.
      'field' => 'fid', // Real field name on the 'foo' table.
aspilicious's avatar
aspilicious committed
300
      'id' => 'standard',
301 302 303 304 305 306
      'label' => t('Default label for relationship'),
      'title' => t('Title seen when adding relationship'),
      'help' => t('More information about relationship.'),
    ),
  );

merlinofchaos's avatar
merlinofchaos committed
307 308 309 310
  // Note that the $data array is not returned – it is modified by reference.
}

/**
311
 * Replace special strings in the query before it is executed.
merlinofchaos's avatar
merlinofchaos committed
312
 *
313
 * @param \Drupal\views\ViewExecutable $view
merlinofchaos's avatar
merlinofchaos committed
314
 *   The View being executed.
315 316 317 318
 * @return array
 *   An associative array where each key is a string to be replaced, and the
 *   corresponding value is its replacement. The strings to replace are often
 *   surrounded with '***', as illustrated in the example implementation.
merlinofchaos's avatar
merlinofchaos committed
319
 */
320
function hook_views_query_substitutions(ViewExecutable $view) {
merlinofchaos's avatar
merlinofchaos committed
321 322 323 324
  // Example from views_views_query_substitutions().
  return array(
    '***CURRENT_VERSION***' => VERSION,
    '***CURRENT_TIME***' => REQUEST_TIME,
325
    '***CURRENT_LANGUAGE***' => language(LANGUAGE_TYPE_CONTENT)->langcode,
326
    '***DEFAULT_LANGUAGE***' => language_default()->langcode,
merlinofchaos's avatar
merlinofchaos committed
327 328 329 330
  );
}

/**
331
 * Replace special strings when processing a view with form elements.
merlinofchaos's avatar
merlinofchaos committed
332
 *
333 334 335
 * @return array
 *   An associative array where each key is a string to be replaced, and the
 *   corresponding value is its replacement.
merlinofchaos's avatar
merlinofchaos committed
336 337 338 339 340 341 342 343
 */
function hook_views_form_substitutions() {
  return array(
    '<!--views-form-example-substitutions-->' => 'Example Substitution',
  );
}

/**
344
 * Alter a view at the very beginning of Views processing.
merlinofchaos's avatar
merlinofchaos committed
345
 *
346 347 348
 * Output can be added to the view by setting $view->attachment_before
 * and $view->attachment_after.
 *
349
 * @param \Drupal\views\ViewExecutable $view
merlinofchaos's avatar
merlinofchaos committed
350
 *   The view object about to be processed.
351
 * @param string $display_id
merlinofchaos's avatar
merlinofchaos committed
352
 *   The machine name of the active display.
353
 * @param array $args
merlinofchaos's avatar
merlinofchaos committed
354
 *   An array of arguments passed into the view.
355
 *
356
 * @see \Drupal\views\ViewExecutable
merlinofchaos's avatar
merlinofchaos committed
357
 */
358
function hook_views_pre_view(ViewExecutable &$view, &$display_id, array &$args) {
merlinofchaos's avatar
merlinofchaos committed
359 360
  // Change the display if the acting user has 'administer site configuration'
  // permission, to display something radically different.
361 362 363
  // @todo Note that this is not necessarily the best way to solve that task.
  //   Add a better example.
  if ($view->name == 'my_special_view' && user_access('administer site configuration') && $display_id == 'public_display') {
merlinofchaos's avatar
merlinofchaos committed
364 365 366 367 368
    $display_id = 'private_display';
  }
}

/**
369
 * Act on the view before the query is built, but after displays are attached.
merlinofchaos's avatar
merlinofchaos committed
370
 *
371 372 373
 * Output can be added to the view by setting $view->attachment_before
 * and $view->attachment_after.
 *
374
 * @param \Drupal\views\ViewExecutable $view
merlinofchaos's avatar
merlinofchaos committed
375
 *   The view object about to be processed.
376
 *
377
 * @see \Drupal\views\ViewExecutable
merlinofchaos's avatar
merlinofchaos committed
378
 */
379
function hook_views_pre_build(ViewExecutable &$view) {
merlinofchaos's avatar
merlinofchaos committed
380 381 382 383 384 385 386 387 388 389
  // Because of some unexplicable business logic, we should remove all
  // attachments from all views on Mondays.
  // (This alter could be done later in the execution process as well.)
  if (date('D') == 'Mon') {
    unset($view->attachment_before);
    unset($view->attachment_after);
  }
}

/**
390
 * Act on the view immediately after the query is built.
merlinofchaos's avatar
merlinofchaos committed
391
 *
392 393 394
 * Output can be added to the view by setting $view->attachment_before
 * and $view->attachment_after.
 *
395
 * @param \Drupal\views\ViewExecutable $view
merlinofchaos's avatar
merlinofchaos committed
396
 *   The view object about to be processed.
397
 *
398
 * @see \Drupal\views\ViewExecutable
merlinofchaos's avatar
merlinofchaos committed
399
 */
400
function hook_views_post_build(ViewExecutable &$view) {
merlinofchaos's avatar
merlinofchaos committed
401 402 403 404 405 406 407 408 409 410 411 412 413 414
  // If the exposed field 'type' is set, hide the column containing the content
  // type. (Note that this is a solution for a particular view, and makes
  // assumptions about both exposed filter settings and the fields in the view.
  // Also note that this alter could be done at any point before the view being
  // rendered.)
  if ($view->name == 'my_view' && isset($view->exposed_raw_input['type']) && $view->exposed_raw_input['type'] != 'All') {
    // 'Type' should be interpreted as content type.
    if (isset($view->field['type'])) {
      $view->field['type']->options['exclude'] = TRUE;
    }
  }
}

/**
415
 * Act on the view after the query is built and just before it is executed.
merlinofchaos's avatar
merlinofchaos committed
416
 *
417 418 419
 * Output can be added to the view by setting $view->attachment_before
 * and $view->attachment_after.
 *
420
 * @param \Drupal\views\ViewExecutable $view
merlinofchaos's avatar
merlinofchaos committed
421
 *   The view object about to be processed.
422
 *
423
 * @see \Drupal\views\ViewExecutable
merlinofchaos's avatar
merlinofchaos committed
424
 */
425
function hook_views_pre_execute(ViewExecutable &$view) {
merlinofchaos's avatar
merlinofchaos committed
426 427 428 429 430 431 432 433 434 435
  // Whenever a view queries more than two tables, show a message that notifies
  // view administrators that the query might be heavy.
  // (This action could be performed later in the execution process, but not
  // earlier.)
  if (count($view->query->tables) > 2 && user_access('administer views')) {
    drupal_set_message(t('The view %view may be heavy to execute.', array('%view' => $view->name)), 'warning');
  }
}

/**
436
 * Act on the view immediately after the query has been executed.
merlinofchaos's avatar
merlinofchaos committed
437
 *
438 439 440 441 442 443
 * At this point the query has been executed, but the pre_render() phase has
 * not yet happened for handlers.
 *
 * Output can be added to the view by setting $view->attachment_before
 * and $view->attachment_after.
 *
444
 * @param \Drupal\views\ViewExecutable $view
merlinofchaos's avatar
merlinofchaos committed
445
 *   The view object about to be processed.
446
 *
447
 * @see \Drupal\views\ViewExecutable
merlinofchaos's avatar
merlinofchaos committed
448
 */
449
function hook_views_post_execute(ViewExecutable &$view) {
merlinofchaos's avatar
merlinofchaos committed
450 451 452 453 454 455 456 457 458 459
  // If there are more than 100 results, show a message that encourages the user
  // to change the filter settings.
  // (This action could be performed later in the execution process, but not
  // earlier.)
  if ($view->total_rows > 100) {
    drupal_set_message(t('You have more than 100 hits. Use the filter settings to narrow down your list.'));
  }
}

/**
460
 * Act on the view immediately before rendering it.
merlinofchaos's avatar
merlinofchaos committed
461
 *
462 463 464
 * At this point the query has been executed, and the pre_render() phase has
 * already happened for handlers, so all data should be available. This hook
 * can be utilized by themes.
merlinofchaos's avatar
merlinofchaos committed
465
 *
466 467 468
 * Output can be added to the view by setting $view->attachment_before
 * and $view->attachment_after.
 *
469
 * @param \Drupal\views\ViewExecutable $view
merlinofchaos's avatar
merlinofchaos committed
470
 *   The view object about to be processed.
471
 *
472
 * @see \Drupal\views\ViewExecutable
merlinofchaos's avatar
merlinofchaos committed
473
 */
474
function hook_views_pre_render(ViewExecutable &$view) {
merlinofchaos's avatar
merlinofchaos committed
475 476 477 478 479 480 481
  // Scramble the order of the rows shown on this result page.
  // Note that this could be done earlier, but not later in the view execution
  // process.
  shuffle($view->result);
}

/**
482
 * Post-process any rendered data.
merlinofchaos's avatar
merlinofchaos committed
483 484 485
 *
 * This can be valuable to be able to cache a view and still have some level of
 * dynamic output. In an ideal world, the actual output will include HTML
486 487
 * comment-based tokens, and then the post process can replace those tokens.
 * This hook can be utilized by themes.
merlinofchaos's avatar
merlinofchaos committed
488 489 490
 *
 * Example usage. If it is known that the view is a node view and that the
 * primary field will be a nid, you can do something like this:
491 492 493 494
 * @code
 *   <!--post-FIELD-NID-->
 * @encode
 * And then in the post-render, create an array with the text that should
merlinofchaos's avatar
merlinofchaos committed
495
 * go there:
496 497 498
 * @code
 *   strtr($output, array('<!--post-FIELD-1-->' => 'output for FIELD of nid 1');
 * @encode
merlinofchaos's avatar
merlinofchaos committed
499 500 501
 * All of the cached result data will be available in $view->result, as well,
 * so all ids used in the query should be discoverable.
 *
502
 * @param \Drupal\views\ViewExecutable $view
merlinofchaos's avatar
merlinofchaos committed
503
 *   The view object about to be processed.
504
 * @param string $output
merlinofchaos's avatar
merlinofchaos committed
505
 *   A flat string with the rendered output of the view.
506
 * @param CacheBackendInterface $cache
merlinofchaos's avatar
merlinofchaos committed
507
 *   The cache settings.
508
 *
509
 * @see \Drupal\views\ViewExecutable
merlinofchaos's avatar
merlinofchaos committed
510
 */
511 512 513 514 515 516
function hook_views_post_render(ViewExecutable &$view, &$output, CacheBackendInterface &$cache) {
  // When using full pager, disable any time-based caching if there are fewer
  // than 10 results.
  if ($view->pager instanceof Drupal\views\Plugin\views\pager\Full && $cache instanceof Drupal\views\Plugin\views\cache\Time && count($view->result) < 10) {
    $cache->options['results_lifespan'] = 0;
    $cache->options['output_lifespan'] = 0;
merlinofchaos's avatar
merlinofchaos committed
517 518 519 520
  }
}

/**
521
 * Alter the query before it is executed.
merlinofchaos's avatar
merlinofchaos committed
522
 *
523
 * @param \Drupal\views\ViewExecutable $view
merlinofchaos's avatar
merlinofchaos committed
524
 *   The view object about to be processed.
525 526 527
 * @param QueryPluginBase $query
 *   The query plugin object for the query.
 *
merlinofchaos's avatar
merlinofchaos committed
528
 * @see hook_views_query_substitutions()
529
 * @see \Drupal\views\Plugin\views\query\Sql
merlinofchaos's avatar
merlinofchaos committed
530
 */
531
function hook_views_query_alter(ViewExecutable &$view, QueryPluginBase &$query) {
merlinofchaos's avatar
merlinofchaos committed
532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553
  // (Example assuming a view with an exposed filter on node title.)
  // If the input for the title filter is a positive integer, filter against
  // node ID instead of node title.
  if ($view->name == 'my_view' && is_numeric($view->exposed_raw_input['title']) && $view->exposed_raw_input['title'] > 0) {
    // Traverse through the 'where' part of the query.
    foreach ($query->where as &$condition_group) {
      foreach ($condition_group['conditions'] as &$condition) {
        // If this is the part of the query filtering on title, chang the
        // condition to filter on node ID.
        if ($condition['field'] == 'node.title') {
          $condition = array(
            'field' => 'node.nid',
            'value' => $view->exposed_raw_input['title'],
            'operator' => '=',
          );
        }
      }
    }
  }
}

/**
554 555 556 557 558
 * Alter the view preview information.
 *
 * The view preview information is optionally displayed when a view is
 * previewed in the administrative UI. It includes query and performance
 * statistics.
merlinofchaos's avatar
merlinofchaos committed
559
 *
560
 * @param array $rows
merlinofchaos's avatar
merlinofchaos committed
561 562 563 564 565
 *   An associative array with two keys:
 *   - query: An array of rows suitable for theme('table'), containing
 *     information about the query and the display title and path.
 *   - statistics: An array of rows suitable for theme('table'), containing
 *     performance statistics.
566
 * @param \Drupal\views\ViewExecutable $view
merlinofchaos's avatar
merlinofchaos committed
567
 *   The view object.
568
 *
569
 * @see \Drupal\views_ui\ViewUI
merlinofchaos's avatar
merlinofchaos committed
570 571
 * @see theme_table()
 */
572
function hook_views_preview_info_alter(array &$rows, ViewExecutable $view) {
merlinofchaos's avatar
merlinofchaos committed
573 574 575 576 577 578 579 580 581
  // Adds information about the tables being queried by the view to the query
  // part of the info box.
  $rows['query'][] = array(
    t('<strong>Table queue</strong>'),
    count($view->query->table_queue) . ': (' . implode(', ', array_keys($view->query->table_queue)) . ')',
  );
}

/**
582 583 584 585 586 587 588 589 590 591 592
 * Alter the links displayed at the top of the view edit form.
 *
 * @param array $links
 *   A renderable array of links which will be displayed at the top of the
 *   view edit form. Each entry will be in a form suitable for theme('link').
 * @param \Drupal\views\ViewExecutable $view
 *   The view object being edited.
 * @param string $display_id
 *   The ID of the display being edited, e.g. 'default' or 'page_1'.
 *
 * @see \Drupal\views_ui\ViewUI::renderDisplayTop()
merlinofchaos's avatar
merlinofchaos committed
593
 */
594
function hook_views_ui_display_top_links_alter(array &$links, ViewExecutable $view, $display_id) {
merlinofchaos's avatar
merlinofchaos committed
595 596 597 598 599 600 601
  // Put the export link first in the list.
  if (isset($links['export'])) {
    $links = array('export' => $links['export']) + $links;
  }
}

/**
602
 * Alter the commands used on a Views AJAX request.
merlinofchaos's avatar
merlinofchaos committed
603
 *
604 605 606
 * @param array $commands
 *   An array of ajax commands.
 * @param \Drupal\views\ViewExecutable $view
merlinofchaos's avatar
merlinofchaos committed
607
 *   The view which is requested.
608 609
 *
 * @see views_ajax()
merlinofchaos's avatar
merlinofchaos committed
610
 */
611
function hook_views_ajax_data_alter(array &$commands, ViewExecutable $view) {
merlinofchaos's avatar
merlinofchaos committed
612 613 614 615 616 617 618 619 620
  // Replace Views' method for scrolling to the top of the element with your
  // custom scrolling method.
  foreach ($commands as &$command) {
    if ($command['method'] == 'viewsScrollTop') {
      $command['method'] .= 'myScrollTop';
    }
  }
}

621
/**
622
 * Allow modules to respond to the invalidation of the Views cache.
623
 *
624
 * This hook will fire whenever a view is enabled, disabled, created,
625 626 627 628 629
 * updated, or deleted.
 *
 * @see views_invalidate_cache()
 */
function hook_views_invalidate_cache() {
630
  cache('mymodule')->invalidateTags(array('views' => TRUE));
631 632
}

merlinofchaos's avatar
merlinofchaos committed
633 634 635 636 637 638 639 640 641 642
/**
 * @}
 */

/**
 * @defgroup views_module_handlers Views module handlers
 * @{
 * Handlers exposed by various modules to Views.
 * @}
 */