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 70.93%

Importance

Changes 0
Metric Value
dl 110
loc 824
rs 1.263
c 0
b 0
f 0
ccs 322
cts 454
cp 0.7093
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
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 8
    public function index(Application $app, Request $request, $page_no = null)
0 ignored issues
show
introduced by
Missing function doc comment
Loading history...
47
    {
48
49 8
        $session = $app['session'];
50
51 8
        $builder = $app['form.factory']
52 8
            ->createBuilder('admin_search_product');
53
54 8
        $event = new EventArgs(
55
            array(
56 8
                'builder' => $builder,
57
            ),
58
            $request
59
        );
60 8
        $app['eccube.event.dispatcher']->dispatch(EccubeEvents::ADMIN_PRODUCT_INDEX_INITIALIZE, $event);
61
62 8
        $searchForm = $builder->getForm();
63
64 8
        $pagination = array();
65
66 8
        $disps = $app['eccube.repository.master.disp']->findAll();
67 8
        $pageMaxis = $app['eccube.repository.master.page_max']->findAll();
68
69
        // 表示件数は順番で取得する、1.SESSION 2.設定ファイル
70 8
        $page_count = $session->get('eccube.admin.product.search.page_count', $app['config']['default_page_count']);
71
        // 表示件数
72
73 8
        $page_count_param = $request->get('page_count');
74
        // 表示件数はURLパラメターから取得する
75 8 View Code Duplication
        if ($page_count_param && is_numeric($page_count_param)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
76 3
            foreach ($pageMaxis as $pageMax) {
77 3
                if ($page_count_param == $pageMax->getName()) {
78 3
                    $page_count = $pageMax->getName();
79
                    // 表示件数入力値正し場合はSESSIONに保存する
80 3
                    $session->set('eccube.admin.product.search.page_count', $page_count);
81 3
                    break;
82
                }
83
            }
84
        }
85
86 8
        $page_status = null;
87 8
        $active = false;
88
89 8
        if ('POST' === $request->getMethod()) {
0 ignored issues
show
Coding Style introduced by
Blank line found at start of control structure
Loading history...
90
91 5
            $searchForm->handleRequest($request);
92
93 5
            if ($searchForm->isValid()) {
94 5
                $searchData = $searchForm->getData();
95
96
                // paginator
97 5
                $qb = $app['eccube.repository.product']->getQueryBuilderBySearchDataForAdmin($searchData);
98 5
                $page_no = 1;
99
100 5
                $event = new EventArgs(
101
                    array(
102 5
                        'qb' => $qb,
103 5
                        'searchData' => $searchData,
104
                    ),
105
                    $request
106
                );
107 5
                $app['eccube.event.dispatcher']->dispatch(EccubeEvents::ADMIN_PRODUCT_INDEX_SEARCH, $event);
108 5
                $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 5
                $pagination = $app['paginator']()->paginate(
111
                    $qb,
112
                    $page_no,
113
                    $page_count,
114 5
                    array('wrap-queries' => true)
115
                );
116
117
                // sessionに検索条件を保持
118 5
                $viewData = FormUtil::getViewData($searchForm);
119 5
                $session->set('eccube.admin.product.search', $viewData);
120 5
                $session->set('eccube.admin.product.search.page_no', $page_no);
121
            }
122
        } else {
123 6
            if (is_null($page_no) && $request->get('resume') != Constant::ENABLED) {
124
                // sessionを削除
125 2
                $session->remove('eccube.admin.product.search');
126 2
                $session->remove('eccube.admin.product.search.page_no');
127 2
                $session->remove('eccube.admin.product.search.page_count');
128
            } else {
129
                // pagingなどの処理
130 4
                if (is_null($page_no)) {
131
                    $page_no = intval($session->get('eccube.admin.product.search.page_no'));
132
                } else {
133 4
                    $session->set('eccube.admin.product.search.page_no', $page_no);
134
                }
135 4
                $viewData = $session->get('eccube.admin.product.search');
136 4
                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 4
                    $linkStatus = $request->get('status');
140 4
                    if (!empty($linkStatus)) {
141
                        // リンクステータスは在庫なし:3以外
142 4
                        if ($linkStatus != $app['config']['admin_product_stock_status']) {
143 3
                            $viewData['link_status'] = $linkStatus;
144 3
                            $viewData['stock_status'] = null;
145 3
                            $viewData['status'] = null;
146 View Code Duplication
                        } else {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
147
                            // リンクステータスは在庫なし:3
148 1
                            $viewData['link_status'] = null;
149 1
                            $viewData['stock_status'] = Constant::DISABLED;
150 1
                            $viewData['status'] = null;
151
                        }
152
                        // ページステータスを設定します(リンクステータスAタグ表示のために)
153 4
                        $page_status = $linkStatus;
154 View Code Duplication
                    } else {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
155
                        // すべてを選択
156 3
                        $viewData['link_status'] = null;
157 3
                        $viewData['stock_status'] = null;
158 3
                        if (!$viewData['status']) {
159 3
                            $viewData['status'] = array();
160
                        }
161
                    }
162
163
                    // 表示件数
164 4
                    $page_count = $request->get('page_count', $page_count);
165 4
                    $searchData = FormUtil::submitAndGetData($searchForm, $viewData);
166 4
                    if ($viewData['link_status']) {
167 3
                        $searchData['link_status'] = $app['eccube.repository.master.disp']->find($viewData['link_status']);
168
                    }
169
                    // リンクステータス[在庫なし]設定されている場合は検索パラメター設定する
170 4
                    if (isset($viewData['stock_status'])) {
171 1
                        $searchData['stock_status'] = $viewData['stock_status'];
172
                    }
173
174 4
                    $session->set('eccube.admin.product.search', $viewData);
175
176 4
                    $qb = $app['eccube.repository.product']->getQueryBuilderBySearchDataForAdmin($searchData);
177
178 4
                    $event = new EventArgs(
179
                        array(
180 4
                            'qb' => $qb,
181 4
                            'searchData' => $searchData,
182
                        ),
183
                        $request
184
                    );
185 4
                    $app['eccube.event.dispatcher']->dispatch(EccubeEvents::ADMIN_PRODUCT_INDEX_SEARCH, $event);
186 4
                    $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 4
                    $pagination = $app['paginator']()->paginate(
190
                        $qb,
191
                        $page_no,
192
                        $page_count,
193 4
                        array('wrap-queries' => true)
194
                    );
195
                }
196
            }
197
        }
