A Laravel package that makes working with money in a secure manner a cinch!
Mula is a Laravel package that makes it super easy to work with money in your applications. It uses Money for PHP under the hood, but takes away all the complexity and provides all the pieces you need to be up and running with money in a matter of minutes.
Mula is also fully immutable, so you won't run in to issues changing values you really wish you hadn't. It also handles rounding and allocation, so you don't have to worry about any finances going missing.
You can install the package via composer:
composer require lukeraymonddowning/mula
You should publish the
mula.phpconfig file by running:
php artisan vendor:publish --provider="Lukeraymonddowning\Mula\MulaServiceProvider"
We provide a
Mulafacade that allows you to easily create, parse and alter monetary values.
To manually create a new instance, use the
createmethod.
Mula::create('12000', 'USD'); // $120.00
Note that when creating, we exclude any decimal point. Currency should be passed as an ISO 4217 code.
You may also exclude the currency, in which case
Mulawill use the default currency defined in the
mula.phpconfig file, or your
.envfile using the
MULA_CURRENCYkey.
Whilst we will use strings to pass values to the
createmethod in the documentation, you are free to pass integer values instead.
More often than not, you'll want to parse existing monetary values rather than create new ones from scratch. You should use the
parsemethod when handling user input or reading monetary values from a 3rd party API.
If you are using the
phpmoneydriver (which is the default), you have a few different drivers you can use for parsing money. You can set your desired driver in the
mula.phpconfig file, by altering the value of
mula.options.phpmoney.parser.default.
We recommend using the default
aggregateparser, but for the sake of clarity, we'll explain the difference between each one.
Whilst we will use strings to pass values to the
parsemethod in the documentation, you are free to pass integers or decimal values instead.
The
aggregateparser (which is the default) is the most flexible driver available, and will attempt to parse monetary strings formatted in international or decimal. Here are a few examples:
Mula::parse('$120.99'); // $120.99Mula::parse('120.99', 'USD'); // $120.99
Mula::parse('£120.99', 'USD'); // $120.99
Mula::parse('120', 'USD'); // $120.00
Note that in the third example, the money object is in USD, even though we parsed a value in GBP. That is because we passed a second parameter of
USD. Passing in a currency will always override the given currency.
The
internationalparser will parse full monetary string with currency, but will not parse decimal strings.
Mula::parse('$120.99'); // $120.99Mula::parse('120.99'); // Exception
The
decimalparser will parse decimal values with the given currency (or the default currency), but will not parse monetary strings.
Mula::parse('120.99', 'USD'); // $120.99Mula::parse('$120.99'); // Exception
To display money in the UI, you can use the
displaymethod. It accepts a single parameter,
includeCurrency, which will either include or omit the currency symbol from the result.
Mula::create('12099', 'USD')->display(); // $120.99Mula::create('12099', 'USD')->display(false); // 120.99
Mulaalso implements the
Stringableinterface, so you can output money directly in a blade view.
@php($money = Mula::create('12099', 'USD')) {{ $money }}{-- This will show as '$120.99' --}
As a syntactical nicety, you may use the
displayWithoutCurrencymethod, which is just an alias for
display(false).
The
currencymethod will return the ISO 4217 code of the money object.
Mula::create('12099', 'USD')->currency(); // USDMula::create('12099', 'GBP')->currency(); // GBP
The
valuemethod will return the nonformatted value of the money object. You will rarely need to use this method, but
Mulamakes use of it for casting values to the database.
Mula::create('12099', 'USD')->value(); // 12099
The
addmethod adds the provided money objects to the current money object and returns a new money object. You may pass any number of money objects as varadic parameters.
Mula::create('1500', 'USD')->add(Mula::create('1500', 'USD'))->display(); // $30.00Mula::create('1500', 'USD')->add(Mula::create('1500', 'USD'), Mula::create('3000', 'USD'))->display(); // $60.00
The
addmethod subtracts the provided money objects from the current money object and returns a new money object. You may pass any number of money objects as varadic parameters.
Mula::create('3000', 'USD')->subtract(Mula::create('1500', 'USD'))->display(); // $15.00Mula::create('6000', 'USD')->subtract(Mula::create('1500', 'USD'), Mula::create('3000', 'USD'))->display(); // $15.00
The
multiplyBymethod multiplies the money object by the given multiplier and returns a new money object.
Mula::create('5000', 'USD')->multiplyBy(2)->display(); // $100.00
The
divideBymethod divides the money object by the given divisor and returns a new money object.
Mula::create('5000', 'USD')->divideBy(2)->display(); // $25.00
The
modmethod returns the remainder of money after being divided into another sum of money.
Mula::create('1000', 'USD')->mod(Mula::create('300', 'USD'))->display(); // $1.00
To check if a money object has the same currency as other money objects, use the
hasSameCurrencyAsmethod. It accepts a variable number of money objects as arguments. If any of the arguments have a different currency, the method will return
false, otherwise it will return
true.
Mula::create('1000', 'USD')->hasSameCurrencyAs(Mula::create('500', 'USD')); // TRUEMula::create('1000', 'USD')->hasSameCurrencyAs(Mula::create('500', 'GBP')); // FALSE
Mula::create('1000', 'USD')->hasSameCurrencyAs(Mula::create('500', 'USD'), Mula::create('3000', 'USD')); // TRUE
Mula::create('1000', 'USD')->hasSameCurrencyAs(Mula::create('500', 'USD'), Mula::create('3000', 'GBP')); // FALSE
To check if a money object is equal to other money objects, use the
equalsmethod. It accepts a variable number of money objects as arguments. If any of the arguments have a different amount, the method will return
false, otherwise it will return
true.
Mula::create('1000', 'USD')->equals(Mula::create('1000', 'USD')); // TRUEMula::create('1000', 'USD')->equals(Mula::create('500', 'USD')); // FALSE
Mula::create('1000', 'USD')->equals(Mula::create('1000', 'USD'), Mula::create('1000', 'USD')); // TRUE
Mula::create('1000', 'USD')->equals(Mula::create('1000', 'USD'), Mula::create('500', 'USD')); // FALSE
The
isGreaterThanmethod checks if a money object is greater than all other money objects. It returns
trueif it is, or
falseif any of the money object provided are greater than or equal to it.
Mula::create('1000', 'USD')->isGreaterThan(Mula::create('999', 'USD')); // TRUEMula::create('1000', 'USD')->isGreaterThan(Mula::create('1000', 'USD')); // FALSE
Mula::create('1000', 'USD')->isGreaterThan(Mula::create('1500', 'USD')); // FALSE
Mula::create('1000', 'USD')->isGreaterThan(Mula::create('999', 'USD'), Mula::create('800', 'USD')); // TRUE
Mula::create('1000', 'USD')->isGreaterThan(Mula::create('1000', 'USD'), Mula::create('500', 'USD')); // FALSE
The
isGreaterThanOrEqualTomethod checks if a money object is greater than or equal to all other money objects. It returns
trueif it is, or
falseif any of the money object provided are greater than it.
Mula::create('1000', 'USD')->isGreaterThanOrEqualTo(Mula::create('999', 'USD')); // TRUEMula::create('1000', 'USD')->isGreaterThanOrEqualTo(Mula::create('1000', 'USD')); // TRUE
Mula::create('1000', 'USD')->isGreaterThanOrEqualTo(Mula::create('1500', 'USD')); // FALSE
Mula::create('1000', 'USD')->isGreaterThanOrEqualTo(Mula::create('999', 'USD'), Mula::create('800', 'USD')); // TRUE
Mula::create('1000', 'USD')->isGreaterThanOrEqualTo(Mula::create('1000', 'USD'), Mula::create('500', 'USD')); // TRUE
Mula::create('1000', 'USD')->isGreaterThanOrEqualTo(Mula::create('1000', 'USD'), Mula::create('1500', 'USD')); // FALSE
The
isLessThanmethod checks if a money object is less than all other money objects. It returns
trueif it is, or
falseif any of the money object provided are less than or equal to it.
Mula::create('1000', 'USD')->isLessThan(Mula::create('999', 'USD')); // FALSEMula::create('1000', 'USD')->isLessThan(Mula::create('1000', 'USD')); // TRUE
Mula::create('1000', 'USD')->isLessThan(Mula::create('1500', 'USD')); // TRUE
Mula::create('1000', 'USD')->isLessThan(Mula::create('1500', 'USD'), Mula::create('800', 'USD')); // FALSE
Mula::create('1000', 'USD')->isLessThan(Mula::create('1200', 'USD'), Mula::create('1500', 'USD')); // TRUE
The
isLessThanOrEqualTomethod checks if a money object is less than or equal to all other money objects. It returns
trueif it is, or
falseif any of the money object provided are less than it.
Mula::create('1000', 'USD')->isLessThanOrEqualTo(Mula::create('999', 'USD')); // FALSEMula::create('1000', 'USD')->isLessThanOrEqualTo(Mula::create('1000', 'USD')); // TRUE
Mula::create('1000', 'USD')->isLessThanOrEqualTo(Mula::create('1500', 'USD')); // TRUE
Mula::create('1000', 'USD')->isLessThanOrEqualTo(Mula::create('999', 'USD'), Mula::create('800', 'USD')); // FALSE
Mula::create('1000', 'USD')->isLessThanOrEqualTo(Mula::create('1000', 'USD'), Mula::create('500', 'USD')); // FALSE
Mula::create('1000', 'USD')->isLessThanOrEqualTo(Mula::create('1000', 'USD'), Mula::create('1500', 'USD')); // TRUE
Split is rather special. It allocates money based on the provided allocation. It can accept an
integer,
arrayor
Collectionand returns a
Collectionof
Money.
If you want to split a money object as evenly as possible between a given number, pass an
integer.
Mula::create('10000', 'USD')->split(3); // A Collection. The first item will have a value of $33.34 the second and third items will have a value of $33.33.
If you want to allocate money based on percentages, you may pass an
arrayor
Collectionof numeric values. The values must add up to 100.
Mula::create('10000', 'USD')->split([30, 70]); // A Collection. The first item will have a value of $30.00 and the second item will have a value of $70.00.Mula::create('10000', 'USD')->split(collect([30, 70])); // A Collection. The first item will have a value of $30.00 and the second item will have a value of $70.00.
Mulamakes it easy to store and retrieve money values from a database by providing a custom cast you can attach to your Eloquent models.
use Illuminate\Database\Eloquent\Model; use Lukeraymonddowning\Mula\Casts\Mula;class Product extends Model {
protected $casts = [ 'price' => Mula::class ];
}
The column storing your monetary values in your database should be a string type. This prevents floating point errors and also allows
Mulato store the currency along with the value.
If you'd prefer to store your amount and currency in two separate columns, which allows you more freedom when performing database queries, you can! Just let
Mulaknow the amount column and currency column respectively in your
$castsarray.
use Illuminate\Database\Eloquent\Model; use Lukeraymonddowning\Mula\Casts\Mula;class Product extends Model {
protected $casts = [ 'price' => Mula::class.':amount,currency' ];
}
Mulaadds macros to Laravel Collections to make it easy to perform common monetary operations to a Collection of money objects.
If you need to add together a
Collectionof money objects, you may use the
financialSummethod. It will return a new money object.
collect(Mula::create('1500', 'USD'), Mula::create('3000', 'USD'))->financialSum(); // A new money object with a value of $45.00.
Mulauses PhpUnit for unit tests. You can run the test suite from the terminal:
composer test
Please see CHANGELOG for more information what has changed recently.
Please see CONTRIBUTING for details.
If you discover any security related issues, please email [email protected] instead of using the issue tracker.
The MIT License (MIT). Please see License File for more information.
This package was generated using the Laravel Package Boilerplate.