Failed Conditions
Pull Request — experimental/3.1 (#2273)
by
unknown
39:32
created

CartService::getCart()   C

Complexity

Conditions 8
Paths 13

Size

Total Lines 48
Code Lines 27

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 72

Importance

Changes 0
Metric Value
cc 8
eloc 27
nc 13
nop 0
dl 0
loc 48
ccs 0
cts 0
cp 0
crap 72
rs 5.9322
c 0
b 0
f 0
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 182
    public function __construct(\Eccube\Application $app)
0 ignored issues
show
introduced by
Missing function doc comment
Loading history...
78
    {
79 182
        $this->app = $app;
80 182
        $this->session = $app['session'];
81 182
        $this->entityManager = $app['orm.em'];
82
83 182
        if ($this->session->has('cart')) {
84
            $this->cart = $this->session->get('cart');
85
        } else {
86 182
            $this->cart = new \Eccube\Entity\Cart();
87
        }
88
89 182
        $this->loadProductClassFromCart();
90
91 182
        $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');
0 ignored issues
show
Unused Code Comprehensibility introduced by
62% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
101
        // $excludes = $softDeleteFilter->getExcludes();
0 ignored issues
show
Unused Code Comprehensibility introduced by
55% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
102
        // $softDeleteFilter->setExcludes(array(
0 ignored issues
show
Unused Code Comprehensibility introduced by
72% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
103
        //     'Eccube\Entity\ProductClass',
104
        // ));
105
106
        // foreach ($this->cart->getCartItems() as $CartItem) {
0 ignored issues
show
Unused Code Comprehensibility introduced by
62% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
107
        //     $this->loadProductClassFromCartItem($CartItem);
0 ignored issues
show
Unused Code Comprehensibility introduced by
75% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
108
        // }
109
110
        // $softDeleteFilter->setExcludes($excludes);
0 ignored issues
show
Unused Code Comprehensibility introduced by
75% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
111
    }
112
113
    /**
114
     * CartItem に対応する ProductClass を設定します。
115
     *
116
     * @param CartItem $CartItem
117
     */
118 48
    protected function loadProductClassFromCartItem(CartItem $CartItem)
119
    {
120
        $ProductClass = $this
121 48
            ->entityManager
122 48
            ->getRepository($CartItem->getClassName())
123 48
            ->find($CartItem->getClassId());
124
125 48
        $CartItem->setObject($ProductClass);
126
127 48
        if (is_null($this->ProductType) && $ProductClass->getDelFlg() == Constant::DISABLED) {
128
            $this->setCanAddProductType($ProductClass->getProductType());
129
        }
130
    }
131
132 88
    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...
133
    {
134 88
        if (is_null($this->ProductType)) {
135 88
            $this->ProductType = $ProductType;
136
        }
137
138 88
        return $this;
139
    }
140
141 82
    public function save()
0 ignored issues
show
introduced by
Missing function doc comment
Loading history...
142
    {
143 82
        return $this->session->set('cart', $this->cart);
144
    }
145
146 4
    public function unlock()
0 ignored issues
show
introduced by
Missing function doc comment
Loading history...
147
    {
148 4
        $this->cart
149 4
            ->setLock(false)
150 4
            ->setPreOrderId(null);
151
    }
152
153 38
    public function lock()
0 ignored issues
show
introduced by
Missing function doc comment
Loading history...
154
    {
155 38
        $this->cart
156 38
            ->setLock(true)
157 38
            ->setPreOrderId(null);
158
    }
159
160
    /**
161
     * @return bool
162
     */
163 45
    public function isLocked()
164
    {
165 45
        return $this->cart->getLock();
166
    }
167
168
    /**
169
     * @param  string $pre_order_id
170
     * @return \Eccube\Service\CartService
171
     */
172 20
    public function setPreOrderId($pre_order_id)
173
    {
174 20
        $this->cart->setPreOrderId($pre_order_id);
175
176 20
        return $this;
177
    }
178
179
    /**
180
     * @return string
181
     */
182 39
    public function getPreOrderId()
183
    {
184 39
        return $this->cart->getPreOrderId();
185
    }
186
187
    /**
188
     * @return \Eccube\Service\CartService
189
     */
190 4
    public function clear()
191
    {
192 4
        $this->cart
193 4
            ->setPreOrderId(null)
194 4
            ->setLock(false)
195 4
            ->clearCartItems();
196
197 4
        return $this;
198
    }
199
200 1
    public function getCanAddProductType()
0 ignored issues
show
introduced by
Missing function doc comment
Loading history...
201
    {
202 1
        return $this->ProductType;
203
    }
204
205
    /**
206
     * @param ProductClass|integer $ProductClass 商品規格エンティティ、またはそのID
207
     * @return CartItem
208
     * @throws CartException
209
     */
210
    public function generateCartItem($ProductClass)
211 44
    {
212 View Code Duplication
        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...
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
213 44
            $ProductClass = $this->entityManager
214 44
                ->getRepository('Eccube\Entity\ProductClass')
215
                ->find($ProductClass);
216 43
            if (!$ProductClass) {
217
                throw new CartException('cart.product.delete');
218
            }
219
        }
220
        $CartItem = new CartItem();
221
        $CartItem
222
            ->setClassName('Eccube\Entity\ProductClass')
223 53
            ->setObject($ProductClass)
224
            ->setClassId((string)$ProductClass->getId())
0 ignored issues
show
Coding Style introduced by
As per coding-style, a cast statement should be followed by a single space.
Loading history...
225 53
            ->setPrice($ProductClass->getPrice02IncTax())
226 53
            ->setQuantity(1);
227 7
        return $CartItem;
0 ignored issues
show
introduced by
Missing blank line before return statement
Loading history...
228
    }
