Verified Commit 5cd249e9 authored by Alex Pott's avatar Alex Pott
Browse files

Issue #3404061 by Wim Leers, borisson_, alexpott, phenaproxima, longwave: When...

Issue #3404061 by Wim Leers, borisson_, alexpott, phenaproxima, longwave: When setting `NotNull` constraint on type: required_label, two validation errors appear
parent 68f3bf2d
Loading
Loading
Loading
Loading
Loading
+13 −0
Original line number Diff line number Diff line
@@ -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;
  }

+1 −0
Original line number Diff line number Diff line
@@ -7,3 +7,4 @@ giraffe:
  hum2: hum2
uuid: '7C30C50E-641A-4E34-A7F1-46BCFB9BE5A3'
langcode: en
string__not_blank: 'this is a label'
+6 −0
Original line number Diff line number Diff line
@@ -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: {}
+29 −1
Original line number Diff line number Diff line
@@ -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());
@@ -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.
   */