Money::zero()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 3
nc 1
nop 2
dl 0
loc 6
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace Money;
4
5
use Brick\Math\BigDecimal;
6
use Brick\Math\BigNumber;
7
use Brick\Math\Exception\ArithmeticException;
8
use Brick\Math\Exception\RoundingNecessaryException;
9
use Brick\Math\RoundingMode;
10
use Currency\Currency;
11
use Money\Exception\CurrencyMismatchException;
12
13
/**
14
 * Money class.
15
 *
16
 * Most popular currency codes for autocomplete.
17
 * @method static Money USD($amount, $customMinorUnit = null)
18
 * @method static Money EUR($amount, $customMinorUnit = null)
19
 * @method static Money RUB($amount, $customMinorUnit = null)
20
 * @method static Money JPY($amount, $customMinorUnit = null)
21
 * @method static Money GBP($amount, $customMinorUnit = null)
22
 * @method static Money CHF($amount, $customMinorUnit = null)
23
 * @method static Money CAD($amount, $customMinorUnit = null)
24
 * @method static Money AUD($amount, $customMinorUnit = null)
25
 * @method static Money ZAR($amount, $customMinorUnit = null)
26
 */
27
class Money implements \JsonSerializable
28
{
29
    /** @var BigDecimal */
30
    private $amount;
31
32
    /** @var Currency */
33
    private $currency;
34
35
    /**
36
     * @param BigNumber|number|string $amount       The amount.
37
     * @param string                  $currencyCode The currency code.
38
     * @param int|null                $customMinorUnit
39
     * @param int                     $rounding
40
     * @throws \InvalidArgumentException
41
     * @throws ArithmeticException
42
     */
43
    public function __construct($amount, $currencyCode, $customMinorUnit = null, $rounding = RoundingMode::UNNECESSARY)
44
    {
45
        $this->currency = Currency::create($currencyCode, $customMinorUnit);
46
        $this->amount = BigDecimal::of($amount)->toScale($this->currency->getMinorUnit(), $rounding);
47
    }
48
49
    /**
50
     * @param string   $amount
51
     * @param string   $currencyCode
52
     * @param int|null $customMinorUnit
53
     * @param int      $rounding
54
     * @return Money
55
     * @throws \InvalidArgumentException
56
     * @throws ArithmeticException
57
     */
58
    public static function create(
59
        $amount,
60
        $currencyCode,
61
        $customMinorUnit = null,
62
        $rounding = RoundingMode::UNNECESSARY
63
    ) {
64
        return new self($amount, $currencyCode, $customMinorUnit, $rounding);
65
    }
66
67
    /**
68
     * Convenience factory method for a Money object.
69
     *
70
     * <code>
71
     * $fiveDollar = Money::USD(5);
72
     * </code>
73
     *
74
     * @param $currencyCode
75
     * @param $arguments
76
     * @return Money
77
     * @throws \InvalidArgumentException
78
     * @throws ArithmeticException
79
     */
80
    public static function __callStatic($currencyCode, $arguments)
81
    {
82
        $amount = isset($arguments[0]) ? $arguments[0] : 0;
83
        $customMinorUnit = isset($arguments[1]) ? $arguments[1] : null;
84
        $rounding = isset($arguments[2]) ? $arguments[2] : RoundingMode::UNNECESSARY;
85
86
        return new self($amount, $currencyCode, $customMinorUnit, $rounding);
87
    }
88
89
    /**
90
     * Returns a Money with zero value, in the given Currency.
91
     *
92
     * @param Currency|string $currencyCode    A currency currency code.
93
     * @param int|null        $customMinorUnit Custom currency minor unit, or null to use the default.
94
     *
95
     * @return Money
96
     * @throws RoundingNecessaryException
97
     * @throws \InvalidArgumentException
98
     * @throws ArithmeticException
99
     */
100
    public static function zero($currencyCode, $customMinorUnit = null)
101
    {
102
        $currency = Currency::create($currencyCode, $customMinorUnit);
103
        $amount = BigDecimal::zero()->toScale($currency->getMinorUnit());
104
105
        return new self($amount, $currencyCode);
106
    }
107
108
    /**
109
     * @param Money $other
110
     * @throws CurrencyMismatchException
111
     */
112
    private function assertCurrency(Money $other)
0 ignored issues
show
Unused Code introduced by
The method assertCurrency() is not used, and could be removed.

This check looks for private methods that have been defined, but are not used inside the class.

Loading history...
113
    {
114
        if (false === $this->isSameCurrency($other)) {
115
            throw CurrencyMismatchException::createFromCurrencies($this->getCurrency(), $other->getCurrency());
116
        }
117
    }
118
119
    /**
120
     * Returns the amount of this Money, as a BigDecimal.
121
     *
122
     * @return BigDecimal
123
     */
124
    public function getAmount()
125
    {
126
        return $this->amount;
127
    }
128
129
    /**
130
     * Returns the Currency of this Money.
131
     *
132
     * @return Currency
133
     */
134
    public function getCurrency()
135
    {
136
        return $this->currency;
137
    }
138
139
    /**
140
     * Returns a Money whose value is the absolute value of this Money.
141
     *
142
     * @return Money
143
     * @throws \InvalidArgumentException
144
     * @throws ArithmeticException
145
     */
146
    public function abs()
147
    {
148
        return new self($this->amount->abs(), $this->currency->getCode());
149
    }
150
151
    /**
152
     * Returns a Money whose value is the negated value of this Money.
153
     *
154
     * @return Money
155
     * @throws \InvalidArgumentException
156
     * @throws ArithmeticException
157
     */
158
    public function negate()
159
    {
160
        return new self($this->amount->negated(), $this->currency->getCode());
161
    }
162
163
    /**
164
     * Returns whether this Money has zero value.
165
     *
166
     * @return bool
167
     */
168
    public function isZero()
169
    {
170
        return $this->amount->isZero();
171
    }
172
173
    /**
174
     * Returns whether this Money has a negative value.
175
     *
176
     * @return bool
177
     */
178
    public function isNegative()
179
    {
180
        return $this->amount->isNegative();
181
    }
182
183
    /**
184
     * Returns whether this Money has a negative or zero value.
185
     *
186
     * @return bool
187
     */
188
    public function isNegativeOrZero()
189
    {
190
        return $this->amount->isNegativeOrZero();
191
    }
192
193
    /**
194
     * Returns whether this Money has a positive value.
195
     *
196
     * @return bool
197
     */
198
    public function isPositive()
199
    {
200
        return $this->amount->isPositive();
201
    }
202
203
    /**
204
     * Returns whether this Money has a positive or zero value.
205
     *
206
     * @return bool
207
     */
208
    public function isPositiveOrZero()
209
    {
210
        return $this->amount->isPositiveOrZero();
211
    }
212
213
    /**
214
     * Returns a new Money object that represents
215
     * the multiplied value by the given factor.
216
     *
217
     * @param $that
218
     * @param int $rounding
219
     * @return Money
220
     */
221
    public function multiply($that, $rounding = RoundingMode::UNNECESSARY)
222
    {
223
        $multiplier = $that instanceof Money ? $that->getAmount() : $that;
224
        $amount = $this->amount->multipliedBy($multiplier);
225
226
        return new self($amount, $this->currency->getCode(), $this->getCurrency()->getMinorUnit(), $rounding);
227
    }
228
229
    /**
230
     * Returns a new Money object that represents
231
     * the divided value by the given factor.
232
     *
233
     * @param $that
234
     * @param int $rounding
235
     * @return Money
236
     */
237
    public function divide($that, $rounding = RoundingMode::UNNECESSARY)
238
    {
239
        $divisor = $that instanceof Money ? $that->getAmount() : $that;
240
        $amount = $this->amount->dividedBy($divisor, $this->getAmount()->scale(), $rounding);
241
242
        return new self($amount, $this->currency->getCode(), $this->getCurrency()->getMinorUnit(), $rounding);
243
    }
244
245
    /**
246
     * Returns a new Money object that represents
247
     * the sum of this and an other Money object.
248
     *
249
     * @param $that
250
     * @return Money
251
     * @throws \InvalidArgumentException
252
     * @throws ArithmeticException
253
     */
254
    public function plus($that)
255
    {
256
        $addend = $that instanceof Money ? $that->getAmount() : $that;
257
        $amount = $this->amount->plus($addend);
258
259
        return new self($amount, $this->currency->getCode(), $this->getCurrency()->getMinorUnit());
260
    }
261
262
    /**
263
     * Returns a new Money object that represents
264
     * the difference of this and an other Money object.
265
     *
266
     * @param $that
267
     * @return Money
268
     * @throws \InvalidArgumentException
269
     * @throws ArithmeticException
270
     */
271
    public function minus($that)
272
    {
273
        $subtrahend = $that instanceof Money ? $that->getAmount() : $that;
274
        $amount = $this->amount->minus($subtrahend);
275
276
        return new self($amount, $this->currency->getCode(), $this->getCurrency()->getMinorUnit());
277
    }
278
279
    /**
280
     * Checks whether a Money has the same Currency as this.
281
     *
282
     * @param Money $that
283
     *
284
     * @return bool
285
     */
286
    public function isSameCurrency(Money $that)
287
    {
288
        return $this->currency->is($that->currency);
289
    }
290
291
    /**
292
     * Checks whether the value represented by this object equals to the other.
293
     *
294
     * @param Money $other
295
     *
296
     * @return bool
297
     */
298
    public function equals(Money $other)
299
    {
300
        return $this->amount->isEqualTo($other->amount) && $this->isSameCurrency($other);
301
    }
302
303
    /**
304
     * Returns whether this Money is less than the given amount
305
     *
306
     * @param Money|BigNumber|number|string $that
307
     *
308
     * @return bool
309
     *
310
     * @throws ArithmeticException       If the argument is an invalid number.
311
     * @throws CurrencyMismatchException If the argument is a money in a different currency.
312
     */
313
    public function lessThan($that)
314
    {
315
        $amount = $that instanceof Money ? $that->getAmount() : $that;
316
317
        return $this->amount->isLessThan($amount);
318
    }
319
320
    /**
321
     * Returns whether this Money is less than or equal to the given amount.
322
     *
323
     * @param Money|BigNumber|number|string $that
324
     *
325
     * @return bool
326
     *
327
     * @throws ArithmeticException       If the argument is an invalid number.
328
     * @throws CurrencyMismatchException If the argument is a money in a different currency.
329
     */
330
    public function lessThanOrEqual($that)
331
    {
332
        $amount = $that instanceof Money ? $that->getAmount() : $that;
333
334
        return $this->amount->isLessThanOrEqualTo($amount);
335
    }
336
337
    /**
338
     * Returns whether this Money is greater than the given amount.
339
     *
340
     * @param Money|BigNumber|number|string $that
341
     *
342
     * @return bool
343
     *
344
     * @throws ArithmeticException       If the argument is an invalid number.
345
     * @throws CurrencyMismatchException If the argument is a money in a different currency.
346
     */
347
    public function greaterThan($that)
348
    {
349
        $amount = $that instanceof Money ? $that->getAmount() : $that;
350
351
        return $this->amount->isGreaterThan($amount);
352
    }
353
354
    /**
355
     * Returns whether this Money is greater than or equal to the given amount.
356
     *
357
     * @param Money|BigNumber|number|string $that
358
     *
359
     * @return bool
360
     *
361
     * @throws ArithmeticException       If the argument is an invalid number.
362
     * @throws CurrencyMismatchException If the argument is a money in a different currency.
363
     */
364
    public function greaterThanOrEqual($that)
365
    {
366
        $amount = $that instanceof Money ? $that->getAmount() : $that;
367
368
        return $this->amount->isGreaterThanOrEqualTo($amount);
369
    }
370
371
    /**
372
     * Formats this Money with the given NumberFormatter.
373
     *
374
     * Note that NumberFormatter internally represents values using floating point arithmetic,
375
     * so discrepancies can appear when formatting very large monetary values.
376
     *
377
     * @param \NumberFormatter $formatter
378
     *
379
     * @return string
380
     */
381
    public function formatWith(\NumberFormatter $formatter)
382
    {
383
        return $formatter->formatCurrency(
384
            (string)$this->amount,
0 ignored issues
show
Bug introduced by
(string)$this->amount of type string is incompatible with the type double expected by parameter $value of NumberFormatter::formatCurrency(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

384
            /** @scrutinizer ignore-type */ (string)$this->amount,
Loading history...
385
            (string)$this->currency
386
        );
387
    }
388
389
    /**
390
     * Formats this Money to the given locale.
391
     *
392
     * Note that this method uses NumberFormatter, which internally represents values using floating point arithmetic,
393
     * so discrepancies can appear when formatting very large monetary values.
394
     *
395
     * @param string $locale
396
     *
397
     * @return string
398
     */
399
    public function formatTo($locale)
400
    {
401
        return $this->formatWith(new \NumberFormatter($locale, \NumberFormatter::CURRENCY));
402
    }
403
404
    /**
405
     * Returns a non-localized string representation of this Money, e.g. "EUR 23.00".
406
     *
407
     * @return string
408
     */
409
    public function __toString()
410
    {
411
        return $this->currency.' '.$this->amount;
412
    }
413
414
    /**
415
     * Serialize money.
416
     *
417
     * @return array
418
     */
419
    public function jsonSerialize()
420
    {
421
        return [
422
            'amount' => (string)$this->amount,
423
            'currency' => (string)$this->currency,
424
        ];
425
    }
426
}
427