229 51
230
    /**
231
     * カート商品を追加する
232
     *
233
     * @param  CartItem $CartItem
234
     * @return \Eccube\Service\CartService
235
     */
236
    public function addCartItem($CartItem)
237
    {
238
        $quantity = $CartItem->getQuantity() + $this->getCartItemQuantity($CartItem);
239 91
        $this->setCartItemQuantity($CartItem, $quantity);
240
241 91
        return $this;
242 86
    }
243 86
244 86
    /**
245 86
     * カート商品の数量を取得する
246 3
     *
247
     * @param CartItem $CartItem
248
     * @return int
249 88
     */
250 1
    public function getCartItemQuantity($CartItem)
251 1
    {
252
        $compareService = $this->generateCartCompareService();
253
        $ExistsCartItem = $compareService->getExistsCartItem($CartItem);
254 87
        return $ExistsCartItem ?
0 ignored issues
show
introduced by
Missing blank line before return statement
Loading history...
255 87
            $ExistsCartItem->getQuantity() :
256 87
            0;
257
    }
258 87
259 85
    /**
260
     * @param  CartItem $CartItem
261
     * @param  integer $quantity
0 ignored issues
show
introduced by
Expected 2 spaces after parameter type; 1 found
Loading history...
262
     * @return \Eccube\Service\CartService
263 87
     * @throws CartException
264
     */
265 87
    public function setCartItemQuantity($CartItem, $quantity)
266
    {
267
        /** @var ProductClass $ProductClass */
268
        $ProductClass = $CartItem->getObject();
269
270
        if (!$this->isProductDisplay($ProductClass)) {
271
            throw new CartException('cart.product.not.status');
272 87
        }
273
274 87
        $productName = $this->getProductName($ProductClass);
275 79
276
        // 商品種別に紐づく配送業者を取得
277 79
        $deliveries = $this->app['eccube.repository.delivery']->getDeliveries($ProductClass->getProductType());
278
279 View Code Duplication
        if (count($deliveries) == 0) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
280
            // 商品種別が存在しなければエラー
281 8
            $this->removeProduct($ProductClass->getId());
282 1
            $this->addError('cart.product.not.producttype', $productName);
283
            throw new CartException('cart.product.not.producttype');
284
        }
