I have a use case where the content author would like to search for an entity through the entity reference autocomplete widget but not by the title field. They would like to search for results by another field on the entity. It would be very nice to not have to completely override the autocomplete callback function but instead have an alter at the end of the autocomplete request that allows other modules to add their matches

eg:


function entityreference_autocomplete_callback_get_matches($type, $field, $instance, $entity_type, $entity_id = '', $string = '') {
  $matches = array();

  $entity = NULL;
  if ($entity_id !== 'NULL') {
    $entity = entity_load_single($entity_type, $entity_id);
    if (!$entity || !entity_access('view', $entity_type, $entity)) {
      return MENU_ACCESS_DENIED;
    }
  }

  $handler = entityreference_get_selection_handler($field, $instance, $entity_type, $entity);

  if ($type == 'tags') {
    // The user enters a comma-separated list of tags. We only autocomplete the last tag.
    $tags_typed = drupal_explode_tags($string);
    $tag_last = drupal_strtolower(array_pop($tags_typed));
    if (!empty($tag_last)) {
      $prefix = count($tags_typed) ? implode(', ', $tags_typed) . ', ' : '';
    }
  }
  else {
    // The user enters a single tag.
    $prefix = '';
    $tag_last = $string;
  }

  if (isset($tag_last)) {
    // Get an array of matching entities.
    $entity_labels = $handler->getReferencableEntities($tag_last, $instance['widget']['settings']['match_operator'], 10);

    // Loop through the products and convert them into autocomplete output.
    foreach ($entity_labels as $values) {
      foreach ($values as $entity_id => $label) {
        $key = "$label ($entity_id)";
        // Strip things like starting/trailing white spaces, line breaks and tags.
        $key = preg_replace('/\s\s+/', ' ', str_replace("\n", '', trim(decode_entities(strip_tags($key)))));
        // Names containing commas or quotes must be wrapped in quotes.
        if (strpos($key, ',') !== FALSE || strpos($key, '"') !== FALSE) {
          $key = '"' . str_replace('"', '""', $key) . '"';
        }
        $matches[$prefix . $key] = '<div class="reference-autocomplete">' . $label . '</div>';
      }
    }
  }

  // implment a hook to futz with autocomplete results so that other modules may add their results or alter these ones :)
  foreach (module_implements('entityreference_alter_matches') as $module) {
    $function = $module . '_entityreference_alter_matches';
    $function($matches, $field, $instance, $entity_type, $entity_id, $string);
  }

  drupal_json_output($matches);
}


Support from Acquia helps fund testing for Drupal Acquia logo

Comments

rudiedirkx’s picture

I'd like this too, but of course using drupal_alter():

$context = compact('type', 'field', 'instance', 'entity_type', 'entity');
drupal_alter('entityreference_matches', $matches, $context);
mcpuddin’s picture

This would be very nice to have. The only other option I found is this roundabout way of altering the callback.

guillaumev’s picture

Status: Active » Needs review
FileSize
473 bytes

I also need this, to alter the output of the results. Here is a patch that adds the alter hook from #1

rudiedirkx’s picture

Status: Needs review » Reviewed & tested by the community

Perfect.

@mcpuddin That's smart. Did you copy all logic or use the normal function and json_decode() its result?

DamienMcKenna’s picture

MorinLuc0’s picture

Status: Reviewed & tested by the community » Needs work

This patch in #3 will not solve the above issue.

If a user already typed in a text in the entity reference field the string parameter has already been searched at the point of execution before your drupal_alter takes effect.

Essentially your list will have already been trimmed by what was searched in the entity reference against the label.

If we wanted to make the entity reference field configurable to search based on a configured field the handlers would need to be modified to access a configured parameter. Because at this point it always uses the entity label as the search key.

  /**
   * Build an EntityFieldQuery to get referencable entities.
   */
  protected function buildEntityFieldQuery($match = NULL, $match_operator = 'CONTAINS') {
    $query = new EntityFieldQuery();
    $query->entityCondition('entity_type', $this->field['settings']['target_type']);
    if (!empty($this->field['settings']['handler_settings']['target_bundles'])) {
      $query->entityCondition('bundle', $this->field['settings']['handler_settings']['target_bundles'], 'IN');
    }
    if (isset($match)) {
      $entity_info = entity_get_info($this->field['settings']['target_type']);
      if (isset($entity_info['entity keys']['label'])) {
        $query->propertyCondition($entity_info['entity keys']['label'], $match, $match_operator);
      }
    }
judapriest’s picture

Status: Needs work » Needs review
FileSize
3.34 KB
3.69 KB

Updating the patch :
- small improvement
- renaming the alter, as a conflict were issue with another contrib : entityreference_autocomplete
- Adding an api file

judapriest’s picture

Title: Add an alter matches hook so other modules may adjust the autocomplete » Add an alter matches hook so other modules may adjust the label displayed
q0rban’s picture

Title: Add an alter matches hook so other modules may adjust the label displayed » Allow autocomplete searching on a field other than title
Status: Needs review » Needs work

@MorinLuc0 is correct, the attached solutions do not solve the request as described by the OP. The request is to be able to search by a field other than the title field, not simply to display something different in the search field.

For those that would like to accomplish what is described (searching by a field other than title), you can provide your own custom autocomplete_path using a form alter, and then perform the search as desired there. In my opinion, that would be the preferred method, rather than using an alter. Alters are memory-intensive and slow, and autocompletes need to be fast to be useful.

If you are just interested in altering the displayed text and not what content to search, may I direct you to #3017242: Allow for modification of autocomplete matches.

judapriest’s picture

It would be very nice to not have to completely override the autocomplete callback function but instead have an alter at the end of the autocomplete request that allows other modules to add their matches

Isn't that we did ?