Completed
Push — 4.0 ( 87d096...bcc1be )
by Kiyotaka
05:44 queued 11s
created

Controller/Admin/Product/CsvImportController.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
/*
4
 * This file is part of EC-CUBE
5
 *
6
 * Copyright(c) EC-CUBE CO.,LTD. All Rights Reserved.
7
 *
8
 * http://www.ec-cube.co.jp/
9
 *
10
 * For the full copyright and license information, please view the LICENSE
11
 * file that was distributed with this source code.
12
 */
13
14
namespace Eccube\Controller\Admin\Product;
15
16
use Doctrine\DBAL\Exception\ForeignKeyConstraintViolationException;
17
use Eccube\Common\Constant;
18
use Eccube\Controller\Admin\AbstractCsvImportController;
19
use Eccube\Entity\BaseInfo;
20
use Eccube\Entity\Category;
21
use Eccube\Entity\Product;
22
use Eccube\Entity\ProductCategory;
23
use Eccube\Entity\ProductClass;
24
use Eccube\Entity\ProductImage;
25
use Eccube\Entity\ProductStock;
26
use Eccube\Entity\ProductTag;
27
use Eccube\Form\Type\Admin\CsvImportType;
28
use Eccube\Repository\BaseInfoRepository;
29
use Eccube\Repository\CategoryRepository;
30
use Eccube\Repository\ClassCategoryRepository;
31
use Eccube\Repository\DeliveryDurationRepository;
32
use Eccube\Repository\Master\ProductStatusRepository;
33
use Eccube\Repository\Master\SaleTypeRepository;
34
use Eccube\Repository\ProductRepository;
35
use Eccube\Repository\TagRepository;
36
use Eccube\Service\CsvImportService;
37
use Eccube\Util\CacheUtil;
38
use Eccube\Util\StringUtil;
39
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
40
use Symfony\Component\Filesystem\Filesystem;
41
use Symfony\Component\Form\FormInterface;
42
use Symfony\Component\HttpFoundation\Request;
43
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
44
use Symfony\Component\Routing\Annotation\Route;
45
use Symfony\Component\Validator\Constraints\GreaterThanOrEqual;
46
use Symfony\Component\Validator\Validator\ValidatorInterface;
47
48
class CsvImportController extends AbstractCsvImportController
49
{
50
    /**
51
     * @var DeliveryDurationRepository
52
     */
53
    protected $deliveryDurationRepository;
54
55
    /**
56
     * @var SaleTypeRepository
57
     */
58
    protected $saleTypeRepository;
59
60
    /**
61
     * @var TagRepository
62
     */
63
    protected $tagRepository;
64
65
    /**
66
     * @var CategoryRepository
67
     */
68
    protected $categoryRepository;
69
70
    /**
71
     * @var ClassCategoryRepository
72
     */
73
    protected $classCategoryRepository;
74
75
    /**
76
     * @var ProductStatusRepository
77
     */
78
    protected $productStatusRepository;
79
80
    /**
81
     * @var ProductRepository
82
     */
83
    protected $productRepository;
84
85
    /**
86
     * @var BaseInfo
87
     */
88
    protected $BaseInfo;
89
90
    /**
91
     * @var ValidatorInterface
92
     */
93
    protected $validator;
94
95
    private $errors = [];
96
97
    /**
98
     * CsvImportController constructor.
99
     *
100
     * @param DeliveryDurationRepository $deliveryDurationRepository
101 16
     * @param SaleTypeRepository $saleTypeRepository
102
     * @param TagRepository $tagRepository
103 16
     * @param CategoryRepository $categoryRepository
104 16
     * @param ClassCategoryRepository $classCategoryRepository
105 16
     * @param ProductStatusRepository $productStatusRepository
106 16
     * @param ProductRepository $productRepository
107 16
     * @param BaseInfoRepository $baseInfoRepository
108 16
     * @param ValidatorInterface $validator
109 16
     *
110 16
     * @throws \Doctrine\ORM\NoResultException
111
     * @throws \Doctrine\ORM\NonUniqueResultException
112
     */
113 View Code Duplication
    public function __construct(
114
        DeliveryDurationRepository $deliveryDurationRepository,
115
        SaleTypeRepository $saleTypeRepository,
116
        TagRepository $tagRepository,
117
        CategoryRepository $categoryRepository,
118
        ClassCategoryRepository $classCategoryRepository,
119 10
        ProductStatusRepository $productStatusRepository,
120
        ProductRepository $productRepository,
121 10
        BaseInfoRepository $baseInfoRepository,
122 10
        ValidatorInterface $validator
123 10
    ) {
124 10
        $this->deliveryDurationRepository = $deliveryDurationRepository;
125 10
        $this->saleTypeRepository = $saleTypeRepository;
126 10
        $this->tagRepository = $tagRepository;
127 10
        $this->categoryRepository = $categoryRepository;
128 10
        $this->classCategoryRepository = $classCategoryRepository;
129 10
        $this->productStatusRepository = $productStatusRepository;
130 10
        $this->productRepository = $productRepository;
131
        $this->BaseInfo = $baseInfoRepository->get();
132
        $this->validator = $validator;
133
    }
134
135 10
    /**
136 10
     * 商品登録CSVアップロード
137 10
     *
138 10
     * @Route("/%eccube_admin_route%/product/product_csv_upload", name="admin_product_csv_import")
139 10
     * @Template("@admin/Product/csv_product.twig")
140 10
     */
141
    public function csvProduct(Request $request, CacheUtil $cacheUtil)
142 10
    {
143
        $form = $this->formFactory->createBuilder(CsvImportType::class)->getForm();
144 10
        $headers = $this->getProductCsvHeader();
145
        if ('POST' === $request->getMethod()) {
146
            $form->handleRequest($request);
147
            if ($form->isValid()) {
148
                $formFile = $form['import_file']->getData();
149
                if (!empty($formFile)) {
150 10
                    log_info('商品CSV登録開始');
151
                    $data = $this->getImportData($formFile);
152 10 View Code Duplication
                    if ($data === false) {
153
                        $this->addErrors(trans('admin.common.csv_invalid_format'));
154
155
                        return $this->renderWithError($form, $headers, false);
156
                    }
157
                    $getId = function ($item) {
158 10
                        return $item['id'];
159 10
                    };
160
                    $requireHeader = array_keys(array_map($getId, array_filter($headers, function ($value) {
161 10
                        return $value['required'];
162 10
                    })));
163
164 10
                    $columnHeaders = $data->getColumnHeaders();
165 10
166 10 View Code Duplication
                    if (count(array_diff($requireHeader, $columnHeaders)) > 0) {
167
                        $this->addErrors(trans('admin.common.csv_invalid_format'));
168
169
                        return $this->renderWithError($form, $headers, false);
170
                    }
171
172
                    $size = count($data);
173 10
174 7 View Code Duplication
                    if ($size < 1) {
175 7
                        $this->addErrors(trans('admin.common.csv_invalid_no_data'));
176
177 4
                        return $this->renderWithError($form, $headers, false);
178 3
                    }
179 3
180 1
                    $headerSize = count($columnHeaders);
181 1
                    $headerByKey = array_flip(array_map($getId, $headers));
182
                    $deleteImages = [];
183 3
184
                    $this->entityManager->getConfiguration()->setSQLLogger(null);
185
                    $this->entityManager->getConnection()->beginTransaction();
186 1
                    // CSVファイルの登録処理
187 1
                    foreach ($data as $row) {
188
                        $line = $data->key() + 1;
189 1
                        if ($headerSize != count($row)) {
190
                            $message = trans('admin.common.csv_invalid_format_line', ['%line%' => $line]);
191
                            $this->addErrors($message);
192
193 8
                            return $this->renderWithError($form, $headers);
194 1
                        }
195 1
196
                        if (!isset($row[$headerByKey['id']]) || StringUtil::isBlank($row[$headerByKey['id']])) {
197 7
                            $Product = new Product();
198 6
                            $this->entityManager->persist($Product);
199 6
                        } else {
200 1
                            if (preg_match('/^\d+$/', $row[$headerByKey['id']])) {
201 1
                                $Product = $this->productRepository->find($row[$headerByKey['id']]);
202
                                if (!$Product) {
203 6
                                    $message = trans('admin.common.csv_invalid_not_found', ['%line%' => $line, '%name%' => $headerByKey['id']]);
204
                                    $this->addErrors($message);
205
206 1
                                    return $this->renderWithError($form, $headers);
207 1
                                }
208
                            } else {
209
                                $message = trans('admin.common.csv_invalid_not_found', ['%line%' => $line, '%name%' => $headerByKey['id']]);
210
                                $this->addErrors($message);
211 8
212
                                return $this->renderWithError($form, $headers);
213
                            }
214
215
                            if (isset($row[$headerByKey['product_del_flg']])) {
216
                                if (StringUtil::isNotBlank($row[$headerByKey['product_del_flg']]) && $row[$headerByKey['product_del_flg']] == (string) Constant::ENABLED) {
217 8
                                    // 商品を物理削除
218
                                    $deleteImages[] = $Product->getProductImage();
219
220 8
                                    try {
221 3
                                        $this->productRepository->delete($Product);
222
                                        $this->entityManager->flush();
223 5
224
                                        continue;
225
                                    } catch (ForeignKeyConstraintViolationException $e) {
226 8
                                        $message = trans('admin.common.csv_invalid_foreign_key', ['%line%' => $line, '%name%' => $Product->getName()]);
227 4
                                        $this->addErrors($message);
228
229 5
                                        return $this->renderWithError($form, $headers);
230
                                    }
231
                                }
232 8
                            }
233 4
                        }
234
235 4
                        if (StringUtil::isBlank($row[$headerByKey['status']])) {
236
                            $message = trans('admin.common.csv_invalid_required', ['%line%' => $line, '%name%' => $headerByKey['status']]);
237
                            $this->addErrors($message);
238 8
                        } else {
239 3
                            if (preg_match('/^\d+$/', $row[$headerByKey['status']])) {
240
                                $ProductStatus = $this->productStatusRepository->find($row[$headerByKey['status']]);
241 5
                                if (!$ProductStatus) {
242
                                    $message = trans('admin.common.csv_invalid_not_found', ['%line%' => $line, '%name%' => $headerByKey['status']]);
243
                                    $this->addErrors($message);
244 8
                                } else {
245 3
                                    $Product->setStatus($ProductStatus);
246
                                }
247 5
                            } else {
248
                                $message = trans('admin.common.csv_invalid_not_found', ['%line%' => $line, '%name%' => $headerByKey['status']]);
249
                                $this->addErrors($message);
250
                            }
251 8
                        }
252
253 8
                        if (StringUtil::isBlank($row[$headerByKey['name']])) {
254
                            $message = trans('admin.common.csv_invalid_not_found', ['%line%' => $line, '%name%' => $headerByKey['name']]);
255
                            $this->addErrors($message);
256 8
257
                            return $this->renderWithError($form, $headers);
258
                        } else {
259 8
                            $Product->setName(StringUtil::trimAll($row[$headerByKey['name']]));
260
                        }
261
262 View Code Duplication
                        if (isset($row[$headerByKey['note']]) && StringUtil::isNotBlank($row[$headerByKey['note']])) {
263 8
                            $Product->setNote(StringUtil::trimAll($row[$headerByKey['note']]));
264 8
                        } else {
265
                            $Product->setNote(null);
266 7
                        }
267 7
268 View Code Duplication
                        if (isset($row[$headerByKey['description_list']]) && StringUtil::isNotBlank($row[$headerByKey['description_list']])) {
269
                            $Product->setDescriptionList(StringUtil::trimAll($row[$headerByKey['description_list']]));
270
                        } else {
271
                            $Product->setDescriptionList(null);
272
                        }
273
274 View Code Duplication
                        if (isset($row[$headerByKey['description_detail']]) && StringUtil::isNotBlank($row[$headerByKey['description_detail']])) {
275
                            $Product->setDescriptionDetail(StringUtil::trimAll($row[$headerByKey['description_detail']]));
276
                        } else {
277
                            $Product->setDescriptionDetail(null);
278
                        }
279 7
280 2 View Code Duplication
                        if (isset($row[$headerByKey['search_word']]) && StringUtil::isNotBlank($row[$headerByKey['search_word']])) {
281
                            $Product->setSearchWord(StringUtil::trimAll($row[$headerByKey['search_word']]));
282
                        } else {
283
                            $Product->setSearchWord(null);
284
                        }
285
286 View Code Duplication
                        if (isset($row[$headerByKey['free_area']]) && StringUtil::isNotBlank($row[$headerByKey['free_area']])) {
287
                            $Product->setFreeArea(StringUtil::trimAll($row[$headerByKey['free_area']]));
288
                        } else {
289
                            $Product->setFreeArea(null);
290 2
                        }
291 2
292
                        // 商品画像登録
293
                        $this->createProductImage($row, $Product, $data, $headerByKey);
294 2
295
                        $this->entityManager->flush();
296
297 2
                        // 商品カテゴリ登録
298 2
                        $this->createProductCategory($row, $Product, $data, $headerByKey);
299 2
300 2
                        //タグ登録
301
                        $this->createProductTag($row, $Product, $data, $headerByKey);
302
303
                        // 商品規格が存在しなければ新規登録
304 2
                        /** @var ProductClass[] $ProductClasses */
305
                        $ProductClasses = $Product->getProductClasses();
306
                        if ($ProductClasses->count() < 1) {
0 ignored issues
show
The method count cannot be called on $ProductClasses (of type array<integer,object<Eccube\Entity\ProductClass>>).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
307
                            // 規格分類1(ID)がセットされていると規格なし商品、規格あり商品を作成
308
                            $ProductClassOrg = $this->createProductClass($row, $Product, $data, $headerByKey);
309 View Code Duplication
                            if ($this->BaseInfo->isOptionProductDeliveryFee()) {
310
                                if (isset($row[$headerByKey['delivery_fee']]) && StringUtil::isNotBlank($row[$headerByKey['delivery_fee']])) {
311 2
                                    $deliveryFee = str_replace(',', '', $row[$headerByKey['delivery_fee']]);
312 2
                                    $errors = $this->validator->validate($deliveryFee, new GreaterThanOrEqual(['value' => 0]));
313 2
                                    if ($errors->count() === 0) {
314 2
                                        $ProductClassOrg->setDeliveryFee($deliveryFee);
315
                                    } else {
316
                                        $message = trans('admin.common.csv_invalid_greater_than_zero', ['%line%' => $line, '%name%' => $headerByKey['delivery_fee']]);
317
                                        $this->addErrors($message);
318 2
                                    }
319 2
                                }
320
                            }
321
322
                            if (isset($row[$headerByKey['class_category1']]) && StringUtil::isNotBlank($row[$headerByKey['class_category1']])) {
323
                                if (isset($row[$headerByKey['class_category2']]) && $row[$headerByKey['class_category1']] == $row[$headerByKey['class_category2']]) {
324 2
                                    $message = trans('admin.common.csv_invalid_not_same', [
325
                                        '%line%' => $line,
326
                                        '%name1%' => $headerByKey['class_category1'],
327
                                        '%name2%' => $headerByKey['class_category2'],
328
                                    ]);
329
                                    $this->addErrors($message);
330
                                } else {
331
                                    // 商品規格あり
332 2
                                    // 規格分類あり商品を作成
333 2
                                    $ProductClass = clone $ProductClassOrg;
334
                                    $ProductStock = clone $ProductClassOrg->getProductStock();
335 2
336 2
                                    // 規格分類1、規格分類2がnullであるデータを非表示
337
                                    $ProductClassOrg->setVisible(false);
338
339 5
                                    // 規格分類1、2をそれぞれセットし作成
340
                                    $ClassCategory1 = null;
341 7
                                    if (preg_match('/^\d+$/', $row[$headerByKey['class_category1']])) {
342
                                        $ClassCategory1 = $this->classCategoryRepository->find($row[$headerByKey['class_category1']]);
343
                                        if (!$ClassCategory1) {
344
                                            $message = trans('admin.common.csv_invalid_not_found', ['%line%' => $line, '%name%' => $headerByKey['class_category1']]);
345
                                            $this->addErrors($message);
346 2
                                        } else {
347 2
                                            $ProductClass->setClassCategory1($ClassCategory1);
348 2
                                        }
349
                                    } else {
350 2
                                        $message = trans('admin.common.csv_invalid_not_found', ['%line%' => $line, '%name%' => $headerByKey['class_category1']]);
351 2
                                        $this->addErrors($message);
352 2
                                    }
353
354
                                    if (isset($row[$headerByKey['class_category2']]) && StringUtil::isNotBlank($row[$headerByKey['class_category2']])) {
355 2
                                        if (preg_match('/^\d+$/', $row[$headerByKey['class_category2']])) {
356 2
                                            $ClassCategory2 = $this->classCategoryRepository->find($row[$headerByKey['class_category2']]);
357 View Code Duplication
                                            if (!$ClassCategory2) {
358 1
                                                $message = trans('admin.common.csv_invalid_not_found', ['%line%' => $line, '%name%' => $headerByKey['class_category2']]);
359
                                                $this->addErrors($message);
360 1
                                            } else {
361
                                                if ($ClassCategory1 &&
362
                                                    ($ClassCategory1->getClassName()->getId() == $ClassCategory2->getClassName()->getId())
363
                                                ) {
364
                                                    $message = trans('admin.common.csv_invalid_not_same', ['%line%' => $line, '%name1%' => $headerByKey['class_category1'], '%name2%' => $headerByKey['class_category2']]);
365
                                                    $this->addErrors($message);
366
                                                } else {
367
                                                    $ProductClass->setClassCategory2($ClassCategory2);
368
                                                }
369
                                            }
370
                                        } else {
371
                                            $message = trans('admin.common.csv_invalid_not_found', ['%line%' => $line, '%name%' => $headerByKey['class_category2']]);
372 1
                                            $this->addErrors($message);
373 2
                                        }
374
                                    }
375
                                    $ProductClass->setProductStock($ProductStock);
376
                                    $ProductStock->setProductClass($ProductClass);
377
378 2
                                    $this->entityManager->persist($ProductClass);
379 1
                                    $this->entityManager->persist($ProductStock);
380 1
                                }
381 1
                            } else {
382
                                if (isset($row[$headerByKey['class_category2']]) && StringUtil::isNotBlank($row[$headerByKey['class_category2']])) {
383
                                    $message = trans('admin.common.csv_invalid_not_found', ['%line%' => $line, '%name%' => $headerByKey['class_category2']]);
384 1
                                    $this->addErrors($message);
385
                                }
386
                            }
387 1
                        } else {
388 1
                            // 商品規格の更新
389
                            $flag = false;
390
                            $classCategoryId1 = StringUtil::isBlank($row[$headerByKey['class_category1']]) ? null : $row[$headerByKey['class_category1']];
391
                            $classCategoryId2 = StringUtil::isBlank($row[$headerByKey['class_category2']]) ? null : $row[$headerByKey['class_category2']];
392
393
                            foreach ($ProductClasses as $pc) {
394
                                $classCategory1 = is_null($pc->getClassCategory1()) ? null : $pc->getClassCategory1()->getId();
395
                                $classCategory2 = is_null($pc->getClassCategory2()) ? null : $pc->getClassCategory2()->getId();
396
397
                                // 登録されている商品規格を更新
398 1
                                if ($classCategory1 == $classCategoryId1 &&
399 1
                                    $classCategory2 == $classCategoryId2
400 1
                                ) {
401 1
                                    $this->updateProductClass($row, $Product, $pc, $data, $headerByKey);
402
403 1 View Code Duplication
                                    if ($this->BaseInfo->isOptionProductDeliveryFee()) {
404
                                        if (isset($row[$headerByKey['delivery_fee']]) && StringUtil::isNotBlank($row[$headerByKey['delivery_fee']])) {
405
                                            $deliveryFee = str_replace(',', '', $row[$headerByKey['delivery_fee']]);
406
                                            $errors = $this->validator->validate($deliveryFee, new GreaterThanOrEqual(['value' => 0]));
407
                                            if ($errors->count() === 0) {
408
                                                $pc->setDeliveryFee($deliveryFee);
409
                                            } else {
410 1
                                                $message = trans('admin.common.csv_invalid_greater_than_zero', ['%line%' => $line, '%name%' => $headerByKey['delivery_fee']]);
411 1
                                                $this->addErrors($message);
412 1
                                            }
413
                                        }
414
                                    }
415
                                    $flag = true;
416 1
                                    break;
417 1
                                }
418 1
                            }
419
420
                            // 商品規格を登録
421
                            if (!$flag) {
422 1
                                $pc = $ProductClasses[0];
423 1
                                if ($pc->getClassCategory1() == null &&
424
                                    $pc->getClassCategory2() == null
425
                                ) {
426
                                    // 規格分類1、規格分類2がnullであるデータを非表示
427
                                    $pc->setVisible(false);
428
                                }
429
430 1
                                if (isset($row[$headerByKey['class_category1']]) && isset($row[$headerByKey['class_category2']])
431
                                    && $row[$headerByKey['class_category1']] == $row[$headerByKey['class_category2']]) {
432
                                    $message = trans('admin.common.csv_invalid_not_same', [
433
                                        '%line%' => $line,
434
                                        '%name1%' => $headerByKey['class_category1'],
435 1
                                        '%name2%' => $headerByKey['class_category2'],
436
                                    ]);
437
                                    $this->addErrors($message);
438
                                } else {
439
                                    // 必ず規格分類1がセットされている
440
                                    // 規格分類1、2をそれぞれセットし作成
441
                                    $ClassCategory1 = null;
442
                                    if (preg_match('/^\d+$/', $classCategoryId1)) {
443
                                        $ClassCategory1 = $this->classCategoryRepository->find($classCategoryId1);
444 1
                                        if (!$ClassCategory1) {
445
                                            $message = trans('admin.common.csv_invalid_not_found', ['%line%' => $line, '%name%' => $headerByKey['class_category1']]);
446 1
                                            $this->addErrors($message);
447
                                        }
448
                                    } else {
449
                                        $message = trans('admin.common.csv_invalid_not_found', ['%line%' => $line, '%name%' => $headerByKey['class_category1']]);
450
                                        $this->addErrors($message);
451
                                    }
452
453
                                    $ClassCategory2 = null;
454
                                    if (isset($row[$headerByKey['class_category2']]) && StringUtil::isNotBlank($row[$headerByKey['class_category2']])) {
455
                                        if ($pc->getClassCategory1() != null && $pc->getClassCategory2() == null) {
456
                                            $message = trans('admin.common.csv_invalid_can_not', ['%line%' => $line, '%name%' => $headerByKey['class_category2']]);
457 1
                                            $this->addErrors($message);
458
                                        } else {
459
                                            if (preg_match('/^\d+$/', $classCategoryId2)) {
460
                                                $ClassCategory2 = $this->classCategoryRepository->find($classCategoryId2);
461 8 View Code Duplication
                                                if (!$ClassCategory2) {
462 3
                                                    $message = trans('admin.common.csv_invalid_not_found', ['%line%' => $line, '%name%' => $headerByKey['class_category2']]);
463
                                                    $this->addErrors($message);
464 5
                                                } else {
465
                                                    if ($ClassCategory1 &&
466 5
                                                        ($ClassCategory1->getClassName()->getId() == $ClassCategory2->getClassName()->getId())
467 5
                                                    ) {
468 5
                                                        $message = trans('admin.common.csv_invalid_not_same', [
469 5
                                                            '%line%' => $line,
470 5
                                                            '%name1%' => $headerByKey['class_category1'],
471
                                                            '%name2%' => $headerByKey['class_category2'],
472
                                                        ]);
473
                                                        $this->addErrors($message);
474
                                                    }
475 5
                                                }
476
                                            } else {
477
                                                $message = trans('admin.common.csv_invalid_not_found', ['%line%' => $line, '%name%' => $headerByKey['class_category2']]);
478
                                                $this->addErrors($message);
479
                                            }
480
                                        }
481
                                    } else {
482
                                        if ($pc->getClassCategory1() != null && $pc->getClassCategory2() != null) {
483
                                            $message = trans('admin.common.csv_invalid_required', ['%line%' => $line, '%name%' => $headerByKey['class_category2']]);
484 6
                                            $this->addErrors($message);
485
                                        }
486 6
                                    }
487
                                    $ProductClass = $this->createProductClass($row, $Product, $data, $headerByKey, $ClassCategory1, $ClassCategory2);
488 6
489 6 View Code Duplication
                                    if ($this->BaseInfo->isOptionProductDeliveryFee()) {
490 6
                                        if (isset($row[$headerByKey['delivery_fee']]) && StringUtil::isNotBlank($row[$headerByKey['delivery_fee']])) {
491 6
                                            $deliveryFee = str_replace(',', '', $row[$headerByKey['delivery_fee']]);
492 6
                                            $errors = $this->validator->validate($deliveryFee, new GreaterThanOrEqual(['value' => 0]));
493 6
                                            if ($errors->count() === 0) {
494 6
                                                $ProductClass->setDeliveryFee($deliveryFee);
495 6
                                            } else {
496 6
                                                $message = trans('admin.common.csv_invalid_greater_than_zero', ['%line%' => $line, '%name%' => $headerByKey['delivery_fee']]);
497
                                                $this->addErrors($message);
498
                                            }
499
                                        }
500
                                    }
501
                                    $Product->addProductClass($ProductClass);
502
                                }
503
                            }
504
                        }
505 6
                        if ($this->hasErrors()) {
506
                            return $this->renderWithError($form, $headers);
507 6
                        }
508 6
                        $this->entityManager->persist($Product);
509 1
                    }
510
                    $this->entityManager->flush();
511 1
                    $this->entityManager->getConnection()->commit();
512
513
                    // 画像ファイルの削除(commit後に削除させる)
514 5 View Code Duplication
                    foreach ($deleteImages as $images) {
515 5
                        foreach ($images as $image) {
516
                            try {
517
                                $fs = new Filesystem();
518
                                $fs->remove($this->eccubeConfig['eccube_save_image_dir'].'/'.$image);
519
                            } catch (\Exception $e) {
520 5
                                // エラーが発生しても無視する
521 5
                            }
522
                        }
523 5
                    }
524
525 5
                    log_info('商品CSV登録完了');
526 5
                    $message = 'admin.common.csv_upload_complete';
527 1
                    $this->session->getFlashBag()->add('eccube.admin.success', $message);
528
529
                    $cacheUtil->clearDoctrineCache();
530
                }
531
            }
532 1
        }
533 1
534
        return $this->renderWithError($form, $headers);
535
    }
536
537
    /**
538 1
     * カテゴリ登録CSVアップロード
539
     *
540
     * @Route("/%eccube_admin_route%/product/category_csv_upload", name="admin_product_category_csv_import")
541
     * @Template("@admin/Product/csv_category.twig")
542
     */
543
    public function csvCategory(Request $request, CacheUtil $cacheUtil)
544
    {
545 5
        $form = $this->formFactory->createBuilder(CsvImportType::class)->getForm();
546 1
547
        $headers = $this->getCategoryCsvHeader();
548
        if ('POST' === $request->getMethod()) {
549
            $form->handleRequest($request);
550
            if ($form->isValid()) {
551
                $formFile = $form['import_file']->getData();
552
                if (!empty($formFile)) {
553
                    log_info('カテゴリCSV登録開始');
554
                    $data = $this->getImportData($formFile);
555 View Code Duplication
                    if ($data === false) {
556
                        $this->addErrors(trans('admin.common.csv_invalid_format'));
557
558
                        return $this->renderWithError($form, $headers, false);
559
                    }
560
561
                    $getId = function ($item) {
562
                        return $item['id'];
563
                    };
564
                    $requireHeader = array_keys(array_map($getId, array_filter($headers, function ($value) {
565 5
                        return $value['required'];
566 1
                    })));
567
568 1
                    $headerByKey = array_flip(array_map($getId, $headers));
569
570 4
                    $columnHeaders = $data->getColumnHeaders();
571 View Code Duplication
                    if (count(array_diff($requireHeader, $columnHeaders)) > 0) {
572
                        $this->addErrors(trans('admin.common.csv_invalid_format'));
573 4
574 4
                        return $this->renderWithError($form, $headers, false);
575 1
                    }
576
577
                    $size = count($data);
578 View Code Duplication
                    if ($size < 1) {
579
                        $this->addErrors(trans('admin.common.csv_invalid_no_data'));
580
581
                        return $this->renderWithError($form, $headers, false);
582 1
                    }
583 1
                    $this->entityManager->getConfiguration()->setSQLLogger(null);
584
                    $this->entityManager->getConnection()->beginTransaction();
585
                    // CSVファイルの登録処理
586
                    foreach ($data as $row) {
587
                        /** @var $Category Category */
588
                        $Category = new Category();
589 4
                        if (isset($row[$headerByKey['id']]) && strlen($row[$headerByKey['id']]) > 0) {
590 View Code Duplication
                            if (!preg_match('/^\d+$/', $row[$headerByKey['id']])) {
591
                                $this->addErrors(($data->key() + 1).'行目のカテゴリIDが存在しません。');
592 4
593
                                return $this->renderWithError($form, $headers);
594
                            }
595
                            $Category = $this->categoryRepository->find($row[$headerByKey['id']]);
596
                            if (!$Category) {
597
                                $this->addErrors(($data->key() + 1).'行目のカテゴリIDが存在しません。');
598
599
                                return $this->renderWithError($form, $headers);
600 4
                            }
601 4
                            if ($row[$headerByKey['id']] == $row[$headerByKey['parent_category_id']]) {
602 1
                                $this->addErrors(($data->key() + 1).'行目のカテゴリIDと親カテゴリIDが同じです。');
603
604
                                return $this->renderWithError($form, $headers);
605
                            }
606 4
                        }
607
608 4
                        if (isset($row[$headerByKey['category_del_flg']]) && StringUtil::isNotBlank($row[$headerByKey['category_del_flg']])) {
609
                            if (StringUtil::trimAll($row[$headerByKey['category_del_flg']]) == 1) {
610
                                if ($Category->getId()) {
611
                                    log_info('カテゴリ削除開始', [$Category->getId()]);
612
                                    try {
613
                                        $this->categoryRepository->delete($Category);
614 4
                                        log_info('カテゴリ削除完了', [$Category->getId()]);
615
                                    } catch (ForeignKeyConstraintViolationException $e) {
616
                                        log_info('カテゴリ削除エラー', [$Category->getId(), $e]);
617 4
                                        $message = trans('admin.common.delete_error_foreign_key', ['%name%' => $Category->getName()]);
618 4
                                        $this->addError($message, 'admin');
619
620
                                        return $this->renderWithError($form, $headers);
621 4
                                    }
622 4
                                }
623 4
624 4
                                continue;
625
                            }
626
                        }
627
628
                        if (!isset($row[$headerByKey['category_name']]) || StringUtil::isBlank($row[$headerByKey['category_name']])) {
629 4
                            $this->addErrors(($data->key() + 1).'行目のカテゴリ名が設定されていません。');
630
631
                            return $this->renderWithError($form, $headers);
632
                        } else {
633
                            $Category->setName(StringUtil::trimAll($row[$headerByKey['category_name']]));
634
                        }
635
636
                        $ParentCategory = null;
637
                        if (isset($row[$headerByKey['parent_category_id']]) && StringUtil::isNotBlank($row[$headerByKey['parent_category_id']])) {
638 View Code Duplication
                            if (!preg_match('/^\d+$/', $row[$headerByKey['parent_category_id']])) {
639
                                $this->addErrors(($data->key() + 1).'行目の親カテゴリIDが存在しません。');
640
641
                                return $this->renderWithError($form, $headers);
642
                            }
643
644
                            /** @var $ParentCategory Category */
645
                            $ParentCategory = $this->categoryRepository->find($row[$headerByKey['parent_category_id']]);
646
                            if (!$ParentCategory) {
647
                                $this->addErrors(($data->key() + 1).'行目の親カテゴリIDが存在しません。');
648
649
                                return $this->renderWithError($form, $headers);
650
                            }
651
                        }
652
                        $Category->setParent($ParentCategory);
653
654
                        // Level
655
                        if (isset($row['階層']) && StringUtil::isNotBlank($row['階層'])) {
656 View Code Duplication
                            if ($ParentCategory == null && $row['階層'] != 1) {
657
                                $this->addErrors(($data->key() + 1).'行目の親カテゴリIDが存在しません。');
658
659
                                return $this->renderWithError($form, $headers);
660
                            }
661
                            $level = StringUtil::trimAll($row['階層']);
662
                        } else {
663 16
                            $level = 1;
664
                            if ($ParentCategory) {
665 16
                                $level = $ParentCategory->getHierarchy() + 1;
666 7
                            }
667 6
                        }
668
669
                        $Category->setHierarchy($level);
670
671 16
                        if ($this->eccubeConfig['eccube_category_nest_level'] < $Category->getHierarchy()) {
672
                            $this->addErrors(($data->key() + 1).'行目のカテゴリが最大レベルを超えているため設定できません。');
673
674 16
                            return $this->renderWithError($form, $headers);
675 16
                        }
676 16
677
                        if ($this->hasErrors()) {
678
                            return $this->renderWithError($form, $headers);
679
                        }
680
                        $this->entityManager->persist($Category);
681
                        $this->categoryRepository->save($Category);
682
                    }
683
684
                    $this->entityManager->getConnection()->commit();
685
                    log_info('カテゴリCSV登録完了');
686
                    $message = 'admin.common.csv_upload_complete';
687 8
                    $this->session->getFlashBag()->add('eccube.admin.success', $message);
688
689 8
                    $cacheUtil->clearDoctrineCache();
690
                }
691 4
            }
692 4
        }
693 2
694 2
        return $this->renderWithError($form, $headers);
695
    }
696
697
    /**
698 4
     * アップロード用CSV雛形ファイルダウンロード
699
     *
700 4
     * @Route("/%eccube_admin_route%/product/csv_template/{type}", requirements={"type" = "\w+"}, name="admin_product_csv_template")
701
     */
702 4
    public function csvTemplate(Request $request, $type)
703 4
    {
704 4
        if ($type == 'product') {
705
            $headers = $this->getProductCsvHeader();
706
            $filename = 'product.csv';
707 4
        } elseif ($type == 'category') {
708
            $headers = $this->getCategoryCsvHeader();
709
            $filename = 'category.csv';
710
        } else {
711
            throw new NotFoundHttpException();
712 4
        }
713 4
714 4
        return $this->sendTemplateResponse($request, array_keys($headers), $filename);
715 4
    }
716 4
717
    /**
718 4
     * 登録、更新時のエラー画面表示
719 4
     *
720 4
     * @param FormInterface $form
721
     * @param array $headers
722
     * @param bool $rollback
723
     *
724
     * @return array
725
     *
726
     * @throws \Doctrine\DBAL\ConnectionException
727
     */
728
    protected function renderWithError($form, $headers, $rollback = true)
729
    {
730
        if ($this->hasErrors()) {
731
            if ($rollback) {
732
                $this->entityManager->getConnection()->rollback();
733
            }
734
        }
735 8
736
        $this->removeUploadedFile();
737
738 8
        return [
739 8
            'form' => $form->createView(),
740 2
            'headers' => $headers,
741 2
            'errors' => $this->errors,
742 2
        ];
743
    }
744
745 8
    /**
746
     * 商品画像の削除、登録
747 4
     *
748 4
     * @param $row
749 4
     * @param Product $Product
750 4
     * @param CsvImportService $data
751 4
     */
752 4
    protected function createProductImage($row, Product $Product, $data, $headerByKey)
753 4
    {
754 4
        if (isset($row[$headerByKey['product_image']]) && StringUtil::isNotBlank($row[$headerByKey['product_image']])) {
755
            // 画像の削除
756
            $ProductImages = $Product->getProductImage();
757
            foreach ($ProductImages as $ProductImage) {
758
                $Product->removeProductImage($ProductImage);
759
                $this->entityManager->remove($ProductImage);
760
            }
761
762 4
            // 画像の登録
763 4
            $images = explode(',', $row[$headerByKey['product_image']]);
764 4
765 4
            $sortNo = 1;
766 4
767
            $pattern = "/\\$|^.*.\.\\\.*|\/$|^.*.\.\/\.*/";
768 4
            foreach ($images as $image) {
769 4
                $fileName = StringUtil::trimAll($image);
770
771
                // 商品画像名のフォーマットチェック
772 4
                if (strlen($fileName) > 0 && preg_match($pattern, $fileName)) {
773
                    $message = trans('admin.common.csv_invalid_image', ['%line%' => $data->key() + 1, '%name%' => $headerByKey['product_image']]);
774
                    $this->addErrors($message);
775
                } else {
776
                    // 空文字は登録対象外
777
                    if (!empty($fileName)) {
778
                        $ProductImage = new ProductImage();
779
                        $ProductImage->setFileName($fileName);
780
                        $ProductImage->setProduct($Product);
781 4
                        $ProductImage->setSortNo($sortNo);
782
783
                        $Product->addProductImage($ProductImage);
784
                        $sortNo++;
785
                        $this->entityManager->persist($ProductImage);
786 4
                    }
787
                }
788
            }
789
        }
790
    }
791
792
    /**
793
     * 商品カテゴリの削除、登録
794 4
     *
795
     * @param $row
796
     * @param Product $Product
797
     * @param CsvImportService $data
798
     * @param $headerByKey
799
     */
800
    protected function createProductCategory($row, Product $Product, $data, $headerByKey)
801
    {
802
        // カテゴリの削除
803
        $ProductCategories = $Product->getProductCategories();
804
        foreach ($ProductCategories as $ProductCategory) {
805
            $Product->removeProductCategory($ProductCategory);
806
            $this->entityManager->remove($ProductCategory);
807 8
            $this->entityManager->flush();
808
        }
809
810 8
        if (isset($row[$headerByKey['product_category']]) && StringUtil::isNotBlank($row[$headerByKey['product_category']])) {
811 8
            // カテゴリの登録
812 1
            $categories = explode(',', $row[$headerByKey['product_category']]);
813 1
            $sortNo = 1;
814
            $categoriesIdList = [];
815
            foreach ($categories as $category) {
816 8
                $line = $data->key() + 1;
817
                if (preg_match('/^\d+$/', $category)) {
818 4
                    $Category = $this->categoryRepository->find($category);
819 4
                    if (!$Category) {
820 4
                        $message = trans('admin.common.csv_invalid_not_found_target', [
821 4
                            '%line%' => $line,
822 4
                            '%name%' => $headerByKey['product_category'],
823
                            '%target_name%' => $category,
824 4
                        ]);
825 4
                        $this->addErrors($message);
826
                    } else {
827 4 View Code Duplication
                        foreach ($Category->getPath() as $ParentCategory) {
828 4
                            if (!isset($categoriesIdList[$ParentCategory->getId()])) {
829
                                $ProductCategory = $this->makeProductCategory($Product, $ParentCategory, $sortNo);
830 4
                                $this->entityManager->persist($ProductCategory);
831
                                $sortNo++;
832 4
833
                                $Product->addProductCategory($ProductCategory);
834
                                $categoriesIdList[$ParentCategory->getId()] = true;
835 4
                            }
836
                        }
837
                        if (!isset($categoriesIdList[$Category->getId()])) {
838
                            $ProductCategory = $this->makeProductCategory($Product, $Category, $sortNo);
839
                            $sortNo++;
840
                            $this->entityManager->persist($ProductCategory);
841 4
                            $Product->addProductCategory($ProductCategory);
842
                            $categoriesIdList[$Category->getId()] = true;
843
                        }
844
                    }
845 View Code Duplication
                } else {
846
                    $message = trans('admin.common.csv_invalid_not_found_target', [
847
                        '%line%' => $line,
848
                        '%name%' => $headerByKey['product_category'],
849
                        '%target_name%' => $category,
850
                    ]);
851
                    $this->addErrors($message);
852
                }
853
            }
854
        }
855
    }
856
857
    /**
858
     * タグの登録
859 8
     *
860
     * @param array $row
861
     * @param Product $Product
862 8
     * @param CsvImportService $data
863 8
     */
864 8
    protected function createProductTag($row, Product $Product, $data, $headerByKey)
865
    {
866 8
        // タグの削除
867 8
        $ProductTags = $Product->getProductTag();
868 8
        foreach ($ProductTags as $ProductTag) {
869 8
            $Product->removeProductTag($ProductTag);
870 8
            $this->entityManager->remove($ProductTag);
871
        }
872
873
        if (isset($row[$headerByKey['product_tag']]) && StringUtil::isNotBlank($row[$headerByKey['product_tag']])) {
874 8
            // タグの登録
875
            $tags = explode(',', $row[$headerByKey['product_tag']]);
876
            foreach ($tags as $tag_id) {
877
                $Tag = null;
878 8
                if (preg_match('/^\d+$/', $tag_id)) {
879
                    $Tag = $this->tagRepository->find($tag_id);
880
881
                    if ($Tag) {
882
                        $ProductTags = new ProductTag();
883
                        $ProductTags
884
                            ->setProduct($Product)
885 8
                            ->setTag($Tag);
886 8
887
                        $Product->addProductTag($ProductTags);
888 8
889 3
                        $this->entityManager->persist($ProductTags);
890 3
                    }
891 3
                }
892 View Code Duplication
                if (!$Tag) {
893
                    $message = trans('admin.common.csv_invalid_not_found_target', [
894
                        '%line%' => $data->key() + 1,
895 3
                        '%name%' => $headerByKey['product_tag'],
896
                        '%target_name%' => $tag_id,
897
                    ]);
898
                    $this->addErrors($message);
899
                }
900
            }
901
        }
902
    }
903 8
904 3
    /**
905
     * 商品規格分類1、商品規格分類2がnullとなる商品規格情報を作成
906 5
     *
907
     * @param $row
908
     * @param Product $Product
909 8
     * @param CsvImportService $data
910
     * @param $headerByKey
911
     * @param null $ClassCategory1
912
     * @param null $ClassCategory2
913 8
     *
914 4
     * @return ProductClass
915
     */
916 4
    protected function createProductClass($row, Product $Product, $data, $headerByKey, $ClassCategory1 = null, $ClassCategory2 = null)
917 4
    {
918 4
        // 規格分類1、規格分類2がnullとなる商品を作成
919 4
        $ProductClass = new ProductClass();
920
        $ProductClass->setProduct($Product);
921
        $ProductClass->setVisible(true);
922 4
923
        $line = $data->key() + 1;
924
        if (isset($row[$headerByKey['sale_type']]) && StringUtil::isNotBlank($row[$headerByKey['sale_type']])) {
925
            if (preg_match('/^\d+$/', $row[$headerByKey['sale_type']])) {
926 4
                $SaleType = $this->saleTypeRepository->find($row[$headerByKey['sale_type']]);
927
                if (!$SaleType) {
928 4
                    $message = trans('admin.common.csv_invalid_not_found', ['%line%' => $line, '%name%' => $headerByKey['sale_type']]);
929 4
                    $this->addErrors($message);
930 4
                } else {
931
                    $ProductClass->setSaleType($SaleType);
932
                }
933
            } else {
934
                $message = trans('admin.common.csv_invalid_not_found', ['%line%' => $line, '%name%' => $headerByKey['sale_type']]);
935
                $this->addErrors($message);
936
            }
937 8
        } else {
938
            $message = trans('admin.common.csv_invalid_required', ['%line%' => $line, '%name%' => $headerByKey['sale_type']]);
939
            $this->addErrors($message);
940
        }
941
942
        $ProductClass->setClassCategory1($ClassCategory1);
943
        $ProductClass->setClassCategory2($ClassCategory2);
944
945
        if (isset($row[$headerByKey['delivery_date']]) && StringUtil::isNotBlank($row[$headerByKey['delivery_date']])) {
946
            if (preg_match('/^\d+$/', $row[$headerByKey['delivery_date']])) {
947 8
                $DeliveryDuration = $this->deliveryDurationRepository->find($row[$headerByKey['delivery_date']]);
948 3
                if (!$DeliveryDuration) {
949 3
                    $message = trans('admin.common.csv_invalid_not_found', ['%line%' => $line, '%name%' => $headerByKey['delivery_date']]);
950 3
                    $this->addErrors($message);
951
                } else {
952
                    $ProductClass->setDeliveryDuration($DeliveryDuration);
953
                }
954
            } else {
955
                $message = trans('admin.common.csv_invalid_not_found', ['%line%' => $line, '%name%' => $headerByKey['delivery_date']]);
956
                $this->addErrors($message);
957 8
            }
958 8
        }
959 8
960 8 View Code Duplication
        if (isset($row[$headerByKey['product_code']]) && StringUtil::isNotBlank($row[$headerByKey['product_code']])) {
961
            $ProductClass->setCode(StringUtil::trimAll($row[$headerByKey['product_code']]));
962
        } else {
963 8
            $ProductClass->setCode(null);
964
        }
965
966 View Code Duplication
        if (!isset($row[$headerByKey['stock_unlimited']])
967
            || StringUtil::isBlank($row[$headerByKey['stock_unlimited']])
968
            || $row[$headerByKey['stock_unlimited']] == (string) Constant::DISABLED
969
        ) {
970 8
            $ProductClass->setStockUnlimited(false);
971 3
            // 在庫数が設定されていなければエラー
972 3
            if (isset($row[$headerByKey['stock']]) && StringUtil::isNotBlank($row[$headerByKey['stock']])) {
973 3
                $stock = str_replace(',', '', $row[$headerByKey['stock']]);
974
                if (preg_match('/^\d+$/', $stock) && $stock >= 0) {
975
                    $ProductClass->setStock($stock);
976
                } else {
977
                    $message = trans('admin.common.csv_invalid_greater_than_zero', ['%line%' => $line, '%name%' => $headerByKey['stock']]);
978
                    $this->addErrors($message);
979
                }
980 8
            } else {
981 8
                $message = trans('admin.common.csv_invalid_required', ['%line%' => $line, '%name%' => $headerByKey['stock']]);
982 8
                $this->addErrors($message);
983 8
            }
984
        } elseif ($row[$headerByKey['stock_unlimited']] == (string) Constant::ENABLED) {
985 8
            $ProductClass->setStockUnlimited(true);
986 4
            $ProductClass->setStock(null);
987
        } else {
988
            $message = trans('admin.common.csv_invalid_required', ['%line%' => $line, '%name%' => $headerByKey['stock_unlimited']]);
989 4
            $this->addErrors($message);
990
        }
991
992 8
        if (isset($row[$headerByKey['sale_limit']]) && StringUtil::isNotBlank($row[$headerByKey['sale_limit']])) {
993 8
            $saleLimit = str_replace(',', '', $row[$headerByKey['sale_limit']]);
994
            if (preg_match('/^\d+$/', $saleLimit) && $saleLimit >= 0) {
995 8
                $ProductClass->setSaleLimit($saleLimit);
996
            } else {
997
                $message = trans('admin.common.csv_invalid_greater_than_zero', ['%line%' => $line, '%name%' => $headerByKey['sale_limit']]);
998
                $this->addErrors($message);
999
            }
1000
        }
1001
1002
        if (isset($row[$headerByKey['price01']]) && StringUtil::isNotBlank($row[$headerByKey['price01']])) {
1003
            $price01 = str_replace(',', '', $row[$headerByKey['price01']]);
1004
            $errors = $this->validator->validate($price01, new GreaterThanOrEqual(['value' => 0]));
1005
            if ($errors->count() === 0) {
1006
                $ProductClass->setPrice01($price01);
1007
            } else {
1008 1
                $message = trans('admin.common.csv_invalid_greater_than_zero', ['%line%' => $line, '%name%' => $headerByKey['price01']]);
1009
                $this->addErrors($message);
1010 1
            }
1011
        }
1012 1
1013 1
        if (isset($row[$headerByKey['price02']]) && StringUtil::isNotBlank($row[$headerByKey['price02']])) {
1014
            $price02 = str_replace(',', '', $row[$headerByKey['price02']]);
1015
            $errors = $this->validator->validate($price02, new GreaterThanOrEqual(['value' => 0]));
1016
            if ($errors->count() === 0) {
1017 1
                $ProductClass->setPrice02($price02);
1018 1
            } else {
1019 1
                $message = trans('admin.common.csv_invalid_greater_than_zero', ['%line%' => $line, '%name%' => $headerByKey['price02']]);
1020
                $this->addErrors($message);
1021
            }
1022
        } else {
1023 1
            $message = trans('admin.common.csv_invalid_required', ['%line%' => $line, '%name%' => $headerByKey['price02']]);
1024
            $this->addErrors($message);
1025
        }
1026
1027 View Code Duplication
        if ($this->BaseInfo->isOptionProductDeliveryFee()) {
1028
            if (isset($row[$headerByKey['delivery_fee']]) && StringUtil::isNotBlank($row[$headerByKey['delivery_fee']])) {
1029
                $delivery_fee = str_replace(',', '', $row[$headerByKey['delivery_fee']]);
1030
                $errors = $this->validator->validate($delivery_fee, new GreaterThanOrEqual(['value' => 0]));
1031
                if ($errors->count() === 0) {
1032 1
                    $ProductClass->setDeliveryFee($delivery_fee);
1033 1
                } else {
1034 1
                    $message = trans('admin.common.csv_invalid_greater_than_zero',
1035 1
                        ['%line%' => $line, '%name%' => $headerByKey['delivery_fee']]);
1036
                    $this->addErrors($message);
1037
                }
1038
            }
1039 1
        }
1040
1041
        $Product->addProductClass($ProductClass);
1042
        $ProductStock = new ProductStock();
1043
        $ProductClass->setProductStock($ProductStock);
1044
        $ProductStock->setProductClass($ProductClass);
1045
1046
        if (!$ProductClass->isStockUnlimited()) {
1047 1
            $ProductStock->setStock($ProductClass->getStock());
1048 1
        } else {
1049 1
            // 在庫無制限時はnullを設定
1050 1
            $ProductStock->setStock(null);
1051
        }
1052
1053
        $this->entityManager->persist($ProductClass);
1054 1
        $this->entityManager->persist($ProductStock);
1055
1056
        return $ProductClass;
1057
    }
1058
1059
    /**
1060
     * 商品規格情報を更新
1061
     *
1062 1
     * @param $row
1063
     * @param Product $Product
1064
     * @param ProductClass $ProductClass
1065
     * @param CsvImportService $data
1066
     *
1067
     * @return ProductClass
1068
     */
1069
    protected function updateProductClass($row, Product $Product, ProductClass $ProductClass, $data, $headerByKey)
1070
    {
1071
        $ProductClass->setProduct($Product);
1072
1073
        $line = $data->key() + 1;
1074
        if ($row[$headerByKey['sale_type']] == '') {
1075
            $message = trans('admin.common.csv_invalid_required', ['%line%' => $line, '%name%' => $headerByKey['sale_type']]);
1076
            $this->addErrors($message);
1077 1
        } else {
1078 1
            if (preg_match('/^\d+$/', $row[$headerByKey['sale_type']])) {
1079
                $SaleType = $this->saleTypeRepository->find($row[$headerByKey['sale_type']]);
1080
                if (!$SaleType) {
1081
                    $message = trans('admin.common.csv_invalid_not_found', ['%line%' => $line, '%name%' => $headerByKey['sale_type']]);
1082
                    $this->addErrors($message);
1083 1
                } else {
1084
                    $ProductClass->setSaleType($SaleType);
1085
                }
1086
            } else {
1087 1
                $message = trans('admin.common.csv_invalid_required', ['%line%' => $line, '%name%' => $headerByKey['sale_type']]);
1088 1
                $this->addErrors($message);
1089
            }
1090 1
        }
1091
1092
        // 規格分類1、2をそれぞれセットし作成
1093 View Code Duplication
        if ($row[$headerByKey['class_category1']] != '') {
1094 1
            if (preg_match('/^\d+$/', $row[$headerByKey['class_category1']])) {
1095 1
                $ClassCategory = $this->classCategoryRepository->find($row[$headerByKey['class_category1']]);
1096 1
                if (!$ClassCategory) {
1097
                    $message = trans('admin.common.csv_invalid_not_found', ['%line%' => $line, '%name%' => $headerByKey['class_category1']]);
1098
                    $this->addErrors($message);
1099 1
                } else {
1100
                    $ProductClass->setClassCategory1($ClassCategory);
1101
                }
1102 1
            } else {
1103 1
                $message = trans('admin.common.csv_invalid_not_found', ['%line%' => $line, '%name%' => $headerByKey['class_category1']]);
1104 1
                $this->addErrors($message);
1105
            }
1106
        }
1107
1108 View Code Duplication
        if ($row[$headerByKey['class_category2']] != '') {
1109
            if (preg_match('/^\d+$/', $row[$headerByKey['class_category2']])) {
1110
                $ClassCategory = $this->classCategoryRepository->find($row[$headerByKey['class_category2']]);
1111 1
                if (!$ClassCategory) {
1112 1
                    $message = trans('admin.common.csv_invalid_not_found', ['%line%' => $line, '%name%' => $headerByKey['class_category2']]);
1113 1
                    $this->addErrors($message);
1114 1
                } else {
1115
                    $ProductClass->setClassCategory2($ClassCategory);
1116
                }
1117
            } else {
1118
                $message = trans('admin.common.csv_invalid_not_found', ['%line%' => $line, '%name%' => $headerByKey['class_category2']]);
1119
                $this->addErrors($message);
1120
            }
1121 1
        }
1122 1
1123 1 View Code Duplication
        if ($row[$headerByKey['delivery_date']] != '') {
1124 1
            if (preg_match('/^\d+$/', $row[$headerByKey['delivery_date']])) {
1125
                $DeliveryDuration = $this->deliveryDurationRepository->find($row[$headerByKey['delivery_date']]);
1126
                if (!$DeliveryDuration) {
1127
                    $message = trans('admin.common.csv_invalid_not_found', ['%line%' => $line, '%name%' => $headerByKey['delivery_date']]);
1128
                    $this->addErrors($message);
1129
                } else {
1130
                    $ProductClass->setDeliveryDuration($DeliveryDuration);
1131 1
                }
1132
            } else {
1133
                $message = trans('admin.common.csv_invalid_not_found', ['%line%' => $line, '%name%' => $headerByKey['delivery_date']]);
1134
                $this->addErrors($message);
1135 1
            }
1136 1
        }
1137 1
1138
        if (StringUtil::isNotBlank($row[$headerByKey['product_code']])) {
1139
            $ProductClass->setCode(StringUtil::trimAll($row[$headerByKey['product_code']]));
1140
        } else {
1141
            $ProductClass->setCode(null);
1142
        }
1143
1144 1 View Code Duplication
        if (!isset($row[$headerByKey['stock_unlimited']])
1145
            || StringUtil::isBlank($row[$headerByKey['stock_unlimited']])
1146 1
            || $row[$headerByKey['stock_unlimited']] == (string) Constant::DISABLED
1147 1
        ) {
1148
            $ProductClass->setStockUnlimited(false);
1149
            // 在庫数が設定されていなければエラー
1150 1
            if ($row[$headerByKey['stock']] == '') {
1151
                $message = trans('admin.common.csv_invalid_required', ['%line%' => $line, '%name%' => $headerByKey['stock']]);
1152
                $this->addErrors($message);
1153 1
            } else {
1154
                $stock = str_replace(',', '', $row[$headerByKey['stock']]);
1155
                if (preg_match('/^\d+$/', $stock) && $stock >= 0) {
1156
                    $ProductClass->setStock($row[$headerByKey['stock']]);
1157
                } else {
1158
                    $message = trans('admin.common.csv_invalid_greater_than_zero', ['%line%' => $line, '%name%' => $headerByKey['stock']]);
1159 7
                    $this->addErrors($message);
1160
                }
1161 7
            }
1162 7
        } elseif ($row[$headerByKey['stock_unlimited']] == (string) Constant::ENABLED) {
1163
            $ProductClass->setStockUnlimited(true);
1164
            $ProductClass->setStock(null);
1165
        } else {
1166
            $message = trans('admin.common.csv_invalid_required', ['%line%' => $line, '%name%' => $headerByKey['stock_unlimited']]);
1167
            $this->addErrors($message);
1168 16
        }
1169
1170 16
        if ($row[$headerByKey['sale_limit']] != '') {
1171
            $saleLimit = str_replace(',', '', $row[$headerByKey['sale_limit']]);
1172
            if (preg_match('/^\d+$/', $saleLimit) && $saleLimit >= 0) {
1173
                $ProductClass->setSaleLimit($saleLimit);
1174
            } else {
1175
                $message = trans('admin.common.csv_invalid_greater_than_zero', ['%line%' => $line, '%name%' => $headerByKey['sale_limit']]);
1176 16
                $this->addErrors($message);
1177
            }
1178 16
        }
1179
1180
        if ($row[$headerByKey['price01']] != '') {
1181
            $price01 = str_replace(',', '', $row[$headerByKey['price01']]);
1182
            $errors = $this->validator->validate($price01, new GreaterThanOrEqual(['value' => 0]));
1183
            if ($errors->count() === 0) {
1184
                $ProductClass->setPrice01($price01);
1185
            } else {
1186 10
                $message = trans('admin.common.csv_invalid_greater_than_zero', ['%line%' => $line, '%name%' => $headerByKey['price01']]);
1187
                $this->addErrors($message);
1188
            }
1189 10
        }
1190
1191
        if ($row[$headerByKey['price02']] == '') {
1192
            $message = trans('admin.common.csv_invalid_required', ['%line%' => $line, '%name%' => $headerByKey['price02']]);
1193
            $this->addErrors($message);
1194 10
        } else {
1195
            $price02 = str_replace(',', '', $row[$headerByKey['price02']]);
1196
            $errors = $this->validator->validate($price02, new GreaterThanOrEqual(['value' => 0]));
1197
            if ($errors->count() === 0) {
1198
                $ProductClass->setPrice02($price02);
1199 10
            } else {
1200
                $message = trans('admin.common.csv_invalid_greater_than_zero', ['%line%' => $line, '%name%' => $headerByKey['price02']]);
1201
                $this->addErrors($message);
1202
            }
1203
        }
1204 10
1205
        $ProductStock = $ProductClass->getProductStock();
1206
1207
        if (!$ProductClass->isStockUnlimited()) {
1208
            $ProductStock->setStock($ProductClass->getStock());
1209 10
        } else {
1210
            // 在庫無制限時はnullを設定
1211
            $ProductStock->setStock(null);
1212
        }
1213
1214 10
        return $ProductClass;
1215
    }
1216
1217
    /**
1218
     * 登録、更新時のエラー画面表示
1219 10
     */
1220
    protected function addErrors($message)
1221
    {
1222
        $this->errors[] = $message;
1223
    }
1224 10
1225
    /**
1226
     * @return array
1227
     */
1228
    protected function getErrors()
1229 10
    {
1230
        return $this->errors;
1231
    }
1232
1233
    /**
1234 10
     * @return boolean
1235
     */
1236
    protected function hasErrors()
1237
    {
1238
        return count($this->getErrors()) > 0;
1239 10
    }
1240
1241
    /**
1242
     * 商品登録CSVヘッダー定義
1243
     *
1244 10
     * @return array
1245
     */
1246
    protected function getProductCsvHeader()
1247
    {
1248
        return [
1249 10
            trans('admin.product.product_csv.product_id_col') => [
1250
                'id' => 'id',
1251
                'description' => 'admin.product.product_csv.product_id_description',
1252
                'required' => false,
1253
            ],
1254 10
            trans('admin.product.product_csv.display_status_col') => [
1255
                'id' => 'status',
1256
                'description' => 'admin.product.product_csv.display_status_description',
1257
                'required' => true,
1258
            ],
1259 10
            trans('admin.product.product_csv.product_name_col') => [
1260
                'id' => 'name',
1261
                'description' => 'admin.product.product_csv.product_name_description',
1262
                'required' => true,
1263
            ],
1264 10
            trans('admin.product.product_csv.shop_memo_col') => [
1265
                'id' => 'note',
1266
                'description' => 'admin.product.product_csv.shop_memo_description',
1267
                'required' => false,
1268
            ],
1269 10
            trans('admin.product.product_csv.description_list_col') => [
1270
                'id' => 'description_list',
1271
                'description' => 'admin.product.product_csv.description_list_description',
1272
                'required' => false,
1273
            ],
1274 10
            trans('admin.product.product_csv.description_detail_col') => [
1275
                'id' => 'description_detail',
1276
                'description' => 'admin.product.product_csv.description_detail_description',
1277
                'required' => false,
1278
            ],
1279 10
            trans('admin.product.product_csv.keyword_col') => [
1280
                'id' => 'search_word',
1281
                'description' => 'admin.product.product_csv.keyword_description',
1282
                'required' => false,
1283
            ],
1284 10
            trans('admin.product.product_csv.free_area_col') => [
1285
                'id' => 'free_area',
1286
                'description' => 'admin.product.product_csv.free_area_description',
1287
                'required' => false,
1288
            ],
1289 10
            trans('admin.product.product_csv.delete_flag_col') => [
1290
                'id' => 'product_del_flg',
1291
                'description' => 'admin.product.product_csv.delete_flag_description',
1292
                'required' => false,
1293
            ],
1294 10
            trans('admin.product.product_csv.product_image_col') => [
1295
                'id' => 'product_image',
1296
                'description' => 'admin.product.product_csv.product_image_description',
1297
                'required' => false,
1298
            ],
1299 10
            trans('admin.product.product_csv.category_col') => [
1300
                'id' => 'product_category',
1301
                'description' => 'admin.product.product_csv.category_description',
1302
                'required' => false,
1303
            ],
1304
            trans('admin.product.product_csv.tag_col') => [
1305
                'id' => 'product_tag',
1306
                'description' => 'admin.product.product_csv.tag_description',
1307
                'required' => false,
1308
            ],
1309
            trans('admin.product.product_csv.sale_type_col') => [
1310 6
                'id' => 'sale_type',
1311
                'description' => 'admin.product.product_csv.sale_type_description',
1312
                'required' => true,
1313 6
            ],
1314
            trans('admin.product.product_csv.class_category1_col') => [
1315
                'id' => 'class_category1',
1316
                'description' => 'admin.product.product_csv.class_category1_description',
1317
                'required' => false,
1318 6
            ],
1319
            trans('admin.product.product_csv.class_category2_col') => [
1320
                'id' => 'class_category2',
1321
                'description' => 'admin.product.product_csv.class_category2_description',
1322
                'required' => false,
1323 6
            ],
1324
            trans('admin.product.product_csv.delivery_duration_col') => [
1325
                'id' => 'delivery_date',
1326
                'description' => 'admin.product.product_csv.delivery_duration_description',
1327
                'required' => false,
1328 6
            ],
1329
            trans('admin.product.product_csv.product_code_col') => [
1330
                'id' => 'product_code',
1331
                'description' => 'admin.product.product_csv.product_code_description',
1332
                'required' => false,
1333
            ],
1334
            trans('admin.product.product_csv.stock_col') => [
1335
                'id' => 'stock',
1336
                'description' => 'admin.product.product_csv.stock_description',
1337
                'required' => false,
1338
            ],
1339
            trans('admin.product.product_csv.stock_unlimited_col') => [
1340
                'id' => 'stock_unlimited',
1341
                'description' => 'admin.product.product_csv.stock_unlimited_description',
1342
                'required' => false,
1343
            ],
1344
            trans('admin.product.product_csv.sale_limit_col') => [
1345 4
                'id' => 'sale_limit',
1346
                'description' => 'admin.product.product_csv.sale_limit_description',
1347 4
                'required' => false,
1348 4
            ],
1349 4
            trans('admin.product.product_csv.normal_price_col') => [
1350 4
                'id' => 'price01',
1351 4
                'description' => 'admin.product.product_csv.normal_price_description',
1352 4
                'required' => false,
1353
            ],
1354 4
            trans('admin.product.product_csv.sale_price_col') => [
1355
                'id' => 'price02',
1356
                'description' => 'admin.product.product_csv.sale_price_description',
1357
                'required' => true,
1358
            ],
1359
            trans('admin.product.product_csv.delivery_fee_col') => [
1360
                'id' => 'delivery_fee',
1361
                'description' => 'admin.product.product_csv.delivery_fee_description',
1362
                'required' => false,
1363
            ],
1364
        ];
1365
    }
1366
1367
    /**
1368
     * カテゴリCSVヘッダー定義
1369
     */
1370
    protected function getCategoryCsvHeader()
1371
    {
1372
        return [
1373
            trans('admin.product.category_csv.category_id_col') => [
1374
                'id' => 'id',
1375
                'description' => 'admin.product.category_csv.category_id_description',
1376
                'required' => false,
1377
            ],
1378
            trans('admin.product.category_csv.category_name_col') => [
1379
                'id' => 'category_name',
1380
                'description' => 'admin.product.category_csv.category_name_description',
1381
                'required' => true,
1382
            ],
1383
            trans('admin.product.category_csv.parent_category_id_col') => [
1384
                'id' => 'parent_category_id',
1385
                'description' => 'admin.product.category_csv.parent_category_id_description',
1386
                'required' => false,
1387
            ],
1388
            trans('admin.product.category_csv.delete_flag_col') => [
1389
                'id' => 'category_del_flg',
1390
                'description' => 'admin.product.category_csv.delete_flag_description',
1391
                'required' => false,
1392
            ],
1393
        ];
1394
    }
1395
1396
    /**
1397
     * ProductCategory作成
1398
     *
1399
     * @param \Eccube\Entity\Product $Product
1400
     * @param \Eccube\Entity\Category $Category
1401
     * @param int $sortNo
1402
     *
1403
     * @return ProductCategory
1404
     */
1405 View Code Duplication
    private function makeProductCategory($Product, $Category, $sortNo)
1406
    {
1407
        $ProductCategory = new ProductCategory();
1408
        $ProductCategory->setProduct($Product);
1409
        $ProductCategory->setProductId($Product->getId());
1410
        $ProductCategory->setCategory($Category);
1411
        $ProductCategory->setCategoryId($Category->getId());
1412
1413
        return $ProductCategory;
1414
    }
1415
}
1416