285
286
        $this->setCanAddProductType($ProductClass->getProductType());
287 87
288 87 View Code Duplication
        if ($this->BaseInfo->getOptionMultipleShipping() != Constant::ENABLED) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
289 87
            if (!$this->canAddProduct($ProductClass->getId())) {
290 8
                // 複数配送対応でなく、かつ商品種別が異なればエラー
291 8
                throw new CartException('cart.product.type.kind');
292
            }
293 87
        } else {
294
            // 複数配送対応で、かつ同一支払方法がなければエラー
295
            if (!$this->canAddProductPayment($ProductClass->getProductType())) {
296 87
                throw new CartException('cart.product.payment.kind');
297 87
            }
298 87
        }
299 1
300 1
        $compareService = $this->generateCartCompareService();
301
        $ExistsCartItem = $compareService->getExistsCartItem($CartItem);
302 86
        $subtotal = 0;
303
        $productClassQuantity = 0;
304 87
305
        foreach ($this->getCartObj()->getCartItems() as $CurrentCartItem) {
0 ignored issues
show
Coding Style introduced by
Blank line found at start of control structure
Loading history...
306 87
307
            $CurrentProductClass = $CurrentCartItem->getObject();
308
309
            // 同じ商品規格IDの数量を集計
310
            if ($CurrentProductClass->getId() == $ProductClass->getId()) {
311
                $productClassQuantity += $CurrentCartItem->getQuantity();
312 87
            }
313 2
314 1
            // 小計を集計
315 1
            $subtotal += $CurrentCartItem->getTotalPrice();
316
        }
317 1
318 1
        // 既存カートの数量と小計を除外
319
        if ($ExistsCartItem) {
320
            $subtotal -= $CurrentCartItem->getTotalPrice();
0 ignored issues
show
Bug introduced by
The variable $CurrentCartItem seems to be defined by a foreach iteration on line 305. Are you sure the iterator is never empty, otherwise this variable is not defined?

It seems like you are relying on a variable being defined by an iteration:

foreach ($a as $b) {
}

// $b is defined here only if $a has elements, for example if $a is array()
// then $b would not be defined here. To avoid that, we recommend to set a
// default value for $b.


// Better
$b = 0; // or whatever default makes sense in your context
foreach ($a as $b) {
}

// $b is now guaranteed to be defined here.
Loading history...
321 87
            $productClassQuantity -= $CurrentCartItem->getQuantity();
322 2
        }
323 2
324 View Code Duplication
        for ($newQuantity = 0; $newQuantity < $quantity; $newQuantity++) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
325 87
            // TODO 単価をProductClassではなくCartItemから取得する
326 3
            $subtotal += $ProductClass->getPrice02IncTax();
327
            if ($subtotal > $this->app['config']['max_total_fee']) {
328
                $this->setError('cart.over.price_limit');
329 87
                break;
330
            }
331 87
        }
332 87
333 87
        // 数量が0の場合、エラー
334 87
        if ($newQuantity == 0) {
335
            throw new CartException('cart.over.price_limit');
336 87
        }
337
338 87
        $totalQuantity = $productClassQuantity + $newQuantity;
339
        // 制限数チェック(在庫不足の場合は、処理の中でカート内商品を削除している)
340
        $newTotalQuantity = $this->setProductLimit($ProductClass, $productName, $totalQuantity);
341
        $quantity = min($quantity, $newTotalQuantity - $productClassQuantity);
342
343
        // 新しい数量でカート内商品を登録する
344
        if (0 < $quantity) {
345 79
            $CartItem->setQuantity($quantity);
346
            $this->cart->setCartItem($CartItem, $compareService);
347
        }
348 79
349 79
        return $this;
350 79
    }
351
352 79
    /**
353
     * @param int $cart_no
354
     * @return \Eccube\Service\CartService
355
     */
356 79
    public function removeCartNo($cart_no)
