Same name and namespace in other branches
  1. 8.9.x core/modules/views/views.api.php \hook_views_data()
  2. 9 core/modules/views/views.api.php \hook_views_data()

Describe data tables and fields (or the equivalent) to Views.

The table and fields are processed in Views using various plugins. See the Views plugins topic for more information.

To provide views data for an entity, instead of implementing this hook, create a class implementing \Drupal\views\EntityViewsDataInterface and reference this in the "handlers.views_data" annotation in the entity class. The return value of the getViewsData() method on the interface is the same as this hook, and base class in \Drupal\views\EntityViewsData will take care of adding the basic Views tables and fields for your entity. See the Entity API topic for more information about entities.

The data described with this hook is fetched and retrieved by \Drupal\views\Views::viewsData()->get().

Return value

array An associative array describing the structure of database tables and fields (and their equivalents) provided for use in Views. At the outermost level, the keys are the names used internally by Views for the tables (usually the actual table name). Each table's array describes the table itself, how to join to other tables, and the fields that are part of the table. The sample function body provides documentation of the details.

See also

hook_views_data_alter()

Related topics

19 functions implement hook_views_data()

Note: this list is generated by pattern matching, so it may include some functions that are not actually implementations of this hook.

book_views_data in core/modules/book/book.views.inc
Implements hook_views_data().
content_moderation_views_data in core/modules/content_moderation/content_moderation.views.inc
Implements hook_views_data().
core_field_views_data in core/modules/views/views.views.inc
Implements hook_field_views_data().
datetime_field_views_data in core/modules/datetime/datetime.views.inc
Implements hook_field_views_data().
datetime_range_field_views_data in core/modules/datetime_range/datetime_range.views.inc
Implements hook_field_views_data().

... See full list

File

core/modules/views/views.api.php, line 125
Describes hooks and plugins provided by the Views module.

Code

