Completed
Push — master ( f79ff7...908aca )
by Dmitry
15:25 queued 10:35
created

src/tools/Aggregator.php (4 issues)

1
<?php
2
/**
3
 * PHP Billing Library
4
 *
5
 * @link      https://github.com/hiqdev/php-billing
6
 * @package   php-billing
7
 * @license   BSD-3-Clause
8
 * @copyright Copyright (c) 2017-2018, HiQDev (http://hiqdev.com/)
9
 */
10
11
namespace hiqdev\php\billing\tools;
12
13
use hiqdev\php\billing\bill\Bill;
14
use hiqdev\php\billing\bill\BillInterface;
15
use hiqdev\php\billing\charge\ChargeInterface;
16
use hiqdev\php\billing\charge\GeneralizerInterface;
17
use hiqdev\php\units\QuantityInterface;
18
use Money\Money;
19
20
/**
21
 * @author Andrii Vasyliev <[email protected]>
22
 */
23
class Aggregator implements AggregatorInterface
24
{
25
    /**
26
     * @var GeneralizerInterface
27
     */
28
    protected $generalizer;
29
30 1
    public function __construct(GeneralizerInterface $generalizer)
31
    {
32 1
        $this->generalizer = $generalizer;
33 1
    }
34
35
    /**
36
     * Aggregates given Charges to Bills. Then aggregates them again with DB.
37
     * @param ChargeInterface[]|ChargeInterface[][] $charges
38
     * @return BillInterface[]
39
     */
40 1
    public function aggregateCharges(array $charges): array
41
    {
42 1
        $bills = [];
43 1
        foreach ($charges as $charge) {
44 1
            if (is_array($charge)) {
45 1
                $others = $this->aggregateCharges($charge);
46 1
            } elseif ($charge instanceof ChargeInterface) {
47 1
                $others = [$this->generalizer->createBill($charge)];
48
            } else {
49
                var_dump($charge);die;
0 ignored issues
show
Security Debugging Code introduced by Andrii Vasyliev
var_dump($charge) looks like debug code. Are you sure you do not want to remove it?
Loading history...
Bug Best Practice introduced by Andrii Vasyliev
In this branch, the function will implicitly return null which is incompatible with the type-hinted return array. Consider adding a return statement or allowing null as return value.

For hinted functions/methods where all return statements with the correct type are only reachable via conditions, ?null? gets implicitly returned which may be incompatible with the hinted type. Let?s take a look at an example:

interface ReturnsInt {
    public function returnsIntHinted(): int;
}

class MyClass implements ReturnsInt {
    public function returnsIntHinted(): int
    {
        if (foo()) {
            return 123;
        }
        // here: null is implicitly returned
    }
}
Loading history...
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
50
                throw new \Exception('not a Charge given to Aggregator');
0 ignored issues
show
ThrowNode is not reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
51
            }
52
53
            $bills = $this->aggregateBills($bills, $others);
54 1
        }
55
56
        return $bills;
57 1
    }
58
59
    /**
60
     * Aggregate arrays of bills.
61
     * @param BillInterface[] $bills
62
     * @param BillInterface[] $others
63
     * @return BillInterface[]
64
     */
65
    protected function aggregateBills(array $bills, array $others): array
66 1
    {
67
        foreach ($others as $bill) {
68 1
            $uid = $bill->getUniqueString();
69 1
            if (empty($bills[$uid])) {
70 1
                $bills[$uid] = $bill;
71 1
            } else {
72
                $bills[$uid] = $this->aggregateBill($bills[$uid], $bill);
73 1
            }
74
        }
75
76
        return $bills;
77 1
    }
78
79
    /**
80
     * @param BillInterface $first
81
     * @param BillInterface $other
82
     * @return BillInterface
83
     */
84
    protected function aggregateBill(BillInterface $first, BillInterface $other): BillInterface
85 1
    {
86
        return new Bill(
87 1
            $this->aggregateId($first, $other),
88 1
            $first->getType(),
89 1
            $first->getTime(),
90 1
            $this->aggregateSum($first, $other),
91 1
            $this->aggregateQuantity($first, $other),
92 1
            $first->getCustomer(),
93 1
            $first->getTarget(),
94 1
            $first->getPlan(),
95 1
            array_merge($first->getCharges(), $other->getCharges())
96 1
        );
97
    }
98
99
    /**
100
     * @param BillInterface $first
101
     * @param BillInterface $other
102
     * @return string|int|null
103
     */
104
    protected function aggregateId(BillInterface $first, BillInterface $other)
105 1
    {
106
        if ($first->getId() === null) {
107 1
            return $other->getId();
108 1
        }
109
        if ($other->getId() === null) {
110
            return $first->getId();
111
        }
112
        if ($first->getId() === $other->getId()) {
113
            return $other->getId();
114
        }
115
116
        throw new AggregationException('cannot aggregate bills with different IDs');
117
    }
118
119
    /**
120
     * @param BillInterface $first
121
     * @param BillInterface $other
122
     * @param ChargeInterface[] $charges
123
     * @return Money
124
     */
125
    protected function aggregateSum(BillInterface $first, BillInterface $other): Money
126 1
    {
127
        return $first->getSum()->add($other->getSum());
128 1
    }
129
130
    /**
131
     * @param BillInterface $first
132
     * @param BillInterface $other
133
     * @param ChargeInterface[] $charges
134
     * @return QuantityInterface
135
     */
136
    protected function aggregateQuantity(BillInterface $first, BillInterface $other): QuantityInterface
137 1
    {
138
        return $first->getQuantity()->add($other->getQuantity());
139 1
    }
140
}
141