Issues (2366)

Branch: master

Security Analysis    not enabled

This project does not seem to handle request data directly as such no vulnerable execution paths were found.

  Cross-Site Scripting
Cross-Site Scripting enables an attacker to inject code into the response of a web-request that is viewed by other users. It can for example be used to bypass access controls, or even to take over other users' accounts.
  File Exposure
File Exposure allows an attacker to gain access to local files that he should not be able to access. These files can for example include database credentials, or other configuration files.
  File Manipulation
File Manipulation enables an attacker to write custom data to files. This potentially leads to injection of arbitrary code on the server.
  Object Injection
Object Injection enables an attacker to inject an object into PHP code, and can lead to arbitrary code execution, file exposure, or file manipulation attacks.
  Code Injection
Code Injection enables an attacker to execute arbitrary code on the server.
  Response Splitting
Response Splitting can be used to send arbitrary responses.
  File Inclusion
File Inclusion enables an attacker to inject custom files into PHP's file loading mechanism, either explicitly passed to include, or for example via PHP's auto-loading mechanism.
  Command Injection
Command Injection enables an attacker to inject a shell command that is execute with the privileges of the web-server. This can be used to expose sensitive data, or gain access of your server.
  SQL Injection
SQL Injection enables an attacker to execute arbitrary SQL code on your database server gaining access to user data, or manipulating user data.
  XPath Injection
XPath Injection enables an attacker to modify the parts of XML document that are read. If that XML document is for example used for authentication, this can lead to further vulnerabilities similar to SQL Injection.
  LDAP Injection
LDAP Injection enables an attacker to inject LDAP statements potentially granting permission to run unauthorized queries, or modify content inside the LDAP tree.
  Header Injection
  Other Vulnerability
This category comprises other attack vectors such as manipulating the PHP runtime, loading custom extensions, freezing the runtime, or similar.
  Regex Injection
Regex Injection enables an attacker to execute arbitrary code in your PHP process.
  XML Injection
XML Injection enables an attacker to read files on your local filesystem including configuration files, or can be abused to freeze your web-server process.
  Variable Injection
Variable Injection enables an attacker to overwrite program variables with custom data, and can lead to further vulnerabilities.
Unfortunately, the security analysis is currently not available for your project. If you are a non-commercial open-source project, please contact support to gain access.

Controller/Admin/Product/ProductController.php (1 issue)

Upgrade to new PHP Analysis Engine

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

1
<?php
2
/*
3
 * This file is part of EC-CUBE
4
 *
5
 * Copyright(c) 2000-2015 LOCKON CO.,LTD. All Rights Reserved.
6
 *
7
 * http://www.lockon.co.jp/
8
 *
9
 * This program is free software; you can redistribute it and/or
10
 * modify it under the terms of the GNU General Public License
11
 * as published by the Free Software Foundation; either version 2
12
 * of the License, or (at your option) any later version.
13
 *
14
 * This program is distributed in the hope that it will be useful,
15
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17
 * GNU General Public License for more details.
18
 *
19
 * You should have received a copy of the GNU General Public License
20
 * along with this program; if not, write to the Free Software
21
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
22
 */
