Completed
Push — 4.0 ( 268f2c...88f012 )
by Hideki
05:48 queued 10s
created

src/Eccube/Controller/CartController.php (2 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
3
/*
4
 * This file is part of EC-CUBE
5
 *
6
 * Copyright(c) EC-CUBE CO.,LTD. All Rights Reserved.
7
 *
8
 * http://www.ec-cube.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\Controller;
15
16
use Eccube\Entity\BaseInfo;
17
use Eccube\Entity\ProductClass;
18
use Eccube\Event\EccubeEvents;
19
use Eccube\Event\EventArgs;
20
use Eccube\Repository\BaseInfoRepository;
21
use Eccube\Repository\ProductClassRepository;
22
use Eccube\Service\CartService;
23
use Eccube\Service\PurchaseFlow\PurchaseContext;
24
use Eccube\Service\PurchaseFlow\PurchaseFlow;
25
use Eccube\Service\PurchaseFlow\PurchaseFlowResult;
26
use Eccube\Service\OrderHelper;
27
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
28
use Symfony\Component\HttpFoundation\Request;
29
use Symfony\Component\Routing\Annotation\Route;
30
31
class CartController extends AbstractController
32
{
33
    /**
34
     * @var ProductClassRepository
35
     */
36
    protected $productClassRepository;
37
38
    /**
39
     * @var CartService
40
     */
41
    protected $cartService;
42
43
    /**
44
     * @var PurchaseFlow
45
     */
46
    protected $purchaseFlow;
47
48
    /**
49
     * @var BaseInfo
50
     */
51
    protected $baseInfo;
52
53
    /**
54
     * CartController constructor.
55
     *
56
     * @param ProductClassRepository $productClassRepository
57
     * @param CartService $cartService
58
     * @param PurchaseFlow $cartPurchaseFlow
59
     * @param BaseInfoRepository $baseInfoRepository
60
     */
61 View Code Duplication
    public function __construct(
62 77
        ProductClassRepository $productClassRepository,
63
        CartService $cartService,
64
        PurchaseFlow $cartPurchaseFlow,
65
        BaseInfoRepository $baseInfoRepository
66
    ) {
67
        $this->productClassRepository = $productClassRepository;
68 77
        $this->cartService = $cartService;
69 77
        $this->purchaseFlow = $cartPurchaseFlow;
70 77
        $this->baseInfo = $baseInfoRepository->get();
71 77
    }
72
73
    /**
74
     * カート画面.
75
     *
76
     * @Route("/cart", name="cart")
77
     * @Template("Cart/index.twig")
78
     */
79
    public function index(Request $request)
80 36
    {
81
        // カートを取得して明細の正規化を実行
82
        $Carts = $this->cartService->getCarts();
83 36
        $this->execPurchaseFlow($Carts);
84 36
85
        // TODO itemHolderから取得できるように
86
        $least = [];
87 36
        $quantity = [];
88 36
        $isDeliveryFree = [];
89 36
        $totalPrice = 0;
90 36
        $totalQuantity = 0;
91 36
92
        foreach ($Carts as $Cart) {
93 36
            $quantity[$Cart->getCartKey()] = 0;
94 35
            $isDeliveryFree[$Cart->getCartKey()] = false;
95 35
96
            if ($this->baseInfo->getDeliveryFreeQuantity()) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->baseInfo->getDeliveryFreeQuantity() of type integer|null is loosely compared to true; this is ambiguous if the integer can be zero. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
97 35
                if ($this->baseInfo->getDeliveryFreeQuantity() > $Cart->getQuantity()) {
98
                    $quantity[$Cart->getCartKey()] = $this->baseInfo->getDeliveryFreeQuantity() - $Cart->getQuantity();
99
                } else {
100
                    $isDeliveryFree[$Cart->getCartKey()] = true;
101
                }
102
            }
103
104
            if ($this->baseInfo->getDeliveryFreeAmount()) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->baseInfo->getDeliveryFreeAmount() of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
105 35
                if (!$isDeliveryFree[$Cart->getCartKey()] && $this->baseInfo->getDeliveryFreeAmount() <= $Cart->getTotalPrice()) {
106
                    $isDeliveryFree[$Cart->getCartKey()] = true;
107
                } else {
108
                    $least[$Cart->getCartKey()] = $this->baseInfo->getDeliveryFreeAmount() - $Cart->getTotalPrice();
109
                }
110
            }
111
112
            $totalPrice += $Cart->getTotalPrice();
113 35
            $totalQuantity += $Cart->getQuantity();
114 35
        }
115
116
        // カートが分割された時のセッション情報を削除
117
        $request->getSession()->remove(OrderHelper::SESSION_CART_DIVIDE_FLAG);
118 36
119
        return [
120
            'totalPrice' => $totalPrice,
121 36
            'totalQuantity' => $totalQuantity,
122 36
            // 空のカートを削除し取得し直す
123 36
            'Carts' => $this->cartService->getCarts(true),
124 36
            'least' => $least,
125 36
            'quantity' => $quantity,
126 36
            'is_delivery_free' => $isDeliveryFree,
127
        ];
128
    }
