Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

Garet's avatar

How to multiply currency field AFTER validation

What I'm trying to do it quite simple but I can't see the wood for the trees.

I am dealing with currency and storing it as an integer in the database. On the front-end I am displaying it as a decimal. So an input field will show 5.99 which would be stored in the database as 599

I don't want to use an accessor and mutator for this purpose. The problem with that is I might want someone to submit a value of 5.99, but I might also want another part of my app to store a non-user submitted value, in which case it would already be an integer and not need multiplying.

I don't want to use the prepareForValidation method to multiply the number because then I have to have rules like:

'price' => 'required|integer|min:1'

rather than

'price' => 'required|numeric|min:0.01'

The issue with the above is that with the former, the validation error messages end up screwed up saying "enter a value no less than 1", whereas with the latter that would say "enter a value no less than 0.01"

Other methods in the FormRequest class don't change the values provided by $request->validated(), $request->safe()->except(['terms']), etc

The only real solution I have so far is:

$product->update(
    $request->safe()->except('price') + 
    ['price'] => $request->validated('price') * 100
);

Which is kind of messy.

Please can someone help me :-)

Essentially I want my form request class to perform validation based on the input field being a decimal, but I want the validated value to then be multiplied by 100 afterwards. As mentioned I don't want to use a mutator because then if my value comes via something other than a form request it would incorrectly be multiplied by 100.

Thank you!

0 likes
4 replies
Glukinho's avatar

It seems it's time for value object Money:

class Money 
{
    public readonly int $amount;
    public readonly Currency $currency = Currency::USD;

    public static function fromFloat(float $value): self
    {
        return new self(round($value * 100));
    }

    public static function fromInt(int $value): self
    {
        return new self($value);
    }
}

enum Currency
{
    case USD;
    case EUR;
    // ...
}

After that you can call desired behaviour from different part of your app:

$money = Money::fromFloat($request->input('price'); // user input is "12.34"

$money = Money::fromInt($some_api->getAmount()); // some external api gives "1234"

$money = Money::fromString("EUR 176"); // etc...

You will always have consistent money data no matter where it came from and in what format.

Also the important thing, cast column price of Product model to Money type as described here: https://laravel.com/docs/12.x/eloquent-mutators#value-object-casting

1 like
Garet's avatar

@Glukinho Thanks for your reply. I currently have a Currency helper/facade that I wrote. I am getting my head around whether I could/should convert that to a value object.

In the meantime your methods fromFloat() and fromtInt() inspired me to add fromMinor() and toMinor() methods to my currency helper to achieve much the same thing.

Thank you for your inspiration and help!

martinbean's avatar

@garet You basically need to multiply the value after validation, but before you save. Where and how you do that is up to you, but in the past I’ve done something like:

public function store(StoreProductRequest $request)
{
    $attributes = $request->safe()->merge([
        'unit_amount' => $request->float('unit_amount') * 100,
    ]);

    $product = Product::query()->create($attributes->toArray());

    // Return response...
}

But it’s not a pattern I’m fond of as it’s assuming the currency is divisible by 100, which not all are.

1 like
Garet's avatar

@martinbean You confirmed my suspicion that I most likely need to do this in the controller. I like the idea of a mutator so you don't have to remember to do it, but it's too indiscriminate for my liking.

Good catch on the $request->safe()->merge() it's a little nicer than how I did it.

I already have a Currency helper so I've added a method to it called toMinor(), and now I can do:

$request->safe()->merge([
'unit_amount' => Currency::toMinor($request->float('unit_amount')),
]);

This multiplies the currency by the correct amount (rather than 100) depending on how many decimal places that currency features.

Thanks, you've been a great help as always

1 like

Please or to participate in this conversation.