Skip to main content

Overview

The Money and Currency classes implement Laravel’s Macroable trait, allowing you to add custom functionality through macros and mixins. This powerful feature enables you to extend the package’s capabilities without modifying the source code.

Using Macros

Macros allow you to add individual methods to the Money or Currency classes at runtime.

Basic Macro Example

Add a static method to create zero-value money:
use Devhammed\LaravelBrickMoney\Money;
use Devhammed\LaravelBrickMoney\Currency;

Money::macro('zero', fn(Currency|string $currency) => Money::of(0, $currency));

// Usage
$zeroUSD = Money::zero('USD'); // $0.00
$zeroEUR = Money::zero('EUR'); // €0,00

Instance Macros

Create instance methods that can access $this:
Money::macro('withPercentage', function (float $percentage): Money {
    return $this->multipliedBy(1 + ($percentage / 100));
});

// Usage
$price = Money::of(100, 'USD');
$withTax = $price->withPercentage(10); // $110.00

Practical Examples

Money::macro('addTax', function (float $taxRate): Money {
    return $this->plus(
        $this->multipliedBy($taxRate / 100)
    );
});

$price = Money::of(100, 'USD');
$priceWithTax = $price->addTax(7.5); // $107.50

Using Mixins

Mixins allow you to add multiple methods to a class at once using a dedicated class. This is cleaner and more maintainable than defining multiple individual macros.

Creating a Mixin Class

use Devhammed\LaravelBrickMoney\Money;
use Devhammed\LaravelBrickMoney\Currency;

class MoneyExtensions
{
    /**
     * Static methods become static macros
     */
    public static function zero(Currency|string $currency): Money
    {
        return Money::of(0, $currency);
    }
    
    /**
     * Instance methods become instance macros
     */
    public function withPercentage(float $percentage): Money
    {
        return $this->multipliedBy(1 + ($percentage / 100));
    }
    
    public function addTax(float $taxRate): Money
    {
        return $this->plus(
            $this->multipliedBy($taxRate / 100)
        );
    }
    
    public function applyDiscount(float $percentage): Money
    {
        $discount = $this->multipliedBy($percentage / 100);
        return $this->minus($discount);
    }
}

Registering a Mixin

Money::mixin(new MoneyExtensions());

// Now all methods are available
$zero = Money::zero('USD');
$price = Money::of(100, 'USD')
    ->withPercentage(10)
    ->addTax(7.5); // $118.25

Service Provider Registration

Register your mixins in a service provider to make them available throughout your application:
namespace App\Providers;

use App\Extensions\MoneyExtensions;
use Devhammed\LaravelBrickMoney\Money;
use Illuminate\Support\ServiceProvider;

class AppServiceProvider extends ServiceProvider
{
    public function boot(): void
    {
        Money::mixin(new MoneyExtensions());
    }
}

Advanced Mixin Example

Here’s a comprehensive example with formatting and validation helpers:
class MoneyHelpers
{
    /**
     * Create Money from cents/minor units
     */
    public static function cents(int $cents, Currency|string $currency): Money
    {
        return Money::ofMinor($cents, $currency);
    }
    
    /**
     * Check if amount is within range
     */
    public function isBetween(Money $min, Money $max): bool
    {
        return $this->isGreaterThanOrEqualTo($min) 
            && $this->isLessThanOrEqualTo($max);
    }
    
    /**
     * Format as accounting notation (negative in parentheses)
     */
    public function formatAccounting(): string
    {
        $formatted = $this->abs()->format();
        return $this->isNegative() ? "({$formatted})" : $formatted;
    }
    
    /**
     * Calculate percentage of total
     */
    public function percentageOf(Money $total): float
    {
        if ($total->isZero()) {
            return 0.0;
        }
        
        return $this->getAmount()
            ->dividedBy($total->getAmount(), 4)
            ->multipliedBy(100)
            ->toFloat();
    }
}

Money::mixin(new MoneyHelpers());

// Usage
$amount = Money::cents(1500, 'USD'); // $15.00
$total = Money::of(100, 'USD');
$amount->percentageOf($total); // 15.0
When using mixins, static methods in your mixin class become static macros on the target class, while instance methods become instance macros with access to $this.

Currency Extensions

You can also extend the Currency class:
use Devhammed\LaravelBrickMoney\Currency;

class CurrencyExtensions
{
    public static function popular(): array
    {
        return [
            Currency::of('USD'),
            Currency::of('EUR'),
            Currency::of('GBP'),
            Currency::of('JPY'),
        ];
    }
    
    public function isCrypto(): bool
    {
        return in_array($this->getCode(), ['BTC', 'ETH', 'USDT']);
    }
}

Currency::mixin(new CurrencyExtensions());

// Usage
$currencies = Currency::popular();
$btc = Currency::of('BTC');
$isCrypto = $btc->isCrypto(); // true
Macros and mixins are particularly useful for adding domain-specific business logic without cluttering your main application code.

Best Practices

Create separate mixin classes for different concerns (e.g., MoneyFormatting, MoneyCalculations, MoneyValidation) rather than one large class.
Add PHPDoc comments to your mixin methods so IDEs can provide autocompletion:
/**
 * @method static Money zero(Currency|string $currency)
 * @method Money withPercentage(float $percentage)
 */
class Money {}
Write unit tests for your custom macros and mixins to ensure they work correctly:
test('withPercentage macro adds percentage correctly', function () {
    $price = Money::of(100, 'USD');
    $result = $price->withPercentage(10);
    
    expect($result->getAmount()->toFloat())->toBe(110.0);
});
Don’t create macros that conflict with existing Money or Currency methods. Check the API Reference first.

Next Steps

Livewire Support

Learn how to use Money and Currency in Livewire components

Formatting

Master advanced formatting options and localization

Build docs developers (and LLMs) love