Failed Conditions
Push — experimental/3.1 ( c6bbe9...5ca513 )
by Yangsin
235:43 queued 228:52
created

ProductClassController::edit()   D

Complexity

Conditions 30
Paths 13

Size

Total Lines 246
Code Lines 140

Duplication

Lines 57
Ratio 23.17 %

Code Coverage

Tests 115
CRAP Score 31.1495

Importance

Changes 0
Metric Value
cc 30
eloc 140
nc 13
nop 3
dl 57
loc 246
ccs 115
cts 129
cp 0.8915
crap 31.1495
rs 4.425
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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 Doctrine\Common\Collections\ArrayCollection;
28
use Doctrine\Common\Collections\Collection;
29
use Doctrine\ORM\EntityManager;
30
use Eccube\Annotation\Inject;
31
use Eccube\Application;
32
use Eccube\Common\Constant;
33
use Eccube\Entity\BaseInfo;
34
use Eccube\Entity\ClassName;
35
use Eccube\Entity\Product;
36
use Eccube\Entity\ProductClass;
37
use Eccube\Entity\ProductStock;
38
use Eccube\Entity\TaxRule;
39
use Eccube\Event\EccubeEvents;
40
use Eccube\Event\EventArgs;
41
use Eccube\Form\Type\Admin\ProductClassType;
42
use Eccube\Repository\ClassCategoryRepository;
43
use Eccube\Repository\Master\ProductTypeRepository;
44
use Eccube\Repository\ProductClassRepository;
45
use Eccube\Repository\ProductRepository;
46
use Eccube\Repository\TaxRuleRepository;
47
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
48
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
49
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
50
use Symfony\Component\EventDispatcher\EventDispatcher;
51
use Symfony\Component\Form\Extension\Core\Type\CollectionType;
52
use Symfony\Component\Form\FormBuilder;
53
use Symfony\Component\Form\FormError;
54
use Symfony\Component\Form\FormFactory;
55
use Symfony\Component\HttpFoundation\RedirectResponse;
56
use Symfony\Component\HttpFoundation\Request;
57
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
58
use Symfony\Component\Validator\Constraints as Assert;
59
60
/**
61
 * @Route(service=ProductClassController::class)
62
 */
