Completed
Pull Request — 4.0 (#4349)
by
unknown
05:01
created

ProductController   F

Complexity

Total Complexity 102

Size/Duplication

Total Lines 1056
Duplicated Lines 12.31 %

Coupling/Cohesion

Components 1
Dependencies 46

Test Coverage

Coverage 65.06%

Importance

Changes 0
Metric Value
dl 130
loc 1056
ccs 313
cts 481
cp 0.6506
rs 1.3759
c 0
b 0
f 0
wmc 102
lcom 1
cbo 46

11 Methods

Rating   Name   Duplication   Size   Complexity  
B loadProductClasses() 0 25 6
A __construct() 0 23 1
C index() 59 119 9
C addImage() 0 102 13
F edit() 28 313 36
C delete() 33 89 11
C copy() 0 96 10
A display() 0 14 2
C export() 0 101 8
A createProductCategory() 10 10 1
A bulkProductStatus() 0 32 5

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like ProductController often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use ProductController, and based on these observations, apply Extract Interface, too.

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\Admin\Product;
15
16
use Doctrine\DBAL\Exception\ForeignKeyConstraintViolationException;
17
use Eccube\Common\Constant;
18
use Eccube\Controller\AbstractController;
19
use Eccube\Entity\BaseInfo;
20
use Eccube\Entity\ExportCsvRow;
21
use Eccube\Entity\Master\CsvType;
22
use Eccube\Entity\Master\ProductStatus;
23
use Eccube\Entity\Product;
24
use Eccube\Entity\ProductCategory;
25
use Eccube\Entity\ProductClass;
26
use Eccube\Entity\ProductImage;
27
use Eccube\Entity\ProductStock;
28
use Eccube\Entity\ProductTag;
29
use Eccube\Event\EccubeEvents;
30
use Eccube\Event\EventArgs;
31
use Eccube\Form\Type\Admin\ProductType;
32
use Eccube\Form\Type\Admin\SearchProductType;
33
use Eccube\Repository\BaseInfoRepository;
34
use Eccube\Repository\CategoryRepository;
35
use Eccube\Repository\Master\PageMaxRepository;
36
use Eccube\Repository\Master\ProductStatusRepository;
37
use Eccube\Repository\ProductClassRepository;
38
use Eccube\Repository\ProductImageRepository;
39
use Eccube\Repository\ProductRepository;
40
use Eccube\Repository\TagRepository;
41
use Eccube\Repository\TaxRuleRepository;
42
use Eccube\Service\CsvExportService;
43
use Eccube\Util\CacheUtil;
44
use Eccube\Util\FormUtil;
45
use Knp\Component\Pager\Paginator;
46
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
47
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
48
use Symfony\Component\Filesystem\Filesystem;
49
use Symfony\Component\HttpFoundation\File\File;
50
use Symfony\Component\HttpFoundation\RedirectResponse;
51
use Symfony\Component\HttpFoundation\Request;
52
use Symfony\Component\HttpFoundation\StreamedResponse;
53
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
54
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
55
use Symfony\Component\HttpKernel\Exception\UnsupportedMediaTypeHttpException;
56
use Symfony\Component\Routing\Annotation\Route;
57
use Symfony\Component\Routing\RouterInterface;
58
59
class ProductController extends AbstractController
60
{
61
    /**
62
     * @var CsvExportService
63
     */
64
    protected $csvExportService;
65
66
    /**
67
     * @var ProductClassRepository
68
     */
69
    protected $productClassRepository;
70
71
    /**
72
     * @var ProductImageRepository
73
     */
74
    protected $productImageRepository;
75
76
    /**
77
     * @var TaxRuleRepository
78
     */
79
    protected $taxRuleRepository;
80
81
    /**
82
     * @var CategoryRepository
83
     */
84
    protected $categoryRepository;
85
86
    /**
87
     * @var ProductRepository
88
     */
89
    protected $productRepository;
90
91
    /**
92
     * @var BaseInfo
93
     */
94
    protected $BaseInfo;
95
96
    /**
97
     * @var PageMaxRepository
98
     */
99
    protected $pageMaxRepository;
100
101
    /**
102
     * @var ProductStatusRepository
103
     */
104
    protected $productStatusRepository;
105
106
    /**
107
     * @var TagRepository
108
     */
109
    protected $tagRepository;
110
111
    /**
112
     * ProductController constructor.
113
     *
114
     * @param CsvExportService $csvExportService
115
     * @param ProductClassRepository $productClassRepository
116
     * @param ProductImageRepository $productImageRepository
117
     * @param TaxRuleRepository $taxRuleRepository
118
     * @param CategoryRepository $categoryRepository
119
     * @param ProductRepository $productRepository
120
     * @param BaseInfoRepository $baseInfoRepository
121
     * @param PageMaxRepository $pageMaxRepository
122
     * @param ProductStatusRepository $productStatusRepository
123
     * @param TagRepository $tagRepository
124 26
     */
125
    public function __construct(
126
        CsvExportService $csvExportService,
127
        ProductClassRepository $productClassRepository,
128
        ProductImageRepository $productImageRepository,
129
        TaxRuleRepository $taxRuleRepository,
130
        CategoryRepository $categoryRepository,
131
        ProductRepository $productRepository,
132
        BaseInfoRepository $baseInfoRepository,
133
        PageMaxRepository $pageMaxRepository,
134
        ProductStatusRepository $productStatusRepository,
135
        TagRepository $tagRepository
136 26
    ) {
137 26
        $this->csvExportService = $csvExportService;
138 26
        $this->productClassRepository = $productClassRepository;
139 26
        $this->productImageRepository = $productImageRepository;
140 26
        $this->taxRuleRepository = $taxRuleRepository;
141 26
        $this->categoryRepository = $categoryRepository;
142 26
        $this->productRepository = $productRepository;
143 26
        $this->BaseInfo = $baseInfoRepository->get();
144 26
        $this->pageMaxRepository = $pageMaxRepository;
145 26
        $this->productStatusRepository = $productStatusRepository;
146
        $this->tagRepository = $tagRepository;
147
    }
148
149
    /**
150
     * @Route("/%eccube_admin_route%/product", name="admin_product")
151
     * @Route("/%eccube_admin_route%/product/page/{page_no}", requirements={"page_no" = "\d+"}, name="admin_product_page")
152
     * @Template("@admin/Product/index.twig")
153 4
     */
154
    public function index(Request $request, $page_no = null, Paginator $paginator)
155 4
    {
156 4
        $builder = $this->formFactory
157
            ->createBuilder(SearchProductType::class);
158 4
159
        $event = new EventArgs(
160 4
            [
161
                'builder' => $builder,
162 4
            ],
163
            $request
164 4
        );
165
        $this->eventDispatcher->dispatch(EccubeEvents::ADMIN_PRODUCT_INDEX_INITIALIZE, $event);
166 4
167
        $searchForm = $builder->getForm();
168
169
        /**
170
         * ページの表示件数は, 以下の順に優先される.
171
         * - リクエストパラメータ
172
         * - セッション
173
         * - デフォルト値
174
         * また, セッションに保存する際は mtb_page_maxと照合し, 一致した場合のみ保存する.
175 4
         **/
176 4
        $page_count = $this->session->get('eccube.admin.order.search.page_count',
177
            $this->eccubeConfig->get('eccube_default_page_count'));
178 4
179 4
        $page_count_param = (int) $request->get('page_count');
180
        $pageMaxis = $this->pageMaxRepository->findAll();
181 4
182 View Code Duplication
        if ($page_count_param) {
183
            foreach ($pageMaxis as $pageMax) {
184
                if ($page_count_param == $pageMax->getName()) {
185
                    $page_count = $pageMax->getName();
186
                    $this->session->set('eccube.admin.order.search.page_count', $page_count);
187
                    break;
188
                }
189
            }
190
        }
191 4
192 2
        if ('POST' === $request->getMethod()) {
193
            $searchForm->handleRequest($request);
194 2
195 View Code Duplication
            if ($searchForm->isValid()) {
196
                /**
197
                 * 検索が実行された場合は, セッションに検索条件を保存する.
198
                 * ページ番号は最初のページ番号に初期化する.
199 2
                 */
200 2
                $page_no = 1;
201
                $searchData = $searchForm->getData();
202
203 2
                // 検索条件, ページ番号をセッションに保持.
204 2
                $this->session->set('eccube.admin.product.search', FormUtil::getViewData($searchForm));
205
                $this->session->set('eccube.admin.product.search.page_no', $page_no);
206
            } else {
207
                // 検索エラーの際は, 詳細検索枠を開いてエラー表示する.
208 2
                return [
209
                    'searchForm' => $searchForm->createView(),
210
                    'pagination' => [],
211
                    'pageMaxis' => $pageMaxis,
212
                    'page_no' => $page_no,
213
                    'page_count' => $page_count,
214
                    'has_errors' => true,
215
                ];
216
            }
217 2 View Code Duplication
        } else {
218
            if (null !== $page_no || $request->get('resume')) {
219
                /*
220
                 * ページ送りの場合または、他画面から戻ってきた場合は, セッションから検索条件を復旧する.
221 1
                 */
222
                if ($page_no) {
223 1
                    // ページ送りで遷移した場合.
224
                    $this->session->set('eccube.admin.product.search.page_no', (int) $page_no);
225
                } else {
226
                    // 他画面から遷移した場合.
227
                    $page_no = $this->session->get('eccube.admin.product.search.page_no', 1);
228 1
                }
229 1
                $viewData = $this->session->get('eccube.admin.product.search', []);
230
                $searchData = FormUtil::submitAndGetData($searchForm, $viewData);
231
            } else {
232
                /**
233
                 * 初期表示の場合.
234 1
                 */
235
                $page_no = 1;
236 1
                // submit default value
237 1
                $viewData = FormUtil::getViewData($searchForm);
238
                $searchData = FormUtil::submitAndGetData($searchForm, $viewData);
239
240 1
                // セッション中の検索条件, ページ番号を初期化.
241 1
                $this->session->set('eccube.admin.product.search', $viewData);
242
                $this->session->set('eccube.admin.product.search.page_no', $page_no);
243
            }
244
        }
245 4
246
        $qb = $this->productRepository->getQueryBuilderBySearchDataForAdmin($searchData);
247 4
248
        $event = new EventArgs(
249 4
            [
250 4
                'qb' => $qb,
251
                'searchData' => $searchData,
252 4
            ],
253
            $request
254
        );
255 4
256
        $this->eventDispatcher->dispatch(EccubeEvents::ADMIN_PRODUCT_INDEX_SEARCH, $event);
257 4
258 4
        $pagination = $paginator->paginate(
259 4
            $qb,
260 4
            $page_no,
261
            $page_count
262
        );
263
264 4
        return [
265 4
            'searchForm' => $searchForm->createView(),
266 4
            'pagination' => $pagination,
267 4
            'pageMaxis' => $pageMaxis,
268 4
            'page_no' => $page_no,
269
            'page_count' => $page_count,
270
            'has_errors' => false,
271
        ];
272
    }
273
274
    /**
275
     * @Route("/%eccube_admin_route%/product/classes/{id}/load", name="admin_product_classes_load", methods={"GET"}, requirements={"id" = "\d+"})
276
     * @Template("@admin/Product/product_class_popup.twig")
277
     * @ParamConverter("Product")
278
     */
279 1
    public function loadProductClasses(Request $request, Product $Product)
280
    {
281 1
        if (!$request->isXmlHttpRequest()) {
282
            throw new BadRequestHttpException();
283
        }
284
285 1
        $data = [];
286
        /** @var $Product ProductRepository */
287 1
        if (!$Product) {
288
            throw new NotFoundHttpException();
289
        }
290
291 1
        if ($Product->hasProductClass()) {
0 ignored issues
show
Documentation Bug introduced by
The method hasProductClass does not exist on object<Eccube\Repository\ProductRepository>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
292 1
            $class = $Product->getProductClasses();
0 ignored issues
show
Documentation Bug introduced by
The method getProductClasses does not exist on object<Eccube\Repository\ProductRepository>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
293 1
            foreach ($class as $item) {
294 1
                if ($item['visible']) {
295 1
                    $data[] = $item;
296
                }
297
            }
298
        }
299
300
        return [
301 1
            'data' => $data,
302
        ];
303
    }
304
305
    /**
306
     * @Route("/%eccube_admin_route%/product/product/image/add", name="admin_product_image_add", methods={"POST"})
307
     */
308
    public function addImage(Request $request)
309
    {
310
        if (!$request->isXmlHttpRequest()) {
311
            throw new BadRequestHttpException();
312
        }
313
314
        $images = $request->files->get('admin_product');
315
316
        $allowExtensions = ['gif', 'jpg', 'jpeg', 'png'];
317
        $files = [];
318
        if (count($images) > 0) {
319
            foreach ($images as $img) {
320
                foreach ($img as $image) {
321
                    //ファイルフォーマット検証
322
                    $mimeType = $image->getMimeType();
323
                    if (0 !== strpos($mimeType, 'image')) {
324
                        throw new UnsupportedMediaTypeHttpException();
325
                    }
326
327
                    // 拡張子
328
                    $extension = $image->getClientOriginalExtension();
329
                    if (!in_array(strtolower($extension), $allowExtensions)) {
330
                        throw new UnsupportedMediaTypeHttpException();
331
                    }
332
333
						// 2019-10-07 Add Start
334
						// 加工前の画像の情報を取得
335
						list($origin_w, $origin_h, $type) = getimagesize($image);
336
337
						// 加工前のファイルをフォーマット別に読み出す
338
						switch ($type) {
339
							case IMAGETYPE_JPEG:
340
								$origin_image = imagecreatefromjpeg($image);
341
								break;
342
343
							case IMAGETYPE_PNG:
344
								$origin_image = imagecreatefrompng($image);
345
								break;
346
347
							case IMAGETYPE_GIF:
348
								$origin_image = imagecreatefromgif($image);
349
								break;
350
351
							default:
352
								throw new RuntimeException('対応していないファイル形式です。: ', $type);
353 18
						}
354
355 18
						// 新しく描画するキャンバスを作成
356 18
						$canvas = imagecreatetruecolor($origin_w, $origin_h);
357 5
						imagecopyresampled($canvas, $origin_image, 0,0,0,0, $origin_w, $origin_h, $origin_w, $origin_h);
358 5
359 5
						$filename = date('mdHis').uniqid('_').'.'.$extension;
360
						$files[] = $filename;
361 5
362 5
						// 保存先を指定
363
						$resize_path = $this->eccubeConfig['eccube_temp_image_dir'] . '/' . $filename;
364 5
365 5
						switch ($type) {
366 5
							case IMAGETYPE_JPEG:
367 5
								imagejpeg($canvas, $resize_path, 60);
368 5
								break;
369 5
370
							case IMAGETYPE_PNG:
371 13
								imagepng($canvas, $resize_path, 9);
372 13
								break;
373
374
							case IMAGETYPE_GIF:
375
								imagegif($canvas, $resize_path);
376 13
								break;
377 13
378 11
						}
379 11
380 11
						imagedestroy($origin_image);
381
						imagedestroy($canvas);
382
						// 2019-10-07 Add End
383 11
384 11
						/* 2019-10-08 Comment Out ↓
385 11
						// 拡張子
386
						$extension = $image->getClientOriginalExtension();
387
						if (!in_array(strtolower($extension), $allowExtensions)) {
388 11
							throw new UnsupportedMediaTypeHttpException();
389 6
						}
390
						$filename = date('mdHis').uniqid('_').'.'.$extension;
391 11
						$canvas->move($this->eccubeConfig['eccube_temp_image_dir'], $filename);
392
						$files[] = $filename;
393
						2019-10-08 Comment Out ↑ */
394
                }
395 18
            }
396 18
        }
397
398
        $event = new EventArgs(
399 18
            [
400 2
                'images' => $images,
401
                'files' => $files,
402
            ],
403 18
            $request
404
        );
405 18
        $this->eventDispatcher->dispatch(EccubeEvents::ADMIN_PRODUCT_ADD_IMAGE_COMPLETE, $event);
406 18
        $files = $event->getArgument('files');
407
408 18
        return $this->json(['files' => $files], 200);
409
    }
410 18
411
    /**
412 18
     * @Route("/%eccube_admin_route%/product/product/new", name="admin_product_product_new")
413
     * @Route("/%eccube_admin_route%/product/product/{id}/edit", requirements={"id" = "\d+"}, name="admin_product_product_edit")
414 18
     * @Template("@admin/Product/product.twig")
415 16
     */
416 16
    public function edit(Request $request, $id = null, RouterInterface $router, CacheUtil $cacheUtil)
417
    {
418
        $has_class = false;
419
        if (is_null($id)) {
420 18
            $Product = new Product();
421 18
            $ProductClass = new ProductClass();
422 18
            $ProductStatus = $this->productStatusRepository->find(ProductStatus::DISPLAY_HIDE);
423 13
            $Product
424
                ->addProductClass($ProductClass)
425 18
                ->setStatus($ProductStatus);
0 ignored issues
show
Bug introduced by
It seems like $ProductStatus defined by $this->productStatusRepo...ctStatus::DISPLAY_HIDE) on line 422 can also be of type object; however, Eccube\Entity\Product::setStatus() does only seem to accept null|object<Eccube\Entity\Master\ProductStatus>, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
426
            $ProductClass
427 18
                ->setVisible(true)
428 18
                ->setStockUnlimited(true)
429 18
                ->setProduct($Product);
430
            $ProductStock = new ProductStock();
431 13
            $ProductClass->setProductStock($ProductStock);
432
            $ProductStock->setProductClass($ProductClass);
433 18
        } else {
434
            $Product = $this->productRepository->find($id);
435 18
            if (!$Product) {
436 18
                throw new NotFoundHttpException();
437
            }
438 18
            // 規格無しの商品の場合は、デフォルト規格を表示用に取得する
439 13
            $has_class = $Product->hasProductClass();
440 13
            if (!$has_class) {
441 13
                $ProductClasses = $Product->getProductClasses();
442 13
                foreach ($ProductClasses as $pc) {
443
                    if (!is_null($pc->getClassCategory1())) {
444 13
                        continue;
445 13
                    }
446
                    if ($pc->isVisible()) {
447
                        $ProductClass = $pc;
448 13
                        break;
449 12
                    }
450 8
                }
451 4
                if ($this->BaseInfo->isOptionProductTaxRule() && $ProductClass->getTaxRule()) {
452
                    $ProductClass->setTaxRate($ProductClass->getTaxRule()->getTaxRate());
0 ignored issues
show
Bug introduced by
The variable $ProductClass does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
453 4
                }
454 4
                $ProductStock = $ProductClass->getProductStock();
455 4
            }
456 4
        }
457 4
458 4
        $builder = $this->formFactory
459
            ->createBuilder(ProductType::class, $Product);
460
461 8
        // 規格あり商品の場合、規格関連情報をFormから除外
462
        if ($has_class) {
463 4
            $builder->remove('class');
464 2
        }
465 2
466
        $event = new EventArgs(
467
            [
468
                'builder' => $builder,
469 13
                'Product' => $Product,
470
            ],
471
            $request
472 13
        );
473
        $this->eventDispatcher->dispatch(EccubeEvents::ADMIN_PRODUCT_EDIT_INITIALIZE, $event);
474
475
        $form = $builder->getForm();
476 13
477
        if (!$has_class) {
478 13
            $ProductClass->setStockUnlimited($ProductClass->isStockUnlimited());
479
            $form['class']->setData($ProductClass);
480
        }
481
482
        // ファイルの登録
483
        $images = [];
484 13
        $ProductImages = $Product->getProductImage();
485 10
        foreach ($ProductImages as $ProductImage) {
486 10
            $images[] = $ProductImage->getFileName();
487
        }
488 13
        $form['images']->setData($images);
489 13
490
        $categories = [];
491 13
        $ProductCategories = $Product->getProductCategories();
492 13
        foreach ($ProductCategories as $ProductCategory) {
493 13
            /* @var $ProductCategory \Eccube\Entity\ProductCategory */
494 13
            $categories[] = $ProductCategory->getCategory();
495
        }
496
        $form['Category']->setData($categories);
497
498
        $Tags = $Product->getTags();
499
        $form['Tag']->setData($Tags);
500
501
        if ('POST' === $request->getMethod()) {
502
            $form->handleRequest($request);
503
            if ($form->isValid()) {
504
                log_info('商品登録開始', [$id]);
505
                $Product = $form->getData();
506
507
                if (!$has_class) {
508
                    $ProductClass = $form['class']->getData();
509
510
                    // 個別消費税
511
                    if ($this->BaseInfo->isOptionProductTaxRule()) {
512
                        if ($ProductClass->getTaxRate() !== null) {
513
                            if ($ProductClass->getTaxRule()) {
514
                                $ProductClass->getTaxRule()->setTaxRate($ProductClass->getTaxRate());
515
                            } else {
516 13
                                $taxrule = $this->taxRuleRepository->newTaxRule();
517 13
                                $taxrule->setTaxRate($ProductClass->getTaxRate());
518
                                $taxrule->setApplyDate(new \DateTime());
519
                                $taxrule->setProduct($Product);
520
                                $taxrule->setProductClass($ProductClass);
521
                                $ProductClass->setTaxRule($taxrule);
522
                            }
523
524
                            $ProductClass->getTaxRule()->setTaxRate($ProductClass->getTaxRate());
525
                        } else {
526
                            if ($ProductClass->getTaxRule()) {
527
                                $this->taxRuleRepository->delete($ProductClass->getTaxRule());
528
                                $ProductClass->setTaxRule(null);
529
                            }
530
                        }
531
                    }
532 13
                    $this->entityManager->persist($ProductClass);
533 13
534
                    // 在庫情報を作成
535
                    if (!$ProductClass->isStockUnlimited()) {
536
                        $ProductStock->setStock($ProductClass->getStock());
0 ignored issues
show
Bug introduced by
The variable $ProductStock does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
537
                    } else {
538
                        // 在庫無制限時はnullを設定
539
                        $ProductStock->setStock(null);
540
                    }
541
                    $this->entityManager->persist($ProductStock);
542
                }
543
544
                // カテゴリの登録
545
                // 一度クリア
546
                /* @var $Product \Eccube\Entity\Product */
547
                foreach ($Product->getProductCategories() as $ProductCategory) {
548 13
                    $Product->removeProductCategory($ProductCategory);
549 13
                    $this->entityManager->remove($ProductCategory);
550
                }
551 13
                $this->entityManager->persist($Product);
552 13
                $this->entityManager->flush();
553
554
                $count = 1;
555
                $Categories = $form->get('Category')->getData();
556
                $categoriesIdList = [];
557
                foreach ($Categories as $Category) {
558 View Code Duplication
                    foreach ($Category->getPath() as $ParentCategory) {
559
                        if (!isset($categoriesIdList[$ParentCategory->getId()])) {
560
                            $ProductCategory = $this->createProductCategory($Product, $ParentCategory, $count);
561
                            $this->entityManager->persist($ProductCategory);
562
                            $count++;
563
                            /* @var $Product \Eccube\Entity\Product */
564 13
                            $Product->addProductCategory($ProductCategory);
565
                            $categoriesIdList[$ParentCategory->getId()] = true;
566
                        }
567
                    }
568 13
                    if (!isset($categoriesIdList[$Category->getId()])) {
569 13
                        $ProductCategory = $this->createProductCategory($Product, $Category, $count);
570 1
                        $this->entityManager->persist($ProductCategory);
571 1
                        $count++;
572
                        /* @var $Product \Eccube\Entity\Product */
573
                        $Product->addProductCategory($ProductCategory);
574
                        $categoriesIdList[$ParentCategory->getId()] = true;
0 ignored issues
show
Bug introduced by
The variable $ParentCategory seems to be defined by a foreach iteration on line 558. 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...
575 13
                    }
576 13
                }
577 13
578
                // 画像の登録
579 13
                $add_images = $form->get('add_images')->getData();
580 13
                foreach ($add_images as $add_image) {
581 13
                    $ProductImage = new \Eccube\Entity\ProductImage();
582 13
                    $ProductImage
583
                        ->setFileName($add_image)
584
                        ->setProduct($Product)
585 13
                        ->setSortNo(1);
586 13
                    $Product->addProductImage($ProductImage);
587
                    $this->entityManager->persist($ProductImage);
588 13
589
                    // 移動
590 13
                    $file = new File($this->eccubeConfig['eccube_temp_image_dir'].'/'.$add_image);
591
                    $file->move($this->eccubeConfig['eccube_save_image_dir']);
592 13
                }
593 13
594
                // 画像の削除
595 13
                $delete_images = $form->get('delete_images')->getData();
596
                foreach ($delete_images as $delete_image) {
597 13
                    $ProductImage = $this->productImageRepository
598
                        ->findOneBy(['file_name' => $delete_image]);
599 13
600
                    // 追加してすぐに削除した画像は、Entityに追加されない
601 13
                    if ($ProductImage instanceof ProductImage) {
602 1
                        $Product->removeProductImage($ProductImage);
603
                        $this->entityManager->remove($ProductImage);
604
                    }
605 13
                    $this->entityManager->persist($Product);
606
607
                    // 削除
608
                    $fs = new Filesystem();
609
                    $fs->remove($this->eccubeConfig['eccube_save_image_dir'].'/'.$delete_image);
610 5
                }
611 5
                $this->entityManager->persist($Product);
612
                $this->entityManager->flush();
613 5
614
                $sortNos = $request->get('sort_no_images');
615 5
                if ($sortNos) {
616 5
                    foreach ($sortNos as $sortNo) {
617
                        list($filename, $sortNo_val) = explode('//', $sortNo);
618 5
                        $ProductImage = $this->productImageRepository
619
                            ->findOneBy([
620 5
                                'file_name' => $filename,
621
                                'Product' => $Product,
622 5
                            ]);
623
                        $ProductImage->setSortNo($sortNo_val);
624 5
                        $this->entityManager->persist($ProductImage);
0 ignored issues
show
Bug introduced by
It seems like $ProductImage defined by $this->productImageRepos...'Product' => $Product)) on line 618 can also be of type null; however, Doctrine\Common\Persiste...bjectManager::persist() does only seem to accept object, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
625
                    }
626
                }
627
                $this->entityManager->flush();
628
629 5
                // 商品タグの登録
630
                // 商品タグを一度クリア
631
                $ProductTags = $Product->getProductTag();
632 5
                foreach ($ProductTags as $ProductTag) {
633 5
                    $Product->removeProductTag($ProductTag);
634 3
                    $this->entityManager->remove($ProductTag);
635 5
                }
636
637
                // 商品タグの登録
638 5
                $Tags = $form->get('Tag')->getData();
639 5
                foreach ($Tags as $Tag) {
640 5
                    $ProductTag = new ProductTag();
641 5
                    $ProductTag
642 5
                        ->setProduct($Product)
643 5
                        ->setTag($Tag);
644 5
                    $Product->addProductTag($ProductTag);
645 5
                    $this->entityManager->persist($ProductTag);
646 5
                }
647
648
                $Product->setUpdateDate(new \DateTime());
649
                $this->entityManager->flush();
650
651
                log_info('商品登録完了', [$id]);
652
653
                $event = new EventArgs(
654 1
                    [
655
                        'form' => $form,
656 1
                        'Product' => $Product,
657 1
                    ],
658 1
                    $request
659 1
                );
660 1
                $this->eventDispatcher->dispatch(EccubeEvents::ADMIN_PRODUCT_EDIT_COMPLETE, $event);
661 1
662
                $this->addSuccess('admin.common.save_complete', 'admin');
663 1
664 View Code Duplication
                if ($returnLink = $form->get('return_link')->getData()) {
665 1
                    try {
666 1
                        // $returnLinkはpathの形式で渡される. pathが存在するかをルータでチェックする.
667
                        $pattern = '/^'.preg_quote($request->getBasePath(), '/').'/';
668
                        $returnLink = preg_replace($pattern, '', $returnLink);
669
                        $result = $router->match($returnLink);
0 ignored issues
show
Bug introduced by
It seems like $returnLink defined by preg_replace($pattern, '', $returnLink) on line 668 can also be of type array<integer,string>; however, Symfony\Component\Routin...tcherInterface::match() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
670
                        // パラメータのみ抽出
671
                        $params = array_filter($result, function ($key) {
672
                            return 0 !== \strpos($key, '_');
673
                        }, ARRAY_FILTER_USE_KEY);
674
675
                        // pathからurlを再構築してリダイレクト.
676
                        return $this->redirectToRoute($result['_route'], $params);
677
                    } catch (\Exception $e) {
678
                        // マッチしない場合はログ出力してスキップ.
679 1
                        log_warning('URLの形式が不正です。');
680 1
                    }
681
                }
682 1
683 1
                $cacheUtil->clearDoctrineCache();
684
685
                return $this->redirectToRoute('admin_product_product_edit', ['id' => $Product->getId()]);
686 1
            }
687 1
        }
