- Laravel wrapper over the MoneyPHP library
- Provides a convenient way to work with the money column as a Value Object
- Uses the Custom Casts Laravel 7.x feature
- Features
- Requirements
- Installation
- Supported concepts
- Display money data in the form input field
- Parse money from request field
- Using in API resources
- Model creation
- Bitcoin creation
- Retrieving data
- Operations
- Library API
- Convenient work with the native the MoneyPHP library and Laravel Eloquent ORM
- Money columns casting
- Currencies columns casting
- Supported concepts
- Money columns with default Currency (without a specific column)
- Currency columns without Money
- Many Money columns reference to one Currency column
- Money to Currencies columns mapping
- PHP ^8.0
- Laravel v7.x|v8.x
Suggest
- BCMath (
ext-bcmath) and GMP (ext-gmp) PHP Extensions for calculations with large integers - Intl PHP Extension (
ext-intl) for formatting
Require package
composer require andriichuk/laracashPublish vendor settings
php artisan vendor:publish --provider="Andriichuk\Laracash\ServiceProviders\LaracashServiceProvider" --tag="config"Default settings
[
'currency' => 'USD',
'locale' => 'en_US',
]<?php
namespace App;
use Andriichuk\Laracash\Casts\MoneyCast;
use Illuminate\Database\Eloquent\Model;
use Money\Money;
/**
* Class OrderItem
*
* @property Money $price
* @property Money $discount
*/
class OrderItem extends Model
{
protected $fillable = ['name', 'price', 'discount'];
protected $casts = [
'price' => MoneyCast::class,
'discount' => MoneyCast::class,
];
}OrderItem::create([
'name' => 'Order Item',
'price' => makeMoney(1000),
'discount' => makeMoney(15),
]);<?php
namespace App;
use Andriichuk\Laracash\Casts\CurrencyCast;
use Andriichuk\Laracash\Model\HasCurrency;
use Andriichuk\Laracash\Model\HasCurrencyInterface;
use Illuminate\Database\Eloquent\Model;
use Money\Currency;
/**
* Class Rate
*
* @property Currency $currency
*/
class Rate extends Model implements HasCurrencyInterface
{
use HasCurrency;
protected $fillable = ['name', 'price', 'currency', 'native_currency'];
protected $casts = [
'currency' => CurrencyCast::class,
'native_currency' => CurrencyCast::class,
];
}Rate::create([
'name' => 'Rate #1',
'price' => 99,
'currency' => new Currency('USD'),
'native_currency' => 'UAH',
]);use Andriichuk\Laracash\Casts\CurrencyCast;
use Andriichuk\Laracash\Casts\MoneyCast;
use Andriichuk\Laracash\Model\HasCurrency;
use Andriichuk\Laracash\Model\HasMoneyWithCurrency;
use Andriichuk\Laracash\Model\HasMoneyWithCurrencyInterface;
use Illuminate\Database\Eloquent\Model;
use Money\Currency;
use Money\Money;
/**
* Class Transaction
*
* @property Money $payment_amount
* @property Money $discount
* @property Currency $currency
*/
class Transaction extends Model implements HasMoneyWithCurrencyInterface
{
use HasMoneyWithCurrency;
use HasCurrency;
protected $fillable = ['name', 'payment_amount', 'discount', 'currency'];
protected $casts = [
'payment_amount' => MoneyCast::class,
'discount' => MoneyCast::class,
'currency' => CurrencyCast::class,
];
public function getCurrencyColumnFor(string $field): string
{
return 'currency';
}
}If the currency is in a related model, just return an empty string (
'') ingetCurrencyColumnFor().
use Andriichuk\Laracash\Casts\CurrencyCast;
use Andriichuk\Laracash\Casts\MoneyCast;
use Andriichuk\Laracash\Model\HasCurrency;use Andriichuk\Laracash\Model\HasMoneyWithCurrency;
use Andriichuk\Laracash\Model\HasMoneyWithCurrencyInterface;
use Illuminate\Database\Eloquent\Model;
use Money\Currency;
use Money\Money;
/**
* Class Product
*
* @property Money $payment_amount
* @property Money $discount
* @property Currency $currency
*/
class Product extends Model implements HasMoneyWithCurrencyInterface
{
use HasMoneyWithCurrency;
use HasCurrency;
protected $fillable = ['name', 'price', 'currency', 'book_price', 'native_currency'];
protected $casts = [
'price' => MoneyCast::class,
'currency' => CurrencyCast::class,
'book_price' => MoneyCast::class,
'native_currency' => CurrencyCast::class
];
public function getCurrencyColumnFor(string $field): string
{
return [
'price' => 'currency',
'book_price' => 'native_currency',
][$field] ?? '';
}
}Product::create([
'price' => \Money\Money::USD(1000),
'book_price' => Money::UAH(25000),
]);If you want to use magic accessors (*_as_currency, *_as_decimal) for money fields then you should add HasMoney trait to your Eloquent Model (accessors will be added automatically)
<?php
namespace App;
use Andriichuk\Laracash\Casts\MoneyCast;
use Andriichuk\Laracash\Model\HasMoney;
use Illuminate\Database\Eloquent\Model;
use Money\Money;
/**
* Class Product
*
* @property Money $price
* @property-read string $price_as_currency
* @property-read string $price_as_decimal
*/
class Product extends Model
{
use HasMoney;
protected $fillable = ['name', 'price'];
protected $casts = [
'price' => MoneyCast::class,
];
}Now you can call magic fields
use App\Product;
$product = Product::find(1);
$product->price_as_decimal; // "10.00"
$product->price_as_currency; // "$10.00"
$product->price = 5000;
$product->price_as_decimal; // "50.00"
$product->price_as_currency; // "$50.00"Assign model
use App\Product;
use Illuminate\Support\Facades\Route;
Route::view('/', 'productForm', ['product' => Product::find(1)]);Present money object as a decimal value
<input type="number" name="price" value="{{ formatMoneyAsDecimal($product->price) }}">
{{-- or with magic syntax --}}
<input type="number" name="price" value="{{ $product->price_as_decimal }}">use App\Product;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;
Route::post('products/{product}', function (Product $product, Request $request) {
$product->price = parseMoneyDecimal($request->get('price')); // 55.99 => Money::USD(5599)
});Define model resource
use App\Product;
use Illuminate\Http\Resources\Json\JsonResource;
/**
* Class ProductResource
*
* @mixin Product
*/
final class ProductResource extends JsonResource
{
public function toArray($request): array
{
return [
'id' => $this->id,
'name' => $this->name,
'price' => $this->price,
'price_as_currency' => $this->price_as_currency, // or formatMoneyAsCurrency($this->price)
];
}
}Apply resource to the model
use App\Product;
use App\Http\Resources\ProductResource;
Route::get('products/{product}', function (Product $product) {
return new ProductResource($product);
});Output
{
"data": {
"id": 1,
"name": "Product name",
"price": {
"amount": "1000",
"currency": "USD"
},
"price_as_currency": "$10.00"
}
}Using scalar values (int|string)
use App\Product;
Product::create([
'name' => 'The First Product',
'price' => 100,
]);Using Money\Money object:
use App\Product;
use Money\Money;
Product::create([
'name' => 'The Second Product',
'price' => Money::USD(100),
]);Using facade:
use Andriichuk\Laracash\Facades\Laracash;
use App\Product;
Product::create([
'name' => 'The Third Product',
'price' => Laracash::factory()->make(100)
]);Using helper function:
use App\Product;
Product::create([
'name' => 'The Fourth Product',
'price' => makeMoney(100)
]);use Andriichuk\Laracash\Facades\Laracash;
use Money\Money;
// Using Facade
Laracash::factory()->makeBitcoin(1000000000);
// Using helper
makeBitcoin(1000000000);
// Using native library factory call
Money::XBT(1000000000);use App\Product;
$product = Product::find(1);
dd($product->price);Money\Money {#403 â–¼
-amount: "1000"
-currency: Money\Currency {#404 â–¼
-code: "USD"
}
}
Check original library docs for more information
use Andriichuk\Laracash\Facades\Laracash;
use App\Product;
$product = Product::find(1);
$product->price = $product->price->add(Laracash::factory()->make(2000));
$product->save();Money instance creation using Laracash facade.
*If you do not pass the second argument currency, then it will take from config file
use \Andriichuk\Laracash\Facades\Laracash;
Laracash::factory()->make(1000);
Laracash::factory()->make('10000000000000');Specify currency
use \Andriichuk\Laracash\Facades\Laracash;
use \Money\Currency;
Laracash::factory()->make(1000, 'USD');
Laracash::factory()->make(1000, new Currency('USD'));
// Or use native method Money::USD(100)Money\Money {#403 â–¼
-amount: "1000"
-currency: Money\Currency {#404 â–¼
-code: "USD"
}
}
Money instance formatting. More info
Decimal
use \Andriichuk\Laracash\Facades\Laracash;
use Money\Money;
Laracash::formatter()->formatAsDecimal(Money::USD(100)); // "1.00"
formatMoneyAsDecimal(Money::USD(100)); // "1.00"Using Intl extension
use \Andriichuk\Laracash\Facades\Laracash;
use Money\Money;
Laracash::formatter()->formatAsIntlDecimal(Money::USD(100)); // "1"
Laracash::formatter()->formatAsIntlDecimal(Money::USD(100), 'uk_UA'); // "1"Intl currency
use \Andriichuk\Laracash\Facades\Laracash;
use Money\Money;
Laracash::formatter()->formatAsIntlCurrency(Money::USD(100)); // "$1.00"
Laracash::formatter()->formatAsIntlCurrency(Money::USD(100), 'uk_UA'); // "1,00Â USD"
formatMoneyAsCurrency(Money::USD(100)); // "$1.00"
formatMoneyAsCurrency(Money::XBT(1000000000)); // "Ƀ10.00"Specify custom Intl formatting style
use \Andriichuk\Laracash\Facades\Laracash;
use Money\Money;
use NumberFormatter;
Laracash::formatter()->formatIntlWithStyle(Money::USD(100), 'en_US', NumberFormatter::SPELLOUT); // "one"
Laracash::formatter()->formatIntlWithStyle(Money::USD(100), 'en_US', NumberFormatter::SCIENTIFIC); // "1E0"Bitcoin
use \Andriichuk\Laracash\Facades\Laracash;
use Money\Money;
Laracash::formatter()->formatBitcoin(Money::XBT(1000000000)); // "Ƀ10.00"
// or use helper function
formatMoneyAsCurrency(makeBitcoin(1000000000)); // "Ƀ10.00"Bitcoin as decimal
use \Andriichuk\Laracash\Facades\Laracash;
use Money\Money;
Laracash::formatter()->formatBitcoinAsDecimal(Money::XBT(1000000000)); // "10.00000000"
// or use helper function
formatMoneyAsDecimal(makeBitcoin(1000000000)); // "10.00000000"Intl parse money string with currency
use Andriichuk\Laracash\Facades\Laracash;
Laracash::parser()->parseIntlCurrency('$1.00');Result
Money\Money {#369 â–¼
-amount: "100"
-currency: Money\Currency {#368 â–¼
-code: "USD"
}
}
Parse decimal
use Andriichuk\Laracash\Facades\Laracash;
Laracash::parser()->parseDecimal('1.30');
parseMoneyDecimal('1.30');Result
Money\Money {#368 â–¼
-amount: "130"
-currency: Money\Currency {#367 â–¼
-code: "USD"
}
}
Run features and unit tests:
./vendor/bin/phpunitLaracash is an open-sourced software licensed under the MIT license.
