Verified Commit da8c8f98 authored by Lauri Timmanee's avatar Lauri Timmanee
Browse files

Issue #2888763 by Graber, skyredwang, borisson_, Wim Leers, tstoeckler,...

Issue #2888763 by Graber, skyredwang, borisson_, Wim Leers, tstoeckler, e0ipso, dawehner: DecimalItem should not use String as its DataDefinition
parent e482afdd
Loading
Loading
Loading
Loading
+1 −19
Changes for core/lib/Drupal/Core/Field/Plugin/Field/FieldType/DecimalItem.php: 1 added line, 19 removed lines.
Original line number Diff line number Diff line
@@ -40,7 +40,7 @@ public static function defaultStorageSettings() {
   * {@inheritdoc}
   */
  public static function propertyDefinitions(FieldStorageDefinitionInterface $field_definition) {
    $properties['value'] = DataDefinition::create('string')
    $properties['value'] = DataDefinition::create('decimal')
      ->setLabel(new TranslatableMarkup('Decimal value'))
      ->setRequired(TRUE);

@@ -92,24 +92,6 @@ public function storageSettingsForm(array &$form, FormStateInterface $form_state
    return $element;
  }

  /**
   * {@inheritdoc}
   */
  public function getConstraints() {
    $constraint_manager = \Drupal::typedDataManager()->getValidationConstraintManager();
    $constraints = parent::getConstraints();

    $constraints[] = $constraint_manager->create('ComplexData', [
      'value' => [
        'Regex' => [
          'pattern' => '/^[+-]?((\d+(\.\d*)?)|(\.\d+))$/i',
        ],
      ],
    ]);

    return $constraints;
  }

  /**
   * {@inheritdoc}
   */
+28 −0
Changes for core/lib/Drupal/Core/TypedData/Plugin/DataType/DecimalData.php: 28 added lines, 0 removed lines.
Original line number Diff line number Diff line
<?php

namespace Drupal\Core\TypedData\Plugin\DataType;

use Drupal\Core\TypedData\Type\DecimalInterface;

/**
 * The decimal data type.
 *
 * Decimal type is stored as "decimal" in the relational database. Because PHP
 * does not have a primitive type decimal and using float can result in
 * unexpected rounding behavior, it is implemented and displayed as string.
 *
 * @DataType(
 *   id = "decimal",
 *   label = @Translation("Decimal")
 * )
 */
class DecimalData extends StringData implements DecimalInterface {

  /**
   * {@inheritdoc}
   */
  public function getCastedValue() {
    return $this->getString() ?: '0.0';
  }

}
+17 −0
Changes for core/lib/Drupal/Core/TypedData/Type/DecimalInterface.php: 17 added lines, 0 removed lines.
Original line number Diff line number Diff line
<?php

namespace Drupal\Core\TypedData\Type;

use Drupal\Core\TypedData\PrimitiveInterface;

/**
 * Interface for decimal numbers.
 *
 * The plain value of a decimal is a PHP string. For setting the value
 * any PHP variable that casts to an numeric string may be passed.
 *
 * @ingroup typed_data
 */
interface DecimalInterface extends PrimitiveInterface {

}
+4 −0
Changes for core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/PrimitiveTypeConstraintValidator.php: 4 added lines, 0 removed lines.
Original line number Diff line number Diff line
@@ -5,6 +5,7 @@
use Drupal\Core\TypedData\Type\BinaryInterface;
use Drupal\Core\TypedData\Type\BooleanInterface;
use Drupal\Core\TypedData\Type\DateTimeInterface;
use Drupal\Core\TypedData\Type\DecimalInterface;
use Drupal\Core\TypedData\Type\DurationInterface;
use Drupal\Core\TypedData\Type\FloatInterface;
use Drupal\Core\TypedData\Type\IntegerInterface;
@@ -48,6 +49,9 @@ public function validate($value, Constraint $constraint) {
    if ($typed_data instanceof IntegerInterface && filter_var($value, FILTER_VALIDATE_INT) === FALSE) {
      $valid = FALSE;
    }
    if ($typed_data instanceof DecimalInterface && !preg_match('/^[+-]?((\d+(\.\d*)?)|(\.\d+))$/i', $value)) {
      $valid = FALSE;
    }
    if ($typed_data instanceof StringInterface && !is_scalar($value) && !($value instanceof MarkupInterface)) {
      $valid = FALSE;
    }
+22 −0
Changes for core/tests/Drupal/KernelTests/Core/TypedData/TypedDataTest.php: 22 added lines, 0 removed lines.
Original line number Diff line number Diff line
@@ -10,6 +10,7 @@
use Drupal\Core\TypedData\Type\BinaryInterface;
use Drupal\Core\TypedData\Type\BooleanInterface;
use Drupal\Core\TypedData\Type\DateTimeInterface;
use Drupal\Core\TypedData\Type\DecimalInterface;
use Drupal\Core\TypedData\Type\DurationInterface;
use Drupal\Core\TypedData\Type\FloatInterface;
use Drupal\Core\TypedData\Type\IntegerInterface;
@@ -118,6 +119,27 @@ public function testGetAndSet() {
    $typed_data->setValue('invalid');
    $this->assertEquals(1, $typed_data->validate()->count(), 'Validation detected invalid value.');

    // Decimal type.
    $value = (string) (mt_rand(1, 10000) / 100);
    $typed_data = $this->createTypedData(['type' => 'decimal'], $value);
    $this->assertInstanceOf(DecimalInterface::class, $typed_data);
    $this->assertSame($value, $typed_data->getValue(), 'Decimal value was fetched.');
    $this->assertEquals(0, $typed_data->validate()->count());
    $new_value = (string) (mt_rand(1, 10000) / 100);
    $typed_data->setValue($new_value);
    $this->assertSame($new_value, $typed_data->getValue(), 'Decimal value was changed.');
    $this->assertIsString($typed_data->getString());
    $this->assertEquals(0, $typed_data->validate()->count());
    $typed_data->setValue(NULL);
    $this->assertNull($typed_data->getValue(), 'Decimal wrapper is null-able.');
    $this->assertEquals(0, $typed_data->validate()->count());
    $typed_data->setValue(0);
    $this->assertSame('0.0', $typed_data->getCastedValue(), '0.0 casted value was fetched.');
    $typed_data->setValue('1337e0');
    $this->assertEquals(1, $typed_data->validate()->count(), 'Scientific notation is not allowed in numeric type.');
    $typed_data->setValue('invalid');
    $this->assertEquals(1, $typed_data->validate()->count(), 'Validation detected invalid value.');

    // Float type.
    $value = 123.45;
    $typed_data = $this->createTypedData(['type' => 'float'], $value);