688
689 1
        // 検索結果の保持
690
        $builder = $this->formFactory
691 1
            ->createBuilder(SearchProductType::class);
692 1
693 1
        $event = new EventArgs(
694
            [
695 1
                'builder' => $builder,
696
                'Product' => $Product,
697 1
            ],
698 1
            $request
699
        );
700
        $this->eventDispatcher->dispatch(EccubeEvents::ADMIN_PRODUCT_EDIT_SEARCH, $event);
701 1
702
        $searchForm = $builder->getForm();
703 1
704 1
        if ('POST' === $request->getMethod()) {
705 1
            $searchForm->handleRequest($request);
706
        }
707
708
        // Get Tags
709
        $TagsList = $this->tagRepository->getList();
710 1
711
        // ツリー表示のため、ルートからのカテゴリを取得
712 1
        $TopCategories = $this->categoryRepository->getList(null);
713 1
        $ChoicedCategoryIds = array_map(function ($Category) {
714
            return $Category->getId();
715
        }, $form->get('Category')->getData());
716 1
717
        return [
718
            'Product' => $Product,
719
            'Tags' => $Tags,
720 1
            'TagsList' => $TagsList,
721
            'form' => $form->createView(),
722
            'searchForm' => $searchForm->createView(),
723
            'has_class' => $has_class,
724
            'id' => $id,
725
            'TopCategories' => $TopCategories,
726
            'ChoicedCategoryIds' => $ChoicedCategoryIds,
727 1
        ];
