Create a gist now

Instantly share code, notes, and snippets.

What would you like to do?
Brief guide to Views Data. What it is, how to declare your table and field information and how some of the special meta data keys work. Additionally there is information on how to integrate into the Apache Solr Views information for declaring your own fields.

Using Views Data

As you're probably aware, if you want Views to acknowledge any of your fields, filters, sorts, or contextual filters; you have to declare their existence in the hook_views_data within your module. This is a brief guide into how to utilise this functionality.

This guide assumes you have already setup your Views integration using the API hook and you are ready to start declaring fields and other related items for your custom data. The basic structure of the array that is returned by the Views data hook is as follows:

    <Table Name>
    |-| <Field Name>
    |--| <Field Info>
    |
    |-| <Field Name>
    |--| <Field Info>
    ...etc

The tables are the primary keys in the array and their respective fields are contained in each table. Tables have their own section that specifies various pieces of information about that table to Views so it knows how to access the table (a primary key field), if there are any access query alterations that need to occur, a human readable name, if this table is a new base table, as well as any relationships that this table may have to other tables in the database. Below is a basic table declaration:

<?php
  // Define the base group of this table. Fields that don't
  // have a group defined will go into this field by default.
  $data['node']['table']['group'] = t('Content');

  // Advertise this table as a possible base table
  $data['node']['table']['base'] = array(
    'field' => 'nid',
    'title' => t('Content'),
    'weight' => -10,
    'access query tag' => 'node_access',
    'defaults' => array(
      'field' => 'title',
    ),
  );
?>

The field items contain all of the information related to each field, declaring titles and descriptions, as well as the class names of the handlers that are to be used. Below is an example of a complete field declaration for the Node ID field (ignore the ).

<?php
// nid
$data['node']['nid'] = array(
  'title' => t('Nid'),
  'help' => t('The node ID.'), // The help that appears on the UI,
  // Information for displaying the nid
  'field' => array(
    'handler' => 'views_handler_field_node',
    'click sortable' => TRUE,
  ),
  // Information for accepting a nid as an argument
  'argument' => array(
    'handler' => 'views_handler_argument_node_nid',
    'name field' => 'title', // the field to display in the summary.
    'numeric' => TRUE,
    'validate type' => 'nid',
  ),
  // Information for accepting a nid as a filter
  'filter' => array(
    'handler' => 'views_handler_filter_numeric',
  ),
  // Information for sorting on a nid.
  'sort' => array(
    'handler' => 'views_handler_sort',
  ),
);
?>

This example should provide a good guide as to how to implement a Views data entry for a basic field that is stored in an SQL database. You can see that the table name is node and the field name is nid. There is a title and help fields to provide the name and description text for the Views UI.

Additionally you can see that this field can be used as a normal field for displaying its contents, as an argument (or contextual filter) to the View, a filter to limit the results of the View, as well as being able to be used to sort the view.

Within each of those items; field, argument, filter, _sort. There is a handler entry that contains the class name of the handler that will be used for this item. These can also contain additional metadata that we'll touch on later. For now be aware that you must consider how your item will be used within Views, and you have to declare the respective handlers here. Otherwise your item will not be available.

Some Examples...

Declaring your own data.

To begin with, lets try to expose our contrived SQL table below to Views.

    mydata_table
    |-- _id (int)
    |-- name (varchar)
    |-- created (int)
    |-- contents (text)
    |-- metainfo (varchar)

Within your hook_views_data create the entry for the table:

<?php
// Declare our table as a new base table to construct Views from.
$data['mydata_table']['table'] = array(
  // Specify a group name for the table.
  'group' => t('My Bonus Content'),
  'base' => array(
    'field' => '_id' // Set our primary key field.
    'title' => t('My Bonus Content Table'),
  ),
);
?>

That is enough for Views to know that we are declaring a new base table, a base table is the starting point for a View. It is the table from which the View will attempt to load all data that does not come from a relationship to another table. Other base tables include Node (aka Content) and Taxonomy Term.

Now we can start to setup our various fields. For starters lets setup our _id field. We want this field to be visible in the View, so we'll need a field handler, and we want to be able to pass it in as an argument, so we'll need an argument handler as well.

<?php
$data['mydata_table']['_id'] = array(
   // Give the field a label.
  'title' => t('My Bonus Content ID'),
  // Add some help or description text to describe
  // to the user what this field is. and what it represents.
  'help' => t('The unique ID of this bonus content.'),
  // Add our FIELD declaration.
  'field' => array(
    // The numeric field handler is suitable.
    'handler' => 'views_handler_field_numeric',
    // The handler name must match the class name exactly.
  ),
  // We also want to be able to provide it as argument.
  'argument' => array(
    // Views provides a handler for this too!
    'handler' => 'views_handler_argument_numeric',
  ),
);
?>

That is it for our _id field declaration! Simple isn't it? If we were to create a View now, we would have an additional choice for the type of data or base table that we're using, our 'My Bonus Content Table'. Within that we would now be able to display the _id for every entry in that table in a View, or limit our View using an argument that is based on our _id.

But that alone is a bit boring so we should go ahead and create items for the rest of the fields on our table. Remember that not all of your database fields will make sense in a View in the same way. The name field from earlier would make sense as a field to be displayed, but not as an argument to the view. However we might want to be able to sort on the name so that it is displayed alphabetically. So we'd keep the field entry and swap the handler to be views_handler_field. Drop the argument entirely, and add a sort using the views_handler_sort handler.

