Loading core/lib/Drupal/Core/TypedData/DataDefinition.php +13 −0 Original line number Diff line number Diff line Loading @@ -261,6 +261,19 @@ public function setSetting($setting_name, $value) { public function getConstraints() { $constraints = $this->definition['constraints'] ?? []; $constraints += $this->getTypedDataManager()->getDefaultConstraints($this); // If either the constraints defined on this data definition or the default // constraints for this data definition's type contain the `NotBlank` // constraint, then prevent a validation error from `NotBlank` if `NotNull` // already would generate one. (When both are present, `NotBlank` should // allow a NULL value, otherwise there will be two validation errors with // distinct messages for the exact same problem. Automatically configuring // `NotBlank`'s `allowNull: true` option mitigates that.) // @see ::isRequired() // @see \Drupal\Core\TypedData\TypedDataManager::getDefaultConstraints() if (array_key_exists('NotBlank', $constraints) && $this->isRequired()) { assert(array_key_exists('NotNull', $constraints)); $constraints['NotBlank']['allowNull'] = TRUE; } return $constraints; } Loading core/modules/config/tests/config_test/config/install/config_test.validation.yml +1 −0 Original line number Diff line number Diff line Loading @@ -7,3 +7,4 @@ giraffe: hum2: hum2 uuid: '7C30C50E-641A-4E34-A7F1-46BCFB9BE5A3' langcode: en string__not_blank: 'this is a label' core/modules/config/tests/config_test/config/schema/config_test.schema.yml +6 −0 Original line number Diff line number Diff line Loading @@ -206,3 +206,9 @@ config_test.validation: callback: [\Drupal\config_test\ConfigValidation, validateGiraffes] uuid: type: uuid # @see \Drupal\KernelTests\Config\TypedConfigTest::testNotBlankInteractionWithNotNull() string__not_blank: type: string constraints: NotBlank: {} core/tests/Drupal/KernelTests/Config/TypedConfigTest.php +29 −1 Original line number Diff line number Diff line Loading @@ -95,7 +95,7 @@ public function testTypedDataAPI() { $typed_config_manager = \Drupal::service('config.typed'); $typed_config = $typed_config_manager->createFromNameAndData('config_test.validation', \Drupal::configFactory()->get('config_test.validation')->get()); $this->assertInstanceOf(TypedConfigInterface::class, $typed_config); $this->assertEquals(['_core', 'llama', 'cat', 'giraffe', 'uuid', 'langcode'], array_keys($typed_config->getElements())); $this->assertEquals(['_core', 'llama', 'cat', 'giraffe', 'uuid', 'langcode', 'string__not_blank'], array_keys($typed_config->getElements())); $this->assertSame('config_test.validation', $typed_config->getName()); $this->assertSame('config_test.validation', $typed_config->getPropertyPath()); $this->assertSame('config_test.validation.llama', $typed_config->get('llama')->getPropertyPath()); Loading @@ -112,6 +112,34 @@ public function testTypedDataAPI() { $this->assertEquals(['uuid', 'langcode', 'status', 'dependencies', 'id', 'label', 'weight', 'style', 'size', 'size_value', 'protected_property'], array_keys($typed_config->getElements())); } /** * Tests the behavior of `NotBlank` on required data. * * @testWith ["", false, "This value should not be blank."] * ["", true, "This value should not be blank."] * [null, false, "This value should not be blank."] * [null, true, "This value should not be null."] * * @see \Drupal\Core\TypedData\DataDefinition::getConstraints() * @see \Drupal\Core\TypedData\DataDefinitionInterface::isRequired() * @see \Drupal\Core\Validation\Plugin\Validation\Constraint\NotNullConstraint * @see \Symfony\Component\Validator\Constraints\NotBlank::$allowNull */ public function testNotBlankInteractionWithNotNull(?string $value, bool $is_required, string $expected_message): void { \Drupal::configFactory()->getEditable('config_test.validation') ->set('string__not_blank', $value) ->save(); $typed_config = \Drupal::service('config.typed')->get('config_test.validation'); $typed_config->get('string__not_blank')->getDataDefinition()->setRequired($is_required); $result = $typed_config->validate(); // Expect 1 validation error message: the one from `NotBlank` or `NotNull`. $this->assertCount(1, $result); $this->assertSame('string__not_blank', $result->get(0)->getPropertyPath()); $this->assertEquals($expected_message, $result->get(0)->getMessage()); } /** * Tests config validation via the Typed Data API. */ Loading Loading
core/lib/Drupal/Core/TypedData/DataDefinition.php +13 −0 Original line number Diff line number Diff line Loading @@ -261,6 +261,19 @@ public function setSetting($setting_name, $value) { public function getConstraints() { $constraints = $this->definition['constraints'] ?? []; $constraints += $this->getTypedDataManager()->getDefaultConstraints($this); // If either the constraints defined on this data definition or the default // constraints for this data definition's type contain the `NotBlank` // constraint, then prevent a validation error from `NotBlank` if `NotNull` // already would generate one. (When both are present, `NotBlank` should // allow a NULL value, otherwise there will be two validation errors with // distinct messages for the exact same problem. Automatically configuring // `NotBlank`'s `allowNull: true` option mitigates that.) // @see ::isRequired() // @see \Drupal\Core\TypedData\TypedDataManager::getDefaultConstraints() if (array_key_exists('NotBlank', $constraints) && $this->isRequired()) { assert(array_key_exists('NotNull', $constraints)); $constraints['NotBlank']['allowNull'] = TRUE; } return $constraints; } Loading
core/modules/config/tests/config_test/config/install/config_test.validation.yml +1 −0 Original line number Diff line number Diff line Loading @@ -7,3 +7,4 @@ giraffe: hum2: hum2 uuid: '7C30C50E-641A-4E34-A7F1-46BCFB9BE5A3' langcode: en string__not_blank: 'this is a label'
core/modules/config/tests/config_test/config/schema/config_test.schema.yml +6 −0 Original line number Diff line number Diff line Loading @@ -206,3 +206,9 @@ config_test.validation: callback: [\Drupal\config_test\ConfigValidation, validateGiraffes] uuid: type: uuid # @see \Drupal\KernelTests\Config\TypedConfigTest::testNotBlankInteractionWithNotNull() string__not_blank: type: string constraints: NotBlank: {}
core/tests/Drupal/KernelTests/Config/TypedConfigTest.php +29 −1 Original line number Diff line number Diff line Loading @@ -95,7 +95,7 @@ public function testTypedDataAPI() { $typed_config_manager = \Drupal::service('config.typed'); $typed_config = $typed_config_manager->createFromNameAndData('config_test.validation', \Drupal::configFactory()->get('config_test.validation')->get()); $this->assertInstanceOf(TypedConfigInterface::class, $typed_config); $this->assertEquals(['_core', 'llama', 'cat', 'giraffe', 'uuid', 'langcode'], array_keys($typed_config->getElements())); $this->assertEquals(['_core', 'llama', 'cat', 'giraffe', 'uuid', 'langcode', 'string__not_blank'], array_keys($typed_config->getElements())); $this->assertSame('config_test.validation', $typed_config->getName()); $this->assertSame('config_test.validation', $typed_config->getPropertyPath()); $this->assertSame('config_test.validation.llama', $typed_config->get('llama')->getPropertyPath()); Loading @@ -112,6 +112,34 @@ public function testTypedDataAPI() { $this->assertEquals(['uuid', 'langcode', 'status', 'dependencies', 'id', 'label', 'weight', 'style', 'size', 'size_value', 'protected_property'], array_keys($typed_config->getElements())); } /** * Tests the behavior of `NotBlank` on required data. * * @testWith ["", false, "This value should not be blank."] * ["", true, "This value should not be blank."] * [null, false, "This value should not be blank."] * [null, true, "This value should not be null."] * * @see \Drupal\Core\TypedData\DataDefinition::getConstraints() * @see \Drupal\Core\TypedData\DataDefinitionInterface::isRequired() * @see \Drupal\Core\Validation\Plugin\Validation\Constraint\NotNullConstraint * @see \Symfony\Component\Validator\Constraints\NotBlank::$allowNull */ public function testNotBlankInteractionWithNotNull(?string $value, bool $is_required, string $expected_message): void { \Drupal::configFactory()->getEditable('config_test.validation') ->set('string__not_blank', $value) ->save(); $typed_config = \Drupal::service('config.typed')->get('config_test.validation'); $typed_config->get('string__not_blank')->getDataDefinition()->setRequired($is_required); $result = $typed_config->validate(); // Expect 1 validation error message: the one from `NotBlank` or `NotNull`. $this->assertCount(1, $result); $this->assertSame('string__not_blank', $result->get(0)->getPropertyPath()); $this->assertEquals($expected_message, $result->get(0)->getMessage()); } /** * Tests config validation via the Typed Data API. */ Loading