Sapnesh Naik
Sapnesh Naik

Reputation: 11636

Eloquent casts decimal as string

I have a decimal field to represent money in my Eloquent Model and I'm noticing erroneous results when trying to add some number to this field.

Upon further inspection, I found that the decimal field is being cast as a string, like "1245114.00" in the tinker console.

I checked the table structure and I can verify that the field is indeed decimal(11,3).

This question was asked before but has no answers.

Why is this happening?

Upvotes: 33

Views: 43806

Answers (5)

Tebe
Tebe

Reputation: 3214

Also notice that 0.000 will give you true.

To get numeric value of it or to compare:

Or

$value = +$model->number_field_decimal

Or

$value = 1*$model->number_field_decimal

Upvotes: 0

dRamentol
dRamentol

Reputation: 1060

That's the way it should be since PHP has no decimal type. If you cast decimal to float you may loose precision.

The best option is leaving it as it is, as strings. Then use bcmath to operate, which is meant to be used with strings.

Upvotes: 7

agm1984
agm1984

Reputation: 17132

I just spent some time analyzing this issue because my Laravel model shows database decimal columns as strings.

The important thing is that adding typecasting to float in the model does fix it, but if you were like me, you noticed dd(\App\SomeModel::someScope()->get()); still shows those decimal columns as strings after adding typecasting in the model.

When these values are sent to the client, they are integers, so the typecasting did fix the original problem, thus allowing my JavaScript to receive Number not String.

I am just making this answer so a person doesn't waste time due to focusing on dd() output. I investigated solutions about the PDO driver, and while some perhaps have merit, it isn't a big deal because the real database outputs are cast to the correct type.

Upvotes: 5

Niels
Niels

Reputation: 676

According to this thread on Laravel's github repository: https://github.com/laravel/framework/issues/11780

It seems to be a PDO driver issue. Automatically casting decimals to strings. People in that thread said that it was a problem with the mysql 5.2 driver and some rolled back to 5.1. If you're on your own server it you'll be able to downgrade. Otherwise you'll have to cast it to float on model level.

Upvotes: 10

You need to define in your model which fields need to be cast to a primitive attribute.

protected $casts = [
    'my_decimal' => 'float',
];

The $casts property on your model provides a convenient method of converting attributes to common data types. The $casts property should be an array where the key is the name of the attribute being cast and the value is the type you wish to cast the column to. The supported cast types are: integer, real, float, double, string, boolean, object, array, collection, date, datetime, and timestamp

There is a really good explanation here:

https://mattstauffer.com/blog/laravel-5.0-eloquent-attribute-casting/

Also there is an explanation in the docs:

https://laravel.com/docs/5.5/eloquent-mutators#attribute-casting

Upvotes: 56

Related Questions