3
0
Fork 0
mirror of https://github.com/farmOS/farmOS.git synced 2024-02-23 11:37:38 +01:00

Issue #3239940: UniqueBirthLogConstraint allows creating two birth logs for the same child

This commit is contained in:
Michael Stenta 2021-10-01 13:55:07 -04:00
commit 986c7a8331
2 changed files with 34 additions and 21 deletions

View file

@ -43,31 +43,33 @@ class UniqueBirthLogConstraintValidator extends ConstraintValidator implements C
* {@inheritdoc} * {@inheritdoc}
*/ */
public function validate($value, Constraint $constraint) { public function validate($value, Constraint $constraint) {
/** @var \Drupal\Core\Field\FieldItemListInterface[] $value */ /** @var \Drupal\Core\Field\EntityReferenceFieldItemList $value */
/** @var \Drupal\farm_birth\Plugin\Validation\Constraint\UniqueBirthLogConstraint $constraint */ /** @var \Drupal\farm_birth\Plugin\Validation\Constraint\UniqueBirthLogConstraint $constraint */
foreach ($value as $item) { foreach ($value->referencedEntities() as $delta => $asset) {
// Get the referenced asset ID. // If the log is not new, skip validation.
$item_value = $item->getValue(); // A birth log exits so there is no need to check if one can be created.
$asset_id = $item_value['target_id'] ?? FALSE; /** @var \Drupal\log\Entity\LogInterface $log */
$log = $value->getParent()->getValue();
// If there is no asset, skip. if (!$log->isNew()) {
if (empty($asset_id)) { return;
continue;
} }
// Perform an entity query to find logs that reference the asset. // Query the number of birth logs that reference the asset.
// We do not check access to ensure that all matching logs are found. // We do not check access to ensure that all matching logs are found.
$query = $this->entityTypeManager->getStorage('log')->getQuery() $count = $this->entityTypeManager->getStorage('log')->getAggregateQuery()
->accessCheck(FALSE) ->accessCheck(FALSE)
->condition('type', 'birth') ->condition('type', 'birth')
->condition('asset', $asset_id); ->condition('asset', $asset->id())
$ids = $query->execute(); ->count()
->execute();
// If more than 1 birth logs reference the asset, add a violation. // If more than 0 birth logs reference the asset, add a violation.
if (count($ids) > 1) { if ($count > 0) {
$asset = $this->entityTypeManager->getStorage('asset')->load($asset_id); $this->context->buildViolation($constraint->message, ['%child' => $asset->label()])
$this->context->addViolation($constraint->message, ['%child' => $asset->label()]); ->atPath((string) $delta . '.target_id')
->setInvalidValue($asset->id())
->addViolation();
} }
} }
} }

View file

@ -27,6 +27,7 @@ class BirthTest extends KernelTestBase {
'farm_birth', 'farm_birth',
'farm_entity', 'farm_entity',
'farm_entity_fields', 'farm_entity_fields',
'farm_entity_views',
'farm_field', 'farm_field',
'farm_id_tag', 'farm_id_tag',
'farm_log', 'farm_log',
@ -35,6 +36,7 @@ class BirthTest extends KernelTestBase {
'image', 'image',
'options', 'options',
'state_machine', 'state_machine',
'system',
'user', 'user',
'taxonomy', 'taxonomy',
'text', 'text',
@ -51,6 +53,7 @@ class BirthTest extends KernelTestBase {
$this->installEntitySchema('taxonomy_term'); $this->installEntitySchema('taxonomy_term');
$this->installEntitySchema('user'); $this->installEntitySchema('user');
$this->installConfig([ $this->installConfig([
'farm_entity_views',
'farm_animal', 'farm_animal',
'farm_animal_type', 'farm_animal_type',
'farm_birth', 'farm_birth',
@ -162,25 +165,33 @@ class BirthTest extends KernelTestBase {
'timestamp' => \Drupal::time()->getRequestTime(), 'timestamp' => \Drupal::time()->getRequestTime(),
'asset' => [['target_id' => $asset->id()]], 'asset' => [['target_id' => $asset->id()]],
]); ]);
$log1->save();
// Confirm that there were no validation errors. // Confirm that there are no validation errors.
$errors = $log1->validate(); $errors = $log1->validate();
$this->assertCount(0, $errors); $this->assertCount(0, $errors);
$log1->save();
// Create a second birth log that references the asset. // Create a second birth log that references the asset.
$log2 = Log::create([ $log2 = Log::create([
'type' => 'birth', 'type' => 'birth',
'timestamp' => \Drupal::time()->getRequestTime(), 'timestamp' => \Drupal::time()->getRequestTime(),
'asset' => [['target_id' => $asset->id()]], 'asset' => [['target_id' => $asset->id()]],
]); ]);
$log2->save();
// Confirm that validation fails. // Confirm that validation fails.
$errors = $log2->validate(); $errors = $log2->validate();
$this->assertCount(1, $errors); $this->assertCount(1, $errors);
$this->assertEquals(new FormattableMarkup('%child already has a birth log. More than one birth log cannot reference the same child.', ['%child' => $asset->label()]), $errors[0]->getMessage()); $this->assertEquals(new FormattableMarkup('%child already has a birth log. More than one birth log cannot reference the same child.', ['%child' => $asset->label()]), $errors[0]->getMessage());
$this->assertEquals('asset', $errors[0]->getPropertyPath()); $this->assertEquals('asset.0.target_id', $errors[0]->getPropertyPath());
// Try updating the original birth log.
$log1->set('name', $this->randomMachineName());
// Confirm there are no validation errors.
$errors = $log1->validate();
$this->assertCount(0, $errors);
$log1->save();
} }
} }