357
    {
358 79
        $this->cart->removeCartItemByCartNo($cart_no);
359
        $this->resetPayment();
360
361
        return $this;
362
    }
363
364
    /**
365 9
     * 支払い方法を再設定する
366
     *
367
     * @return $this
368 9
     */
369 9
    protected function resetPayment()
370 9
    {
371
        // 支払方法の再設定
372
        if ($this->BaseInfo->getOptionMultipleShipping() == Constant::ENABLED) {
0 ignored issues
show
Coding Style introduced by
Blank line found at start of control structure
Loading history...
373 9
374
            // 複数配送対応
375 9
            $productTypes = array();
376
            foreach ($this->getCart()->getCartItems() as $item) {
377 9
                /* @var $ProductClass \Eccube\Entity\ProductClass */
378 9
                $ProductClass = $item->getObject();
379
                $productTypes[] = $ProductClass->getProductType();
380
            }
381
382 7
            // 配送業者を取得
383 7
            $deliveries = $this->entityManager->getRepository('Eccube\Entity\Delivery')->getDeliveries($productTypes);
384 7
385 7
            // 支払方法を取得
386 6
            $payments = $this->entityManager->getRepository('Eccube\Entity\Payment')->findAllowedPayments($deliveries);
387 7
388
            $this->getCart()->setPayments($payments);
389
        }
390
391
        return $this;
392 7
    }
393 6
394 6
    /**
395
     *
396
     * @param  string $productClassId
0 ignored issues
show
introduced by
Expected 2 spaces after parameter type; 1 found
Loading history...
397
     * @param  integer $quantity
398 1
     * @return \Eccube\Service\CartService
399
     */
400
    public function addProduct($productClassId, $quantity = 1)
0 ignored issues
show
introduced by
Declare public methods first, then protected ones and finally private ones
Loading history...
401
    {
402
        $quantity += $this->getProductQuantity($productClassId);
403
        $this->setProductQuantity($productClassId, $quantity);
404
405
        return $this;
406
    }
407 158
408
    /**
409 158
     * @param  string $productClassId
410 48
     * @return integer
411 48
     */
412 48
    public function getProductQuantity($productClassId)
413
    {
414 48
        $CartItem = $this->cart->getCartItemByIdentifier('Eccube\Entity\ProductClass', (string)$productClassId);
0 ignored issues
show
Coding Style introduced by
As per coding-style, a cast statement should be followed by a single space.
Loading history...
415
        if ($CartItem) {
416
            return $CartItem->getQuantity();
417 48
        } else {
418
            return 0;
419 48
        }
420 48
    }
421
422
    /**
423
     * @param  \Eccube\Entity\ProductClass|integer $ProductClass
424
     * @param  integer $quantity
0 ignored issues
show
introduced by
Expected 29 spaces after parameter type; 1 found
Loading history...
425 48
     * @return \Eccube\Service\CartService
426 48
     * @throws CartException
427 48
     */
428
    public function setProductQuantity($ProductClass, $quantity)
429
    {
430 48 View Code Duplication
        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...
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
431
            $ProductClass = $this->entityManager
432 48
                ->getRepository('Eccube\Entity\ProductClass')
433
                ->find($ProductClass);
434
            if (!$ProductClass) {
435
                throw new CartException('cart.product.delete');
436
            }
437
        }
438
439 158
        if (!$this->isProductDisplay($ProductClass)) {
440
            throw new CartException('cart.product.not.status');
441
        }
442
443 158
        $productName = $this->getProductName($ProductClass);
444
445
        // 商品種別に紐づく配送業者を取得
446
        $deliveries = $this->app['eccube.repository.delivery']->getDeliveries($ProductClass->getProductType());
447
448 View Code Duplication
        if (count($deliveries) == 0) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
449
            // 商品種別が存在しなければエラー
450 9
            $this->removeProduct($ProductClass->getId());
451
            $this->addError('cart.product.not.producttype', $productName);
452 9
            throw new CartException('cart.product.not.producttype');
