Joining two views in Drupal 8

Suppose that the information to be displayed comes from two different views that somehow needs to be joined.  In SQL this can be done using a "UNION' but Views does not have such a construct.  But it does not take a lot of code to achieve this in Drupal 8.

States by author viewCreate example

The example for this will be a listing of books by state.  The book can be set in a particular state or the author may reside in that state; we want to display books in either case.  First start by creating a vocabulary named State.  Add several states to the vocabulary including Arizona and New Mexico.

The next step is to create a couple new content types.  The Author content type should have a State field which is an entity reference to the State vocabulary.  The Book content type should also have the same State field and also an Author field which is an entity reference to the Author content type.  Now add some content using these content types.  For an author add Tony Hillerman and the state of New Mexico.  For a book enter "A Thief of Time" and Arizona for where it takes place and Tony Hillerman as the author.

Create views

Now create two views.  The first view is "Books by author" which will be page with an HTML list of fields from the Book content type.  The two fields are the title of the book with a link to the node and the author without a link.  The path should be /books-by-author.  It should look like the first image.

Now on the right of the screen open the advanced options.  Under relationships we want to add the author content referenced in the author field.  Also add the state field and under the Relationship select box add to use the author field so we get the state for the author.  The last step is to add a contextual filter for the state.  The filter should be for the term name and use the state field for the relationship.  Select "Provide default value" with "Raw value from URL" and 2 for the "Path component."  For "Case in path" select lower case.  The result should look like the second image.  Save the view.Advanced options for the second view.

The second view is "Books by state" which should be the same as the first view but with a path /books-by-state.  For the advanced options the first relationship is the same.  The second relationship is the taxonomy term in the state field.  The author relationship is not going to be used but is included because the union requires the same number of fields in both queries.  The contextual filter should be similar to the first view.  The third image shows the advanced options for the second view which are similar to the first view.

Now test the views.  The path books-by-author/arizona should not show any books.  For books-by-author/new mexico the book A Thief of Time by Tony Hillerman should appear.  books-by-state/new mexico should have no books while books-by-state/arizona should list one book.  If you get different results then go Advanced options for viewback and edit the views to get them working correctly.

Add code with union

Now we want to alter the books by state view so it joins the two views.  It is time to write some code but it will not take a lot of code to achieve our goal.  Create a new custom module which we will call union.  The union.info.yml file is simple.

name: Union
type: module
description: Union two views.
core: 8.x

Now add a union.module file with an implementation of hook_views_pre_execute().

use Drupal\views\Views;
use Drupal\views\ViewExecutable;

/**
 * Implements hook_views_pre_execute().
 */
function union_views_pre_execute(ViewExecutable $view) {
  if ($view->id() == 'books_by_state') {
    $view_by_author = Views::getView('books_by_author');
    $view_by_author->build();
    $query_by_author = $view_by_author->build_info['query'];

    $query_by_state = &$view->build_info['query'];

    $query_by_state->union($query_by_author);
  }
}

The change is only applied to the books by state view. The first three lines gets the books by author view and constructs the SQL query. Then we get a reference to the SQL query for the books by state view. The last line we add a union to the books by state query and pass the books by author query. This is pretty straightforward if everything is correct but it is easy to get something wrong and run into problems. If everything is working then we can go to books-by-state/new mexico and the book should appear. But since views are cached make sure that the cache is flushed first. The result should be similar to the following image.

Two views joined by a union.

Categories