Without seeing all the code used for the custom_type entity, including the code for its handlers, and answering to why the code doesn't find duplicates, there are two "flaws" I can imagine possible in the shown code.
The first "flaw" is that the query searching for existing entities is more restrictive than it should. This means it checks for entity fields that should be irrelevant for the entities to be duplicates, for example:
- The status field, assuming it's the status field used by the Drupal core entities
- The date field, assuming it contains the creation date/timestamp
The only Drupal core entity that uses an entity validation to avoid duplicate entities are created is the path_alias entity, implemented by the PathAlias
class. That entity has a status field, it supports revisions, but it doesn't have a field to store when it has been created, nor does it have an owner entity (like nodes do).
UniquePathAliasConstraintValidator
is its entity constraint validator; the code for UniquePathAliasConstraintValidator::validate()
is the following one.
$path = $entity->getPath();
$alias = $entity->getAlias();
$langcode = $entity->language()->getId();
$storage = $this->entityTypeManager->getStorage('path_alias');
$query = $storage->getQuery()
->accessCheck(FALSE)
->condition('alias', $alias, '=')
->condition('langcode', $langcode, '=');
if (!$entity->isNew()) {
$query->condition('id', $entity->id(), '<>');
}
if ($path) {
$query->condition('path', $path, '<>');
}
if ($result = $query->range(0, 1)->execute()) {
$existing_alias_id = reset($result);
$existing_alias = $storage->load($existing_alias_id);
if ($existing_alias->getAlias() !== $alias) {
$this->context->buildViolation($constraint->differentCapitalizationMessage, ['%alias' => $alias, '%stored_alias' => $existing_alias->getAlias()])
->addViolation();
}
else {
$this->context->buildViolation($constraint->message, ['%alias' => $alias])
->addViolation();
}
}
}
Using that code as example, and using only the code that strictly checks for duplicates, in your case I would use the following code. (I am showing only the code for isUnique()
.)
private function isUnique(CustomType $entity) {
$date = $entity->get('date')->value;
$type = $entity->bundle();
$employee = $entity->get('employee')->target_id;
$query = $this->entityTypeManager->getStorage('custom_type')
->getQuery()
->accessCheck(FALSE)
->condition('type', $type)
->condition('employee', $employee)
->condition('date', $date);
if (!$entity->isNew()) {
$query->condition('id', $entity->id(), '<>');
}
$result = $query->range(0, 1)->execute();
return empty($result);
}
I added the call to accessCheck(FALSE)
because, without seeing the code used by the entity access handler, and without knowing if the entity has an owner entity, I cannot exclude the implementation of isUnique()
isn't finding duplicates because the currently logged-in user doesn't have access to the duplicates (or any entity of that type). Without calling accessCheck(FALSE)
, the query will return the entities to which the currently logged-in user has access.
(The missing call to accessCheck(FALSE)
is the other, possible, "flaw" I can see in the shown code.)