453
        }
454
455 9
        $this->setCanAddProductType($ProductClass->getProductType());
456
457 View Code Duplication
        if ($this->BaseInfo->getOptionMultipleShipping() != Constant::ENABLED) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
458 1
            if (!$this->canAddProduct($ProductClass->getId())) {
459 1
                // 複数配送対応でなければ商品種別が異なればエラー
460
                throw new CartException('cart.product.type.kind');
461 1
            }
462 1
        } else {
463
            // 複数配送の場合、同一支払方法がなければエラー
464
            if (!$this->canAddProductPayment($ProductClass->getProductType())) {
465
                throw new CartException('cart.product.payment.kind');
466 1
            }
467
        }
468
469 1
        $tmp_subtotal = 0;
470
        $tmp_quantity = 0;
471 1
        foreach ($this->getCartObj()->getCartItems() as $cartitem) {
472
            $pc = $cartitem->getObject();
473
            if ($pc->getId() != $ProductClass->getId()) {
474 9
                // 追加された商品以外のtotal priceをセット
475
                $tmp_subtotal += $cartitem->getTotalPrice();
476
            }
477
        }
478 View Code Duplication
        for ($i = 0; $i < $quantity; $i++) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
479
            $tmp_subtotal += $ProductClass->getPrice02IncTax();
480
            if ($tmp_subtotal > $this->app['config']['max_total_fee']) {
481
                $this->setError('cart.over.price_limit');
482 4
                break;
483
            }
484 4
            $tmp_quantity++;
485 4
        }
486 4
        if ($tmp_quantity == 0) {
487 3
            // 数量が0の場合、エラー
488
            throw new CartException('cart.over.price_limit');
489 4
        }
490
491
        // 制限数チェック(在庫不足の場合は、処理の中でカート内商品を削除している)
492
        $quantity = $this->setProductLimit($ProductClass, $productName, $tmp_quantity);
493
494
		// 新しい数量でカート内商品を登録する
495
        if (0 < $quantity) {
496 4
            $CartItem = new CartItem();
497
            $CartItem
498 4
                ->setClassName('Eccube\Entity\ProductClass')
499 4
                ->setClassId((string)$ProductClass->getId())
0 ignored issues
show
Coding Style introduced by
As per coding-style, a cast statement should be followed by a single space.
Loading history...
500
                ->setPrice($ProductClass->getPrice02IncTax())
501 3
                ->setQuantity($quantity);
502
503
            $this->cart->setCartItem($CartItem, $this->generateCartCompareService());
504
        }
505
506
        return $this;
507
    }
508 5
509
    /**
510 5
     * @param  string $productClassId
511
     * @return boolean
512 5
     */
513 1
    public function canAddProduct($productClassId)
514
    {
515 4
        $ProductClass = $this
516
            ->entityManager
517
            ->getRepository('\Eccube\Entity\ProductClass')
518 5
            ->find($productClassId);
519
520
        if (!$ProductClass) {
521
            return false;
522
        }
523
524 20
        $ProductType = $ProductClass->getProductType();
525
526
        return $this->ProductType == $ProductType;
527 20
    }
528 20
529
    /**
530 20
     * @param \Eccube\Entity\Master\ProductType $ProductType
531 20
     * @return bool
532
     */
533 20
    public function canAddProductPayment(\Eccube\Entity\Master\ProductType $ProductType)
534
    {
535
        $deliveries = $this
536
            ->entityManager
537
            ->getRepository('\Eccube\Entity\Delivery')
538
            ->findBy(array('ProductType' => $ProductType));
539
540 3
        // 支払方法を取得
541
        $payments = $this->entityManager->getRepository('Eccube\Entity\Payment')->findAllowedPayments($deliveries);
542 3
543
        if ($this->getCart()->getTotalPrice() < 1) {
544
            // カートになければ支払方法を全て設定
545
            $this->getCart()->setPayments($payments);
546
547
            return true;
548 1
        }
549
550 1
        // カートに存在している支払方法と追加された商品の支払方法チェック
551
        $arr = array();
552
        foreach ($payments as $payment) {
553
            foreach ($this->getCart()->getPayments() as $p) {
554
                if ($payment['id'] == $p['id']) {
555
                    $arr[] = $payment;
556
                    break;
557 1
                }
558
            }
559 1
        }
560
561 1
        if (count($arr) > 0) {
562
            $this->getCart()->setPayments($arr);
563
564
            return true;
565
        }
566
567 1
        // 支払条件に一致しない
568
        return false;
569 1
570
    }
