custom/plugins/UandiEfbDownloadCenter/src/Controller/PdfController.php line 192

Open in your IDE?
  1. <?php declare(strict_types=1);
  2. namespace Uandi\UandiEfbDownloadCenter\Controller;
  3. use Mpdf\MpdfException;
  4. use Psr\Log\LoggerInterface;
  5. use Shopware\Core\Content\Product\ProductEntity;
  6. use Shopware\Core\Framework\DataAbstractionLayer\EntityRepository;
  7. use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
  8. use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\EqualsFilter;
  9. use Shopware\Core\System\SalesChannel\SalesChannelContext;
  10. use Shopware\Storefront\Controller\StorefrontController;
  11. use Symfony\Component\HttpFoundation\BinaryFileResponse;
  12. use Symfony\Component\HttpFoundation\RedirectResponse;
  13. use Symfony\Component\HttpFoundation\Request;
  14. use Symfony\Component\HttpFoundation\ResponseHeaderBag;
  15. use Symfony\Component\Mime\FileinfoMimeTypeGuesser;
  16. use Symfony\Component\Routing\Annotation\Route;
  17. use Twig\Error\LoaderError;
  18. use Twig\Error\RuntimeError;
  19. use Twig\Error\SyntaxError;
  20. use Uandi\UandiEfbDownloadCenter\Service\PdfRenderer;
  21. /**
  22.  * @Route(defaults={"_routeScope"={"storefront"}})
  23.  */
  24. class PdfController extends StorefrontController
  25. {
  26.     private EntityRepository $productRepository;
  27.     private PdfRenderer $pdfRenderer;
  28.     private LoggerInterface $logger;
  29.     public function __construct(
  30.         EntityRepository $productRepository,
  31.         PdfRenderer $pdfRenderer,
  32.         LoggerInterface $logger
  33.     ) {
  34.         $this->productRepository $productRepository;
  35.         $this->pdfRenderer $pdfRenderer;
  36.         $this->logger $logger;
  37.     }
  38.     /**
  39.      * Find the product with the supplied product number, render a datasheet and return for download.
  40.      * Required GET parameter: productNumber
  41.      *
  42.      * @Route("/download/datasheet/", name="uandi.downloadcenter.pdf.datasheet", methods={"GET"})
  43.      *
  44.      * @param Request $request
  45.      * @param SalesChannelContext $salesChannelContext
  46.      *
  47.      * @return BinaryFileResponse|RedirectResponse
  48.      */
  49.     public function dataSheetPdf(
  50.         Request $request,
  51.         SalesChannelContext $salesChannelContext
  52.     ): BinaryFileResponse|RedirectResponse {
  53.         $product $this->findProduct($request$salesChannelContext);
  54.         if ($product == null) {
  55.             return $this->createErrorRedirectResponse($request'uandiDownloadCenter.productNotFound');
  56.         }
  57.         try {
  58.             $pdf $this->pdfRenderer->renderDataSheetPdf($product$salesChannelContext);
  59.         } catch (MpdfException|LoaderError|RuntimeError|SyntaxError $e) {
  60.             $this->logger->error(
  61.                 sprintf(
  62.                     '%s: Product %s: Exception on rendering datasheet: %s, Trace: %s',
  63.                     __METHOD__,
  64.                     $product->getProductNumber(),
  65.                     $e->getMessage(),
  66.                     $e->getTraceAsString()
  67.                 )
  68.             );
  69.             return $this->createErrorRedirectResponse($request"uandiDownloadCenter.pdfRenderError");
  70.         }
  71.         if ($pdf === null) {
  72.             return $this->createErrorRedirectResponse($request"uandiDownloadCenter.pdfRenderError");
  73.         }
  74.         return $this->createPdfDownloadResponse($pdf'datasheet'$product$request->getLocale());
  75.     }
  76.     /**
  77.      * Find the product with the supplied product number, call ERP API,
  78.      * render conformity declaration pdf, and return for download.
  79.      * Required POST parameter: productNumber
  80.      *
  81.      * @Route(
  82.      *     "/download/conformitydeclaration/", name="uandi.downloadcenter.pdf.conformitydeclaration", methods={"GET"}
  83.      *     )
  84.      *
  85.      * @param Request $request
  86.      * @param SalesChannelContext $salesChannelContext
  87.      *
  88.      * @return BinaryFileResponse|RedirectResponse
  89.      */
  90.     public function conformityDeclarationPdf(
  91.         Request $request,
  92.         SalesChannelContext $salesChannelContext
  93.     ): BinaryFileResponse|RedirectResponse {
  94.         $product $this->findProduct($request$salesChannelContext);
  95.         if ($product == null) {
  96.             return $this->createErrorRedirectResponse($request"uandiDownloadCenter.productNotFound");
  97.         }
  98.         try {
  99.             $pdf $this->pdfRenderer->renderConfirmityDeclarationPdf(
  100.                 [$product],
  101.                 $salesChannelContext
  102.             );
  103.         } catch (MpdfException|SyntaxError|RuntimeError|LoaderError $e) {
  104.             $this->logger->error(
  105.                 sprintf(
  106.                     '%s: Product %s: Exception on rendering declaration of conformity: %s, Trace: %s',
  107.                     __METHOD__,
  108.                     $product->getProductNumber(),
  109.                     $e->getMessage(),
  110.                     $e->getTraceAsString()
  111.                 )
  112.             );
  113.             return $this->createErrorRedirectResponse($request"uandiDownloadCenter.pdfRenderError");
  114.         }
  115.         if ($pdf === null $pdf === false) {
  116.             return $this->createErrorRedirectResponse($request"uandiDownloadCenter.pdfRenderError");
  117.         }
  118.         return $this->createPdfDownloadResponse($pdf'declarationofconformity'$product$request->getLocale());
  119.     }
  120.     /**
  121.      * Find the product with the supplied product number, call ERP API,
  122.      * render UKCA conformity declaration pdf, and return for download.
  123.      * Required POST parameter: productNumber
  124.      *
  125.      * @Route(
  126.      *     "/download/ukca/", name="uandi.downloadcenter.pdf.ukca", methods={"GET"}
  127.      *     )
  128.      *
  129.      * @param Request $request
  130.      * @param SalesChannelContext $salesChannelContext
  131.      *
  132.      * @return BinaryFileResponse|RedirectResponse
  133.      */
  134.     public function ukcaPdf(
  135.         Request $request,
  136.         SalesChannelContext $salesChannelContext
  137.     ): BinaryFileResponse|RedirectResponse {
  138.         $product $this->findProduct($request$salesChannelContext);
  139.         if ($product == null) {
  140.             return $this->createErrorRedirectResponse($request"uandiDownloadCenter.productNotFound");
  141.         }
  142.         try {
  143.             $pdf $this->pdfRenderer->renderUkcaPdf(
  144.                 [$product],
  145.                 $salesChannelContext
  146.             );
  147.         } catch (MpdfException|SyntaxError|RuntimeError|LoaderError $e) {
  148.             $this->logger->error(
  149.                 sprintf(
  150.                     '%s: Product %s: Exception on rendering ukca: %s, Trace: %s',
  151.                     __METHOD__,
  152.                     $product->getProductNumber(),
  153.                     $e->getMessage(),
  154.                     $e->getTraceAsString()
  155.                 )
  156.             );
  157.             return $this->createErrorRedirectResponse($request"uandiDownloadCenter.pdfRenderError");
  158.         }
  159.         if ($pdf === null $pdf === false) {
  160.             return $this->createErrorRedirectResponse($request"uandiDownloadCenter.pdfRenderError");
  161.         }
  162.         return $this->createPdfDownloadResponse($pdf'ukca'$product$request->getLocale());
  163.     }
  164.     /**
  165.      * Find product for the customer entered product number.
  166.      *
  167.      * @param Request $request
  168.      * @param SalesChannelContext $salesChannelContext
  169.      *
  170.      * @return mixed|null
  171.      */
  172.     private function findProduct(Request $requestSalesChannelContext $salesChannelContext): ?ProductEntity
  173.     {
  174.         $productSearchQuery $request->get('productNumber');
  175.         $criteria = new Criteria();
  176.         $criteria->addFilter(new EqualsFilter('productNumber'$productSearchQuery));
  177.         $criteria->addAssociations(['properties''cover''media']);
  178.         return $this->productRepository->search($criteria$salesChannelContext->getContext())->first();
  179.     }
  180.     /**
  181.      * Return pdf stream as a file download response.
  182.      *
  183.      * @param string $pdf
  184.      * @param string $type
  185.      * @param ProductEntity $productEntity
  186.      * @param string $locale
  187.      * @return BinaryFileResponse
  188.      */
  189.     private function createPdfDownloadResponse(
  190.         string $pdf,
  191.         string $type,
  192.         ProductEntity $productEntity,
  193.         string $locale
  194.     ): BinaryFileResponse {
  195.         $tmpFile tempnam("/tmp"$type);
  196.         file_put_contents($tmpFile$pdf);
  197.         $response = new BinaryFileResponse($tmpFile);
  198.         $mimeTypeGuesser = new FileinfoMimeTypeGuesser();
  199.         $response->headers->set('Content-Type'$mimeTypeGuesser->guessMimeType($tmpFile));
  200.         $language $this->getDocumentLanguage($locale);
  201.         $documentType = match ($type) {
  202.             'ukca' => '_UKCA_',
  203.             'declarationofconformity' => '_CE_',
  204.             default => '_',
  205.         };
  206.         $fileName $productEntity->getProductNumber() . $documentType $language '.pdf';
  207.         $response->setContentDisposition(ResponseHeaderBag::DISPOSITION_ATTACHMENT$fileName);
  208.         return $response;
  209.     }
  210.     /**
  211.      * Redirect user to previous page adding flash message with error
  212.      * - Add timestamp in url to avoid cache and show error message
  213.      *
  214.      * @param Request $request
  215.      * @param string $snippet
  216.      * @return RedirectResponse
  217.      */
  218.     private function createErrorRedirectResponse(Request $requeststring $snippet): RedirectResponse
  219.     {
  220.         $this->addFlash(self::DANGER$this->trans($snippet));
  221.         $previousPageUrl parse_url($request->headers->get('referer') ?? '/');
  222.         $redirectPage sprintf('%s?%s'$previousPageUrl['path'], http_build_query(['c' => time()]));
  223.         return $this->redirect($redirectPage);
  224.     }
  225.     /**
  226.      * Get language code according to requirements.
  227.      *
  228.      * @param string $locale
  229.      * @return string
  230.      */
  231.     private function getDocumentLanguage(string $locale): string
  232.     {
  233.         if (!empty($locale)) {
  234.             list($langCode$country) = explode('-'$locale);
  235.             $langCode mb_strtoupper($langCode);
  236.             if ($langCode == 'DA') {
  237.                 $langCode 'EN';
  238.             }
  239.             return $langCode;
  240.         }
  241.         return 'de';
  242.     }
  243. }