andriichuk / laracash
PHP Laravel Money Package
Installs: 102 457
Dependents: 1
Suggesters: 0
Security: 0
Stars: 69
Watchers: 5
Forks: 12
Open Issues: 0
Requires
- php: ^8.0
- ext-json: *
- illuminate/config: ^7.2|^8.0|^9.0|^10.0|^11.0
- illuminate/contracts: ^7.2|^8.0|^9.0|^10.0|^11.0
- illuminate/database: ^7.30|^8.40|^9.0|^10.0|^11.0
- illuminate/support: ^7.2|^8.0|^9.0|^10.0|^11.0
- moneyphp/money: ^4.0
Requires (Dev)
- ext-bcmath: *
- ext-gmp: *
- ext-intl: *
- orchestra/testbench: ^6.20|^8.0|^9.0
- phpunit/phpunit: ^9.0|^10.5
- vimeo/psalm: ^4.9|^5.6
This package is auto-updated.
Last update: 2024-11-16 04:12:37 UTC
README
- 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
Table of Contents
- 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
Features
- 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
Requirements
- 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
Installation
Require package
composer require andriichuk/laracash
Publish vendor settings
php artisan vendor:publish --provider="Andriichuk\Laracash\ServiceProviders\LaracashServiceProvider" --tag="config"
Default settings
[ 'currency' => 'USD', 'locale' => 'en_US', ]
Usage Concepts
Money columns with default Currency
<?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), ]);
Currency columns without Money
<?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', ]);
Multiple Money columns refer to one Currency column
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()
.
Money to Currencies columns mapping
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"
Display money data in the form input field
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 }}">
Parse money from request field
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) });
Using in API resources
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" } }
Model Creation
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) ]);
Bitcoin creation
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);
Retrieving data
use App\Product; $product = Product::find(1); dd($product->price);
Money\Money {#403 ▼
-amount: "1000"
-currency: Money\Currency {#404 ▼
-code: "USD"
}
}
Operations
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();
API
Creation
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"
}
}
Formatting
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"
Parsing
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"
}
}
Tests
Run features and unit tests:
./vendor/bin/phpunit
Credits
License
Laracash is an open-sourced software licensed under the MIT license.