571
572
    /**
573
     * カートブロックに表示するカートを取得します。
574
     * ブロックに表示するカートはチェックを行わず、セットされているカートを返します。
575
     *
576 1
     * @return \Eccube\Entity\Cart
577
     */
578 1
    public function getCartObj()
579 1
    {
580 1
581
        foreach ($this->cart->getCartItems() as $CartItem) {
582
583
            /** @var \Eccube\Entity\ProductClass $ProductClass */
584
            $ProductClass = $CartItem->getObject();
585
            if (!$ProductClass) {
586
                $this->loadProductClassFromCartItem($CartItem);
587
588
                $ProductClass = $CartItem->getObject();
589
            }
590
591
            if ($ProductClass->getDelFlg()) {
592
                // 商品情報が削除されていたらエラー
593
                $this->setError('cart.product.delete');
594
                // カートから削除
595
                $this->removeProduct($ProductClass->getId());
596
            }
597
        }
598
599
        return $this->cart;
600
601
    }
602
603
    /**
604
     * カートを取得します。
605
     *
606
     * @return \Eccube\Entity\Cart
607
     */
608
    public function getCart()
609
    {
610
        $productClassQuantities = [];
611
        foreach ($this->cart->getCartItems() as $CartItem) {
612
613
            /** @var \Eccube\Entity\ProductClass $ProductClass */
614
            $ProductClass = $CartItem->getObject();
615
            if (!$ProductClass) {
616
                $this->loadProductClassFromCartItem($CartItem);
617
618
                $ProductClass = $CartItem->getObject();
619
            }
620
621
            if ($ProductClass->getDelFlg() == Constant::DISABLED) {
622
                // 商品情報が有効
623
624
                if (!$this->isProductDisplay($ProductClass)) {
625
                    $this->setError('cart.product.not.status');
626
                } else {
0 ignored issues
show
Coding Style introduced by
Blank line found at start of control structure
Loading history...
627
628
                    $productName = $this->getProductName($ProductClass);
629
                    $productClassId = $ProductClass->getId();
630
631
                    $quantity = $CartItem->getQuantity();
632
                    $productClassQuantity = isset($productClassQuantities[$productClassId]) ?
633
                        $productClassQuantities[$productClassId] :
634
                        0;
635
                    $totalQuantity = $productClassQuantity + $quantity;
636
                    $newTotalQuantity = $this->setProductLimit($ProductClass, $productName, $totalQuantity);
637
                    $newQuantity = min($quantity, $newTotalQuantity - $productClassQuantity);
638
                    $productClassQuantities[$productClassId] = $newTotalQuantity;
639
640
                    /// 個数が異なれば、新しい数量でカート内商品を更新する
641
                    if ((0 < $newQuantity) && ($quantity != $newQuantity)) {
642
                        // 個数が異なれば更新
643
                        $CartItem->setQuantity($newQuantity);
644
                    }
645
                }
646
            } else {
647
                // 商品情報が削除されていたらエラー
648
                $this->setError('cart.product.delete');
649
                // カートから削除
650
                $this->removeProduct($ProductClass->getId());
651
            }
652
        }
653
654
        return $this->cart;
655
    }
656
657
    /**
658
     * @param  string $productClassId
659
     * @return \Eccube\Service\CartService
660
     */
661
    public function removeProduct($productClassId)
