views.api.php 23.4 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\views\Views::viewsData()->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
    ),
    'sort' => array(
aspilicious's avatar
aspilicious committed
196
      'id' => 'standard',
merlinofchaos's avatar
merlinofchaos committed
197 198
    ),
    'filter' => array(
aspilicious's avatar
aspilicious committed
199
      'id' => 'string',
merlinofchaos's avatar
merlinofchaos committed
200 201
    ),
    'argument' => array(
aspilicious's avatar
aspilicious committed
202
      'id' => 'string',
merlinofchaos's avatar
merlinofchaos committed
203 204 205 206 207 208 209 210
    ),
  );

  // 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
211
      'id' => 'numeric',
merlinofchaos's avatar
merlinofchaos committed
212 213
     ),
    'filter' => array(
aspilicious's avatar
aspilicious committed
214
      'id' => 'numeric',
merlinofchaos's avatar
merlinofchaos committed
215 216
    ),
    'sort' => array(
aspilicious's avatar
aspilicious committed
217
      'id' => 'standard',
merlinofchaos's avatar
merlinofchaos committed
218 219 220 221 222 223 224 225
    ),
  );

  // 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
226
      'id' => 'boolean',
merlinofchaos's avatar
merlinofchaos committed
227 228
    ),
    'filter' => array(
aspilicious's avatar
aspilicious committed
229
      'id' => 'boolean',
merlinofchaos's avatar
merlinofchaos committed
230 231 232 233 234
      // 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.
235
      'use_equal' => TRUE,
merlinofchaos's avatar
merlinofchaos committed
236 237
    ),
    'sort' => array(
aspilicious's avatar
aspilicious committed
238
      'id' => 'standard',
merlinofchaos's avatar
merlinofchaos committed
239 240 241 242 243 244 245 246
    ),
  );

  // 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
247
      'id' => 'date',
merlinofchaos's avatar
merlinofchaos committed
248 249
    ),
    'sort' => array(
aspilicious's avatar
aspilicious committed
250
      'id' => 'date',
merlinofchaos's avatar
merlinofchaos committed
251 252
    ),
    'filter' => array(
aspilicious's avatar
aspilicious committed
253
      'id' => 'date',
merlinofchaos's avatar
merlinofchaos committed
254 255 256 257 258 259 260
    ),
  );

  return $data;
}

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

273
  // This example adds an example field to the users table.
merlinofchaos's avatar
merlinofchaos committed
274 275 276 277 278 279 280
  $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.
281
  // In this handler you could do stuff, like preview of the node when clicking
merlinofchaos's avatar
merlinofchaos committed
282 283 284
  // the node title.
  $data['node']['title']['handler'] = 'modulename_handlers_field_node_title';

285 286 287 288 289 290 291 292 293 294 295
  // 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
296
      'id' => 'standard',
297 298 299 300 301 302
      'label' => t('Default label for relationship'),
      'title' => t('Title seen when adding relationship'),
      'help' => t('More information about relationship.'),
    ),
  );

merlinofchaos's avatar
merlinofchaos committed
303 304 305 306
  // Note that the $data array is not returned – it is modified by reference.
}

/**
307
 * Replace special strings in the query before it is executed.
merlinofchaos's avatar
merlinofchaos committed
308
 *
309
 * @param \Drupal\views\ViewExecutable $view
merlinofchaos's avatar
merlinofchaos committed
310
 *   The View being executed.
311 312 313 314
 * @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
315
 */
316
function hook_views_query_substitutions(ViewExecutable $view) {
merlinofchaos's avatar
merlinofchaos committed
317 318 319 320
  // Example from views_views_query_substitutions().
  return array(
    '***CURRENT_VERSION***' => VERSION,
    '***CURRENT_TIME***' => REQUEST_TIME,
321
    '***CURRENT_LANGUAGE***' => language(\Drupal\Core\Language\Language::TYPE_CONTENT)->langcode,
322
    '***DEFAULT_LANGUAGE***' => language_default()->langcode,
merlinofchaos's avatar
merlinofchaos committed
323 324 325 326
  );
}

/**
327
 * Replace special strings when processing a view with form elements.
merlinofchaos's avatar
merlinofchaos committed
328
 *
329 330 331
 * @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
332 333 334 335 336 337 338 339
 */
function hook_views_form_substitutions() {
  return array(
    '<!--views-form-example-substitutions-->' => 'Example Substitution',
  );
}

