From 5f5efe5e9d56f12c02eb32319638c5ca5a7d494a Mon Sep 17 00:00:00 2001 From: Luke Sheppard Date: Thu, 20 Jul 2023 21:26:40 +0100 Subject: [PATCH 1/2] Add Macro and Mixin information to README --- README.md | 70 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) diff --git a/README.md b/README.md index 8fe62b1..e361b13 100644 --- a/README.md +++ b/README.md @@ -101,6 +101,76 @@ or ``` +### Macros + +This package implements the Laravel `Macroable` trait, allowing macros and mixins on both `Money` and `Currency`. + +Example use case: + +```php +use Akaunting\Money\Currency; +use Akaunting\Money\Money; + +Money::macro( + 'absolute', + fn () => $this->isPositive() ? $this : $this->multiply(-1) +); + +$money = Money::USD(1000)->multiply(-1); + +$absolute = $money->absolute(); +``` + +Macros can be called statically too: + +```php +use Akaunting\Money\Currency; +use Akaunting\Money\Money; + +Money::macro('zero', fn (?string $currency = null) => new Money(0, new Currency($currency ?? 'GBP'))); + +$money = Money::zero(); +``` + +### Mixins + +Along with Macros, Mixins are also supported. This allows merging another classes methods into the Money or Currency class. + +Define the mixin class: + +```php +use Akaunting\Money\Money; + +class CustomMoney +{ + public function absolute(): Money + { + return $this->isPositive() ? $this : $this->multiply(-1); + } + + public static function zero(?string $currency = null): Money + { + return new Money(0, new Currency($currency ?? 'GBP')); + } +} +``` + +Register the mixin, by passing an instance of the class: + +```php +Money::mixin(new CustomMoney); +``` + +The methods from the custom class will be available: + +```php +$money = Money::USD(1000)->multiply(-1); +$absolute = $money->absolute(); + +// Static methods via mixins are supported too: +$money = Money::zero(); +``` + ## Changelog Please see [Releases](../../releases) for more information on what has changed recently. From b43e60f191221b856b6f0ca3411c1a7699ba2cc7 Mon Sep 17 00:00:00 2001 From: Luke Sheppard Date: Thu, 20 Jul 2023 21:38:48 +0100 Subject: [PATCH 2/2] #87 Allow static Macros Money and Currency override the Macroable __callStatic method, effectively disabling static macros. Add a check in, if the statically called method exists as a macro, then call the macro instead. --- src/Currency.php | 8 +++++++- src/Money.php | 8 +++++++- tests/CurrencyTest.php | 7 +++++++ tests/MoneyTest.php | 7 +++++++ 4 files changed, 28 insertions(+), 2 deletions(-) diff --git a/src/Currency.php b/src/Currency.php index d93a0d8..4cc11ab 100644 --- a/src/Currency.php +++ b/src/Currency.php @@ -182,7 +182,9 @@ */ class Currency implements Arrayable, Castable, Jsonable, JsonSerializable, Renderable { - use Macroable; + use Macroable { + __callStatic as protected macroableCallStatic; + } protected string $currency; @@ -235,6 +237,10 @@ public function __construct(string $currency) public static function __callStatic(string $method, array $arguments): Currency { + if (static::hasMacro($method)) { + return static::macroableCallStatic($method, $arguments); + } + return new self($method); } diff --git a/src/Money.php b/src/Money.php index 9784ac7..671f89b 100644 --- a/src/Money.php +++ b/src/Money.php @@ -186,7 +186,9 @@ */ class Money implements Arrayable, Castable, Jsonable, JsonSerializable, Renderable { - use Macroable; + use Macroable { + __callStatic as protected macroableCallStatic; + } const ROUND_HALF_UP = PHP_ROUND_HALF_UP; @@ -283,6 +285,10 @@ protected function convertAmount(int|float $amount, bool $convert = false): int| public static function __callStatic(string $method, array $arguments): Money { + if (static::hasMacro($method)) { + return static::macroableCallStatic($method, $arguments); + } + $convert = isset($arguments[1]) && is_bool($arguments[1]) && $arguments[1]; return new self($arguments[0], new Currency($method), $convert); diff --git a/tests/CurrencyTest.php b/tests/CurrencyTest.php index f5c40d4..90a0656 100644 --- a/tests/CurrencyTest.php +++ b/tests/CurrencyTest.php @@ -88,4 +88,11 @@ public function testResetCurrencies() $this->assertEmpty(Currency::getCurrencies()); Currency::setCurrencies($currencies); } + + public function testStaticMacro() + { + Currency::macro('testMacro', fn () => Currency::EUR()); + + $this->assertEquals(Currency::EUR(), Currency::testMacro()); + } } diff --git a/tests/MoneyTest.php b/tests/MoneyTest.php index 9fe9299..04faf9e 100644 --- a/tests/MoneyTest.php +++ b/tests/MoneyTest.php @@ -411,4 +411,11 @@ public function testMakingMutable() $this->assertTrue($money->isImmutable()); $this->assertFalse($money->mutable()->isImmutable()); } + + public function testStaticMacro() + { + Money::macro('testMacro', fn () => Money::USD(1099)); + + $this->assertEquals(Money::USD(1099), Money::testMacro()); + } }