728
    }
729
730 1
    /**
731 1
     * @Route("/%eccube_admin_route%/product/product/{id}/delete", requirements={"id" = "\d+"}, name="admin_product_product_delete", methods={"DELETE"})
732
     */
733
    public function delete(Request $request, $id = null, CacheUtil $cacheUtil)
734
    {
735
        $this->isTokenValid();
736 1
        $session = $request->getSession();
737
        $page_no = intval($session->get('eccube.admin.product.search.page_no'));
738 1
        $page_no = $page_no ? $page_no : Constant::ENABLED;
739
        $message = null;
740
        $success = false;
741
742
        if (!is_null($id)) {
743
            /* @var $Product \Eccube\Entity\Product */
744
            $Product = $this->productRepository->find($id);
745 View Code Duplication
            if (!$Product) {
746 1
                if ($request->isXmlHttpRequest()) {
747
                    $message = trans('admin.common.delete_error_already_deleted');
748 1
749
                    return $this->json(['success' => $success, 'message' => $message]);
750 1
                } else {
751 1
                    $this->deleteMessage();
752 1
                    $rUrl = $this->generateUrl('admin_product_page', ['page_no' => $page_no]).'?resume='.Constant::ENABLED;
753 1
754 1
                    return $this->redirect($rUrl);
755 1
                }
756 1
            }
757
758 1
            if ($Product instanceof Product) {
759 1
                log_info('商品削除開始', [$id]);
760 1
761
                $deleteImages = $Product->getProductImage();
762
                $ProductClasses = $Product->getProductClasses();
763
764 1
                try {
765 1
                    $this->productRepository->delete($Product);
766 1
                    $this->entityManager->flush();
767
768
                    $event = new EventArgs(
769 1
                        [
770
                            'Product' => $Product,
771 1
                            'ProductClass' => $ProductClasses,
772 1
                            'deleteImages' => $deleteImages,
773 1
                        ],
774
                        $request
775
                    );
776 1
                    $this->eventDispatcher->dispatch(EccubeEvents::ADMIN_PRODUCT_DELETE_COMPLETE, $event);
777 1
                    $deleteImages = $event->getArgument('deleteImages');
778 1
779 1
                    // 画像ファイルの削除(commit後に削除させる)
780 1 View Code Duplication
                    foreach ($deleteImages as $deleteImage) {
781 1
                        try {
782
                            $fs = new Filesystem();
783 1
                            $fs->remove($this->eccubeConfig['eccube_save_image_dir'].'/'.$deleteImage);
784 1
                        } catch (\Exception $e) {
785
                            // エラーが発生しても無視する
786
                        }
787
                    }
788
789
                    log_info('商品削除完了', [$id]);
790 1
791
                    $success = true;
792 1
                    $message = trans('admin.common.delete_complete');
793 1
794
                    $cacheUtil->clearDoctrineCache();
795 1
                } catch (ForeignKeyConstraintViolationException $e) {
796 1
                    log_info('商品削除エラー', [$id]);
797
                    $message = trans('admin.common.delete_error_foreign_key', ['%name%' => $Product->getName()]);
798 1
                }
799 1
            } else {
800 1
                log_info('商品削除エラー', [$id]);
801
                $message = trans('admin.common.delete_error');
802
            }
803 1
        } else {
804
            log_info('商品削除エラー', [$id]);
805 1
            $message = trans('admin.common.delete_error');
806
        }
807 1
808 1 View Code Duplication
        if ($request->isXmlHttpRequest()) {
809
            return $this->json(['success' => $success, 'message' => $message]);
810
        } else {
811
            if ($success) {
812 1
                $this->addSuccess($message, 'admin');
813
            } else {
814 1
                $this->addError($message, 'admin');
815
            }
816 1
817
            $rUrl = $this->generateUrl('admin_product_page', ['page_no' => $page_no]).'?resume='.Constant::ENABLED;
818 1
819 1
            return $this->redirect($rUrl);
820 1
        }
821 1
    }
