Skip to content

NumberType does not apply rouding when scale is not defined #20134

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
pacproduct opened this issue Aug 19, 2024 · 4 comments
Open

NumberType does not apply rouding when scale is not defined #20134

pacproduct opened this issue Aug 19, 2024 · 4 comments
Labels
Form help wanted Issues and PRs which are looking for volunteers to complete them.

Comments

@pacproduct
Copy link

pacproduct commented Aug 19, 2024

Hi :)

I may be wrong, but documentation (Symfony 5.x) says that NumberType's option rounding_mode defaults to \NumberFormatter::ROUND_HALFUP : https://symfony.com/doc/5.x/reference/forms/types/number.html#rounding-mode

In my project, one of my form's fields is a NumberType, with no rounding_mode nor scale configured:

    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add(
                'altitude',
                NumberType::class,
                [
                    'label' => 'common.label.altimetric_reference.altitude',
                    'attr' => ['class' => 'altitude-field'],
                    'required' => false,
                    'help' => 'common.help.value_in_m',
                ]
            )
[...]

But because of how \Symfony\Component\Form\Extension\Core\DataTransformer\NumberToLocalizedStringTransformer::getNumberFormatter has been implemented, I think the documentation is not accurate:

    protected function getNumberFormatter()
    {
        $formatter = new \NumberFormatter($this->locale ?? \Locale::getDefault(), \NumberFormatter::DECIMAL);

        if (null !== $this->scale) {
            $formatter->setAttribute(\NumberFormatter::FRACTION_DIGITS, $this->scale);
            $formatter->setAttribute(\NumberFormatter::ROUNDING_MODE, $this->roundingMode);
        }

        $formatter->setAttribute(\NumberFormatter::GROUPING_USED, $this->grouping);

        return $formatter;
    }

As shown above, the number formatter is not configured with any rounding when no scale is defined (even if one is configured in the form I reckon). Because of that, in our project (with French locale), the effective rounding mode used is \NumberFormatter::ROUND_HALFEVEN (and scale seems to default to 3). Instead of the advertised \NumberFormatter::ROUND_HALFUP.

This gives us an unexpected and weird behavior when users type in numbers like 485,3485, as it gets rounded to 485,348 instead of 485,349.

In all honesty, I'm not sure if this is a documentation issue, a bug in NumberToLocalizedStringTransformer::getNumberFormatter or if I'm missing something?

Thanks for your insights :)

@pacproduct
Copy link
Author

As a side-note, this doesn't seem to be linked to the fr locale. It simply is the default behavior of \NumberFormatter, apparently.

Here is a short reproducer:

$formatter = new \NumberFormatter('en', \NumberFormatter::DECIMAL);
var_dump($formatter->format(485.3485)); // Outputs: string(7) "485.348"

@pacproduct pacproduct changed the title NumberType does not apply default rouding when scale is not defined NumberType does not apply rouding when scale is not defined Aug 19, 2024
@pacproduct
Copy link
Author

pacproduct commented Aug 19, 2024

I'm starting to think that it might not be a documentation problem, but rather a bug in \Symfony\Component\Form\Extension\Core\DataTransformer\NumberToLocalizedStringTransformer::getNumberFormatter.

In \Symfony\Component\Form\Extension\Core\Type\NumberType::configureOptions, default options do set "rounding_mode" to \NumberFormatter::ROUND_HALFUP as advertised in the documentation.

Also, NumberToLocalizedStringTransformer's constructor configures the rounding mode by default as NumberFormatter::ROUND_HALFUP too.

But because NumberToLocalizedStringTransformer::getNumberFormatter() ignores it when no scale is defined, it does not get applied to the instantiated NumberFormatter.


In any case, I'm kind of confused.
If any experienced user could shed some light on this behavior, that would be greatly appreciated ^^

Many thanks.

@javiereguiluz
Copy link
Member

I'm a bit lost here too. Let's see if someone can take a look here and give us some clue. Thanks!

@pacproduct
Copy link
Author

I found time to run a few more tests and I could create a reproducer that illustrates better the behavior I'm experiencing, and I really think it might be a bug now.

Here is the issue (with the reproducer): symfony/symfony#58204

Not sure if this ticket should stay open, then.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Form help wanted Issues and PRs which are looking for volunteers to complete them.
Projects
None yet
Development

No branches or pull requests

2 participants