129
130
    /**
131
     * @param $Carts
132
     *
133
     * @return \Symfony\Component\HttpFoundation\RedirectResponse
134
     */
135
    protected function execPurchaseFlow($Carts)
136
    {
137
        /** @var PurchaseFlowResult[] $flowResults */
138 77
        $flowResults = array_map(function ($Cart) {
139 75
            $purchaseContext = new PurchaseContext($Cart, $this->getUser());
140
141 75
            return $this->purchaseFlow->validate($Cart, $purchaseContext);
142 77
        }, $Carts);
143
144
        // 復旧不可のエラーが発生した場合はカートをクリアして再描画
145 77
        $hasError = false;
146 77
        foreach ($flowResults as $result) {
147 75
            if ($result->hasError()) {
148 1
                $hasError = true;
149 1
                foreach ($result->getErrors() as $error) {
150 75
                    $this->addRequestError($error->getMessage());
151
                }
152
            }
153
        }
154 77
        if ($hasError) {
155 1
            $this->cartService->clear();
156
157 1
            return $this->redirectToRoute('cart');
158
        }
159
160 76
        $this->cartService->save();
161
162 76
        foreach ($flowResults as $index => $result) {
163 74
            foreach ($result->getWarning() as $warning) {
164 74
                if ($Carts[$index]->getItems()->count() > 0) {
165
                    $cart_key = $Carts[$index]->getCartKey();
166
                    $this->addRequestError($warning->getMessage(), "front.cart.${cart_key}");
167
                } else {
168
                    // キーが存在しない場合はグローバルにエラーを表示する
169
                    $this->addRequestError($warning->getMessage());
170
                }
171
            }
172
        }
173
    }
174
175
    /**
176
     * カート明細の加算/減算/削除を行う.
177
     *
178
     * - 加算
179
     *      - 明細の個数を1増やす
180
     * - 減算
181
     *      - 明細の個数を1減らす
182
     *      - 個数が0になる場合は、明細を削除する
183
     * - 削除
184
     *      - 明細を削除する
185
     *
186
     * @Route(
187
     *     path="/cart/{operation}/{productClassId}",
188
     *     name="cart_handle_item",
189
     *     methods={"PUT"},
190
     *     requirements={
191
     *          "operation": "up|down|remove",
192 51
     *          "productClassId": "\d+"
193
     *     }
194 51
     * )
195
     */
196
    public function handleCartItem($operation, $productClassId)
197 51
    {
198
        log_info('カート明細操作開始', ['operation' => $operation, 'product_class_id' => $productClassId]);
199 51
200
        $this->isTokenValid();
201
202
        /** @var ProductClass $ProductClass */
203
        $ProductClass = $this->productClassRepository->find($productClassId);
204
205
        if (is_null($ProductClass)) {
206 51
            log_info('商品が存在しないため、カート画面へredirect', ['operation' => $operation, 'product_class_id' => $productClassId]);
207
208 44
            return $this->redirectToRoute('cart');
209 44
        }
210
211 6
        // 明細の増減・削除
212 6
        switch ($operation) {
213
            case 'up':
214 1
                $this->cartService->addProduct($ProductClass, 1);
215 1
                break;
216
            case 'down':
217
                $this->cartService->addProduct($ProductClass, -1);
218
                break;
219 51
            case 'remove':
220 51
                $this->cartService->removeProduct($ProductClass);
221
                break;
222 51
        }
223
224 51
        // カートを取得して明細の正規化を実行
225
        $Carts = $this->cartService->getCarts();
226
        $this->execPurchaseFlow($Carts);
227
228
        log_info('カート演算処理終了', ['operation' => $operation, 'product_class_id' => $productClassId]);
229
230
        return $this->redirectToRoute('cart');
231
    }
232
233
    /**
234 53
     * カートをロック状態に設定し、購入確認画面へ遷移する.
235 53
     *
236
     * @Route("/cart/buystep/{cart_key}", name="cart_buystep", requirements={"cart_key" = "[a-zA-Z0-9]+[_][\x20-\x7E]+"})
237
     */
238
    public function buystep(Request $request, $cart_key)
239 53
    {
240 53
        $Carts = $this->cartService->getCart();
241 53
        if (!is_object($Carts)) {
242
            return $this->redirectToRoute('cart');
243 53
        }
244
        // FRONT_CART_BUYSTEP_INITIALIZE
245 53
        $event = new EventArgs(
246 53
            [],
247
            $request
248
        );
249 53
        $this->eventDispatcher->dispatch(EccubeEvents::FRONT_CART_BUYSTEP_INITIALIZE, $event);
250 53
251 53
        $this->cartService->setPrimary($cart_key);
252
        $this->cartService->save();
253 53
254
        // FRONT_CART_BUYSTEP_COMPLETE
255 53
        $event = new EventArgs(
256
            [],
257
            $request
258
        );
259 53
        $this->eventDispatcher->dispatch(EccubeEvents::FRONT_CART_BUYSTEP_COMPLETE, $event);
260
261
        if ($event->hasResponse()) {
262
            return $event->getResponse();
263
        }
264
265
        return $this->redirectToRoute('shopping');
266
    }
267
}
268