diff --git a/core/lib/Drupal/Core/Entity/Plugin/Validation/Constraint/EntityChangedConstraintValidator.php b/core/lib/Drupal/Core/Entity/Plugin/Validation/Constraint/EntityChangedConstraintValidator.php index b6391af4a9..6906999596 100644 --- a/core/lib/Drupal/Core/Entity/Plugin/Validation/Constraint/EntityChangedConstraintValidator.php +++ b/core/lib/Drupal/Core/Entity/Plugin/Validation/Constraint/EntityChangedConstraintValidator.php @@ -18,26 +18,25 @@ public function validate($entity, Constraint $constraint) { /** @var \Drupal\Core\Entity\EntityInterface $entity */ if (!$entity->isNew()) { $saved_entity = \Drupal::entityManager()->getStorage($entity->getEntityTypeId())->loadUnchanged($entity->id()); - // We have to ensure that all the entity translations match their - // current version in the storage in order to avoid reverting changes. - // A situation where the entity object contains an older entity - // translation version might occur when an entity translation is being - // concurrently edited. If the form that is being submitted last is not - // yet cached then on submitting it the entity will be retrieved from - // the entity storage and that entity object will be the updated one - // from the previous form submission. As a prevention of saving the - // entity resulting from the second submission the changed timestamp - // might be added to the form so that on submit it is set back on the - // entity object, which should be used to determine that a previous - // entity translation version has been edited and is currently being - // saved. We could compare only the latest changed timestamps across all - // translations to detect such cases. Unfortunatelly this comparison - // will not be sufficient if other translations of the entity have been - // edited and saved meanwhile, therefore we have to compare the changed - // timestamps of each entity translation individually. + // Ensure that all the entity translations match their current version + // in the storage in order to avoid reverting other changes. The entity + // object might contain an older entity translation when a translation + // is being concurrently edited. If the form that is submitted last + // is not yet cached, the entity will be retrieved from the entity + // storage on submit, and that entity object will be the updated one + // from the previous form submission. To prevent the entity from the + // second submission from being saved and overwriting changes from the + // first, the changed timestamp can be added to the form so that it + // updates the entity object on submit. We use the timestamp to + // determine when a previous entity translation version has been edited + // and is currently being saved. if ($saved_entity) { $common_translation_languages = array_intersect_key($entity->getTranslationLanguages(), $saved_entity->getTranslationLanguages()); foreach (array_keys($common_translation_languages) as $langcode) { + // Merely comparing the latest changed timestamps across all + // translations is not sufficient since other translations may have + // been edited and saved in the meanwhile. Therefore, compare the + // changed timestamps of each entity translation individually. if ($saved_entity->getTranslation($langcode)->getChangedTime() > $entity->getTranslation($langcode)->getChangedTime()) { $this->context->addViolation($constraint->message); break;