198
199 8
        return $app->render('Product/index.twig', array(
200 8
            'searchForm' => $searchForm->createView(),
201 8
            'pagination' => $pagination,
202 8
            'disps' => $disps,
203 8
            'pageMaxis' => $pageMaxis,
204 8
            'page_no' => $page_no,
205 8
            'page_status' => $page_status,
206 8
            'page_count' => $page_count,
207 8
            'active' => $active,
208
        ));
209
    }
210
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
        }
216
217
        $images = $request->files->get('admin_product');
218
219
        $files = array();
220
        if (count($images) > 0) {
221
            foreach ($images as $img) {
222
                foreach ($img as $image) {
223
                    //ファイルフォーマット検証
224
                    $mimeType = $image->getMimeType();
225
                    if (0 !== strpos($mimeType, 'image')) {
226
                        throw new UnsupportedMediaTypeHttpException('ファイル形式が不正です');
227
                    }
228
229
                    $extension = $image->getClientOriginalExtension();
230
                    $filename = date('mdHis').uniqid('_').'.'.$extension;
231
                    $image->move($app['config']['image_temp_realdir'], $filename);
232
                    $files[] = $filename;
233
                }
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 20
    public function edit(Application $app, Request $request, $id = null)
0 ignored issues
show
introduced by
Missing function doc comment
Loading history...
251
    {
252 20
        $has_class = false;
253 20
        if (is_null($id)) {
254 6
            $Product = new \Eccube\Entity\Product();
255 6
            $ProductClass = new \Eccube\Entity\ProductClass();
256 6
            $Disp = $app['eccube.repository.master.disp']->find(\Eccube\Entity\Master\Disp::DISPLAY_HIDE);
257
            $Product
258 6
                ->setDelFlg(Constant::DISABLED)
259 6
                ->addProductClass($ProductClass)
260 6
                ->setStatus($Disp);
261
            $ProductClass
262 6
                ->setDelFlg(Constant::DISABLED)
263 6
                ->setStockUnlimited(true)
264 6
                ->setProduct($Product);
265 6
            $ProductStock = new \Eccube\Entity\ProductStock();
266 6
            $ProductClass->setProductStock($ProductStock);
267 6
            $ProductStock->setProductClass($ProductClass);
268
        } else {
269 14
            $Product = $app['eccube.repository.product']->find($id);
270 14
            if (!$Product) {
271
                throw new NotFoundHttpException();
272
            }
273
            // 規格あり商品か
274 14
            $has_class = $Product->hasProductClass();
275 14
            if (!$has_class) {
276 11
                $ProductClasses = $Product->getProductClasses();
277 11
                $ProductClass = $ProductClasses[0];
278 11
                $BaseInfo = $app['eccube.repository.base_info']->get();
279 11 View Code Duplication
                if ($BaseInfo->getOptionProductTaxRule() == Constant::ENABLED && $ProductClass->getTaxRule() && !$ProductClass->getTaxRule()->getDelFlg()) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
280 6
                    $ProductClass->setTaxRate($ProductClass->getTaxRule()->getTaxRate());
281
                }
282 11
                $ProductStock = $ProductClasses[0]->getProductStock();
283
            }
284
        }
285
286 20
        $builder = $app['form.factory']
287 20
            ->createBuilder('admin_product', $Product);
288
289
        // 規格あり商品の場合、規格関連情報をFormから除外
290 20
        if ($has_class) {
291 3
            $builder->remove('class');
292
        }
293
294 20
        $event = new EventArgs(
295
            array(
296 20
                'builder' => $builder,
297 20
                'Product' => $Product,
298
            ),
299
            $request
300
        );
301 20
        $app['eccube.event.dispatcher']->dispatch(EccubeEvents::ADMIN_PRODUCT_EDIT_INITIALIZE, $event);
302
303 20
        $form = $builder->getForm();
304
305 20
        if (!$has_class) {
306 17
            $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 17
            $form['class']->setData($ProductClass);
308
        }
309
310
        // ファイルの登録
311 20
        $images = array();
312 20
        $ProductImages = $Product->getProductImage();
313 20
        foreach ($ProductImages as $ProductImage) {
314 20
            $images[] = $ProductImage->getFileName();
315
        }
316 20
        $form['images']->setData($images);
317
318 20
        $categories = array();
319 20
        $ProductCategories = $Product->getProductCategories();
320 20
        foreach ($ProductCategories as $ProductCategory) {
321
            /* @var $ProductCategory \Eccube\Entity\ProductCategory */
322 20
            $categories[] = $ProductCategory->getCategory();
323
        }
324 20
        $form['Category']->setData($categories);
325
326 20
        $Tags = array();
327 20
        $ProductTags = $Product->getProductTag();
328 20
        foreach ($ProductTags as $ProductTag) {
329 20
            $Tags[] = $ProductTag->getTag();
330
        }
331 20
        $form['Tag']->setData($Tags);
332
333 20
        if ('POST' === $request->getMethod()) {
334 14
            $form->handleRequest($request);
335 14
            if ($form->isValid()) {
336 14
                log_info('商品登録開始', array($id));
337 14
                $Product = $form->getData();
338
339 14
                if (!$has_class) {
340 14
                    $ProductClass = $form['class']->getData();
341
342
                    // 個別消費税
343 14
                    $BaseInfo = $app['eccube.repository.base_info']->get();
344 14
                    if ($BaseInfo->getOptionProductTaxRule() == Constant::ENABLED) {
345 12
                        if ($ProductClass->getTaxRate() !== null) {
346 8 View Code Duplication
                            if ($ProductClass->getTaxRule()) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
347 4
                                if ($ProductClass->getTaxRule()->getDelFlg() == Constant::ENABLED) {
348
                                    $ProductClass->getTaxRule()->setDelFlg(Constant::DISABLED);
349
                                }
350
351 4
                                $ProductClass->getTaxRule()->setTaxRate($ProductClass->getTaxRate());
352
                            } else {
353 4
                                $taxrule = $app['eccube.repository.tax_rule']->newTaxRule();
354 4
                                $taxrule->setTaxRate($ProductClass->getTaxRate());
355 4
                                $taxrule->setApplyDate(new \DateTime());
356 4
                                $taxrule->setProduct($Product);
357 4
                                $taxrule->setProductClass($ProductClass);
358 8
                                $ProductClass->setTaxRule($taxrule);
359
                            }
360
                        } else {
361 4
                            if ($ProductClass->getTaxRule()) {
362 2
                                $ProductClass->getTaxRule()->setDelFlg(Constant::ENABLED);
363
                            }
364
                        }
365
                    }
366 14
                    $app['orm.em']->persist($ProductClass);
367
368
                    // 在庫情報を作成
369 14
                    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
                    } else {
372
                        // 在庫無制限時はnullを設定
373 14
                        $ProductStock->setStock(null);
374
                    }
375 14
                    $app['orm.em']->persist($ProductStock);
376
                }
377
378
                // カテゴリの登録
379
                // 一度クリア
380
                /* @var $Product \Eccube\Entity\Product */
381 14
                foreach ($Product->getProductCategories() as $ProductCategory) {
382 11
                    $Product->removeProductCategory($ProductCategory);
383 14
                    $app['orm.em']->remove($ProductCategory);
384
                }
385 14
                $app['orm.em']->persist($Product);
386 14
                $app['orm.em']->flush();
387
388 14
                $count = 1;
389 14
                $Categories = $form->get('Category')->getData();
390 14
                $categoriesIdList = array();
391 14
                foreach ($Categories as $Category) {
392 View Code Duplication
                    foreach ($Category->getPath() as $ParentCategory) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
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 14
                        $categoriesIdList[$Category->getId()] = true;
409
                    }
410
                }
411
412
                // 画像の登録
413 14
                $add_images = $form->get('add_images')->getData();
414 14
                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 14
                    $file->move($app['config']['image_save_realdir']);
426
                }