/**
340
 * Alter a view at the very beginning of Views processing.
merlinofchaos's avatar
merlinofchaos committed
341
 *
342 343 344
 * Output can be added to the view by setting $view->attachment_before
 * and $view->attachment_after.
 *
345
 * @param \Drupal\views\ViewExecutable $view
merlinofchaos's avatar
merlinofchaos committed
346
 *   The view object about to be processed.
347
 * @param string $display_id
merlinofchaos's avatar
merlinofchaos committed
348
 *   The machine name of the active display.
349
 * @param array $args
merlinofchaos's avatar
merlinofchaos committed
350
 *   An array of arguments passed into the view.
351
 *
352
 * @see \Drupal\views\ViewExecutable
merlinofchaos's avatar
merlinofchaos committed
353
 */
354
function hook_views_pre_view(ViewExecutable &$view, &$display_id, array &$args) {
merlinofchaos's avatar
merlinofchaos committed
355 356
  // Change the display if the acting user has 'administer site configuration'
  // permission, to display something radically different.
357 358 359
  // @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
360 361 362 363 364
    $display_id = 'private_display';
  }
}

/**
365
 * Act on the view before the query is built, but after displays are attached.
merlinofchaos's avatar
merlinofchaos committed
366
 *
367 368 369
 * Output can be added to the view by setting $view->attachment_before
 * and $view->attachment_after.
 *
370
 * @param \Drupal\views\ViewExecutable $view
merlinofchaos's avatar
merlinofchaos committed
371
 *   The view object about to be processed.
372
 *
373
 * @see \Drupal\views\ViewExecutable
merlinofchaos's avatar
merlinofchaos committed
374
 */
375
function hook_views_pre_build(ViewExecutable &$view) {
merlinofchaos's avatar
merlinofchaos committed
376 377 378 379 380 381 382 383 384 385
  // 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);
  }
}

/**
386
 * Act on the view immediately after the query is built.
merlinofchaos's avatar
merlinofchaos committed
387
 *
388 389 390
 * Output can be added to the view by setting $view->attachment_before
 * and $view->attachment_after.
 *
391
 * @param \Drupal\views\ViewExecutable $view
merlinofchaos's avatar
merlinofchaos committed
392
 *   The view object about to be processed.
393
 *
394
 * @see \Drupal\views\ViewExecutable
merlinofchaos's avatar
merlinofchaos committed
395
 */
396
function hook_views_post_build(ViewExecutable &$view) {
merlinofchaos's avatar
merlinofchaos committed
397 398 399 400 401 402 403 404 405 406 407 408 409 410
  // 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;
    }
  }
}

/**
411
 * Act on the view after the query is built and just before it is executed.
merlinofchaos's avatar
merlinofchaos committed
412
 *
413 414 415
 * Output can be added to the view by setting $view->attachment_before
 * and $view->attachment_after.
 *
416
 * @param \Drupal\views\ViewExecutable $view
merlinofchaos's avatar
merlinofchaos committed
417
 *   The view object about to be processed.
418
 *
419
 * @see \Drupal\views\ViewExecutable
merlinofchaos's avatar
merlinofchaos committed
420
 */
421
function hook_views_pre_execute(ViewExecutable &$view) {
merlinofchaos's avatar
merlinofchaos committed
422 423 424 425 426 427 428 429 430 431
  // 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');
  }
}

/**
432
 * Act on the view immediately after the query has been executed.
merlinofchaos's avatar
merlinofchaos committed
433
 *
434 435 436 437 438 439
 * 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.
 *
440
 * @param \Drupal\views\ViewExecutable $view
merlinofchaos's avatar
merlinofchaos committed
441
 *   The view object about to be processed.
442
 *
443
 * @see \Drupal\views\ViewExecutable
merlinofchaos's avatar
merlinofchaos committed
444
 */
445
function hook_views_post_execute(ViewExecutable &$view) {
merlinofchaos's avatar
merlinofchaos committed
446 447 448 449 450 451 452 453 454 455
  // 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.'));
  }
}

/**
456
 * Act on the view immediately before rendering it.
merlinofchaos's avatar
merlinofchaos committed
457
 *
458 459 460
 * 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
461
 *
462 463 464
 * Output can be added to the view by setting $view->attachment_before
 * and $view->attachment_after.
 *
465
 * @param \Drupal\views\ViewExecutable $view
merlinofchaos's avatar
merlinofchaos committed
466
 *   The view object about to be processed.
467
 *
468
 * @see \Drupal\views\ViewExecutable
merlinofchaos's avatar
merlinofchaos committed
469
 */
