Passed
Push — master ( 1e8a0f...55b2d7 )
by Alec
04:01
created

MoneyFunctions   A

Complexity

Total Complexity 35

Size/Duplication

Total Lines 396
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 0
Metric Value
eloc 62
dl 0
loc 396
ccs 79
cts 79
cp 1
rs 9.6
c 0
b 0
f 0
wmc 35

25 Methods

Rating   Name   Duplication   Size   Complexity  
A greaterThan() 0 3 1
A lessThan() 0 3 1
A min() 0 11 3
A mod() 0 5 1
A avg() 0 3 1
A divide() 0 11 2
A sum() 0 3 1
A greaterThanOrEqual() 0 3 1
A lessThanOrEqual() 0 3 1
A equals() 0 3 2
A multiply() 0 8 1
A max() 0 11 3
A allocateTo() 0 7 2
A add() 0 11 2
A allocate() 0 4 1
A isNotZero() 0 4 1
A isPositive() 0 3 1
A ratioOf() 0 7 2
A subtract() 0 12 2
A negative() 0 3 1
A isNotPositive() 0 4 1
A absolute() 0 3 1
A isZero() 0 3 1
A isNotNegative() 0 4 1
A isNegative() 0 3 1
1
<?php
2
/**
3
 * User: alec
4
 * Date: 26.11.18
5
 * Time: 14:35
6
 */
