function EntityAutocomplete::validateEntityAutocomplete

Same name in other branches
  1. 8.9.x core/lib/Drupal/Core/Entity/Element/EntityAutocomplete.php \Drupal\Core\Entity\Element\EntityAutocomplete::validateEntityAutocomplete()
  2. 10 core/lib/Drupal/Core/Entity/Element/EntityAutocomplete.php \Drupal\Core\Entity\Element\EntityAutocomplete::validateEntityAutocomplete()
  3. 11.x 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 197

Class

EntityAutocomplete
Provides an entity autocomplete form element.

Namespace

Drupal\Core\Entity\Element

Code

public static function validateEntityAutocomplete(array &$element, FormStateInterface $form_state, array &$complete_form) {
    $value = NULL;
    if (!empty($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);
}

Buggy or inaccurate documentation? Please file an issue. Need support? Need help programming? Connect with the Drupal community.