23
24
25
namespace Eccube\Controller\Admin\Product;
26
27
use Eccube\Application;
28
use Eccube\Common\Constant;
29
use Eccube\Controller\AbstractController;
30
use Eccube\Entity\Master\CsvType;
31
use Eccube\Entity\ProductTag;
32
use Eccube\Event\EccubeEvents;
33
use Eccube\Event\EventArgs;
34
use Eccube\Service\CsvExportService;
35
use Eccube\Util\FormUtil;
36
use Symfony\Component\Filesystem\Filesystem;
37
use Symfony\Component\HttpFoundation\File\File;
38
use Symfony\Component\HttpFoundation\Request;
39 1
use Symfony\Component\HttpFoundation\StreamedResponse;
40
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
41
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
42
use Symfony\Component\HttpKernel\Exception\UnsupportedMediaTypeHttpException;
43
44
class ProductController extends AbstractController
45
{
46
    public function index(Application $app, Request $request, $page_no = null)
47
    {
48 1
49
        $session = $app['session'];
50
51
        $builder = $app['form.factory']
52
            ->createBuilder('admin_search_product');
53 1
54 1
        $event = new EventArgs(
55
            array(
56
                'builder' => $builder,
57
            ),
58
            $request
59
        );
60
        $app['eccube.event.dispatcher']->dispatch(EccubeEvents::ADMIN_PRODUCT_INDEX_INITIALIZE, $event);
61
62
        $searchForm = $builder->getForm();
63
64
        $pagination = array();
65
66
        $disps = $app['eccube.repository.master.disp']->findAll();
67
        $pageMaxis = $app['eccube.repository.master.page_max']->findAll();
68
69
        // 表示件数は順番で取得する、1.SESSION 2.設定ファイル
70
        $page_count = $session->get('eccube.admin.product.search.page_count', $app['config']['default_page_count']);
71
        // 表示件数
72
73
        $page_count_param = $request->get('page_count');
74
        // 表示件数はURLパラメターから取得する
75 View Code Duplication
        if ($page_count_param && is_numeric($page_count_param)) {
76
            foreach ($pageMaxis as $pageMax) {
77
                if ($page_count_param == $pageMax->getName()) {
78
                    $page_count = $pageMax->getName();
79
                    // 表示件数入力値正し場合はSESSIONに保存する
80
                    $session->set('eccube.admin.product.search.page_count', $page_count);
81
                    break;
82
                }
83
            }
84
        }
85
86
        $page_status = null;
87
        $active = false;
88
89
        if ('POST' === $request->getMethod()) {
90
91
            $searchForm->handleRequest($request);
92
93
            if ($searchForm->isValid()) {
94
                $searchData = $searchForm->getData();
95
96
                // paginator
97
                $qb = $app['eccube.repository.product']->getQueryBuilderBySearchDataForAdmin($searchData);
98
                $page_no = 1;
99
100
                $event = new EventArgs(
101
                    array(
102
                        'qb' => $qb,
103
                        'searchData' => $searchData,
104
                    ),
105
                    $request
106
                );
107
                $app['eccube.event.dispatcher']->dispatch(EccubeEvents::ADMIN_PRODUCT_INDEX_SEARCH, $event);
108
                $searchData = $event->getArgument('searchData');
109
110
                $pagination = $app['paginator']()->paginate(
111
                    $qb,
112
                    $page_no,
113
                    $page_count,
114
                    array('wrap-queries' => true)
115
                );
116
117
                // sessionに検索条件を保持
118
                $viewData = FormUtil::getViewData($searchForm);
119
                $session->set('eccube.admin.product.search', $viewData);
120
                $session->set('eccube.admin.product.search.page_no', $page_no);
121
            }
122
        } else {
123
            if (is_null($page_no) && $request->get('resume') != Constant::ENABLED) {
124
                // sessionを削除
125
                $session->remove('eccube.admin.product.search');
126
                $session->remove('eccube.admin.product.search.page_no');
127
                $session->remove('eccube.admin.product.search.page_count');
128
            } else {
129
                // pagingなどの処理
130 1
                if (is_null($page_no)) {
131
                    $page_no = intval($session->get('eccube.admin.product.search.page_no'));
132
                } else {
133 1
                    $session->set('eccube.admin.product.search.page_no', $page_no);
134 1
                }
135
                $viewData = $session->get('eccube.admin.product.search');
136
                if (!is_null($viewData)) {
137
                    // 公開ステータス
138
                    // 1:公開, 2:非公開, 3:在庫なし
139
                    $linkStatus = $request->get('status');
140
                    if (!empty($linkStatus)) {
141
                        // リンクステータスは在庫なし:3以外
142
                        if ($linkStatus != $app['config']['admin_product_stock_status']) {
143 1
                            $viewData['link_status'] = $linkStatus;
144
                            $viewData['stock_status'] = null;
145
                            $viewData['status'] = null;
146 View Code Duplication
                        } else {
147
                            // リンクステータスは在庫なし:3
148
                            $viewData['link_status'] = null;
149
                            $viewData['stock_status'] = Constant::DISABLED;
150
                            $viewData['status'] = null;
151
                        }
152
                        // ページステータスを設定します(リンクステータスAタグ表示のために)
153
                        $page_status = $linkStatus;
154 View Code Duplication
                    } else {
155
                        // すべてを選択
156
                        $viewData['link_status'] = null;
157
                        $viewData['stock_status'] = null;
158
                        if (!$viewData['status']) {
159
                            $viewData['status'] = array();
160
                        }
161
                    }
162
163
                    // 表示件数
164 2
                    $page_count = $request->get('page_count', $page_count);
165
                    $searchData = FormUtil::submitAndGetData($searchForm, $viewData);
166
                    if ($viewData['link_status']) {
167
                        $searchData['link_status'] = $app['eccube.repository.master.disp']->find($viewData['link_status']);
168
                    }
169
                    // リンクステータス[在庫なし]設定されている場合は検索パラメター設定する
170
                    if (isset($viewData['stock_status'])) {
171
                        $searchData['stock_status'] = $viewData['stock_status'];
172 2
                    }
173
174
                    $session->set('eccube.admin.product.search', $viewData);
175
176
                    $qb = $app['eccube.repository.product']->getQueryBuilderBySearchDataForAdmin($searchData);
177
178 1
                    $event = new EventArgs(
179 1
                        array(
180
                            'qb' => $qb,
181
                            'searchData' => $searchData,
182 1
                        ),
183 1
                        $request
184
                    );
185
                    $app['eccube.event.dispatcher']->dispatch(EccubeEvents::ADMIN_PRODUCT_INDEX_SEARCH, $event);
186
                    $searchData = $event->getArgument('searchData');
187
188
189
                    $pagination = $app['paginator']()->paginate(
190 1
                        $qb,
191
                        $page_no,
192
                        $page_count,
193
                        array('wrap-queries' => true)
194
                    );
195 1
                }
196
            }
197
        }
198
199
        return $app->render('Product/index.twig', array(
200
            'searchForm' => $searchForm->createView(),
201
            'pagination' => $pagination,
202
            'disps' => $disps,
203
            'pageMaxis' => $pageMaxis,
204 1
            'page_no' => $page_no,
205
            'page_status' => $page_status,
206
            'page_count' => $page_count,
207
            'active' => $active,
208
        ));
209
    }
210 2
211
    public function addImage(Application $app, Request $request)
212
    {
213
        if (!$request->isXmlHttpRequest()) {
214
            throw new BadRequestHttpException('リクエストが不正です');
215 2
        }
216
217
        $images = $request->files->get('admin_product');
218
219
        $files = array();
220
        if (count($images) > 0) {
221 2
            foreach ($images as $img) {
222
                foreach ($img as $image) {
223
                    //ファイルフォーマット検証
224
                    $mimeType = $image->getMimeType();
225 1
                    if (0 !== strpos($mimeType, 'image')) {
226
                        throw new UnsupportedMediaTypeHttpException('ファイル形式が不正です');
227
                    }
228 2
229
                    $extension = $image->getClientOriginalExtension();
230
                    $filename = date('mdHis').uniqid('_').'.'.$extension;
231
                    $image->move($app['config']['image_temp_realdir'], $filename);
232
                    $files[] = $filename;
233 1
                }
234
            }
235
        }
236
237
        $event = new EventArgs(
238
            array(
239
                'images' => $images,
240
                'files' => $files,
241
            ),
242
            $request
243
        );
244
        $app['eccube.event.dispatcher']->dispatch(EccubeEvents::ADMIN_PRODUCT_ADD_IMAGE_COMPLETE, $event);
245
        $files = $event->getArgument('files');
246
247
        return $app->json(array('files' => $files), 200);
248
    }
249
250
    public function edit(Application $app, Request $request, $id = null)
251
    {
252
        $has_class = false;
253
        if (is_null($id)) {
254
            $Product = new \Eccube\Entity\Product();
255
            $ProductClass = new \Eccube\Entity\ProductClass();
256
            $Disp = $app['eccube.repository.master.disp']->find(\Eccube\Entity\Master\Disp::DISPLAY_HIDE);
257
            $Product
258
                ->setDelFlg(Constant::DISABLED)
259
                ->addProductClass($ProductClass)
260
                ->setStatus($Disp);
261
            $ProductClass
262
                ->setDelFlg(Constant::DISABLED)
263
                ->setStockUnlimited(true)
264
                ->setProduct($Product);
265
            $ProductStock = new \Eccube\Entity\ProductStock();
266
            $ProductClass->setProductStock($ProductStock);
267
            $ProductStock->setProductClass($ProductClass);
268
        } else {
269
            $Product = $app['eccube.repository.product']->find($id);
270
            if (!$Product) {
271
                throw new NotFoundHttpException();
272
            }
273
            // 規格あり商品か
274
            $has_class = $Product->hasProductClass();
275
            if (!$has_class) {
276
                $ProductClasses = $Product->getProductClasses();
277
                $ProductClass = $ProductClasses[0];
278
                $BaseInfo = $app['eccube.repository.base_info']->get();
279 View Code Duplication
                if ($BaseInfo->getOptionProductTaxRule() == Constant::ENABLED && $ProductClass->getTaxRule() && !$ProductClass->getTaxRule()->getDelFlg()) {
280
                    $ProductClass->setTaxRate($ProductClass->getTaxRule()->getTaxRate());
281
                }
282
                $ProductStock = $ProductClasses[0]->getProductStock();
283
            }
284
        }
285
286
        $builder = $app['form.factory']
287
            ->createBuilder('admin_product', $Product);
288
289
        // 規格あり商品の場合、規格関連情報をFormから除外
290
        if ($has_class) {
291
            $builder->remove('class');
292
        }
293
294
        $event = new EventArgs(
295
            array(
296
                'builder' => $builder,
297
                'Product' => $Product,
298
            ),
299
            $request
300
        );
301
        $app['eccube.event.dispatcher']->dispatch(EccubeEvents::ADMIN_PRODUCT_EDIT_INITIALIZE, $event);
302
303
        $form = $builder->getForm();
304
305
        if (!$has_class) {
306
            $ProductClass->setStockUnlimited((boolean)$ProductClass->getStockUnlimited());
307
            $form['class']->setData($ProductClass);
308
        }
309
310
        // ファイルの登録
311
        $images = array();
312
        $ProductImages = $Product->getProductImage();
313
        foreach ($ProductImages as $ProductImage) {
314
            $images[] = $ProductImage->getFileName();
315
        }
316
        $form['images']->setData($images);
317
318
        $categories = array();
319
        $ProductCategories = $Product->getProductCategories();
320
        foreach ($ProductCategories as $ProductCategory) {
321
            /* @var $ProductCategory \Eccube\Entity\ProductCategory */
322
            $categories[] = $ProductCategory->getCategory();
323
        }
324
        $form['Category']->setData($categories);
325
326
        $Tags = array();
327
        $ProductTags = $Product->getProductTag();
328
        foreach ($ProductTags as $ProductTag) {
329
            $Tags[] = $ProductTag->getTag();
330
        }
331
        $form['Tag']->setData($Tags);
332
333
        if ('POST' === $request->getMethod()) {
334
            $form->handleRequest($request);
335
            if ($form->isValid()) {
336
                log_info('商品登録開始', array($id));
337
                $Product = $form->getData();
338
339
                if (!$has_class) {
340
                    $ProductClass = $form['class']->getData();
341
342
                    // 個別消費税
343
                    $BaseInfo = $app['eccube.repository.base_info']->get();
344
                    if ($BaseInfo->getOptionProductTaxRule() == Constant::ENABLED) {
345
                        if ($ProductClass->getTaxRate() !== null) {
346 View Code Duplication
                            if ($ProductClass->getTaxRule()) {
347
                                if ($ProductClass->getTaxRule()->getDelFlg() == Constant::ENABLED) {
348
                                    $ProductClass->getTaxRule()->setDelFlg(Constant::DISABLED);
349
                                }
350
351
                                $ProductClass->getTaxRule()->setTaxRate($ProductClass->getTaxRate());
352
                            } else {
353
                                $taxrule = $app['eccube.repository.tax_rule']->newTaxRule();
354
                                $taxrule->setTaxRate($ProductClass->getTaxRate());
355
                                $taxrule->setApplyDate(new \DateTime());
356
                                $taxrule->setProduct($Product);
357
                                $taxrule->setProductClass($ProductClass);
358
                                $ProductClass->setTaxRule($taxrule);
359
                            }
360
                        } else {
361
                            if ($ProductClass->getTaxRule()) {
362
                                $ProductClass->getTaxRule()->setDelFlg(Constant::ENABLED);
363
                            }
364
                        }
365
                    }
366
                    $app['orm.em']->persist($ProductClass);
367
368
                    // 在庫情報を作成
369
                    if (!$ProductClass->getStockUnlimited()) {
370
                        $ProductStock->setStock($ProductClass->getStock());
371 2
                    } else {
372
                        // 在庫無制限時はnullを設定
373 2
                        $ProductStock->setStock(null);
374 2
                    }
375
                    $app['orm.em']->persist($ProductStock);
376
                }
377
378 2
                // カテゴリの登録
379
                // 一度クリア
380
                /* @var $Product \Eccube\Entity\Product */
381
                foreach ($Product->getProductCategories() as $ProductCategory) {
382
                    $Product->removeProductCategory($ProductCategory);
383
                    $app['orm.em']->remove($ProductCategory);
384
                }
385
                $app['orm.em']->persist($Product);
386
                $app['orm.em']->flush();
387
388
                $count = 1;
389
                $Categories = $form->get('Category')->getData();
390
                $categoriesIdList = array();
391
                foreach ($Categories as $Category) {
392 View Code Duplication
                    foreach ($Category->getPath() as $ParentCategory) {
393
                        if (!isset($categoriesIdList[$ParentCategory->getId()])) {
394
                            $ProductCategory = $this->createProductCategory($Product, $ParentCategory, $count);
395
                            $app['orm.em']->persist($ProductCategory);
396
                            $count++;
397
                            /* @var $Product \Eccube\Entity\Product */
398
                            $Product->addProductCategory($ProductCategory);
399
                            $categoriesIdList[$ParentCategory->getId()] = true;
400
                        }
401
                    }
402
                    if (!isset($categoriesIdList[$Category->getId()])) {
403
                        $ProductCategory = $this->createProductCategory($Product, $Category, $count);
404
                        $app['orm.em']->persist($ProductCategory);
405
                        $count++;
406
                        /* @var $Product \Eccube\Entity\Product */
407
                        $Product->addProductCategory($ProductCategory);
408
                        $categoriesIdList[$Category->getId()] = true;
409
                    }
410
                }
411
412
                // 画像の登録
413
                $add_images = $form->get('add_images')->getData();
414
                foreach ($add_images as $add_image) {
415
                    $ProductImage = new \Eccube\Entity\ProductImage();
416
                    $ProductImage
417
                        ->setFileName($add_image)
418
                        ->setProduct($Product)
419
                        ->setRank(1);
420
                    $Product->addProductImage($ProductImage);
421
                    $app['orm.em']->persist($ProductImage);
422
423
                    // 移動
424
                    $file = new File($app['config']['image_temp_realdir'].'/'.$add_image);
425
                    $file->move($app['config']['image_save_realdir']);
426
                }
427
428
                // 画像の削除
429
                $delete_images = $form->get('delete_images')->getData();
430
                foreach ($delete_images as $delete_image) {
431
                    $ProductImage = $app['eccube.repository.product_image']
432
                        ->findOneBy(array('file_name' => $delete_image));
433
434
                    // 追加してすぐに削除した画像は、Entityに追加されない
435
                    if ($ProductImage instanceof \Eccube\Entity\ProductImage) {
436
                        $Product->removeProductImage($ProductImage);
437
                        $app['orm.em']->remove($ProductImage);
438
439
                    }
440
                    $app['orm.em']->persist($Product);
441
442
                    // 削除
443 View Code Duplication
                    if (!empty($delete_image)) {
444
                        $fs = new Filesystem();
445
                        $fs->remove($app['config']['image_save_realdir'].'/'.$delete_image);
446
                    }
447
                }
448
                $app['orm.em']->persist($Product);
449
                $app['orm.em']->flush();
450
451
452
                $ranks = $request->get('rank_images');
453
                if ($ranks) {
454
                    foreach ($ranks as $rank) {
455
                        list($filename, $rank_val) = explode('//', $rank);
456
                        $ProductImage = $app['eccube.repository.product_image']
457
                            ->findOneBy(array(
458
                                'file_name' => $filename,
459
                                'Product' => $Product,
460
                            ));
461
                        $ProductImage->setRank($rank_val);
462
                        $app['orm.em']->persist($ProductImage);
463
                    }
464
                }
465
                $app['orm.em']->flush();
466
467
                // 商品タグの登録
468
                // 商品タグを一度クリア
469
                $ProductTags = $Product->getProductTag();
470
                foreach ($ProductTags as $ProductTag) {
471
                    $Product->removeProductTag($ProductTag);
472
                    $app['orm.em']->remove($ProductTag);
473
                }
474
475
                // 商品タグの登録
476
                $Tags = $form->get('Tag')->getData();
477
                foreach ($Tags as $Tag) {
478
                    $ProductTag = new ProductTag();
479
                    $ProductTag
480
                        ->setProduct($Product)
481
                        ->setTag($Tag);
482
                    $Product->addProductTag($ProductTag);
483
                    $app['orm.em']->persist($ProductTag);
484
                }
485
486
                $Product->setUpdateDate(new \DateTime());
487
                $app['orm.em']->flush();
488
489
                log_info('商品登録完了', array($id));
490
491
                $event = new EventArgs(
492
                    array(
493
                        'form' => $form,
494
                        'Product' => $Product,
495
                    ),
496
                    $request
497
                );
498
                $app['eccube.event.dispatcher']->dispatch(EccubeEvents::ADMIN_PRODUCT_EDIT_COMPLETE, $event);
499
500
                $app->addSuccess('admin.register.complete', 'admin');
501
502
                return $app->redirect($app->url('admin_product_product_edit', array('id' => $Product->getId())));
503
            } else {
504
                log_info('商品登録チェックエラー', array($id));
505
                $app->addError('admin.register.failed', 'admin');
506
            }
507
        }
508
509
        // 検索結果の保持
510
        $builder = $app['form.factory']
511
            ->createBuilder('admin_search_product');
512
513
        $event = new EventArgs(
514
            array(
515
                'builder' => $builder,
516
                'Product' => $Product,
517
            ),
518
            $request
519
        );
520
        $app['eccube.event.dispatcher']->dispatch(EccubeEvents::ADMIN_PRODUCT_EDIT_SEARCH, $event);
521
522
        $searchForm = $builder->getForm();
523
524
        if ('POST' === $request->getMethod()) {
525
            $searchForm->handleRequest($request);
526
        }
527
528
        return $app->render('Product/product.twig', array(
529
            'Product' => $Product,
530
            'form' => $form->createView(),
531
            'searchForm' => $searchForm->createView(),
532
            'has_class' => $has_class,
533
            'id' => $id,
534
        ));
535
    }
536
537
    public function delete(Application $app, Request $request, $id = null)
538
    {
539
        $this->isTokenValid($app);
540
        $session = $request->getSession();
541
        $page_no = intval($session->get('eccube.admin.product.search.page_no'));
542
        $page_no = $page_no ? $page_no : Constant::ENABLED;
543
544
        if (!is_null($id)) {
545
            /* @var $Product \Eccube\Entity\Product */
546
            $Product = $app['eccube.repository.product']->find($id);
547
            if (!$Product) {
548
                $app->deleteMessage();
549
550
                return $app->redirect($app->url('admin_product_page', array('page_no' => $page_no)).'?resume='.Constant::ENABLED);
551
            }
552
553
            if ($Product instanceof \Eccube\Entity\Product) {
554
                log_info('商品削除開始', array($id));
555
556
                $Product->setDelFlg(Constant::ENABLED);
557
558
                $ProductClasses = $Product->getProductClasses();
559
                $deleteImages = array();
560
                foreach ($ProductClasses as $ProductClass) {
561
                    $ProductClass->setDelFlg(Constant::ENABLED);
562
                    $Product->removeProductClass($ProductClass);
563
564
                    $ProductClasses = $Product->getProductClasses();
565
                    foreach ($ProductClasses as $ProductClass) {
566
                        $ProductClass->setDelFlg(Constant::ENABLED);
567
                        $Product->removeProductClass($ProductClass);
568
569
                        $ProductStock = $ProductClass->getProductStock();
570
                        $app['orm.em']->remove($ProductStock);
571
                    }
572
573
                    $ProductImages = $Product->getProductImage();
574
                    foreach ($ProductImages as $ProductImage) {
575
                        $Product->removeProductImage($ProductImage);
576
                        $deleteImages[] = $ProductImage->getFileName();
577
                        $app['orm.em']->remove($ProductImage);
578
                    }
579
580
                    $ProductCategories = $Product->getProductCategories();
581
                    foreach ($ProductCategories as $ProductCategory) {
582
                        $Product->removeProductCategory($ProductCategory);
583
                        $app['orm.em']->remove($ProductCategory);
584
                    }
585
586
                }
587
588
                $app['orm.em']->persist($Product);
589
590
                $app['orm.em']->flush();
591
592
                $event = new EventArgs(
593
                    array(
594
                        'Product' => $Product,
595
                        'ProductClass' => $ProductClasses,
596
                        'deleteImages' => $deleteImages,
597
                    ),
598
                    $request
599
                );
600
                $app['eccube.event.dispatcher']->dispatch(EccubeEvents::ADMIN_PRODUCT_DELETE_COMPLETE, $event);
601
                $deleteImages = $event->getArgument('deleteImages');
602
603
                // 画像ファイルの削除(commit後に削除させる)
604
                foreach ($deleteImages as $deleteImage) {
605
                    try {
606 View Code Duplication
                        if (!empty($deleteImage)) {
607
                            $fs = new Filesystem();
608
                            $fs->remove($app['config']['image_save_realdir'].'/'.$deleteImage);
609
                        }
610
                    } catch (\Exception $e) {
611
                        // エラーが発生しても無視する
612
                    }
613
                }
614
615
                log_info('商品削除完了', array($id));
616
617
                $app->addSuccess('admin.delete.complete', 'admin');
618
            } else {
619
                log_info('商品削除エラー', array($id));
620
                $app->addError('admin.delete.failed', 'admin');
621
            }
622
        } else {
623
            log_info('商品削除エラー', array($id));
624
            $app->addError('admin.delete.failed', 'admin');
625
        }
626
627
        return $app->redirect($app->url('admin_product_page', array('page_no' => $page_no)).'?resume='.Constant::ENABLED);
628
    }
629
630
    public function copy(Application $app, Request $request, $id = null)
631
    {
632
        $this->isTokenValid($app);
633
634
        if (!is_null($id)) {
635
            $Product = $app['eccube.repository.product']->find($id);
636
            if ($Product instanceof \Eccube\Entity\Product) {
637
                $CopyProduct = clone $Product;
638
                $CopyProduct->copy();
639
                $Disp = $app['eccube.repository.master.disp']->find(\Eccube\Entity\Master\Disp::DISPLAY_HIDE);
640
                $CopyProduct->setStatus($Disp);
641
642
                $CopyProductCategories = $CopyProduct->getProductCategories();
643
                foreach ($CopyProductCategories as $Category) {
644
                    $app['orm.em']->persist($Category);
645
                }
646
647
                // 規格あり商品の場合は, デフォルトの商品規格を取得し登録する.
648
                if ($CopyProduct->hasProductClass()) {
649
                    $softDeleteFilter = $app['orm.em']->getFilters()->getFilter('soft_delete');
650
                    $softDeleteFilter->setExcludes(array(
0 ignored issues
show
Add a comma after each item in a multi-line array
Loading history...
651
                        'Eccube\Entity\ProductClass'
652
                    ));
653
                    $dummyClass = $app['eccube.repository.product_class']->findOneBy(array(
654
                        'del_flg' => \Eccube\Common\Constant::ENABLED,
655
                        'ClassCategory1' => null,
656
                        'ClassCategory2' => null,
657
                        'Product' => $Product,
658
                    ));
659
                    $dummyClass = clone $dummyClass;
660
                    $dummyClass->setProduct($CopyProduct);
661
                    $CopyProduct->addProductClass($dummyClass);
662
                    $softDeleteFilter->setExcludes(array());
663
                }
664
665
                $CopyProductClasses = $CopyProduct->getProductClasses();
666
                foreach ($CopyProductClasses as $Class) {
667
                    $Stock = $Class->getProductStock();
668
                    $CopyStock = clone $Stock;
669
                    $CopyStock->setProductClass($Class);
670
                    $app['orm.em']->persist($CopyStock);
671
672
                    $app['orm.em']->persist($Class);
673
                }
674
                $Images = $CopyProduct->getProductImage();
675
                foreach ($Images as $Image) {
676
677
                    // 画像ファイルを新規作成
678
                    $extension = pathinfo($Image->getFileName(), PATHINFO_EXTENSION);
679
                    $filename = date('mdHis').uniqid('_').'.'.$extension;
680
                    try {
681
                        $fs = new Filesystem();
682
                        $fs->copy($app['config']['image_save_realdir'].'/'.$Image->getFileName(), $app['config']['image_save_realdir'].'/'.$filename);
683
                    } catch (\Exception $e) {
684
                        // エラーが発生しても無視する
685
                    }
686
                    $Image->setFileName($filename);
687
688
                    $app['orm.em']->persist($Image);
689
                }
690
                $Tags = $CopyProduct->getProductTag();
691
                foreach ($Tags as $Tag) {
692
                    $app['orm.em']->persist($Tag);
693
                }
694
695
                $app['orm.em']->persist($CopyProduct);
696
697
                $app['orm.em']->flush();
698
699
                $event = new EventArgs(
700
                    array(
701
                        'Product' => $Product,
702
                        'CopyProduct' => $CopyProduct,
703
                        'CopyProductCategories' => $CopyProductCategories,
704
                        'CopyProductClasses' => $CopyProductClasses,
705
                        'images' => $Images,
706
                        'Tags' => $Tags,
707
                    ),
708
                    $request
709
                );
710
                $app['eccube.event.dispatcher']->dispatch(EccubeEvents::ADMIN_PRODUCT_COPY_COMPLETE, $event);
711
712
                $app->addSuccess('admin.product.copy.complete', 'admin');
713
714
                return $app->redirect($app->url('admin_product_product_edit', array('id' => $CopyProduct->getId())));
715
            } else {
716
                $app->addError('admin.product.copy.failed', 'admin');
717
            }
718
        } else {
719
            $app->addError('admin.product.copy.failed', 'admin');
720
        }
721
722
        return $app->redirect($app->url('admin_product'));
723
    }
724
725
    public function display(Application $app, Request $request, $id = null)
726
    {
727
        $event = new EventArgs(
728
            array(),
729
            $request
730
        );
731
        $app['eccube.event.dispatcher']->dispatch(EccubeEvents::ADMIN_PRODUCT_DISPLAY_COMPLETE, $event);
732
733
        if (!is_null($id)) {
734
            return $app->redirect($app->url('product_detail', array('id' => $id, 'admin' => '1')));
735
        }
736
737
        return $app->redirect($app->url('admin_product'));
738
    }
739
740
    /**
741
     * 商品CSVの出力.
742
     *
743
     * @param Application $app
744
     * @param Request $request
745
     * @return StreamedResponse
746
     */
747
    public function export(Application $app, Request $request)
748
    {
749
        // タイムアウトを無効にする.
750
        set_time_limit(0);
751
752
        // sql loggerを無効にする.
753
        $em = $app['orm.em'];
754
        $em->getConfiguration()->setSQLLogger(null);
755
756
        $response = new StreamedResponse();
757
        $response->setCallback(function () use ($app, $request) {
758
759
            // CSV種別を元に初期化.
760
            $app['eccube.service.csv.export']->initCsvType(CsvType::CSV_TYPE_PRODUCT);
761
762
            // ヘッダ行の出力.
763
            $app['eccube.service.csv.export']->exportHeader();
764
765
            // 商品データ検索用のクエリビルダを取得.
766
            $qb = $app['eccube.service.csv.export']
767
                ->getProductQueryBuilder($request);
768
769
            // Get stock status
770
            $isOutOfStock = 0;
771
            $session = $request->getSession();
772
            if ($session->has('eccube.admin.product.search')) {
773
                $searchData = $session->get('eccube.admin.product.search', array());
774
                if (isset($searchData['stock_status']) && $searchData['stock_status'] === 0) {
775
                    $isOutOfStock = 1;
776
                }
777
            }
778
779
            // joinする場合はiterateが使えないため, select句をdistinctする.
780
            // http://qiita.com/suin/items/2b1e98105fa3ef89beb7
781
            // distinctのmysqlとpgsqlの挙動をあわせる.
782
            // http://uedatakeshi.blogspot.jp/2010/04/distinct-oeder-by-postgresmysql.html
783
            $qb->resetDQLPart('select')
784
                ->resetDQLPart('orderBy')
785
                ->orderBy('p.update_date', 'DESC');
786
787
            if ($isOutOfStock) {
788
                $qb->select('p, pc')
789
                    ->distinct();
790
            } else {
791
                $qb->select('p')
792
                    ->distinct();
793
            }
794
            // データ行の出力.
795
            $app['eccube.service.csv.export']->setExportQueryBuilder($qb);
796
797 View Code Duplication
            $app['eccube.service.csv.export']->exportData(function ($entity, CsvExportService $csvService) use ($app, $request) {
798
                $Csvs = $csvService->getCsvs();
799
800
                /** @var $Product \Eccube\Entity\Product */
801
                $Product = $entity;
802
803
                /** @var $ProductClassess \Eccube\Entity\ProductClass[] */
804
                $ProductClassess = $Product->getProductClasses();
805
806
                foreach ($ProductClassess as $ProductClass) {
807
                    $ExportCsvRow = new \Eccube\Entity\ExportCsvRow();
808
809
                    // CSV出力項目と合致するデータを取得.
810
                    foreach ($Csvs as $Csv) {
811
                        // 商品データを検索.
812
                        $ExportCsvRow->setData($csvService->getData($Csv, $Product));
813
                        if ($ExportCsvRow->isDataNull()) {
814
                            // 商品規格情報を検索.
815
                            $ExportCsvRow->setData($csvService->getData($Csv, $ProductClass));
816
                        }
817
818
                        $event = new EventArgs(
819
                            array(
820
                                'csvService' => $csvService,
821
                                'Csv' => $Csv,
822
                                'ProductClass' => $ProductClass,
823
                                'ExportCsvRow' => $ExportCsvRow,
824
                            ),
825
                            $request
826
                        );
827
                        $app['eccube.event.dispatcher']->dispatch(EccubeEvents::ADMIN_PRODUCT_CSV_EXPORT, $event);
828
829
                        $ExportCsvRow->pushData();
830
                    }
831
832
                    // $row[] = number_format(memory_get_usage(true));
833
                    // 出力.
834
                    $csvService->fputcsv($ExportCsvRow->getRow());
835
                }
836
            });
837
        });
838
839
        $now = new \DateTime();
840
        $filename = 'product_'.$now->format('YmdHis').'.csv';
841
        $response->headers->set('Content-Type', 'application/octet-stream');
842
        $response->headers->set('Content-Disposition', 'attachment; filename='.$filename);
843
        $response->send();
844
845
        log_info('商品CSV出力ファイル名', array($filename));
846
847
        return $response;
848
    }
849
850
    /**
851
     * ProductCategory作成
852
     * @param \Eccube\Entity\Product $Product
853
     * @param \Eccube\Entity\Category $Category
854
     * @return \Eccube\Entity\ProductCategory
855
     */
856 View Code Duplication
    private function createProductCategory($Product, $Category, $count)
857
    {
858
        $ProductCategory = new \Eccube\Entity\ProductCategory();
859
        $ProductCategory->setProduct($Product);
860
        $ProductCategory->setProductId($Product->getId());
861
        $ProductCategory->setCategory($Category);
862
        $ProductCategory->setCategoryId($Category->getId());
863
        $ProductCategory->setRank($count);
864
865
        return $ProductCategory;
866
    }
867
}
868