Quantcast
Channel: Issues for Drupal core
Viewing all articles
Browse latest Browse all 296253

Simple decimals fail to pass validation

$
0
0

Problem/Motivation

- Create decimal field, set precision to 10 (minimum in the UI and scale to 4
- Saving new node with value 19999.0000 succeeds (precision is 5+4 = 9).
- Saving new node with value 99999.0000 fails (same precision as above).

or

- Create decimal field, set scale to anything over 6 (need 8 to store bitcoin values for example). I used 16 as precission.
- Saving new node with value 20.12345678 fails validation while 0.1234567 succeeds.

This is because Drupal\Component\Utility\Number::validStep() returns false. Detailed investigation on this function (which is only used once in Drupal), reveals that the first argument ($value) is received as a string, but $step and $offset are floats. PHP seems to slightly mangle the $step value on the first case above from 0.0001 to 0.00010000000000000001438. Passing the step parameter as a string in the case of decimal numbers maintains the correct precision, and allows a correct approximation calculation.

Proposed resolution

Bypass weak PHP floating-point handling by passing the step as a string.

Remaining tasks

Merge. Commit. Decimals FTW!

User interface changes

None.

API changes

A new field was added to the Number FormElement, in order to decide when to use the workaround. This "#number_type" field may be useful in other cases.

Data model changes

None.

Possible workaround if you need big decimals

Disable this validation by setting the render element #step to 'any'

i.e.

$element['#step'] = 'any';

In the case of fields, you can do

function MYMODULE_form_FORM_WITH_BIG_DECIMAL_FIELD_alter (array &$form, FormStateInterface $form_state) {
  $form['field_some']['widget'][0]['value']['#step']='any';
}

And if you want to target all decimal fields:

/**
 * Prevents validation of decimal numbers
 * @see https://www.drupal.org/node/2230909
 */
function MYMODULE_field_widget_form_alter(&$element, \Drupal\Core\Form\FormStateInterface $form_state, $context) {
  $field_definition = $context['items']->getFieldDefinition();
  if ($field_definition->getType() == 'decimal') {
    $element['value']['#step'] = 'any';
  }
}

Viewing all articles
Browse latest Browse all 296253

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>