427
428
                // 画像の削除
429 14
                $delete_images = $form->get('delete_images')->getData();
430 14
                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)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
444
                        $fs = new Filesystem();
445 14
                        $fs->remove($app['config']['image_save_realdir'].'/'.$delete_image);
446
                    }
447
                }
448 14
                $app['orm.em']->persist($Product);
449 14
                $app['orm.em']->flush();
450
451
452 14
                $ranks = $request->get('rank_images');
453 14
                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 14
                $app['orm.em']->flush();
466
467
                // 商品タグの登録
468
                // 商品タグを一度クリア
469 14
                $ProductTags = $Product->getProductTag();
470 14
                foreach ($ProductTags as $ProductTag) {
471
                    $Product->removeProductTag($ProductTag);
472 14
                    $app['orm.em']->remove($ProductTag);
473
                }
474
475
                // 商品タグの登録
476 14
                $Tags = $form->get('Tag')->getData();
477 14
                foreach ($Tags as $Tag) {
478 14
                    $ProductTag = new ProductTag();
479
                    $ProductTag
480 14
                        ->setProduct($Product)
481 14
                        ->setTag($Tag);
482 14
                    $Product->addProductTag($ProductTag);
483 14
                    $app['orm.em']->persist($ProductTag);
484
                }
485
486 14
                $Product->setUpdateDate(new \DateTime());
