Completed
Push — master ( 25e257...c0f64f )
by Dmitry
03:06
created

FullCombination   A

Complexity

Total Complexity 26

Size/Duplication

Total Lines 143
Duplicated Lines 0 %

Test Coverage

Coverage 6.06%

Importance

Changes 0
Metric Value
eloc 63
dl 0
loc 143
ccs 4
cts 66
cp 0.0606
rs 10
c 0
b 0
f 0
wmc 26

5 Methods

Rating   Name   Duplication   Size   Complexity  
C modifyCharge() 0 46 13
A unique() 0 15 3
B chargesSum() 0 40 7
A __construct() 0 4 1
A isSuitable() 0 3 2
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\charge\modifiers;
12
13
use hiqdev\php\billing\action\ActionInterface;
14
use hiqdev\php\billing\charge\Charge;
15
use hiqdev\php\billing\charge\ChargeInterface;
16
use hiqdev\php\billing\charge\ChargeModifier;
17
18
/**
19
 * Class FullCombination combines charges from all formulas from $left and $right parts of condition
20
 *
21
 * @author Dmytro Naumenko <[email protected]>
22
 */
23
class FullCombination implements ChargeModifier
24
{
25
    /**
26
     * @var ChargeModifier
27
     */
28
    protected $left;
29
    /**
30
     * @var ChargeModifier
31
     */
32
    protected $right;
33
34 1
    public function __construct(ChargeModifier $left, ChargeModifier $right)
35
    {
36 1
        $this->left = $left;
37 1
        $this->right = $right;
38 1
    }
39
40
    /**
41
     * {@inheritdoc}
42
     */
43
    public function modifyCharge(?ChargeInterface $charge, ActionInterface $action): array
44
    {
45
        $leftCharges = [$charge];
46
        $rightCharges = [$charge];
47
48
        if ($this->left->isSuitable($charge, $action)) {
49
            $leftCharges = $this->left->modifyCharge($charge, $action);
50
            if ($charge && empty($leftCharges)) {
51
                return []; // If there was at least one charge, but it disappeared – modifier does not want this charge to happen. Stop.
52
            }
53
        }
54
55
        /** @var Charge $leftTotal */
56
        /** @var Charge $charge */
57
        $leftTotal = $this->chargesSum($charge, $leftCharges);
58
        if ($this->right->isSuitable($leftTotal, $action)) {
59
            $dirtyRightCharges = $this->right->modifyCharge($leftTotal, $action);
60
            if ($leftTotal && empty($dirtyRightCharges)) {
61
                return []; // If there was a charge, but it disappeared – modifier does not want this charge to happen. Stop.
62
            }
63
64
            // Drop $leftTotal from $rightCharges array
65
            $rightCharges = array_filter($dirtyRightCharges, function (ChargeInterface $charge) use ($leftTotal) {
66
                return $charge !== $leftTotal;
67
            });
68
69
            if (\count($rightCharges) === \count($dirtyRightCharges)) { // Original $leftTotal was not returned
70
                return $rightCharges;
71
            }
72
        }
73
74
        if ($charge && $leftTotal) {
0 ignored issues
show
introduced by
$leftTotal is of type hiqdev\php\billing\charge\ChargeInterface, thus it always evaluated to true.
Loading history...
75
            // If we had charge and left hand total charge – pass comments and events that were probably generated in left total
76
            if ($leftTotal->getComment()) {
77
                $charge->setComment($leftTotal->getComment());
78
            }
79
80
            $events = $leftTotal->releaseEvents();
0 ignored issues
show
Bug introduced by
The method releaseEvents() does not exist on hiqdev\php\billing\charge\ChargeInterface. Since it exists in all sub-types, consider adding an abstract or default implementation to hiqdev\php\billing\charge\ChargeInterface. ( Ignorable by Annotation )

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

80
            /** @scrutinizer ignore-call */ 
81
            $events = $leftTotal->releaseEvents();
Loading history...
81
            if (!empty($events)) {
82
                foreach ($events as $event) {
83
                    $charge->recordThat($event);
84
                }
85
            }
86
        }
87
88
        return $this->unique(array_merge($leftCharges, $rightCharges));
89
    }
90
91
    /**
92
     * {@inheritdoc}
93
     */
94
    public function isSuitable(?ChargeInterface $charge, ActionInterface $action): bool
95
    {
96
        return $this->left->isSuitable($charge, $action) || $this->right->isSuitable($charge, $action);
97
    }
98
99
    /**
100
     * @param ChargeInterface[] $charges
101
     * @return ChargeInterface[] unique charges
102
     */
103
    private function unique(array $charges): array
104
    {
105
        $hashes = [];
106
        $result = [];
107
108
        foreach ($charges as $charge) {
109
            $hash = spl_object_hash($charge);
110
            if (isset($hashes[$hash])) {
111
                continue;
112
            }
113
            $hashes[$hash] = true;
114
            $result[] = $charge;
115
        }
116
117
        return $result;
118
    }
119
120
    /**
121
     * @param ChargeInterface $originalCharge
122
     * @param ChargeInterface[] $producedCharges
123
     * @return ChargeInterface|null
124
     * @throws \Exception
125
     */
126
    private function chargesSum(?ChargeInterface $originalCharge, array $producedCharges): ?ChargeInterface
127
    {
128
        if ($originalCharge === null) {
129
            return null;
130
        }
131
132
        $sum = $originalCharge->getSum();
133
134
        $additionalCharges = [];
135
        foreach ($producedCharges as $charge) {
136
            if ($originalCharge === $charge) {
137
                continue;
138
            }
139
140
            $additionalCharges[] = $charge;
141
            $sum = $sum->add($charge->getSum());
142
        }
143
144
        if (empty($additionalCharges)) {
145
            return $originalCharge;
146
        }
147
148
        $tempCharge = new Charge(
149
            $originalCharge->getId(),
150
            $originalCharge->getType(),
151
            $originalCharge->getTarget(),
152
            $originalCharge->getAction(),
153
            $originalCharge->getPrice(),
154
            $originalCharge->getUsage(),
155
            $sum,
156
            $originalCharge->getBill()
0 ignored issues
show
Bug introduced by
The method getBill() does not exist on hiqdev\php\billing\charge\ChargeInterface. Since it exists in all sub-types, consider adding an abstract or default implementation to hiqdev\php\billing\charge\ChargeInterface. ( Ignorable by Annotation )

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

156
            $originalCharge->/** @scrutinizer ignore-call */ 
157
                             getBill()
Loading history...
157
        );
158
        if ($originalCharge->getComment() !== null) {
159
            $tempCharge->setComment($originalCharge->getComment());
160
        }
161
        if ($originalCharge->getParent() !== null) {
162
            $tempCharge->setParent($originalCharge->getParent());
163
        }
164
165
        return $tempCharge;
166
    }
167
}
168