Completed
Push — 4.0 ( 268f2c...88f012 )
by Hideki
05:48 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(
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) {
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...
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