daikon-cqrs /
money-interop
| 1 | <?php declare(strict_types=1); |
||
| 2 | /** |
||
| 3 | * This file is part of the daikon-cqrs/money-interop project. |
||
| 4 | * |
||
| 5 | * For the full copyright and license information, please view the LICENSE |
||
| 6 | * file that was distributed with this source code. |
||
| 7 | */ |
||
| 8 | |||
| 9 | namespace Daikon\Money\ValueObject; |
||
| 10 | |||
| 11 | use Daikon\Interop\Assertion; |
||
| 12 | use Daikon\Interop\InvalidArgumentException; |
||
| 13 | use Daikon\Money\ValueObject\MoneyInterface; |
||
| 14 | use Money\Currency as PhpCurrency; |
||
| 15 | use Money\Money as PhpMoney; |
||
| 16 | |||
| 17 | class Money implements MoneyInterface |
||
| 18 | { |
||
| 19 | protected ?PhpMoney $money; |
||
| 20 | |||
| 21 | /** @param static $comparator */ |
||
| 22 | 1 | public function equals($comparator): bool |
|
| 23 | { |
||
| 24 | 1 | Assertion::isInstanceOf($comparator, static::class); |
|
| 25 | 1 | return $this->toNative() === $comparator->toNative(); |
|
| 26 | } |
||
| 27 | |||
| 28 | 16 | public function getAmount(): string |
|
| 29 | { |
||
| 30 | 16 | $this->assertNotEmpty(); |
|
| 31 | 16 | return $this->money->getAmount(); |
|
|
0 ignored issues
–
show
|
|||
| 32 | } |
||
| 33 | |||
| 34 | 22 | public function getCurrency(): string |
|
| 35 | { |
||
| 36 | 22 | $this->assertNotEmpty(); |
|
| 37 | 22 | return $this->money->getCurrency()->getCode(); |
|
| 38 | } |
||
| 39 | |||
| 40 | /** @return static */ |
||
| 41 | 4 | public function multiply($multiplier, int $roundingMode = self::ROUND_HALF_UP): self |
|
| 42 | { |
||
| 43 | 4 | $this->assertNotEmpty(); |
|
| 44 | 2 | Assertion::numeric($multiplier, 'Multipler must be numeric.'); |
|
| 45 | 2 | $multiplied = $this->money->multiply($multiplier, $roundingMode); |
|
| 46 | 2 | return new static($multiplied); |
|
| 47 | } |
||
| 48 | |||
| 49 | /** @return static */ |
||
| 50 | 4 | public function divide($divisor, int $roundingMode = self::ROUND_HALF_UP): self |
|
| 51 | { |
||
| 52 | 4 | $this->assertNotEmpty(); |
|
| 53 | 2 | Assertion::numeric($divisor, 'Divider must be numeric.'); |
|
| 54 | 2 | Assertion::notEq(0, $divisor, 'Divisor must not be zero.'); |
|
| 55 | 2 | $divided = $this->money->divide($divisor, $roundingMode); |
|
| 56 | 2 | return new static($divided); |
|
| 57 | } |
||
| 58 | |||
| 59 | /** @return static */ |
||
| 60 | 2 | public function percentage($percentage, int $roundingMode = self::ROUND_HALF_UP): self |
|
| 61 | { |
||
| 62 | 2 | $this->assertNotEmpty(); |
|
| 63 | 1 | return $this->multiply($percentage)->divide(100, $roundingMode); |
|
| 64 | } |
||
| 65 | |||
| 66 | /** @return static */ |
||
| 67 | 5 | public function add(MoneyInterface $money): self |
|
| 68 | { |
||
| 69 | 5 | $this->assertNotEmpty(); |
|
| 70 | 4 | $this->assertSameCurrency($money); |
|
| 71 | 3 | Assertion::false($money->isEmpty(), 'Addition must not be empty.'); |
|
| 72 | 3 | $added = $this->money->add( |
|
| 73 | 3 | static::asBaseMoney($money->getAmount(), $money->getCurrency()) |
|
| 74 | ); |
||
| 75 | 3 | return new static($added); |
|
| 76 | } |
||
| 77 | |||
| 78 | /** @return static */ |
||
| 79 | 4 | public function subtract(MoneyInterface $money): self |
|
| 80 | { |
||
| 81 | 4 | $this->assertNotEmpty(); |
|
| 82 | 3 | $this->assertSameCurrency($money); |
|
| 83 | 2 | Assertion::false($money->isEmpty(), 'Subtraction must not be empty.'); |
|
| 84 | 2 | $subtracted = $this->money->subtract( |
|
| 85 | 2 | static::asBaseMoney($money->getAmount(), $money->getCurrency()) |
|
| 86 | ); |
||
| 87 | 2 | return new static($subtracted); |
|
| 88 | } |
||
| 89 | |||
| 90 | /** @return static */ |
||
| 91 | 19 | public static function makeEmpty(): self |
|
| 92 | { |
||
| 93 | 19 | return new static; |
|
| 94 | } |
||
| 95 | |||
| 96 | 37 | public function isEmpty(): bool |
|
| 97 | { |
||
| 98 | 37 | return $this->money === null; |
|
| 99 | } |
||
| 100 | |||
| 101 | 5 | public function isZero(): bool |
|
| 102 | { |
||
| 103 | 5 | $this->assertNotEmpty(); |
|
| 104 | 4 | return $this->money->isZero(); |
|
| 105 | } |
||
| 106 | |||
| 107 | 2 | public function isPositive(): bool |
|
| 108 | { |
||
| 109 | 2 | $this->assertNotEmpty(); |
|
| 110 | 1 | return $this->money->isPositive(); |
|
| 111 | } |
||
| 112 | |||
| 113 | 2 | public function isNegative(): bool |
|
| 114 | { |
||
| 115 | 2 | $this->assertNotEmpty(); |
|
| 116 | 1 | return $this->money->isNegative(); |
|
| 117 | } |
||
| 118 | |||
| 119 | 4 | public function isLessThanOrEqual(MoneyInterface $comparator): bool |
|
| 120 | { |
||
| 121 | 4 | $this->assertNotEmpty(); |
|
| 122 | 3 | $this->assertSameCurrency($comparator); |
|
| 123 | 1 | Assertion::false($comparator->isEmpty(), 'Comparator must not be empty.'); |
|
| 124 | 1 | return $this->money->lessThanOrEqual( |
|
| 125 | 1 | static::asBaseMoney($comparator->getAmount(), $comparator->getCurrency()) |
|
| 126 | ); |
||
| 127 | } |
||
| 128 | |||
| 129 | 5 | public function isGreaterThanOrEqual(MoneyInterface $comparator): bool |
|
| 130 | { |
||
| 131 | 5 | $this->assertNotEmpty(); |
|
| 132 | 4 | $this->assertSameCurrency($comparator); |
|
| 133 | 2 | Assertion::false($comparator->isEmpty(), 'Comparator must not be empty.'); |
|
| 134 | 2 | return $this->money->greaterThanOrEqual( |
|
| 135 | 2 | static::asBaseMoney($comparator->getAmount(), $comparator->getCurrency()) |
|
| 136 | ); |
||
| 137 | } |
||
| 138 | |||
| 139 | /** |
||
| 140 | * @param null|string $value |
||
| 141 | * @return static |
||
| 142 | */ |
||
| 143 | 30 | public static function fromNative($value): self |
|
| 144 | { |
||
| 145 | 30 | Assertion::nullOrString($value, 'Must be a string.'); |
|
| 146 | 30 | if ($value === null) { |
|
| 147 | 3 | return new static; |
|
| 148 | } |
||
| 149 | |||
| 150 | 30 | if (!preg_match('/^(?<amount>-?\d+)\s?(?<currency>[a-z][a-z0-9]*)$/i', $value, $matches)) { |
|
| 151 | 1 | throw new InvalidArgumentException('Invalid amount.'); |
|
| 152 | } |
||
| 153 | |||
| 154 | 30 | return new static(static::asBaseMoney($matches['amount'], $matches['currency'])); |
|
| 155 | } |
||
| 156 | |||
| 157 | /** @return static */ |
||
| 158 | 16 | public static function zero($currency = null): self |
|
| 159 | { |
||
| 160 | 16 | Assertion::regex($currency, '/^[a-z][a-z0-9]*$/i', 'Invalid currency.'); |
|
| 161 | 16 | return static::fromNative('0'.$currency); |
|
| 162 | } |
||
| 163 | |||
| 164 | 12 | public function toNative(): ?string |
|
| 165 | { |
||
| 166 | 12 | return !$this->isEmpty() ? $this->getAmount().$this->getCurrency() : null; |
|
| 167 | } |
||
| 168 | |||
| 169 | 8 | public function __toString(): string |
|
| 170 | { |
||
| 171 | 8 | return (string)$this->toNative(); |
|
| 172 | } |
||
| 173 | |||
| 174 | 30 | protected static function asBaseMoney(string $amount, string $currency): PhpMoney |
|
| 175 | { |
||
| 176 | 30 | return new PhpMoney($amount, new PhpCurrency($currency)); |
|
| 177 | } |
||
| 178 | |||
| 179 | 36 | protected function assertNotEmpty(): void |
|
| 180 | { |
||
| 181 | 36 | Assertion::false($this->isEmpty(), 'Money is empty.'); |
|
| 182 | 24 | } |
|
| 183 | |||
| 184 | 14 | protected function assertSameCurrency(MoneyInterface $money): void |
|
| 185 | { |
||
| 186 | 14 | Assertion::eq($this->getCurrency(), $money->getCurrency(), 'Currencies must be identical.'); |
|
| 187 | 8 | } |
|
| 188 | |||
| 189 | 39 | final protected function __construct(?PhpMoney $money = null) |
|
| 190 | { |
||
| 191 | 39 | $this->money = $money; |
|
| 192 | 39 | } |
|
| 193 | } |
||
| 194 |
This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.
This is most likely a typographical error or the method has been renamed.