Completed
Push — 4.0 ( be821e...e6ef8b )
by Hideki
04:45 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) 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\Repository\TaxRuleRepository;
37
use Eccube\Service\CsvImportService;
38
use Eccube\Util\CacheUtil;
39
use Eccube\Util\StringUtil;
40
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
41
use Symfony\Component\Filesystem\Filesystem;
42
use Symfony\Component\Form\FormInterface;
43
use Symfony\Component\HttpFoundation\Request;
44
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
45
use Symfony\Component\Routing\Annotation\Route;
46
use Symfony\Component\Validator\Constraints\GreaterThanOrEqual;
47
use Symfony\Component\Validator\Validator\ValidatorInterface;
48
49
class CsvImportController extends AbstractCsvImportController
50
{
51
    /**
52
     * @var DeliveryDurationRepository
53
     */
54
    protected $deliveryDurationRepository;
55
56
    /**
57
     * @var SaleTypeRepository
58
     */
59
    protected $saleTypeRepository;
60
61
    /**
62
     * @var TagRepository
63
     */
64
    protected $tagRepository;
65
66
    /**
67
     * @var CategoryRepository
68
     */
69
    protected $categoryRepository;
70
71
    /**
72
     * @var ClassCategoryRepository
73
     */
74
    protected $classCategoryRepository;
75
76
    /**
77
     * @var ProductStatusRepository
78
     */
79
    protected $productStatusRepository;
80
81
    /**
82
     * @var ProductRepository
83
     */
84
    protected $productRepository;
85
86
    /**
87
     * @var TaxRuleRepository
88
     */
89
    private $taxRuleRepository;
90
91
    /**
92
     * @var BaseInfo
93
     */
94
    protected $BaseInfo;
95
96
    /**
97
     * @var ValidatorInterface
98
     */
99
    protected $validator;
100
101 16
    private $errors = [];
102
103 16
    /**
104 16
     * CsvImportController constructor.
105 16
     *
106 16
     * @param DeliveryDurationRepository $deliveryDurationRepository
107 16
     * @param SaleTypeRepository $saleTypeRepository
108 16
     * @param TagRepository $tagRepository
109 16
     * @param CategoryRepository $categoryRepository
110 16
     * @param ClassCategoryRepository $classCategoryRepository
111
     * @param ProductStatusRepository $productStatusRepository
112
     * @param ProductRepository $productRepository
113
     * @param TaxRuleRepository $taxRuleRepository
114
     * @param BaseInfoRepository $baseInfoRepository
115
     * @param ValidatorInterface $validator
116
     *
117
     * @throws \Doctrine\ORM\NoResultException
118
     * @throws \Doctrine\ORM\NonUniqueResultException
119 10
     */
120 View Code Duplication
    public function __construct(
0 ignored issues
show
This method seems to be duplicated in your project.

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

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

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