Change entity autocomplete selection rules in Drupal 8

Mar 21, 2019
By Ihor
Drupal

I've prepared a particular topic for Drupal enthusiasts and passionate community members. It's about the Drupal 8 trick that can make your coding life more comfortable.

Drupal 8 contains a new form element called entity_autocomplete. For example, this code shows an essential autocomplete element that matches node titles from all bundles:

$form['my_element'] = [
  '#type' => 'entity_autocomplete',
  '#target_type' => 'node',
  // #default_value - Entity object or an array of entity objects.
  '#default_value' => $entity,
];

The entity type is required in #target_type. If we want to restrict the matches to a single or a set of bundles, we can use the target_bundles selection setting:

$form['my_element'] = [
  '#type' => 'entity_autocomplete',
  '#target_type' => 'node',
  '#selection_settings' => [
    'target_bundles' => ['article', 'page'],
  ],
];

#selection_settings – an array of settings passed to the selection handler.

If we want to allow input of multiple entity labels into the element (commonly known as "tagging" fields), we set the #tags property to TRUE (its default value is FALSE):

$form['my_element'] = [
  '#type' => 'entity_autocomplete',
  '#target_type' => 'node',
  '#tags' => TRUE,
];

In some cases, we need to use specific selection rules for autocomplete results. And, in this case, #selection_handler param can help. The default selection handler is pre-populated to 'default'. You can set here a plugin ID of the entity reference selection handler.

For example, we want to get results filtered by value from the node field. That's how it should look:

$form['my_element'] = [
  '#type' => 'entity_autocomplete',
  '#target_type' => 'node',
  '#selection_handler' => 'default:node_by_field',
  '#selection_settings' => [
    'target_bundles' => ['article'],
    'filter' => ['field_dummy_filter' => $dummy_field_value],
  ],
];

Where:

  • default:node_by_field – custom selection handler
  • filter – param that used in custom selection handler.

For default:node_by_field custom selection handler we need to create EntityReferenceSelection plugin extended from NodeSelection class:

<?php

namespace Drupal\test_module_name\Plugin\EntityReferenceSelection;

use Drupal\node\Plugin\EntityReferenceSelection\NodeSelection;

/**
 * Provides specific access control for the node entity type.
 *
 * @EntityReferenceSelection(
 *   id = "default:node_by_field",
 *   label = @Translation("Node by field selection"),
 *   entity_types = {"node"},
 *   group = "default",
 *   weight = 3
 * )
 */
class NodeByFieldSelection extends NodeSelection {

  /**
   * {@inheritdoc}
   */
  protected function buildEntityQuery($match = NULL, $match_operator = 'CONTAINS') {
    $query = parent::buildEntityQuery($match, $match_operator);
    $handler_settings = $this->configuration['handler_settings'];
    if (!isset($handler_settings['filter'])) {
      return $query;
    }
    $filter_settings = $handler_settings['filter'];
    foreach ($filter_settings as $field_name => $value) {
      $query->condition($field_name, $value, '=');
    }
    return $query;
  }

}

As a result, entity_autocomplete will show only nodes that meet the additional condition.

Ihor
Ihor
Developer with 8 years of experience in developing web applications. His extensive expertise in web application integration with third-party services allowed him to succeed working on e-commerce projects, sites for startups, sites for Medicine & Health companies.

LET'S CONNECT

Get a stunning website, integrate with your tools,
measure, optimize and focus on success!