63
class ProductClassController
64
{
65
    /**
66
     * @Inject(TaxRuleRepository::class)
67
     * @var TaxRuleRepository
68
     */
69
    protected $taxRuleRepository;
70
71
    /**
72
     * @Inject("config")
73
     * @var array
74
     */
75
    protected $appConfig;
76
77
    /**
78
     * @Inject(ProductTypeRepository::class)
79
     * @var ProductTypeRepository
80
     */
81
    protected $productTypeRepository;
82
83
    /**
84
     * @Inject(ClassCategoryRepository::class)
85
     * @var ClassCategoryRepository
86
     */
87
    protected $classCategoryRepository;
88
89
    /**
90
     * @Inject(ProductClassRepository::class)
91
     * @var ProductClassRepository
92
     */
93
    protected $productClassRepository;
94
95
    /**
96
     * @Inject("orm.em")
97
     * @var EntityManager
98
     */
99
    protected $entityManager;
100
101
    /**
102
     * @Inject(BaseInfo::class)
103
     * @var BaseInfo
104
     */
105
    protected $BaseInfo;
106
107
    /**
108
     * @Inject("eccube.event.dispatcher")
109
     * @var EventDispatcher
110
     */
111
    protected $eventDispatcher;
112
113
    /**
114
     * @Inject("form.factory")
115
     * @var FormFactory
116
     */
117
    protected $formFactory;
118
119
    /**
120
     * @Inject(ProductRepository::class)
121
     * @var ProductRepository
122
     */
123
    protected $productRepository;
124
125
    /**
0 ignored issues
show
introduced by
Doc comment for parameter "$app" missing
Loading history...
introduced by
Doc comment for parameter "$request" missing
Loading history...
introduced by
Doc comment for parameter "$id" missing
Loading history...
126
     * 商品規格が登録されていなければ新規登録、登録されていれば更新画面を表示する
127
     *
128
     * @Route("/{_admin}/product/product/class/{id}", requirements={"id" = "\d+"}, name="admin_product_product_class")
129
     * @Template("Product/product_class.twig")
130
     */
0 ignored issues
show
introduced by
Missing @return tag in function comment
Loading history...
131 10
    public function index(Application $app, Request $request, $id)
132
    {
133
        /** @var $Product \Eccube\Entity\Product */
134 10
        $Product = $this->productRepository->find($id);
135 10
        $hasClassCategoryFlg = false;
136
137 10
        if (!$Product) {
138
            throw new NotFoundHttpException('商品が存在しません');
139
        }
140
141
        // 商品規格情報が存在しなければ新規登録させる
142 10
        if (!$Product->hasProductClass()) {
143
            // 登録画面を表示
144
145 4
            log_info('商品規格新規登録表示', array($id));
146
147 4
            $builder = $this->formFactory->createBuilder();
148
149
            $builder
150 4
                ->add('class_name1', EntityType::class, array(
151 4
                    'class' => 'Eccube\Entity\ClassName',
152 4
                    'choice_label' => 'name',
153 4
                    'placeholder' => '規格1を選択',
154
                    'constraints' => array(
155 4
                        new Assert\NotBlank(),
156
                    ),
157
                ))
158 4
                ->add('class_name2', EntityType::class, array(
159 4
                    'class' => 'Eccube\Entity\ClassName',
160
                    'choice_label' => 'name',
161
                    'placeholder' => '規格2を選択',
162
                    'required' => false,
163
                ));
164
165 4
            $event = new EventArgs(
166
                array(
167 4
                    'builder' => $builder,
168 4
                    'Product' => $Product,
169
                ),
170 4
                $request
171
            );
172 4
            $this->eventDispatcher->dispatch(EccubeEvents::ADMIN_PRODUCT_PRODUCT_CLASS_INDEX_INITIALIZE, $event);
173
174 4
            $form = $builder->getForm();
175
176 4
            $productClassForm = null;
177
178 4
            if ('POST' === $request->getMethod()) {
0 ignored issues
show
Coding Style introduced by
Blank line found at start of control structure
Loading history...
179
180 4
                $form->handleRequest($request);
181
182 4
                if ($form->isValid()) {
0 ignored issues
show
Coding Style introduced by
Blank line found at start of control structure
Loading history...
183
184 4
                    $data = $form->getData();
185
186 4
                    $ClassName1 = $data['class_name1'];
187 4
                    $ClassName2 = $data['class_name2'];
188
189 4
                    log_info('選択された商品規格', array($ClassName1, $ClassName2));
190
191
                    // 各規格が選択されている際に、分類を保有しているか確認
192 4
                    $class1Valied = $this->isValiedCategory($ClassName1);
193 4
                    $class2Valied = $this->isValiedCategory($ClassName2);
194
195
                    // 規格が選択されていないか、選択された状態で分類が保有されていれば、画面表示
196 4
                    if($class1Valied && $class2Valied){
197 4
                        $hasClassCategoryFlg = true;
198
                    }
199
200 4
                    if (!is_null($ClassName2) && $ClassName1->getId() == $ClassName2->getId()) {
201
                        // 規格1と規格2が同じ値はエラー
202
                        $form['class_name2']->addError(new FormError('規格1と規格2は、同じ値を使用できません。'));
203
                    } else {
204
                        // 規格分類が設定されていない商品規格を取得
205 4
                        $orgProductClasses = $Product->getProductClasses();
206 4
                        $sourceProduct = $orgProductClasses[0];
207
208
                        // 規格分類が組み合わされた商品規格を取得
209 4
                        $ProductClasses = $this->createProductClasses($app, $Product, $ClassName1, $ClassName2);
210
211
                        // 組み合わされた商品規格にデフォルト値をセット
212 4
                        foreach ($ProductClasses as $productClass) {
213 4
                            $this->setDefaultProductClass($app, $productClass, $sourceProduct);
214
                        }
215
216 4
                        $builder = $this->formFactory->createBuilder();
217
218
                        $builder
219 4
                            ->add('product_classes', CollectionType::class, array(
220 4
                                'entry_type' => ProductClassType::class,
221
                                'allow_add' => true,
222
                                'allow_delete' => true,
223 4
                                'data' => $ProductClasses,
224
                             ));
0 ignored issues
show
Coding Style introduced by
This line of the multi-line function call does not seem to be indented correctly. Expected 28 spaces, but found 29.
Loading history...
225
226 4
                        $event = new EventArgs(
227
                            array(
228 4
                                'builder' => $builder,
229 4
                                'Product' => $Product,
230 4
                                'ProductClasses' => $ProductClasses,
231
                            ),
232 4
                            $request
233
                        );
234 4
                        $this->eventDispatcher->dispatch(EccubeEvents::ADMIN_PRODUCT_PRODUCT_CLASS_INDEX_CLASSES, $event);
235
236 4
                        $productClassForm = $builder->getForm()->createView();
237
0 ignored issues
show
Coding Style introduced by
Blank line found at end of control structure
Loading history...
238
                    }
239
0 ignored issues
show
Coding Style introduced by
Blank line found at end of control structure
Loading history...
240
                }
241
            }
242
243
            return [
244 4
                'form' => $form->createView(),
245 4
                'classForm' => $productClassForm,
246 4
                'Product' => $Product,
247
                'not_product_class' => true,
248
                'error' => null,
249 4
                'has_class_category_flg' => $hasClassCategoryFlg,
250
            ];
251
        } else {
252
            // 既に商品規格が登録されている場合、商品規格画面を表示する
253
254 6
            log_info('商品規格登録済表示', array($id));
255
256
            // 既に登録されている商品規格を取得
257 6
            $ProductClasses = $this->getProductClassesExcludeNonClass($Product);
258
259
            // 設定されている規格分類1、2を取得(商品規格の規格分類には必ず同じ値がセットされている)
260 6
            $ProductClass = $ProductClasses->first();
261 6
            $ClassName1 = $ProductClass->getClassCategory1()->getClassName();
262 6
            $ClassName2 = null;
263 6
            if (!is_null($ProductClass->getClassCategory2())) {
264 6
                $ClassName2 = $ProductClass->getClassCategory2()->getClassName();
265
            }
266
267
            // 規格分類が組み合わされた空の商品規格を取得
268 6
            $createProductClasses = $this->createProductClasses($app, $Product, $ClassName1, $ClassName2);
269
270 6
            $mergeProductClasses = array();
271
272
            // 商品税率が設定されている場合、商品税率を項目に設定
273 6
            if ($this->BaseInfo->getOptionProductTaxRule() == Constant::ENABLED) {
274 6
                foreach ($ProductClasses as $class) {
275 6
                    if ($class->getTaxRule()) {
276 6
                        $class->setTaxRate($class->getTaxRule()->getTaxRate());
277
                    }
278
                }
279
            }
280
281
            // 登録済み商品規格と空の商品規格をマージ
282 6
            $flag = false;
283 6
            foreach ($createProductClasses as $createProductClass) {
284
                // 既に登録済みの商品規格にチェックボックスを設定
285 6
                foreach ($ProductClasses as $productClass) {
286 6
                    if ($productClass->getClassCategory1() == $createProductClass->getClassCategory1() &&
287 6
                            $productClass->getClassCategory2() == $createProductClass->getClassCategory2()) {
288
                                // チェックボックスを追加
289 6
                                $productClass->setAdd(true);
290 6
                                $flag = true;
291 6
                                break;
292
                    }
293
                }
294
295 6
                if (!$flag) {
296 1
                    $mergeProductClasses[] = $createProductClass;
297
                }
298
299 6
                $flag = false;
300
            }
301
302
            // 登録済み商品規格と空の商品規格をマージ
303 6
            foreach ($mergeProductClasses as $mergeProductClass) {
304
                // 空の商品規格にデフォルト値を設定
305 1
                $this->setDefaultProductClass($app, $mergeProductClass, $ProductClass);
306 1
                $ProductClasses->add($mergeProductClass);
307
            }
308
309 6
            $builder = $this->formFactory->createBuilder();
310
311
            $builder
312 6
                ->add('product_classes', CollectionType::class, array(
313 6
                    'entry_type' => ProductClassType::class,
314
                    'allow_add' => true,
315
                    'allow_delete' => true,
316 6
                    'data' => $ProductClasses,
317
                ));
318
319 6
            $event = new EventArgs(
320
                array(
321 6
                    'builder' => $builder,
322 6
                    'Product' => $Product,
323 6
                    'ProductClasses' => $ProductClasses,
324
                ),
325 6
                $request
326
            );
327 6
            $this->eventDispatcher->dispatch(EccubeEvents::ADMIN_PRODUCT_PRODUCT_CLASS_INDEX_CLASSES, $event);
328
329 6
            $productClassForm = $builder->getForm()->createView();
330
331
            return [
332 6
                'classForm' => $productClassForm,
333 6
                'Product' => $Product,
334 6
                'class_name1' => $ClassName1,
335 6
                'class_name2' => $ClassName2,
336
                'not_product_class' => false,
337
                'error' => null,
338
                'has_class_category_flg' => true,
339
            ];
340
        }
341
    }
342
343
    /**
344
     * 商品規格の登録、更新、削除を行う
345
     *
346
     * @Route("/{_admin}/product/product/class/edit/{id}", requirements={"id" = "\d+"}, name="admin_product_product_class_edit")
347
     * @Template("Product/product_class.twig")
348
     *
349
     * @param Application $app
350
     * @param Request     $request
351
     * @param int         $id
352
     * @return RedirectResponse
353
     */
354 11
    public function edit(Application $app, Request $request, $id)
355
    {
356
        /** @var $Product \Eccube\Entity\Product */
357 11
        $Product = $this->productRepository->find($id);
358
359 11
        if (!$Product) {
360
            throw new NotFoundHttpException('商品が存在しません');
361
        }
362
363
        /* @var FormBuilder $builder */
364 11
        $builder = $this->formFactory->createBuilder();
365 11
        $builder->add('product_classes', CollectionType::class, array(
366 11
                    'entry_type' => ProductClassType::class,
367
                    'allow_add' => true,
368
                    'allow_delete' => true,
369
        ));
370
371 11
        $event = new EventArgs(
372
            array(
373 11
                'builder' => $builder,
374 11
                'Product' => $Product,
375
            ),
376 11
            $request
377
        );
378 11
        $this->eventDispatcher->dispatch(EccubeEvents::ADMIN_PRODUCT_PRODUCT_CLASS_EDIT_INITIALIZE, $event);
379
380 11
        $form = $builder->getForm();
381
382 11
        $ProductClasses = $this->getProductClassesExcludeNonClass($Product);
383
384 11
        $form->handleRequest($request);
385 11
        if ($form->isSubmitted()) {
386 10
            switch ($request->get('mode')) {
387 10
                case 'edit':
388
                    // 新規登録
389 4
                    log_info('商品規格新規登録開始', array($id));
390
391 4 View Code Duplication
                    if (count($ProductClasses) > 0) {
392
                        // 既に登録されていれば最初の画面に戻す
393
                        log_info('商品規格登録済', array($id));
394
                        return $app->redirect($app->url('admin_product_product_class', array('id' => $id)));
0 ignored issues
show
introduced by
Missing blank line before return statement
Loading history...
395
                    }
396
397 4
                    $addProductClasses = array();
398
399 4
                    $tmpProductClass = null;
400 4 View Code Duplication
                    foreach ($form->get('product_classes') as $formData) {
401
                        // 追加対象の行をvalidate
402 4
                        $ProductClass = $formData->getData();
403
404 4
                        if ($ProductClass->getAdd()) {
405 4
                            if ($formData->isValid()) {
406 3
                                $addProductClasses[] = $ProductClass;
407
                            } else {
408
                                // 対象行のエラー
409 1
                                return $this->render($app, $Product, $ProductClass, true, $form);
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $this->render($ap...uctClass, true, $form); (array) is incompatible with the return type documented by Eccube\Controller\Admin\...ctClassController::edit of type Symfony\Component\HttpFoundation\RedirectResponse.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
410
                            }
411
                        }
412 3
                        $tmpProductClass = $ProductClass;
413
                    }
414
415 3 View Code Duplication
                    if (count($addProductClasses) == 0) {
416
                        // 対象がなければエラー
417
                        log_info('商品規格が未選択', array($id));
418
                        $error = array('message' => '商品規格が選択されていません。');
419
                        return $this->render($app, $Product, $tmpProductClass, true, $form, $error);
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $this->render($ap..., true, $form, $error); (array) is incompatible with the return type documented by Eccube\Controller\Admin\...ctClassController::edit of type Symfony\Component\HttpFoundation\RedirectResponse.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
introduced by
Missing blank line before return statement
Loading history...
420
                    }
421
422
                    // 選択された商品規格を登録
423 3
                    $this->insertProductClass($app, $Product, $addProductClasses);
424
425
                    // デフォルトの商品規格を非表示
426
                    /** @var ProductClass $defaultProductClass */
427 3
                    $defaultProductClass = $this->productClassRepository
428 3
                            ->findOneBy(array('Product' => $Product, 'ClassCategory1' => null, 'ClassCategory2' => null));
429 3
                    $defaultProductClass->setVisible(false);
430
431 3
                    $this->entityManager->flush();
432
433 3
                    log_info('商品規格新規登録完了', array($id));
434
435 3
                    $event = new EventArgs(
436
                        array(
437 3
                            'form' => $form,
438 3
                            'Product' => $Product,
439 3
                            'defaultProductClass' => $defaultProductClass,
440
                        ),
441 3
                        $request
442
                    );
443 3
                    $this->eventDispatcher->dispatch(EccubeEvents::ADMIN_PRODUCT_PRODUCT_CLASS_EDIT_COMPLETE, $event);
444
445 3
                    $app->addSuccess('admin.product.product_class.save.complete', 'admin');
446
447 3
                    break;
448 6
                case 'update':
449
                    // 更新
450 5
                    log_info('商品規格更新開始', array($id));
451
452 5 View Code Duplication
                    if (count($ProductClasses) == 0) {
453
                        // 商品規格が0件であれば最初の画面に戻す
454
                        log_info('商品規格が存在しません', array($id));
455
                        return $app->redirect($app->url('admin_product_product_class', array('id' => $id)));
0 ignored issues
show
introduced by
Missing blank line before return statement
Loading history...
456
                    }
457
458 5
                    $checkProductClasses = array();
459 5
                    $removeProductClasses = array();
460
461 5
                    $tempProductClass = null;
462 5 View Code Duplication
                    foreach ($form->get('product_classes') as $formData) {
463
                        // 追加対象の行をvalidate
464 5
                        $ProductClass = $formData->getData();
465
466 5
                        if ($ProductClass->getAdd()) {
467 5
                            if ($formData->isValid()) {
468 4
                                $checkProductClasses[] = $ProductClass;
469
                            } else {
470 5
                                return $this->render($app, $Product, $ProductClass, false, $form);
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $this->render($ap...ctClass, false, $form); (array) is incompatible with the return type documented by Eccube\Controller\Admin\...ctClassController::edit of type Symfony\Component\HttpFoundation\RedirectResponse.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
471
                            }
472
                        } else {
473
                            // 削除対象の行
474 1
                            $removeProductClasses[] = $ProductClass;
475
                        }
476 4
                        $tempProductClass = $ProductClass;
477
                    }
478
479 4 View Code Duplication
                    if (count($checkProductClasses) == 0) {
480
                        // 対象がなければエラー
481
                        log_info('商品規格が存在しません', array($id));
482
                        $error = array('message' => '商品規格が選択されていません。');
483
                        return $this->render($app, $Product, $tempProductClass, false, $form, $error);
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $this->render($ap... false, $form, $error); (array) is incompatible with the return type documented by Eccube\Controller\Admin\...ctClassController::edit of type Symfony\Component\HttpFoundation\RedirectResponse.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
introduced by
Missing blank line before return statement
Loading history...
484
                    }
485
486
487
                    // 登録対象と更新対象の行か判断する
488 4
                    $addProductClasses = array();
489 4
                    $updateProductClasses = array();
490 4
                    foreach ($checkProductClasses as $cp) {
491 4
                        $flag = false;
492
493
                        // 既に登録済みの商品規格か確認
494 4
                        foreach ($ProductClasses as $productClass) {
495 4
                            if ($productClass->getProduct()->getId() == $id &&
496 4
                                    $productClass->getClassCategory1() == $cp->getClassCategory1() &&
497 4
                                    $productClass->getClassCategory2() == $cp->getClassCategory2()) {
498 4
                                $updateProductClasses[] = $cp;
499
500
                                // 商品情報
501 4
                                $cp->setProduct($Product);
502
                                // 商品在庫
503 4
                                $productStock = $productClass->getProductStock();
504 4
                                if (!$cp->getStockUnlimited()) {
505 1
                                    $productStock->setStock($cp->getStock());
506
                                } else {
507 3
                                    $productStock->setStock(null);
508
                                }
509 4
                                $this->setDefaultProductClass($app, $productClass, $cp);
510 4
                                $flag = true;
511 4
                                break;
512
                            }
513
                        }
514 4
                        if (!$flag) {
515 4
                            $addProductClasses[] = $cp;
516
                        }
517
                    }
518
519 4
                    foreach ($removeProductClasses as $rc) {
520
                        // 登録されている商品規格を非表示
521
                        /** @var ProductClass $productClass */
522 1
                        foreach ($ProductClasses as $productClass) {
523 1
                            if ($productClass->getProduct()->getId() == $id &&
524 1
                                    $productClass->getClassCategory1() == $rc->getClassCategory1() &&
525 1
                                    $productClass->getClassCategory2() == $rc->getClassCategory2()) {
526 1
                                $productClass->setVisible(false);
527 1
                                break;
528
                            }
529
                        }
530
                    }
531
532
                    // 選択された商品規格を登録
533 4
                    $this->insertProductClass($app, $Product, $addProductClasses);
534
535 4
                    $this->entityManager->flush();
536
537 4
                    log_info('商品規格更新完了', array($id));
538
539 4
                    $event = new EventArgs(
540
                        array(
541 4
                            'form' => $form,
542 4
                            'Product' => $Product,
543 4
                            'updateProductClasses' => $updateProductClasses,
544 4
                            'addProductClasses' => $addProductClasses,
545
                        ),
546 4
                        $request
547
                    );
548 4
                    $this->eventDispatcher->dispatch(EccubeEvents::ADMIN_PRODUCT_PRODUCT_CLASS_EDIT_UPDATE, $event);
549
550 4
                    $app->addSuccess('admin.product.product_class.update.complete', 'admin');
551
552 4
                    break;
553
554 1
                case 'delete':
555
                    // 削除
556 1
                    log_info('商品規格削除開始', array($id));
557
558 1 View Code Duplication
                    if (count($ProductClasses) == 0) {
559
                        // 既に商品が削除されていれば元の画面に戻す
560
                        log_info('商品規格が存在しません', array($id));
561
                        return $app->redirect($app->url('admin_product_product_class', array('id' => $id)));
0 ignored issues
show
introduced by
Missing blank line before return statement
Loading history...
562
                    }
563
564 1
                    foreach ($ProductClasses as $ProductClass) {
565
                        // 登録されている商品規格を非表示
566 1
                        $ProductClass->setVisible(false);
567
                    }
568
569
                    // デフォルトの商品規格を表示
570
                    /** @var ProductClass $defaultProductClass */
571
572 1
                    $defaultProductClass = $this->productClassRepository
573 1
                            ->findOneBy(array('Product' => $Product, 'ClassCategory1' => null, 'ClassCategory2' => null, 'visible' => false));
574 1
                    $defaultProductClass->setVisible(true);
575
576 1
                    $this->entityManager->flush();
577 1
                    log_info('商品規格削除完了', array($id));
578
579 1
                    $event = new EventArgs(
580
                        array(
581 1
                            'form' => $form,
582 1
                            'Product' => $Product,
583 1
                            'defaultProductClass' => $defaultProductClass,
584
                        ),
585 1
                        $request
586
                    );
587 1
                    $this->eventDispatcher->dispatch(EccubeEvents::ADMIN_PRODUCT_PRODUCT_CLASS_EDIT_DELETE, $event);
588
589 1
                    $app->addSuccess('admin.product.product_class.delete.complete', 'admin');
590
591 1
                    break;
592
                default:
593
                    break;
594
            }
595
0 ignored issues
show
Coding Style introduced by
Blank line found at end of control structure
Loading history...
596
        }
597
598 9
        return $app->redirect($app->url('admin_product_product_class', array('id' => $id)));
599
    }
600
601
    /**
602
     * 登録、更新時のエラー画面表示
603
     *
604
     */
605 2
    protected function render($app, $Product, $ProductClass, $not_product_class, $classForm, $error = null)
606
    {
607
608 2
        $ClassName1 = null;
609 2
        $ClassName2 = null;
610
        // 規格を取得
611 2
        if (isset($ProductClass)) {
612 2
            $ClassCategory1 = $ProductClass->getClassCategory1();
613 2
            if ($ClassCategory1) {
614 2
                $ClassName1 = $ClassCategory1->getClassName();
615
            }
616 2
            $ClassCategory2 = $ProductClass->getClassCategory2();
617 2
            if ($ClassCategory2) {
618 1
                $ClassName2 = $ClassCategory2->getClassName();
619
            }
620
        }
621
622 2
        $form = $app->form()
623 2
            ->add('class_name1', EntityType::class, array(
624 2
                'class' => 'Eccube\Entity\ClassName',
625 2
                'choice_label' => 'name',
626 2
                'placeholder' => '規格1を選択',
627 2
                'data' => $ClassName1,
628
            ))
629 2
            ->add('class_name2', EntityType::class, array(
630 2
                'class' => 'Eccube\Entity\ClassName',
631 2
                'choice_label' => 'name',
632 2
                'placeholder' => '規格2を選択',
633 2
                'data' => $ClassName2,
634
            ))
635 2
            ->getForm();
636
637 2
        log_info('商品規格登録エラー');
638
639
640
        return [
641 2
            'form' => $form->createView(),
642 2
            'classForm' => $classForm->createView(),
643 2
            'Product' => $Product,
644 2
            'class_name1' => $ClassName1,
645 2
            'class_name2' => $ClassName2,
646 2
            'not_product_class' => $not_product_class,
647 2
            'error' => $error,
648
            'has_class_category_flg' => true,
649
        ];
650
    }
651
652
653
    /**
654
     * 規格1と規格2を組み合わせた商品規格を作成
655
     */
656 10
    private function createProductClasses($app, Product $Product, ClassName $ClassName1 = null, ClassName $ClassName2 = null)
657
    {
658
659 10
        $ClassCategories1 = array();
660 10
        if ($ClassName1) {
661 10
            $ClassCategories1 = $this->classCategoryRepository->findBy(array('ClassName' => $ClassName1));
662
        }
663
664 10
        $ClassCategories2 = array();
665 10
        if ($ClassName2) {
666 6
            $ClassCategories2 = $this->classCategoryRepository->findBy(array('ClassName' => $ClassName2));
667
        }
668
669 10
        $ProductClasses = array();
670 10
        foreach ($ClassCategories1 as $ClassCategory1) {
671 10
            if ($ClassCategories2) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $ClassCategories2 of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
672 6
                foreach ($ClassCategories2 as $ClassCategory2) {
673 6
                    $ProductClass = $this->newProductClass($app);
674 6
                    $ProductClass->setProduct($Product);
675 6
                    $ProductClass->setClassCategory1($ClassCategory1);
676 6
                    $ProductClass->setClassCategory2($ClassCategory2);
677 6
                    $ProductClass->setTaxRate(null);
678 6
                    $ProductClass->setVisible(true);
679 6
                    $ProductClasses[] = $ProductClass;
680
                }
681
            } else {
682 4
                $ProductClass = $this->newProductClass($app);
683 4
                $ProductClass->setProduct($Product);
684 4
                $ProductClass->setClassCategory1($ClassCategory1);
685 4
                $ProductClass->setTaxRate(null);
686 4
                $ProductClass->setVisible(true);
687 10
                $ProductClasses[] = $ProductClass;
688
            }
689
0 ignored issues
show
Coding Style introduced by
Blank line found at end of control structure
Loading history...
690
        }
691 10
        return $ProductClasses;
0 ignored issues
show
introduced by
Missing blank line before return statement
Loading history...
692
    }