662
    {
663
        $this->cart->removeCartItemByIdentifier('Eccube\Entity\ProductClass', (string)$productClassId);
0 ignored issues
show
Coding Style introduced by
As per coding-style, a cast statement should be followed by a single space.
Loading history...
664
        $this->resetPayment();
665
666
        return $this;
667
    }
668
669
    /**
670
     * @param  string $error
671
     * @param  string $productName
672
     * @return \Eccube\Service\CartService
673
     */
674
    public function addError($error = null, $productName = null)
675
    {
676
        $this->errors[] = $error;
677
        $this->session->getFlashBag()->add('eccube.front.request.error', $error);
678
        if (!is_null($productName)) {
679
            $this->session->getFlashBag()->add('eccube.front.request.product', $productName);
680
        }
681
682
        return $this;
683
    }
684
685
    /**
686
     * @param  string $productClassId
687
     * @return \Eccube\Service\CartService
688
     */
689
    public function upProductQuantity($productClassId)
690
    {
691
        $quantity = $this->getProductQuantity($productClassId) + 1;
692
        $this->setProductQuantity($productClassId, $quantity);
693
694
        return $this;
695
    }
696
697
    /**
698
     * @param  string $productClassId
699
     * @return \Eccube\Service\CartService
700
     */
701
    public function downProductQuantity($productClassId)
702
    {
703
        $quantity = $this->getProductQuantity($productClassId) - 1;
704
        if ($quantity > 0) {
705
            $this->setProductQuantity($productClassId, $quantity);
706
        }
707
708
        return $this;
709
    }
710
711
    /**
712
     * @param int $cart_no
713
     * @return \Eccube\Service\CartService
714
     */
715
    public function upCartNoQuantity($cart_no)
716
    {
717
        $CartItem = $this->getCart()->getCartItemByCartNo($cart_no);
718
        if ($CartItem) {
719
            $this->setCartItemQuantity($CartItem, $CartItem->getQuantity() + 1);
720
        }
721
722
        return $this;
723
    }
724
725
    /**
726
     * @param int $cart_no
727
     * @return \Eccube\Service\CartService
728
     */
729
    public function downCartNoQuantity($cart_no)
730
    {
731
        $CartItem = $this->getCart()->getCartItemByCartNo($cart_no);
732
        if ($CartItem) {
733
            $quantity = $CartItem->getQuantity() - 1;
734
            if ($quantity > 0) {
735
                $this->setCartItemQuantity($CartItem, $quantity);
736
            }
737
        }
738
739
        return $this;
740
    }
741
742
    /**
743
     * @return array
744
     */
745
    public function getProductTypes()
746
    {
747
748
        $productTypes = array();
749
        foreach ($this->getCart()->getCartItems() as $item) {
750
            /* @var $ProductClass \Eccube\Entity\ProductClass */
751
            $ProductClass = $item->getObject();
752
            $productTypes[] = $ProductClass->getProductType();
753
        }
754
755
        return array_unique($productTypes);
756
757
    }
758
759
    /**
760
     * @return string[]
761
     */
762
    public function getErrors()
763
    {
764
        return $this->errors;
765
    }
766
767
    /**
768
     * @return string[]
769
     */
770
    public function getMessages()
771
    {
772
        return $this->messages;
773
    }
774
775
    /**
776
     * @param  string $message
777
     * @return \Eccube\Service\CartService
778
     */
779
    public function setMessage($message)
780
    {
781
        $this->messages[] = $message;
782
783
        return $this;
784
    }
785
786
    /**
787
     * @return string
788
     */
789
    public function getError()
790
    {
791
        return $this->error;
792
    }
793
794
    /**
795
     * @param  string $error
796
     * @return \Eccube\Service\CartService
797
     */
798
    public function setError($error = null)
799
    {
800
        $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...
801
        $this->session->getFlashBag()->set('eccube.front.request.error', $error);
802
803
        return $this;
804
    }
805
806
    /**
807
     * 商品名を取得
808
     *
809
     * @param ProductClass $ProductClass
810
     * @return string
811
     */
