Failed Conditions
Branch experimental/sf (68db07)
by Kentaro
42:17 queued 33:39
created

CartService::loadItems()   B

Complexity

Conditions 5
Paths 3

Size

Total Lines 15
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 30

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 5
eloc 8
nc 3
nop 0
dl 0
loc 15
rs 8.8571
c 2
b 0
f 0
ccs 0
cts 7
cp 0
crap 30
1
<?php
2
3
/*
4
 * This file is part of EC-CUBE
5
 *
6
 * Copyright(c) LOCKON CO.,LTD. All Rights Reserved.
7
 *
8
 * http://www.lockon.co.jp/
9
 *
10
 * For the full copyright and license information, please view the LICENSE
11
 * file that was distributed with this source code.
12
 */
13
14
namespace Eccube\Service;
15
16
use Doctrine\ORM\UnitOfWork;
17
use Eccube\Entity\Cart;
18
use Eccube\Entity\CartItem;
19
use Eccube\Entity\Customer;
20
use Eccube\Entity\ItemHolderInterface;
21
use Eccube\Entity\ProductClass;
22
use Eccube\Repository\CartRepository;
23
use Eccube\Repository\ProductClassRepository;
24
use Eccube\Repository\OrderRepository;
25
use Eccube\Service\Cart\CartItemAllocator;
26
use Eccube\Service\Cart\CartItemComparator;
27
use Eccube\Util\StringUtil;
28
use Symfony\Component\HttpFoundation\Session\SessionInterface;
29
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
30
use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
31
use Doctrine\ORM\EntityManagerInterface;
32
33
class CartService
0 ignored issues
show
introduced by
Missing class doc comment
Loading history...
34
{
35
    /**
36
     * @var Cart[]
37
     */
38
    protected $carts;
39
40
    /**
41
     * @var SessionInterface
42
     */
43
    protected $session;
44
45
    /**
46
     * @var \Doctrine\ORM\EntityManagerInterface
47
     */
48
    protected $entityManager;
49
50
    /**
51
     * @var ItemHolderInterface
52
     *
53
     * @deprecated
54
     */
55
    protected $cart;
56
57
    /**
58
     * @var ProductClassRepository
59
     */
60
    protected $productClassRepository;
61
62
    /**
63
     * @var CartRepository
64
     */
65
    protected $cartRepository;
66
67
    /**
68
     * @var CartItemComparator
69
     */
70
    protected $cartItemComparator;
71
72
    /**
73
     * @var CartItemAllocator
74
     */
75
    protected $cartItemAllocator;
76
77
    /**
78
     * @var OrderHelper
79
     */
80
    protected $orderHelper;
81
82
    /**
83
     * @var OrderRepository
84
     */
85
    protected $orderRepository;
86
87
    /**
88
     * @var TokenStorageInterface
89
     */
90
    protected $tokenStorage;
91
92
    /**
93
     * @var AuthorizationCheckerInterface
94
     */
95
    protected $authorizationChecker;
96
97
    /**
0 ignored issues
show
introduced by
Doc comment for parameter "$cartRepository" missing
Loading history...
introduced by
Doc comment for parameter "$orderRepository" missing
Loading history...
98
     * CartService constructor.
99
     *
100
     * @param SessionInterface $session
0 ignored issues
show
introduced by
Expected 14 spaces after parameter type; 1 found
Loading history...
101
     * @param EntityManagerInterface $entityManager
0 ignored issues
show
introduced by
Expected 8 spaces after parameter type; 1 found
Loading history...
102
     * @param ProductClassRepository $productClassRepository
0 ignored issues
show
introduced by
Expected 8 spaces after parameter type; 1 found
Loading history...
103
     * @param CartItemComparator $cartItemComparator
0 ignored issues
show
introduced by
Expected 12 spaces after parameter type; 1 found
Loading history...
introduced by
Doc comment for parameter $cartItemComparator does not match actual variable name $cartRepository
Loading history...
104
     * @param CartItemAllocator $cartItemAllocator
0 ignored issues
show
introduced by
Expected 13 spaces after parameter type; 1 found
Loading history...
introduced by
Doc comment for parameter $cartItemAllocator does not match actual variable name $cartItemComparator
Loading history...
105
     * @param OrderHelper $orderHelper
0 ignored issues
show
introduced by
Expected 19 spaces after parameter type; 1 found
Loading history...
introduced by
Doc comment for parameter $orderHelper does not match actual variable name $cartItemAllocator
Loading history...
106
     * @param TokenStorageInterface $tokenStorage
0 ignored issues
show
introduced by
Expected 9 spaces after parameter type; 1 found
Loading history...
introduced by
Doc comment for parameter $tokenStorage does not match actual variable name $orderHelper
Loading history...
107
     * @param AuthorizationCheckerInterface $authorizationChecker
0 ignored issues
show
introduced by
Doc comment for parameter $authorizationChecker does not match actual variable name $orderRepository
Loading history...
108
     */
109 171
    public function __construct(
110
        SessionInterface $session,
111
        EntityManagerInterface $entityManager,
112
        ProductClassRepository $productClassRepository,
113
        CartRepository $cartRepository,
114
        CartItemComparator $cartItemComparator,
115
        CartItemAllocator $cartItemAllocator,
116
        OrderHelper $orderHelper,
117
        OrderRepository $orderRepository,
118
        TokenStorageInterface $tokenStorage,
119
        AuthorizationCheckerInterface $authorizationChecker
120
    ) {
121 171
        $this->session = $session;
122 171
        $this->entityManager = $entityManager;
123 171
        $this->productClassRepository = $productClassRepository;
124 171
        $this->cartRepository = $cartRepository;
125 171
        $this->cartItemComparator = $cartItemComparator;
126 171
        $this->cartItemAllocator = $cartItemAllocator;
127 171
        $this->orderHelper = $orderHelper;
128 171
        $this->orderRepository = $orderRepository;
129 171
        $this->tokenStorage = $tokenStorage;
130 171
        $this->authorizationChecker = $authorizationChecker;
131
    }
132
133 131
    public function getCarts()
134
    {
135 131
        if (!empty($this->carts)) {
136 85
            return $this->carts;
137
        }
138
139 131
        $cartKeys = $this->session->get('cart_keys', []);
140 131
        $this->carts = $this->cartRepository->findBy(['cart_key' => $cartKeys], ['id' => 'DESC']);
141
142 131
        return $this->carts;
143
    }
144
145
    /**
146
     * 会員が保持する永続化されたカートと、非会員時のカートをマージする.
147
     *
148
     * @param Customer $Customer
149
     */
150
    public function mergeFromPersistedCart(Customer $Customer)
151
    {
152
        $Carts = $this->cartRepository->findBy(['Customer' => $Customer]);
153
154
        $CartItems = [];
155
        foreach ($Carts as $Cart) {
156
            $CartItems = $this->mergeCartItems($Cart->getCartItems(), $CartItems);
157
        }
158
159
        // セッションにある非会員カートとDBから取得した会員カートをマージする.
160
        $CartItems = $this->mergeAllCartItems($CartItems);
161
        $this->restoreCarts($CartItems);
162
    }
163
164
    /**
165
     * @return ItemHolderInterface|Cart
166
     */
167 65
    public function getCart()
168
    {
169 65
        $Carts = $this->getCarts();
170
171 65
        if (empty($Carts)) {
172 4
            return null;
173
        }
174
175 63
        return current($Carts);
176
    }
177
178
    /**
179
     * @param CartItem[] $cartItems
180
     *
181
     * @return CartItem[]
182
     */
183 86
    protected function mergeAllCartItems($cartItems = [])
184
    {
185
        /** @var CartItem[] $allCartItems */
186 86
        $allCartItems = [];
187
188 86
        foreach ($this->getCarts() as $Cart) {
189 39
            $allCartItems = $this->mergeCartItems($Cart->getCartItems(), $allCartItems);
190
        }
191
192 86
        return $this->mergeCartItems($cartItems, $allCartItems);
193
    }
194
195
    /**
196
     * @param $cartItems
197
     * @param $allCartItems
198
     *
199
     * @return array
200
     */
201 86
    protected function mergeCartItems($cartItems, $allCartItems)
202
    {
203 86
        foreach ($cartItems as $item) {
204 85
            $itemExists = false;
205 85
            foreach ($allCartItems as $itemInArray) {
206
                // 同じ明細があればマージする
207 38
                if ($this->cartItemComparator->compare($item, $itemInArray)) {
208 36
                    $itemInArray->setQuantity($itemInArray->getQuantity() + $item->getQuantity());
209 36
                    $itemExists = true;
210 38
                    break;
211
                }
212
            }
213 85
            if (!$itemExists) {
214 85
                $allCartItems[] = $item;
215
            }
216
        }
217
218 86
        return $allCartItems;
219
    }
220
221 86
    protected function restoreCarts($cartItems)
222
    {
223 86
        if (empty($cartItems)) {
224 2
            foreach ($this->getCarts() as $Cart) {
225 1
                foreach ($Cart->getCartItems() as $i) {
226 1
                    $this->entityManager->remove($i);
227 1
                    $this->entityManager->flush($i);
0 ignored issues
show
Unused Code introduced by
The call to EntityManagerInterface::flush() has too many arguments starting with $i.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
228
                }
229 1
                $this->entityManager->remove($Cart);
230 1
                $this->entityManager->flush($Cart);
0 ignored issues
show
Unused Code introduced by
The call to EntityManagerInterface::flush() has too many arguments starting with $Cart.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
231
            }
232 2
            $this->carts = [];
233
        }
234
235
        /** @var Cart[] $Carts */
236 86
        $Carts = [];
237
238 86
        foreach ($cartItems as $item) {
239 85
            $allocatedId = $this->cartItemAllocator->allocate($item);
240 85
            $cartKey = $this->createCartKey($allocatedId, $this->getUser());
241
242 85
            if (isset($Carts[$cartKey])) {
243 16
                $Cart = $Carts[$cartKey];
244 16
                $Cart->addCartItem($item);
245 16
                $item->setCart($Cart);
246
            } else {
247
                /** @var Cart $Cart */
248 85
                $Cart = $this->cartRepository->findOneBy(['cart_key' => $cartKey]);
249 85
                if ($Cart) {
250 34
                    foreach ($Cart->getCartItems() as $i) {
251 34
                        $this->entityManager->remove($i);
252 34
                        $this->entityManager->flush($i);
0 ignored issues
show
Unused Code introduced by
The call to EntityManagerInterface::flush() has too many arguments starting with $i.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
253
                    }
254 34
                    $this->entityManager->remove($Cart);
255 34
                    $this->entityManager->flush($Cart);
0 ignored issues
show
Unused Code introduced by
The call to EntityManagerInterface::flush() has too many arguments starting with $Cart.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
256
                }
257 85
                $Cart = new Cart();
258 85
                $Cart->setCartKey($cartKey);
259 85
                $Cart->addCartItem($item);
260 85
                $item->setCart($Cart);
261 85
                $Carts[$cartKey] = $Cart;
262
            }
263
        }
264
265 86
        $this->carts = array_values($Carts);
266
    }
267
268
    /**
0 ignored issues
show
introduced by
Doc comment for parameter "$ProductClass" missing
Loading history...
introduced by
Doc comment for parameter "$quantity" missing
Loading history...
269
     * カートに商品を追加します.
270
     *
271
     * @param $ProductClass ProductClass 商品規格
0 ignored issues
show
introduced by
Missing parameter name
Loading history...
272
     * @param $quantity int 数量
0 ignored issues
show
introduced by
Missing parameter name
Loading history...
273
     *
274
     * @return bool 商品を追加できた場合はtrue
275
     */
276 85
    public function addProduct($ProductClass, $quantity = 1)
0 ignored issues
show
introduced by
Declare public methods first, then protected ones and finally private ones
Loading history...
277
    {
278 85 View Code Duplication
        if (!$ProductClass instanceof ProductClass) {
279 45
            $ProductClassId = $ProductClass;
280 45
            $ProductClass = $this->entityManager
281 45
                ->getRepository(ProductClass::class)
282 45
                ->find($ProductClassId);
283 45
            if (is_null($ProductClass)) {
284
                return false;
285
            }
286
        }
287
288 85
        $ClassCategory1 = $ProductClass->getClassCategory1();
289 85
        if ($ClassCategory1 && !$ClassCategory1->isVisible()) {
290
            return false;
291
        }
292 85
        $ClassCategory2 = $ProductClass->getClassCategory2();
293 85
        if ($ClassCategory2 && !$ClassCategory2->isVisible()) {
294
            return false;
295
        }
296
297 85
        $newItem = new CartItem();
298 85
        $newItem->setQuantity($quantity);
299 85
        $newItem->setPrice($ProductClass->getPrice02IncTax());
300 85
        $newItem->setProductClass($ProductClass);
301
302 85
        $allCartItems = $this->mergeAllCartItems([$newItem]);
303 85
        $this->restoreCarts($allCartItems);
304
305 85
        return true;
306
    }
307
308 2
    public function removeProduct($ProductClass)
309
    {
310 2 View Code Duplication
        if (!$ProductClass instanceof ProductClass) {
311 1
            $ProductClassId = $ProductClass;
312 1
            $ProductClass = $this->entityManager
313 1
                ->getRepository(ProductClass::class)
314 1
                ->find($ProductClassId);
315 1
            if (is_null($ProductClass)) {
316
                return false;
317
            }
318
        }
319
320 2
        $removeItem = new CartItem();
321 2
        $removeItem->setPrice($ProductClass->getPrice02IncTax());
322 2
        $removeItem->setProductClass($ProductClass);
323
324 2
        $allCartItems = $this->mergeAllCartItems();
325 2
        $foundIndex = -1;
326 2
        foreach ($allCartItems as $index => $itemInCart) {
327 1
            if ($this->cartItemComparator->compare($itemInCart, $removeItem)) {
328 1
                $foundIndex = $index;
329 1
                break;
330
            }
331
        }
332
333 2
        array_splice($allCartItems, $foundIndex, 1);
334 2
        $this->restoreCarts($allCartItems);
335
336 2
        return true;
337
    }
338
339 80
    public function save()
340
    {
341 80
        $cartKeys = [];
342 80
        foreach ($this->carts as $Cart) {
343 77
            $Cart->setCustomer($this->getUser());
344 77
            $this->entityManager->persist($Cart);
345 77
            foreach ($Cart->getCartItems() as $item) {
346 77
                $this->entityManager->persist($item);
347 77
                $this->entityManager->flush($item);
0 ignored issues
show
Unused Code introduced by
The call to EntityManagerInterface::flush() has too many arguments starting with $item.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
348
            }
349 77
            $this->entityManager->flush($Cart);
0 ignored issues
show
Unused Code introduced by
The call to EntityManagerInterface::flush() has too many arguments starting with $Cart.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
350 77
            $cartKeys[] = $Cart->getCartKey();
351
        }
352
353 80
        $this->session->set('cart_keys', $cartKeys);
354
355 80
        return;
356
    }
357
358
    /**
359
     * @param  string $pre_order_id
360
     *
361
     * @return \Eccube\Service\CartService
362
     */
363 52
    public function setPreOrderId($pre_order_id)
364
    {
365 52
        $this->getCart()->setPreOrderId($pre_order_id);
366
367 52
        return $this;
368
    }
369
370
    /**
371
     * @return string
372
     */
373 51
    public function getPreOrderId()
374
    {
375 51
        return $this->getCart()->getPreOrderId();
376
    }
377
378
    /**
379
     * @return \Eccube\Service\CartService
380
     */
381 10
    public function clear()
382
    {
383 10
        $Carts = $this->getCarts();
384 10
        $removed = array_splice($Carts, 0, 1);
385 10
        if (!empty($removed)) {
386 8
            if (UnitOfWork::STATE_MANAGED === $this->entityManager->getUnitOfWork()->getEntityState($removed[0])) {
387 7
                $this->entityManager->remove($removed[0]);
388 7
                $this->entityManager->flush($removed[0]);
0 ignored issues
show
Unused Code introduced by
The call to EntityManagerInterface::flush() has too many arguments starting with $removed[0].

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
389
            }
390
        }
391 10
        $this->carts = $Carts;
392
393 10
        $cartKeys = [];
394 10
        foreach ($Carts as $Cart) {
395
            $cartKeys[] = $Cart->getCartKey();
396
        }
397
398 10
        $this->session->set('cart_keys', $cartKeys);
399
400 10
        return $this;
401
    }
402
403
    /**
404
     * @param CartItemComparator $cartItemComparator
405
     */
406 1
    public function setCartItemComparator($cartItemComparator)
407
    {
408 1
        $this->cartItemComparator = $cartItemComparator;
409
    }
410
411
    /**
412
     * 指定したインデックスにあるカートを優先にする
413
     *
414
     * @param int $index カートのインデックス
415
     */
416 53
    public function setPrimary($index = 0)
417
    {
418 53
        $Carts = $this->getCarts();
419 53
        $primary = $Carts[$index];
420 53
        $prev = $Carts[0];
421 53
        array_splice($Carts, 0, 1, [$primary]);
422 53
        array_splice($Carts, $index, 1, [$prev]);
423 53
        $this->carts = $Carts;
424 53
        $this->save();
425
    }
426
427 85
    protected function getUser()
428
    {
429 85
        if (null === $token = $this->tokenStorage->getToken()) {
430 10
            return;
431
        }
432
433 75
        if (!is_object($user = $token->getUser())) {
434
            // e.g. anonymous authentication
435 25
            return;
436
        }
437
438 50
        return $user;
439
    }
440
441 85
    protected function createCartKey($allocatedId, Customer $Customer = null)
442
    {
443 85
        if ($Customer instanceof Customer) {
444 50
            return $Customer->getId().'_'.$allocatedId;
445
        }
446
447 35
        if ($this->session->has('cart_key_prefix')) {
448 17
            return $this->session->get('cart_key_prefix').'_'.$allocatedId;
449
        }
450
451
        do {
452 35
            $random = StringUtil::random(32);
453 35
            $cartKey = $random.'_'.$allocatedId;
454 35
            $Cart = $this->cartRepository->findOneBy(['cart_key' => $cartKey]);
455 35
        } while ($Cart);
456
457 35
        $this->session->set('cart_key_prefix', $random);
458
459 35
        return $cartKey;
460
    }
461
}
462