Thanks to visit codestin.com
Credit goes to github.com

Skip to content

MoneyType with divisor: integer conversion leads to wrong database values #21026

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

Closed
elmariachi111 opened this issue Dec 22, 2016 · 5 comments
Closed

Comments

@elmariachi111
Copy link

Q A
Bug report? yes
Feature request? no
BC Break report? no
RFC? no
Symfony version 2.8.14

http://stackoverflow.com/questions/41286474/symfony2-moneytype-with-divisor-integer-conversion-leads-to-wrong-database-valu

We're storing all our money related values as cents in our database (ODM but ORM will likely behave the same). We're using MoneyType to convert user facing values (12,34€) into their cents representation (1234c). The typical float precision problem arises here: due to insufficient precision there are many cases that create rounding errors that are merely visible when debugging. MoneyType will convert incoming strings to floats that may be not precise ("1765" => 1764.9999999998). Things get bad as soon as you persist these values. The (integer) cast in IntType (ODM/ORM) will strip off the value's mantissa instead of rounding the value, effectively leading to writing wrong values into the database (1764 instead of 1765 when "1765" is internally 1764.9999999998).

Here's a unit test that should work from within any Symfony/container application:

//for better debugging: set ini_set('precision', 17); 

class PrecisionTest extends WebTestCase
{
    private function buildForm() {
        $builder = $this->getContainer()->get('form.factory')->createBuilder(FormType::class, null, []);
        $form = $builder->add('money', MoneyType::class, [
            'divisor' => 100
        ])->getForm();
        return $form;
    }

    // high-level symptom
    public function testMoneyType() {
        $form = $this->buildForm();
        $form->submit(['money' => '12,34']);

        $data = $form->getData();

        $this->assertEquals(1234, $data['money']);
        $this->assertEquals(1234, (int)$data['money']);

        $form = $this->buildForm();
        $form->submit(['money' => '17,65']);

        $data = $form->getData();

        $this->assertEquals(1765, $data['money']);
        $this->assertEquals(1765, (int)$data['money']); //fails: data[money] === 1764 
    }

    //root cause
    public function testParsedIntegerPrecision() {

        $string = "17,65";
        $transformer = new MoneyToLocalizedStringTransformer(2, false,null, 100);
        $value = $transformer->reverseTransform($string);

        $int = (integer) $value;
        $float = (float) $value;

        $this->assertEquals(1765, (float)$float);
        $this->assertEquals(1765, $int); //fails: $int === 1764
    }
}

might relate to #10240 and #8473

@sstok
Copy link
Contributor

sstok commented Dec 27, 2016

I would vote to remove deprecate the devisor and rounding stuff for money as this doesn't work properly and use a proper library like https://github.com/moneyphp/money.

That's what I did for RollerworksSearch after almost killing myself with this logic...
rollerworks/search#125

Edit. In my case I actually had to increment the whole amount (+1.00) and reset the cents, but even then the numbers did not always work as expected.

@elmariachi111
Copy link
Author

That would be a hard option and definitely raises a fat BC issue ;)

@mvrhov
Copy link

mvrhov commented Dec 27, 2016

Yeah it would be a BC break, but it would solve this issue properly and probably once and for all.

@elmariachi111
Copy link
Author

This one's fixed by #24036 ! FINALLY! Thank you so much 😘

@fabpot fabpot closed this as completed Oct 27, 2017
@chalasr
Copy link
Member

chalasr commented Oct 27, 2017

Closing then

fabpot added a commit that referenced this issue May 17, 2018
…s divisions on transform() (syastrebov)

This PR was merged into the 2.7 branch.

Discussion
----------

[Form] Fix precision of MoneyToLocalizedStringTransformer's divisions on transform()

| Q             | A
| ------------- | ---
| Branch?       | 2.7
| Bug fix?      | yes
| New feature?  | no
| BC breaks?    | no
| Deprecations? | no
| Tests pass?   | yes
| Fixed tickets | no
| License       | MIT
| Doc PR        |

Related issue #21026.
Previous PR #24036.
Similar fix for `transform()` method.

Commits
-------

f94b7aa fix rounding from string
symfony-splitter pushed a commit to symfony/form that referenced this issue May 17, 2018
…s divisions on transform() (syastrebov)

This PR was merged into the 2.7 branch.

Discussion
----------

[Form] Fix precision of MoneyToLocalizedStringTransformer's divisions on transform()

| Q             | A
| ------------- | ---
| Branch?       | 2.7
| Bug fix?      | yes
| New feature?  | no
| BC breaks?    | no
| Deprecations? | no
| Tests pass?   | yes
| Fixed tickets | no
| License       | MIT
| Doc PR        |

Related issue symfony/symfony#21026.
Previous PR symfony/symfony#24036.
Similar fix for `transform()` method.

Commits
-------

f94b7aadd3 fix rounding from string
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

7 participants