function hook_views_data() {

  // This example describes how to write hook_views_data() for a table defined
  // like this:
  // @code
  // CREATE TABLE example_table (
  //   nid INT(11) NOT NULL         COMMENT 'Primary key: {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.',
  //   langcode VARCHAR(12)         COMMENT 'Language code field.',
  //   PRIMARY KEY(nid)
  // );
  // @endcode
  // Define the return array.
  $data = [];

  // The outermost keys of $data are Views table names, which should usually
  // be the same as the hook_schema() table names.
  $data['example_table'] = [];

  // The value corresponding to key 'table' gives properties of the table
  // itself.
  $data['example_table']['table'] = [];

  // Within 'table', the value of 'group' (translated string) is used as a
  // prefix in Views UI for this table's fields, filters, etc. When adding
  // a field, filter, etc. you can also filter by the group.
  $data['example_table']['table']['group'] = t('Example table');

  // Within 'table', the value of 'provider' is the module that provides schema
  // or the entity type that causes the table to exist. Setting this ensures
  // that views have the correct dependencies. This is automatically set to the
  // module that implements hook_views_data().
  $data['example_table']['table']['provider'] = 'example_module';

  // Some tables are "base" tables, meaning that they can be the base tables
  // for views. Non-base tables can only be brought in via relationships in
  // views based on other tables. To define a table to be a base table, add
  // key 'base' to the 'table' array:
  $data['example_table']['table']['base'] = [
    // Identifier (primary) field in this table for Views.
    'field' => 'nid',
    // Label in the UI.
    'title' => t('Example table'),
    // Longer description in the UI. Required.
    'help' => t('Example table contains example content and can be related to nodes.'),
    'weight' => -10,
  ];

  // Some tables have an implicit, automatic relationship to other tables,
  // meaning that when the other table is available in a view (either as the
  // base table or through a relationship), this table's fields, filters, etc.
  // are automatically made available without having to add an additional
  // relationship. To define an implicit relationship that will make your
  // table automatically available when another table is present, add a 'join'
  // section to your 'table' section. Note that it is usually only a good idea
  // to do this for one-to-one joins, because otherwise your automatic join
  // will add more rows to the view. It is also not a good idea to do this if
  // most views won't need your table -- if that is the case, define a
  // relationship instead (see below).
  //
  // If you've decided an automatic join is a good idea, here's how to do it;
  // the resulting SQL query will look something like this:
  // @code
  //   ... FROM example_table et ... JOIN node_field_data nfd
  //   ON et.nid = nfd.nid AND ('extra' clauses will be here) ...
  // @endcode
  // although the table aliases will be different.
  $data['example_table']['table']['join'] = [
    // Within the 'join' section, list one or more tables to automatically
    // join to. In this example, every time 'node_field_data' is available in
    // a view, 'example_table' will be too. The array keys here are the array
    // keys for the other tables, given in their hook_views_data()
    // implementations. If the table listed here is from another module's
    // hook_views_data() implementation, make sure your module depends on that
    // other module.
    'node_field_data' => [
      // Primary key field in node_field_data to use in the join.
      'left_field' => 'nid',
      // Foreign key field in example_table to use in the join.
      'field' => 'nid',
      // 'extra' is an array of additional conditions on the join.
      'extra' => [
        0 => [
          // Adds AND node_field_data.published = TRUE to the join.
          'field' => 'published',
          'value' => TRUE,
        ],
        1 => [
          // Adds AND example_table.numeric_field = 1 to the join.
          'left_field' => 'numeric_field',
          'value' => 1,
          // If true, the value will not be surrounded in quotes.
          'numeric' => TRUE,
        ],
        2 => [
          // Adds AND example_table.boolean_field <>
          // node_field_data.published to the join.
          'field' => 'published',
          'left_field' => 'boolean_field',
          // The operator used, Defaults to "=".
          'operator' => '!=',
        ],
      ],
    ],
  ];

  // You can also do a more complex join, where in order to get to a certain
  // base table defined in a hook_views_data() implementation, you will join
  // to a different table that Views knows how to auto-join to the base table.
  // For instance, if another module that your module depends on had
  // defined a table 'foo' with an automatic join to 'node_field_table' (as
  // shown above), you could join to 'node_field_table' via the 'foo' table.
  // Here's how to do this, and the resulting SQL query would look something
  // like this:
  // @code
  //   ... FROM example_table et ... JOIN foo foo
  //   ON et.nid = foo.nid AND ('extra' clauses will be here) ...
  //   JOIN node_field_data nfd ON (definition of the join from the foo
  //   module goes here) ...
  // @endcode
  // although the table aliases will be different.
  $data['example_table']['table']['join']['node_field_data'] = [
    // 'node_field_data' above is the base we're joining to in Views.
    // 'left_table' is the table we're actually joining to, in order to get to
    // 'node_field_data'. It has to be something that Views knows how to join
    // to 'node_field_data'.
    'left_table' => 'foo',
    'left_field' => 'nid',
    'field' => 'nid',
    // 'extra' is an array of additional conditions on the join.
    'extra' => [
      // This syntax matches additional fields in the two tables:
      // ... AND foo.langcode = example_table.langcode ...
      [
        'left_field' => 'langcode',
        'field' => 'langcode',
      ],
      // This syntax adds a condition on our table. 'operator' defaults to
      // '=' for non-array values, or 'IN' for array values.
      // ... AND example_table.numeric_field > 0 ...
      [
        'field' => 'numeric_field',
        'value' => 0,
        'numeric' => TRUE,
        'operator' => '>',
      ],
    ],
  ];

  // Other array elements at the top level of your table's array describe
  // individual database table fields made available to Views. The array keys
  // are the names (unique within the table) used by Views for the fields,
  // usually equal to the database field names.
  //
  // Each field entry must have the following elements:
  // - title: Translated label for the field in the UI.
  // - help: Description of the field in the UI.
  //
  // Each field entry may also have one or more of the following elements,
  // describing "handlers" (plugins) for the field:
  // - relationship: Specifies a handler that allows this field to be used
  //   to define a relationship to another table in Views.
  // - field: Specifies a handler to make it available to Views as a field.
  // - filter: Specifies a handler to make it available to Views as a filter.
  // - sort: Specifies a handler to make it available to Views as a sort.
  // - argument: Specifies a handler to make it available to Views as an
  //   argument, or contextual filter as it is known in the UI.
  // - area: Specifies a handler to make it available to Views to add content
  //   to the header, footer, or as no result behavior.
  //
  // Note that when specifying handlers, you must give the handler plugin ID
  // and you may also specify overrides for various settings that make up the
  // plugin definition. See examples below; the Boolean example demonstrates
  // setting overrides.
  // Node ID field, exposed as relationship only, since it is a foreign key
  // in this table.
  $data['example_table']['nid'] = [
    'title' => t('Example content'),
    'help' => t('Relate example content to the node content'),
    // Define a relationship to the node_field_data table, so views whose
    // base table is example_table can add a relationship to nodes. To make a
    // relationship in the other direction, you can:
    // - Use hook_views_data_alter() -- see the function body example on that
    //   hook for details.
    // - Use the implicit join method described above.
    'relationship' => [
      // Views name of the table to join to for the relationship.
      'base' => 'node_field_data',
      // Database field name in the other table to join on.
      'base field' => 'nid',
      // ID of relationship handler plugin to use.
      'id' => 'standard',
      // Default label for relationship in the UI.
      'label' => t('Example node'),
    ],
  ];

  // Plain text field, exposed as a field, sort, filter, and argument.
  $data['example_table']['plain_text_field'] = [
    'title' => t('Plain text field'),
    'help' => t('Just a plain text field.'),
    'field' => [
      // ID of field handler plugin to use.
      'id' => 'standard',
    ],
    'sort' => [
      // ID of sort handler plugin to use.
      'id' => 'standard',
    ],
    'filter' => [
      // ID of filter handler plugin to use.
      'id' => 'string',
    ],
    'argument' => [
      // ID of argument handler plugin to use.
      'id' => 'string',
    ],
  ];

  // Numeric field, exposed as a field, sort, filter, and argument.
  $data['example_table']['numeric_field'] = [
    'title' => t('Numeric field'),
    'help' => t('Just a numeric field.'),
    'field' => [
      // ID of field handler plugin to use.
      'id' => 'numeric',
    ],
    'sort' => [
      // ID of sort handler plugin to use.
      'id' => 'standard',
    ],
    'filter' => [
      // ID of filter handler plugin to use.
      'id' => 'numeric',
    ],
    'argument' => [
      // ID of argument handler plugin to use.
      'id' => 'numeric',
    ],
  ];

  // Boolean field, exposed as a field, sort, and filter. The filter section
  // illustrates overriding various settings.
  $data['example_table']['boolean_field'] = [
    'title' => t('Boolean field'),
    'help' => t('Just an on/off field.'),
    'field' => [
      // ID of field handler plugin to use.
      'id' => 'boolean',
    ],
    'sort' => [
      // ID of sort handler plugin to use.
      'id' => 'standard',
    ],
    'filter' => [
      // ID of filter handler plugin to use.
      'id' => 'boolean',
      // Override the generic field title, so that the filter uses a different
      // label in the UI.
      'label' => t('Published'),
      // Override the default BooleanOperator filter handler's 'type' setting,
      // to display this as a "Yes/No" filter instead of a "True/False" filter.
      'type' => 'yes-no',
      // Override the default Boolean filter handler's 'use_equal' setting, to
      // make the query use 'boolean_field = 1' instead of 'boolean_field <> 0'.
      'use_equal' => TRUE,
    ],
  ];

  // Integer timestamp field, exposed as a field, sort, and filter.
  $data['example_table']['timestamp_field'] = [
    'title' => t('Timestamp field'),
    'help' => t('Just a timestamp field.'),
    'field' => [
      // ID of field handler plugin to use.
      'id' => 'date',
    ],
    'sort' => [
      // ID of sort handler plugin to use.
      'id' => 'date',
    ],
    'filter' => [
      // ID of filter handler plugin to use.
      'id' => 'date',
    ],
  ];

  // Computed field example. Computed fields are not associated with actual data
  // tables and fields, and therefore have no schema. Instead, they are computed
  // when the value is read from the entity. Here's the definition of a computed
  // field that exists for a particular entity type. The value of the field will
  // be calculated by a defined class. If the defined class for the computed
  // fields differs between multiple bundles of the same entity type, then each
  // of those fields should be added separately.
  // @see \Drupal\Core\TypedData\DataDefinitionInterface::setComputed().
  // @see \Drupal\Core\TypedData\DataDefinitionInterface::setClass().
  $data['example_table']['computed_bundle_field'] = [
    'title' => t('Computed Bundle Field'),
    'help' => t('The computed bundle field'),
    'field' => [
      'id' => 'field',
      'default_formatter' => 'string',
      'field_name' => 'computed_bundle_field',
    ],
  ];

  // Area example. Areas are not generally associated with actual data
  // tables and fields. This example is from views_views_data(), which defines
  // the "Global" table (not really a table, but a group of Fields, Filters,
  // etc. that are grouped into section "Global" in the UI). Here's the
  // definition of the generic "Text area":
  $data['views']['area'] = [
    'title' => t('Text area'),
    'help' => t('Provide markup text for the area.'),
    'area' => [
      // ID of the area handler plugin to use.
      'id' => 'text',
    ],
  ];
  return $data;
}