src/Controller/Admin/FriendsOfSylius/ImportExport/ImportDataController.php line 41

Open in your IDE?
  1. <?php
  2. declare(strict_types=1);
  3. namespace App\Controller\Admin\FriendsOfSylius\ImportExport;
  4. use App\Entity\Import\SavedImport;
  5. use App\Form\Type\ImportExport\ConfirmedImportType;
  6. use App\Form\Type\ImportExport\ImportType;
  7. use Doctrine\ORM\EntityManagerInterface;
  8. use FriendsOfSylius\SyliusImportExportPlugin\Exception\ImporterException;
  9. use FriendsOfSylius\SyliusImportExportPlugin\Importer\ImporterInterface;
  10. use FriendsOfSylius\SyliusImportExportPlugin\Importer\ImporterRegistry;
  11. use FriendsOfSylius\SyliusImportExportPlugin\Importer\ImporterResult;
  12. use Knp\Component\Pager\PaginatorInterface;
  13. use Port\Reader\ReaderFactory;
  14. use Sylius\Component\Registry\ServiceRegistryInterface;
  15. use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
  16. use Symfony\Component\Form\FormFactoryInterface;
  17. use Symfony\Component\Form\FormInterface;
  18. use Symfony\Component\HttpFoundation\File\UploadedFile;
  19. use Symfony\Component\HttpFoundation\RedirectResponse;
  20. use Symfony\Component\HttpFoundation\Request;
  21. use Symfony\Component\HttpFoundation\Response;
  22. use Symfony\Component\HttpFoundation\Session\Flash\FlashBagInterface;
  23. final class ImportDataController extends AbstractController
  24. {
  25.     public function __construct(
  26.         private ServiceRegistryInterface $registry,
  27.         private FlashBagInterface $flashBag,
  28.         private FormFactoryInterface $formFactory,
  29.         private \Twig_Environment $twig,
  30.         private ReaderFactory $readerFactory,
  31.         private PaginatorInterface $paginator,
  32.         private EntityManagerInterface $entityManager,
  33.     ) {
  34.     }
  35.     // partial view for upload import form
  36.     public function importFormAction(Request $request): Response
  37.     {
  38.         $importer $request->attributes->get('resource');
  39.         $referer $request->attributes->get('referer');
  40.         $form $this->getForm($importer);
  41.         if ($importer === 'product') {
  42.             // overrided product processor
  43.             $importer 'app_product_base';
  44.         } elseif ($importer === 'taxonomy') {
  45.             $importer 'app_product_taxon';
  46.         }
  47.         // get importer service to get headers keys
  48.         $name ImporterRegistry::buildServiceName($importer'csv');
  49.         /** @var ImporterInterface $service */
  50.         $service $this->registry->get($name);
  51.         $headersKeys $service->getHeaders();
  52.         $content $this->twig->render(
  53.             '@FOSSyliusImportExportPlugin/Crud/import_form.html.twig',
  54.             ['form' => $form->createView(), 'resource' => $importer'headersKeys' => $headersKeys'referer' => $referer]
  55.         );
  56.         return new Response($content);
  57.     }
  58.     // on submit upload import form
  59.     public function importAction(Request $request): Response
  60.     {
  61.         $importer $request->attributes->get('resource');
  62.         $form $this->getForm($importer);
  63.         $form->handleRequest($request);
  64.         if ($importer === 'product') {
  65.             // overrided product processor
  66.             $importer 'app_product_base';
  67.         }
  68.         $referer $request->headers->get('referer');
  69.         // import form
  70.         if ($form->isSubmitted() && $form->isValid()) {
  71.             $preview $this->getDataPreviewAction($form);
  72.             $previewJson json_encode($preview);
  73.             if (strlen($previewJson) >= 2000000000) {
  74.                 $this->flashBag->add('error'"l'import est trop important, veuillez le fractionner puis recommencer");
  75.                 return new RedirectResponse($referer);
  76.             }
  77.             $import = new SavedImport();
  78.             $import->setType($importer);
  79.             $import->setJsonData($previewJson);
  80.             $this->entityManager->persist($import);
  81.             $this->entityManager->flush();
  82.             return new RedirectResponse($this->generateUrl('app_admin_import_preview', [
  83.                 'keys' => $form->getData()['headerKeys'],
  84.                 'referer' => $referer,
  85.                 'importId' => $import->getId(),
  86.                 'format' => $form->getData()['format'],
  87.                 'importer' => $importer, ]));
  88.         }
  89.         return new RedirectResponse($referer);
  90.     }
  91.     // view preview with confirmed form
  92.     public function previewAction(Request $request)
  93.     {
  94.         $importId $request->query->get('importId');
  95.         $keysJson $request->query->get('keys');
  96.         $referer $request->query->get('referer');
  97.         $format $request->query->get('format');
  98.         $importer $request->query->get('importer');
  99.         if (!$importId || !$keysJson || !$referer || !$format || !$importer) {
  100.             throw new ImporterException('Data not found');
  101.         }
  102.         $import $this->container->get('doctrine')->getRepository(SavedImport::class)->find($importId);
  103.         if (!$import) {
  104.             throw new ImporterException('Data not found');
  105.         }
  106.         $preview json_decode($import->getJsonData(), true);
  107.         $result $this->paginator->paginate(
  108.             $preview[1], // datas
  109.             $request->query->getInt('page'1), // current page, 1 if we can't know
  110.             30 // Number of result per page
  111.         );
  112.         // define default data that can be filled during preview
  113.         $keys json_decode($keysJsontrue);
  114.         $defaultData = [];
  115.         foreach ($keys['optional'] as $optionalKey) {
  116.             if (!in_array($optionalKey$keys['mandatory']) && !in_array($optionalKey$preview[0])) {
  117.                 $defaultData[] = $optionalKey;
  118.             }
  119.         }
  120.         // confirmed form with action to confirmImportDataAction
  121.         $confirmedForm $this->formFactory->create(ConfirmedImportType::class, null, [
  122.             'dataToImport' => $preview[1],
  123.             'format' => $format,
  124.             'referer' => $referer,
  125.             'importer' => $importer,
  126.             'defaultData' => $defaultData, ]);
  127.         $confirmedForm->handleRequest($request);
  128.         $content $this->twig->render(
  129.             '@SyliusAdmin/Import/preview.html.twig',
  130.             [
  131.                 'dataHeader' => $preview[0], 'result' => $result,
  132.                 'resultPerPage' => $result->getItemNumberPerPage(),
  133.                 'count' => $result->getTotalItemCount(),
  134.                 'referer' => $referer,
  135.                 'form' => $confirmedForm->createView(), ]
  136.         );
  137.         return new Response($content);
  138.     }
  139.     // after submit confirm form
  140.     public function confirmImportDataAction(Request $request)
  141.     {
  142.         $referer $request->request->get('app_confirm_import')['referer'];
  143.         $serializedData $request->request->get('app_confirm_import')['data'];
  144.         $importer $request->request->get('app_confirm_import')['importer'];
  145.         $format $request->request->get('app_confirm_import')['format'];
  146.         if (!$referer || !$serializedData || !$importer || !$format) {
  147.             throw new ImporterException('Data not found');
  148.         }
  149.         $data json_decode($serializedDatatrue);
  150.         // find filled default datas
  151.         $defaultDatas = [];
  152.         foreach ($request->request->get('app_confirm_import') as $key => $value) {
  153.             if (substr($key013) === 'default_data_' && $value && $value !== '') {
  154.                 $defaultDatas[str_replace('default_data_'''$key)] = $value;
  155.             }
  156.         }
  157.         try {
  158.             $this->importDataFromArray($importer$referer$data$format$defaultDatas);
  159.         } catch (\Throwable $exception) {
  160.             $this->flashBag->add('error'$exception->getMessage());
  161.         }
  162.         return new RedirectResponse($referer);
  163.     }
  164.     // get data form preview
  165.     private function getDataPreviewAction($form): array
  166.     {
  167.         /** @var UploadedFile|null $file */
  168.         $file $form->get('import-data')->getData();
  169.         if (null === $file) {
  170.             throw new ImporterException('No file selected');
  171.         }
  172.         $path $file->getRealPath();
  173.         if (false === $path) {
  174.             throw new ImporterException(sprintf('File %s could not be loaded'$file->getClientOriginalName()));
  175.         }
  176.         $reader $this->readerFactory->getReader(new \SplFileObject($path));
  177.         $dataPreview $header = [];
  178.         foreach ($reader as $i => $row) {
  179.             if (!$row) {
  180.                 continue;
  181.             }
  182.             if ($i === 1) {
  183.                 $header array_keys($row);
  184.             }
  185.             $dataPreview[$i] = $row;
  186.         }
  187.         return [$header$dataPreview];
  188.     }
  189.     // get upload form
  190.     private function getForm(string $importerType): FormInterface
  191.     {
  192.         return $this->formFactory->create(ImportType::class, null, ['importer_type' => $importerType]);
  193.     }
  194.     // import data from array from preview
  195.     private function importDataFromArray(string $importerstring $referer, array $datastring $format, array $defaultData): void
  196.     {
  197.         $name ImporterRegistry::buildServiceName($importer$format);
  198.         if (!$this->registry->has($name)) {
  199.             $message sprintf("No importer found of type '%s' for format '%s'"$importer$format);
  200.             throw new ImporterException($message);
  201.         }
  202.         /** @var ImporterInterface $service */
  203.         $service $this->registry->get($name);
  204.         /** @var ImporterResult $result */
  205.         $result $service->importFromArray($data$defaultData);
  206.         $message sprintf(
  207.             'Import de %s (Temps en ms: %s, %s lignes importées, %s lignes passées, %s lignes en erreur)',
  208.             $name,
  209.             $result->getDuration(),
  210.             count($result->getSuccessRows()),
  211.             count($result->getSkippedRows()),
  212.             count($result->getFailedRows())
  213.         );
  214.         $this->flashBag->add('success'$message);
  215.         if ($result->getMessage() !== null) {
  216.             throw new ImporterException($result->getMessage());
  217.         }
  218.     }
  219.     // import data from form (without preview)
  220.     private function importData(string $importerFormInterface $form): void
  221.     {
  222.         $format $form->get('format')->getData();
  223.         $name ImporterRegistry::buildServiceName($importer$format);
  224.         if (!$this->registry->has($name)) {
  225.             $message sprintf("No importer found of type '%s' for format '%s'"$importer$format);
  226.             throw new ImporterException($message);
  227.         }
  228.         /** @var UploadedFile|null $file */
  229.         $file $form->get('import-data')->getData();
  230.         /** @var ImporterInterface $service */
  231.         $service $this->registry->get($name);
  232.         if (null === $file) {
  233.             throw new ImporterException('No file selected');
  234.         }
  235.         $path $file->getRealPath();
  236.         if (false === $path) {
  237.             throw new ImporterException(sprintf('File %s could not be loaded'$file->getClientOriginalName()));
  238.         }
  239.         /** @var ImporterResult $result */
  240.         $result $service->import($path);
  241.         $message sprintf(
  242.             'Import de %s (Temps en ms: %s, %s lignes importées, %s lignes passées, %s lignes en erreur)',
  243.             $name,
  244.             $result->getDuration(),
  245.             count($result->getSuccessRows()),
  246.             count($result->getSkippedRows()),
  247.             count($result->getFailedRows())
  248.         );
  249.         $this->flashBag->add('success'$message);
  250.         if ($result->getMessage() !== null) {
  251.             throw new ImporterException($result->getMessage());
  252.         }
  253.     }
  254. }