For a full list of the handlers that are available from Views, have a look in the handlers folder within the Views module itself.

Field Options and Extra Data

Within both the table and field declarations it is possible to add addtional data which is used by various handlers to provide extra functionality to your fields and table without needing to write in any additional PHP code. We will only cover a few basic examples here as there is simply too much to cover in a single document and remember that to see what is being used or what is available always consult the handler code itself. It is the best documentation for this.

Click Sorting (Simple)

The simplest example of this additional data is the click sortable key in a field declaration. You can see an example of this on the nid field snippet from earlier. Add 'click sortable' => TRUE, underneath the handler item in your field array. Now when your field is displayed in a table or similar display plugin, the option will be available for the display to be sorted on this field by clicking on the column heading.

Additional Fields (Advanced)

If you're creating a custom handler for your field that is a the result of a calculation using a couple of different fields. It is possible to declare within the Views data for this field that whenever it is added to the View, to also make sure to include the data from the additional fields. So when your handler code is run, the data you need is already there without any extra effort on your part. The additional fields array is added to handler section where it is required.

Using our table from earlier... Our contents field contains the basic data stored on our bonus content item, however the formatting information is stored on the metainfo field on the same row. We could include code to pull that information from the database everytime the handler is run in our handler but that would be another database query for everytime the field appears in the View, which is horrible. So let's just add the following under our handler entry in the field section for our contents field:

<?php
'additional fields' => array(
  // Provide a useful name for the data we're acquiring.
  'formatting_info' => array(
    // Tell Views what table it's on.
    'table' => 'mydata_table',
    'field' => 'metainfo',
  ),
),
?>

That's it! Now inside our field handler for this field there will be an array called additional fields that will be keyed by the names provided above and they will contain the data from specified field and table.

<?php
// From within your handler.
$this->additional_fields['formatting_info'];
?>

Virtual Fields (Advanced)

The final item we're going to discuss is the creation of virtual fields within Views data. These are fields that whilst based on stored information are not actually entries in the database. This is a powerful feature of Views that allows you to move often used functionality and display components into easy to use handlers. One possible use case is a clever price handler that uses various pieces of information to alter how the price is presented based on other information. However we don't want to add this overhead every time the field is used as the raw information is useful as well. So we'll create a virtual price field that suits our needs.

To do this you declare another field entry on the same table where the original field exists, with the addition of the real field key that tells Views which field this one is based on:

<?php
// Give our field a 'machine name' or id to use. This should not
// match any other field name, existing or virtual. It must be unique.
$data['mydata_table']['fancy_price_field'] = array(
  // Title and help fields as normal.
  'title' => t('Self Formatting Price'),
  'help' => t('This field will attempt to format itself!'),
  // The real field value must be a selectable field in the query. It
  // cannot be another virtual field.
  'real field' => 'price_field',
  'field' => array(
    'handler' => 'views_handler_field_fancy_price',
    // Capture some addtional formatting field info.
    'additional fields' => array(
      // We can drop the table declaration if the additional fields
      // are on the same table as this field.
      'local_currency',
      'currency_symbol',
    ),
  ),
);
?>

Now within the views_handler_field_fancy_price handler we will automatically have the price_field information as if this was the price field. Combined with the additional_fields information we can do the hard work in the render step without ever having to worry about selecting the additional information, or overloading the base price_field with options that are more easily contained in a different handler configuration.

Solr Views Data !

This section covers some of the caveats involved in extending the Solr Views integration.

The most significant part of the Solr Views data declaration is ensuring that the base table value is correct. Within a Solr View the base table is one of the configured Solr environments on that site, identified by the machine name of that instance. So we can't afford to hardcode a base table name because there is just no way of knowing ahead of time. Thankfully the Apache Solr module helps us out here by providing a list of the configured environments, simply call apachesolr_load_all_environments(); for an array with all the information you need.

Then following the example provided by the core apachesolr_views module we then create a Views data list of our fields for every configured environment. The snippet based on the apachesolr_views implementation is as follows:

<?php
$data = array();
$environments = apachesolr_load_all_environments();

foreach ($environments as $env_id => $env_info) {
  $name = $env_info['name'];
  $base_table = 'apachesolr__' . $env_id;

  // Example field.
  $data[$base_table]['ss_string_field'] = array(
    // You know this bit already. ;)
  );
}
?>

That's about the only tricky thing to remember when creating Views data to be used for Solr Views. The other important things to note are:

  • Look in the apachesolr_views/handers directory to find the list of available base handlers. Most of these extend the base Views handlers and provide the tweaks and changes necessary to deal with Solr information and syntax.
  • You are still able to create virtual fields as the real field key still works, remembering that you have to use the exact Solr field ID that is indexed. So remember that if that is not a field you control, you should check if the module that provides it is enabled before trying to add your field.
  • The additional fields array is available as well, however you have to declare each item as its own array. So array('placeholder' => array('table' => $base_table, 'field' => $field_id)),.
  • Relationships and Joins are not supported and will be ignored, or might create terrible errors.

Great guide! I don't know if things have been changed, but the way to access your additional fields is

$field_alias = $this->aliases['formatting_info'];
$formatting_info = $values->$field_alias;

$this->additional_fields['formatting_info']; will just hold the definitions from your hook_views_data entry.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment