diff --git a/core/modules/system/src/Tests/Entity/FieldWidgetConstraintValidatorTest.php b/core/modules/system/src/Tests/Entity/FieldWidgetConstraintValidatorTest.php index 4a56198..0882a4c 100644 --- a/core/modules/system/src/Tests/Entity/FieldWidgetConstraintValidatorTest.php +++ b/core/modules/system/src/Tests/Entity/FieldWidgetConstraintValidatorTest.php @@ -7,7 +7,10 @@ namespace Drupal\system\Tests\Entity; +use Drupal\Component\Utility\SafeMarkup; +use Drupal\Core\Entity\EntityInterface; use Drupal\Core\Form\FormState; +use Drupal\entity_test\Entity\EntityTestCompositeConstraint; use Drupal\simpletest\KernelTestBase; use Drupal\system\Tests\TypedData; @@ -30,12 +33,13 @@ protected function setUp() { $this->container->get('router.builder')->rebuild(); $this->installEntitySchema('user'); + $this->installEntitySchema('entity_test_composite_constraint'); } /** * Tests widget constraint validation. */ - public function testValidation() { + public function ptestValidation() { $entity_type = 'entity_test_constraint_violation'; $entity = entity_create($entity_type, array('id' => 1, 'revision_id' => 1)); $display = entity_get_form_display($entity_type, $entity_type, 'default'); @@ -57,4 +61,82 @@ public function testValidation() { $this->assertEqual($errors['name'], 'Widget constraint has failed.', 'Constraint violation is generated correctly'); } + /** + * Gets the form errors for a given entity. + * + * @param \Drupal\Core\Entity\EntityInterface $entity + * The entity + * @param array $hidden_fields + * (optional) A list of hidden fields. + * + * @return array + * The form errors. + */ + protected function getErrorsForEntity(EntityInterface $entity, $hidden_fields = []) { + $entity_type_id = 'entity_test_composite_constraint'; + $display = entity_get_form_display($entity_type_id, $entity_type_id, 'default'); + + foreach ($hidden_fields as $hidden_field) { + $display->setComponent($hidden_field, []); + } + + $form = []; + $form_state = new FormState(); + $display->buildForm($entity, $form, $form_state); + + $form_state->setFormObject(\Drupal::entityManager()->getFormObject($entity_type_id, 'default')); + \Drupal::formBuilder()->prepareForm('field_test_entity_form', $form, $form_state); + \Drupal::formBuilder()->processForm('field_test_entity_form', $form, $form_state); + + // Validate the field constraint. + $form_state->getFormObject()->setEntity($entity)->setFormDisplay($display, $form_state); + $entity = $form_state->getFormObject()->buildEntity($form, $form_state); + $display->validateFormValues($entity, $form, $form_state); + + return $form_state->getErrors(); + } + + /** + * Tests widget constraint validation with composite constraints. + */ + public function testValidationWIthCompositeConstraint() { + // First provide a valid value, this should cause no validation. + $entity = EntityTestCompositeConstraint::create([ + 'name' => 'valid-value', + ]); + $entity->save(); + + $errors = $this->getErrorsForEntity($entity); + $this->assertFalse(isset($errors['name'])); + $this->assertFalse(isset($errors['type'])); + + // Provide an invalidate value for the name field. + $entity = EntityTestCompositeConstraint::create([ + 'name' => 'failure-field-name', + ]); + $errors = $this->getErrorsForEntity($entity); + $this->assertTrue(isset($errors['name'])); + $this->assertFalse(isset($errors['type'])); + + // Hide the second field (type) and ensure the validation still happens. The + // error message appears on the first field (name). + $entity = EntityTestCompositeConstraint::create([ + 'name' => 'failure-field-name', + ]); + $errors = $this->getErrorsForEntity($entity, ['type']); + $this->assertTrue(isset($errors['name'])); + $this->assertFalse(isset($errors['type'])); + + // Provide a violation again, but this time hide the first field (name). + // Ensure that the validation still happens and the error message is moved + // from the field field to the second field and have a custom error message. + $entity = EntityTestCompositeConstraint::create([ + 'name' => 'failure-field-name', + ]); + $errors = $this->getErrorsForEntity($entity, ['name']); + $this->assertFalse(isset($errors['name'])); + $this->assertTrue(isset($errors['type'])); + $this->assertEqual($errors['type'], Safemarkup::format('The provided value is invalid in the context of the current value of field %field-label.', ['%field-label' => 'Name'])); + } + } diff --git a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestCompositeConstraint.php b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestCompositeConstraint.php index c387b93..1085c92 100644 --- a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestCompositeConstraint.php +++ b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestCompositeConstraint.php @@ -6,6 +6,7 @@ */ namespace Drupal\entity_test\Entity; +use Drupal\Core\Entity\EntityTypeInterface; /** * Defines a test class for testing composite constraints. @@ -19,6 +20,11 @@ * "bundle" = "type", * "label" = "name" * }, + * handlers = { + * "form" = { + * "default" = "Drupal\entity_test\EntityTestForm" + * } + * }, * base_table = "entity_test_composite_constraint", * persistent_cache = FALSE, * constraints = { @@ -28,4 +34,23 @@ */ class EntityTestCompositeConstraint extends EntityTest { + /** + * {@inheritdoc} + */ + public static function baseFieldDefinitions(EntityTypeInterface $entity_type) { + $fields = parent::baseFieldDefinitions($entity_type); + + $fields['name']->setDisplayOptions('form', array( + 'type' => 'string', + 'weight' => 0, + )); + + $fields['type']->setDisplayOptions('form', array( + 'type' => 'entity_reference_autocomplete', + 'weight' => 0, + )); + + return $fields; + } + } diff --git a/core/modules/system/tests/modules/entity_test/src/Plugin/Validation/Constraint/EntityTestCompositeConstraintValidator.php b/core/modules/system/tests/modules/entity_test/src/Plugin/Validation/Constraint/EntityTestCompositeConstraintValidator.php index 54fb969..d643b74 100644 --- a/core/modules/system/tests/modules/entity_test/src/Plugin/Validation/Constraint/EntityTestCompositeConstraintValidator.php +++ b/core/modules/system/tests/modules/entity_test/src/Plugin/Validation/Constraint/EntityTestCompositeConstraintValidator.php @@ -7,6 +7,7 @@ namespace Drupal\entity_test\Plugin\Validation\Constraint; +use Drupal\Core\Entity\EntityTypeInterface; use Symfony\Component\Validator\Constraint; use Symfony\Component\Validator\ConstraintValidator; @@ -32,7 +33,16 @@ public function validate($entity, Constraint $constraint) { ->atPath('type') ->addViolation(); } - + if ($entity->name->value === 'failure-field-name') { + $this->context->buildViolation('Name field violation') + ->atPath('name') + ->addViolation(); + } + elseif ($entity->name->value === 'failure-field-type') { + $this->context->buildViolation('Type field violation') + ->atPath('type') + ->addViolation(); + } } }