ProductController   F
last analyzed

Complexity

Total Complexity 89

Size/Duplication

Total Lines 824
Duplicated Lines 13.35 %

Coupling/Cohesion

Components 0
Dependencies 14

Test Coverage

Coverage 74.29%

Importance

Changes 0
Metric Value
dl 110
loc 824
rs 1.263
c 0
b 0
f 0
ccs 26
cts 35
cp 0.7429
wmc 89
lcom 0
cbo 14

8 Methods

Rating   Name   Duplication   Size   Complexity  
D index() 24 164 16
B addImage() 0 38 6
F edit() 31 286 35
C delete() 4 92 12
C copy() 0 94 9
A display() 0 14 2
C export() 40 102 8
A createProductCategory() 11 11 1

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
 * 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\Controller\Admin\Product;
26
27
use Eccube\Application;
28
use Eccube\Common\Constant;
29
use Eccube\Controller\AbstractController;
30
use Eccube\Entity\Master\CsvType;
31
use Eccube\Entity\ProductTag;
32
use Eccube\Event\EccubeEvents;
33
use Eccube\Event\EventArgs;
34
use Eccube\Service\CsvExportService;
35
use Eccube\Util\FormUtil;
36
use Symfony\Component\Filesystem\Filesystem;
37
use Symfony\Component\HttpFoundation\File\File;
38
use Symfony\Component\HttpFoundation\Request;
39 1
use Symfony\Component\HttpFoundation\StreamedResponse;
40
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
41
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
42
use Symfony\Component\HttpKernel\Exception\UnsupportedMediaTypeHttpException;
43
44
class ProductController extends AbstractController
0 ignored issues
show
introduced by
Missing class doc comment
Loading history...
45
{
46
    public function index(Application $app, Request $request, $page_no = null)
0 ignored issues
show
introduced by
Missing function doc comment
Loading history...
47
    {
48 1
49
        $session = $app['session'];
50
51
        $builder = $app['form.factory']
52
            ->createBuilder('admin_search_product');
53 1
54 1
        $event = new EventArgs(
55
            array(
56
                'builder' => $builder,
57
            ),
58
            $request
59
        );
60
        $app['eccube.event.dispatcher']->dispatch(EccubeEvents::ADMIN_PRODUCT_INDEX_INITIALIZE, $event);
61
62
        $searchForm = $builder->getForm();
63
64
        $pagination = array();
65
66
        $disps = $app['eccube.repository.master.disp']->findAll();
67
        $pageMaxis = $app['eccube.repository.master.page_max']->findAll();
68
69
        // 表示件数は順番で取得する、1.SESSION 2.設定ファイル
70
        $page_count = $session->get('eccube.admin.product.search.page_count', $app['config']['default_page_count']);
71
        // 表示件数
72
73
        $page_count_param = $request->get('page_count');
74
        // 表示件数はURLパラメターから取得する
75 View Code Duplication
        if ($page_count_param && is_numeric($page_count_param)) {
76
            foreach ($pageMaxis as $pageMax) {
77
                if ($page_count_param == $pageMax->getName()) {
78
                    $page_count = $pageMax->getName();
79
                    // 表示件数入力値正し場合はSESSIONに保存する
80
                    $session->set('eccube.admin.product.search.page_count', $page_count);
81
                    break;
82
                }
83
            }
84
        }
85
86
        $page_status = null;
87
        $active = false;
88
89
        if ('POST' === $request->getMethod()) {
0 ignored issues
show
Coding Style introduced by
Blank line found at start of control structure
Loading history...
90
91
            $searchForm->handleRequest($request);
92
93
            if ($searchForm->isValid()) {
94
                $searchData = $searchForm->getData();
95
96
                // paginator
97
                $qb = $app['eccube.repository.product']->getQueryBuilderBySearchDataForAdmin($searchData);
98
                $page_no = 1;
99
100
                $event = new EventArgs(
101
                    array(
102
                        'qb' => $qb,
103
                        'searchData' => $searchData,
104
                    ),
105
                    $request
106
                );
107
                $app['eccube.event.dispatcher']->dispatch(EccubeEvents::ADMIN_PRODUCT_INDEX_SEARCH, $event);
108
                $searchData = $event->getArgument('searchData');
0 ignored issues
show
Unused Code introduced by
$searchData is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
109
110
                $pagination = $app['paginator']()->paginate(
111
                    $qb,
112
                    $page_no,
113
                    $page_count,
114
                    array('wrap-queries' => true)
115
                );
116
117
                // sessionに検索条件を保持
118
                $viewData = FormUtil::getViewData($searchForm);
119
                $session->set('eccube.admin.product.search', $viewData);
120
                $session->set('eccube.admin.product.search.page_no', $page_no);
121
            }
122
        } else {
123
            if (is_null($page_no) && $request->get('resume') != Constant::ENABLED) {
124
                // sessionを削除
125
                $session->remove('eccube.admin.product.search');
126
                $session->remove('eccube.admin.product.search.page_no');
127
                $session->remove('eccube.admin.product.search.page_count');
128
            } else {
129
                // pagingなどの処理
130 1
                if (is_null($page_no)) {
131
                    $page_no = intval($session->get('eccube.admin.product.search.page_no'));
132
                } else {
133 1
                    $session->set('eccube.admin.product.search.page_no', $page_no);
134 1
                }
135
                $viewData = $session->get('eccube.admin.product.search');
136
                if (!is_null($viewData)) {
137
                    // 公開ステータス
138
                    // 1:公開, 2:非公開, 3:在庫なし
0 ignored issues
show
Unused Code Comprehensibility introduced by
58% 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...
139
                    $linkStatus = $request->get('status');
140
                    if (!empty($linkStatus)) {
141
                        // リンクステータスは在庫なし:3以外
142
                        if ($linkStatus != $app['config']['admin_product_stock_status']) {
143 1
                            $viewData['link_status'] = $linkStatus;
144
                            $viewData['stock_status'] = null;
145
                            $viewData['status'] = null;
146 View Code Duplication
                        } else {
147
                            // リンクステータスは在庫なし:3
148
                            $viewData['link_status'] = null;
149
                            $viewData['stock_status'] = Constant::DISABLED;
150
                            $viewData['status'] = null;
151
                        }
152
                        // ページステータスを設定します(リンクステータスAタグ表示のために)
153
                        $page_status = $linkStatus;
154 View Code Duplication
                    } else {
155
                        // すべてを選択
156
                        $viewData['link_status'] = null;
157
                        $viewData['stock_status'] = null;
158
                        if (!$viewData['status']) {
159
                            $viewData['status'] = array();
160
                        }
161
                    }
162
163
                    // 表示件数
164 2
                    $page_count = $request->get('page_count', $page_count);
165
                    $searchData = FormUtil::submitAndGetData($searchForm, $viewData);
166
                    if ($viewData['link_status']) {
167
                        $searchData['link_status'] = $app['eccube.repository.master.disp']->find($viewData['link_status']);
168
                    }
169
                    // リンクステータス[在庫なし]設定されている場合は検索パラメター設定する
170
                    if (isset($viewData['stock_status'])) {
171
                        $searchData['stock_status'] = $viewData['stock_status'];
172 2
                    }
173
174
                    $session->set('eccube.admin.product.search', $viewData);
175
176
                    $qb = $app['eccube.repository.product']->getQueryBuilderBySearchDataForAdmin($searchData);
177
178 1
                    $event = new EventArgs(
179 1
                        array(
180
                            'qb' => $qb,
181
                            'searchData' => $searchData,
182 1
                        ),
183 1
                        $request
184
                    );
185
                    $app['eccube.event.dispatcher']->dispatch(EccubeEvents::ADMIN_PRODUCT_INDEX_SEARCH, $event);
186
                    $searchData = $event->getArgument('searchData');
0 ignored issues
show
Unused Code introduced by
$searchData is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
187
188
189
                    $pagination = $app['paginator']()->paginate(
190 1
                        $qb,
191
                        $page_no,
192
                        $page_count,
193
                        array('wrap-queries' => true)
194
                    );
195 1
                }
196
            }
197
        }
198
199
        return $app->render('Product/index.twig', array(
200
            'searchForm' => $searchForm->createView(),
201
            'pagination' => $pagination,
202
            'disps' => $disps,
203
            'pageMaxis' => $pageMaxis,
204 1
            'page_no' => $page_no,
205
            'page_status' => $page_status,
206
            'page_count' => $page_count,
207
            'active' => $active,
208
        ));
209
    }
210 2
211
    public function addImage(Application $app, Request $request)
0 ignored issues
show
introduced by
Missing function doc comment
Loading history...
212
    {
213
        if (!$request->isXmlHttpRequest()) {
214
            throw new BadRequestHttpException('リクエストが不正です');
215 2
        }
216
217
        $images = $request->files->get('admin_product');
218
219
        $files = array();
220
        if (count($images) > 0) {
221 2
            foreach ($images as $img) {
222
                foreach ($img as $image) {
223
                    //ファイルフォーマット検証
224
                    $mimeType = $image->getMimeType();
225 1
                    if (0 !== strpos($mimeType, 'image')) {
226
                        throw new UnsupportedMediaTypeHttpException('ファイル形式が不正です');
227
                    }
228 2
229
                    $extension = $image->getClientOriginalExtension();
230
                    $filename = date('mdHis').uniqid('_').'.'.$extension;
231
                    $image->move($app['config']['image_temp_realdir'], $filename);
232
                    $files[] = $filename;
233 1
                }
234
            }
235
        }
236
237
        $event = new EventArgs(
238
            array(
239
                'images' => $images,
240
                'files' => $files,
241
            ),
242
            $request
243
        );
244
        $app['eccube.event.dispatcher']->dispatch(EccubeEvents::ADMIN_PRODUCT_ADD_IMAGE_COMPLETE, $event);
245
        $files = $event->getArgument('files');
246
247
        return $app->json(array('files' => $files), 200);
248
    }
249
250
    public function edit(Application $app, Request $request, $id = null)
0 ignored issues
show
introduced by
Missing function doc comment
Loading history...
251
    {
252
        $has_class = false;
253
        if (is_null($id)) {
254
            $Product = new \Eccube\Entity\Product();
255
            $ProductClass = new \Eccube\Entity\ProductClass();
256
            $Disp = $app['eccube.repository.master.disp']->find(\Eccube\Entity\Master\Disp::DISPLAY_HIDE);
257
            $Product
258
                ->setDelFlg(Constant::DISABLED)
259
                ->addProductClass($ProductClass)
260
                ->setStatus($Disp);
261
            $ProductClass
262
                ->setDelFlg(Constant::DISABLED)
263
                ->setStockUnlimited(true)
264
                ->setProduct($Product);
265
            $ProductStock = new \Eccube\Entity\ProductStock();
266
            $ProductClass->setProductStock($ProductStock);
267
            $ProductStock->setProductClass($ProductClass);
268
        } else {
269
            $Product = $app['eccube.repository.product']->find($id);
270
            if (!$Product) {
271
                throw new NotFoundHttpException();
272
            }
273
            // 規格あり商品か
274
            $has_class = $Product->hasProductClass();
275
            if (!$has_class) {
276
                $ProductClasses = $Product->getProductClasses();
277
                $ProductClass = $ProductClasses[0];
278
                $BaseInfo = $app['eccube.repository.base_info']->get();
279 View Code Duplication
                if ($BaseInfo->getOptionProductTaxRule() == Constant::ENABLED && $ProductClass->getTaxRule() && !$ProductClass->getTaxRule()->getDelFlg()) {
280
                    $ProductClass->setTaxRate($ProductClass->getTaxRule()->getTaxRate());
281
                }
282
                $ProductStock = $ProductClasses[0]->getProductStock();
283
            }
284
        }
285
286
        $builder = $app['form.factory']
287
            ->createBuilder('admin_product', $Product);
288
289
        // 規格あり商品の場合、規格関連情報をFormから除外
290
        if ($has_class) {
291
            $builder->remove('class');
292
        }
293
294
        $event = new EventArgs(
295
            array(
296
                'builder' => $builder,
297
                'Product' => $Product,
298
            ),
299
            $request
300
        );
301
        $app['eccube.event.dispatcher']->dispatch(EccubeEvents::ADMIN_PRODUCT_EDIT_INITIALIZE, $event);
302
303
        $form = $builder->getForm();
304
305
        if (!$has_class) {
306
            $ProductClass->setStockUnlimited((boolean)$ProductClass->getStockUnlimited());
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...
Coding Style introduced by
As per coding-style, a cast statement should be followed by a single space.
Loading history...
307
            $form['class']->setData($ProductClass);
308
        }
309
310
        // ファイルの登録
311
        $images = array();
312
        $ProductImages = $Product->getProductImage();
313
        foreach ($ProductImages as $ProductImage) {
314
            $images[] = $ProductImage->getFileName();
315
        }
316
        $form['images']->setData($images);
317
318
        $categories = array();
319
        $ProductCategories = $Product->getProductCategories();
320
        foreach ($ProductCategories as $ProductCategory) {
321
            /* @var $ProductCategory \Eccube\Entity\ProductCategory */
322
            $categories[] = $ProductCategory->getCategory();
323
        }
324
        $form['Category']->setData($categories);
325
326
        $Tags = array();
327
        $ProductTags = $Product->getProductTag();
328
        foreach ($ProductTags as $ProductTag) {
329
            $Tags[] = $ProductTag->getTag();
330
        }
331
        $form['Tag']->setData($Tags);
332
333
        if ('POST' === $request->getMethod()) {
334
            $form->handleRequest($request);
335
            if ($form->isValid()) {
336
                log_info('商品登録開始', array($id));
337
                $Product = $form->getData();
338
339
                if (!$has_class) {
340
                    $ProductClass = $form['class']->getData();
341
342
                    // 個別消費税
343
                    $BaseInfo = $app['eccube.repository.base_info']->get();
344
                    if ($BaseInfo->getOptionProductTaxRule() == Constant::ENABLED) {
345
                        if ($ProductClass->getTaxRate() !== null) {
346 View Code Duplication
                            if ($ProductClass->getTaxRule()) {
347
                                if ($ProductClass->getTaxRule()->getDelFlg() == Constant::ENABLED) {
348
                                    $ProductClass->getTaxRule()->setDelFlg(Constant::DISABLED);
349
                                }
350
351
                                $ProductClass->getTaxRule()->setTaxRate($ProductClass->getTaxRate());
352
                            } else {
353
                                $taxrule = $app['eccube.repository.tax_rule']->newTaxRule();
354
                                $taxrule->setTaxRate($ProductClass->getTaxRate());
355
                                $taxrule->setApplyDate(new \DateTime());
356
                                $taxrule->setProduct($Product);
357
                                $taxrule->setProductClass($ProductClass);
358
                                $ProductClass->setTaxRule($taxrule);
359
                            }
360
                        } else {
361
                            if ($ProductClass->getTaxRule()) {
362
                                $ProductClass->getTaxRule()->setDelFlg(Constant::ENABLED);
363
                            }
364
                        }
365
                    }
366
                    $app['orm.em']->persist($ProductClass);
367
368
                    // 在庫情報を作成
369
                    if (!$ProductClass->getStockUnlimited()) {
370
                        $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...
371 2
                    } else {
372
                        // 在庫無制限時はnullを設定
373 2
                        $ProductStock->setStock(null);
374 2
                    }
375
                    $app['orm.em']->persist($ProductStock);
376
                }
377
378 2
                // カテゴリの登録
379
                // 一度クリア
380
                /* @var $Product \Eccube\Entity\Product */
381
                foreach ($Product->getProductCategories() as $ProductCategory) {
382
                    $Product->removeProductCategory($ProductCategory);
383
                    $app['orm.em']->remove($ProductCategory);
384
                }
385
                $app['orm.em']->persist($Product);
386
                $app['orm.em']->flush();
387
388
                $count = 1;
389
                $Categories = $form->get('Category')->getData();
390
                $categoriesIdList = array();
391
                foreach ($Categories as $Category) {
392 View Code Duplication
                    foreach ($Category->getPath() as $ParentCategory) {
393
                        if (!isset($categoriesIdList[$ParentCategory->getId()])) {
394
                            $ProductCategory = $this->createProductCategory($Product, $ParentCategory, $count);
395
                            $app['orm.em']->persist($ProductCategory);
396
                            $count++;
397
                            /* @var $Product \Eccube\Entity\Product */
398
                            $Product->addProductCategory($ProductCategory);
399
                            $categoriesIdList[$ParentCategory->getId()] = true;
400
                        }
401
                    }
402
                    if (!isset($categoriesIdList[$Category->getId()])) {
403
                        $ProductCategory = $this->createProductCategory($Product, $Category, $count);
404
                        $app['orm.em']->persist($ProductCategory);
405
                        $count++;
406
                        /* @var $Product \Eccube\Entity\Product */
407
                        $Product->addProductCategory($ProductCategory);
408
                        $categoriesIdList[$Category->getId()] = true;
409
                    }
410
                }
411
412
                // 画像の登録
413
                $add_images = $form->get('add_images')->getData();
414
                foreach ($add_images as $add_image) {
415
                    $ProductImage = new \Eccube\Entity\ProductImage();
416
                    $ProductImage
417
                        ->setFileName($add_image)
418
                        ->setProduct($Product)
419
                        ->setRank(1);
420
                    $Product->addProductImage($ProductImage);
421
                    $app['orm.em']->persist($ProductImage);
422
423
                    // 移動
424
                    $file = new File($app['config']['image_temp_realdir'].'/'.$add_image);
425
                    $file->move($app['config']['image_save_realdir']);
426
                }
427
428
                // 画像の削除
429
                $delete_images = $form->get('delete_images')->getData();
430
                foreach ($delete_images as $delete_image) {
431
                    $ProductImage = $app['eccube.repository.product_image']
432
                        ->findOneBy(array('file_name' => $delete_image));
433
434
                    // 追加してすぐに削除した画像は、Entityに追加されない
435
                    if ($ProductImage instanceof \Eccube\Entity\ProductImage) {
0 ignored issues
show
Bug introduced by
The class Eccube\Entity\ProductImage 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...
436
                        $Product->removeProductImage($ProductImage);
437
                        $app['orm.em']->remove($ProductImage);
438
0 ignored issues
show
Coding Style introduced by
Blank line found at end of control structure
Loading history...
439
                    }
440
                    $app['orm.em']->persist($Product);
441
442
                    // 削除
443 View Code Duplication
                    if (!empty($delete_image)) {
444
                        $fs = new Filesystem();
445
                        $fs->remove($app['config']['image_save_realdir'].'/'.$delete_image);
446
                    }
447
                }
448
                $app['orm.em']->persist($Product);
449
                $app['orm.em']->flush();
450
451
452
                $ranks = $request->get('rank_images');
453
                if ($ranks) {
454
                    foreach ($ranks as $rank) {
455
                        list($filename, $rank_val) = explode('//', $rank);
456
                        $ProductImage = $app['eccube.repository.product_image']
457
                            ->findOneBy(array(
458
                                'file_name' => $filename,
459
                                'Product' => $Product,
460
                            ));
461
                        $ProductImage->setRank($rank_val);
462
                        $app['orm.em']->persist($ProductImage);
463
                    }
464
                }
465
                $app['orm.em']->flush();
466
467
                // 商品タグの登録
468
                // 商品タグを一度クリア
469
                $ProductTags = $Product->getProductTag();
470
                foreach ($ProductTags as $ProductTag) {
471
                    $Product->removeProductTag($ProductTag);
472
                    $app['orm.em']->remove($ProductTag);
473
                }
474
475
                // 商品タグの登録
476
                $Tags = $form->get('Tag')->getData();
477
                foreach ($Tags as $Tag) {
478
                    $ProductTag = new ProductTag();
479
                    $ProductTag
480
                        ->setProduct($Product)
481
                        ->setTag($Tag);
482
                    $Product->addProductTag($ProductTag);
483
                    $app['orm.em']->persist($ProductTag);
484
                }
485
486
                $Product->setUpdateDate(new \DateTime());
487
                $app['orm.em']->flush();
488
489
                log_info('商品登録完了', array($id));
490
491
                $event = new EventArgs(
492
                    array(
493
                        'form' => $form,
494
                        'Product' => $Product,
495
                    ),
496
                    $request
497
                );
498
                $app['eccube.event.dispatcher']->dispatch(EccubeEvents::ADMIN_PRODUCT_EDIT_COMPLETE, $event);
499
500
                $app->addSuccess('admin.register.complete', 'admin');
501
502
                return $app->redirect($app->url('admin_product_product_edit', array('id' => $Product->getId())));
503
            } else {
504
                log_info('商品登録チェックエラー', array($id));
505
                $app->addError('admin.register.failed', 'admin');
506
            }
507
        }
508
509
        // 検索結果の保持
510
        $builder = $app['form.factory']
511
            ->createBuilder('admin_search_product');
512
513
        $event = new EventArgs(
514
            array(
515
                'builder' => $builder,
516
                'Product' => $Product,
517
            ),
518
            $request
519
        );
520
        $app['eccube.event.dispatcher']->dispatch(EccubeEvents::ADMIN_PRODUCT_EDIT_SEARCH, $event);
521
522
        $searchForm = $builder->getForm();
523
524
        if ('POST' === $request->getMethod()) {
525
            $searchForm->handleRequest($request);
526
        }
527
528
        return $app->render('Product/product.twig', array(
529
            'Product' => $Product,
530
            'form' => $form->createView(),
531
            'searchForm' => $searchForm->createView(),
532
            'has_class' => $has_class,
533
            'id' => $id,
534
        ));
535
    }
536
537
    public function delete(Application $app, Request $request, $id = null)
0 ignored issues
show
introduced by
Missing function doc comment
Loading history...
538
    {
539
        $this->isTokenValid($app);
540
        $session = $request->getSession();
541
        $page_no = intval($session->get('eccube.admin.product.search.page_no'));
542
        $page_no = $page_no ? $page_no : Constant::ENABLED;
543
544
        if (!is_null($id)) {
545
            /* @var $Product \Eccube\Entity\Product */
546
            $Product = $app['eccube.repository.product']->find($id);
547
            if (!$Product) {
548
                $app->deleteMessage();
549
550
                return $app->redirect($app->url('admin_product_page', array('page_no' => $page_no)).'?resume='.Constant::ENABLED);
551
            }
552
553
            if ($Product instanceof \Eccube\Entity\Product) {
0 ignored issues
show
Bug introduced by
The class Eccube\Entity\Product 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...
554
                log_info('商品削除開始', array($id));
555
556
                $Product->setDelFlg(Constant::ENABLED);
557
558
                $ProductClasses = $Product->getProductClasses();
559
                $deleteImages = array();
560
                foreach ($ProductClasses as $ProductClass) {
561
                    $ProductClass->setDelFlg(Constant::ENABLED);
562
                    $Product->removeProductClass($ProductClass);
563
564
                    $ProductClasses = $Product->getProductClasses();
565
                    foreach ($ProductClasses as $ProductClass) {
566
                        $ProductClass->setDelFlg(Constant::ENABLED);
567
                        $Product->removeProductClass($ProductClass);
568
569
                        $ProductStock = $ProductClass->getProductStock();
570
                        $app['orm.em']->remove($ProductStock);
571
                    }
572
573
                    $ProductImages = $Product->getProductImage();
574
                    foreach ($ProductImages as $ProductImage) {
575
                        $Product->removeProductImage($ProductImage);
576
                        $deleteImages[] = $ProductImage->getFileName();
577
                        $app['orm.em']->remove($ProductImage);
578
                    }
579
580
                    $ProductCategories = $Product->getProductCategories();
581
                    foreach ($ProductCategories as $ProductCategory) {
582
                        $Product->removeProductCategory($ProductCategory);
583
                        $app['orm.em']->remove($ProductCategory);
584
                    }
585
0 ignored issues
show
Coding Style introduced by
Blank line found at end of control structure
Loading history...
586
                }
587
588
                $app['orm.em']->persist($Product);
589
590
                $app['orm.em']->flush();
591
592
                $event = new EventArgs(
593
                    array(
594
                        'Product' => $Product,
595
                        'ProductClass' => $ProductClasses,
596
                        'deleteImages' => $deleteImages,
597
                    ),
598
                    $request
599
                );
600
                $app['eccube.event.dispatcher']->dispatch(EccubeEvents::ADMIN_PRODUCT_DELETE_COMPLETE, $event);
601
                $deleteImages = $event->getArgument('deleteImages');
602
603
                // 画像ファイルの削除(commit後に削除させる)
604
                foreach ($deleteImages as $deleteImage) {
605
                    try {
606 View Code Duplication
                        if (!empty($deleteImage)) {
607
                            $fs = new Filesystem();
608
                            $fs->remove($app['config']['image_save_realdir'].'/'.$deleteImage);
609
                        }
610
                    } catch (\Exception $e) {
611
                        // エラーが発生しても無視する
612
                    }
613
                }
614
615
                log_info('商品削除完了', array($id));
616
617
                $app->addSuccess('admin.delete.complete', 'admin');
618
            } else {
619
                log_info('商品削除エラー', array($id));
620
                $app->addError('admin.delete.failed', 'admin');
621
            }
622
        } else {
623
            log_info('商品削除エラー', array($id));
624
            $app->addError('admin.delete.failed', 'admin');
625
        }
626
627
        return $app->redirect($app->url('admin_product_page', array('page_no' => $page_no)).'?resume='.Constant::ENABLED);
628
    }
629
630
    public function copy(Application $app, Request $request, $id = null)
0 ignored issues
show
introduced by
Missing function doc comment
Loading history...
631
    {
632
        $this->isTokenValid($app);
633
634
        if (!is_null($id)) {
635
            $Product = $app['eccube.repository.product']->find($id);
636
            if ($Product instanceof \Eccube\Entity\Product) {
0 ignored issues
show
Bug introduced by
The class Eccube\Entity\Product 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...
637
                $CopyProduct = clone $Product;
638
                $CopyProduct->copy();
639
                $Disp = $app['eccube.repository.master.disp']->find(\Eccube\Entity\Master\Disp::DISPLAY_HIDE);
640
                $CopyProduct->setStatus($Disp);
641
642
                $CopyProductCategories = $CopyProduct->getProductCategories();
643
                foreach ($CopyProductCategories as $Category) {
644
                    $app['orm.em']->persist($Category);
645
                }
646
647
                // 規格あり商品の場合は, デフォルトの商品規格を取得し登録する.
648
                if ($CopyProduct->hasProductClass()) {
649
                    $softDeleteFilter = $app['orm.em']->getFilters()->getFilter('soft_delete');
650
                    $softDeleteFilter->setExcludes(array(
0 ignored issues
show
introduced by
Add a comma after each item in a multi-line array
Loading history...
651
                        'Eccube\Entity\ProductClass'
652
                    ));
653
                    $dummyClass = $app['eccube.repository.product_class']->findOneBy(array(
654
                        'del_flg' => \Eccube\Common\Constant::ENABLED,
655
                        'ClassCategory1' => null,
656
                        'ClassCategory2' => null,
657
                        'Product' => $Product,
658
                    ));
659
                    $dummyClass = clone $dummyClass;
660
                    $dummyClass->setProduct($CopyProduct);
661
                    $CopyProduct->addProductClass($dummyClass);
662
                    $softDeleteFilter->setExcludes(array());
663
                }
664
665
                $CopyProductClasses = $CopyProduct->getProductClasses();
666
                foreach ($CopyProductClasses as $Class) {
667
                    $Stock = $Class->getProductStock();
668
                    $CopyStock = clone $Stock;
669
                    $CopyStock->setProductClass($Class);
670
                    $app['orm.em']->persist($CopyStock);
671
672
                    $app['orm.em']->persist($Class);
673
                }
674
                $Images = $CopyProduct->getProductImage();
675
                foreach ($Images as $Image) {
0 ignored issues
show
Coding Style introduced by
Blank line found at start of control structure
Loading history...
676
677
                    // 画像ファイルを新規作成
678
                    $extension = pathinfo($Image->getFileName(), PATHINFO_EXTENSION);
679
                    $filename = date('mdHis').uniqid('_').'.'.$extension;
680
                    try {
681
                        $fs = new Filesystem();
682
                        $fs->copy($app['config']['image_save_realdir'].'/'.$Image->getFileName(), $app['config']['image_save_realdir'].'/'.$filename);
683
                    } catch (\Exception $e) {
684
                        // エラーが発生しても無視する
685
                    }
686
                    $Image->setFileName($filename);
687
688
                    $app['orm.em']->persist($Image);
689
                }
690
                $Tags = $CopyProduct->getProductTag();
691
                foreach ($Tags as $Tag) {
692
                    $app['orm.em']->persist($Tag);
693
                }
694
695
                $app['orm.em']->persist($CopyProduct);
696
697
                $app['orm.em']->flush();
698
699
                $event = new EventArgs(
700
                    array(
701
                        'Product' => $Product,
702
                        'CopyProduct' => $CopyProduct,
703
                        'CopyProductCategories' => $CopyProductCategories,
704
                        'CopyProductClasses' => $CopyProductClasses,
705
                        'images' => $Images,
706
                        'Tags' => $Tags,
707
                    ),
708
                    $request
709
                );
710
                $app['eccube.event.dispatcher']->dispatch(EccubeEvents::ADMIN_PRODUCT_COPY_COMPLETE, $event);
711
712
                $app->addSuccess('admin.product.copy.complete', 'admin');
713
714
                return $app->redirect($app->url('admin_product_product_edit', array('id' => $CopyProduct->getId())));
715
            } else {
716
                $app->addError('admin.product.copy.failed', 'admin');
717
            }
718
        } else {
719
            $app->addError('admin.product.copy.failed', 'admin');
720
        }
721
722
        return $app->redirect($app->url('admin_product'));
723
    }
724
725
    public function display(Application $app, Request $request, $id = null)
0 ignored issues
show
introduced by
Missing function doc comment
Loading history...
726
    {
727
        $event = new EventArgs(
728
            array(),
729
            $request
730
        );
731
        $app['eccube.event.dispatcher']->dispatch(EccubeEvents::ADMIN_PRODUCT_DISPLAY_COMPLETE, $event);
732
733
        if (!is_null($id)) {
734
            return $app->redirect($app->url('product_detail', array('id' => $id, 'admin' => '1')));
735
        }
736
737
        return $app->redirect($app->url('admin_product'));
738
    }
739
740
    /**
741
     * 商品CSVの出力.
742
     *
743
     * @param Application $app
744
     * @param Request $request
0 ignored issues
show
introduced by
Expected 5 spaces after parameter type; 1 found
Loading history...
745
     * @return StreamedResponse
746
     */
747
    public function export(Application $app, Request $request)
748
    {
749
        // タイムアウトを無効にする.
750
        set_time_limit(0);
751
752
        // sql loggerを無効にする.
753
        $em = $app['orm.em'];
754
        $em->getConfiguration()->setSQLLogger(null);
755
756
        $response = new StreamedResponse();
757
        $response->setCallback(function () use ($app, $request) {
758
759
            // CSV種別を元に初期化.
760
            $app['eccube.service.csv.export']->initCsvType(CsvType::CSV_TYPE_PRODUCT);
761
762
            // ヘッダ行の出力.
763
            $app['eccube.service.csv.export']->exportHeader();
764
765
            // 商品データ検索用のクエリビルダを取得.
766
            $qb = $app['eccube.service.csv.export']
767
                ->getProductQueryBuilder($request);
768
769
            // Get stock status
770
            $isOutOfStock = 0;
771
            $session = $request->getSession();
772
            if ($session->has('eccube.admin.product.search')) {
773
                $searchData = $session->get('eccube.admin.product.search', array());
774
                if (isset($searchData['stock_status']) && $searchData['stock_status'] === 0) {
775
                    $isOutOfStock = 1;
776
                }
777
            }
778
779
            // joinする場合はiterateが使えないため, select句をdistinctする.
780
            // http://qiita.com/suin/items/2b1e98105fa3ef89beb7
781
            // distinctのmysqlとpgsqlの挙動をあわせる.
782
            // http://uedatakeshi.blogspot.jp/2010/04/distinct-oeder-by-postgresmysql.html
783
            $qb->resetDQLPart('select')
784
                ->resetDQLPart('orderBy')
785
                ->orderBy('p.update_date', 'DESC');
786
787
            if ($isOutOfStock) {
788
                $qb->select('p, pc')
789
                    ->distinct();
790
            } else {
791
                $qb->select('p')
792
                    ->distinct();
793
            }
794
            // データ行の出力.
795
            $app['eccube.service.csv.export']->setExportQueryBuilder($qb);
796
797 View Code Duplication
            $app['eccube.service.csv.export']->exportData(function ($entity, CsvExportService $csvService) use ($app, $request) {
798
                $Csvs = $csvService->getCsvs();
799
800
                /** @var $Product \Eccube\Entity\Product */
801
                $Product = $entity;
802
803
                /** @var $ProductClassess \Eccube\Entity\ProductClass[] */
804
                $ProductClassess = $Product->getProductClasses();
805
806
                foreach ($ProductClassess as $ProductClass) {
807
                    $ExportCsvRow = new \Eccube\Entity\ExportCsvRow();
808
809
                    // CSV出力項目と合致するデータを取得.
810
                    foreach ($Csvs as $Csv) {
811
                        // 商品データを検索.
812
                        $ExportCsvRow->setData($csvService->getData($Csv, $Product));
813
                        if ($ExportCsvRow->isDataNull()) {
814
                            // 商品規格情報を検索.
815
                            $ExportCsvRow->setData($csvService->getData($Csv, $ProductClass));
816
                        }
817
818
                        $event = new EventArgs(
819
                            array(
820
                                'csvService' => $csvService,
821
                                'Csv' => $Csv,
822
                                'ProductClass' => $ProductClass,
823
                                'ExportCsvRow' => $ExportCsvRow,
824
                            ),
825
                            $request
826
                        );
827
                        $app['eccube.event.dispatcher']->dispatch(EccubeEvents::ADMIN_PRODUCT_CSV_EXPORT, $event);
828
829
                        $ExportCsvRow->pushData();
830
                    }
831
832
                    // $row[] = number_format(memory_get_usage(true));
0 ignored issues
show
Unused Code Comprehensibility introduced by
60% 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...
833
                    // 出力.
834
                    $csvService->fputcsv($ExportCsvRow->getRow());
835
                }
836
            });
837
        });
838
839
        $now = new \DateTime();
840
        $filename = 'product_'.$now->format('YmdHis').'.csv';
841
        $response->headers->set('Content-Type', 'application/octet-stream');
842
        $response->headers->set('Content-Disposition', 'attachment; filename='.$filename);
843
        $response->send();
844
845
        log_info('商品CSV出力ファイル名', array($filename));
846
847
        return $response;
848
    }
849
850
    /**
851
     * ProductCategory作成
852
     * @param \Eccube\Entity\Product $Product
853
     * @param \Eccube\Entity\Category $Category
854
     * @return \Eccube\Entity\ProductCategory
855
     */
856 View Code Duplication
    private function createProductCategory($Product, $Category, $count)
857
    {
858
        $ProductCategory = new \Eccube\Entity\ProductCategory();
859
        $ProductCategory->setProduct($Product);
860
        $ProductCategory->setProductId($Product->getId());
861
        $ProductCategory->setCategory($Category);
862
        $ProductCategory->setCategoryId($Category->getId());
863
        $ProductCategory->setRank($count);
864
865
        return $ProductCategory;
866
    }
867
}
868