487 14
                $app['orm.em']->flush();
488
489 14
                log_info('商品登録完了', array($id));
490
491 14
                $event = new EventArgs(
492
                    array(
493 14
                        'form' => $form,
494 14
                        'Product' => $Product,
495
                    ),
496
                    $request
497
                );
498 14
                $app['eccube.event.dispatcher']->dispatch(EccubeEvents::ADMIN_PRODUCT_EDIT_COMPLETE, $event);
499
500 14
                $app->addSuccess('admin.register.complete', 'admin');
501
502 14
                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 6
        $builder = $app['form.factory']
511 6
            ->createBuilder('admin_search_product');
512
513 6
        $event = new EventArgs(
514
            array(
515 6
                'builder' => $builder,
516 6
                'Product' => $Product,
517
            ),
518
            $request
519
        );
520 6
        $app['eccube.event.dispatcher']->dispatch(EccubeEvents::ADMIN_PRODUCT_EDIT_SEARCH, $event);
521
522 6
        $searchForm = $builder->getForm();
523
524 6
        if ('POST' === $request->getMethod()) {
525
            $searchForm->handleRequest($request);
526
        }
527
528 6
        return $app->render('Product/product.twig', array(
529 6
            'Product' => $Product,
530 6
            'form' => $form->createView(),
531 6
            'searchForm' => $searchForm->createView(),
532 6
            'has_class' => $has_class,
533 6
            'id' => $id,
534
        ));