470
function hook_views_pre_render(ViewExecutable &$view) {
merlinofchaos's avatar
merlinofchaos committed
471 472 473 474 475 476 477
  // 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);
}

/**
478
 * Post-process any rendered data.
merlinofchaos's avatar
merlinofchaos committed
479 480 481
 *
 * 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
482 483
 * comment-based tokens, and then the post process can replace those tokens.
 * This hook can be utilized by themes.
merlinofchaos's avatar
merlinofchaos committed
484 485 486
 *
 * 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:
487 488 489 490
 * @code
 *   <!--post-FIELD-NID-->
 * @encode
 * And then in the post-render, create an array with the text that should
merlinofchaos's avatar
merlinofchaos committed
491
 * go there:
492 493 494
 * @code
 *   strtr($output, array('<!--post-FIELD-1-->' => 'output for FIELD of nid 1');
 * @encode
merlinofchaos's avatar
merlinofchaos committed
495 496 497
 * All of the cached result data will be available in $view->result, as well,
 * so all ids used in the query should be discoverable.
 *
498
 * @param \Drupal\views\ViewExecutable $view
merlinofchaos's avatar
merlinofchaos committed
499
 *   The view object about to be processed.
500
 * @param string $output
merlinofchaos's avatar
merlinofchaos committed
501
 *   A flat string with the rendered output of the view.
502
 * @param CacheBackendInterface $cache
merlinofchaos's avatar
merlinofchaos committed
503
 *   The cache settings.
504
 *
505
 * @see \Drupal\views\ViewExecutable
merlinofchaos's avatar
merlinofchaos committed
506
 */
507 508 509 510 511 512
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
513 514 515 516
  }
}

/**
517
 * Alter the query before it is executed.
merlinofchaos's avatar
merlinofchaos committed
518
 *
519
 * @param \Drupal\views\ViewExecutable $view
merlinofchaos's avatar
merlinofchaos committed
520
 *   The view object about to be processed.
521 522 523
 * @param QueryPluginBase $query
 *   The query plugin object for the query.
 *
merlinofchaos's avatar
merlinofchaos committed
524
 * @see hook_views_query_substitutions()
525
 * @see \Drupal\views\Plugin\views\query\Sql
merlinofchaos's avatar
merlinofchaos committed
526
 */
527
function hook_views_query_alter(ViewExecutable &$view, QueryPluginBase &$query) {
merlinofchaos's avatar
merlinofchaos committed
528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549
  // (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' => '=',
          );
        }
      }
    }
  }
}

/**
550 551 552 553 554
 * 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
555
 *
556
 * @param array $rows
merlinofchaos's avatar
merlinofchaos committed
557 558 559 560 561
 *   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.
562
 * @param \Drupal\views\ViewExecutable $view
merlinofchaos's avatar
merlinofchaos committed
563
 *   The view object.
564
 *
565
 * @see \Drupal\views_ui\ViewUI
merlinofchaos's avatar
merlinofchaos committed
566 567
 * @see theme_table()
 */
568
function hook_views_preview_info_alter(array &$rows, ViewExecutable $view) {
merlinofchaos's avatar
merlinofchaos committed
569 570 571 572 573 574 575 576 577
  // 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)) . ')',
  );
}

/**
578 579 580 581 582 583 584 585 586 587 588
 * 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
589
 */
590
function hook_views_ui_display_top_links_alter(array &$links, ViewExecutable $view, $display_id) {
merlinofchaos's avatar
merlinofchaos committed
591 592 593 594 595 596
  // Put the export link first in the list.
  if (isset($links['export'])) {
    $links = array('export' => $links['export']) + $links;
  }
}

597
// @todo Describe how to alter a view ajax response with event listeners.
merlinofchaos's avatar
merlinofchaos committed
598

599
/**
600
 * Allow modules to respond to the invalidation of the Views cache.
601
 *
602
 * This hook will fire whenever a view is enabled, disabled, created,
603 604 605 606 607
 * updated, or deleted.
 *
 * @see views_invalidate_cache()
 */
function hook_views_invalidate_cache() {
608
  cache('mymodule')->invalidateTags(array('views' => TRUE));
609 610
}

merlinofchaos's avatar
merlinofchaos committed
611 612 613 614 615 616 617 618 619 620
/**
 * @}
 */

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