693
694
    /**
695
     * 新しい商品規格を作成
696
     */
697 10
    private function newProductClass(Application $app)
0 ignored issues
show
Unused Code introduced by
The parameter $app is not used and could be removed.

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

Loading history...
698
    {
699 10
        $ProductType = $this->productTypeRepository->find($this->appConfig['product_type_normal']);
700
701 10
        $ProductClass = new ProductClass();
702 10
        $ProductClass->setProductType($ProductType);
703 10
        return $ProductClass;
0 ignored issues
show
introduced by
Missing blank line before return statement
Loading history...
704
    }
705
706
    /**
707
     * 商品規格のコピーを取得.
708
     *
709
     * @see http://symfony.com/doc/current/cookbook/form/form_collections.html
710
     * @param Product $Product
711
     * @return \Eccube\Entity\ProductClass[]
712
     */
713
    private function getProductClassesOriginal(Product $Product)
0 ignored issues
show
Unused Code introduced by
This method is not used, and could be removed.
Loading history...
714
    {
715
        $ProductClasses = $Product->getProductClasses();
716
        return $ProductClasses->filter(function($ProductClass) {
0 ignored issues
show
Unused Code introduced by
The parameter $ProductClass is not used and could be removed.

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

Loading history...
introduced by
Missing blank line before return statement
Loading history...
Coding Style introduced by
Expected 1 space after FUNCTION keyword; 0 found
Loading history...
717
            return true;
718
        });
719
    }