535
    }
536
537 2
    public function delete(Application $app, Request $request, $id = null)
0 ignored issues
show
introduced by
Missing function doc comment
Loading history...
538
    {
539 2
        $this->isTokenValid($app);
540 2
        $session = $request->getSession();
541 2
        $page_no = intval($session->get('eccube.admin.product.search.page_no'));
542 2
        $page_no = $page_no ? $page_no : Constant::ENABLED;
543
544 2
        if (!is_null($id)) {
545
            /* @var $Product \Eccube\Entity\Product */
546 2
            $Product = $app['eccube.repository.product']->find($id);
547 2
            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 2
            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 2
                log_info('商品削除開始', array($id));
555
556 2
                $Product->setDelFlg(Constant::ENABLED);
557
558 2
                $ProductClasses = $Product->getProductClasses();
559 2
                $deleteImages = array();
560 2
                foreach ($ProductClasses as $ProductClass) {
561 2
                    $ProductClass->setDelFlg(Constant::ENABLED);
562 2
                    $Product->removeProductClass($ProductClass);
563
564 2
                    $ProductClasses = $Product->getProductClasses();
565 2
                    foreach ($ProductClasses as $ProductClass) {
566 2
                        $ProductClass->setDelFlg(Constant::ENABLED);
567 2
                        $Product->removeProductClass($ProductClass);
568
569 2
                        $ProductStock = $ProductClass->getProductStock();
570 2
                        $app['orm.em']->remove($ProductStock);
571
                    }
572
573 2
                    $ProductImages = $Product->getProductImage();
574 2
                    foreach ($ProductImages as $ProductImage) {
575 2
                        $Product->removeProductImage($ProductImage);
576 2
                        $deleteImages[] = $ProductImage->getFileName();
577 2
                        $app['orm.em']->remove($ProductImage);
578
                    }
579
580 2
                    $ProductCategories = $Product->getProductCategories();
581 2
                    foreach ($ProductCategories as $ProductCategory) {
582 2
                        $Product->removeProductCategory($ProductCategory);
583 2
                        $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 2
                $app['orm.em']->persist($Product);
589
590 2
                $app['orm.em']->flush();
591
592 2
                $event = new EventArgs(
593
                    array(
594 2
                        'Product' => $Product,
595 2
                        'ProductClass' => $ProductClasses,
596 2
                        'deleteImages' => $deleteImages,
597
                    ),
598
                    $request
599
                );
600 2
                $app['eccube.event.dispatcher']->dispatch(EccubeEvents::ADMIN_PRODUCT_DELETE_COMPLETE, $event);
601 2
                $deleteImages = $event->getArgument('deleteImages');
602
603
                // 画像ファイルの削除(commit後に削除させる)
604 2
                foreach ($deleteImages as $deleteImage) {
605
                    try {
606 2 View Code Duplication
                        if (!empty($deleteImage)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
607 2
                            $fs = new Filesystem();
608 2
                            $fs->remove($app['config']['image_save_realdir'].'/'.$deleteImage);
609
                        }
610 2
                    } catch (\Exception $e) {
611
                        // エラーが発生しても無視する
612
                    }
613
                }
614
615 2
                log_info('商品削除完了', array($id));
616
617 2
                $app->addSuccess('admin.delete.complete', 'admin');
618
            } else {
619
                log_info('商品削除エラー', array($id));
620 2
                $app->addError('admin.delete.failed', 'admin');
621
            }
622
        } else {
623
            log_info('商品削除エラー', array($id));
624
            $app->addError('admin.delete.failed', 'admin');
625
        }
626
627 2
        return $app->redirect($app->url('admin_product_page', array('page_no' => $page_no)).'?resume='.Constant::ENABLED);
628
    }
629
630 2
    public function copy(Application $app, Request $request, $id = null)
0 ignored issues
show
introduced by
Missing function doc comment
Loading history...
631
    {
632 2
        $this->isTokenValid($app);
633
634 2
        if (!is_null($id)) {
635 2
            $Product = $app['eccube.repository.product']->find($id);
636 2
            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 2
                $CopyProduct = clone $Product;
638 2
                $CopyProduct->copy();
639 2
                $Disp = $app['eccube.repository.master.disp']->find(\Eccube\Entity\Master\Disp::DISPLAY_HIDE);
640 2
                $CopyProduct->setStatus($Disp);
641
642 2
                $CopyProductCategories = $CopyProduct->getProductCategories();
643 2
                foreach ($CopyProductCategories as $Category) {
644 2
                    $app['orm.em']->persist($Category);
645
                }
646
647
                // 規格あり商品の場合は, デフォルトの商品規格を取得し登録する.
648 2
                if ($CopyProduct->hasProductClass()) {
649 2
                    $softDeleteFilter = $app['orm.em']->getFilters()->getFilter('soft_delete');
650 2
                    $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 2
                    ));
653 2
                    $dummyClass = $app['eccube.repository.product_class']->findOneBy(array(
654 2
                        'del_flg' => \Eccube\Common\Constant::ENABLED,
655
                        'ClassCategory1' => null,
656
                        'ClassCategory2' => null,
657 2
                        'Product' => $Product,
658
                    ));
659 2
                    $dummyClass = clone $dummyClass;
660 2
                    $dummyClass->setProduct($CopyProduct);
661 2
                    $CopyProduct->addProductClass($dummyClass);
662 2
                    $softDeleteFilter->setExcludes(array());
663
                }
664
665 2
                $CopyProductClasses = $CopyProduct->getProductClasses();
666 2
                foreach ($CopyProductClasses as $Class) {
667 2
                    $Stock = $Class->getProductStock();
668 2
                    $CopyStock = clone $Stock;
669 2
                    $CopyStock->setProductClass($Class);
670 2
                    $app['orm.em']->persist($CopyStock);
671
672 2
                    $app['orm.em']->persist($Class);
673
                }
674 2
                $Images = $CopyProduct->getProductImage();
675 2
                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 2
                    $extension = pathinfo($Image->getFileName(), PATHINFO_EXTENSION);
679 2
                    $filename = date('mdHis').uniqid('_').'.'.$extension;
680
                    try {
681 2
                        $fs = new Filesystem();
682 2
                        $fs->copy($app['config']['image_save_realdir'].'/'.$Image->getFileName(), $app['config']['image_save_realdir'].'/'.$filename);
683 2
                    } catch (\Exception $e) {
684
                        // エラーが発生しても無視する
685
                    }
686 2
                    $Image->setFileName($filename);
687
688 2
                    $app['orm.em']->persist($Image);
689
                }