822 1
823 1
    /**
824
     * @Route("/%eccube_admin_route%/product/product/{id}/copy", requirements={"id" = "\d+"}, name="admin_product_product_copy", methods={"POST"})
825 1
     */
826
    public function copy(Request $request, $id = null)
827 1
    {
828
        $this->isTokenValid();
829 1
830
        if (!is_null($id)) {
831 1
            $Product = $this->productRepository->find($id);
832
            if ($Product instanceof Product) {
833
                $CopyProduct = clone $Product;
834
                $CopyProduct->copy();
835
                $ProductStatus = $this->productStatusRepository->find(ProductStatus::DISPLAY_HIDE);
836
                $CopyProduct->setStatus($ProductStatus);
0 ignored issues
show
Bug introduced by
It seems like $ProductStatus defined by $this->productStatusRepo...ctStatus::DISPLAY_HIDE) on line 835 can also be of type object; however, Eccube\Entity\Product::setStatus() does only seem to accept null|object<Eccube\Entity\Master\ProductStatus>, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
837
838
                $CopyProductCategories = $CopyProduct->getProductCategories();
839
                foreach ($CopyProductCategories as $Category) {
840
                    $this->entityManager->persist($Category);
841
                }
842
843
                // 規格あり商品の場合は, デフォルトの商品規格を取得し登録する.
844
                if ($CopyProduct->hasProductClass()) {
845
                    $dummyClass = $this->productClassRepository->findOneBy([
846
                        'visible' => false,
847
                        'ClassCategory1' => null,
848
                        'ClassCategory2' => null,
849
                        'Product' => $Product,
850
                    ]);
851
                    $dummyClass = clone $dummyClass;
852
                    $dummyClass->setProduct($CopyProduct);
853
                    $CopyProduct->addProductClass($dummyClass);
854
                }
855
856
                $CopyProductClasses = $CopyProduct->getProductClasses();
857
                foreach ($CopyProductClasses as $Class) {
858
                    $Stock = $Class->getProductStock();
859
                    $CopyStock = clone $Stock;
860
                    $CopyStock->setProductClass($Class);
861
                    $this->entityManager->persist($CopyStock);
862
863
                    $TaxRule = $Class->getTaxRule();
864
                    if ($TaxRule) {
865
                        $CopyTaxRule = clone $TaxRule;
866
                        $CopyTaxRule->setProductClass($Class);
867
                        $CopyTaxRule->setProduct($CopyProduct);
868
                        $this->entityManager->persist($CopyTaxRule);
869
                    }
870
                    $this->entityManager->persist($Class);
871
                }
872
                $Images = $CopyProduct->getProductImage();
873
                foreach ($Images as $Image) {
874
                    // 画像ファイルを新規作成
875
                    $extension = pathinfo($Image->getFileName(), PATHINFO_EXTENSION);
876
                    $filename = date('mdHis').uniqid('_').'.'.$extension;
877
                    try {
878
                        $fs = new Filesystem();
879
                        $fs->copy($this->eccubeConfig['eccube_save_image_dir'].'/'.$Image->getFileName(), $this->eccubeConfig['eccube_save_image_dir'].'/'.$filename);
880
                    } catch (\Exception $e) {
881
                        // エラーが発生しても無視する
882
                    }
883
                    $Image->setFileName($filename);
884
885
                    $this->entityManager->persist($Image);
886
                }
887
                $Tags = $CopyProduct->getProductTag();
888
                foreach ($Tags as $Tag) {
889
                    $this->entityManager->persist($Tag);
890
                }
891
892
                $this->entityManager->persist($CopyProduct);
893
894
                $this->entityManager->flush();
895
896
                $event = new EventArgs(
897
                    [
898
                        'Product' => $Product,
899
                        'CopyProduct' => $CopyProduct,
900
                        'CopyProductCategories' => $CopyProductCategories,
901
                        'CopyProductClasses' => $CopyProductClasses,
902
                        'images' => $Images,
903
                        'Tags' => $Tags,
904
                    ],
905
                    $request
906
                );
907
                $this->eventDispatcher->dispatch(EccubeEvents::ADMIN_PRODUCT_COPY_COMPLETE, $event);
908
909
                $this->addSuccess('admin.product.copy_complete', 'admin');
910
911
                return $this->redirectToRoute('admin_product_product_edit', ['id' => $CopyProduct->getId()]);
912
            } else {
913
                $this->addError('admin.product.copy_error', 'admin');
914
            }
915
        } else {
916
            $msg = trans('admin.product.copy_error');
917
            $this->addError($msg, 'admin');
918
        }