720
721
    /**
722
     * 規格なし商品を除いて商品規格を取得.
723
     *
724
     * @param Product $Product
725
     * @return Collection
726
     */
727 11
    private function getProductClassesExcludeNonClass(Product $Product)
728
    {
729 11
        $ProductClasses = $Product->getProductClasses();
730 11
        return new ArrayCollection(array_values($ProductClasses->filter(function($ProductClass) {
0 ignored issues
show
introduced by
Missing blank line before return statement
Loading history...
Coding Style introduced by
Expected 1 space after FUNCTION keyword; 0 found
Loading history...
731 11
            $ClassCategory1 = $ProductClass->getClassCategory1();
732 11
            $ClassCategory2 = $ProductClass->getClassCategory2();
733 11
            return ($ClassCategory1 || $ClassCategory2);
0 ignored issues
show
introduced by
Missing blank line before return statement
Loading history...
734 11
        })->toArray()));
735
    }
736
737
    /**
738
     * デフォルトとなる商品規格を設定
739
     *
740
     * @param $productClassDest ProductClass コピー先となる商品規格
741
     * @param $productClassOrig ProductClass コピー元となる商品規格
742
     */
743 8
    private function setDefaultProductClass($app, $productClassDest, $productClassOrig) {
0 ignored issues
show
Unused Code introduced by
The parameter $app is not used and could be removed.

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

Loading history...
744 8
        $productClassDest->setDeliveryDate($productClassOrig->getDeliveryDate());
745 8
        $productClassDest->setProduct($productClassOrig->getProduct());
746 8
        $productClassDest->setProductType($productClassOrig->getProductType());
747 8
        $productClassDest->setCode($productClassOrig->getCode());
748 8
        $productClassDest->setStock($productClassOrig->getStock());
749 8
        $productClassDest->setStockUnlimited($productClassOrig->getStockUnlimited());
750 8
        $productClassDest->setSaleLimit($productClassOrig->getSaleLimit());
751 8
        $productClassDest->setPrice01($productClassOrig->getPrice01());
752 8
        $productClassDest->setPrice02($productClassOrig->getPrice02());
753 8
        $productClassDest->setDeliveryFee($productClassOrig->getDeliveryFee());
754
755
        // 個別消費税
756 8
        if ($this->BaseInfo->getOptionProductTaxRule() == Constant::ENABLED) {
757 8
            if ($productClassOrig->getTaxRate() !== false && $productClassOrig->getTaxRate() !== null) {
758 3
                $productClassDest->setTaxRate($productClassOrig->getTaxRate());
759 3 View Code Duplication
                if ($productClassDest->getTaxRule()) {
760
                    $productClassDest->getTaxRule()->setTaxRate($productClassOrig->getTaxRate());
761
                } else {
762 3
                    $taxrule = $this->taxRuleRepository->newTaxRule();
763 3
                    $taxrule->setTaxRate($productClassOrig->getTaxRate());
764 3
                    $taxrule->setApplyDate(new \DateTime());
765 3
                    $taxrule->setProduct($productClassDest->getProduct());
766 3
                    $taxrule->setProductClass($productClassDest);
767 3
                    $productClassDest->setTaxRule($taxrule);
768
                }
769
            } else {
770 8
                if ($productClassDest->getTaxRule()) {
771
                    $this->taxRuleRepository->delete($productClassDest->getTaxRule());
772
                    $productClassDest->setTaxRule(null);
773
                }
774
            }
775
        }
776
    }
