Completed
Pull Request — master (#20)
by Klochok
14:52
created

ShoppingCart::getDiscount()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 0
cts 2
cp 0
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 0
crap 2
1
<?php
2
3
/*
4
 * Cart module for Yii2
5
 *
6
 * @link      https://github.com/hiqdev/yii2-cart
7
 * @package   yii2-cart
8
 * @license   BSD-3-Clause
9
 * @copyright Copyright (c) 2015-2016, HiQDev (http://hiqdev.com/)
10
 */
11
12
namespace hiqdev\yii2\cart;
13
14
use hipanel\modules\finance\cart\AbstractCartPosition;
15
use Yii;
16
use yii\base\Event;
17
use yz\shoppingcart\CartActionEvent;
18
19
/**
20
 * Class ShoppingCart.
21
 * @property AbstractCartPosition[] $positions
22
 */
23
class ShoppingCart extends \yz\shoppingcart\ShoppingCart
24
{
25
    /**
26
     * @var AbstractCartPosition[]
27
     * TODO make local AbstractCartPosition
28
     */
29
    protected $_positions = [];
30
31
    /**
32
     * The cart module.
33
     */
34
    public $module;
35
36
    /**
37
     * @return integer
38
     */
39 1
    public function getCount(): int
40
    {
41 1
        $count = 0;
42
        foreach ($this->_positions as $position) {
43
            if (!$position->hasParent()) {
44 1
                $count += 1;
45
            }
46 1
        }
47 1
48 1
        return $count;
49
    }
50
51 1
    public function findRelatedFor(CartPositionInterface $parent): ?CartPositionInterface
52
    {
53
        foreach ($this->_positions as $position) {
54 2
            if ($position->hasParent() && $position->parent_id === $parent->getId()) {
55
                return $position;
56 2
            }
57
        }
58
59 2
        return null;
60
    }
61 2
62
    /**
63
     * @return CartPositionInterface[]
64 1
     */
65
    public function getRootPositions(): array
66 1
    {
67
        return array_filter($this->getPositions(), static function (CartPositionInterface $position): bool {
68
            return !$position->hasParent();
69 1
        });
70
    }
71 1
72
    public function getQuantity()
73
    {
74
        $count = 0;
75
        foreach ($this->_positions as $position) {
76
            $count += $position->getQuantity();
77
        }
78
79
        return $count;
80
    }
81
82
    public function getSubtotal()
83
    {
84
        return $this->getCost(false);
85
    }
86
87
    public function getTotal()
88
    {
89
        return $this->getCost(true);
90
    }
91
92
    public function getDiscount()
93
    {
94
        return $this->getTotal() - $this->getSubtotal();
95
    }
96
97
    public function formatCurrency($sum, $currency = null)
98
    {
99
        return $sum !== null ? Yii::$app->formatter->format($sum, ['currency', $currency ?? $this->getCurrency()]) : '--';
100
    }
101
102
    /**
103
     * Sets cart from serialized string
104
     * @param string $serialized
105
     */
106
    public function setSerialized($serialized)
107
    {
108
        try {
109
            parent::setSerialized($serialized);
110
        } catch (\Exception $e) {
111
            Yii::error('Failed to unserlialize cart: ' . $e->getMessage(), __METHOD__);
112
            $this->_positions = [];
113
            $this->saveToSession();
114
        }
115
    }
116
117
    /**
118
     * Checks whether any of cart positions has error in `id` attribute.
119
     * @return boolean
120
     */
121
    public function hasErrors()
122
    {
123
        foreach ($this->_positions as $position) {
124
            if ($position->hasErrors('id')) {
125
                return true;
126
            }
127
        }
128
129
        return false;
130
    }
131
132
    /**
133
     * @param CartPositionInterface[] $positions
134
     */
135
    public function putPositions($positions)
136
    {
137
        foreach ($positions as $position) {
138
            if (isset($this->_positions[$position->getId()])) {
139
                if ($position instanceof DontIncrementQuantityWhenAlreadyInCart) {
140
                    continue;
141
                }
142
                $existingPosition = $this->_positions[$position->getId()];
143
                $existingPosition->setQuantity($existingPosition->getQuantity() + 1);
144
            } else {
145
                if ($position->getQuantity() <= 0) {
146
                    $position->setQuantity(1);
147
                }
148
                $this->_positions[$position->getId()] = $position;
149
            }
150
        }
151
152
        $this->trigger(self::EVENT_CART_CHANGE, new CartActionEvent([
153
            'action' => CartActionEvent::ACTION_POSITION_PUT,
154
        ]));
155
        if ($this->storeInSession)
156
            $this->saveToSession();
157
    }
158
159
    public function getCurrency(): ?string
160
    {
161
        if (!empty($this->_positions)) {
162
            return reset($this->_positions)->currency;
163
        }
164
165
        return Yii::$app->params['currency'];
166
    }
167
168
    /**
169
     * @return array
170
     */
171
    public function getAdditionalLinks(): array
172
    {
173
        $links = [];
174
        $positions = $this->_positions;
175
        if (empty($positions)) {
176
            return $links;
177
        }
178
179
        foreach ($positions as $position) {
180
            $additionalLinks = $position->getAdditionalLinks();
181
            if (!empty($additionalLinks)) {
182
                foreach ($additionalLinks as $link) {
183
                    [$url, $label] = $link;
0 ignored issues
show
Bug introduced by
The variable $url does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
Bug introduced by
The variable $label does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
184
                    if ($url && $label && !isset($links[$url])) {
185
                        $links[$url] = $label;
186
                    }
187
                }
188
            }
189
        }
190
191
        return $links;
192
    }
193
194
    /**
195
     * @var CartActionEvent[]|null
196
     */
197
    private $_accumulatedEvents;
198
    public function trigger($name, Event $event = null)
199
    {
200
        if (is_array($this->_accumulatedEvents)) {
201
            \Yii::info("Shopping cart accumulates event $name");
202
            $this->_accumulatedEvents[] = [$name, $event];
203
        } else {
204
            parent::trigger($name, $event);
205
        }
206
    }
207
208
    /**
209
     * Runs $closure and accumulates all events occurred during $closure run.
210
     * Events get released immediately after a success $closure run.
211
     *
212
     * The method can be used to prevent useless calculations that happen after
213
     * bunch of similar updates on a cart.
214
     *
215
     * @param \Closure $closure
216
     */
217
    public function accumulateEvents(\Closure $closure): void
218
    {
219
        $this->_accumulatedEvents = [];
220
        try {
221
            $closure();
222
            $events = $this->_accumulatedEvents;
223
            $this->_accumulatedEvents = null;
224
            foreach ($events as [$name, $event]) {
225
                \Yii::info("Releases event $name");
0 ignored issues
show
Bug introduced by
The variable $name does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
226
                $this->trigger($name, $event);
0 ignored issues
show
Bug introduced by
The variable $event does not exist. Did you mean $events?

This check looks for variables that are accessed but have not been defined. It raises an issue if it finds another variable that has a similar name.

The variable may have been renamed without also renaming all references.

Loading history...
227
            }
228
        } finally {
229
            $this->_accumulatedEvents = null;
230
        }
231
    }
232
}
233