Custom Views argument

When we first exposed the player and team data to Views, we used an argument plugin so that we could have a contextual filter on the team ID a player belongs to. To do this, we used the existing numeric plugin on the actual team_id field of the players table. But what if we wanted an argument that works on more levels? For example, we don't exactly know what kind of data we'll receive, but we want to be able to handle nicely both a numeric one (team ID) and a textual one (team name). All in one argument. To achieve this, we can create a simple ViewsArgument plugin to handle this for us.

First thing, like always, is to define this field. We don't want to mess with the team_id field onto which we added the earlier argument as that can still be used. Instead, we'll create a new field, this time on the teams table, which we will simply call team:

$data['teams']['team'] = array( 
  'title' => t('Team'), 
  'help' => t('The team (either an ID or a team name).'), 
  'argument' => array( 
    'id' => 'team', 
  ), 
); 

This time, though, we don't create a field for it as we don't need this to display anything. Rather, we stick just to the argument responsibility, which will be handled by our new team plugin. You may also note that the team column doesn't actually exist in the database table.

So, let's see the plugin:

namespace Drupal\sports\Plugin\views\argument; 
 
use Drupal\views\Plugin\views\argument\ArgumentPluginBase; 
 
/** 
 * Argument for filtering by a team. 
 * 
 * @ViewsArgument("team") 
 */ 
class Team extends ArgumentPluginBase { 
 
  /** 
   * {@inheritdoc} 
   */ 
  public function query($group_by = FALSE) { 
    $this->ensureMyTable(); 
    $field = is_numeric($this->argument) ? 'id' : 'name'; 
    $this->query->addWhere(0, "$this->tableAlias.$field", $this->argument); 
  } 
}  

As usual, we are extending from the base plugin class of its type and adding the proper annotation. Inside, we only deal with the query() method, which we override. Arguments are very similar to filters in the sense that they aim to restrict the result set via the query. The main difference is the actual value used to filter, which, in this case, is dynamic and can be found on the $argument property of the (parent) class. And what we do is simply add a query condition to the right field on the teams table (since that is the base table), depending on the type of data we are dealing with. But before we do that, we call the ensureMyTable() method which simply ensures that the table our plugin needs is included in the query by Views.

That's it. We can now add our newly created argument to the View and, regardless of what we passed as a contextual filter (ID or name), it will filter accordingly. Of course, we can also have options like most other Views plugin types, but I'll let you explore those on your own. There are also a lot more we can override from the parent class in order to integrate with Views. But that's a bit more advanced and it's unlikely you'll need to deal with that for a good while. I definitely recommend exploring the code behind it.