app/Customize/Controller/Admin/Product/CsvImportController.php line 56

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