3 namespace Drupal\Core\Field\Plugin\Field\FieldType;
5 use Drupal\Core\Field\FieldDefinitionInterface;
6 use Drupal\Core\Field\FieldStorageDefinitionInterface;
7 use Drupal\Core\Form\FormStateInterface;
8 use Drupal\Core\TypedData\DataDefinition;
11 * Defines the 'decimal' field type.
15 * label = @Translation("Number (decimal)"),
16 * description = @Translation("This field stores a number in the database in a fixed decimal format."),
17 * category = @Translation("Number"),
18 * default_widget = "number",
19 * default_formatter = "number_decimal"
22 class DecimalItem extends NumericItemBase {
27 public static function defaultStorageSettings() {
31 ] + parent::defaultStorageSettings();
37 public static function propertyDefinitions(FieldStorageDefinitionInterface $field_definition) {
38 $properties['value'] = DataDefinition::create('string')
39 ->setLabel(t('Decimal value'))
48 public static function schema(FieldStorageDefinitionInterface $field_definition) {
53 'precision' => $field_definition->getSetting('precision'),
54 'scale' => $field_definition->getSetting('scale'),
63 public function storageSettingsForm(array &$form, FormStateInterface $form_state, $has_data) {
65 $settings = $this->getSettings();
67 $element['precision'] = [
69 '#title' => t('Precision'),
72 '#default_value' => $settings['precision'],
73 '#description' => t('The total number of digits to store in the database, including those to the right of the decimal.'),
74 '#disabled' => $has_data,
79 '#title' => t('Scale', [], ['context' => 'decimal places']),
82 '#default_value' => $settings['scale'],
83 '#description' => t('The number of digits to the right of the decimal.'),
84 '#disabled' => $has_data,
93 public function getConstraints() {
94 $constraint_manager = \Drupal::typedDataManager()->getValidationConstraintManager();
95 $constraints = parent::getConstraints();
97 $constraints[] = $constraint_manager->create('ComplexData', [
100 'pattern' => '/^[+-]?((\d+(\.\d*)?)|(\.\d+))$/i',
112 public function fieldSettingsForm(array $form, FormStateInterface $form_state) {
113 $element = parent::fieldSettingsForm($form, $form_state);
114 $settings = $this->getSettings();
116 $element['min']['#step'] = pow(0.1, $settings['scale']);
117 $element['max']['#step'] = pow(0.1, $settings['scale']);
125 public function preSave() {
126 $this->value = round($this->value, $this->getSetting('scale'));
132 public static function generateSampleValue(FieldDefinitionInterface $field_definition) {
133 $settings = $field_definition->getSettings();
134 $precision = $settings['precision'] ?: 10;
135 $scale = $settings['scale'] ?: 2;
136 // $precision - $scale is the number of digits on the left of the decimal
138 // The maximum number you can get with 3 digits is 10^3 - 1 --> 999.
139 // The minimum number you can get with 3 digits is -1 * (10^3 - 1).
140 $max = is_numeric($settings['max']) ?: pow(10, ($precision - $scale)) - 1;
141 $min = is_numeric($settings['min']) ?: -pow(10, ($precision - $scale)) + 1;
143 // Get the number of decimal digits for the $max
144 $decimal_digits = self::getDecimalDigits($max);
145 // Do the same for the min and keep the higher number of decimal digits.
146 $decimal_digits = max(self::getDecimalDigits($min), $decimal_digits);
147 // If $min = 1.234 and $max = 1.33 then $decimal_digits = 3
148 $scale = rand($decimal_digits, $scale);
150 // @see "Example #1 Calculate a random floating-point number" in
151 // http://php.net/manual/function.mt-getrandmax.php
152 $random_decimal = $min + mt_rand() / mt_getrandmax() * ($max - $min);
153 $values['value'] = self::truncateDecimal($random_decimal, $scale);
159 * Helper method to get the number of decimal digits out of a decimal number.
161 * @param int $decimal
162 * The number to calculate the number of decimals digits from.
165 * The number of decimal digits.
167 protected static function getDecimalDigits($decimal) {
169 while ($decimal - round($decimal)) {