Completed
Pull Request — experimental/sf (#3408)
by
unknown
129:59 queued 121:08
created

CartService::getCarts()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 11

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 2

Importance

Changes 0
Metric Value
cc 2
nc 2
nop 0
dl 0
loc 11
ccs 6
cts 6
cp 1
crap 2
rs 9.9
c 0
b 0
f 0
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 173
    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 173
        $this->session = $session;
122 173
        $this->entityManager = $entityManager;
123 173
        $this->productClassRepository = $productClassRepository;
124 173
        $this->cartRepository = $cartRepository;
125 173
        $this->cartItemComparator = $cartItemComparator;
126 173
        $this->cartItemAllocator = $cartItemAllocator;
127 173
        $this->orderHelper = $orderHelper;
128 173
        $this->orderRepository = $orderRepository;
129 173
        $this->tokenStorage = $tokenStorage;
130 173
        $this->authorizationChecker = $authorizationChecker;
131
    }
132
133 130
    public function getCarts()
134
    {
135 130
        if (!empty($this->carts)) {
136 82
            return $this->carts;
137
        }
138
139 130
        $cartKeys = $this->session->get('cart_keys', []);
140 130
        $this->carts = $this->cartRepository->findBy(['cart_key' => $cartKeys], ['id' => 'DESC']);
141
142 130
        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
        $cartKeys = $this->session->get('cart_keys', []);
170 65
        foreach ($cartKeys as $cartKey) {
171 56
            $this->carts[] = $this->cartRepository->findOneBy(['cart_key' => $cartKey]);
172
        }
173
174 65
        if (empty($this->carts)) {
175 2
            return null;
176
        }
177
178 63
        return current($this->carts);
179
    }
180
181
    /**
182
     * @param CartItem[] $cartItems
183
     *
184
     * @return CartItem[]
185
     */
186 87
    protected function mergeAllCartItems($cartItems = [])
187
    {
188
        /** @var CartItem[] $allCartItems */
189 87
        $allCartItems = [];
190
191 87
        foreach ($this->getCarts() as $Cart) {
192 39
            $allCartItems = $this->mergeCartItems($Cart->getCartItems(), $allCartItems);
193
        }
194
195 87
        return $this->mergeCartItems($cartItems, $allCartItems);
196
    }
197
198
    /**
199
     * @param $cartItems
200
     * @param $allCartItems
201
     *
202
     * @return array
203
     */
204 87
    protected function mergeCartItems($cartItems, $allCartItems)
205
    {
206 87
        foreach ($cartItems as $item) {
207 86
            $itemExists = false;
208 86
            foreach ($allCartItems as $itemInArray) {
209
                // 同じ明細があればマージする
210 38
                if ($this->cartItemComparator->compare($item, $itemInArray)) {
211 36
                    $itemInArray->setQuantity($itemInArray->getQuantity() + $item->getQuantity());
212 36
                    $itemExists = true;
213 38
                    break;
214
                }
215
            }
216 86
            if (!$itemExists) {
217 86
                $allCartItems[] = $item;
218
            }
219
        }
220
221 87
        return $allCartItems;
222
    }
223
224 87
    protected function restoreCarts($cartItems)
225
    {
226 87
        if (empty($cartItems)) {
227 2
            foreach ($this->getCarts() as $Cart) {
228 1
                foreach ($Cart->getCartItems() as $i) {
229 1
                    $this->entityManager->remove($i);
230 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...
231
                }
232 1
                $this->entityManager->remove($Cart);
233 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...
234
            }
235 2
            $this->carts = [];
236
        }
237
238
        /** @var Cart[] $Carts */
239 87
        $Carts = [];
240
241 87
        foreach ($cartItems as $item) {
242 86
            $allocatedId = $this->cartItemAllocator->allocate($item);
243 86
            $cartKey = $this->createCartKey($allocatedId, $this->getUser());
244
245 86
            if (isset($Carts[$cartKey])) {
246 16
                $Cart = $Carts[$cartKey];
247 16
                $Cart->addCartItem($item);
248 16
                $item->setCart($Cart);
249
            } else {
250
                /** @var Cart $Cart */
251 86
                $Cart = $this->cartRepository->findOneBy(['cart_key' => $cartKey]);
252 86
                if ($Cart) {
253 34
                    foreach ($Cart->getCartItems() as $i) {
254 34
                        $this->entityManager->remove($i);
255 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...
256
                    }
257 34
                    $this->entityManager->remove($Cart);
258 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...
259
                }
260 86
                $Cart = new Cart();
261 86
                $Cart->setCartKey($cartKey);
262 86
                $Cart->addCartItem($item);
263 86
                $item->setCart($Cart);
264 86
                $Carts[$cartKey] = $Cart;
265
            }
266
        }
267
268 87
        $this->carts = array_values($Carts);
269
    }
