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.