Completed
Push — master ( 7d6821...1d6bc5 )
by Dmitry
10:57
created

ShoppingCart::findRelatedFor()   A

Complexity

Conditions 4
Paths 3

Size

Total Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 4

Importance

Changes 0
Metric Value
dl 0
loc 10
c 0
b 0
f 0
ccs 4
cts 4
cp 1
rs 9.9332
cc 4
nc 3
nop 1
crap 4
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 hiqdev\yii2\cart\behaviors\EnsureDeleteRelatedPosition;
16
use Yii;
17
use yii\base\Event;
18
use yz\shoppingcart\CartActionEvent;
19
20
/**
21
 * Class ShoppingCart.
22
 * @property AbstractCartPosition[] $positions
23
 */
24
class ShoppingCart extends \yz\shoppingcart\ShoppingCart
25
{
26
    /**
27
     * @var AbstractCartPosition[]
28
     * TODO make local AbstractCartPosition
29
     */
30
    protected $_positions = [];
31
32
    /**
33
     * The cart module.
34
     */
35
    public $module;
36
37
    public function behaviors()
38
    {
39 1
        return [
40
            [
41 1
                'class' => EnsureDeleteRelatedPosition::class,
42
            ]
43
        ];
44 1
    }
45
46 1
    /**
47 1
     * @return integer
48 1
     */
49
    public function getCount(): int
50
    {
51 1
        $count = 0;
52
        foreach ($this->_positions as $position) {
53
            if (!$position->hasParent()) {
54 2
                $count += 1;
55
            }
56 2
        }
57
58
        return $count;
59 2
    }
60
61 2
    public function findRelatedFor(CartPositionInterface $parent): ?CartPositionInterface
62
    {
63
        foreach ($this->_positions as $position) {
64 1
            if ($position->hasParent() && $position->parent_id === $parent->getId()) {
65
                return $position;
66 1
            }
67
        }
68
69 1
        return null;
70
    }
71 1
72
    /**
73
     * @return CartPositionInterface[]
74
     */
75
    public function getRootPositions(): array
76
    {
77
        return array_filter($this->getPositions(), static function (CartPositionInterface $position): bool {
78
            return !$position->hasParent();
79
        });
80
    }
81
82
    public function getQuantity()
83
    {
84
        $count = 0;
85
        foreach ($this->_positions as $position) {
86
            $count += $position->getQuantity();
87
        }
88
89
        return $count;
90
    }
91
92
    public function getSubtotal()
93
    {
94
        return $this->getCost(false);
95
    }
96
97
    public function getTotal()
98
    {
99
        return $this->getCost(true);
100
    }
101
102
    public function getDiscount()
103
    {
104
        return $this->getTotal() - $this->getSubtotal();
105
    }
106
107
    public function formatCurrency($sum, $currency = null)
108
    {
109
        return $sum !== null ? Yii::$app->formatter->format($sum, ['currency', $currency ?? $this->getCurrency()]) : '--';
110
    }
111
112
    /**
113
     * Sets cart from serialized string
114
     * @param string $serialized
115
     */
116
    public function setSerialized($serialized)
117
    {
118
        try {
119
            parent::setSerialized($serialized);
120
        } catch (\Exception $e) {
121
            Yii::error('Failed to unserlialize cart: ' . $e->getMessage(), __METHOD__);
122
            $this->_positions = [];
123
            $this->saveToSession();
124
        }
125
    }
126
127
    /**
128
     * Checks whether any of cart positions has error in `id` attribute.
129
     * @return boolean
130
     */
131
    public function hasErrors()
132
    {
133
        foreach ($this->_positions as $position) {
134
            if ($position->hasErrors('id')) {
135
                return true;
136
            }
137
        }
138
139
        return false;
140
    }
141
142
    /**
143
     * @param CartPositionInterface[] $positions
144
     */
145
    public function putPositions($positions)
146
    {
147
        foreach ($positions as $position) {
148
            if (isset($this->_positions[$position->getId()])) {
149
                if ($position instanceof DontIncrementQuantityWhenAlreadyInCart) {
150
                    continue;
151
                }
152
                $existingPosition = $this->_positions[$position->getId()];
153
                $existingPosition->setQuantity($existingPosition->getQuantity() + 1);
154
            } else {
155
                if ($position->getQuantity() <= 0) {
156
                    $position->setQuantity(1);
157
                }
158
                $this->_positions[$position->getId()] = $position;
159
            }
160
        }
161
162
        $this->trigger(self::EVENT_CART_CHANGE, new CartActionEvent([
163
            'action' => CartActionEvent::ACTION_POSITION_PUT,
164
        ]));
165
        if ($this->storeInSession)
166
            $this->saveToSession();
167
    }
168
169
    public function getCurrency(): ?string
170
    {
171
        if (!empty($this->_positions)) {
172
            return reset($this->_positions)->currency;
173
        }
174
175
        return Yii::$app->params['currency'];
176
    }
177
178
    /**
179
     * @return array
180
     */
181
    public function getAdditionalLinks(): array
182
    {
183
        $links = [];
184
        $positions = $this->_positions;
185
        if (empty($positions)) {
186
            return $links;
187
        }
188
189
        foreach ($positions as $position) {
190
            $additionalLinks = $position->getAdditionalLinks();
191
            if (!empty($additionalLinks)) {
192
                foreach ($additionalLinks as $link) {
193
                    [$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...
194
                    if ($url && $label && !isset($links[$url])) {
195
                        $links[$url] = $label;
196
                    }
197
                }
198
            }
199
        }
200
201
        return $links;
202
    }
203
204
    /**
205
     * @var CartActionEvent[]|null
206
     */
207
    private $_accumulatedEvents;
208
    public function trigger($name, Event $event = null)
209
    {
210
        if (is_array($this->_accumulatedEvents)) {
211
            \Yii::info("Shopping cart accumulates event $name");
212
            $this->_accumulatedEvents[] = [$name, $event];
213
        } else {
214
            parent::trigger($name, $event);
215
        }
216
    }
217
218
    /**
219
     * Runs $closure and accumulates all events occurred during $closure run.
220
     * Events get released immediately after a success $closure run.
221
     *
222
     * The method can be used to prevent useless calculations that happen after
223
     * bunch of similar updates on a cart.
224
     *
225
     * @param \Closure $closure
226
     */
227
    public function accumulateEvents(\Closure $closure): void
228
    {
229
        $this->_accumulatedEvents = [];
230
        try {
231
            $closure();
232
            $events = $this->_accumulatedEvents;
233
            $this->_accumulatedEvents = null;
234
            foreach ($events as [$name, $event]) {
235
                \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...
236
                $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...
237
            }
238
        } finally {
239
            $this->_accumulatedEvents = null;
240
        }
241
    }
242
}
243