919
920
        return $this->redirectToRoute('admin_product');
921
    }
922
923
    /**
924
     * @Route("/%eccube_admin_route%/product/product/{id}/display", requirements={"id" = "\d+"}, name="admin_product_product_display")
925
     */
926
    public function display(Request $request, $id = null)
927
    {
928
        $event = new EventArgs(
929
            [],
930
            $request
931
        );
932
        $this->eventDispatcher->dispatch(EccubeEvents::ADMIN_PRODUCT_DISPLAY_COMPLETE, $event);
933
934
        if (!is_null($id)) {
935
            return $this->redirectToRoute('product_detail', ['id' => $id, 'admin' => '1']);
936
        }
937
938
        return $this->redirectToRoute('admin_product');
939
    }
940
941
    /**
942
     * 商品CSVの出力.
943
     *
944
     * @Route("/%eccube_admin_route%/product/export", name="admin_product_export")
945
     *
946
     * @param Request $request
947
     *
948
     * @return StreamedResponse
949
     */
950
    public function export(Request $request)
951
    {
952
        // タイムアウトを無効にする.
953
        set_time_limit(0);
954
955
        // sql loggerを無効にする.
956
        $em = $this->entityManager;
957
        $em->getConfiguration()->setSQLLogger(null);
958
959
        $response = new StreamedResponse();
960
        $response->setCallback(function () use ($request) {
961
            // CSV種別を元に初期化.
962
            $this->csvExportService->initCsvType(CsvType::CSV_TYPE_PRODUCT);
963
964
            // ヘッダ行の出力.
965
            $this->csvExportService->exportHeader();
966
967
            // 商品データ検索用のクエリビルダを取得.
968
            $qb = $this->csvExportService
969
                ->getProductQueryBuilder($request);
970
971
            // Get stock status
972
            $isOutOfStock = 0;
973
            $session = $request->getSession();
974
            if ($session->has('eccube.admin.product.search')) {
975
                $searchData = $session->get('eccube.admin.product.search', []);
976
                if (isset($searchData['stock_status']) && $searchData['stock_status'] === 0) {
977
                    $isOutOfStock = 1;
978
                }
979
            }
980
981
            // joinする場合はiterateが使えないため, select句をdistinctする.
982
            // http://qiita.com/suin/items/2b1e98105fa3ef89beb7
983
            // distinctのmysqlとpgsqlの挙動をあわせる.
984
            // http://uedatakeshi.blogspot.jp/2010/04/distinct-oeder-by-postgresmysql.html
985
            $qb->resetDQLPart('select')
986
                ->resetDQLPart('orderBy')
987
                ->orderBy('p.update_date', 'DESC');
988
989
            if ($isOutOfStock) {
990
                $qb->select('p, pc')
991
                    ->distinct();
992
            } else {
993
                $qb->select('p')
994
                    ->distinct();
995
            }
996
            // データ行の出力.
997
            $this->csvExportService->setExportQueryBuilder($qb);
998
999
            $this->csvExportService->exportData(function ($entity, CsvExportService $csvService) use ($request) {
1000
                $Csvs = $csvService->getCsvs();
1001
1002
                /** @var $Product \Eccube\Entity\Product */
1003
                $Product = $entity;
1004 1
1005
                /** @var $ProductClasses \Eccube\Entity\ProductClass[] */
1006 1
                $ProductClasses = $Product->getProductClasses();
1007
1008
                foreach ($ProductClasses as $ProductClass) {
1009 1
                    $ExportCsvRow = new ExportCsvRow();
1010 1
1011 1
                    // CSV出力項目と合致するデータを取得.
1012
                    foreach ($Csvs as $Csv) {
1013 1
                        // 商品データを検索.
1014 1
                        $ExportCsvRow->setData($csvService->getData($Csv, $Product));
1015 1
                        if ($ExportCsvRow->isDataNull()) {
1016
                            // 商品規格情報を検索.
1017 1
                            $ExportCsvRow->setData($csvService->getData($Csv, $ProductClass));
1018
                        }
1019
1020
                        $event = new EventArgs(
1021 1
                            [
1022 1
                                'csvService' => $csvService,
1023 1
                                'Csv' => $Csv,
1024 1
                                'ProductClass' => $ProductClass,
1025 1
                                'ExportCsvRow' => $ExportCsvRow,
1026
                            ],
1027 1
                            $request
1028
                        );
1029
                        $this->eventDispatcher->dispatch(EccubeEvents::ADMIN_PRODUCT_CSV_EXPORT, $event);
1030
1031
                        $ExportCsvRow->pushData();
1032
                    }
1033 1
1034
                    // $row[] = number_format(memory_get_usage(true));
1035
                    // 出力.
1036
                    $csvService->fputcsv($ExportCsvRow->getRow());
1037
                }
1038
            });
1039
        });
1040
1041
        $now = new \DateTime();
1042
        $filename = 'product_'.$now->format('YmdHis').'.csv';
1043
        $response->headers->set('Content-Type', 'application/octet-stream');
1044
        $response->headers->set('Content-Disposition', 'attachment; filename='.$filename);
1045
        $response->send();
1046
1047
        log_info('商品CSV出力ファイル名', [$filename]);
1048
1049
        return $response;
1050
    }
