brick / money

A money and currency library for PHP
MIT License
1.65k stars 102 forks source link

Question: Correct way for working with MoneyBag #48

Closed jokaorgua closed 3 years ago

jokaorgua commented 3 years ago

Hello.

I just want to understand the correct way of working with MoneyBag.

First, we have an instance of Money class

$money = Money::of(1.23,'EUR')

Second, we create a money bag and add money to it

$bag = new MoneyBag();
$bag->add($money);

And when we are going to use that MoneyBag we have a BigRational number

$amount = $bag->getAmount('EUR')

and how to use this BigRational for normal numbers? Let's say I want to convert it to int, float, etc

I always get

This rational number cannot be represented as an integer value without rounding.

And I don't quite understand where and how to add rounding in this case. Need an advice

Thank you.

BenMorel commented 3 years ago

Hi, you have a few options with a MoneyBag:

Now both Money::getAmount() and MoneyBag::getAmount() return a BigNumber (respectively a BigDecimal and a BigRational).

If you want to convert a BigNumber that does not represent an integer value to an integer, you need to round it first:

use Brick\Math\RoundingMode;

$amount->toScale(0, RoundingMode::DOWN)->toInt();

You can also apply a rounding to 2 decimals, if you wish:

echo $amount->toScale(2, RoundingMode::DOWN); // e.g.: 12.34

Does that answer your question?

jokaorgua commented 3 years ago

thank you @BenMorel

Seems to me too much things have to be done for using MoneyBag. As for me would be easier if MoneyBag returned Money object with currency, rouding, etc. When I add Money object I expect it to be returned, without hidden conversion to another object(BigRational).

BenMorel commented 3 years ago

Hi, the real purpose of MoneyBag is not to store monies to be retrieved as is. Actually, it's not really meant to be used to retrieve anything directly. Its goal is to be used through a CurrencyConverter to convert this bag of money to a single Money in a single currency.

It stores monies internally as BigRational because this is the lowest common denominator for all accepted money objects: Money, RationalMoney, MoneyBag.

The real use case for a MoneyBag is therefore, as mentioned above:

// want a Money?
$money = $converter->convert($moneyBag, 'EUR', RoundingMode::DOWN); // e.g. EUR 1.23

// want cents?
echo $money->getMinorAmount()->toInt(); // e.g. 123
BenMorel commented 3 years ago

I'm closing this issue, but feel free to comment if you need extra help.