CartService::__construct()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 16
Code Lines 10

Duplication

Lines 0
Ratio 0 %
Metric Value
dl 0
loc 16
rs 9.4285
cc 2
eloc 10
nc 2
nop 1
1
<?php
2
/*
3
 * This file is part of EC-CUBE
4
 *
5
 * Copyright(c) 2000-2015 LOCKON CO.,LTD. All Rights Reserved.
6
 *
7
 * http://www.lockon.co.jp/
8
 *
9
 * This program is free software; you can redistribute it and/or
10
 * modify it under the terms of the GNU General Public License
11
 * as published by the Free Software Foundation; either version 2
12
 * of the License, or (at your option) any later version.
13
 *
14
 * This program is distributed in the hope that it will be useful,
15
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17
 * GNU General Public License for more details.
18
 *
19
 * You should have received a copy of the GNU General Public License
20
 * along with this program; if not, write to the Free Software
21
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
22
 */
23
24
25
namespace Eccube\Service;
26
27
use Doctrine\ORM\EntityManager;
28
use Eccube\Common\Constant;
29
use Eccube\Entity\CartItem;
30
use Eccube\Entity\Master\Disp;
31
use Eccube\Entity\ProductClass;
32
use Eccube\Exception\CartException;
33
use Symfony\Component\HttpFoundation\Session\Session;
34
35
class CartService
0 ignored issues
show
introduced by
Missing class doc comment
Loading history...
36
{
37
    /** @var \Eccube\Application */
38
    public $app;
39
40
    /**
41
     * @var Session
42
     */
43
    private $session;
44
45
    /**
46
     * @var EntityManager
47
     */
48
    private $entityManager;
49
50
    /**
51
     * @var \Eccube\Entity\Cart
52
     */
53
    private $cart;
54
55
    /**
56
     * @var \Eccube\Entity\BaseInfo
57
     */
58
    private $BaseInfo;
59
60
    /**
61
     * @var array
62
     */
63
    private $errors = array();
64
65
    private $ProductType = null;
66
67
    /**
68
     * @var array
69
     */
70
    private $messages = array();
71
72
    /**
73
     * @var array
74
     */
75
    private $error;
76
77
    public function __construct(\Eccube\Application $app)
0 ignored issues
show
introduced by
Missing function doc comment
Loading history...
78
    {
79
        $this->app = $app;
80
        $this->session = $app['session'];
81
        $this->entityManager = $app['orm.em'];
82
83
        if ($this->session->has('cart')) {
84
            $this->cart = $this->session->get('cart');
85
        } else {
86
            $this->cart = new \Eccube\Entity\Cart();
87
        }
88
89
        $this->loadProductClassFromCart();
90
91
        $this->BaseInfo = $app['eccube.repository.base_info']->get();
92
    }
93
94
    /**
95
     * カートに保存されている商品の ProductClass エンティティを読み込み、カートへ設定します。
96
     */
97
    protected function loadProductClassFromCart()
98
    {
99
        /* @var $softDeleteFilter \Eccube\Doctrine\Filter\SoftDeleteFilter */
100
        $softDeleteFilter = $this->entityManager->getFilters()->getFilter('soft_delete');
101
        $softDeleteFilter->setExcludes(array(
102
            'Eccube\Entity\ProductClass',
103
        ));
104
105
        foreach ($this->cart->getCartItems() as $CartItem) {
106
            $this->loadProductClassFromCartItem($CartItem);
107
        }
108
109
        $softDeleteFilter->setExcludes(array());
110
    }
111
112
    /**
113
     * CartItem に対応する ProductClass を設定します。
114
     *
115
     * @param CartItem $CartItem
116
     */
117
    protected function loadProductClassFromCartItem(CartItem $CartItem)
118
    {
119
        $ProductClass = $this
120
            ->entityManager
121
            ->getRepository($CartItem->getClassName())
122
            ->find($CartItem->getClassId());
123
124
        $CartItem->setObject($ProductClass);
125
126
        if (is_null($this->ProductType) && $ProductClass->getDelFlg() == Constant::DISABLED) {
127
            $this->setCanAddProductType($ProductClass->getProductType());
128
        }
129
    }
130
131
    public function setCanAddProductType(\Eccube\Entity\Master\ProductType $ProductType)
0 ignored issues
show
introduced by
Declare public methods first, then protected ones and finally private ones
Loading history...
introduced by
Missing function doc comment
Loading history...
132
    {
133
        if (is_null($this->ProductType)) {
134
            $this->ProductType = $ProductType;
135
        }
136
137
        return $this;
138
    }
139
140
    public function save()
0 ignored issues
show
introduced by
Missing function doc comment
Loading history...
141
    {
142
        return $this->session->set('cart', $this->cart);
143
    }
144
145
    public function unlock()
0 ignored issues
show
introduced by
Missing function doc comment
Loading history...
146
    {
147
        $this->cart
148
            ->setLock(false)
149
            ->setPreOrderId(null);
150
    }
151
152
    public function lock()
0 ignored issues
show
introduced by
Missing function doc comment
Loading history...
153
    {
154
        $this->cart
155
            ->setLock(true)
156
            ->setPreOrderId(null);
157
    }
158
159
    /**
160
     * @return bool
161
     */
162
    public function isLocked()
163
    {
164
        return $this->cart->getLock();
165
    }
166
167
    /**
168
     * @param  string $pre_order_id
169
     * @return \Eccube\Service\CartService
170
     */
171
    public function setPreOrderId($pre_order_id)
172
    {
173
        $this->cart->setPreOrderId($pre_order_id);
174
175
        return $this;
176
    }
177
178
    /**
179
     * @return string
180
     */
181
    public function getPreOrderId()
182
    {
183
        return $this->cart->getPreOrderId();
184
    }
185
186
    /**
187
     * @return \Eccube\Service\CartService
188
     */
189
    public function clear()
190
    {
191
        $this->cart
192
            ->setPreOrderId(null)
193
            ->setLock(false)
194
            ->clearCartItems();
195
196
        return $this;
197
    }
198
199
    public function getCanAddProductType()
0 ignored issues
show
introduced by
Missing function doc comment
Loading history...
200
    {
201
        return $this->ProductType;
202
    }
203
204
    /**
205
     *
206
     * @param  string $productClassId
0 ignored issues
show
introduced by
Expected 2 spaces after parameter type; 1 found
Loading history...
207
     * @param  integer $quantity
208
     * @return \Eccube\Service\CartService
209
     */
210
    public function addProduct($productClassId, $quantity = 1)
211
    {
212
        $quantity += $this->getProductQuantity($productClassId);
213
        $this->setProductQuantity($productClassId, $quantity);
214
215
        return $this;
216
    }
217
218
    /**
219
     * @param  string $productClassId
220
     * @return integer
221
     */
222
    public function getProductQuantity($productClassId)
223
    {
224
        $CartItem = $this->cart->getCartItemByIdentifier('Eccube\Entity\ProductClass', (string) $productClassId);
225
        if ($CartItem) {
226
            return $CartItem->getQuantity();
227
        } else {
228
            return 0;
229
        }
230
    }
231
232
    /**
233
     * @param  \Eccube\Entity\ProductClass|integer $ProductClass
234
     * @param  integer $quantity
0 ignored issues
show
introduced by
Expected 29 spaces after parameter type; 1 found
Loading history...
235
     * @return \Eccube\Service\CartService
236
     * @throws CartException
237
     */
238
    public function setProductQuantity($ProductClass, $quantity)
239
    {
240
        if (!$ProductClass instanceof ProductClass) {
0 ignored issues
show
Bug introduced by
The class Eccube\Entity\ProductClass does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
241
            $ProductClass = $this->entityManager
242
                ->getRepository('Eccube\Entity\ProductClass')
243
                ->find($ProductClass);
244
            if (!$ProductClass) {
245
                throw new CartException('cart.product.delete');
246
            }
247
        }
248
        if ($ProductClass->getProduct()->getStatus()->getId() !== Disp::DISPLAY_SHOW) {
249
            $this->removeProduct($ProductClass->getId());
250
            throw new CartException('cart.product.not.status');
251
        }
252
253
        $productName = $ProductClass->getProduct()->getName();
254
        if ($ProductClass->hasClassCategory1()) {
255
            $productName .= " - ".$ProductClass->getClassCategory1()->getName();
256
        }
257
        if ($ProductClass->hasClassCategory2()) {
258
            $productName .= " - ".$ProductClass->getClassCategory2()->getName();
259
        }
260
261
        // 商品種別に紐づく配送業者を取得
262
        $deliveries = $this->app['eccube.repository.delivery']->getDeliveries($ProductClass->getProductType());
263
264
        if (count($deliveries) == 0) {
265
            // 商品種別が存在しなければエラー
266
            $this->removeProduct($ProductClass->getId());
267
            $this->addError('cart.product.not.producttype', $productName);
268
            throw new CartException('cart.product.not.producttype');
269
        }
270
271
        $this->setCanAddProductType($ProductClass->getProductType());
272
273
        if ($this->BaseInfo->getOptionMultipleShipping() != Constant::ENABLED) {
274
            if (!$this->canAddProduct($ProductClass->getId())) {
275
                // 複数配送対応でなければ商品種別が異なればエラー
276
                throw new CartException('cart.product.type.kind');
277
            }
278
        } else {
279
            // 複数配送の場合、同一支払方法がなければエラー
280
            if (!$this->canAddProductPayment($ProductClass->getProductType())) {
281
                throw new CartException('cart.product.payment.kind');
282
            }
283
0 ignored issues
show
Coding Style introduced by
Blank line found at end of control structure
Loading history...
284
        }
285
286
        $tmp_subtotal = 0;
287
        $tmp_quantity = 0;
288
        foreach ($this->getCart()->getCartItems() as $cartitem) {
289
            $pc = $cartitem->getObject();
290
            if ($pc->getId() != $ProductClass->getId()) {
291
                // まず、追加された商品以外のtotal priceをセット
292
                $tmp_subtotal += $cartitem->getTotalPrice();
293
            }
294
        }
295
        for ($i = 0; $i < $quantity; $i++) {
296
            $tmp_subtotal += $ProductClass->getPrice02IncTax();
297
            if ($tmp_subtotal > $this->app['config']['max_total_fee']) {
298
                $this->setError('cart.over.price_limit');
299
                break;
300
            }
301
            $tmp_quantity++;
302
        }
303
        $quantity = $tmp_quantity;
304
305
        $tmp_quantity = 0;
306
307
        /*
308
         * 実際の在庫は ProductClass::ProductStock だが、購入時にロックがかかるため、
309
         * ここでは ProductClass::stock で在庫のチェックをする
310
         */
311
        if (!$ProductClass->getStockUnlimited() && $quantity > $ProductClass->getStock()) {
312
            if ($ProductClass->getSaleLimit() && $ProductClass->getStock() > $ProductClass->getSaleLimit()) {
313
                $tmp_quantity = $ProductClass->getSaleLimit();
314
                $this->addError('cart.over.sale_limit', $productName);
315
            } else {
316
                $tmp_quantity = $ProductClass->getStock();
317
                $this->addError('cart.over.stock', $productName);
318
            }
319
        }
320
        if ($ProductClass->getSaleLimit() && $quantity > $ProductClass->getSaleLimit()) {
321
            $tmp_quantity = $ProductClass->getSaleLimit();
322
            $this->addError('cart.over.sale_limit', $productName);
323
        }
324
        if ($tmp_quantity) {
325
            $quantity = $tmp_quantity;
326
        }
327
328
        $CartItem = new CartItem();
329
        $CartItem
330
            ->setClassName('Eccube\Entity\ProductClass')
331
            ->setClassId((string) $ProductClass->getId())
332
            ->setPrice($ProductClass->getPrice02IncTax())
333
            ->setQuantity($quantity);
334
335
        $this->cart->setCartItem($CartItem);
336
337
        return $this;
338
    }
339
340
    /**
341
     * @param  string $productClassId
342
     * @return boolean
343
     */
344
    public function canAddProduct($productClassId)
345
    {
346
        $ProductClass = $this
347
            ->entityManager
348
            ->getRepository('\Eccube\Entity\ProductClass')
349
            ->find($productClassId);
350
351
        if (!$ProductClass) {
352
            return false;
353
        }
354
355
        $ProductType = $ProductClass->getProductType();
356
357
        return $this->ProductType == $ProductType;
358
    }
359
360
    /**
361
     * @param \Eccube\Entity\Master\ProductType $ProductType
362
     * @return bool
363
     */
364
    public function canAddProductPayment(\Eccube\Entity\Master\ProductType $ProductType)
365
    {
366
        $deliveries = $this
367
            ->entityManager
368
            ->getRepository('\Eccube\Entity\Delivery')
369
            ->findBy(array('ProductType' => $ProductType));
370
371
        // 支払方法を取得
372
        $payments = $this->entityManager->getRepository('Eccube\Entity\Payment')->findAllowedPayments($deliveries);
373
374
        if ($this->getCart()->getTotalPrice() < 1) {
375
            // カートになければ支払方法を全て設定
376
            $this->getCart()->setPayments($payments);
377
            return true;
0 ignored issues
show
introduced by
Missing blank line before return statement
Loading history...
378
        }
379
380
        // カートに存在している支払方法と追加された商品の支払方法チェック
381
        $arr = array();
382
        foreach ($payments as $payment) {
383
            foreach ($this->getCart()->getPayments() as $p) {
384
                if ($payment['id'] == $p['id']) {
385
                    $arr[] = $payment;
386
                    break;
387
                }
388
            }
389
        }
390
391
        if (count($arr) > 0) {
392
            $this->getCart()->setPayments($arr);
393
            return true;
0 ignored issues
show
introduced by
Missing blank line before return statement
Loading history...
394
        }
395
396
        // 支払条件に一致しない
397
        return false;
398
399
    }
400
401
    /**
402
     * カートを取得します。
403
     *
404
     * @return \Eccube\Entity\Cart
405
     */
406
    public function getCart()
407
    {
408
        foreach ($this->cart->getCartItems() as $CartItem) {
409
            $ProductClass = $CartItem->getObject();
410
            if (!$ProductClass) {
411
                $this->loadProductClassFromCartItem($CartItem);
412
413
                $ProductClass = $CartItem->getObject();
414
            }
415
416
            if ($ProductClass->getDelFlg() == Constant::DISABLED) {
417
                // 商品情報が有効
418
                $stockUnlimited = $ProductClass->getStockUnlimited();
419
                if ($stockUnlimited == Constant::DISABLED && $ProductClass->getStock() < 1) {
420
                    // 在庫がなければカートから削除
421
                    $this->setError('cart.zero.stock');
422
                    $this->removeProduct($ProductClass->getId());
423
                } else {
424
                    $quantity = $CartItem->getQuantity();
425
                    $saleLimit = $ProductClass->getSaleLimit();
426
                    if ($stockUnlimited == Constant::DISABLED && $ProductClass->getStock() < $quantity) {
427
                        // 購入数が在庫数を超えている場合、メッセージを表示
428
                        $this->setError('cart.over.stock');
429
                    } elseif (!is_null($saleLimit) && $saleLimit < $quantity) {
430
                        // 購入数が販売制限数を超えている場合、メッセージを表示
431
                        $this->setError('cart.over.sale_limit');
432
                    }
433
                }
434
            } else {
435
                // 商品情報が削除されていたらエラー
436
                $this->setError('cart.product.delete');
437
                // カートから削除
438
                $this->removeProduct($ProductClass->getId());
439
            }
440
        }
441
442
        return $this->cart;
443
    }
444
445
    /**
446
     * @param  string $productClassId
447
     * @return \Eccube\Service\CartService
448
     */
449
    public function removeProduct($productClassId)
450
    {
451
        $this->cart->removeCartItemByIdentifier('Eccube\Entity\ProductClass', (string) $productClassId);
452
453
        // 支払方法の再設定
454
        if ($this->BaseInfo->getOptionMultipleShipping() == Constant::ENABLED) {
0 ignored issues
show
Coding Style introduced by
Blank line found at start of control structure
Loading history...
455
456
            // 複数配送対応
457
            $productTypes = array();
458
            foreach ($this->getCart()->getCartItems() as $item) {
459
                /* @var $ProductClass \Eccube\Entity\ProductClass */
460
                $ProductClass = $item->getObject();
461
                $productTypes[] = $ProductClass->getProductType();
462
            }
463
464
            // 配送業者を取得
465
            $deliveries = $this->entityManager->getRepository('Eccube\Entity\Delivery')->getDeliveries($productTypes);
466
467
            // 支払方法を取得
468
            $payments = $this->entityManager->getRepository('Eccube\Entity\Payment')->findAllowedPayments($deliveries);
469
470
            $this->getCart()->setPayments($payments);
471
        }
472
473
        return $this;
474
    }
475
476
    /**
477
     * @param  string $error
478
     * @param  string $productName
479
     * @return \Eccube\Service\CartService
480
     */
481
    public function addError($error = null, $productName = null)
482
    {
483
        $this->errors[] = $error;
484
        $this->session->getFlashBag()->add('eccube.front.request.error', $error);
485
        if (!is_null($productName)) {
486
            $this->session->getFlashBag()->add('eccube.front.request.product', $productName);
487
        }
488
        return $this;
0 ignored issues
show
introduced by
Missing blank line before return statement
Loading history...
489
    }
490
491
    /**
492
     * @param  string $productClassId
493
     * @return \Eccube\Service\CartService
494
     */
495
    public function upProductQuantity($productClassId)
496
    {
497
        $quantity = $this->getProductQuantity($productClassId) + 1;
498
        $this->setProductQuantity($productClassId, $quantity);
499
500
        return $this;
501
    }
502
503
    /**
504
     * @param  string $productClassId
505
     * @return \Eccube\Service\CartService
506
     */
507
    public function downProductQuantity($productClassId)
508
    {
509
        $quantity = $this->getProductQuantity($productClassId) - 1;
510
511
        if ($quantity > 0) {
512
            $this->setProductQuantity($productClassId, $quantity);
513
        } else {
514
            $this->removeProduct($productClassId);
515
        }
516
517
        return $this;
518
    }
519
520
    /**
521
     * @return array
522
     */
523
    public function getProductTypes()
524
    {
525
526
        $productTypes = array();
527
        foreach ($this->getCart()->getCartItems() as $item) {
528
            /* @var $ProductClass \Eccube\Entity\ProductClass */
529
            $ProductClass = $item->getObject();
530
            $productTypes[] = $ProductClass->getProductType();
531
        }
532
        return array_unique($productTypes);
0 ignored issues
show
introduced by
Missing blank line before return statement
Loading history...
533
534
    }
535
536
    /**
537
     * @return string[]
538
     */
539
    public function getErrors()
540
    {
541
        return $this->errors;
542
    }
543
544
    /**
545
     * @return string[]
546
     */
547
    public function getMessages()
548
    {
549
        return $this->messages;
550
    }
551
552
    /**
553
     * @param  string $message
554
     * @return \Eccube\Service\CartService
555
     */
556
    public function setMessage($message)
557
    {
558
        $this->messages[] = $message;
559
560
        return $this;
561
    }
562
563
    /**
564
     * @return string
565
     */
566
    public function getError()
567
    {
568
        return $this->error;
569
    }
570
571
    /**
572
     * @param  string $error
573
     * @return \Eccube\Service\CartService
574
     */
575
    public function setError($error = null)
576
    {
577
        $this->error = $error;
0 ignored issues
show
Documentation Bug introduced by
It seems like $error of type string or null is incompatible with the declared type array of property $error.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
578
        $this->session->getFlashBag()->set('eccube.front.request.error', $error);
579
        return $this;
0 ignored issues
show
introduced by
Missing blank line before return statement
Loading history...
580
    }
581
582
}
583