1051
1052
    /**
1053
     * ProductCategory作成
1054
     *
1055
     * @param \Eccube\Entity\Product $Product
1056
     * @param \Eccube\Entity\Category $Category
1057
     * @param integer $count
1058
     *
1059
     * @return \Eccube\Entity\ProductCategory
1060
     */
1061 View Code Duplication
    private function createProductCategory($Product, $Category, $count)
0 ignored issues
show
Unused Code introduced by
The parameter $count is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Duplication introduced by
This method seems to be duplicated in 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...
1062
    {
1063
        $ProductCategory = new ProductCategory();
1064
        $ProductCategory->setProduct($Product);
1065
        $ProductCategory->setProductId($Product->getId());
1066
        $ProductCategory->setCategory($Category);
1067
        $ProductCategory->setCategoryId($Category->getId());
1068
1069
        return $ProductCategory;
1070
    }
1071
1072
    /**
1073
     * Bulk public action
1074
     *
1075
     * @Route("/%eccube_admin_route%/product/bulk/product-status/{id}", requirements={"id" = "\d+"}, name="admin_product_bulk_product_status", methods={"POST"})
1076
     *
1077
     * @param Request $request
1078
     * @param ProductStatus $ProductStatus
1079
     *
1080
     * @return RedirectResponse
1081
     */
