Feature: #102217 - Configurable scale for TCA type "number" 

See forge#102217

Description 

Fields using TCA type number with format set to decimal have always been limited to two decimal digits. The only alternative was the usage of TCA type number with format set to integer without any decimal digits.

The new TCA column configuration option scale makes this number configurable:

'conversion_factor' => [
    'label' => 'Conversion factor',
    'config' => [
        'type' => 'number',
        'scale' => 6,
    ],
],
Copied!

The option defaults to 0 , which is the previous behavior. Values are limited to a scale between 0 and 30 , the maximum supported by all database platforms.

If the database column is auto-created by TYPO3, the scale is part of the column definition. For a scale equal to 0 , an integer column will be generated.

For a scale greater than 0 , the following configuration applies: The number of digits in front of the decimal point stays at eight, the configured scale is added on top: The example above results in decimal(14,6) .

Impact 

Decimal numbers can be stored and edited with more (or less) than two decimal digits. The scale is respected by the automatically created database column, by the DataHandler when persisting a value, and by the FormEngine when rendering and validating the field in the backend.

Decimal values are rounded on their digits and no longer through a float, so values with a scale a float can not represent are kept exactly. The new API method MathUtility::roundDecimalString() does this rounding and is available for extensions as well. It accepts digits with an optional sign, decimal point and exponent, and throws an \InvalidArgumentException for anything else: A value like '1,5' is rejected instead of being silently read as 15 .

Lowering the scale of an existing field leaves stored values with more decimal digits than the field now allows. Such a value is rounded to the scale when the record is opened in the backend, and it is stored rounded with the next save of that record. This matters because a value that is no multiple of the step attribute makes the browser refuse to submit the whole form, and it does so without any visible message if the field sits on an inactive tab. MySQL and PostgreSQL round the stored values themselves as soon as the column is altered, while SQLite keeps decimal values as strings and therefore does not.

The rendered input field carries the scale as its step attribute, so a scale of 6 results in step="0.000001" . Browsers evaluate that attribute in double precision and can no longer do so below 1e-18 , so a scale above 18 is rendered as step="any" instead. Such a field is still rounded to its scale by the DataHandler and by the FormEngine, but the browser no longer restricts the value, and the arrows of the input field step by one.

As part of this, the internal web component typo3-formengine-valueslider now reads the attribute scale instead of precision .

Migration 

The TCA migration from format to scale is done like the following:

// Before
'<mycolumn_integer>' => [
    'label' => 'Format integer',
    'config' => [
        'type' => 'number',
        'format' => 'integer',
    ],
],
'<mycolumn_decimal>' => [
    'label' => 'Format decimal',
    'config' => [
        'type' => 'number',
        'format' => 'decimal',
    ],
],
// After
'<mycolumn_integer>' => [
    'label' => 'Format integer',
    'config' => [
        'type' => 'number',
        'scale' => 0,
    ],
],
'<mycolumn_decimal>' => [
    'label' => 'Format decimal',
    'config' => [
        'type' => 'number',
        'scale' => 2,
    ],
],
Copied!

An automatic TCA migration is performed on the fly, migrating all occurrences of format to scale.