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\EntityManagerInterface; |
17
|
|
|
use Doctrine\ORM\UnitOfWork; |
18
|
|
|
use Eccube\Entity\Cart; |
19
|
|
|
use Eccube\Entity\CartItem; |
20
|
|
|
use Eccube\Entity\Customer; |
21
|
|
|
use Eccube\Entity\ItemHolderInterface; |
22
|
|
|
use Eccube\Entity\ProductClass; |
23
|
|
|
use Eccube\Repository\CartRepository; |
24
|
|
|
use Eccube\Repository\OrderRepository; |
25
|
|
|
use Eccube\Repository\ProductClassRepository; |
26
|
|
|
use Eccube\Service\Cart\CartItemAllocator; |
27
|
|
|
use Eccube\Service\Cart\CartItemComparator; |
28
|
|
|
use Eccube\Util\StringUtil; |
29
|
|
|
use Symfony\Component\HttpFoundation\Session\SessionInterface; |
30
|
|
|
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; |
31
|
|
|
use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface; |
32
|
|
|
|
33
|
|
|
class CartService |
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
|
|
|
/** |
98
|
|
|
* CartService constructor. |
99
|
|
|
* |
100
|
|
|
* @param SessionInterface $session |
101
|
|
|
* @param EntityManagerInterface $entityManager |
102
|
|
|
* @param ProductClassRepository $productClassRepository |
103
|
|
|
* @param CartItemComparator $cartItemComparator |
104
|
|
|
* @param CartItemAllocator $cartItemAllocator |
105
|
|
|
* @param OrderHelper $orderHelper |
106
|
|
|
* @param TokenStorageInterface $tokenStorage |
107
|
|
|
* @param AuthorizationCheckerInterface $authorizationChecker |
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
|
132 |
|
public function getCarts() |
134
|
|
|
{ |
135
|
132 |
|
if (!empty($this->carts)) { |
136
|
86 |
|
return $this->carts; |
137
|
|
|
} |
138
|
|
|
|
139
|
132 |
|
$cartKeys = $this->session->get('cart_keys', []); |
140
|
132 |
|
$this->carts = $this->cartRepository->findBy(['cart_key' => $cartKeys], ['id' => 'DESC']); |
141
|
|
|
|
142
|
132 |
|
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
|
87 |
|
protected function mergeAllCartItems($cartItems = []) |
184
|
|
|
{ |
185
|
|
|
/** @var CartItem[] $allCartItems */ |
186
|
87 |
|
$allCartItems = []; |
187
|
|
|
|
188
|
87 |
|
foreach ($this->getCarts() as $Cart) { |
189
|
39 |
|
$allCartItems = $this->mergeCartItems($Cart->getCartItems(), $allCartItems); |
190
|
|
|
} |
191
|
|
|
|
192
|
87 |
|
return $this->mergeCartItems($cartItems, $allCartItems); |
193
|
|
|
} |
194
|
|
|
|
195
|
|
|
/** |
196
|
|
|
* @param $cartItems |
197
|
|
|
* @param $allCartItems |
198
|
|
|
* |
199
|
|
|
* @return array |
200
|
|
|
*/ |
201
|
87 |
|
protected function mergeCartItems($cartItems, $allCartItems) |
202
|
|
|
{ |
203
|
87 |
|
foreach ($cartItems as $item) { |
204
|
86 |
|
$itemExists = false; |
205
|
86 |
|
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
|
86 |
|
if (!$itemExists) { |
214
|
86 |
|
$allCartItems[] = $item; |
215
|
|
|
} |
216
|
|
|
} |
217
|
|
|
|
218
|
87 |
|
return $allCartItems; |
219
|
|
|
} |
220
|
|
|
|
221
|
87 |
|
protected function restoreCarts($cartItems) |
222
|
|
|
{ |
223
|
87 |
|
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); |
|
|
|
|
228
|
|
|
} |
229
|
1 |
|
$this->entityManager->remove($Cart); |
230
|
1 |
|
$this->entityManager->flush($Cart); |
|
|
|
|
231
|
|
|
} |
232
|
2 |
|
$this->carts = []; |
233
|
|
|
} |
234
|
|
|
|
235
|
|
|
/** @var Cart[] $Carts */ |
236
|
87 |
|
$Carts = []; |
237
|
|
|
|
238
|
87 |
|
foreach ($cartItems as $item) { |
239
|
86 |
|
$allocatedId = $this->cartItemAllocator->allocate($item); |
240
|
86 |
|
$cartKey = $this->createCartKey($allocatedId, $this->getUser()); |
241
|
|
|
|
242
|
86 |
|
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
|
86 |
|
$Cart = $this->cartRepository->findOneBy(['cart_key' => $cartKey]); |
249
|
86 |
|
if ($Cart) { |
250
|
34 |
|
foreach ($Cart->getCartItems() as $i) { |
251
|
34 |
|
$this->entityManager->remove($i); |
252
|
34 |
|
$this->entityManager->flush($i); |
|
|
|
|
253
|
|
|
} |
254
|
34 |
|
$this->entityManager->remove($Cart); |
255
|
34 |
|
$this->entityManager->flush($Cart); |
|
|
|
|
256
|
|
|
} |
257
|
86 |
|
$Cart = new Cart(); |
258
|
86 |
|
$Cart->setCartKey($cartKey); |
259
|
86 |
|
$Cart->addCartItem($item); |
260
|
86 |
|
$item->setCart($Cart); |
261
|
86 |
|
$Carts[$cartKey] = $Cart; |
262
|
|
|
} |
263
|
|
|
} |
264
|
|
|
|
265
|
87 |
|
$this->carts = array_values($Carts); |
266
|
|
|
} |
267
|
|
|
|
268
|
|
|
/** |
269
|
|
|
* カートに商品を追加します. |
270
|
|
|
* |
271
|
|
|
* @param $ProductClass ProductClass 商品規格 |
272
|
|
|
* @param $quantity int 数量 |
273
|
|
|
* |
274
|
|
|
* @return bool 商品を追加できた場合はtrue |
275
|
|
|
*/ |
276
|
86 |
|
public function addProduct($ProductClass, $quantity = 1) |
277
|
|
|
{ |
278
|
86 |
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
|
86 |
|
$ClassCategory1 = $ProductClass->getClassCategory1(); |
289
|
86 |
|
if ($ClassCategory1 && !$ClassCategory1->isVisible()) { |
290
|
|
|
return false; |
291
|
|
|
} |
292
|
86 |
|
$ClassCategory2 = $ProductClass->getClassCategory2(); |
293
|
86 |
|
if ($ClassCategory2 && !$ClassCategory2->isVisible()) { |
294
|
|
|
return false; |
295
|
|
|
} |
296
|
|
|
|
297
|
86 |
|
$newItem = new CartItem(); |
298
|
86 |
|
$newItem->setQuantity($quantity); |
299
|
86 |
|
$newItem->setPrice($ProductClass->getPrice02IncTax()); |
300
|
86 |
|
$newItem->setProductClass($ProductClass); |
301
|
|
|
|
302
|
86 |
|
$allCartItems = $this->mergeAllCartItems([$newItem]); |
303
|
86 |
|
$this->restoreCarts($allCartItems); |
304
|
|
|
|
305
|
86 |
|
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
|
78 |
|
$Cart->setCustomer($this->getUser()); |
344
|
78 |
|
$this->entityManager->persist($Cart); |
345
|
78 |
|
foreach ($Cart->getCartItems() as $item) { |
346
|
78 |
|
$this->entityManager->persist($item); |
347
|
78 |
|
$this->entityManager->flush($item); |
|
|
|
|
348
|
|
|
} |
349
|
78 |
|
$this->entityManager->flush($Cart); |
|
|
|
|
350
|
78 |
|
$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 |
|
if (!empty($Carts)) { |
385
|
8 |
|
$removed = array_shift($Carts); |
386
|
8 |
|
if ($removed && UnitOfWork::STATE_MANAGED === $this->entityManager->getUnitOfWork()->getEntityState($removed)) { |
387
|
7 |
|
$this->entityManager->remove($removed); |
388
|
7 |
|
$this->entityManager->flush($removed); |
|
|
|
|
389
|
|
|
|
390
|
7 |
|
$cartKeys = []; |
391
|
7 |
|
foreach ($Carts as $Cart) { |
392
|
|
|
$cartKeys[] = $Cart->getCartKey(); |
393
|
|
|
} |
394
|
7 |
|
$this->session->set('cart_keys', $cartKeys); |
395
|
7 |
|
$this->carts = $this->cartRepository->findBy(['cart_key' => $cartKeys], ['id' => 'DESC']); |
396
|
|
|
} |
397
|
|
|
} |
398
|
|
|
|
399
|
10 |
|
return $this; |
400
|
|
|
} |
401
|
|
|
|
402
|
|
|
/** |
403
|
|
|
* @param CartItemComparator $cartItemComparator |
404
|
|
|
*/ |
405
|
1 |
|
public function setCartItemComparator($cartItemComparator) |
406
|
|
|
{ |
407
|
1 |
|
$this->cartItemComparator = $cartItemComparator; |
408
|
|
|
} |
409
|
|
|
|
410
|
|
|
/** |
411
|
|
|
* 指定したインデックスにあるカートを優先にする |
412
|
|
|
* |
413
|
|
|
* @param int $index カートのインデックス |
414
|
|
|
*/ |
415
|
53 |
|
public function setPrimary($index = 0) |
416
|
|
|
{ |
417
|
53 |
|
$Carts = $this->getCarts(); |
418
|
53 |
|
$primary = $Carts[$index]; |
419
|
53 |
|
$prev = $Carts[0]; |
420
|
53 |
|
array_splice($Carts, 0, 1, [$primary]); |
421
|
53 |
|
array_splice($Carts, $index, 1, [$prev]); |
422
|
53 |
|
$this->carts = $Carts; |
423
|
53 |
|
$this->save(); |
424
|
|
|
} |
425
|
|
|
|
426
|
86 |
|
protected function getUser() |
427
|
|
|
{ |
428
|
86 |
|
if (null === $token = $this->tokenStorage->getToken()) { |
429
|
10 |
|
return; |
430
|
|
|
} |
431
|
|
|
|
432
|
76 |
|
if (!is_object($user = $token->getUser())) { |
433
|
|
|
// e.g. anonymous authentication |
434
|
25 |
|
return; |
435
|
|
|
} |
436
|
|
|
|
437
|
51 |
|
return $user; |
438
|
|
|
} |
439
|
|
|
|
440
|
|
|
/** |
441
|
|
|
* @param string $allocatedId |
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
|
|
|
|
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.