1082
    public function bulkProductStatus(Request $request, ProductStatus $ProductStatus, CacheUtil $cacheUtil)
1083
    {
1084
        $this->isTokenValid();
1085
1086
        /** @var Product[] $Products */
1087
        $Products = $this->productRepository->findBy(['id' => $request->get('ids')]);
1088
        $count = 0;
1089
        foreach ($Products as $Product) {
1090
            try {
1091
                $Product->setStatus($ProductStatus);
1092
                $this->productRepository->save($Product);
1093
                $count++;
1094
            } catch (\Exception $e) {
1095
                $this->addError($e->getMessage(), 'admin');
1096
            }
1097
        }
1098
        try {
1099
            if ($count) {
1100
                $this->entityManager->flush();
1101
                $msg = $this->translator->trans('admin.product.bulk_change_status_complete', [
1102
                    '%count%' => $count,
1103
                    '%status%' => $ProductStatus->getName(),
1104
                ]);
1105
                $this->addSuccess($msg, 'admin');
1106
                $cacheUtil->clearDoctrineCache();
1107
            }
1108
        } catch (\Exception $e) {
1109
            $this->addError($e->getMessage(), 'admin');
1110
        }
1111
1112
        return $this->redirectToRoute('admin_product', ['resume' => Constant::ENABLED]);
1113
    }
1114
}
1115