vendor/sylius/sylius/src/Sylius/Bundle/UserBundle/Controller/UserController.php line 73

Open in your IDE?
  1. <?php
  2. /*
  3.  * This file is part of the Sylius package.
  4.  *
  5.  * (c) Paweł Jędrzejewski
  6.  *
  7.  * For the full copyright and license information, please view the LICENSE
  8.  * file that was distributed with this source code.
  9.  */
  10. declare(strict_types=1);
  11. namespace Sylius\Bundle\UserBundle\Controller;
  12. use FOS\RestBundle\View\View;
  13. use Sylius\Bundle\ResourceBundle\Controller\RequestConfiguration;
  14. use Sylius\Bundle\ResourceBundle\Controller\ResourceController;
  15. use Sylius\Bundle\UserBundle\Form\Model\ChangePassword;
  16. use Sylius\Bundle\UserBundle\Form\Model\PasswordReset;
  17. use Sylius\Bundle\UserBundle\Form\Model\PasswordResetRequest;
  18. use Sylius\Bundle\UserBundle\Form\Type\UserChangePasswordType;
  19. use Sylius\Bundle\UserBundle\Form\Type\UserRequestPasswordResetType;
  20. use Sylius\Bundle\UserBundle\Form\Type\UserResetPasswordType;
  21. use Sylius\Bundle\UserBundle\UserEvents;
  22. use Sylius\Component\User\Model\UserInterface;
  23. use Sylius\Component\User\Repository\UserRepositoryInterface;
  24. use Sylius\Component\User\Security\Generator\GeneratorInterface;
  25. use Symfony\Component\EventDispatcher\GenericEvent;
  26. use Symfony\Component\Form\FormInterface;
  27. use Symfony\Component\HttpFoundation\RedirectResponse;
  28. use Symfony\Component\HttpFoundation\Request;
  29. use Symfony\Component\HttpFoundation\Response;
  30. use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
  31. use Symfony\Component\Security\Core\Exception\AccessDeniedException;
  32. use Webmozart\Assert\Assert;
  33. class UserController extends ResourceController
  34. {
  35.     public function changePasswordAction(Request $request): Response
  36.     {
  37.         $configuration $this->requestConfigurationFactory->create($this->metadata$request);
  38.         if (!$this->container->get('security.authorization_checker')->isGranted('IS_AUTHENTICATED_REMEMBERED')) {
  39.             throw new AccessDeniedException('You have to be registered user to access this section.');
  40.         }
  41.         $user $this->container->get('security.token_storage')->getToken()->getUser();
  42.         $changePassword = new ChangePassword();
  43.         $formType $this->getSyliusAttribute($request'form'UserChangePasswordType::class);
  44.         $form $this->createResourceForm($configuration$formType$changePassword);
  45.         if (in_array($request->getMethod(), ['POST''PUT''PATCH'], true) && $form->handleRequest($request)->isValid()) {
  46.             return $this->handleChangePassword($request$configuration$user$changePassword->getNewPassword());
  47.         }
  48.         if (!$configuration->isHtmlRequest()) {
  49.             return $this->viewHandler->handle($configurationView::create($formResponse::HTTP_BAD_REQUEST));
  50.         }
  51.         return $this->container->get('templating')->renderResponse(
  52.             $configuration->getTemplate('changePassword.html'),
  53.             ['form' => $form->createView()]
  54.         );
  55.     }
  56.     public function requestPasswordResetTokenAction(Request $request): Response
  57.     {
  58.         /** @var GeneratorInterface $generator */
  59.         $generator $this->container->get(sprintf('sylius.%s.token_generator.password_reset'$this->metadata->getName()));
  60.         return $this->prepareResetPasswordRequest($request$generatorUserEvents::REQUEST_RESET_PASSWORD_TOKEN);
  61.     }
  62.     public function requestPasswordResetPinAction(Request $request): Response
  63.     {
  64.         /** @var GeneratorInterface $generator */
  65.         $generator $this->container->get(sprintf('sylius.%s.pin_generator.password_reset'$this->metadata->getName()));
  66.         return $this->prepareResetPasswordRequest($request$generatorUserEvents::REQUEST_RESET_PASSWORD_PIN);
  67.     }
  68.     public function resetPasswordAction(Request $requeststring $token): Response
  69.     {
  70.         $configuration $this->requestConfigurationFactory->create($this->metadata$request);
  71.         /** @var UserInterface $user */
  72.         $user $this->repository->findOneBy(['passwordResetToken' => $token]);
  73.         if (null === $user) {
  74.             throw new NotFoundHttpException('Token not found.');
  75.         }
  76.         $resetting $this->metadata->getParameter('resetting');
  77.         $lifetime = new \DateInterval($resetting['token']['ttl']);
  78.         if (!$user->isPasswordRequestNonExpired($lifetime)) {
  79.             return $this->handleExpiredToken($request$configuration$user);
  80.         }
  81.         $passwordReset = new PasswordReset();
  82.         $formType $this->getSyliusAttribute($request'form'UserResetPasswordType::class);
  83.         $form $this->createResourceForm($configuration$formType$passwordReset);
  84.         if (in_array($request->getMethod(), ['POST''PUT''PATCH'], true) && $form->handleRequest($request)->isValid()) {
  85.             return $this->handleResetPassword($request$configuration$user$passwordReset->getPassword());
  86.         }
  87.         if (!$configuration->isHtmlRequest()) {
  88.             return $this->viewHandler->handle($configurationView::create($formResponse::HTTP_BAD_REQUEST));
  89.         }
  90.         return $this->container->get('templating')->renderResponse(
  91.             $configuration->getTemplate('resetPassword.html'),
  92.             [
  93.                 'form' => $form->createView(),
  94.                 'user' => $user,
  95.             ]
  96.         );
  97.     }
  98.     public function verifyAction(Request $requeststring $token): Response
  99.     {
  100.         $configuration $this->requestConfigurationFactory->create($this->metadata$request);
  101.         $redirectRoute $this->getSyliusAttribute($request'redirect'null);
  102.         $response $this->redirectToRoute($redirectRoute);
  103.         /** @var UserInterface $user */
  104.         $user $this->repository->findOneBy(['emailVerificationToken' => $token]);
  105.         if (null === $user) {
  106.             if (!$configuration->isHtmlRequest()) {
  107.                 return $this->viewHandler->handle($configurationView::create($configurationResponse::HTTP_BAD_REQUEST));
  108.             }
  109.             $this->addTranslatedFlash('error''sylius.user.verify_email_by_invalid_token');
  110.             return $this->redirectToRoute($redirectRoute);
  111.         }
  112.         $user->setVerifiedAt(new \DateTime());
  113.         $user->setEmailVerificationToken(null);
  114.         $user->enable();
  115.         $eventDispatcher $this->container->get('event_dispatcher');
  116.         $eventDispatcher->dispatch(UserEvents::PRE_EMAIL_VERIFICATION, new GenericEvent($user));
  117.         $this->manager->flush();
  118.         $eventDispatcher->dispatch(UserEvents::POST_EMAIL_VERIFICATION, new GenericEvent($user));
  119.         if (!$configuration->isHtmlRequest()) {
  120.             return $this->viewHandler->handle($configurationView::create($user));
  121.         }
  122.         $flashMessage $this->getSyliusAttribute($request'flash''sylius.user.verify_email');
  123.         $this->addTranslatedFlash('success'$flashMessage);
  124.         return $response;
  125.     }
  126.     public function requestVerificationTokenAction(Request $request): Response
  127.     {
  128.         $configuration $this->requestConfigurationFactory->create($this->metadata$request);
  129.         $redirectRoute $this->getSyliusAttribute($request'redirect''referer');
  130.         $user $this->getUser();
  131.         if (null === $user) {
  132.             if (!$configuration->isHtmlRequest()) {
  133.                 return $this->viewHandler->handle($configurationView::create($configurationResponse::HTTP_UNAUTHORIZED));
  134.             }
  135.             $this->addTranslatedFlash('notice''sylius.user.verify_no_user');
  136.             return $this->redirectHandler->redirectToRoute($configuration$redirectRoute);
  137.         }
  138.         if (null !== $user->getVerifiedAt()) {
  139.             if (!$configuration->isHtmlRequest()) {
  140.                 return $this->viewHandler->handle($configurationView::create($configurationResponse::HTTP_BAD_REQUEST));
  141.             }
  142.             $this->addTranslatedFlash('notice''sylius.user.verify_verified_email');
  143.             return $this->redirectHandler->redirectToRoute($configuration$redirectRoute);
  144.         }
  145.         /** @var GeneratorInterface $tokenGenerator */
  146.         $tokenGenerator $this->container->get(sprintf('sylius.%s.token_generator.email_verification'$this->metadata->getName()));
  147.         $user->setEmailVerificationToken($tokenGenerator->generate());
  148.         $this->manager->flush();
  149.         $eventDispatcher $this->container->get('event_dispatcher');
  150.         $eventDispatcher->dispatch(UserEvents::REQUEST_VERIFICATION_TOKEN, new GenericEvent($user));
  151.         if (!$configuration->isHtmlRequest()) {
  152.             return $this->viewHandler->handle($configurationView::create(nullResponse::HTTP_NO_CONTENT));
  153.         }
  154.         $this->addTranslatedFlash('success''sylius.user.verify_email_request');
  155.         return $this->redirectHandler->redirectToRoute($configuration$redirectRoute);
  156.     }
  157.     protected function prepareResetPasswordRequest(Request $requestGeneratorInterface $generatorstring $senderEvent): Response
  158.     {
  159.         $configuration $this->requestConfigurationFactory->create($this->metadata$request);
  160.         $passwordReset = new PasswordResetRequest();
  161.         $formType $this->getSyliusAttribute($request'form'UserRequestPasswordResetType::class);
  162.         $form $this->createResourceForm($configuration$formType$passwordReset);
  163.         $template $this->getSyliusAttribute($request'template'null);
  164.         if ($configuration->isHtmlRequest()) {
  165.             Assert::notNull($template'Template is not configured.');
  166.         }
  167.         if (in_array($request->getMethod(), ['POST''PUT''PATCH'], true) && $form->handleRequest($request)->isValid()) {
  168.             /** @var UserRepositoryInterface $userRepository */
  169.             $userRepository $this->repository;
  170.             Assert::isInstanceOf($userRepositoryUserRepositoryInterface::class);
  171.             $user $userRepository->findOneByEmail($passwordReset->getEmail());
  172.             if (null !== $user) {
  173.                 $this->handleResetPasswordRequest($generator$user$senderEvent);
  174.             }
  175.             if (!$configuration->isHtmlRequest()) {
  176.                 return $this->viewHandler->handle($configurationView::create(nullResponse::HTTP_NO_CONTENT));
  177.             }
  178.             $this->addTranslatedFlash('success''sylius.user.reset_password_request');
  179.             $redirectRoute $this->getSyliusAttribute($request'redirect'null);
  180.             Assert::notNull($redirectRoute'Redirect is not configured.');
  181.             if (is_array($redirectRoute)) {
  182.                 return $this->redirectHandler->redirectToRoute(
  183.                     $configuration,
  184.                     $configuration->getParameters()->get('redirect')['route'],
  185.                     $configuration->getParameters()->get('redirect')['parameters']
  186.                 );
  187.             }
  188.             return $this->redirectHandler->redirectToRoute($configuration$redirectRoute);
  189.         }
  190.         if (!$configuration->isHtmlRequest()) {
  191.             return $this->viewHandler->handle($configurationView::create($formResponse::HTTP_BAD_REQUEST));
  192.         }
  193.         return $this->container->get('templating')->renderResponse(
  194.             $template,
  195.             [
  196.                 'form' => $form->createView(),
  197.             ]
  198.         );
  199.     }
  200.     /**
  201.      * {@inheritdoc}
  202.      */
  203.     protected function addTranslatedFlash(string $typestring $message): void
  204.     {
  205.         $translator $this->container->get('translator');
  206.         $this->container->get('session')->getFlashBag()->add($type$translator->trans($message, [], 'flashes'));
  207.     }
  208.     /**
  209.      * @param object $object
  210.      */
  211.     protected function createResourceForm(
  212.         RequestConfiguration $configuration,
  213.         string $type,
  214.         $object
  215.     ): FormInterface {
  216.         if (!$configuration->isHtmlRequest()) {
  217.             return $this->container->get('form.factory')->createNamed(''$type$object, ['csrf_protection' => false]);
  218.         }
  219.         return $this->container->get('form.factory')->create($type$object);
  220.     }
  221.     protected function handleExpiredToken(Request $requestRequestConfiguration $configurationUserInterface $user): Response
  222.     {
  223.         $user->setPasswordResetToken(null);
  224.         $user->setPasswordRequestedAt(null);
  225.         $this->manager->flush();
  226.         if (!$configuration->isHtmlRequest()) {
  227.             return $this->viewHandler->handle($configurationView::create($userResponse::HTTP_BAD_REQUEST));
  228.         }
  229.         $this->addTranslatedFlash('error''sylius.user.expire_password_reset_token');
  230.         $redirectRouteName $this->getSyliusAttribute($request'redirect'null);
  231.         Assert::notNull($redirectRouteName'Redirect is not configured.');
  232.         return new RedirectResponse($this->container->get('router')->generate($redirectRouteName));
  233.     }
  234.     protected function handleResetPasswordRequest(
  235.         GeneratorInterface $generator,
  236.         UserInterface $user,
  237.         string $senderEvent
  238.     ): void {
  239.         $user->setPasswordResetToken($generator->generate());
  240.         $user->setPasswordRequestedAt(new \DateTime());
  241.         // I have to use doctrine manager directly, because domain manager functions add a flash messages. I can't get rid of them.
  242.         $manager $this->container->get('doctrine.orm.default_entity_manager');
  243.         $manager->persist($user);
  244.         $manager->flush();
  245.         $dispatcher $this->container->get('event_dispatcher');
  246.         $dispatcher->dispatch($senderEvent, new GenericEvent($user));
  247.     }
  248.     protected function handleResetPassword(
  249.         Request $request,
  250.         RequestConfiguration $configuration,
  251.         UserInterface $user,
  252.         string $newPassword
  253.     ): Response {
  254.         $user->setPlainPassword($newPassword);
  255.         $user->setPasswordResetToken(null);
  256.         $user->setPasswordRequestedAt(null);
  257.         $dispatcher $this->container->get('event_dispatcher');
  258.         $dispatcher->dispatch(UserEvents::PRE_PASSWORD_RESET, new GenericEvent($user));
  259.         $this->manager->flush();
  260.         $this->addTranslatedFlash('success''sylius.user.reset_password');
  261.         $dispatcher->dispatch(UserEvents::POST_PASSWORD_RESET, new GenericEvent($user));
  262.         if (!$configuration->isHtmlRequest()) {
  263.             return $this->viewHandler->handle($configurationView::create(nullResponse::HTTP_NO_CONTENT));
  264.         }
  265.         $redirectRouteName $this->getSyliusAttribute($request'redirect'null);
  266.         Assert::notNull($redirectRouteName'Redirect is not configured.');
  267.         return new RedirectResponse($this->container->get('router')->generate($redirectRouteName));
  268.     }
  269.     protected function handleChangePassword(
  270.         Request $request,
  271.         RequestConfiguration $configuration,
  272.         UserInterface $user,
  273.         string $newPassword
  274.     ): Response {
  275.         $user->setPlainPassword($newPassword);
  276.         $dispatcher $this->container->get('event_dispatcher');
  277.         $dispatcher->dispatch(UserEvents::PRE_PASSWORD_CHANGE, new GenericEvent($user));
  278.         $this->manager->flush();
  279.         $this->addTranslatedFlash('success''sylius.user.change_password');
  280.         $dispatcher->dispatch(UserEvents::POST_PASSWORD_CHANGE, new GenericEvent($user));
  281.         if (!$configuration->isHtmlRequest()) {
  282.             return $this->viewHandler->handle($configurationView::create(nullResponse::HTTP_NO_CONTENT));
  283.         }
  284.         $redirectRouteName $this->getSyliusAttribute($request'redirect'null);
  285.         Assert::notNull($redirectRouteName'Redirect is not configured.');
  286.         return new RedirectResponse($this->container->get('router')->generate($redirectRouteName));
  287.     }
  288.     protected function getUser(): ?UserInterface
  289.     {
  290.         $user parent::getUser();
  291.         $authorizationChecker $this->container->get('security.authorization_checker');
  292.         if (
  293.             $authorizationChecker->isGranted('IS_AUTHENTICATED_REMEMBERED') &&
  294.             $user instanceof UserInterface
  295.         ) {
  296.             return $user;
  297.         }
  298.         return null;
  299.     }
  300.     private function getSyliusAttribute(Request $requeststring $attribute$default null)
  301.     {
  302.         $attributes $request->attributes->get('_sylius');
  303.         return $attributes[$attribute] ?? $default;
  304.     }
  305. }