Further Drupal 8.6.4 changes. Some core files were not committed before a commit...
[yaffs-website] / web / core / lib / Drupal / Core / Field / Plugin / Field / FieldType / DecimalItem.php
1 <?php
2
3 namespace Drupal\Core\Field\Plugin\Field\FieldType;
4
5 use Drupal\Core\Field\FieldDefinitionInterface;
6 use Drupal\Core\Field\FieldStorageDefinitionInterface;
7 use Drupal\Core\Form\FormStateInterface;
8 use Drupal\Core\TypedData\DataDefinition;
9
10 /**
11  * Defines the 'decimal' field type.
12  *
13  * @FieldType(
14  *   id = "decimal",
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"
20  * )
21  */
22 class DecimalItem extends NumericItemBase {
23
24   /**
25    * {@inheritdoc}
26    */
27   public static function defaultStorageSettings() {
28     return [
29       'precision' => 10,
30       'scale' => 2,
31     ] + parent::defaultStorageSettings();
32   }
33
34   /**
35    * {@inheritdoc}
36    */
37   public static function propertyDefinitions(FieldStorageDefinitionInterface $field_definition) {
38     $properties['value'] = DataDefinition::create('string')
39       ->setLabel(t('Decimal value'))
40       ->setRequired(TRUE);
41
42     return $properties;
43   }
44
45   /**
46    * {@inheritdoc}
47    */
48   public static function schema(FieldStorageDefinitionInterface $field_definition) {
49     return [
50       'columns' => [
51         'value' => [
52           'type' => 'numeric',
53           'precision' => $field_definition->getSetting('precision'),
54           'scale' => $field_definition->getSetting('scale'),
55         ],
56       ],
57     ];
58   }
59
60   /**
61    * {@inheritdoc}
62    */
63   public function storageSettingsForm(array &$form, FormStateInterface $form_state, $has_data) {
64     $element = [];
65     $settings = $this->getSettings();
66
67     $element['precision'] = [
68       '#type' => 'number',
69       '#title' => t('Precision'),
70       '#min' => 10,
71       '#max' => 32,
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,
75     ];
76
77     $element['scale'] = [
78       '#type' => 'number',
79       '#title' => t('Scale', [], ['context' => 'decimal places']),
80       '#min' => 0,
81       '#max' => 10,
82       '#default_value' => $settings['scale'],
83       '#description' => t('The number of digits to the right of the decimal.'),
84       '#disabled' => $has_data,
85     ];
86
87     return $element;
88   }
89
90   /**
91    * {@inheritdoc}
92    */
93   public function getConstraints() {
94     $constraint_manager = \Drupal::typedDataManager()->getValidationConstraintManager();
95     $constraints = parent::getConstraints();
96
97     $constraints[] = $constraint_manager->create('ComplexData', [
98       'value' => [
99         'Regex' => [
100           'pattern' => '/^[+-]?((\d+(\.\d*)?)|(\.\d+))$/i',
101         ],
102       ],
103     ]);
104
105     return $constraints;
106   }
107
108   /**
109    * {@inheritdoc}
110    */
111   public function fieldSettingsForm(array $form, FormStateInterface $form_state) {
112     $element = parent::fieldSettingsForm($form, $form_state);
113     $settings = $this->getSettings();
114
115     $element['min']['#step'] = pow(0.1, $settings['scale']);
116     $element['max']['#step'] = pow(0.1, $settings['scale']);
117
118     return $element;
119   }
120
121   /**
122    * {@inheritdoc}
123    */
124   public function preSave() {
125     $this->value = round($this->value, $this->getSetting('scale'));
126   }
127
128   /**
129    * {@inheritdoc}
130    */
131   public static function generateSampleValue(FieldDefinitionInterface $field_definition) {
132     $settings = $field_definition->getSettings();
133     $precision = $settings['precision'] ?: 10;
134     $scale = $settings['scale'] ?: 2;
135     // $precision - $scale is the number of digits on the left of the decimal
136     // point.
137     // The maximum number you can get with 3 digits is 10^3 - 1 --> 999.
138     // The minimum number you can get with 3 digits is -1 * (10^3 - 1).
139     $max = is_numeric($settings['max']) ?: pow(10, ($precision - $scale)) - 1;
140     $min = is_numeric($settings['min']) ?: -pow(10, ($precision - $scale)) + 1;
141
142     // Get the number of decimal digits for the $max
143     $decimal_digits = self::getDecimalDigits($max);
144     // Do the same for the min and keep the higher number of decimal digits.
145     $decimal_digits = max(self::getDecimalDigits($min), $decimal_digits);
146     // If $min = 1.234 and $max = 1.33 then $decimal_digits = 3
147     $scale = rand($decimal_digits, $scale);
148
149     // @see "Example #1 Calculate a random floating-point number" in
150     // http://php.net/manual/function.mt-getrandmax.php
151     $random_decimal = $min + mt_rand() / mt_getrandmax() * ($max - $min);
152     $values['value'] = self::truncateDecimal($random_decimal, $scale);
153     return $values;
154   }
155
156   /**
157    * Helper method to get the number of decimal digits out of a decimal number.
158    *
159    * @param int $decimal
160    *   The number to calculate the number of decimals digits from.
161    *
162    * @return int
163    *   The number of decimal digits.
164    */
165   protected static function getDecimalDigits($decimal) {
166     $digits = 0;
167     while ($decimal - round($decimal)) {
168       $decimal *= 10;
169       $digits++;
170     }
171     return $digits;
172   }
173
174 }