vendor/shopware/storefront/Controller/RegisterController.php line 163

Open in your IDE?
  1. <?php declare(strict_types=1);
  2. namespace Shopware\Storefront\Controller;
  3. use Shopware\Core\Checkout\Cart\SalesChannel\CartService;
  4. use Shopware\Core\Checkout\Customer\CustomerEntity;
  5. use Shopware\Core\Checkout\Customer\Exception\CustomerAlreadyConfirmedException;
  6. use Shopware\Core\Checkout\Customer\Exception\CustomerNotFoundByHashException;
  7. use Shopware\Core\Checkout\Customer\SalesChannel\AbstractRegisterConfirmRoute;
  8. use Shopware\Core\Checkout\Customer\SalesChannel\AbstractRegisterRoute;
  9. use Shopware\Core\Content\Newsletter\Exception\SalesChannelDomainNotFoundException;
  10. use Shopware\Core\Framework\DataAbstractionLayer\EntityRepositoryInterface;
  11. use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
  12. use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\EqualsFilter;
  13. use Shopware\Core\Framework\Feature;
  14. use Shopware\Core\Framework\Log\Package;
  15. use Shopware\Core\Framework\Routing\Annotation\RouteScope;
  16. use Shopware\Core\Framework\Routing\Annotation\Since;
  17. use Shopware\Core\Framework\Routing\Exception\MissingRequestParameterException;
  18. use Shopware\Core\Framework\Validation\DataBag\DataBag;
  19. use Shopware\Core\Framework\Validation\DataBag\QueryDataBag;
  20. use Shopware\Core\Framework\Validation\DataBag\RequestDataBag;
  21. use Shopware\Core\Framework\Validation\DataValidationDefinition;
  22. use Shopware\Core\Framework\Validation\Exception\ConstraintViolationException;
  23. use Shopware\Core\System\SalesChannel\SalesChannelContext;
  24. use Shopware\Core\System\SystemConfig\SystemConfigService;
  25. use Shopware\Storefront\Framework\AffiliateTracking\AffiliateTrackingListener;
  26. use Shopware\Storefront\Framework\Captcha\Annotation\Captcha;
  27. use Shopware\Storefront\Framework\Routing\Annotation\NoStore;
  28. use Shopware\Storefront\Framework\Routing\RequestTransformer;
  29. use Shopware\Storefront\Page\Account\CustomerGroupRegistration\AbstractCustomerGroupRegistrationPageLoader;
  30. use Shopware\Storefront\Page\Account\CustomerGroupRegistration\CustomerGroupRegistrationPageLoadedHook;
  31. use Shopware\Storefront\Page\Account\Login\AccountLoginPageLoader;
  32. use Shopware\Storefront\Page\Account\Register\AccountRegisterPageLoadedHook;
  33. use Shopware\Storefront\Page\Checkout\Register\CheckoutRegisterPageLoadedHook;
  34. use Shopware\Storefront\Page\Checkout\Register\CheckoutRegisterPageLoader;
  35. use Symfony\Component\HttpFoundation\Request;
  36. use Symfony\Component\HttpFoundation\Response;
  37. use Symfony\Component\HttpFoundation\Session\SessionInterface;
  38. use Symfony\Component\Routing\Annotation\Route;
  39. use Symfony\Component\Validator\Constraints\EqualTo;
  40. use Symfony\Component\Validator\Constraints\NotBlank;
  41. /**
  42.  * @Route(defaults={"_routeScope"={"storefront"}})
  43.  *
  44.  * @deprecated tag:v6.5.0 - reason:becomes-internal - Will be internal
  45.  */
  46. #[Package('customer-order')]
  47. class RegisterController extends StorefrontController
  48. {
  49.     private AccountLoginPageLoader $loginPageLoader;
  50.     private CartService $cartService;
  51.     private CheckoutRegisterPageLoader $registerPageLoader;
  52.     private SystemConfigService $systemConfigService;
  53.     private EntityRepositoryInterface $customerRepository;
  54.     private AbstractCustomerGroupRegistrationPageLoader $customerGroupRegistrationPageLoader;
  55.     private AbstractRegisterRoute $registerRoute;
  56.     private AbstractRegisterConfirmRoute $registerConfirmRoute;
  57.     private EntityRepositoryInterface $domainRepository;
  58.     /**
  59.      * @internal
  60.      */
  61.     public function __construct(
  62.         AccountLoginPageLoader $loginPageLoader,
  63.         AbstractRegisterRoute $registerRoute,
  64.         AbstractRegisterConfirmRoute $registerConfirmRoute,
  65.         CartService $cartService,
  66.         CheckoutRegisterPageLoader $registerPageLoader,
  67.         SystemConfigService $systemConfigService,
  68.         EntityRepositoryInterface $customerRepository,
  69.         AbstractCustomerGroupRegistrationPageLoader $customerGroupRegistrationPageLoader,
  70.         EntityRepositoryInterface $domainRepository
  71.     ) {
  72.         $this->loginPageLoader $loginPageLoader;
  73.         $this->cartService $cartService;
  74.         $this->registerPageLoader $registerPageLoader;
  75.         $this->systemConfigService $systemConfigService;
  76.         $this->customerRepository $customerRepository;
  77.         $this->customerGroupRegistrationPageLoader $customerGroupRegistrationPageLoader;
  78.         $this->registerRoute $registerRoute;
  79.         $this->registerConfirmRoute $registerConfirmRoute;
  80.         $this->domainRepository $domainRepository;
  81.     }
  82.     /**
  83.      * @Since("6.0.0.0")
  84.      * @Route("/account/register", name="frontend.account.register.page", methods={"GET"})
  85.      * @NoStore
  86.      */
  87.     public function accountRegisterPage(Request $requestRequestDataBag $dataSalesChannelContext $context): Response
  88.     {
  89.         if ($context->getCustomer() && $context->getCustomer()->getGuest()) {
  90.             return $this->redirectToRoute('frontend.account.logout.page');
  91.         }
  92.         if ($context->getCustomer()) {
  93.             return $this->redirectToRoute('frontend.account.home.page');
  94.         }
  95.         $redirect $request->query->get('redirectTo''frontend.account.home.page');
  96.         $page $this->loginPageLoader->load($request$context);
  97.         $this->hook(new AccountRegisterPageLoadedHook($page$context));
  98.         return $this->renderStorefront('@Storefront/storefront/page/account/register/index.html.twig', [
  99.             'redirectTo' => $redirect,
  100.             'redirectParameters' => $request->get('redirectParameters'json_encode([])),
  101.             'page' => $page,
  102.             'data' => $data,
  103.         ]);
  104.     }
  105.     /**
  106.      * @Since("6.3.1.0")
  107.      * @Route("/customer-group-registration/{customerGroupId}", name="frontend.account.customer-group-registration.page", methods={"GET"})
  108.      * @NoStore
  109.      */
  110.     public function customerGroupRegistration(string $customerGroupIdRequest $requestRequestDataBag $dataSalesChannelContext $context): Response
  111.     {
  112.         if ($context->getCustomer() && $context->getCustomer()->getGuest()) {
  113.             return $this->redirectToRoute('frontend.account.logout.page');
  114.         }
  115.         if ($context->getCustomer()) {
  116.             return $this->redirectToRoute('frontend.account.home.page');
  117.         }
  118.         $redirect $request->query->get('redirectTo''frontend.account.home.page');
  119.         $page $this->customerGroupRegistrationPageLoader->load($request$context);
  120.         if ($page->getGroup()->getTranslation('registrationOnlyCompanyRegistration')) {
  121.             $data->set('accountType'CustomerEntity::ACCOUNT_TYPE_BUSINESS);
  122.         }
  123.         $this->hook(new CustomerGroupRegistrationPageLoadedHook($page$context));
  124.         return $this->renderStorefront('@Storefront/storefront/page/account/customer-group-register/index.html.twig', [
  125.             'redirectTo' => $redirect,
  126.             'redirectParameters' => $request->get('redirectParameters'json_encode([])),
  127.             'errorParameters' => json_encode(['customerGroupId' => $customerGroupId]),
  128.             'page' => $page,
  129.             'data' => $data,
  130.         ]);
  131.     }
  132.     /**
  133.      * @Since("6.0.0.0")
  134.      * @Route("/checkout/register", name="frontend.checkout.register.page", options={"seo"="false"}, methods={"GET"})
  135.      * @NoStore
  136.      */
  137.     public function checkoutRegisterPage(Request $requestRequestDataBag $dataSalesChannelContext $context): Response
  138.     {
  139.         /** @var string $redirect */
  140.         $redirect $request->get('redirectTo''frontend.checkout.confirm.page');
  141.         if ($context->getCustomer()) {
  142.             return $this->redirectToRoute($redirect);
  143.         }
  144.         if ($this->cartService->getCart($context->getToken(), $context)->getLineItems()->count() === 0) {
  145.             return $this->redirectToRoute('frontend.checkout.cart.page');
  146.         }
  147.         $page $this->registerPageLoader->load($request$context);
  148.         $this->hook(new CheckoutRegisterPageLoadedHook($page$context));
  149.         return $this->renderStorefront(
  150.             '@Storefront/storefront/page/checkout/address/index.html.twig',
  151.             ['redirectTo' => $redirect'page' => $page'data' => $data]
  152.         );
  153.     }
  154.     /**
  155.      * @Since("6.0.0.0")
  156.      * @Route("/account/register", name="frontend.account.register.save", methods={"POST"}, defaults={"_captcha"=true})
  157.      */
  158.     public function register(Request $requestRequestDataBag $dataSalesChannelContext $context): Response
  159.     {
  160.         if ($context->getCustomer()) {
  161.             return $this->redirectToRoute('frontend.account.home.page');
  162.         }
  163.         try {
  164.             if (!$data->has('differentShippingAddress')) {
  165.                 $data->remove('shippingAddress');
  166.             }
  167.             $data->set('storefrontUrl'$this->getConfirmUrl($context$request));
  168.             $data $this->prepareAffiliateTracking($data$request->getSession());
  169.             if (Feature::isActive('FEATURE_NEXT_16236')) {
  170.                 if ($data->getBoolean('createCustomerAccount')) {
  171.                     $data->set('guest'false);
  172.                 } else {
  173.                     $data->set('guest'true);
  174.                 }
  175.             } else {
  176.                 if ($data->has('guest')) {
  177.                     $data->set('guest'$data->has('guest'));
  178.                 }
  179.             }
  180.             $this->registerRoute->register(
  181.                 $data->toRequestDataBag(),
  182.                 $context,
  183.                 false,
  184.                 $this->getAdditionalRegisterValidationDefinitions($data$context)
  185.             );
  186.         } catch (ConstraintViolationException $formViolations) {
  187.             if (!$request->request->has('errorRoute')) {
  188.                 throw new MissingRequestParameterException('errorRoute');
  189.             }
  190.             $params $this->decodeParam($request'errorParameters');
  191.             // this is to show the correct form because we have different usecases (account/register||checkout/register)
  192.             return $this->forwardToRoute($request->get('errorRoute'), ['formViolations' => $formViolations], $params);
  193.         }
  194.         if ($this->isDoubleOptIn($data$context)) {
  195.             return $this->redirectToRoute('frontend.account.register.page');
  196.         }
  197.         return $this->createActionResponse($request);
  198.     }
  199.     /**
  200.      * @Since("6.1.0.0")
  201.      * @Route("/registration/confirm", name="frontend.account.register.mail", methods={"GET"})
  202.      */
  203.     public function confirmRegistration(SalesChannelContext $contextQueryDataBag $queryDataBag): Response
  204.     {
  205.         try {
  206.             $customerId $this->registerConfirmRoute
  207.                 ->confirm($queryDataBag->toRequestDataBag(), $context)
  208.                 ->getCustomer()
  209.                 ->getId();
  210.         } catch (CustomerNotFoundByHashException CustomerAlreadyConfirmedException ConstraintViolationException $exception) {
  211.             $this->addFlash(self::DANGER$this->trans('account.confirmationIsAlreadyDone'));
  212.             return $this->redirectToRoute('frontend.account.register.page');
  213.         }
  214.         /** @var CustomerEntity $customer */
  215.         $customer $this->customerRepository->search(new Criteria([$customerId]), $context->getContext())->first();
  216.         if ($customer->getGuest()) {
  217.             $this->addFlash(self::SUCCESS$this->trans('account.doubleOptInMailConfirmationSuccessfully'));
  218.             return $this->redirectToRoute('frontend.checkout.confirm.page');
  219.         }
  220.         $this->addFlash(self::SUCCESS$this->trans('account.doubleOptInRegistrationSuccessfully'));
  221.         if ($redirectTo $queryDataBag->get('redirectTo')) {
  222.             return $this->redirectToRoute($redirectTo);
  223.         }
  224.         return $this->redirectToRoute('frontend.account.home.page');
  225.     }
  226.     private function isDoubleOptIn(DataBag $dataSalesChannelContext $context): bool
  227.     {
  228.         $creatueCustomerAccount $data->getBoolean('createCustomerAccount');
  229.         if (Feature::isActive('FEATURE_NEXT_16236')) {
  230.             $configKey $creatueCustomerAccount
  231.                 'core.loginRegistration.doubleOptInRegistration'
  232.                 'core.loginRegistration.doubleOptInGuestOrder';
  233.         } else {
  234.             $configKey $data->has('guest')
  235.                 ? 'core.loginRegistration.doubleOptInGuestOrder'
  236.                 'core.loginRegistration.doubleOptInRegistration';
  237.         }
  238.         $doubleOptInRequired $this->systemConfigService
  239.             ->get($configKey$context->getSalesChannel()->getId());
  240.         if (!$doubleOptInRequired) {
  241.             return false;
  242.         }
  243.         if (Feature::isActive('FEATURE_NEXT_16236')) {
  244.             if ($creatueCustomerAccount) {
  245.                 $this->addFlash(self::SUCCESS$this->trans('account.optInRegistrationAlert'));
  246.                 return true;
  247.             }
  248.             $this->addFlash(self::SUCCESS$this->trans('account.optInGuestAlert'));
  249.             return true;
  250.         }
  251.         if ($data->has('guest')) {
  252.             $this->addFlash(self::SUCCESS$this->trans('account.optInGuestAlert'));
  253.             return true;
  254.         }
  255.         $this->addFlash(self::SUCCESS$this->trans('account.optInRegistrationAlert'));
  256.         return true;
  257.     }
  258.     private function getAdditionalRegisterValidationDefinitions(DataBag $dataSalesChannelContext $context): DataValidationDefinition
  259.     {
  260.         $definition = new DataValidationDefinition('storefront.confirmation');
  261.         $definition->add('salutationId', new NotBlank());
  262.         if ($this->systemConfigService->get('core.loginRegistration.requireEmailConfirmation'$context->getSalesChannel()->getId())) {
  263.             $definition->add('emailConfirmation', new NotBlank(), new EqualTo([
  264.                 'value' => $data->get('email'),
  265.             ]));
  266.         }
  267.         if ($data->has('guest')) {
  268.             return $definition;
  269.         }
  270.         if ($this->systemConfigService->get('core.loginRegistration.requirePasswordConfirmation'$context->getSalesChannel()->getId())) {
  271.             $definition->add('passwordConfirmation', new NotBlank(), new EqualTo([
  272.                 'value' => $data->get('password'),
  273.             ]));
  274.         }
  275.         return $definition;
  276.     }
  277.     private function prepareAffiliateTracking(RequestDataBag $dataSessionInterface $session): DataBag
  278.     {
  279.         $affiliateCode $session->get(AffiliateTrackingListener::AFFILIATE_CODE_KEY);
  280.         $campaignCode $session->get(AffiliateTrackingListener::CAMPAIGN_CODE_KEY);
  281.         if ($affiliateCode !== null && $campaignCode !== null) {
  282.             $data->add([
  283.                 AffiliateTrackingListener::AFFILIATE_CODE_KEY => $affiliateCode,
  284.                 AffiliateTrackingListener::CAMPAIGN_CODE_KEY => $campaignCode,
  285.             ]);
  286.         }
  287.         return $data;
  288.     }
  289.     private function getConfirmUrl(SalesChannelContext $contextRequest $request): string
  290.     {
  291.         /** @var string $domainUrl */
  292.         $domainUrl $this->systemConfigService
  293.             ->get('core.loginRegistration.doubleOptInDomain'$context->getSalesChannel()->getId());
  294.         if ($domainUrl) {
  295.             return $domainUrl;
  296.         }
  297.         $domainUrl $request->attributes->get(RequestTransformer::STOREFRONT_URL);
  298.         if ($domainUrl) {
  299.             return $domainUrl;
  300.         }
  301.         $criteria = new Criteria();
  302.         $criteria->addFilter(new EqualsFilter('salesChannelId'$context->getSalesChannel()->getId()));
  303.         $criteria->setLimit(1);
  304.         $domain $this->domainRepository
  305.             ->search($criteria$context->getContext())
  306.             ->first();
  307.         if (!$domain) {
  308.             throw new SalesChannelDomainNotFoundException($context->getSalesChannel());
  309.         }
  310.         return $domain->getUrl();
  311.     }
  312. }