812
    private function getProductName(ProductClass $ProductClass)
813
    {
814
815
        $productName = $ProductClass->getProduct()->getName();
816
817
        if ($ProductClass->hasClassCategory1()) {
818
            $productName .= " - ".$ProductClass->getClassCategory1()->getName();
819
        }
820
821
        if ($ProductClass->hasClassCategory2()) {
822
            $productName .= " - ".$ProductClass->getClassCategory2()->getName();
823
        }
824
825
        return $productName;
826
    }
827
828
829
    /**
830
     * 非公開商品の場合、カートから削除
831
     *
832
     * @param ProductClass $ProductClass
833
     * @return bool
834
     */
835
    private function isProductDisplay(ProductClass $ProductClass)
836
    {
837
838
        if ($ProductClass->getProduct()->getStatus()->getId() !== Disp::DISPLAY_SHOW) {
839
            // 非公開の商品はカートから削除
840
            $this->removeProduct($ProductClass->getId());
841
842
            return false;
843
        }
844
845
        return true;
846
    }
847
848
849
    /**
850
     * 在庫数と販売制限数のチェック
851
     * 在庫数または販売制限数以上の個数が設定されていれば、それぞれの個数にセットし、
852
     * 在庫数と販売制限数ともに個数が超えていれば、少ない方を適用させてメッセージを表示する
853
     *
854
     * @param ProductClass $ProductClass
855
     * @param $productName
856
     * @param $quantity
857
     * @return int チェック後に更新した個数
858
     */
859
    private function setProductLimit(ProductClass $ProductClass, $productName, $quantity)
860
    {
861
862
        /**
863
         * 実際の在庫は ProductClass::ProductStock だが、購入時にロックがかかるため、
864
         * ここでは ProductClass::stock で在庫のチェックをする
865
         */
866
867
        // 在庫数(在庫無制限の場合、null)
868
        $stock = $ProductClass->getStock();
869
        // 在庫無制限(在庫無制限の場合、1)
870
        $stockUnlimited = $ProductClass->getStockUnlimited();
871
872
        // 販売制限数(設定されていなければnull)
873
        $saleLimit = $ProductClass->getSaleLimit();
874
875
        if ($stockUnlimited) {
876
            // 在庫無制限
877
878
            if ($saleLimit && $saleLimit < $quantity) {
879
                // 販売制限数を超えていれば販売制限数をセット
880
                $this->addError('cart.over.sale_limit', $productName);
881
882
                return $saleLimit;
883
            }
884
        } else {
885
            // 在庫制限あり
886
887
            if ($stock < 1) {
888
                // 在庫がなければカートから削除
889
                $this->addError('cart.zero.stock', $productName);
890
                $this->removeProduct($ProductClass->getId());
891
892
                return 0;
893
            } else {
894
                // 在庫数チェックと販売制限数チェックどちらを適用するか設定
895
                $message = 'cart.over.stock';
896
                if ($saleLimit) {
897
                    if ($stock > $saleLimit) {
898
                        // 販売制限数チェック
899
                        $limit = $saleLimit;
900
                        $message = 'cart.over.sale_limit';
901
                    } else {
902
                        // 在庫数チェック
903
                        $limit = $stock;
904
                    }
905
                } else {
906
                    // 在庫数チェック
907
                    $limit = $stock;
908
                }
909
910
                if ($limit < $quantity) {
911
                    // 在庫数、販売制限数を超えていれば購入可能数までをセット
912
                    $this->addError($message, $productName);
913
914
                    return $limit;
915
                }
916
            }
917
        }
918
919
        return $quantity;
920
    }
921
922
    /**
923
     * @return \Eccube\Service\CartCompareService
924
     */
925
    public function generateCartCompareService()
0 ignored issues
show
introduced by
Declare public methods first, then protected ones and finally private ones
Loading history...
926
    {
927
        return $this->app['eccube.service.cart.compare']($this->getCart());
928
    }
929
}
930