app/Customize/Controller/Admin/Product/CsvImportControllerCustomizer.php line 58

Open in your IDE?
  1. <?php
  2. /*
  3.  * This file is part of EC-CUBE
  4.  *
  5.  * Copyright(c) EC-CUBE CO.,LTD. All Rights Reserved.
  6.  *
  7.  * http://www.ec-cube.co.jp/
  8.  *
  9.  * For the full copyright and license information, please view the LICENSE
  10.  * file that was distributed with this source code.
  11.  */
  12. namespace Customize\Controller\Admin\Product;
  13. use Doctrine\DBAL\Exception\ForeignKeyConstraintViolationException;
  14. use Eccube\Common\Constant;
  15. use Eccube\Controller\Admin\AbstractCsvImportController;
  16. use Eccube\Entity\BaseInfo;
  17. use Eccube\Entity\Category;
  18. use Eccube\Entity\Product;
  19. use Eccube\Entity\ProductCategory;
  20. use Eccube\Entity\ProductClass;
  21. use Eccube\Entity\ProductImage;
  22. use Eccube\Entity\ProductStock;
  23. use Eccube\Entity\ProductTag;
  24. use Eccube\Form\Type\Admin\CsvImportType;
  25. use Eccube\Repository\BaseInfoRepository;
  26. use Eccube\Repository\CategoryRepository;
  27. use Eccube\Repository\ClassCategoryRepository;
  28. use Eccube\Repository\DeliveryDurationRepository;
  29. use Eccube\Repository\Master\ProductStatusRepository;
  30. use Eccube\Repository\Master\SaleTypeRepository;
  31. use Eccube\Repository\ProductImageRepository;
  32. use Eccube\Repository\ProductRepository;
  33. use Eccube\Repository\TagRepository;
  34. use Eccube\Repository\TaxRuleRepository;
  35. use Eccube\Service\CsvImportService;
  36. use Eccube\Stream\Filter\ConvertLineFeedFilter;
  37. use Eccube\Stream\Filter\SjisToUtf8EncodingFilter;
  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\Finder\Finder;
  43. use Symfony\Component\Form\FormInterface;
  44. use Symfony\Component\HttpFoundation\File\UploadedFile;
  45. use Symfony\Component\HttpFoundation\Request;
  46. use Symfony\Component\HttpFoundation\StreamedResponse;
  47. use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
  48. use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
  49. use Symfony\Component\Routing\Annotation\Route;
  50. use Symfony\Component\Security\Csrf\CsrfTokenManagerInterface;
  51. use Symfony\Component\Validator\Constraints\GreaterThanOrEqual;
  52. use Symfony\Component\Validator\Validator\ValidatorInterface;
  53. use Eccube\Controller\Admin\Product\CsvImportController;
  54. class CsvImportControllerCustomizer extends CsvImportController
  55. {
  56.     /**
  57.      * 商品登録CSVアップロード
  58.      *
  59.      * @Route("/%eccube_admin_route%/product/product_csv_upload", name="admin_product_csv_import", methods={"GET", "POST"})
  60.      * @Template("@admin/Product/csv_product.twig")
  61.      *
  62.      * @return array
  63.      *
  64.      * @throws \Doctrine\DBAL\ConnectionException
  65.      * @throws \Doctrine\ORM\NoResultException
  66.      */
  67.     public function csvProduct(Request $requestCacheUtil $cacheUtil)
  68.     {
  69.         $form $this->formFactory->createBuilder(CsvImportType::class)->getForm();
  70.         $headers $this->getProductCsvHeader();
  71.         if ('POST' === $request->getMethod()) {
  72.             $form->handleRequest($request);
  73.             if ($form->isValid()) {
  74.                 $this->isSplitCsv $form['is_split_csv']->getData();
  75.                 $this->csvFileNo $form['csv_file_no']->getData();
  76.                 $formFile $form['import_file']->getData();
  77.                 if (!empty($formFile)) {
  78.                     log_info('商品CSV登録開始');
  79.                     $data $this->getImportData($formFile);
  80.                     if ($data === false) {
  81.                         $this->addErrors(trans('admin.common.csv_invalid_format'));
  82.                         return $this->renderWithError($form$headersfalse);
  83.                     }
  84.                     $getId = function ($item) {
  85.                         return $item['id'];
  86.                     };
  87.                     $requireHeader array_keys(array_map($getIdarray_filter($headers, function ($value) {
  88.                         return $value['required'];
  89.                     })));
  90.                     $columnHeaders $data->getColumnHeaders();
  91.                     if (count(array_diff($requireHeader$columnHeaders)) > 0) {
  92.                         $this->addErrors(trans('admin.common.csv_invalid_format'));
  93.                         return $this->renderWithError($form$headersfalse);
  94.                     }
  95.                     $size count($data);
  96.                     if ($size 1) {
  97.                         $this->addErrors(trans('admin.common.csv_invalid_no_data'));
  98.                         return $this->renderWithError($form$headersfalse);
  99.                     }
  100.                     $headerSize count($columnHeaders);
  101.                     $headerByKey array_flip(array_map($getId$headers));
  102.                     $deleteImages = [];
  103.                     $this->entityManager->getConfiguration()->setSQLLogger(null);
  104.                     $this->entityManager->getConnection()->beginTransaction();
  105.                     // CSVファイルの登録処理
  106.                     foreach ($data as $row) {
  107.                         $line $this->convertLineNo($data->key() + 1);
  108.                         $this->currentLineNo $line;
  109.                         if ($headerSize != count($row)) {
  110.                             $message trans('admin.common.csv_invalid_format_line', ['%line%' => $line]);
  111.                             $this->addErrors($message);
  112.                             return $this->renderWithError($form$headers);
  113.                         }
  114.                         if (!isset($row[$headerByKey['id']]) || StringUtil::isBlank($row[$headerByKey['id']])) {
  115.                             $Product = new Product();
  116.                             $this->entityManager->persist($Product);
  117.                         } else {
  118.                             if (preg_match('/^\d+$/'$row[$headerByKey['id']])) {
  119.                                 $Product $this->productRepository->find($row[$headerByKey['id']]);
  120.                                 if (!$Product) {
  121.                                     $message trans('admin.common.csv_invalid_not_found', ['%line%' => $line'%name%' => $headerByKey['id']]);
  122.                                     $this->addErrors($message);
  123.                                     return $this->renderWithError($form$headers);
  124.                                 }
  125.                             } else {
  126.                                 $message trans('admin.common.csv_invalid_not_found', ['%line%' => $line'%name%' => $headerByKey['id']]);
  127.                                 $this->addErrors($message);
  128.                                 return $this->renderWithError($form$headers);
  129.                             }
  130.                             if (isset($row[$headerByKey['product_del_flg']])) {
  131.                                 if (StringUtil::isNotBlank($row[$headerByKey['product_del_flg']]) && $row[$headerByKey['product_del_flg']] == (string) Constant::ENABLED) {
  132.                                     // 商品を物理削除
  133.                                     $deleteImages[] = $Product->getProductImage();
  134.                                     try {
  135.                                         $this->productRepository->delete($Product);
  136.                                         $this->entityManager->flush();
  137.                                         continue;
  138.                                     } catch (ForeignKeyConstraintViolationException $e) {
  139.                                         $message trans('admin.common.csv_invalid_foreign_key', ['%line%' => $line'%name%' => $Product->getName()]);
  140.                                         $this->addErrors($message);
  141.                                         return $this->renderWithError($form$headers);
  142.                                     }
  143.                                 }
  144.                             }
  145.                         }
  146.                         if (StringUtil::isBlank($row[$headerByKey['status']])) {
  147.                             $message trans('admin.common.csv_invalid_required', ['%line%' => $line'%name%' => $headerByKey['status']]);
  148.                             $this->addErrors($message);
  149.                         } else {
  150.                             if (preg_match('/^\d+$/'$row[$headerByKey['status']])) {
  151.                                 $ProductStatus $this->productStatusRepository->find($row[$headerByKey['status']]);
  152.                                 if (!$ProductStatus) {
  153.                                     $message trans('admin.common.csv_invalid_not_found', ['%line%' => $line'%name%' => $headerByKey['status']]);
  154.                                     $this->addErrors($message);
  155.                                 } else {
  156.                                     $Product->setStatus($ProductStatus);
  157.                                 }
  158.                             } else {
  159.                                 $message trans('admin.common.csv_invalid_not_found', ['%line%' => $line'%name%' => $headerByKey['status']]);
  160.                                 $this->addErrors($message);
  161.                             }
  162.                         }
  163.                         if (StringUtil::isBlank($row[$headerByKey['name']])) {
  164.                             $message trans('admin.common.csv_invalid_not_found', ['%line%' => $line'%name%' => $headerByKey['name']]);
  165.                             $this->addErrors($message);
  166.                             return $this->renderWithError($form$headers);
  167.                         } else {
  168.                             $Product->setName(StringUtil::trimAll($row[$headerByKey['name']]));
  169.                         }
  170.                         if (isset($row[$headerByKey['note']])) {
  171.                             if (StringUtil::isNotBlank($row[$headerByKey['note']])) {
  172.                                 $Product->setNote(StringUtil::trimAll($row[$headerByKey['note']]));
  173.                             } else {
  174.                                 $Product->setNote(null);
  175.                             }
  176.                         }
  177.                         if (isset($row[$headerByKey['description_list']])) {
  178.                             if (StringUtil::isNotBlank($row[$headerByKey['description_list']])) {
  179.                                 $Product->setDescriptionList(StringUtil::trimAll($row[$headerByKey['description_list']]));
  180.                             } else {
  181.                                 $Product->setDescriptionList(null);
  182.                             }
  183.                         }
  184.                         if (isset($row[$headerByKey['description_detail']])) {
  185.                             if (StringUtil::isNotBlank($row[$headerByKey['description_detail']])) {
  186.                                 if (mb_strlen($row[$headerByKey['description_detail']]) > $this->eccubeConfig['eccube_ltext_len']) {
  187.                                     $message trans('admin.common.csv_invalid_description_detail_upper_limit', [
  188.                                         '%line%' => $line,
  189.                                         '%name%' => $headerByKey['description_detail'],
  190.                                         '%max%' => $this->eccubeConfig['eccube_ltext_len'],
  191.                                     ]);
  192.                                     $this->addErrors($message);
  193.                                     return $this->renderWithError($form$headers);
  194.                                 } else {
  195.                                     $Product->setDescriptionDetail(StringUtil::trimAll($row[$headerByKey['description_detail']]));
  196.                                 }
  197.                             } else {
  198.                                 $Product->setDescriptionDetail(null);
  199.                             }
  200.                         }
  201.                         // ▼追加項目ここから
  202.                         if (isset($row[$headerByKey['brand']])) {
  203.                             if (StringUtil::isNotBlank($row[$headerByKey['brand']])) {
  204.                                 $Product->setBrand(StringUtil::trimAll($row[$headerByKey['brand']]));
  205.                             } else {
  206.                                 $Product->setBrand(null);
  207.                             }
  208.                         }
  209.                         if (isset($row[$headerByKey['number']])) {
  210.                             if (StringUtil::isNotBlank($row[$headerByKey['number']])) {
  211.                                 $Product->setNumber(StringUtil::trimAll($row[$headerByKey['number']]));
  212.                             } else {
  213.                                 $Product->setNumber(null);
  214.                             }
  215.                         }
  216.                         if (isset($row[$headerByKey['size']])) {
  217.                             if (StringUtil::isNotBlank($row[$headerByKey['size']])) {
  218.                                 $Product->setSize(StringUtil::trimAll($row[$headerByKey['size']]));
  219.                             } else {
  220.                                 $Product->setSize(null);
  221.                             }
  222.                         }
  223.                         if (isset($row[$headerByKey['material']])) {
  224.                             if (StringUtil::isNotBlank($row[$headerByKey['material']])) {
  225.                                 $Product->setMaterial(StringUtil::trimAll($row[$headerByKey['material']]));
  226.                             } else {
  227.                                 $Product->setMaterial(null);
  228.                             }
  229.                         }
  230.                         if (isset($row[$headerByKey['notification_email']])) {
  231.                             if (StringUtil::isNotBlank($row[$headerByKey['notification_email']])) {
  232.                                 $Product->setNotificationEmail(StringUtil::trimAll($row[$headerByKey['notification_email']]));
  233.                             } else {
  234.                                 $Product->setNotificationEmail(null);
  235.                             }
  236.                         }
  237.                         // ▲追加項目ここまで
  238.                         if (isset($row[$headerByKey['search_word']])) {
  239.                             if (StringUtil::isNotBlank($row[$headerByKey['search_word']])) {
  240.                                 $Product->setSearchWord(StringUtil::trimAll($row[$headerByKey['search_word']]));
  241.                             } else {
  242.                                 $Product->setSearchWord(null);
  243.                             }
  244.                         }
  245.                         if (isset($row[$headerByKey['free_area']])) {
  246.                             if (StringUtil::isNotBlank($row[$headerByKey['free_area']])) {
  247.                                 $Product->setFreeArea(StringUtil::trimAll($row[$headerByKey['free_area']]));
  248.                             } else {
  249.                                 $Product->setFreeArea(null);
  250.                             }
  251.                         }
  252.                         // 商品画像登録
  253.                         $this->createProductImage($row$Product$data$headerByKey);
  254.                         $this->entityManager->flush();
  255.                         // 商品カテゴリ登録
  256.                         $this->createProductCategory($row$Product$data$headerByKey);
  257.                         // タグ登録
  258.                         $this->createProductTag($row$Product$data$headerByKey);
  259.                         // 商品規格が存在しなければ新規登録
  260.                         /** @var ProductClass[] $ProductClasses */
  261.                         $ProductClasses $Product->getProductClasses();
  262.                         if ($ProductClasses->count() < 1) {
  263.                             // 規格分類1(ID)がセットされていると規格なし商品、規格あり商品を作成
  264.                             $ProductClassOrg $this->createProductClass($row$Product$data$headerByKey);
  265.                             if ($this->BaseInfo->isOptionProductDeliveryFee()) {
  266.                                 if (isset($row[$headerByKey['delivery_fee']]) && StringUtil::isNotBlank($row[$headerByKey['delivery_fee']])) {
  267.                                     $deliveryFee str_replace(','''$row[$headerByKey['delivery_fee']]);
  268.                                     $errors $this->validator->validate($deliveryFee, new GreaterThanOrEqual(['value' => 0]));
  269.                                     if ($errors->count() === 0) {
  270.                                         $ProductClassOrg->setDeliveryFee($deliveryFee);
  271.                                     } else {
  272.                                         $message trans('admin.common.csv_invalid_greater_than_zero', ['%line%' => $line'%name%' => $headerByKey['delivery_fee']]);
  273.                                         $this->addErrors($message);
  274.                                     }
  275.                                 }
  276.                             }
  277.                             // 商品別税率機能が有効の場合に税率を更新
  278.                             if ($this->BaseInfo->isOptionProductTaxRule()) {
  279.                                 if (isset($row[$headerByKey['tax_rate']]) && StringUtil::isNotBlank($row[$headerByKey['tax_rate']])) {
  280.                                     $taxRate $row[$headerByKey['tax_rate']];
  281.                                     $errors $this->validator->validate($taxRate, new GreaterThanOrEqual(['value' => 0]));
  282.                                     if ($errors->count() === 0) {
  283.                                         if ($ProductClassOrg->getTaxRule()) {
  284.                                             // 商品別税率の設定があれば税率を更新
  285.                                             $ProductClassOrg->getTaxRule()->setTaxRate($taxRate);
  286.                                         } else {
  287.                                             // 商品別税率の設定がなければ新規作成
  288.                                             $TaxRule $this->taxRuleRepository->newTaxRule();
  289.                                             $TaxRule->setTaxRate($taxRate);
  290.                                             $TaxRule->setApplyDate(new \DateTime());
  291.                                             $TaxRule->setProduct($Product);
  292.                                             $TaxRule->setProductClass($ProductClassOrg);
  293.                                             $ProductClassOrg->setTaxRule($TaxRule);
  294.                                         }
  295.                                     } else {
  296.                                         $message trans('admin.common.csv_invalid_greater_than_zero', ['%line%' => $line'%name%' => $headerByKey['tax_rate']]);
  297.                                         $this->addErrors($message);
  298.                                     }
  299.                                 } else {
  300.                                     // 税率の入力がなければ税率の設定を削除
  301.                                     if ($ProductClassOrg->getTaxRule()) {
  302.                                         $this->taxRuleRepository->delete($ProductClassOrg->getTaxRule());
  303.                                         $ProductClassOrg->setTaxRule(null);
  304.                                     }
  305.                                 }
  306.                             }
  307.                             if (isset($row[$headerByKey['class_category1']]) && StringUtil::isNotBlank($row[$headerByKey['class_category1']])) {
  308.                                 if (isset($row[$headerByKey['class_category2']]) && $row[$headerByKey['class_category1']] == $row[$headerByKey['class_category2']]) {
  309.                                     $message trans('admin.common.csv_invalid_not_same', [
  310.                                         '%line%' => $line,
  311.                                         '%name1%' => $headerByKey['class_category1'],
  312.                                         '%name2%' => $headerByKey['class_category2'],
  313.                                     ]);
  314.                                     $this->addErrors($message);
  315.                                 } else {
  316.                                     // 商品規格あり
  317.                                     // 規格分類あり商品を作成
  318.                                     $ProductClass = clone $ProductClassOrg;
  319.                                     $ProductStock = clone $ProductClassOrg->getProductStock();
  320.                                     // 規格分類1、規格分類2がnullであるデータを非表示
  321.                                     $ProductClassOrg->setVisible(false);
  322.                                     // 規格分類1、2をそれぞれセットし作成
  323.                                     $ClassCategory1 null;
  324.                                     if (preg_match('/^\d+$/'$row[$headerByKey['class_category1']])) {
  325.                                         $ClassCategory1 $this->classCategoryRepository->find($row[$headerByKey['class_category1']]);
  326.                                         if (!$ClassCategory1) {
  327.                                             $message trans('admin.common.csv_invalid_not_found', ['%line%' => $line'%name%' => $headerByKey['class_category1']]);
  328.                                             $this->addErrors($message);
  329.                                         } else {
  330.                                             $ProductClass->setClassCategory1($ClassCategory1);
  331.                                         }
  332.                                     } else {
  333.                                         $message trans('admin.common.csv_invalid_not_found', ['%line%' => $line'%name%' => $headerByKey['class_category1']]);
  334.                                         $this->addErrors($message);
  335.                                     }
  336.                                     if (isset($row[$headerByKey['class_category2']]) && StringUtil::isNotBlank($row[$headerByKey['class_category2']])) {
  337.                                         if (preg_match('/^\d+$/'$row[$headerByKey['class_category2']])) {
  338.                                             $ClassCategory2 $this->classCategoryRepository->find($row[$headerByKey['class_category2']]);
  339.                                             if (!$ClassCategory2) {
  340.                                                 $message trans('admin.common.csv_invalid_not_found', ['%line%' => $line'%name%' => $headerByKey['class_category2']]);
  341.                                                 $this->addErrors($message);
  342.                                             } else {
  343.                                                 if ($ClassCategory1 &&
  344.                                                     ($ClassCategory1->getClassName()->getId() == $ClassCategory2->getClassName()->getId())
  345.                                                 ) {
  346.                                                     $message trans('admin.common.csv_invalid_not_same', ['%line%' => $line'%name1%' => $headerByKey['class_category1'], '%name2%' => $headerByKey['class_category2']]);
  347.                                                     $this->addErrors($message);
  348.                                                 } else {
  349.                                                     $ProductClass->setClassCategory2($ClassCategory2);
  350.                                                 }
  351.                                             }
  352.                                         } else {
  353.                                             $message trans('admin.common.csv_invalid_not_found', ['%line%' => $line'%name%' => $headerByKey['class_category2']]);
  354.                                             $this->addErrors($message);
  355.                                         }
  356.                                     }
  357.                                     $ProductClass->setProductStock($ProductStock);
  358.                                     $ProductStock->setProductClass($ProductClass);
  359.                                     $this->entityManager->persist($ProductClass);
  360.                                     $this->entityManager->persist($ProductStock);
  361.                                 }
  362.                             } else {
  363.                                 if (isset($row[$headerByKey['class_category2']]) && StringUtil::isNotBlank($row[$headerByKey['class_category2']])) {
  364.                                     $message trans('admin.common.csv_invalid_not_found', ['%line%' => $line'%name%' => $headerByKey['class_category2']]);
  365.                                     $this->addErrors($message);
  366.                                 }
  367.                             }
  368.                         } else {
  369.                             // 商品規格の更新
  370.                             $flag false;
  371.                             $classCategoryId1 StringUtil::isBlank($row[$headerByKey['class_category1']]) ? null $row[$headerByKey['class_category1']];
  372.                             $classCategoryId2 StringUtil::isBlank($row[$headerByKey['class_category2']]) ? null $row[$headerByKey['class_category2']];
  373.                             foreach ($ProductClasses as $pc) {
  374.                                 $classCategory1 is_null($pc->getClassCategory1()) ? null $pc->getClassCategory1()->getId();
  375.                                 $classCategory2 is_null($pc->getClassCategory2()) ? null $pc->getClassCategory2()->getId();
  376.                                 // 登録されている商品規格を更新
  377.                                 if ($classCategory1 == $classCategoryId1 &&
  378.                                     $classCategory2 == $classCategoryId2
  379.                                 ) {
  380.                                     $this->updateProductClass($row$Product$pc$data$headerByKey);
  381.                                     if ($this->BaseInfo->isOptionProductDeliveryFee()) {
  382.                                         if (isset($row[$headerByKey['delivery_fee']]) && StringUtil::isNotBlank($row[$headerByKey['delivery_fee']])) {
  383.                                             $deliveryFee str_replace(','''$row[$headerByKey['delivery_fee']]);
  384.                                             $errors $this->validator->validate($deliveryFee, new GreaterThanOrEqual(['value' => 0]));
  385.                                             if ($errors->count() === 0) {
  386.                                                 $pc->setDeliveryFee($deliveryFee);
  387.                                             } else {
  388.                                                 $message trans('admin.common.csv_invalid_greater_than_zero', ['%line%' => $line'%name%' => $headerByKey['delivery_fee']]);
  389.                                                 $this->addErrors($message);
  390.                                             }
  391.                                         }
  392.                                     }
  393.                                     // 商品別税率機能が有効の場合に税率を更新
  394.                                     if ($this->BaseInfo->isOptionProductTaxRule()) {
  395.                                         if (isset($row[$headerByKey['tax_rate']]) && StringUtil::isNotBlank($row[$headerByKey['tax_rate']])) {
  396.                                             $taxRate $row[$headerByKey['tax_rate']];
  397.                                             $errors $this->validator->validate($taxRate, new GreaterThanOrEqual(['value' => 0]));
  398.                                             if ($errors->count() === 0) {
  399.                                                 if ($pc->getTaxRule()) {
  400.                                                     // 商品別税率の設定があれば税率を更新
  401.                                                     $pc->getTaxRule()->setTaxRate($taxRate);
  402.                                                 } else {
  403.                                                     // 商品別税率の設定がなければ新規作成
  404.                                                     $TaxRule $this->taxRuleRepository->newTaxRule();
  405.                                                     $TaxRule->setTaxRate($taxRate);
  406.                                                     $TaxRule->setApplyDate(new \DateTime());
  407.                                                     $TaxRule->setProduct($Product);
  408.                                                     $TaxRule->setProductClass($pc);
  409.                                                     $pc->setTaxRule($TaxRule);
  410.                                                 }
  411.                                             } else {
  412.                                                 $message trans('admin.common.csv_invalid_greater_than_zero', ['%line%' => $line'%name%' => $headerByKey['tax_rate']]);
  413.                                                 $this->addErrors($message);
  414.                                             }
  415.                                         } else {
  416.                                             // 税率の入力がなければ税率の設定を削除
  417.                                             if ($pc->getTaxRule()) {
  418.                                                 $this->taxRuleRepository->delete($pc->getTaxRule());
  419.                                                 $pc->setTaxRule(null);
  420.                                             }
  421.                                         }
  422.                                     }
  423.                                     $flag true;
  424.                                     break;
  425.                                 }
  426.                             }
  427.                             // 商品規格を登録
  428.                             if (!$flag) {
  429.                                 $pc $ProductClasses[0];
  430.                                 if ($pc->getClassCategory1() == null &&
  431.                                     $pc->getClassCategory2() == null
  432.                                 ) {
  433.                                     // 規格分類1、規格分類2がnullであるデータを非表示
  434.                                     $pc->setVisible(false);
  435.                                 }
  436.                                 if (isset($row[$headerByKey['class_category1']]) && isset($row[$headerByKey['class_category2']])
  437.                                     && $row[$headerByKey['class_category1']] == $row[$headerByKey['class_category2']]) {
  438.                                     $message trans('admin.common.csv_invalid_not_same', [
  439.                                         '%line%' => $line,
  440.                                         '%name1%' => $headerByKey['class_category1'],
  441.                                         '%name2%' => $headerByKey['class_category2'],
  442.                                     ]);
  443.                                     $this->addErrors($message);
  444.                                 } else {
  445.                                     // 必ず規格分類1がセットされている
  446.                                     // 規格分類1、2をそれぞれセットし作成
  447.                                     $ClassCategory1 null;
  448.                                     if (preg_match('/^\d+$/'$classCategoryId1)) {
  449.                                         $ClassCategory1 $this->classCategoryRepository->find($classCategoryId1);
  450.                                         if (!$ClassCategory1) {
  451.                                             $message trans('admin.common.csv_invalid_not_found', ['%line%' => $line'%name%' => $headerByKey['class_category1']]);
  452.                                             $this->addErrors($message);
  453.                                         }
  454.                                     } else {
  455.                                         $message trans('admin.common.csv_invalid_not_found', ['%line%' => $line'%name%' => $headerByKey['class_category1']]);
  456.                                         $this->addErrors($message);
  457.                                     }
  458.                                     $ClassCategory2 null;
  459.                                     if (isset($row[$headerByKey['class_category2']]) && StringUtil::isNotBlank($row[$headerByKey['class_category2']])) {
  460.                                         if ($pc->getClassCategory1() != null && $pc->getClassCategory2() == null) {
  461.                                             $message trans('admin.common.csv_invalid_can_not', ['%line%' => $line'%name%' => $headerByKey['class_category2']]);
  462.                                             $this->addErrors($message);
  463.                                         } else {
  464.                                             if (preg_match('/^\d+$/'$classCategoryId2)) {
  465.                                                 $ClassCategory2 $this->classCategoryRepository->find($classCategoryId2);
  466.                                                 if (!$ClassCategory2) {
  467.                                                     $message trans('admin.common.csv_invalid_not_found', ['%line%' => $line'%name%' => $headerByKey['class_category2']]);
  468.                                                     $this->addErrors($message);
  469.                                                 } else {
  470.                                                     if ($ClassCategory1 &&
  471.                                                         ($ClassCategory1->getClassName()->getId() == $ClassCategory2->getClassName()->getId())
  472.                                                     ) {
  473.                                                         $message trans('admin.common.csv_invalid_not_same', [
  474.                                                             '%line%' => $line,
  475.                                                             '%name1%' => $headerByKey['class_category1'],
  476.                                                             '%name2%' => $headerByKey['class_category2'],
  477.                                                         ]);
  478.                                                         $this->addErrors($message);
  479.                                                     }
  480.                                                 }
  481.                                             } else {
  482.                                                 $message trans('admin.common.csv_invalid_not_found', ['%line%' => $line'%name%' => $headerByKey['class_category2']]);
  483.                                                 $this->addErrors($message);
  484.                                             }
  485.                                         }
  486.                                     } else {
  487.                                         if ($pc->getClassCategory1() != null && $pc->getClassCategory2() != null) {
  488.                                             $message trans('admin.common.csv_invalid_required', ['%line%' => $line'%name%' => $headerByKey['class_category2']]);
  489.                                             $this->addErrors($message);
  490.                                         }
  491.                                     }
  492.                                     $ProductClass $this->createProductClass($row$Product$data$headerByKey$ClassCategory1$ClassCategory2);
  493.                                     if ($this->BaseInfo->isOptionProductDeliveryFee()) {
  494.                                         if (isset($row[$headerByKey['delivery_fee']]) && StringUtil::isNotBlank($row[$headerByKey['delivery_fee']])) {
  495.                                             $deliveryFee str_replace(','''$row[$headerByKey['delivery_fee']]);
  496.                                             $errors $this->validator->validate($deliveryFee, new GreaterThanOrEqual(['value' => 0]));
  497.                                             if ($errors->count() === 0) {
  498.                                                 $ProductClass->setDeliveryFee($deliveryFee);
  499.                                             } else {
  500.                                                 $message trans('admin.common.csv_invalid_greater_than_zero', ['%line%' => $line'%name%' => $headerByKey['delivery_fee']]);
  501.                                                 $this->addErrors($message);
  502.                                             }
  503.                                         }
  504.                                     }
  505.                                     // 商品別税率機能が有効の場合に税率を更新
  506.                                     if ($this->BaseInfo->isOptionProductTaxRule()) {
  507.                                         if (isset($row[$headerByKey['tax_rate']]) && StringUtil::isNotBlank($row[$headerByKey['tax_rate']])) {
  508.                                             $taxRate $row[$headerByKey['tax_rate']];
  509.                                             $errors $this->validator->validate($taxRate, new GreaterThanOrEqual(['value' => 0]));
  510.                                             if ($errors->count() === 0) {
  511.                                                 $TaxRule $this->taxRuleRepository->newTaxRule();
  512.                                                 $TaxRule->setTaxRate($taxRate);
  513.                                                 $TaxRule->setApplyDate(new \DateTime());
  514.                                                 $TaxRule->setProduct($Product);
  515.                                                 $TaxRule->setProductClass($ProductClass);
  516.                                                 $ProductClass->setTaxRule($TaxRule);
  517.                                             } else {
  518.                                                 $message trans('admin.common.csv_invalid_greater_than_zero', ['%line%' => $line'%name%' => $headerByKey['tax_rate']]);
  519.                                                 $this->addErrors($message);
  520.                                             }
  521.                                         }
  522.                                     }
  523.                                     $Product->addProductClass($ProductClass);
  524.                                 }
  525.                             }
  526.                         }
  527.                         if ($this->hasErrors()) {
  528.                             return $this->renderWithError($form$headers);
  529.                         }
  530.                         $this->entityManager->persist($Product);
  531.                     }
  532.                     $this->entityManager->flush();
  533.                     $this->entityManager->getConnection()->commit();
  534.                     // 画像ファイルの削除(commit後に削除させる)
  535.                     foreach ($deleteImages as $images) {
  536.                         /** @var ProductImage $image */
  537.                         foreach ($images as $image) {
  538.                             if ($this->productImageRepository->findOneBy(['file_name' => $image->getFileName()])) {
  539.                                 continue;
  540.                             }
  541.                             try {
  542.                                 $fs = new Filesystem();
  543.                                 $fs->remove($this->eccubeConfig['eccube_save_image_dir'].'/'.$image);
  544.                             } catch (\Exception $e) {
  545.                                 // エラーが発生しても無視する
  546.                             }
  547.                         }
  548.                     }
  549.                     log_info('商品CSV登録完了');
  550.                     if (!$this->isSplitCsv) {
  551.                         $message 'admin.common.csv_upload_complete';
  552.                         $this->session->getFlashBag()->add('eccube.admin.success'$message);
  553.                     }
  554.                     $cacheUtil->clearDoctrineCache();
  555.                 }
  556.             }
  557.         }
  558.         return $this->renderWithError($form$headers);
  559.     }
  560.     /**
  561.      * 商品登録CSVヘッダー定義
  562.      *
  563.      * @return array
  564.      */
  565.     protected function getProductCsvHeader()
  566.     {
  567.         return [
  568.             trans('admin.product.product_csv.product_id_col') => [
  569.                 'id' => 'id',
  570.                 'description' => 'admin.product.product_csv.product_id_description',
  571.                 'required' => false,
  572.             ],
  573.             trans('admin.product.product_csv.display_status_col') => [
  574.                 'id' => 'status',
  575.                 'description' => 'admin.product.product_csv.display_status_description',
  576.                 'required' => true,
  577.             ],
  578.             trans('admin.product.product_csv.product_name_col') => [
  579.                 'id' => 'name',
  580.                 'description' => 'admin.product.product_csv.product_name_description',
  581.                 'required' => true,
  582.             ],
  583.             trans('admin.product.product_csv.shop_memo_col') => [
  584.                 'id' => 'note',
  585.                 'description' => 'admin.product.product_csv.shop_memo_description',
  586.                 'required' => false,
  587.             ],
  588.             trans('admin.product.product_csv.description_list_col') => [
  589.                 'id' => 'description_list',
  590.                 'description' => 'admin.product.product_csv.description_list_description',
  591.                 'required' => false,
  592.             ],
  593.             trans('admin.product.product_csv.description_detail_col') => [
  594.                 'id' => 'description_detail',
  595.                 'description' => 'admin.product.product_csv.description_detail_description',
  596.                 'required' => false,
  597.             ],
  598.             trans('admin.product.product_csv.brand_col') => [
  599.                 'id' => 'brand',
  600.                 'description' => 'admin.product.product_csv.brand_description',
  601.                 'required' => false,
  602.             ],
  603.             trans('admin.product.product_csv.number_col') => [
  604.                 'id' => 'number',
  605.                 'description' => 'admin.product.product_csv.number_description',
  606.                 'required' => false,
  607.             ],
  608.             trans('admin.product.product_csv.size_col') => [
  609.                 'id' => 'size',
  610.                 'description' => 'admin.product.product_csv.size_description',
  611.                 'required' => false,
  612.             ],
  613.             trans('admin.product.product_csv.material_col') => [
  614.                 'id' => 'material',
  615.                 'description' => 'admin.product.product_csv.material_description',
  616.                 'required' => false,
  617.             ],
  618.             trans('admin.product.product_csv.notification_email_col') => [
  619.                 'id' => 'notification_email',
  620.                 'description' => 'admin.product.product_csv.notification_email_description',
  621.                 'required' => false,
  622.             ],
  623.             trans('admin.product.product_csv.keyword_col') => [
  624.                 'id' => 'search_word',
  625.                 'description' => 'admin.product.product_csv.keyword_description',
  626.                 'required' => false,
  627.             ],
  628.             trans('admin.product.product_csv.free_area_col') => [
  629.                 'id' => 'free_area',
  630.                 'description' => 'admin.product.product_csv.free_area_description',
  631.                 'required' => false,
  632.             ],
  633.             trans('admin.product.product_csv.delete_flag_col') => [
  634.                 'id' => 'product_del_flg',
  635.                 'description' => 'admin.product.product_csv.delete_flag_description',
  636.                 'required' => false,
  637.             ],
  638.             trans('admin.product.product_csv.product_image_col') => [
  639.                 'id' => 'product_image',
  640.                 'description' => 'admin.product.product_csv.product_image_description',
  641.                 'required' => false,
  642.             ],
  643.             trans('admin.product.product_csv.category_col') => [
  644.                 'id' => 'product_category',
  645.                 'description' => 'admin.product.product_csv.category_description',
  646.                 'required' => false,
  647.             ],
  648.             trans('admin.product.product_csv.tag_col') => [
  649.                 'id' => 'product_tag',
  650.                 'description' => 'admin.product.product_csv.tag_description',
  651.                 'required' => false,
  652.             ],
  653.             trans('admin.product.product_csv.sale_type_col') => [
  654.                 'id' => 'sale_type',
  655.                 'description' => 'admin.product.product_csv.sale_type_description',
  656.                 'required' => true,
  657.             ],
  658.             trans('admin.product.product_csv.class_category1_col') => [
  659.                 'id' => 'class_category1',
  660.                 'description' => 'admin.product.product_csv.class_category1_description',
  661.                 'required' => false,
  662.             ],
  663.             trans('admin.product.product_csv.class_category2_col') => [
  664.                 'id' => 'class_category2',
  665.                 'description' => 'admin.product.product_csv.class_category2_description',
  666.                 'required' => false,
  667.             ],
  668.             trans('admin.product.product_csv.delivery_duration_col') => [
  669.                 'id' => 'delivery_date',
  670.                 'description' => 'admin.product.product_csv.delivery_duration_description',
  671.                 'required' => false,
  672.             ],
  673.             trans('admin.product.product_csv.product_code_col') => [
  674.                 'id' => 'product_code',
  675.                 'description' => 'admin.product.product_csv.product_code_description',
  676.                 'required' => false,
  677.             ],
  678.             trans('admin.product.product_csv.stock_col') => [
  679.                 'id' => 'stock',
  680.                 'description' => 'admin.product.product_csv.stock_description',
  681.                 'required' => false,
  682.             ],
  683.             trans('admin.product.product_csv.stock_unlimited_col') => [
  684.                 'id' => 'stock_unlimited',
  685.                 'description' => 'admin.product.product_csv.stock_unlimited_description',
  686.                 'required' => false,
  687.             ],
  688.             trans('admin.product.product_csv.sale_limit_col') => [
  689.                 'id' => 'sale_limit',
  690.                 'description' => 'admin.product.product_csv.sale_limit_description',
  691.                 'required' => false,
  692.             ],
  693.             trans('admin.product.product_csv.normal_price_col') => [
  694.                 'id' => 'price01',
  695.                 'description' => 'admin.product.product_csv.normal_price_description',
  696.                 'required' => false,
  697.             ],
  698.             trans('admin.product.product_csv.sale_price_col') => [
  699.                 'id' => 'price02',
  700.                 'description' => 'admin.product.product_csv.sale_price_description',
  701.                 'required' => true,
  702.             ],
  703.             trans('admin.product.product_csv.delivery_fee_col') => [
  704.                 'id' => 'delivery_fee',
  705.                 'description' => 'admin.product.product_csv.delivery_fee_description',
  706.                 'required' => false,
  707.             ],
  708.             trans('admin.product.product_csv.tax_rate_col') => [
  709.                 'id' => 'tax_rate',
  710.                 'description' => 'admin.product.product_csv.tax_rate_description',
  711.                 'required' => false,
  712.             ],
  713.             trans('admin.product.product_csv.product_class_visible_flag_col') => [
  714.                 'id' => 'product_class_visible_flg',
  715.                 'description' => 'admin.product.product_csv.product_class_visible_flag_description',
  716.                 'required' => false,
  717.             ],
  718.         ];
  719.     }
  720. }