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