7
8
namespace AlecRabbit\Money;
9
10
use AlecRabbit\Money\Contracts\CalculatorInterface;
11
12
trait MoneyFunctions
13
{
14
    /** @var CalculatorInterface */
15
    protected $calculator;
16
17
    /**
18
     * @param Money $first
19
     * @param Money ...$collection
20
     *
21
     * @return Money
22
     */
23 3
    public static function min(Money $first, Money ...$collection): Money
24
    {
25 3
        $min = $first;
26
27 3
        foreach ($collection as $money) {
28 2
            if ($money->lessThan($min)) {
29 2
                $min = $money;
30
            }
31
        }
32
33 3
        return $min;
34
    }
35
36
    /**
37
     * Checks whether the value represented by this object is less than the other.
38
     *
39
     * @param Money $other
40
     *
41
     * @return bool
42
     */
43 5
    public function lessThan(Money $other): bool
44
    {
45 5
        return $this->compare($other) === -1;
46
    }
47
48
    /**
49
     * @param Money $first
50
     * @param Money ...$collection
51
     *
52
     * @return Money
53
     */
54 3
    public static function max(Money $first, Money ...$collection): Money
55
    {
56 3
        $max = $first;
57
58 3
        foreach ($collection as $money) {
59 2
            if ($money->greaterThan($max)) {
60 2
                $max = $money;
61
            }
62
        }
63
64 3
        return $max;
65
    }
66
67
    /**
68
     * Checks whether the value represented by this object is greater than the other.
69
     *
70
     * @param Money $other
71
     *
72
     * @return bool
73
     */
74 5
    public function greaterThan(Money $other): bool
75
    {
76 5
        return $this->compare($other) === 1;
77
    }
78
79
    /**
80
     * @param Money $first
81
     * @param Money ...$collection
82
     *
83
     * @return Money
84
     */
85 6
    public static function sum(Money $first, Money ...$collection): Money
86
    {
87 6
        return $first->add(...$collection);
88
    }
89
90
    /**
91
     * Returns a new Money object that represents
92
     * the sum of this and an other Money object.
93
     *
94
     * @param Money ...$addends
95
     *
96
     * @return Money
97
     */
98 28
    public function add(Money ...$addends): Money
99
    {
100 28
        $amount = $this->getAmount();
101 28
        $calculator = $this->calculator;
102
103 28
        foreach ($addends as $addend) {
104 25
            $this->assertSameCurrency($addend);
105
106 25
            $amount = $calculator->add($amount, $addend->getAmount());
107
        }
108 28
        return new Money($amount, $this->getCurrency());
109
    }
110
111
    /**
112
     * @param Money $first
113
     * @param Money ...$collection
114
     *
115
     * @return Money
116
     */
117 5
    public static function avg(Money $first, Money ...$collection): Money
118
    {
119 5
        return $first->add(...$collection)->divide(\func_num_args());
120
    }
121
122
    /**
123
     * Returns a new Money object that represents
124
     * the divided value by the given factor.
125
     *
126
     * @param float|int|string $divisor
127
     *
128
     * @return Money
129
     */
130 16
    public function divide($divisor): Money
131
    {
132 16
        $this->assertOperand($divisor);
133
134 11
        if ($this->calculator->compare((string)$divisor, '0') === 0) {
135 1
            throw new \InvalidArgumentException('Division by zero.');
136
        }
137
138 10
        $quotient = $this->calculator->divide($this->getAmount(), $divisor);
139
        return
140 10
            $this->newInstance($quotient);
0 ignored issues
show
Bug introduced by
It seems like newInstance() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

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

140
            $this->/** @scrutinizer ignore-call */ 
141
                   newInstance($quotient);
Loading history...
141
    }
142
143
    /**
144
     * Checks whether the value represented by this object equals to the other.
145
     *
146
     * @param Money $other
147
     *
148
     * @return bool
149
     */
150 8
    public function equals(Money $other): bool
151
    {
152 8
        return $this->isSameCurrency($other) && $this->getAmount() === $other->amount;
0 ignored issues
show
Bug introduced by
The property amount is declared protected in AlecRabbit\Money\Money and cannot be accessed from this context.
Loading history...
153
    }
154
155
    /**
156
     * @param Money $other
157
     *
158
     * @return bool
159
     */
160 3
    public function greaterThanOrEqual(Money $other): bool
161
    {
162 3
        return $this->compare($other) >= 0;
163
    }
164
165
    /**
166
     * @param Money $other
167
     *
168
     * @return bool
169
     */
170 3
    public function lessThanOrEqual(Money $other): bool
171
    {
172 3
        return $this->compare($other) <= 0;
173
    }
174
175
    /**
176
     * Returns a new Money object that represents
177
     * the multiplied value by the given factor.
178
     *
179
     * @param float|int|string $multiplier
180
     *
181
     * @return Money
182
     */
183 9
    public function multiply($multiplier): Money
184
    {
185 9
        $this->assertOperand($multiplier);
186
187 4
        $product = $this->calculator->multiply($this->getAmount(), $multiplier);
188
189
        return
190 4
            $this->newInstance($product);
191
    }
192
193
    /**
194
     * Returns a new Money object that represents
195
     * the remainder after dividing the value by
196
     * the given factor.
197
     *
198
     * @param Money $divisor
199
     *
200
     * @return Money
201
     */
202 4
    public function mod(Money $divisor): Money
203
    {
204 4
        $this->assertSameCurrency($divisor);
205
206 4
        return new Money($this->calculator->mod($this->getAmount(), $divisor->amount), $this->getCurrency());
0 ignored issues
show
Bug introduced by
The property amount is declared protected in AlecRabbit\Money\Money and cannot be accessed from this context.
Loading history...
207
    }
208
209
    /**
210
     * Allocate the money among N targets.
211
     *
212
     * @param int $n
213
     *
214
     * @param int|null $precision
215
     * @return Money[]
216
     *
217
     */
218 7
    public function allocateTo(int $n, ?int $precision = null): array
219
    {
220 7
        if ($n <= 0) {
221 2
            throw new \InvalidArgumentException('Number to allocateTo must be greater than zero.');
222
        }
223
224 5
        return $this->allocate(array_fill(0, $n, 1), $precision);
225
    }
226
227
    /**
228
     * Allocate the money according to a list of ratios.
229
     *
230
     * @param array $ratios
231
     *
232
     * @param int|null $precision
233
     * @return Money[]
234
     */
235 37
    public function allocate(array $ratios, ?int $precision = null): array
236
    {
237
        return
238 37
            (new AllocationCalculator($this))->compute($ratios, $precision);
239
240
    }
0 ignored issues
show
Coding Style introduced by
Function closing brace must go on the next line following the body; found 1 blank lines before brace
Loading history...
241
242
    /**
243
     * @param Money $money
244
     *
245
     * @return string
246
     */
247 2
    public function ratioOf(Money $money): string
248
    {
249 2
        if ($money->isZero()) {
250 1
            throw new \InvalidArgumentException('Cannot calculate a ratio of zero.');
251
        }
252
253 1
        return $this->calculator->divide($this->getAmount(), $money->amount);
0 ignored issues
show
Bug introduced by
The property amount is declared protected in AlecRabbit\Money\Money and cannot be accessed from this context.
Loading history...
254
    }
255
256
    /**
257
     * Checks if the value represented by this object is zero.
258
     *
259
     * @return bool
260
     */
261 30
    public function isZero(): bool
262
    {
263 30
        return $this->calculator->compare($this->getAmount(), '0') === 0;
264
    }
265
266
    /**
267
     * @return Money
268
     */
269 7
    public function absolute(): Money
270
    {
271 7
        return $this->newInstance($this->calculator->absolute($this->getAmount()));
272
    }
273
274
    /**
275
     * @return Money
276
     */
277 8
    public function negative(): Money
278
    {
279 8
        return $this->newInstance(0)->subtract($this);
280
    }
281
282
    /**
283
     * Returns a new Money object that represents
284
     * the difference of this and an other Money object.
285
     *
286
     * @param Money ...$subtrahends
287
     *
288
     * @return Money
289
     */
290 20
    public function subtract(Money ...$subtrahends): Money
291
    {
292 20
        $amount = $this->getAmount();
293 20
        $calculator = $this->calculator;
294
295 20
        foreach ($subtrahends as $subtrahend) {
296 20
            $this->assertSameCurrency($subtrahend);
297
298 20
            $amount = $calculator->subtract($amount, $subtrahend->amount);
0 ignored issues
show
Bug introduced by
The property amount is declared protected in AlecRabbit\Money\Money and cannot be accessed from this context.
Loading history...
299
        }
300
301 20
        return new Money($amount, $this->getCurrency());
302
    }
303
304
    /**
305
     * Checks if the value represented by this object is not negative.
306
     *
307
     * @return bool
308
     */
309 6
    public function isNotNegative(): bool
310
    {
311
        return
312 6
            !$this->isNegative();
313
    }
314
315
    /**
316
     * Checks if the value represented by this object is negative.
317
     *
318
     * @return bool
319
     */
320 13
    public function isNegative(): bool
321
    {
322 13
        return $this->calculator->compare($this->getAmount(), '0') === -1;
323
    }
324
325
    /**
326
     * Checks if the value represented by this object is not zero.
327
     *
328
     * @return bool
329
     */
330 6
    public function isNotZero(): bool
331
    {
332
        return
333 6
            !$this->isZero();
334
    }
335
336
    /**
337
     * Checks if the value represented by this object is not positive.
338
     *
339
     * @return bool
340
     */
341 17
    public function isNotPositive(): bool
342
    {
343
        return
344 17
            !$this->isPositive();
345
    }
346
347
    /**
348
     * Checks if the value represented by this object is positive.
349
     *
350
     * @return bool
351
     */
352 23
    public function isPositive(): bool
353
    {
354 23
        return $this->calculator->compare($this->getAmount(), '0') === 1;
355
    }
356
357
    /**
358
     * Returns an integer less than, equal to, or greater than zero
359
     * if the value of this object is considered to be respectively
360
     * less than, equal to, or greater than the other.
361
     *
362
     * @param Money $other
363
     *
364
     * @return int
365
     */
366
    abstract public function compare(Money $other): int;
367
368
    /**
369
     * Checks whether a Money has the same Currency as this.
370
     *
371
     * @param Money $other
372
     *
373
     * @return bool
374
     */
375
    abstract public function isSameCurrency(Money $other): bool;
376
377
    /**
378
     * Returns the value represented by this object.
379
     *
380
     * @return string
381
     */
382
    abstract public function getAmount(): string;
383
384
    /**
385
     * Returns the currency of this object.
386
     *
387
     * @return Currency
388
     */
389
    abstract public function getCurrency(): Currency;
390
391
    /**
392
     * Asserts that a Money has the same currency as this.
393
     *
394
     * @param Money $other
395
     *
396
     * @throws \InvalidArgumentException If $other has a different currency
397
     */
398
    abstract protected function assertSameCurrency(Money $other): void;
399
400
    /**
401
     * Asserts that the operand is integer or float.
402
     *
403
     * @param float|int|string|object $operand
404
     *
405
     * @throws \InvalidArgumentException If $operand is neither integer nor float
406
     */
407
    abstract protected function assertOperand($operand): void;
408
409
410
}
411