Same name and namespace in other branches
  1. 8.9.x core/lib/Drupal/Core/Entity/Element/EntityAutocomplete.php \Drupal\Core\Entity\Element\EntityAutocomplete::validateEntityAutocomplete()
  2. 9 core/lib/Drupal/Core/Entity/Element/EntityAutocomplete.php \Drupal\Core\Entity\Element\EntityAutocomplete::validateEntityAutocomplete()

Form element validation handler for entity_autocomplete elements.

File

core/lib/Drupal/Core/Entity/Element/EntityAutocomplete.php, line 203

Class

EntityAutocomplete

Namespace

Drupal\Core\Entity\Element

Code

public static function validateEntityAutocomplete(array &$element, FormStateInterface $form_state, array &$complete_form) {
  $value = NULL;

  // Check the value for emptiness, but allow the use of (string) "0".
  if (!empty($element['#value']) || is_string($element['#value']) && strlen($element['#value'])) {
    $options = $element['#selection_settings'] + [
      'target_type' => $element['#target_type'],
      'handler' => $element['#selection_handler'],
    ];

    /** @var \Drupal\Core\Entity\EntityReferenceSelection\SelectionInterface $handler */
    $handler = \Drupal::service('plugin.manager.entity_reference_selection')
      ->getInstance($options);
    $autocreate = (bool) $element['#autocreate'] && $handler instanceof SelectionWithAutocreateInterface;

    // GET forms might pass the validated data around on the next request, in
    // which case it will already be in the expected format.
    if (is_array($element['#value'])) {
      $value = $element['#value'];
    }
    else {
      $input_values = $element['#tags'] ? Tags::explode($element['#value']) : [
        $element['#value'],
      ];
      foreach ($input_values as $input) {
        $match = static::extractEntityIdFromAutocompleteInput($input);
        if ($match === NULL) {

          // Try to get a match from the input string when the user didn't use
          // the autocomplete but filled in a value manually.
          $match = static::matchEntityByTitle($handler, $input, $element, $form_state, !$autocreate);
        }
        if ($match !== NULL) {
          $value[] = [
            'target_id' => $match,
          ];
        }
        elseif ($autocreate) {

          /** @var \Drupal\Core\Entity\EntityReferenceSelection\SelectionWithAutocreateInterface $handler */

          // Auto-create item. See an example of how this is handled in
          // \Drupal\Core\Field\Plugin\Field\FieldType\EntityReferenceItem::presave().
          $value[] = [
            'entity' => $handler
              ->createNewEntity($element['#target_type'], $element['#autocreate']['bundle'], $input, $element['#autocreate']['uid']),
          ];
        }
      }
    }

    // Check that the referenced entities are valid, if needed.
    if ($element['#validate_reference'] && !empty($value)) {

      // Validate existing entities.
      $ids = array_reduce($value, function ($return, $item) {
        if (isset($item['target_id'])) {
          $return[] = $item['target_id'];
        }
        return $return;
      });
      if ($ids) {
        $valid_ids = $handler
          ->validateReferenceableEntities($ids);
        if ($invalid_ids = array_diff($ids, $valid_ids)) {
          foreach ($invalid_ids as $invalid_id) {
            $form_state
              ->setError($element, t('The referenced entity (%type: %id) does not exist.', [
              '%type' => $element['#target_type'],
              '%id' => $invalid_id,
            ]));
          }
        }
      }

      // Validate newly created entities.
      $new_entities = array_reduce($value, function ($return, $item) {
        if (isset($item['entity'])) {
          $return[] = $item['entity'];
        }
        return $return;
      });
      if ($new_entities) {
        if ($autocreate) {
          $valid_new_entities = $handler
            ->validateReferenceableNewEntities($new_entities);
          $invalid_new_entities = array_diff_key($new_entities, $valid_new_entities);
        }
        else {

          // If the selection handler does not support referencing newly
          // created entities, all of them should be invalidated.
          $invalid_new_entities = $new_entities;
        }
        foreach ($invalid_new_entities as $entity) {

          /** @var \Drupal\Core\Entity\EntityInterface $entity */
          $form_state
            ->setError($element, t('This entity (%type: %label) cannot be referenced.', [
            '%type' => $element['#target_type'],
            '%label' => $entity
              ->label(),
          ]));
        }
      }
    }

    // Use only the last value if the form element does not support multiple
    // matches (tags).
    if (!$element['#tags'] && !empty($value)) {
      $last_value = $value[count($value) - 1];
      $value = $last_value['target_id'] ?? $last_value;
    }
  }
  $form_state
    ->setValueForElement($element, $value);
}