src/Controller/ConfiguratorController.php line 41

Open in your IDE?
  1. <?php
  2. /**
  3.  * Created by Elements.at New Media Solutions GmbH
  4.  *
  5.  */
  6. namespace App\Controller;
  7. use App\Templating\Helper\LinkGenerator;
  8. use App\Twig\ConfigHelper;
  9. use App\Twig\SimpleHelper;
  10. use Carbon\Carbon;
  11. use Elements\Bundle\CmsToolsBundle\Tool\Helper\MailHelper;
  12. use Elements\Bundle\HashCashBundle\Service\HashCashService;
  13. use Pimcore\Bundle\AdminBundle\HttpFoundation\JsonResponse;
  14. use Pimcore\Mail;
  15. use Pimcore\Model\DataObject\CompleteConfiguration;
  16. use Pimcore\Model\DataObject\ConfigurationComponent;
  17. use Pimcore\Model\DataObject\ConfigurationProduct;
  18. use Pimcore\Model\DataObject\Service;
  19. use Pimcore\Model\DataObject\SiteConfig;
  20. use Pimcore\Model\Document\Email;
  21. use Pimcore\Model\Document\Page;
  22. use Symfony\Component\HttpFoundation\Request;
  23. use Symfony\Component\HttpFoundation\Response;
  24. use Symfony\Component\Routing\Annotation\Route;
  25. class ConfiguratorController extends AbstractController
  26. {
  27.     public function __construct(private readonly LinkGenerator $linkGenerator, private readonly ConfigHelper $configHelper, private readonly HashCashService $hashCashService)
  28.     {
  29.     }
  30.     /**
  31.      *
  32.      * @param Request $request
  33.      *
  34.      * @return Response
  35.      */
  36.     public function overviewAction(Request $request): Response
  37.     {
  38.         $returnArray = [];
  39.         $configuratorObjects = new ConfigurationProduct\Listing();
  40.         if ($request->get('ajaxForm')) {
  41.             $siteConfig $this->configHelper->getSiteConfig();
  42.             if ($siteConfig instanceof SiteConfig && $siteConfig->getSuccessPageConfigurator() && $siteConfig->getAdminMailConfigurator() && $siteConfig->getUserMailConfigurator()) {
  43.                 $adminMail $siteConfig->getAdminMailConfigurator();
  44.                 $userMail $siteConfig->getUserMailConfigurator();
  45.                 $successPage $siteConfig->getSuccessPageConfigurator();
  46.             }
  47.             $required = ['name''company''mail''street''zip''city'];
  48.             $params $this->checkForm($request$required);
  49.             if (!empty($params['errors'])) {
  50.                 $errors[] = $params['errors'];
  51.             } else {
  52.                 $adminMailSuccess false;
  53.                 $userMailSuccess false;
  54.                 if (isset($adminMail) && $adminMail instanceof Email) {
  55.                     $mail = new Mail();
  56.                     try {
  57.                         $mail->setParams($params);
  58.                         $mail->setDocument($adminMail);
  59.                         $mail->send();
  60.                         $adminMailSuccess true;
  61.                     } catch(\Throwable $t) {
  62.                         $errors[] = 'sending admin mail failed: ' $t->getMessage();
  63.                     }
  64.                 }
  65.                 if (isset($userMail) && $userMail instanceof Email) {
  66.                     $mail = new Mail();
  67.                     try {
  68.                         $mail->addTo($params['mail']);
  69.                         $mail->setDocument($userMail);
  70.                         $mail->send();
  71.                         $userMailSuccess true;
  72.                     } catch(\Throwable $t) {
  73.                         $errors[] = 'sending user mail failed: ' $t->getMessage();
  74.                     }
  75.                 }
  76.                 if (empty($errors) && $adminMailSuccess && $userMailSuccess && isset($successPage) && $successPage instanceof Page) {
  77.                     return $this->redirect((string)$successPage);
  78.                 }
  79.             }
  80.             return $this->json([
  81.                 'success' => false,
  82.                 'errors' => $errors ?? [],
  83.             ]);
  84.         }
  85.         if ($request->isXmlHttpRequest() && $request->get('ajax')) {
  86.             $completeConfigurations = new CompleteConfiguration\Listing();
  87.             $completeConfigurations->addConditionParam('code = ?', [$request->get('search')]);
  88.             $completeConfiguration $completeConfigurations->current();
  89.             if ($completeConfiguration instanceof CompleteConfiguration) {
  90.                 return $this->json([
  91.                     'success' => true,
  92.                     'html' =>$this->redirect($this->linkGenerator->generate($completeConfiguration), 301)->getContent(),
  93.                 ]);
  94.             }
  95.         }
  96.         $returnArray['configurationProducts'] = $configuratorObjects->load();
  97.         return $this->renderTemplate('configurator/overview.html.twig'$returnArray);
  98.     }
  99.     /**
  100.      *
  101.      * @param Request $request
  102.      *
  103.      * @return Response
  104.      */
  105.     public function detailAction(Request $requestConfigurationProduct $id): Response
  106.     {
  107.         $configuration $id;
  108.         $steps = [];
  109.         $componentData = [];
  110.         foreach ($configuration->getConfigItems() as $configItem) {
  111.             $steps[$configItem->getStep()] = [
  112.                 'step' => $configItem->getStep(),
  113.                 'name' => $configItem->getVariantType(),
  114.                 'mandatory' => $configItem->getIsMandatory(),
  115.             ];
  116.         }
  117.         $steps array_values($steps);
  118.         foreach ($configuration->getConfigItems() as $configItem) {
  119.             $mandatoryComponentIds = [];
  120.             foreach ($configItem->getMandatoryComponents() as $mandComponent) {
  121.                 $mandatoryComponentIds[] = $mandComponent->getId();
  122.             }
  123.             $incompatibleComponents = [];
  124.             foreach ($configItem->getIncompatibleComponents() as $incompatibleComponent) {
  125.                 $incompatibleComponents[] = $incompatibleComponent->getId();
  126.             }
  127.             $componentData[] = [
  128.                 "pimcoreId" => $configItem->getId(),
  129.                 "title" => strip_tags($configItem->getDescription()),
  130.                 "description" => strip_tags($configItem->getDescription()),
  131.                 "shortDescription" => $configItem->getArticleNumber(),
  132.                 "price" => intval($configItem->getPrice()),
  133.                 "mandatoryComponents" => $mandatoryComponentIds,
  134.                 "incompatibleComponents" => $incompatibleComponents,
  135.                 "categoryStep" => $configItem->getStep(),
  136.                 "defaultSelected" => $configItem->getIsDefault(),
  137.             ];
  138.         }
  139.         $configurationToEdit = [];
  140.         if ($request->get('completeConfigurationId')) {
  141.             $completeConfiguration CompleteConfiguration::getById($request->get('completeConfigurationId'));
  142.             if ($completeConfiguration instanceof CompleteConfiguration) {
  143.                 $parts = [];
  144.                 foreach ($completeConfiguration->getParts() as $part) {
  145.                     $parts[] = $part->getId();
  146.                 }
  147.                 $configurationToEdit = [
  148.                     'componentsById' => $parts,
  149.                     'configurationName' => $completeConfiguration->getTitle(),
  150.                     'code' => $completeConfiguration->getCode(),
  151.                 ];
  152.             }
  153.         }
  154.         $returnArray = [
  155.             'steps' => $steps,
  156.             'configuration' => $configuration,
  157.             'componentData' => $componentData,
  158.             'configurationToEdit' => $configurationToEdit,
  159.         ];
  160.         return $this->renderTemplate('configurator/detail.html.twig'$returnArray);
  161.     }
  162.     /**
  163.      * @param Request $request
  164.      *
  165.      * @return JsonResponse
  166.      */
  167.     #[Route('/{_locale}/vue/configurator-save-json'name'vue_configurator-save-json')]
  168.     public function configuratorSaveJsonAction(Request $request)
  169.     {
  170.         $this->addResponseHeader('X-Robots-Tag''noindex'true);
  171.         if ($request->get('productId')) {
  172.             $configuration ConfigurationProduct::getById($request->get('productId'));
  173.             $components json_decode($request->get('components'), true);
  174.             $configurationName $request->get('configurationName');
  175.             $productId $request->get('productId');
  176.             $code $request->get('code');
  177.             $price $request->get('price');
  178.             $completeConfiguration $this->getOrCreateCompleteConfiguration($configuration$components$code$configurationName$productId$price);
  179.             $detailLink $this->linkGenerator->generate($completeConfiguration, ['id' => $completeConfiguration->getCode()]);
  180.             $responseData = [
  181.                 'success' => true,
  182.                 'detailLink' => $detailLink,
  183.                 'configurationId' => $completeConfiguration->getCode(),
  184.             ];
  185.         } else {
  186.             $responseData = [
  187.                 'success' => false,
  188.             ];
  189.         }
  190.         return new JsonResponse($responseData);
  191.     }
  192.     /**
  193.      * @param Request $request
  194.      *
  195.      * @return Response
  196.      *
  197.      * if pdf is last word of route, nginx looks for a file in /public.
  198.      * took me way too long to figure that out - now its pdf-print
  199.      */
  200.     #[Route('/{_locale}/vue/configurator-pdf-print'name'vue_configurator-print-pdf')]
  201.     public function configuratorPrintPdfAction(Request $request): Response
  202.     {
  203.         $completeConfiguration CompleteConfiguration::getById($request->query->get('completeConfiguration'));
  204.         $html $this->renderTemplate('configurator/pdf/result-pdf.html.twig', ['completeConfiguration' => $completeConfiguration])->getContent();
  205.         $adapter \Pimcore\Web2Print\Processor::getInstance();
  206.         $params = [
  207.             'filename' => 'configurator-' $completeConfiguration->getCode() . '.pdf',
  208.             'landscape' => false,
  209.             'printBackground' => true,
  210.             'displayHeaderFooter' => true,
  211.             'format' => 'A4',
  212.             'margin' => [
  213.                 'top' => '35 mm',
  214.                 'bottom' => '40 mm',
  215.                 'right' => '14.11 mm',
  216.                 'left' => '14.11 mm',
  217.             ],
  218.             'headerTemplate' => $this->getHeaderTemplate(),
  219.             'footerTemplate' => $this->getFooterTemplate()
  220.         ];
  221.         return new \Symfony\Component\HttpFoundation\Response(
  222.             $adapter->getPdfFromString($html$params),
  223.             200,
  224.             array(
  225.                 'Content-Type' => 'application/pdf',
  226.             )
  227.         );
  228.     }
  229.     private function getHeaderTemplate(): string {
  230.         return $this->renderTemplate('configurator/pdf/result-pdf-header.html.twig')->getContent();
  231.     }
  232.     private function getFooterTemplate(): string {
  233.         return $this->renderTemplate('configurator/pdf/result-pdf-footer.html.twig')->getContent();
  234.     }
  235.     /**
  236.      *
  237.      * @param Request $request
  238.      *
  239.      * @return Response
  240.      */
  241.     public function resultAction(Request $requestCompleteConfiguration $code): Response
  242.     {
  243.         if ($request->isXmlHttpRequest() && $request->get('ajax')) {
  244.             $returnArray = [
  245.                 'completeConfiguration' => $code,
  246.             ];
  247.         }
  248.         $returnArray = [
  249.             'completeConfiguration' => $code,
  250.         ];
  251.         return $this->renderTemplate('configurator/partials/result.html.twig'$returnArray);
  252.     }
  253.     private function generateUniqueCode(int $objectId): string
  254.     {
  255.         $length 6;
  256.         $chars 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
  257.         $code $objectId 100000;
  258.         for ($i 0$i <= $length strlen($code); $i++) {
  259.             $code .= $chars[random_int(0strlen($chars) - 1)];
  260.         }
  261.         return $code;
  262.     }
  263.     private function getOrCreateCompleteConfiguration(ConfigurationProduct $configurationmixed $componentsstring|null $codestring $configurationNameint $productIdstring $price): ?CompleteConfiguration
  264.     {
  265.         $completeConfiguration CompleteConfiguration::getByCode($code);
  266.         $completeConfiguration $completeConfiguration->current();
  267.         if (!$completeConfiguration instanceof CompleteConfiguration) {
  268.             \Pimcore\Model\Version::disable();
  269.             $completeConfiguration = new CompleteConfiguration();
  270.             $completeConfiguration->setPublished(false);
  271.             $completeConfiguration->setParent(Service::createFolderByPath('Configurator/CompleteConfigurations'));
  272.             $objectKey Service::getValidKey(Carbon::now()->timestamp'object');
  273.             $completeConfiguration->setKey($objectKey);
  274.             try {
  275.                 $completeConfiguration->save();
  276.             } catch (\Exception $exception) {
  277.                 p_r(SimpleHelper::printException($exception));
  278.             }
  279.             $code $this->generateUniqueCode($completeConfiguration->getId());
  280.             $completeConfiguration->setCode($code);
  281.             $objectKey Service::getValidKey($configuration->getModell() . '-' $code'object');
  282.             $completeConfiguration->setKey($objectKey);
  283.             try {
  284.                 $completeConfiguration->setPublished(true);
  285.                 $completeConfiguration->save();
  286.             } catch (\Throwable $exception) {
  287.                 p_r(SimpleHelper::printException($exception));
  288.                 return null;
  289.             }
  290.         }
  291.         $componentObjects = [];
  292.         foreach ($components as $componentId) {
  293.             $componentObjects[] = ConfigurationComponent::getById($componentId);
  294.         }
  295.         $completeConfiguration->setParts($componentObjects);
  296.         $completeConfiguration->setConfigurationProduct($configuration);
  297.         $completeConfiguration->setTitle($configurationName);
  298.         $completeConfiguration->setPrice($price);
  299.         try {
  300.             $completeConfiguration->save();
  301.         } catch (\Throwable $exception) {
  302.             p_r(SimpleHelper::printException($exception));
  303.             return null;
  304.         }
  305.         return $completeConfiguration;
  306.     }
  307.     private function checkForm(Request $requestmixed $required): mixed
  308.     {
  309.         $validHashCash $this->hashCashService->validateProcessFrom();
  310.         if ($validHashCash) {
  311.             $params $request->request->all();
  312.             unset($params['elhc_stamp'], $params['elhc_difficulty'], $params['elhc_nonce']);
  313.             $errors = [];
  314.             foreach ($required as $param) {
  315.                 if ($request->get($param) == '') {
  316.                     $errors[$param] =  $param ' is missing';
  317.                 }
  318.                 if ($param == 'mail' && !MailHelper::isValidEmailAddress($request->get($param))) {
  319.                     $errors[$param] = 'mail invalid';
  320.                 }
  321.             }
  322.             if (!empty($errors)) {
  323.                 $params['errors'] = $errors;
  324.             }
  325.             $params['items'] = $params;
  326.         } else {
  327.             $params['errors'] = ['recaptcha' => 'invalid captcha'];
  328.         }
  329.         return $params;
  330.     }
  331. }