Drupal 8 Views tutorial for developers. Part II —Tables & Fields

Oleksandr Trotsenko
Oleksandr Trotsenko
5 min readJan 15, 2019

So after quickly considering the necessary theory in part I, let’s actually get started.

To repeat, we have the following 2 tables which we want to expose to the Views.

Table of fruits

CREATE TABLE `fruit` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT 'Unique ID of the fruit.',
`label` varchar(255) NOT NULL COMMENT 'Label of the fruit',
`weight` float unsigned NOT NULL COMMENT 'Weight of the fruit. Units are stored in weight_unit column.',
`weight_unit` varchar(255) NOT NULL COMMENT 'Unit of the weight.',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Stores data on fruits'

Table of relations between fruits (some fruits are sweeter and/or bigger than others!):

CREATE TABLE `fruit_relations` (
`fruit_id` int(10) unsigned NOT NULL COMMENT '{fruit}.id of the fruit whose relation is described in this row.',
`relation` varchar(255) NOT NULL COMMENT 'Type of relation. Allowed values are: sweeter, bigger',
`fruit_id_related` int(10) unsigned NOT NULL COMMENT '{fruit}.id of the fruit that is related to the fruit described in this row.'
) ENGINE=InnoDB DEFAULT CHARSET=utf8

The first logical thing to do is to make sure Views can display data from those tables, leaving sorting and filtering for later.

Views has the notion of tables, pretty much like normal DB tables. The only difference is that it distinguishes base tables and non-base ones whatsoever. What’s the difference?

Base tables represent some self-sufficient data (entities) and thus may act as a starting point (base) of your view. As an example: does it make sense to start building our view from the fruit_relations table? Hardly… That table only gains some meaning when paired with the fruit table. Thus in our case the base table is going to be fruit.

Now, the deal with non-base tables is that their content naturally belongs to a particular base table, however, due to SQL storage implementation it is outsourced from the base table into a dedicated table. That is, the ‘bigger than’ or ‘sweeter than’ properties of Fruit does sound like integral part of it, but due to some external reasons on the SQL level it is stored in a separate table. That’s a very vivid example of a non-base table. Such tables should become implicitly available to the site-builder whenever their respective base table becomes available.

So let’s grab a fruity_views module and implement its hook_views_data() per what we have just discussed above:

We are done here with tables. If you type in the necessary fruity_views.info.yml file and enable this module in your Drupal 8 instance, you should be able to initialize a view on your brand new base table.

Do not forget to clean your caches whenever you update hook_views_data(). drush cr in terminal should do it.

The bad news is that none of the 2 tables have any fields defined, thus while tables are discovered by Views module, it cannot display anything within them. Let us fix this up. You can think of Views fields as of columns in a DB table. However, as you have seen above, DB tables are somewhat different from Views table. Similar subtle difference is observed in the case of fields too. For example, you could define 2 different Views fields that both point to the same DB column but use different field handlers thus obtaining 2 distinct outcomes. However, we shall keep it simple here: let’s add the {fruit}.label column as a Views field. Just append the following into your hook_views_data():

Go and try to add the Fruit label field to your view. You should have something quite close to the print screen below:

Yay! Our first fully custom view is actually working!

Actual SQL query the view executes at this moment is:

SELECT fruit.label AS fruit_label
FROM
{fruit} fruit
LIMIT 11 OFFSET 0

This standard field plugin actually requires no further input but the column name. However, if a field plugin you are intending to use requires additional definition parameters, supply them right next to the ‘id’ key, i.e.

Normally the docblock comments on top of plugin class describe expected additional definition by that plugin, if any. You may peek into \Drupal\views\Plugin\views\field\MachineName if you are curious to see how such additional definition properties are documented (there 2 additional properties of options callback and options arguments are introduced).

In general, have a look around the folder ./core/modules/views/src/Plugin/views/field to get familiar with field plugins core ships with. I advise to reuse them whenever possible. However, sooner or later you will end up in a situation where no pre-existing field plugin covers your needs. This is exactly the case with our ‘weight’ property of the fruit: because the actual weight is stored across 2 columns (absolute value and units of measure) it is very unlikely any field plugin out there will be able to display it in a user-friendly way.

Alright, it means to introduce the ‘weight’ field, we first must code our custom Views field plugin. It might sound complex, but it is not… Just follow me in the code below:

As Plugin API dictates it, place this Weight.php file under the fruity_views/src/Plugin/views/field folder.

This, however, does not conclude our mission — all we have done so far is just coded an abstract reusable Views field plugin. We still lack to connect it to our fruit table. It is now time to come back to hook_views_data() and to leverage this custom Views field plugin.

This should get the ‘Fruit weight’ field available in our Views UI. Here is a print screen of my view with the 2 fields added:

Observe how you can literally control output of a view column and columns being fetched from DB when coding a custom field handler.

Actual SQL executed is:

SELECT fruit.label AS fruit_label, fruit.weight AS fruit_weight, fruit.weight_unit AS fruit_weight_unit
FROM
{fruit} fruit
LIMIT 11 OFFSET 0

As you can see, developing custom Views field plugins is far easier than one could imagine. Knowing how to leverage existing Views field plugins and to write one in case of some unique business requirement produces a much more elegant solution than hacking things in some alter hooks or theme layer.

The whole fruity_views module can be accessed from this repository https://github.com/bucefal91/fruity_views/tree/part-2 Make sure to stay on the branch part-2. The repository has a branch per each part of this series.

In the next chapter we shall explore sorting and filtering Views plugins. Stay tuned! Part III is available here

--

--