Drupal 8 Views tutorial for developers. Part IV — Arguments

Oleksandr Trotsenko
Oleksandr Trotsenko
4 min readJan 17, 2019

Arguments, also known as ‘contextual filters’, act quite similar to the normal filters. The difference resides in the source where you are grabbing actual filter criteria from.

Hey, part III is posted at this link — in case you’re wondering.

In the case of normal filters your criteria come from either pre-defined values (those specified by site-builder at the moment of building a view) or from user input (whenever the filter is exposed). Contextual filters intake the criteria from… the current context, as you could have guessed. The fancy ‘current context’ actually stands for the current URL.

I wish you’d have to use arguments only within the context of Drupal Views.

In a simplified form, the following happens when a view that has arguments is being executed:

  1. The actual arguments are extracted from the URL. So if view’s path is /some/view/{arg1}/display and the current URL is some/view/valueOfArg1/display then we end up with the argument of valueOfArg1 after this step.
  2. If there is any argument validator associated with the argument in question, let it have its word. If argument validator does not validate the actual received argument (valueOfArg1), take respective steps, i.e. error out.
  3. Lastly, if the validation step above terminated successfully, the actual argument handler intervenes and changes the SQL query built so far so to reflect the actual logic behind argument (mostly it reduces to adding one additional clause into WHERE part of the SQL).

As you can see, there are actually 2 actors involved — the argument handler and the optional argument validator handler. They both are Views handlers and most of the stuff we have already learnt about handlers is just as applicable to them as to any other handler type.

Let’s begin by exposing an argument on the fruit.label column. Since this is just a string column, we can re-use the preexisting argument handler string. See below how you can report arguments to Views within hook_views_data().

At this point you should be able to set up contextual filter on the fruit label.

In my case I got the following set up:

Example of how to set up an argument (contextual filter).

And actual executed SQL was (the WHERE clause is coming from our argument!):

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

While making your way through the Views UI you might have noticed the part of the argument settings form that relates to argument validator, namely the “Specify validation criteria” checkbox. That’s where optional argument validator can be assigned to a contextual filter.

As an exercise we could write an argument handler that expects raw input in the format \d+(kg|lb), in other words things like ‘5kg’ or ‘10.2lb’ and filters fruits so only those of the requested weight are left in the query.

Hopefully by now you can follow most of the code above with little explanation. We basically take the raw input, explode it into 2 separate parts (value and unit) in ::explodeArgument() method, and rest is pretty identical to that of the filter handler (convert actual SQL value to the necessary unit and compare against argument’s value up to a given precision).

At this stage we are ready to leverage the argument handler for our particular fruit.weight column within our hook_views_data():

Go and have a little bit of fun with this new argument in your Views UI.

For example, on the following setup:

My actual SQL query was (again, WHERE clause is coming from our argument):

SELECT fruit.label AS fruit_label, fruit.weight AS fruit_weight, fruit.weight_unit AS fruit_weight_unit
FROM
{fruit} fruit
WHERE (ROUND(
CASE fruit.weight_unit
WHEN 'kg' THEN fruit.weight * '1'
WHEN 'lb' THEN fruit.weight * '0.4535924'
END
, '2') = '1')
LIMIT 11 OFFSET 0

While playing with it, you might discover that supplying malformed data as the argument input actually ruins it — SQL errors! This is exactly the zone of responsibility for argument validators. Unfortunately, there is not a single argument validator available within Drupal 8 core that could validate the input format we have picked \d+(kg|lb). This means we ought to code a custom one.

As we strive to make it as reusable as possible, we let the site-builder specify actual list of allowed terminations on the options form of this argument validator. The actual validation happens in the ::validateArgument() method where we assert provided raw argument in fact terminates with one of the allowed suffixes and that the beginning of the argument is numerical.

In the case of argument validators, we do not have to alter a thing within $views_data of hook_views_data(). All you have to do to kick it in is to change the configuration of your original contextual filter to use the Numeric ends with validator. Give it a shot and see that now SQL query does not break whenever we supply malformed input into the argument.

A little visual guidance on how to set up an argument validator.

This summarizes the notion of contextual filters (arguments) and a few concepts underneath them. The full code of fruity_views module for this chapter is available following this link. The branch is called part-4.

Continue to the part 5 here.

--

--