777
778
779
    /**
780
     * 商品規格を登録
781
     *
782
     * @param Application     $app
783
     * @param Product         $Product
784
     * @param ProductClass[] $ProductClasses 登録される商品規格
785
     */
786 7
    private function insertProductClass($app, $Product, $ProductClasses) {
0 ignored issues
show
Unused Code introduced by
The parameter $app is not used and could be removed.

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

Loading history...
787
788
789
        // 選択された商品を登録
790 7
        foreach ($ProductClasses as $ProductClass) {
0 ignored issues
show
Coding Style introduced by
Blank line found at start of control structure
Loading history...
791
792 3
            $ProductClass->setVisible(true);
793 3
            $ProductClass->setProduct($Product);
794 3
            $this->entityManager->persist($ProductClass);
795
796
            // 在庫情報を作成
797 3
            $ProductStock = new ProductStock();
798 3
            $ProductClass->setProductStock($ProductStock);
799 3
            $ProductStock->setProductClass($ProductClass);
800 3
            if (!$ProductClass->getStockUnlimited()) {
801 3
                $ProductStock->setStock($ProductClass->getStock());
802
            } else {
803
                // 在庫無制限時はnullを設定
804
                $ProductStock->setStock(null);
805
            }
806 3
            $this->entityManager->persist($ProductStock);
807
0 ignored issues
show
Coding Style introduced by
Blank line found at end of control structure
Loading history...
808
        }
809
810
        // 商品税率が設定されている場合、商品税率をセット
811 7
        if ($this->BaseInfo->getOptionProductTaxRule() == Constant::ENABLED) {
812
            // 初期設定の税設定.
813 7
            $TaxRule = $this->taxRuleRepository->find(TaxRule::DEFAULT_TAX_RULE_ID);
814
            // 初期税率設定の計算方法を設定する
815 7
            $RoundingType = $TaxRule->getRoundingType();
816 7
            foreach ($ProductClasses as $ProductClass) {
817 3
                if ($ProductClass && is_numeric($taxRate = $ProductClass->getTaxRate())) {
818 2
                    $TaxRule = new TaxRule();
819 2
                    $TaxRule->setProduct($Product);
820 2
                    $TaxRule->setProductClass($ProductClass);
821 2
                    $TaxRule->setRoundingType($RoundingType);
822 2
                    $TaxRule->setTaxRate($taxRate);
823 2
                    $TaxRule->setTaxAdjust(0);
824 2
                    $TaxRule->setApplyDate(new \DateTime());
825 3
                    $this->entityManager->persist($TaxRule);
826
                }
827
            }
828
        }
829
830
    }
831
832
    /**
833
     * 規格の分類判定
834
     *
835
     * @param $class_name
836
     * @return boolean
837
     */
838 4
    private function isValiedCategory($class_name)
839
    {
840 4
        if (empty($class_name)) {
841 4
            return true;
842
        }
843 4
        if (count($class_name->getClassCategories()) < 1) {
844
            return false;
845
        }
846 4
        return true;
0 ignored issues
show
introduced by
Missing blank line before return statement
Loading history...
847
    }
848
}
849