Verified Commit 2ceafd06 authored by Lauri Timmanee's avatar Lauri Timmanee
Browse files

Issue #3052663 by joaopauloc.dev, smustgrave, quietone, Balu Ertl, xjm,...

Issue #3052663 by joaopauloc.dev, smustgrave, quietone, Balu Ertl, xjm, scottsperry: Validate the min, max and default values for Numeric fields
parent d582b8c5
Loading
Loading
Loading
Loading
Loading
+29 −0
Original line number Diff line number Diff line
@@ -33,6 +33,7 @@ public function fieldSettingsForm(array $form, FormStateInterface $form_state) {
      '#type' => 'number',
      '#title' => $this->t('Minimum'),
      '#default_value' => $settings['min'],
      '#element_validate' => [[static::class, 'validateMinAndMaxConfig']],
      '#description' => $this->t('The minimum value that should be allowed in this field. Leave blank for no minimum.'),
    ];
    $element['max'] = [
@@ -124,4 +125,32 @@ protected static function truncateDecimal($decimal, $num) {
    return floor($decimal * pow(10, $num)) / pow(10, $num);
  }

  /**
   * Validates that the minimum value is less than the maximum.
   *
   * @param array[] $element
   *   The numeric element to be validated.
   * @param \Drupal\Core\Form\FormStateInterface $form_state
   *   The current state of the form.
   * @param array[] $complete_form
   *   The complete form structure.
   */
  public static function validateMinAndMaxConfig(array &$element, FormStateInterface &$form_state, array &$complete_form): void {
    $settingsValue = $form_state->getValue('settings');

    // Ensure that the minimum and maximum are numeric.
    $minValue = is_numeric($settingsValue['min']) ? (float) $settingsValue['min'] : NULL;
    $maxValue = is_numeric($settingsValue['max']) ? (float) $settingsValue['max'] : NULL;

    // Only proceed with validation if both values are numeric.
    if ($minValue === NULL || $maxValue === NULL) {
      return;
    }

    if ($minValue > $maxValue) {
      $form_state->setError($element, t('The minimum value must be less than or equal to %max.', ['%max' => $maxValue]));
      return;
    }
  }

}
+11 −0
Original line number Diff line number Diff line
@@ -284,6 +284,17 @@ public function testNumberIntegerField() {
    // Verify that the "content" attribute has been set to the value of the
    // field, and the prefix is being displayed.
    $this->assertSession()->elementTextContains('xpath', '//div[@content="' . $integer_value . '"]', 'ThePrefix' . $integer_value);

    $field_configuration_url = 'entity_test/structure/entity_test/fields/entity_test.entity_test.' . $field_name;
    $this->drupalGet($field_configuration_url);

    // Tests Number validation messages.
    $edit = [
      'settings[min]' => 10,
      'settings[max]' => 8,
    ];
    $this->submitForm($edit, 'Save settings');
    $this->assertSession()->pageTextContains("The minimum value must be less than or equal to {$edit['settings[max]']}.");
  }

  /**
+66 −0
Original line number Diff line number Diff line
@@ -4,6 +4,8 @@

use Drupal\Core\Field\FieldItemInterface;
use Drupal\Core\Field\FieldItemListInterface;
use Drupal\Core\Field\Plugin\Field\FieldType\NumericItemBase;
use Drupal\Core\Form\FormState;
use Drupal\entity_test\Entity\EntityTest;
use Drupal\field\Entity\FieldConfig;
use Drupal\Tests\field\Kernel\FieldKernelTestBase;
@@ -188,4 +190,68 @@ public function dataNumberFieldSettingsProvider() {
    yield ['decimal', 1, 2, 1.5, FALSE];
  }

  /**
   * Tests the validation of minimum and maximum values.
   *
   * @param int|float|string $min
   *   Min value to be tested.
   * @param int|float|string $max
   *   Max value to be tested.
   * @param int|float|string $value
   *   Value to be tested with min and max values.
   * @param bool $hasError
   *   Expected validation result.
   * @param string $message
   *   (optional) Error message result.
   *
   * @dataProvider dataTestMinMaxValue
   */
  public function testFormFieldMinMaxValue(int|float|string $min, int|float|string $max, int|float|string $value, bool $hasError, string $message = ''): void {
    $element = [
      '#type' => 'number',
      '#title' => 'min',
      '#default_value' => $min,
      '#element_validate' => [[NumericItemBase::class, 'validateMinAndMaxConfig']],
      '#description' => 'The minimum value that should be allowed in this field. Leave blank for no minimum.',
      '#parents' => [],
      '#name' => 'min',
    ];

    $form_state = new FormState();
    $form_state->setValue('min', $value);
    $form_state->setValue('settings', [
      'min' => $min,
      'max' => $max,
      'prefix' => '',
      'suffix' => '',
      'precision' => 10,
      'scale' => 2,
    ]);
    $completed_form = [];
    NumericItemBase::validateMinAndMaxConfig($element, $form_state, $completed_form);
    $errors = $form_state->getErrors();
    $this->assertEquals($hasError, count($errors) > 0);
    if ($errors) {
      $error = current($errors);
      $this->assertEquals($error, $message);
    }
  }

  /**
   * Data provider for testFormFieldMinMaxValue().
   *
   * @return \Generator
   *   The test data.
   */
  public function dataTestMinMaxValue() {
    yield [1, 10, 5, FALSE, ''];
    yield [10, 5, 6, TRUE, 'The minimum value must be less than or equal to 5.'];
    yield [1, 0, 6, TRUE, 'The minimum value must be less than or equal to 0.'];
    yield [0, -2, 0.5, TRUE, 'The minimum value must be less than or equal to -2.'];
    yield [-10, -20, -5, TRUE, 'The minimum value must be less than or equal to -20.'];
    yield [1, '', -5, FALSE, ''];
    yield ['', '', '', FALSE, ''];
    yield ['2', '1', '', TRUE, 'The minimum value must be less than or equal to 1.'];
  }

}