690 2
                $Tags = $CopyProduct->getProductTag();
691 2
                foreach ($Tags as $Tag) {
692 2
                    $app['orm.em']->persist($Tag);
693
                }
694
695 2
                $app['orm.em']->persist($CopyProduct);
696
697 2
                $app['orm.em']->flush();
698
699 2
                $event = new EventArgs(
700
                    array(
701 2
                        'Product' => $Product,
702 2
                        'CopyProduct' => $CopyProduct,
703 2
                        'CopyProductCategories' => $CopyProductCategories,
704 2
                        'CopyProductClasses' => $CopyProductClasses,
705 2
                        'images' => $Images,
706 2
                        'Tags' => $Tags,
707
                    ),
708
                    $request
709
                );
710 2
                $app['eccube.event.dispatcher']->dispatch(EccubeEvents::ADMIN_PRODUCT_COPY_COMPLETE, $event);
711
712 2
                $app->addSuccess('admin.product.copy.complete', 'admin');
713
714 2
                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 1
    public function display(Application $app, Request $request, $id = null)
0 ignored issues
show
introduced by
Missing function doc comment
Loading history...
726
    {
727 1
        $event = new EventArgs(
728 1
            array(),
729
            $request
730
        );
731 1
        $app['eccube.event.dispatcher']->dispatch(EccubeEvents::ADMIN_PRODUCT_DISPLAY_COMPLETE, $event);
732
733 1
        if (!is_null($id)) {
734 1
            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) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
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)
0 ignored issues
show
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...
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