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

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 new Response($this->container->get('twig')->render(
  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|null $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 new Response($this->container->get('twig')->render(
  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|null $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(new GenericEvent($user), UserEvents::PRE_EMAIL_VERIFICATION);
  117.         $this->manager->flush();
  118.         $eventDispatcher->dispatch(new GenericEvent($user), UserEvents::POST_EMAIL_VERIFICATION);
  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(new GenericEvent($user), UserEvents::REQUEST_VERIFICATION_TOKEN);
  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.             $userRepository $this->repository;
  169.             /** @var UserRepositoryInterface $userRepository */
  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 new Response($this->container->get('twig')->render(
  194.             $template,
  195.             [
  196.                 'form' => $form->createView(),
  197.             ]
  198.         ));
  199.     }
  200.     protected function addTranslatedFlash(string $typestring $message): void
  201.     {
  202.         $translator $this->container->get('translator');
  203.         $this->container->get('session')->getFlashBag()->add($type$translator->trans($message, [], 'flashes'));
  204.     }
  205.     /**
  206.      * @param object $object
  207.      */
  208.     protected function createResourceForm(
  209.         RequestConfiguration $configuration,
  210.         string $type,
  211.         $object
  212.     ): FormInterface {
  213.         if (!$configuration->isHtmlRequest()) {
  214.             return $this->container->get('form.factory')->createNamed(''$type$object, ['csrf_protection' => false]);
  215.         }
  216.         return $this->container->get('form.factory')->create($type$object);
  217.     }
  218.     protected function handleExpiredToken(Request $requestRequestConfiguration $configurationUserInterface $user): Response
  219.     {
  220.         $user->setPasswordResetToken(null);
  221.         $user->setPasswordRequestedAt(null);
  222.         $this->manager->flush();
  223.         if (!$configuration->isHtmlRequest()) {
  224.             return $this->viewHandler->handle($configurationView::create($userResponse::HTTP_BAD_REQUEST));
  225.         }
  226.         $this->addTranslatedFlash('error''sylius.user.expire_password_reset_token');
  227.         $redirectRouteName $this->getSyliusAttribute($request'redirect'null);
  228.         Assert::notNull($redirectRouteName'Redirect is not configured.');
  229.         return new RedirectResponse($this->container->get('router')->generate($redirectRouteName));
  230.     }
  231.     protected function handleResetPasswordRequest(
  232.         GeneratorInterface $generator,
  233.         UserInterface $user,
  234.         string $senderEvent
  235.     ): void {
  236.         $user->setPasswordResetToken($generator->generate());
  237.         $user->setPasswordRequestedAt(new \DateTime());
  238.         // I have to use doctrine manager directly, because domain manager functions add a flash messages. I can't get rid of them.
  239.         $manager $this->container->get('doctrine.orm.default_entity_manager');
  240.         $manager->persist($user);
  241.         $manager->flush();
  242.         $dispatcher $this->container->get('event_dispatcher');
  243.         $dispatcher->dispatch(new GenericEvent($user), $senderEvent);
  244.     }
  245.     protected function handleResetPassword(
  246.         Request $request,
  247.         RequestConfiguration $configuration,
  248.         UserInterface $user,
  249.         string $newPassword
  250.     ): Response {
  251.         $user->setPlainPassword($newPassword);
  252.         $user->setPasswordResetToken(null);
  253.         $user->setPasswordRequestedAt(null);
  254.         $dispatcher $this->container->get('event_dispatcher');
  255.         $dispatcher->dispatch(new GenericEvent($user), UserEvents::PRE_PASSWORD_RESET);
  256.         $this->manager->flush();
  257.         $this->addTranslatedFlash('success''sylius.user.reset_password');
  258.         $dispatcher->dispatch(new GenericEvent($user), UserEvents::POST_PASSWORD_RESET);
  259.         if (!$configuration->isHtmlRequest()) {
  260.             return $this->viewHandler->handle($configurationView::create(nullResponse::HTTP_NO_CONTENT));
  261.         }
  262.         $redirectRouteName $this->getSyliusAttribute($request'redirect'null);
  263.         Assert::notNull($redirectRouteName'Redirect is not configured.');
  264.         return new RedirectResponse($this->container->get('router')->generate($redirectRouteName));
  265.     }
  266.     protected function handleChangePassword(
  267.         Request $request,
  268.         RequestConfiguration $configuration,
  269.         UserInterface $user,
  270.         string $newPassword
  271.     ): Response {
  272.         $user->setPlainPassword($newPassword);
  273.         $dispatcher $this->container->get('event_dispatcher');
  274.         $dispatcher->dispatch(new GenericEvent($user), UserEvents::PRE_PASSWORD_CHANGE);
  275.         $this->manager->flush();
  276.         $this->addTranslatedFlash('success''sylius.user.change_password');
  277.         $dispatcher->dispatch(new GenericEvent($user), UserEvents::POST_PASSWORD_CHANGE);
  278.         if (!$configuration->isHtmlRequest()) {
  279.             return $this->viewHandler->handle($configurationView::create(nullResponse::HTTP_NO_CONTENT));
  280.         }
  281.         $redirectRouteName $this->getSyliusAttribute($request'redirect'null);
  282.         Assert::notNull($redirectRouteName'Redirect is not configured.');
  283.         return new RedirectResponse($this->container->get('router')->generate($redirectRouteName));
  284.     }
  285.     protected function getUser(): ?UserInterface
  286.     {
  287.         $user parent::getUser();
  288.         $authorizationChecker $this->container->get('security.authorization_checker');
  289.         if (
  290.             $authorizationChecker->isGranted('IS_AUTHENTICATED_REMEMBERED') &&
  291.             $user instanceof UserInterface
  292.         ) {
  293.             return $user;
  294.         }
  295.         return null;
  296.     }
  297.     private function getSyliusAttribute(Request $requeststring $attribute$default null)
  298.     {
  299.         $attributes $request->attributes->get('_sylius');
  300.         return $attributes[$attribute] ?? $default;
  301.     }
  302. }