src/Eccube/Controller/Admin/Product/CsvImportController.php line 1383

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