function UniqueFieldValueValidator::validate

Same name and namespace in other branches
  1. 9 core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/UniqueFieldValueValidator.php \Drupal\Core\Validation\Plugin\Validation\Constraint\UniqueFieldValueValidator::validate()
  2. 8.9.x core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/UniqueFieldValueValidator.php \Drupal\Core\Validation\Plugin\Validation\Constraint\UniqueFieldValueValidator::validate()
  3. 11.x core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/UniqueFieldValueValidator.php \Drupal\Core\Validation\Plugin\Validation\Constraint\UniqueFieldValueValidator::validate()

File

core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/UniqueFieldValueValidator.php, line 41

Class

UniqueFieldValueValidator
Validates that a field is unique for the given entity type.

Namespace

Drupal\Core\Validation\Plugin\Validation\Constraint

Code

public function validate($items, Constraint $constraint) {
  if (!$items->first()) {
    return;
  }
  /** @var \Drupal\Core\Entity\EntityInterface $entity */
  $entity = $items->getEntity();
  $entity_type = $entity->getEntityType();
  $entity_type_id = $entity_type->id();
  $entity_label = $entity->getEntityType()
    ->getSingularLabel();
  $field_name = $items->getFieldDefinition()
    ->getName();
  $field_label = $items->getFieldDefinition()
    ->getLabel();
  $field_storage_definitions = $this->entityFieldManager
    ->getFieldStorageDefinitions($entity_type_id);
  $property_name = $field_storage_definitions[$field_name]->getMainPropertyName();
  $id_key = $entity_type->getKey('id');
  $is_multiple = $field_storage_definitions[$field_name]->isMultiple();
  $is_new = $entity->isNew();
  $item_values = array_column($items->getValue(), $property_name);
  // Check if any item values for this field already exist in other entities.
  $query = $this->entityTypeManager
    ->getStorage($entity_type_id)
    ->getAggregateQuery()
    ->accessCheck(FALSE)
    ->groupBy("{$field_name}.{$property_name}");
  if (!$is_new) {
    $entity_id = $entity->id();
    $query->condition($id_key, $entity_id, '<>');
  }
  if ($constraint->caseSensitive) {
    $query->condition($field_name, $item_values, 'IN');
  }
  else {
    $or_group = $query->orConditionGroup();
    foreach ($item_values as $item_value) {
      $or_group->condition($field_name, \Drupal::database()->escapeLike($item_value), 'LIKE');
    }
    $query->condition($or_group);
  }
  $results = $query->execute();
  if (!empty($results)) {
    // The results array is a single-column multidimensional array. The
    // column key includes the field name but may or may not include the
    // property name. Pop the column key from the first result to be sure.
    $column_key = key(reset($results));
    $other_entity_values = array_column($results, $column_key);
    // If our entity duplicates field values in any other entity, the query
    // will return all field values that belong to those entities. Narrow
    // down to only the specific duplicate values.
    $duplicate_values = $this->caseInsensitiveArrayIntersect($item_values, $other_entity_values);
    foreach ($duplicate_values as $delta => $dupe) {
      $violation = $this->context
        ->buildViolation($constraint->message)
        ->setParameter('@entity_type', $entity_label)
        ->setParameter('@field_name', $field_label)
        ->setParameter('%value', $dupe);
      if ($is_multiple) {
        $violation->atPath((string) $delta);
      }
      $violation->addViolation();
    }
  }
  // Check if items are duplicated within this entity.
  if ($is_multiple) {
    $duplicate_values = $this->extractDuplicates($item_values);
    foreach ($duplicate_values as $delta => $dupe) {
      $this->context
        ->buildViolation($constraint->message)
        ->setParameter('@entity_type', $entity_label)
        ->setParameter('@field_name', $field_label)
        ->setParameter('%value', $dupe)
        ->atPath((string) $delta)
        ->addViolation();
    }
  }
}

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