vendor/store.shopware.com/moorlformbuilder/src/Core/Service/FormService.php line 322

Open in your IDE?
  1. <?php
  2. namespace MoorlFormBuilder\Core\Service;
  3. use MoorlFormBuilder\Core\Content\FormAppointment\FormAppointmentCollection;
  4. use MoorlFormBuilder\Core\Content\FormAppointment\FormAppointmentDefinition;
  5. use Shopware\Core\Content\Product\ProductEntity;
  6. use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\RangeFilter;
  7. use Doctrine\DBAL\Connection;
  8. use MoorlFormBuilder\Core\Content\Form\FormCollection;
  9. use MoorlFormBuilder\Core\Content\Form\FormEntity;
  10. use MoorlFormBuilder\Core\Event\AutocompleteCriteriaEvent;
  11. use MoorlFormBuilder\Core\Event\CmsFormEvent;
  12. use MoorlFormBuilder\Core\Event\FormCriteriaEvent;
  13. use MoorlFormBuilder\Core\Event\FormFireEvent;
  14. use MoorlFormBuilder\Core\Event\FormLoadEvent;
  15. use MoorlFormBuilder\Core\Event\FormOptionCriteriaEvent;
  16. use MoorlFormBuilder\MoorlFormBuilder;
  17. use MoorlFoundation\Core\PluginHelpers;
  18. use Shopware\Core\Content\Media\MediaCollection;
  19. use Shopware\Core\Framework\Adapter\Translation\Translator;
  20. use Shopware\Core\Framework\Context;
  21. use Shopware\Core\Framework\DataAbstractionLayer\DefinitionInstanceRegistry;
  22. use Shopware\Core\Framework\DataAbstractionLayer\Entity;
  23. use Shopware\Core\Framework\DataAbstractionLayer\EntityRepositoryInterface;
  24. use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
  25. use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\ContainsFilter;
  26. use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\EqualsFilter;
  27. use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\MultiFilter;
  28. use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\NotFilter;
  29. use Shopware\Core\Framework\DataAbstractionLayer\Search\Grouping\FieldGrouping;
  30. use Shopware\Core\Framework\DataAbstractionLayer\Search\Sorting\FieldSorting;
  31. use Shopware\Core\Framework\Event\EventData\MailRecipientStruct;
  32. use Shopware\Core\Framework\Uuid\Uuid;
  33. use Shopware\Core\Framework\Validation\DataBag\RequestDataBag;
  34. use Shopware\Core\System\SalesChannel\SalesChannelContext;
  35. use Shopware\Core\System\SystemConfig\SystemConfigService;
  36. use Shopware\Storefront\Framework\Captcha\AbstractCaptcha;
  37. use Shopware\Storefront\Framework\Captcha\Exception\CaptchaInvalidException;
  38. use Shopware\Storefront\Framework\Routing\RequestTransformer;
  39. use Symfony\Component\HttpFoundation\File\UploadedFile;
  40. use Symfony\Component\HttpFoundation\RequestStack;
  41. use Symfony\Component\HttpFoundation\Session\Session;
  42. use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
  43. class FormService
  44. {
  45.     protected Criteria $formCriteria;
  46.     protected StorefrontMediaUploader $mediaUploader;
  47.     protected ?array $blacklist;
  48.     private Context $context;
  49.     private ?SalesChannelContext $salesChannelContext null;
  50.     private DefinitionInstanceRegistry $definitionInstanceRegistry;
  51.     private NewsletterService $newsletterService;
  52.     private SystemConfigService $systemConfigService;
  53.     private Connection $connection;
  54.     private EventDispatcherInterface $eventDispatcher;
  55.     private EntityRepositoryInterface $formRepo;
  56.     private array $whitelist;
  57.     private ?string $localeCode null;
  58.     private ?string $formId null;
  59.     private ?FormEntity $form null;
  60.     private ?FormCollection $forms null;
  61.     private ?Session $session null;
  62.     private array $violations = [];
  63.     private RequestStack $requestStack;
  64.     private bool $checkCache false;
  65.     /**
  66.      * @var iterable<AbstractCaptcha>
  67.      */
  68.     private iterable $captchas;
  69.     private Translator $translator;
  70.     public function __construct(
  71.         NewsletterService $newsletterService,
  72.         DefinitionInstanceRegistry $definitionInstanceRegistry,
  73.         Connection $connection,
  74.         SystemConfigService $systemConfigService,
  75.         EventDispatcherInterface $eventDispatcher,
  76.         EntityRepositoryInterface $formRepo,
  77.         StorefrontMediaUploader $mediaUploader,
  78.         RequestStack $requestStack,
  79.         iterable $captchas,
  80.         array $allowedExtensions,
  81.         Translator $translator
  82.     )
  83.     {
  84.         $this->newsletterService $newsletterService;
  85.         $this->definitionInstanceRegistry $definitionInstanceRegistry;
  86.         $this->connection $connection;
  87.         $this->systemConfigService $systemConfigService;
  88.         $this->eventDispatcher $eventDispatcher;
  89.         $this->formRepo $formRepo;
  90.         $this->mediaUploader $mediaUploader;
  91.         $this->requestStack $requestStack;
  92.         $this->whitelist $allowedExtensions;
  93.         $this->captchas $captchas;
  94.         $this->translator $translator;
  95.         $this->context Context::createDefaultContext();
  96.     }
  97.     /**
  98.      * @param FormEntity|null $form
  99.      */
  100.     public function setForm(?FormEntity $form): void
  101.     {
  102.         $this->form $form;
  103.     }
  104.     /**
  105.      * @param bool $checkCache
  106.      */
  107.     public function setCheckCache(bool $checkCache): void
  108.     {
  109.         $this->checkCache $checkCache;
  110.     }
  111.     public function setFormElementsOptions(?Criteria $mainCriteria null): void
  112.     {
  113.         foreach ($this->form->getFormElements() as $formElement) {
  114.             if ($formElement->getType() === 'appointment') {
  115.                 $timeInterval = new \DateInterval(sprintf("PT%sM"$formElement->getTimeStep()));
  116.                 $timeMin = new \DateTime();
  117.                 $timeMax = clone($timeMin);
  118.                 $timeRange = new \DatePeriod(
  119.                     $timeMin->setTime($formElement->getTimeMin(),0),
  120.                     $timeInterval,
  121.                     $timeMax->setTime($formElement->getTimeMax(),0)
  122.                 );
  123.                 $dateInterval = new \DateInterval(sprintf("P%sD"$formElement->getDateStep()));
  124.                 $dateMin = (new \DateTime($formElement->getDateMin()))->setTime(0,0);
  125.                 $dateMax = (new \DateTime($formElement->getDateMax()))->setTime(23,59);
  126.                 $dateRange = new \DatePeriod($dateMin$dateInterval$dateMax);
  127.                 if ($mainCriteria) {
  128.                     $criteria = clone $mainCriteria;
  129.                 } else {
  130.                     $criteria = new Criteria();
  131.                 }
  132.                 $criteria->addFilter(new EqualsFilter('active'true));
  133.                 $criteria->addFilter(new EqualsFilter('formElement'$formElement->getName()));
  134.                 $criteria->addFilter(new EqualsFilter('formId'$this->form->getId()));
  135.                 $criteria->addFilter(new RangeFilter('start', [
  136.                     'lte' => $dateMax->format(DATE_ATOM),
  137.                     'gte' => $dateMin->format(DATE_ATOM),
  138.                 ]));
  139.                 $appointmentRepository $this->definitionInstanceRegistry->getRepository(FormAppointmentDefinition::ENTITY_NAME);
  140.                 /** @var FormAppointmentCollection $appointments */
  141.                 $appointments $appointmentRepository->search($criteria$this->getContext())->getEntities();
  142.                 $optgroup = [];
  143.                 foreach ($dateRange as $date) {
  144.                     if (in_array($date->format("w"), $formElement->getDateExclude())) {
  145.                         continue;
  146.                     }
  147.                     $options = [];
  148.                     foreach ($timeRange as $time) {
  149.                         $value sprintf("%sT%s"$date->format('Y-m-d'), $time->format('H:i'));
  150.                         $options[] = [
  151.                             'value' => $value,
  152.                             'blocked' => $appointments->isBlocked($value)
  153.                         ];
  154.                     }
  155.                     $optgroup[] = [
  156.                         'label' => $date->format('Y-m-d'),
  157.                         'options' => $options,
  158.                     ];
  159.                 }
  160.                 $formElement->setOptions($optgroup);
  161.             }
  162.         }
  163.     }
  164.     public function disableAppointment(array $keyValues = []): void
  165.     {
  166.         $criteria = new Criteria();
  167.         foreach ($keyValues as $field => $keyValue) {
  168.             $criteria->addFilter(new EqualsFilter($field$keyValue));
  169.         }
  170.         $appointmentRepository $this->definitionInstanceRegistry->getRepository(FormAppointmentDefinition::ENTITY_NAME);
  171.         $ids $appointmentRepository->searchIds($criteria$this->getContext())->getIds();
  172.         $payload array_map(function ($id) {
  173.             return [
  174.                 'active' => false,
  175.                 'id' => $id
  176.             ];
  177.         }, $ids);
  178.         $appointmentRepository->upsert($payload$this->getContext());
  179.     }
  180.     public function addAppointment(string $formId, ?array $userValues null, array $keyValues = []): void
  181.     {
  182.         if (!$userValues) {
  183.             $userValues $this->form->getUserValues();
  184.             if (!$userValues) {
  185.                 return;
  186.             }
  187.         }
  188.         $form $this->getFormById($formId);
  189.         $payload = [];
  190.         foreach ($form->getFormElements() as $formElement) {
  191.             if ($formElement->getType() === 'appointment') {
  192.                 if (!empty($userValues[$formElement->getName()])) {
  193.                     $payload[] = array_merge([
  194.                         'id' => Uuid::randomHex(),
  195.                         'active' => true,
  196.                         'formElement' => $formElement->getName(),
  197.                         'formId' => $formId,
  198.                         'start' => $userValues[$formElement->getName()]
  199.                     ], $keyValues);
  200.                 }
  201.             }
  202.         }
  203.         if (empty($payload)) {
  204.             return;
  205.         }
  206.         $appointmentRepository $this->definitionInstanceRegistry->getRepository(FormAppointmentDefinition::ENTITY_NAME);
  207.         $appointmentRepository->upsert($payload$this->getContext());
  208.     }
  209.     public function fire(Context $contextSalesChannelContext $salesChannelContext null): ?array
  210.     {
  211.         $this->setContext($context);
  212.         $this->setSalesChannelContext($salesChannelContext);
  213.         $this->initForm();
  214.         if ($this->hasViolations()) {
  215.             return $this->getViolations();
  216.         }
  217.         if ($this->getSalesChannelContext()) {
  218.             $salesChannelId $this->getSalesChannelContext()->getSalesChannel()->getId();
  219.             $email $this->systemConfigService->get('core.basicInformation.email'$salesChannelId);
  220.             $blacklist $this->systemConfigService->get('MoorlFormBuilder.config.blacklist'$salesChannelId);
  221.         } else {
  222.             $email $this->systemConfigService->get('core.basicInformation.email');
  223.             $blacklist $this->systemConfigService->get('MoorlFormBuilder.config.blacklist');
  224.         }
  225.         $this->cacheUserData($email);
  226.         if ($this->getFormId()) {
  227.             // example: add to cart item has no form id and no data
  228.             $this->checkCaptcha();
  229.             $this->setBlacklist($blacklist);
  230.             $this->validateUserData();
  231.             $this->validateFiles();
  232.             if ($this->hasViolations()) {
  233.                 return $this->getViolations();
  234.             }
  235.             $this->uploadFiles();
  236.             if ($this->hasViolations()) {
  237.                 return $this->getViolations();
  238.             }
  239.         }
  240.         $this->setCurrentFormPayload();
  241.         $this->setCurrentFormSummaryHTML();
  242.         $this->setCurrentFormSummaryPlain();
  243.         return null;
  244.     }
  245.     public function initForm(): bool
  246.     {
  247.         if (!$this->form) {
  248.             if (!$this->getFormId()) {
  249.                 $this->violations[] = $this->trans('moorl-form-builder.general.internalError');
  250.             } else {
  251.                 $this->initCurrentForm($this->getFormId());
  252.                 if (!$this->form) {
  253.                     $this->violations[] = $this->trans('moorl-form-builder.general.internalError');
  254.                 }
  255.             }
  256.         }
  257.         return $this->hasViolations();
  258.     }
  259.     public function getFormId(): ?string
  260.     {
  261.         if (!$this->formId) {
  262.             $this->formId $this->requestStack->getCurrentRequest()->get('_form_id');
  263.         }
  264.         return $this->formId;
  265.     }
  266.     public function setFormId(string $formId): void
  267.     {
  268.         $this->formId $formId;
  269.     }
  270.     public function trans(string $snippet, ?array $data = []): array
  271.     {
  272.         return [
  273.             'snippet' => $snippet,
  274.             'data' => $data
  275.         ];
  276.     }
  277.     public function initCurrentForm(?string $formId null)
  278.     {
  279.         $this->setCurrentForm($formId);
  280.         $this->_initCurrentForm();
  281.     }
  282.     public function setCurrentForm(?string $formId null)
  283.     {
  284.         if ($formId || $this->getFormId()) {
  285.             if ($formId) {
  286.                 $this->setFormId($formId);
  287.             }
  288.             if (!$this->forms || !$this->forms->get($this->getFormId())) {
  289.                 $this->setFormById($this->getFormId());
  290.             }
  291.             $this->form $this->forms->get($this->getFormId());
  292.         } else {
  293.             if (!$this->forms || !$this->forms->last()) {
  294.                 $this->setForms(); // context and criteria need to be set
  295.             }
  296.             $this->form $this->forms->last(); // get last inserted form
  297.         }
  298.     }
  299.     public function setFormById(string $formId): void
  300.     {
  301.         $this->setFormCriteria(new Criteria([$formId]));
  302.         $this->setForms();
  303.     }
  304.     private function _initCurrentForm(): void
  305.     {
  306.         $this->getLocaleCode();
  307.         if ($this->form) {
  308.             if ($this->form->getInitialized()) {
  309.                 return;
  310.             }
  311.             $this->addEntitySelections();
  312.             $event = new FormLoadEvent($this->getContext(), $this->form);
  313.             $this->eventDispatcher->dispatch($event);
  314.             $this->setFormDataFromSession();
  315.             $this->setFormDataFromCustomer();
  316.             $this->setCurrentFormPayload();
  317.             $this->setCurrentFormSummaryHTML();
  318.             $this->setCurrentFormSummaryPlain();
  319.             $this->setFormElementsOptions();
  320.             $this->form->setInitialized(true);
  321.             $this->forms->add($this->form);
  322.         }
  323.     }
  324.     public function getLocaleCode(): string
  325.     {
  326.         if (!$this->localeCode && $this->getContext()) {
  327.             $repository $this->definitionInstanceRegistry->getRepository('language');
  328.             $criteria = new Criteria([$this->getContext()->getLanguageId()]);
  329.             $criteria->addAssociation('locale');
  330.             $this->localeCode $repository->search($criteria$this->getContext())->first()->getLocale()->getCode() ?: 'en-GB';
  331.         }
  332.         return $this->localeCode ?: 'en-GB';
  333.     }
  334.     public function getContext(): Context
  335.     {
  336.         return $this->context;
  337.     }
  338.     public function setContext(Context $context)
  339.     {
  340.         $this->context $context;
  341.     }
  342.     private function addEntitySelections(): void
  343.     {
  344.         $locale $this->getLocaleCode();
  345.         /* Set translations FormEntity */
  346.         $this->form->setTranslated([
  347.             'label' => $this->getLocalVariable($this->form->getLabel()),
  348.             'successMessage' => $this->getLocalVariable($this->form->getSuccessMessage()),
  349.             'submitText' => $this->getLocalVariable($this->form->getSubmitText()),
  350.         ]);
  351.         $elements $this->form->getData();
  352.         foreach ($elements as &$element) {
  353.             if ($this->getIsSet($element'isEntitySelect')) {
  354.                 $repository $this->definitionInstanceRegistry->getRepository($element['entitySelect']['relatedEntity']);
  355.                 $criteria = new Criteria();
  356.                 // Product Media Hack
  357.                 if ($element['entitySelect']['relatedEntity'] == 'product') {
  358.                     $criteria->addAssociation('cover');
  359.                 }
  360.                 $criteria->addSorting(new FieldSorting($element['entitySelect']['labelProperty'], FieldSorting::ASCENDING));
  361.                 $event = new FormOptionCriteriaEvent($this->getContext(), $criteria$element$this->form->getAction());
  362.                 $this->eventDispatcher->dispatch($event);
  363.                 $collection $repository->search($criteria$this->getContext())->getEntities();
  364.                 $options = [];
  365.                 foreach ($collection as $entity) {
  366.                     $mediaId null;
  367.                     if ($this->getIsSet($element'useImageSelection')) {
  368.                         // Product Media Hack
  369.                         if ($element['entitySelect']['relatedEntity'] == 'product' && $entity->getCover()) {
  370.                             $mediaId $entity->getCover()->getMedia()->getId();
  371.                         } else {
  372.                             $mediaId $entity->get($element['entitySelect']['mediaProperty']);
  373.                         }
  374.                     }
  375.                     try {
  376.                         if (isset($entity->getTranslated()[$element['entitySelect']['labelProperty']])) {
  377.                             $label $entity->getTranslated()[$element['entitySelect']['labelProperty']];
  378.                         } else {
  379.                             $label $entity->get($element['entitySelect']['labelProperty']);
  380.                         }
  381.                     } catch (\Exception $exception) {
  382.                     }
  383.                     $options[] = [
  384.                         'id' => $entity->get($element['entitySelect']['valueProperty']),
  385.                         'value' => $entity->get($element['entitySelect']['valueProperty']),
  386.                         'label' => [
  387.                             $locale => $label
  388.                         ],
  389.                         'entity' => $entity// set complete entity for customizing
  390.                         'mediaId' => $mediaId,
  391.                         'useTrans' => null,
  392.                         'emailReceiver' => null,
  393.                     ];
  394.                 }
  395.                 $element['options'] = $options;
  396.             }
  397.             /* Set translations FormEntity - Element */
  398.             $element['translated'] = [
  399.                 'label' => $this->getLocalVariable($this->getIsSet($element'label')),
  400.                 'placeholder' => $this->getLocalVariable($this->getIsSet($element'placeholder')),
  401.             ];
  402.             /* Set translations FormEntity - Element options */
  403.             foreach ($element['options'] as &$option) {
  404.                 $option['translated'] = [
  405.                     'label' => $this->getLocalVariable($this->getIsSet($option'label')),
  406.                     'customField1' => $this->getLocalVariable($this->getIsSet($option'customField1')),
  407.                     'customField2' => $this->getLocalVariable($this->getIsSet($option'customField2')),
  408.                     'customField3' => $this->getLocalVariable($this->getIsSet($option'customField3')),
  409.                 ];
  410.             }
  411.         }
  412.         $this->form->setData($elements);
  413.     }
  414.     public function getLocalVariable(?array $var): ?string
  415.     {
  416.         if (isset($var[$this->localeCode])) {
  417.             return $var[$this->localeCode];
  418.         } elseif (is_array($var) && count($var) > 0) {
  419.             return reset($var);
  420.         } else {
  421.             return null;
  422.         }
  423.     }
  424.     public function getIsSet(?array $varstring $index$alt null)
  425.     {
  426.         if (isset($var[$index])) {
  427.             return $var[$index];
  428.         } else {
  429.             return $alt;
  430.         }
  431.     }
  432.     public function setFormDataFromCustomer(): void
  433.     {
  434.         if ($this->form->getRelatedEntity() !== 'customer') {
  435.             return;
  436.         }
  437.         if (!$this->getSalesChannelContext()) {
  438.             return;
  439.         }
  440.         $customer $this->getSalesChannelContext()->getCustomer();
  441.         if (!$customer) {
  442.             return;
  443.         }
  444.         $customerCustomFields $customer->getCustomFields();
  445.         $formElements $this->form->getData();
  446.         foreach ($formElements as &$formElement) {
  447.             if ($formElement['mapping']) {
  448.                 $mapping explode('.'$formElement['mapping']);
  449.                 if ($mapping[0] === 'customFields') {
  450.                     $formElement['value'] = $this->getIsSet($customerCustomFields$mapping[1]);
  451.                 } else {
  452.                     $formElement['value'] = $customer->get($mapping[0]);
  453.                 }
  454.             }
  455.         }
  456.         $this->form->setData($formElements);
  457.         $criteria = new Criteria();
  458.         $criteria->addFilter(new EqualsFilter('customerId'$customer->getId()));
  459.         $this->setFormElementsOptions($criteria);
  460.     }
  461.     public function setFormDataFromSession(): void
  462.     {
  463.         if ($this->checkCache && getenv("SHOPWARE_HTTP_CACHE_ENABLED") === "1") {
  464.             return; // prevent prefill when cache turned on
  465.         }
  466.         if ($this->checkCache && $this->systemConfigService->get('MoorlFormBuilder.config.disableCache')) {
  467.             return; // prevent prefill by config
  468.         }
  469.         $this->initSession();
  470.         $userValues $this->session->get('moorl-form-builder.values_' $this->form->getId());
  471.         if (!$userValues) {
  472.             return;
  473.         }
  474.         $formElements $this->form->getData();
  475.         foreach ($formElements as &$formElement) {
  476.             if ($userValue $this->getIsSet($userValues$formElement['name'])) {
  477.                 $formElement['value'] = $userValue;
  478.             }
  479.         }
  480.         $this->form->setData($formElements);
  481.     }
  482.     public function initSession(): void
  483.     {
  484.         if (!$this->session) {
  485.             $this->session = new Session();
  486.         }
  487.     }
  488.     public function validateTaxIdNumber(string $taxIdNumber): bool
  489.     {
  490.         try {
  491.             $vatid preg_replace("/[^a-zA-Z0-9]]/"""$taxIdNumber);
  492.             $vatidRegex "/^[a-z]{2}[a-z0-9]{0,12}$/i";
  493.             if (preg_match($vatidRegex$vatid) !== 1) {
  494.                 throw new \Exception('Invalid Vat Id Format');
  495.             }
  496.             $client = new \SoapClient("https://ec.europa.eu/taxation_customs/vies/checkVatService.wsdl");
  497.             $params = [
  498.                 'countryCode' => substr($vatid02),
  499.                 'vatNumber' => substr($vatid2),
  500.             ];
  501.             $result $client->checkVatApprox($params);
  502.             if ($result->valid) {
  503.                 return true;
  504.             } else {
  505.                 return false;
  506.             }
  507.         } catch (\Exception $exception) {
  508.             return false;
  509.         }
  510.     }
  511.     public function setCurrentFormSummaryPlain()
  512.     {
  513.         $medias $this->getMediaCollection();
  514.         $html "\n";
  515.         foreach ($this->form->getData() as $formElement) {
  516.             if ($formElement['value'] || in_array($formElement['type'], ['checkbox''switch'])) {
  517.                 $html .= $formElement['translated']['label'] . " ";
  518.                 switch ($formElement['type']) {
  519.                     case 'datepicker':
  520.                         $html .= $formElement['value'];
  521.                         break;
  522.                     case 'upload':
  523.                         $media $medias->get($formElement['value']);
  524.                         if ($media) {
  525.                             $html .= $media->getUrl();
  526.                         }
  527.                         break;
  528.                     case 'select':
  529.                     case 'multiselect':
  530.                     case 'radio-group':
  531.                     case 'checkbox-group':
  532.                         foreach ($formElement['options'] as $option) {
  533.                             if ($option['value'] == $formElement['value'] || (is_array($formElement['value']) && in_array($option['value'], $formElement['value']))) {
  534.                                 $html .= $option['translated']['label'] . " ";
  535.                                 if (isset($option['priceCalculation']) && is_numeric($option['priceCalculation'])) {
  536.                                     // Todo: get the currency here!?
  537.                                     $html .= number_format($option['priceCalculation'], 2',''.');
  538.                                 }
  539.                             } elseif (isset($formElement['value'][$option['value']])) {
  540.                                 $html .= $option['translated']['label'] . ': ' $formElement['value'][$option['value']] . ' ';
  541.                             }
  542.                         }
  543.                         break;
  544.                     case 'repeater-open':
  545.                         $html .= $this->form->getRepeaterDataValue($formElement['name']);
  546.                         break;
  547.                     case 'checkbox':
  548.                     case 'switch':
  549.                         $html .= empty($formElement['value']) ? $this->translator->trans("moorl-form-builder.general.no") : $this->translator->trans("moorl-form-builder.general.yes");
  550.                         break;
  551.                     default:
  552.                         $html .= $formElement['value'];
  553.                 }
  554.                 $html .= "\n";
  555.             }
  556.         }
  557.         $this->form->setSummaryPlain($html);
  558.     }
  559.     public function setCurrentFormSummaryHTML()
  560.     {
  561.         $medias $this->getMediaCollection();
  562.         $html '<table border="0" style="font-size: 1em; margin-bottom: 5px">';
  563.         foreach ($this->form->getData() as $formElement) {
  564.             $addHtml '';
  565.             if ($formElement['value'] || in_array($formElement['type'], ['checkbox''switch'])) {
  566.                 $html .= '<tr><td bgcolor="#F7F7F2" style="border-bottom:1px solid #cccccc;">' $formElement['translated']['label'] . '</td>';
  567.                 if ($this->getIsSet($formElement'usePriceCalculation')) {
  568.                     $cols 1;
  569.                 } else {
  570.                     $cols 2;
  571.                 }
  572.                 $html .= '<td colspan="' $cols '" style="border-bottom:1px solid #cccccc;">';
  573.                 switch ($formElement['type']) {
  574.                     case 'datepicker':
  575.                         $html .= $formElement['value'];
  576.                         break;
  577.                     case 'upload':
  578.                         $media $medias->get($formElement['value']);
  579.                         if ($media) {
  580.                             if (in_array($media->getFileExtension(), ['png''jpg''jpeg''gif'])) {
  581.                                 $html .= '<a href="' $media->getUrl() . '"><img style="width: 100px;" src="' $media->getUrl() . '" alt="' $media->getFileName() . '"></a>';
  582.                             } else {
  583.                                 $html .= '<a href="' $media->getUrl() . '">' $formElement['translated']['label'] . '</a>';
  584.                             }
  585.                         }
  586.                         break;
  587.                     case 'appointment':
  588.                         $appointment=  new \DateTime($formElement['value']);
  589.                         $html .= $appointment->format($this->translator->trans("moorl-form-builder.general.dateTimeFormat"));
  590.                         break;
  591.                     case 'select':
  592.                     case 'multiselect':
  593.                     case 'radio-group':
  594.                     case 'checkbox-group':
  595.                         $addHtml '<td align="right" style="border-bottom:1px solid #cccccc;">';
  596.                         foreach ($formElement['options'] as $option) {
  597.                             if ($option['value'] == $formElement['value'] || (is_array($formElement['value']) && in_array($option['value'], $formElement['value']))) {
  598.                                 $html .= $option['translated']['label'] . '<br>';
  599.                                 if (isset($option['priceCalculation']) && is_numeric($option['priceCalculation'])) {
  600.                                     // Todo: get the currency here!?
  601.                                     $addHtml .= number_format($option['priceCalculation'], 2',''.') . '<br>';
  602.                                 }
  603.                             } elseif (isset($formElement['value'][$option['value']])) {
  604.                                 $html .= $option['translated']['label'] . ': ' $formElement['value'][$option['value']] . '<br>';
  605.                             }
  606.                         }
  607.                         $addHtml .= '</td>';
  608.                         break;
  609.                     case 'repeater-open':
  610.                         $html .= nl2br($this->form->getRepeaterDataValue($formElement['name']));
  611.                         break;
  612.                     case 'checkbox':
  613.                     case 'switch':
  614.                         $html .= empty($formElement['value']) ? $this->translator->trans("moorl-form-builder.general.no") : $this->translator->trans("moorl-form-builder.general.yes");
  615.                         break;
  616.                     default:
  617.                         $html .= nl2br(trim(str_replace(["'""\""], "&quot;"$formElement['value'])));
  618.                 }
  619.                 $html .= '</td>' . ($cols == $addHtml '') . '</tr>';
  620.             }
  621.         }
  622.         $html .= '</table>';
  623.         $html strip_tags($html'<table><tr><td><br><img><a>');
  624.         $this->form->setSummaryHTML($html);
  625.     }
  626.     public function getMediaCollection(?array $mediaIds null): ?MediaCollection
  627.     {
  628.         if ($this->form->getMedias()) {
  629.             return $this->form->getMedias();
  630.         }
  631.         if (!$mediaIds) {
  632.             $mediaIds = [];
  633.             foreach ($this->form->getData() as $formElement) {
  634.                 if ($formElement['value'] && $formElement['type'] == 'upload') {
  635.                     $mediaIds[] = $formElement['value'];
  636.                 }
  637.             }
  638.         }
  639.         if (count($mediaIds) > 0) {
  640.             $repo $this->definitionInstanceRegistry->getRepository('media');
  641.             $this->form->setMedias($repo->search(new Criteria($mediaIds), $this->getContext())->getEntities());
  642.         }
  643.         return $this->form->getMedias();
  644.     }
  645.     public function setCurrentFormPayload(): void
  646.     {
  647.         $payload = [];
  648.         foreach ($this->form->getData() as $formElement) {
  649.             if ($formElement['name'] && $formElement['mapping'] && $formElement['value']) {
  650.                 if (!empty($formElement['value'])) {
  651.                     if ($formElement['value'] === 'true') {
  652.                         $payload[$formElement['mapping']] = true;
  653.                     } elseif ($formElement['value'] === 'false') {
  654.                         $payload[$formElement['mapping']] = false;
  655.                     } else {
  656.                         if (in_array($formElement['type'], ['switch','checkbox'])) {
  657.                             $payload[$formElement['mapping']] = true;
  658.                         } else {
  659.                             $payload[$formElement['mapping']] = $formElement['value'];
  660.                         }
  661.                     }
  662.                 }
  663.             }
  664.             $formElements[] = $formElement;
  665.         }
  666.         PluginHelpers::getNestedVar($payload);
  667.         $this->form->setPayload($payload);
  668.     }
  669.     public function hasViolations(): bool
  670.     {
  671.         return count($this->violations) > true false;
  672.     }
  673.     public function getViolations(): array
  674.     {
  675.         return $this->violations;
  676.     }
  677.     /**
  678.      * @return SalesChannelContext|null
  679.      */
  680.     public function getSalesChannelContext(): ?SalesChannelContext
  681.     {
  682.         return $this->salesChannelContext;
  683.     }
  684.     /**
  685.      * @param SalesChannelContext|null $salesChannelContext
  686.      */
  687.     public function setSalesChannelContext(?SalesChannelContext $salesChannelContext): void
  688.     {
  689.         $this->salesChannelContext $salesChannelContext;
  690.         if ($salesChannelContext) {
  691.             $this->context $salesChannelContext->getContext();
  692.         }
  693.     }
  694.     public function cacheUserData($fallbackReceiver null): bool
  695.     {
  696.         $data $this->requestStack->getCurrentRequest();
  697.         $receivers $this->form->getEmailReceiver() ? explode(";"$this->form->getEmailReceiver()) : ($fallbackReceiver ? [$fallbackReceiver] : []);
  698.         $customerEmailReceiver = [];
  699.         $userValues = [
  700.             'storefrontUrl' => $data->attributes->get(RequestTransformer::STOREFRONT_URL)
  701.         ];
  702.         $formElements = [];
  703.         foreach ($this->form->getData() as $formElement) {
  704.             $requestValue $data->get($formElement['name']);
  705.             if ($formElement['name'] && $requestValue) {
  706.                 if (!empty($requestValue)) {
  707.                     if ($requestValue instanceof RequestDataBag) {
  708.                         $requestValue $requestValue->all();
  709.                     }
  710.                     $userValues[$formElement['name']] = $requestValue;
  711.                     $formElement['value'] = $requestValue;
  712.                     if ($formElement['type'] == 'email' && ($this->form->getSendCopyType() === 'always' || $data->get('_send_copy'))) {
  713.                         $customerEmailReceiver[] = $requestValue;
  714.                     }
  715.                     if ($formElement['type'] == 'email') {
  716.                         $this->form->setReplyTo($requestValue);
  717.                     }
  718.                     if ($this->getIsSet($formElement'hasEmailReceiver') && is_array($formElement['options'])) {
  719.                         foreach ($formElement['options'] as $option) {
  720.                             if ($this->getIsSet($option'emailReceiver')) {
  721.                                 if (is_array($requestValue)) {
  722.                                     if (in_array($option['value'], $requestValue)) {
  723.                                         $receivers array_merge(
  724.                                             $receivers,
  725.                                             explode(";"$option['emailReceiver'])
  726.                                         );
  727.                                     }
  728.                                 } else {
  729.                                     if ($option['value'] == $requestValue) {
  730.                                         $receivers array_merge(
  731.                                             $receivers,
  732.                                             explode(";"$option['emailReceiver'])
  733.                                         );
  734.                                     }
  735.                                 }
  736.                             }
  737.                         }
  738.                     }
  739.                 }
  740.             }
  741.             $formElements[] = $formElement;
  742.         }
  743.         $this->form->setEmailReceiver(implode(";"$receivers));
  744.         $this->form->setCustomerEmailReceiver(implode(";"$customerEmailReceiver));
  745.         $this->form->setData($formElements);
  746.         $this->form->setUserValues($userValues);
  747.         $this->addSessionUserValues($userValues);
  748.         return $this->hasViolations();
  749.     }
  750.     public function addSessionUserValues(array $userValues = [], ?string $id null): void
  751.     {
  752.         $this->initSession();
  753.         if ($id) {
  754.             $id $id $this->form->getId();
  755.         } else {
  756.             $id $this->form->getId();
  757.         }
  758.         $userValues array_merge($this->form->getUserValues(), $userValues);
  759.         $this->session->set('moorl-form-builder.values_' $id$userValues);
  760.     }
  761.     public function checkCaptcha(): bool
  762.     {
  763.         $this->initSession();
  764.         if ($this->form->getUseCaptcha()) {
  765.             $activeCaptchas $this->systemConfigService->get('core.basicInformation.activeCaptchasV2');
  766.             foreach ($this->captchas as $captcha) {
  767.                 $captchaConfig $activeCaptchas[$captcha->getName()] ?? [];
  768.                 $request $this->requestStack->getCurrentRequest();
  769.                 if (!$captcha->supports($request$captchaConfig)) {
  770.                     continue;
  771.                 }
  772.                 if (!$captcha->isValid($request$captchaConfig)) {
  773.                     if ($captcha->shouldBreak()) {
  774.                         throw new CaptchaInvalidException($captcha);
  775.                     }
  776.                     $this->violations[] = $this->trans('moorl-form-builder.general.captchaError');
  777.                 }
  778.             }
  779.         }
  780.         return $this->hasViolations();
  781.     }
  782.     public function setBlacklist(?string $blacklist): void
  783.     {
  784.         if ($blacklist) {
  785.             $blacklist explode(','$blacklist);
  786.             $blacklist array_map('trim'$blacklist);
  787.             $blacklist array_map('mb_strtolower'$blacklist);
  788.             $this->blacklist $blacklist;
  789.         }
  790.     }
  791.     public function validateUserData(): bool
  792.     {
  793.         $data $this->requestStack->getCurrentRequest();
  794.         $formRepeaterName null;
  795.         foreach ($this->form->getData() as $formElement) {
  796.             if ($formElement['type'] === 'repeater-open') {
  797.                 $formRepeaterName $formElement['name'];
  798.             }
  799.             if ($formElement['type'] === 'repeater-close') {
  800.                 $formRepeaterName null;
  801.             }
  802.             if ($formRepeaterName) {
  803.                 // Hotfix: Form elements within repeater will be validated client side
  804.                 continue;
  805.             }
  806.             $requestValue $data->get($formElement['name']);
  807.             if (!$requestValue) {
  808.                 continue;
  809.             }
  810.             if ($formElement['type'] === 'tax-id-number') {
  811.                 if (!$this->validateTaxIdNumber($requestValue)) {
  812.                     $this->violations[] = $this->trans('moorl-form-builder.general.taxIdNumberError', [
  813.                         '%value%' => $this->getIsSet($formElement['translated'], 'label'$formElement['name']),
  814.                     ]);
  815.                 }
  816.                 continue;
  817.             }
  818.             if ($requestValue instanceof RequestDataBag) {
  819.                 $requestValue $requestValue->all();
  820.             }
  821.             // Hotfix: Form elements with conditions will be validated client side
  822.             $formElementConditions = (isset($formElement['conditions']) && count($formElement['conditions']) > 0);
  823.             // Hotfix: Form elements with file uploads are set after the validation
  824.             $formElementIsUpload = ($formElement['type'] === 'upload');
  825.             if (!$requestValue && !$formElementConditions && !$formElementIsUpload && $formElement['required']) {
  826.                 $this->violations[] = $this->trans('moorl-form-builder.general.requiredError', [
  827.                     '%value%' => $this->getIsSet($formElement['translated'], 'label'$formElement['name']),
  828.                 ]);
  829.             }
  830.             if (!empty($formElement['useBlacklist'])) {
  831.                 if ($requestValue && $this->inBlacklist($requestValue)) {
  832.                     $this->violations[] = $this->trans('moorl-form-builder.general.blacklistError', [
  833.                         '%value%' => $this->getIsSet($formElement['translated'], 'label'$formElement['name']),
  834.                     ]);
  835.                 }
  836.             }
  837.             if (!empty($formElement['mapping']) && isset($formElement['isUnique']) && $requestValue) {
  838.                 if (!empty($requestValue) && $formElement['isUnique']) {
  839.                     $repo $this->definitionInstanceRegistry->getRepository($this->form->getRelatedEntity());
  840.                     $criteria = new Criteria();
  841.                     $criteria->addFilter(new EqualsFilter($formElement['mapping'], $requestValue));
  842.                     if ($repo->search($criteria$this->getContext())->first()) {
  843.                         $this->violations[] = $this->trans('moorl-form-builder.general.duplicateError', [
  844.                             '%value%' => $requestValue,
  845.                         ]);
  846.                     }
  847.                 }
  848.             }
  849.         }
  850.         return $this->hasViolations();
  851.     }
  852.     public function inBlacklist($var): bool
  853.     {
  854.         if (!$this->blacklist || !is_array($this->blacklist)) {
  855.             return false;
  856.         }
  857.         $vars is_array($var) ? $var : [$var];
  858.         foreach ($vars as $item) {
  859.             foreach ($this->blacklist as $blacklistItem) {
  860.                 if (is_array($item)) {
  861.                     return $this->inBlacklist($item);
  862.                 } else {
  863.                     if (strpos(mb_strtolower($item), $blacklistItem) !== false) {
  864.                         return true;
  865.                     }
  866.                 }
  867.             }
  868.         }
  869.         return false;
  870.     }
  871.     /**
  872.      * @param UploadedFile $file
  873.      * @param string $technicalName
  874.      *
  875.      * Validates a single UploadedFile and add to binary attachment
  876.      */
  877.     private function validateFile(UploadedFile $filestring $technicalName): void
  878.     {
  879.         $formElement $this->form->getFormElement($technicalName);
  880.         if ($formElement->getType() !== 'upload') {
  881.             return;
  882.         }
  883.         if (!$this->mediaUploader->validate($file$formElement->getMediaType())) {
  884.             $this->violations[] = $this->trans('moorl-form-builder.general.mediaTypeError', [
  885.                 '%name%' => pathinfo($file->getClientOriginalName(), PATHINFO_FILENAME),
  886.                 '%extension%' => $file->getClientOriginalExtension(),
  887.                 '%expected%' => $formElement->getMediaType()
  888.             ]);
  889.         }
  890.         if (!$this->mediaUploader->checkSize($file)) {
  891.             $this->violations[] = $this->trans('moorl-form-builder.general.mediaSizeError', [
  892.                 '%size%' => $this->mediaUploader->getFileSize(),
  893.                 '%maxSize%' => $this->mediaUploader->getMaxFileSize(),
  894.             ]);
  895.         }
  896.         if ($this->hasViolations()) {
  897.             return;
  898.         }
  899.         $formElement->setValue($file->getClientOriginalName());
  900.         $this->form->addBinAttachment([
  901.             'content' => file_get_contents($file->getPathname()),
  902.             'fileName' => $file->getClientOriginalName(),
  903.             'mimeType' => $file->getMimeType(),
  904.         ]);
  905.     }
  906.     public function validateFiles(): bool
  907.     {
  908.         $request $this->requestStack->getCurrentRequest();
  909.         $this->mediaUploader->setMaxFileSize($this->form->getMaxFileSize() * 1000000); // MB to Bytes
  910.         foreach ($request->files as $name => $file) {
  911.             if (is_array($file)) {
  912.                 foreach ($file as $repeaterItem) {
  913.                     if (!is_array($repeaterItem)) {
  914.                         continue;
  915.                     }
  916.                     foreach ($repeaterItem as $repeaterName => $repeaterFile) {
  917.                         if ($repeaterFile instanceof UploadedFile) {
  918.                             $this->validateFile($repeaterFile$repeaterName);
  919.                         }
  920.                     }
  921.                 }
  922.             } elseif ($file instanceof UploadedFile) {
  923.                 $this->validateFile($file$name);
  924.             }
  925.         }
  926.         return $this->hasViolations();
  927.     }
  928.     private function getAttachment(UploadedFile $file): array
  929.     {
  930.         return [
  931.             'content' => file_get_contents($file->getPathname()),
  932.             'fileName' => $file->getClientOriginalName(),
  933.             'mimeType' => $file->getMimeType(),
  934.         ];
  935.     }
  936.     public function uploadFiles(): bool
  937.     {
  938.         // Attachment only if sendMail active
  939.         if ($this->form->getSendMail() && in_array($this->form->getType(), ['cms','snippet','customerRegister','productRequest'])) {
  940.             return false;
  941.         }
  942.         $request $this->requestStack->getCurrentRequest();
  943.         $mediaIds = [];
  944.         $formElements = [];
  945.         $userValues = [];
  946.         try {
  947.             foreach ($this->form->getData() as $formElement) {
  948.                 if ($formElement['type'] == 'upload' && $file $request->files->get($formElement['name'])) {
  949.                     $mediaId $this->mediaUploader->upload($file$this->form->getMediaFolderId(), $this->getContext());
  950.                     $formElement['value'] = $mediaId;
  951.                     $userValues[$formElement['name']] = $mediaId;
  952.                     $mediaIds[] = $mediaId;
  953.                     $this->addSessionUserMedia($mediaId);
  954.                 }
  955.                 $formElements[] = $formElement;
  956.             }
  957.             $this->form->setData($formElements);
  958.             if (count($mediaIds) > 0) {
  959.                 $this->getMediaCollection($mediaIds);
  960.             }
  961.         } catch (\Exception $exception) {
  962.             $this->violations[] = $this->trans('moorl-form-builder.general.internalError');
  963.             $this->violations[] = $this->trans($exception->getMessage());
  964.         }
  965.         $this->addSessionUserValues($userValues);
  966.         $this->form->setUserValues(array_merge($this->form->getUserValues(), $userValues));
  967.         return $this->hasViolations();
  968.     }
  969.     public function addSessionUserMedia(string $mediaId): void
  970.     {
  971.         $this->initSession();
  972.         $media $this->session->get('moorl-form-builder.media') ?: [];
  973.         $media[] = $mediaId;
  974.         $this->session->set('moorl-form-builder.media'$media);
  975.     }
  976.     public function setFormDataFromEntity(Entity $entity): void
  977.     {
  978.         $formElements $this->form->getData();
  979.         foreach ($formElements as &$formElement) {
  980.             if ($entity && isset($formElement['mapping']) && !empty($formElement['mapping'])) {
  981.                 try {
  982.                     if (isset($entity->getTranslated()[$formElement['mapping']])) {
  983.                         $formElement['value'] = $entity->getTranslated()[$formElement['mapping']];
  984.                     } else {
  985.                         $formElement['value'] = $entity->get($formElement['mapping']);
  986.                     }
  987.                 } catch (\Exception $exception) {
  988.                 }
  989.             }
  990.         }
  991.         $this->form->setData($formElements);
  992.         $criteria = new Criteria();
  993.         if ($entity instanceof ProductEntity) {
  994.             $criteria->addFilter(new EqualsFilter('productId'$entity->getId()));
  995.         }
  996.         $this->setFormElementsOptions($criteria);
  997.     }
  998.     public function getFormCriteria(): Criteria
  999.     {
  1000.         if (!$this->formCriteria && $this->getFormId()) {
  1001.             $this->setFormCriteria(new Criteria([$this->getFormId()]));
  1002.         }
  1003.         return $this->formCriteria;
  1004.     }
  1005.     public function setFormCriteria(Criteria $formCriteria): void
  1006.     {
  1007.         $this->formCriteria $formCriteria;
  1008.     }
  1009.     public function getFormById(string $formId): ?FormEntity
  1010.     {
  1011.         return $this->forms->get($formId);
  1012.     }
  1013.     public function setFormByCriteria(Criteria $criteria): void
  1014.     {
  1015.         $criteria->setLimit(1);
  1016.         $criteria->addFilter(new EqualsFilter('active'true));
  1017.         $this->setFormCriteria($criteria);
  1018.         $this->setForms();
  1019.     }
  1020.     public function initCurrentFormByAction(string $action)
  1021.     {
  1022.         $this->form $this->forms->getByAction($action);
  1023.         $this->_initCurrentForm();
  1024.     }
  1025.     public function initCurrentFormByProductId(string $productId)
  1026.     {
  1027.         $this->form $this->forms->getByProductId($productId);
  1028.         $this->_initCurrentForm();
  1029.     }
  1030.     public function initCurrentFormByTypeProductId(string $type, ?string $productId null)
  1031.     {
  1032.         $this->form $this->forms->getByTypeProductId($type$productId);
  1033.         $this->_initCurrentForm();
  1034.     }
  1035.     public function initCurrentFormByTypeProductProperty(string $typestring $property$value)
  1036.     {
  1037.         $this->form $this->forms->getByTypeProductProperty($type$property$value);
  1038.         $this->_initCurrentForm();
  1039.     }
  1040.     public function getForms(): ?FormCollection
  1041.     {
  1042.         return $this->forms;
  1043.     }
  1044.     public function setForms(): void
  1045.     {
  1046.         $criteria $this->getFormCriteria();
  1047.         $event = new FormCriteriaEvent($this->getContext(), $criteria);
  1048.         $this->eventDispatcher->dispatch($event);
  1049.         $formCollection $this->formRepo->search($criteria$this->getContext())->getEntities();
  1050.         if ($this->forms instanceof FormCollection) {
  1051.             $this->forms->merge($formCollection);
  1052.         } else {
  1053.             $this->forms $formCollection;
  1054.         }
  1055.     }
  1056.     public function initFormsByType(Context $contextstring $type$initializeDeep true): void
  1057.     {
  1058.         $criteria = new Criteria();
  1059.         $criteria->addFilter(new EqualsFilter('active'1));
  1060.         $criteria->addFilter(new EqualsFilter('type'$type));
  1061.         if ($this->getSalesChannelContext()) {
  1062.             $salesChannelId $this->getSalesChannelContext()->getSalesChannelId();
  1063.             $criteria->addFilter(new MultiFilter(MultiFilter::CONNECTION_OR, [
  1064.                 new EqualsFilter('salesChannelId'$salesChannelId),
  1065.                 new EqualsFilter('salesChannelId'null)
  1066.             ]));
  1067.         }
  1068.         $criteria->addAssociation('products.children');
  1069.         /* BUGFIX v6.4.6.0 */
  1070.         $productsCriteria $criteria->getAssociation('products');
  1071.         $productsCriteria->addFilter(new NotFilter(NotFilter::CONNECTION_OR, [
  1072.             new EqualsFilter('id'null)
  1073.         ]));
  1074.         $this->initForms($context$criteria$initializeDeep);
  1075.     }
  1076.     public function initFormsByTypeProductId(Context $contextstring $type, ?string $productId null$initializeDeep true): void
  1077.     {
  1078.         $criteria = new Criteria();
  1079.         $criteria->addFilter(new EqualsFilter('active'1));
  1080.         $criteria->addFilter(new EqualsFilter('type'$type));
  1081.         if ($this->getSalesChannelContext()) {
  1082.             $salesChannelId $this->getSalesChannelContext()->getSalesChannelId();
  1083.             $criteria->addFilter(new MultiFilter(MultiFilter::CONNECTION_OR, [
  1084.                 new EqualsFilter('salesChannelId'$salesChannelId),
  1085.                 new EqualsFilter('salesChannelId'null)
  1086.             ]));
  1087.         }
  1088.         $criteria->addAssociation('products.children');
  1089.         $productsCriteria $criteria->getAssociation('products');
  1090.         $productsCriteria->addFilter(new EqualsFilter('id'$productId));
  1091.         $this->initForms($context$criteria$initializeDeep);
  1092.     }
  1093.     public function initForms(Context $contextCriteria $criteria$initializeDeep true): void
  1094.     {
  1095.         $this->setContext($context);
  1096.         $this->setFormCriteria($criteria);
  1097.         $this->setForms();
  1098.         if ($initializeDeep) {
  1099.             foreach ($this->forms as $form) {
  1100.                 if (!$form->getInitialized()) {
  1101.                     $this->form $form;
  1102.                     $this->_initCurrentForm();
  1103.                 }
  1104.             }
  1105.         }
  1106.     }
  1107.     public function getPageReload(): bool
  1108.     {
  1109.         $data $this->requestStack->getCurrentRequest()->get('_reload');
  1110.         return $data true false;
  1111.     }
  1112.     public function unsetUserData(): void
  1113.     {
  1114.         $this->initSession();
  1115.         $this->session->remove('moorl-form-builder.values_' $this->form->getId());
  1116.     }
  1117.     public function unsetUserDataByFormId(string $formId): void
  1118.     {
  1119.         $this->initSession();
  1120.         $this->session->remove('moorl-form-builder.values_' $formId);
  1121.     }
  1122.     public function unsetAllUserData(): void
  1123.     {
  1124.         $this->initSession();
  1125.         foreach ($this->forms as $form) {
  1126.             $this->session->remove('moorl-form-builder.values_' $form->getId());
  1127.         }
  1128.     }
  1129.     public function autocomplete(string $formElementId$isArray true): array
  1130.     {
  1131.         $query $this->requestStack->getCurrentRequest()->query->get('q');
  1132.         if (strlen($query) < 3) {
  1133.             return [];
  1134.         }
  1135.         $this->initForm();
  1136.         $formElements $this->form->getData();
  1137.         $formElements array_values(array_filter($formElements, function ($v$k) use ($formElementId) {
  1138.             return $v['id'] == $formElementId;
  1139.         }, ARRAY_FILTER_USE_BOTH));
  1140.         if (count($formElements) == 0) {
  1141.             return [];
  1142.         }
  1143.         $formElement $formElements[0];
  1144.         if (isset($formElement['autocomplete']) && isset($formElement['autocomplete']['relatedEntity']) && isset($formElement['autocomplete']['property'])) {
  1145.             $relatedEntity $formElement['autocomplete']['relatedEntity'];
  1146.             $property $formElement['autocomplete']['property'];
  1147.             $repo $this->definitionInstanceRegistry->getRepository($relatedEntity);
  1148.             $criteria = new Criteria();
  1149.             $criteria->setLimit(10);
  1150.             $criteria->addFilter(new ContainsFilter($property$query));
  1151.             $criteria->addGroupField(new FieldGrouping($property));
  1152.             $event = new AutocompleteCriteriaEvent($this->getContext(), $criteria$formElement$this->form->getAction());
  1153.             $this->eventDispatcher->dispatch($event);
  1154.             $results = [];
  1155.             /* @var $entity Entity */
  1156.             if ($isArray) {
  1157.                 foreach ($repo->search($criteria$this->getContext())->getEntities() as $entity) {
  1158.                     $results[] = $entity->get($property);
  1159.                 }
  1160.             } else {
  1161.                 foreach ($repo->search($criteria$this->getContext())->getEntities() as $entity) {
  1162.                     $results[$entity->getId()] = $entity->get($property);
  1163.                 }
  1164.             }
  1165.             return $results;
  1166.         }
  1167.         return [];
  1168.     }
  1169.     public function removeUserMedia(string $mediaId): void
  1170.     {
  1171.         $customer $this->salesChannelContext->getCustomer();
  1172.         if ($customer) {
  1173.             $customerCustomFields $customer->getCustomFields();
  1174.             if (is_array($customerCustomFields)) {
  1175.                 foreach ($customerCustomFields as $name => $value) {
  1176.                     if ($value === $mediaId) {
  1177.                         $this->mediaUploader->delete($mediaId$this->getContext());
  1178.                         $payload = [
  1179.                             'id' => $customer->getId(),
  1180.                             'customFields' => [
  1181.                                 $name => null
  1182.                             ]
  1183.                         ];
  1184.                         $repository $this->definitionInstanceRegistry->getRepository('customer');
  1185.                         $repository->upsert([$payload], $this->context);
  1186.                         return;
  1187.                     }
  1188.                 }
  1189.             }
  1190.         }
  1191.         $this->initSession();
  1192.         $media $this->session->get('moorl-form-builder.media') ?: [];
  1193.         if (in_array($mediaId$media)) {
  1194.             $this->mediaUploader->delete($mediaId$this->getContext());
  1195.         } else {
  1196.             $this->violations[] = $this->trans('moorl-form-builder.general.internalError');
  1197.         }
  1198.     }
  1199.     public function fireForm()
  1200.     {
  1201.         $event = new FormFireEvent($this->getContext(), $this->form);
  1202.         $this->eventDispatcher->dispatch($event);
  1203.         if ($this->form->getSendMail()) {
  1204.             /* Send Mail to Shop Owner */
  1205.             $receivers explode(";"$this->form->getEmailReceiver());
  1206.             $receivers array_map('trim'$receivers);
  1207.             $receivers array_unique($receivers);
  1208.             foreach ($receivers as $receiver) {
  1209.                 $this->setMailEvent($receiver);
  1210.             }
  1211.             /* Send Mail to Customer */
  1212.             if ($this->form->getCustomerEmailReceiver() && !empty($this->form->getCustomerEmailReceiver())) {
  1213.                 $customerMailTemplateId $this->form->getCustomerMailTemplateId();
  1214.                 if ($customerMailTemplateId) {
  1215.                     $this->form->setMailTemplateId($customerMailTemplateId);
  1216.                 }
  1217.                 $receivers explode(";"$this->form->getCustomerEmailReceiver());
  1218.                 $receivers array_map('trim'$receivers);
  1219.                 $receivers array_unique($receivers);
  1220.                 foreach ($receivers as $receiver) {
  1221.                     $this->setMailEvent($receiver);
  1222.                 }
  1223.             }
  1224.         }
  1225.         if ($this->form->getInsertNewsletter()) {
  1226.             if ($this->requestStack->getCurrentRequest()->get('_insert_newsletter')) {
  1227.                 $userValues $this->form->getUserValues();
  1228.                 $this->newsletterService->subscribe($userValues$this->getSalesChannelContext(), false);
  1229.             }
  1230.         }
  1231.         if ($this->form->getInsertHistory()) {
  1232.             $this->insertHistory();
  1233.         }
  1234.         if ($this->form->getInsertDatabase()) {
  1235.             $this->insertDatabase();
  1236.         }
  1237.     }
  1238.     private function setMailEvent(?string $receiver null): void
  1239.     {
  1240.         if (!$receiver || empty($receiver)) {
  1241.             return;
  1242.         }
  1243.         $event = new CmsFormEvent(
  1244.             $this->getContext(),
  1245.             $this->getSalesChannelContext()->getSalesChannel()->getId(),
  1246.             new MailRecipientStruct([$receiver => $receiver]),
  1247.             $this->getCurrentForm(),
  1248.             $this->form->getMedias()
  1249.         );
  1250.         $this->eventDispatcher->dispatch(
  1251.             $event,
  1252.             MoorlFormBuilder::MAIL_TEMPLATE_MAIL_SEND_ACTION
  1253.         );
  1254.     }
  1255.     public function getCurrentForm(): ?FormEntity
  1256.     {
  1257.         return $this->form;
  1258.     }
  1259.     private function insertHistory(): void
  1260.     {
  1261.         $dataBag $this->requestStack->getCurrentRequest();
  1262.         $data = [
  1263.             'id' => Uuid::randomHex(),
  1264.             'formId' => $this->form->getId(),
  1265.             'salesChannelId' => $this->getSalesChannelContext()->getSalesChannel()->getId(),
  1266.             'name' => $this->form->getName(),
  1267.             'email' => $this->form->getEmailReceiver(),
  1268.             'requestData' => $dataBag->request->all(),
  1269.             'data' => $this->form->getUserValues(),
  1270.             'media' => $this->form->getMedias() ? $this->form->getMedias()->getIds() : null
  1271.         ];
  1272.         $repository $this->definitionInstanceRegistry->getRepository('moorl_form_history');
  1273.         $repository->create([$data], $this->getContext());
  1274.     }
  1275.     private function insertDatabase(): void
  1276.     {
  1277.         $entityName $this->form->getRelatedEntity();
  1278.         if (!$entityName) {
  1279.             return;
  1280.         }
  1281.         if ($entityName === 'customer' && $this->salesChannelContext && $this->salesChannelContext->getCustomer()) {
  1282.             $data = ['id' => $this->salesChannelContext->getCustomer()->getId()];
  1283.         } else {
  1284.             $data = ['id' => Uuid::randomHex()];
  1285.         }
  1286.         $userValues $this->form->getUserValues();
  1287.         foreach ($this->form->getData() as $formElement) {
  1288.             if (in_array($formElement['type'], ['checkbox','switch'])) {
  1289.                 if (isset($userValues[$formElement['name']])) {
  1290.                     $userValues[$formElement['name']] = 'true';
  1291.                 } else {
  1292.                     $userValues[$formElement['name']] = 'false';
  1293.                 }
  1294.             }
  1295.             if ($formElement['name'] && $formElement['mapping'] && isset($userValues[$formElement['name']])) {
  1296.                 if (!empty($userValues[$formElement['name']])) {
  1297.                     if ($userValues[$formElement['name']] === 'true') {
  1298.                         $data[$formElement['mapping']] = true;
  1299.                     } elseif ($userValues[$formElement['name']] === 'false') {
  1300.                         $data[$formElement['mapping']] = false;
  1301.                     } else {
  1302.                         $data[$formElement['mapping']] = $userValues[$formElement['name']];
  1303.                     }
  1304.                 }
  1305.             }
  1306.         }
  1307.         PluginHelpers::getNestedVar($data);
  1308.         $repository $this->definitionInstanceRegistry->getRepository($entityName);
  1309.         $repository->upsert([$data], $this->getContext());
  1310.     }
  1311.     public function extendFileTypeWhitelist(?array $whitelist): array
  1312.     {
  1313.         if (!$whitelist) {
  1314.             $whitelist $this->whitelist;
  1315.         }
  1316.         $whitelistConfig $this->systemConfigService->get('MoorlFormBuilder.config.fileExtensions');
  1317.         if ($whitelistConfig) {
  1318.             $whitelistConfig explode(","$whitelistConfig);
  1319.             $whitelistConfig array_map('trim'$whitelistConfig);
  1320.             if (is_array($whitelistConfig)) {
  1321.                 $whitelist array_merge($whitelist$whitelistConfig);
  1322.             }
  1323.         }
  1324.         return $whitelist;
  1325.     }
  1326.     public function sanitizeFormData()
  1327.     {
  1328.         // TODO: remove unused data to minify payloads etc
  1329.     }
  1330.     public function addFlashBag(array $violations): void
  1331.     {
  1332.         $this->initSession();
  1333.         if ($violations) {
  1334.             foreach ($violations as $violation) {
  1335.                 $this->session->getFlashBag()->add('danger'$violation['snippet']);
  1336.                 /* TODO: translate this
  1337.                 $this->trans($violation['snippet'], $violation['data']);
  1338.                 */
  1339.             }
  1340.         }
  1341.     }
  1342. }