Loading core/lib/Drupal/Core/Field/Plugin/Field/FieldType/NumericItemBase.php +29 −0 Original line number Diff line number Diff line Loading @@ -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'] = [ Loading Loading @@ -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; } } } core/modules/field/tests/src/Functional/Number/NumberFieldTest.php +11 −0 Original line number Diff line number Diff line Loading @@ -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]']}."); } /** Loading core/modules/field/tests/src/Kernel/Number/NumberItemTest.php +66 −0 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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.']; } } Loading
core/lib/Drupal/Core/Field/Plugin/Field/FieldType/NumericItemBase.php +29 −0 Original line number Diff line number Diff line Loading @@ -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'] = [ Loading Loading @@ -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; } } }
core/modules/field/tests/src/Functional/Number/NumberFieldTest.php +11 −0 Original line number Diff line number Diff line Loading @@ -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]']}."); } /** Loading
core/modules/field/tests/src/Kernel/Number/NumberItemTest.php +66 −0 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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.']; } }