270
271
    /**
0 ignored issues
show
introduced by
Doc comment for parameter "$ProductClass" missing
Loading history...
introduced by
Doc comment for parameter "$quantity" missing
Loading history...
272
     * カートに商品を追加します.
273
     *
274
     * @param $ProductClass ProductClass 商品規格
0 ignored issues
show
introduced by
Missing parameter name
Loading history...
275
     * @param $quantity int 数量
0 ignored issues
show
introduced by
Missing parameter name
Loading history...
276
     *
277
     * @return bool 商品を追加できた場合はtrue
278
     */
279 86
    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...
280
    {
281 86 View Code Duplication
        if (!$ProductClass instanceof ProductClass) {
282 45
            $ProductClassId = $ProductClass;
283 45
            $ProductClass = $this->entityManager
284 45
                ->getRepository(ProductClass::class)
285 45
                ->find($ProductClassId);
286 45
            if (is_null($ProductClass)) {
287
                return false;
288
            }
289
        }
290
291 86
        $ClassCategory1 = $ProductClass->getClassCategory1();
292 86
        if ($ClassCategory1 && !$ClassCategory1->isVisible()) {
293
            return false;
294
        }
295 86
        $ClassCategory2 = $ProductClass->getClassCategory2();
296 86
        if ($ClassCategory2 && !$ClassCategory2->isVisible()) {
297
            return false;
298
        }
299
300 86
        $newItem = new CartItem();
301 86
        $newItem->setQuantity($quantity);
302 86
        $newItem->setPrice($ProductClass->getPrice02IncTax());
303 86
        $newItem->setProductClass($ProductClass);
304
305 86
        $allCartItems = $this->mergeAllCartItems([$newItem]);
306 86
        $this->restoreCarts($allCartItems);
307
308 86
        return true;
309
    }
310
311 2
    public function removeProduct($ProductClass)
312
    {
313 2 View Code Duplication
        if (!$ProductClass instanceof ProductClass) {
314 1
            $ProductClassId = $ProductClass;
315 1
            $ProductClass = $this->entityManager
316 1
                ->getRepository(ProductClass::class)
317 1
                ->find($ProductClassId);
318 1
            if (is_null($ProductClass)) {
319
                return false;
320
            }
321
        }
322
323 2
        $removeItem = new CartItem();
324 2
        $removeItem->setPrice($ProductClass->getPrice02IncTax());
325 2
        $removeItem->setProductClass($ProductClass);
326
327 2
        $allCartItems = $this->mergeAllCartItems();
328 2
        $foundIndex = -1;
329 2
        foreach ($allCartItems as $index => $itemInCart) {
330 1
            if ($this->cartItemComparator->compare($itemInCart, $removeItem)) {
331 1
                $foundIndex = $index;
332 1
                break;
333
            }
334
        }
335
336 2
        array_splice($allCartItems, $foundIndex, 1);
337 2
        $this->restoreCarts($allCartItems);
338
339 2
        return true;
340
    }
341
342 80
    public function save()
343
    {
344 80
        $cartKeys = [];
345 80
        foreach ($this->carts as $Cart) {
346 78
            $Cart->setCustomer($this->getUser());
347 78
            $this->entityManager->persist($Cart);
348 78
            foreach ($Cart->getCartItems() as $item) {
349 78
                $this->entityManager->persist($item);
350 78
                $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...
351
            }
352 78
            $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...
353 78
            $cartKeys[] = $Cart->getCartKey();
354
        }
355
356 80
        $this->session->set('cart_keys', $cartKeys);
357
358 80
        return;
0 ignored issues
show
Coding Style introduced by
Empty return statement not required here
Loading history...
359
    }
360
361
    /**
362
     * @param  string $pre_order_id
363
     *
364
     * @return \Eccube\Service\CartService
365
     */
366 52
    public function setPreOrderId($pre_order_id)
367
    {
368 52
        $this->getCart()->setPreOrderId($pre_order_id);
369
370 52
        return $this;
371
    }
372
373
    /**
374
     * @return string
375
     */
376 51
    public function getPreOrderId()
377
    {
378 51
        return $this->getCart()->getPreOrderId();
379
    }
380
381
    /**
382
     * @return \Eccube\Service\CartService
383
     */
384 10
    public function clear()
385
    {
386 10
        $Carts = $this->getCarts();
387 10
        if (!empty($Carts)) {
388 8
            $removed = array_shift($Carts);
389 8
            if ($removed && UnitOfWork::STATE_MANAGED === $this->entityManager->getUnitOfWork()->getEntityState($removed)) {
390 7
                $this->entityManager->remove($removed);
391 7
                $this->entityManager->flush($removed);
0 ignored issues
show
Unused Code introduced by
The call to EntityManagerInterface::flush() has too many arguments starting with $removed.

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