1 <?php
declare(strict_types
=1);
4 * This file is part of the Rapsys UserBundle package.
6 * (c) Raphaël Gertz <symfony@rapsys.eu>
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
12 namespace Rapsys\UserBundle\Controller
;
14 use Doctrine\Bundle\DoctrineBundle\Registry
;
15 use Doctrine\ORM\EntityManagerInterface
;
16 use Doctrine\DBAL\Exception\UniqueConstraintViolationException
;
17 use Psr\Log\LoggerInterface
;
18 use Symfony\Bridge\Twig\Mime\TemplatedEmail
;
19 use Symfony\Component\Form\FormError
;
20 use Symfony\Component\HttpFoundation\Request
;
21 use Symfony\Component\HttpFoundation\Response
;
22 use Symfony\Component\HttpKernel\Exception\BadRequestHttpException
;
23 use Symfony\Component\Mailer\Exception\TransportExceptionInterface
;
24 use Symfony\Component\Mailer\MailerInterface
;
25 use Symfony\Component\Mime\Address
;
26 use Symfony\Component\Routing\Generator\UrlGeneratorInterface
;
27 use Symfony\Component\Routing\RouterInterface
;
28 use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface
;
29 use Symfony\Component\Security\Http\Authentication\AuthenticationUtils
;
31 use Rapsys\PackBundle\Util\SluggerUtil
;
36 class DefaultController
extends AbstractController
{
38 * Confirm account from mail link
40 * @param Request $request The request
41 * @param Registry $manager The doctrine registry
42 * @param UserPasswordEncoderInterface $encoder The password encoder
43 * @param EntityManagerInterface $manager The doctrine entity manager
44 * @param SluggerUtil $slugger The slugger
45 * @param MailerInterface $mailer The mailer
46 * @param string $mail The shorted mail address
47 * @param string $hash The hashed password
48 * @return Response The response
50 public function confirm(Request
$request, Registry
$doctrine, UserPasswordEncoderInterface
$encoder, EntityManagerInterface
$manager, SluggerUtil
$slugger, MailerInterface
$mailer, $mail, $hash): Response
{
52 if ($hash != $slugger->hash($mail)) {
54 throw new BadRequestHttpException($this->translator
->trans('Invalid %field% field: %value%', ['%field%' => 'hash', '%value%' => $hash]));
58 $mail = $slugger->unshort($smail = $mail);
61 if (filter_var($mail, FILTER_VALIDATE_EMAIL
) === false) {
63 //XXX: prevent slugger reverse engineering by not displaying decoded mail
64 throw new BadRequestHttpException($this->translator
->trans('Invalid %field% field: %value%', ['%field%' => 'mail', '%value%' => $smail]));
67 //Without existing registrant
68 if (!($user = $doctrine->getRepository($this->config
['class']['user'])->findOneByMail($mail))) {
69 //Add error message mail already exists
70 //XXX: prevent slugger reverse engineering by not displaying decoded mail
71 $this->addFlash('error', $this->translator
->trans('Account %mail% do not exists', ['%mail%' => $smail]));
73 //Redirect to register view
74 return $this->redirectToRoute($this->config
['route']['register']['name'], ['mail' => $smail, 'field' => $sfield = $slugger->serialize([]), 'hash' => $slugger->hash($smail.$sfield)]+
$this->config
['route']['register']['context']);
78 $user->setActive(true);
81 $manager->persist($user);
86 //Add error message mail already exists
87 $this->addFlash('notice', $this->translator
->trans('Your account has been activated'));
89 //Redirect to user view
90 return $this->redirectToRoute($this->config
['route']['edit']['name'], ['mail' => $smail, 'hash' => $slugger->hash($smail)]+
$this->config
['route']['edit']['context']);
94 * Edit account by shorted mail
96 * @param Request $request The request
97 * @param Registry $manager The doctrine registry
98 * @param UserPasswordEncoderInterface $encoder The password encoder
99 * @param EntityManagerInterface $manager The doctrine entity manager
100 * @param SluggerUtil $slugger The slugger
101 * @param string $mail The shorted mail address
102 * @param string $hash The hashed password
103 * @return Response The response
105 public function edit(Request
$request, Registry
$doctrine, UserPasswordEncoderInterface
$encoder, EntityManagerInterface
$manager, SluggerUtil
$slugger, $mail, $hash): Response
{
107 if ($hash != $slugger->hash($mail)) {
109 throw new BadRequestHttpException($this->translator
->trans('Invalid %field% field: %value%', ['%field%' => 'hash', '%value%' => $hash]));
113 $mail = $slugger->unshort($smail = $mail);
115 //With existing subscriber
116 if (empty($user = $doctrine->getRepository($this->config
['class']['user'])->findOneByMail($mail))) {
118 //XXX: prevent slugger reverse engineering by not displaying decoded mail
119 throw $this->createNotFoundException($this->translator
->trans('Unable to find account %mail%', ['%mail%' => $smail]));
122 //Prevent access when not admin, user is not guest and not currently logged user
123 if (!$this->isGranted('ROLE_ADMIN') && $user != $this->getUser() || !$this->isGranted('IS_AUTHENTICATED_FULLY')) {
124 //Throw access denied
125 //XXX: prevent slugger reverse engineering by not displaying decoded mail
126 throw $this->createAccessDeniedException($this->translator
->trans('Unable to access user: %mail%', ['%mail%' => $smail]));
129 //Create the RegisterType form and give the proper parameters
130 $edit = $this->createForm($this->config
['edit']['view']['edit'], $user, [
131 //Set action to register route name and context
132 'action' => $this->generateUrl($this->config
['route']['edit']['name'], ['mail' => $smail, 'hash' => $slugger->hash($smail)]+
$this->config
['route']['edit']['context']),
134 'civility_class' => $this->config
['class']['civility'],
135 //Set civility default
136 'civility_default' => $doctrine->getRepository($this->config
['class']['civility'])->findOneByTitle($this->config
['default']['civility']),
138 'mail' => $this->isGranted('ROLE_ADMIN'),
143 ]+
$this->config
['edit']['field']);
146 if ($this->isGranted('ROLE_ADMIN')) {
147 //Create the LoginType form and give the proper parameters
148 $reset = $this->createForm($this->config
['edit']['view']['reset'], $user, [
149 //Set action to register route name and context
150 'action' => $this->generateUrl($this->config
['route']['edit']['name'], ['mail' => $smail, 'hash' => $slugger->hash($smail)]+
$this->config
['route']['edit']['context']),
158 if ($request->isMethod('POST')) {
159 //Refill the fields in case the form is not valid.
160 $reset->handleRequest($request);
162 //With reset submitted and valid
163 if ($reset->isSubmitted() && $reset->isValid()) {
165 $data = $reset->getData();
168 $data->setPassword($encoder->encodePassword($data, $data->getPassword()));
171 $manager->persist($data);
173 //Flush to get the ids
177 $this->addFlash('notice', $this->translator
->trans('Account %mail% password updated', ['%mail%' => $mail = $data->getMail()]));
179 //Redirect to cleanup the form
180 return $this->redirectToRoute($this->config
['route']['edit']['name'], ['mail' => $smail = $slugger->short($mail), 'hash' => $slugger->hash($smail)]+
$this->config
['route']['edit']['context']);
185 $this->config
['edit']['view']['context']['reset'] = $reset->createView();
189 if ($request->isMethod('POST')) {
190 //Refill the fields in case the form is not valid.
191 $edit->handleRequest($request);
193 //With edit submitted and valid
194 if ($edit->isSubmitted() && $edit->isValid()) {
196 $data = $edit->getData();
199 $manager->persist($data);
201 //Try saving in database
203 //Flush to get the ids
207 $this->addFlash('notice', $this->translator
->trans('Account %mail% updated', ['%mail%' => $mail = $data->getMail()]));
209 //Redirect to cleanup the form
210 return $this->redirectToRoute($this->config
['route']['edit']['name'], ['mail' => $smail = $slugger->short($mail), 'hash' => $slugger->hash($smail)]+
$this->config
['route']['edit']['context']);
211 //Catch double slug or mail
212 } catch (UniqueConstraintViolationException
$e) {
213 //Add error message mail already exists
214 $this->addFlash('error', $this->translator
->trans('Account %mail% already exists', ['%mail%' => $data->getMail()]));
218 //XXX: prefer a reset on login to force user unspam action
219 } elseif (!$this->isGranted('ROLE_ADMIN')) {
221 $this->addFlash('notice', $this->translator
->trans('To change your password login with your mail and any password then follow the procedure'));
225 return $this->render(
227 $this->config
['edit']['view']['name'],
229 ['edit' => $edit->createView(), 'sent' => $request->query
->get('sent', 0)]+
$this->config
['edit']['view']['context']
236 * @param Request $request The request
237 * @param AuthenticationUtils $authenticationUtils The authentication utils
238 * @param RouterInterface $router The router instance
239 * @param SluggerUtil $slugger The slugger
240 * @param string $mail The shorted mail address
241 * @param string $hash The hashed password
242 * @return Response The response
244 public function login(Request
$request, AuthenticationUtils
$authenticationUtils, RouterInterface
$router, SluggerUtil
$slugger, $mail, $hash): Response
{
245 //Create the LoginType form and give the proper parameters
246 $login = $this->createForm($this->config
['login']['view']['form'], null, [
247 //Set action to login route name and context
248 'action' => $this->generateUrl($this->config
['route']['login']['name'], $this->config
['route']['login']['context']),
249 //Disable repeated password
250 'password_repeated' => false,
259 if (!empty($mail) && !empty($hash)) {
261 if ($hash != $slugger->hash($mail)) {
263 throw new BadRequestHttpException($this->translator
->trans('Invalid %field% field: %value%', ['%field%' => 'hash', '%value%' => $hash]));
267 $mail = $slugger->unshort($smail = $mail);
270 if (filter_var($mail, FILTER_VALIDATE_EMAIL
) === false) {
272 throw new BadRequestHttpException($this->translator
->trans('Invalid %field% field: %value%', ['%field%' => 'mail', '%value%' => $smail]));
276 $login->get('mail')->setData($mail);
277 //Last username entered by the user
278 } elseif ($lastUsername = $authenticationUtils->getLastUsername()) {
279 $login->get('mail')->setData($lastUsername);
282 //Get the login error if there is one
283 if ($error = $authenticationUtils->getLastAuthenticationError()) {
284 //Get translated error
285 $error = $this->translator
->trans($error->getMessageKey());
287 //Add error message to mail field
288 $login->get('mail')->addError(new FormError($error));
290 //Create the LoginType form and give the proper parameters
291 $recover = $this->createForm($this->config
['recover']['view']['form'], null, [
292 //Set action to recover route name and context
293 'action' => $this->generateUrl($this->config
['route']['recover']['name'], $this->config
['route']['recover']['context']),
300 //Get recover mail entity
301 $recover->get('mail')
302 //Set mail from login form
303 ->setData($login->get('mail')->getData())
305 ->addError(new FormError($this->translator
->trans('Use this form to recover your account')));
307 //Add recover form to context
308 $context['recover'] = $recover->createView();
311 $this->addFlash('notice', $this->translator
->trans('To change your password login with your mail and any password then follow the procedure'));
315 return $this->render(
317 $this->config
['login']['view']['name'],
319 ['login' => $login->createView()]+
$context+
$this->config
['login']['view']['context']
326 * @param Request $request The request
327 * @param Registry $manager The doctrine registry
328 * @param UserPasswordEncoderInterface $encoder The password encoder
329 * @param EntityManagerInterface $manager The doctrine entity manager
330 * @param SluggerUtil $slugger The slugger
331 * @param MailerInterface $mailer The mailer
332 * @param string $mail The shorted mail address
333 * @param string $pass The shorted password
334 * @param string $hash The hashed password
335 * @return Response The response
337 public function recover(Request
$request, Registry
$doctrine, UserPasswordEncoderInterface
$encoder, EntityManagerInterface
$manager, SluggerUtil
$slugger, MailerInterface
$mailer, $mail, $pass, $hash): Response
{
338 //Without mail, pass and hash
339 if (empty($mail) && empty($pass) && empty($hash)) {
340 //Create the LoginType form and give the proper parameters
341 $form = $this->createForm($this->config
['recover']['view']['form'], null, [
342 //Set action to recover route name and context
343 'action' => $this->generateUrl($this->config
['route']['recover']['name'], $this->config
['route']['recover']['context']),
350 if ($request->isMethod('POST')) {
351 //Refill the fields in case the form is not valid.
352 $form->handleRequest($request);
354 if ($form->isValid()) {
356 $data = $form->getData();
358 //Find user by data mail
359 if ($user = $doctrine->getRepository($this->config
['class']['user'])->findOneByMail($data['mail'])) {
361 $recoverMail =& $this->config
['recover']['mail'];
364 $mail = $slugger->short($user->getMail());
367 $pass = $slugger->hash($user->getPassword());
369 //Generate each route route
370 foreach($this->config
['recover']['route'] as $route => $tag) {
371 //Only process defined routes
372 if (!empty($this->config
['route'][$route])) {
373 //Process for recover mail url
374 if ($route == 'recover') {
375 //Set the url in context
376 $recoverMail['context'][$tag] = $this->get('router')->generate(
377 $this->config
['route'][$route]['name'],
378 //Prepend recover context with tag
382 'hash' => $slugger->hash($mail.$pass)
383 ]+
$this->config
['route'][$route]['context'],
384 UrlGeneratorInterface
::ABSOLUTE_URL
391 $recoverMail['context']['recipient_mail'] = $user->getMail();
394 $recoverMail['context']['recipient_name'] = $user->getRecipientName();
396 //Init subject context
397 $subjectContext = $slugger->flatten(array_replace_recursive($this->config
['recover']['view']['context'], $recoverMail['context']), null, '.', '%', '%');
400 $recoverMail['subject'] = ucfirst($this->translator
->trans($recoverMail['subject'], $subjectContext));
403 $message = (new TemplatedEmail())
405 ->from(new Address($this->config
['contact']['mail'], $this->config
['contact']['title']))
407 //XXX: remove the debug set in vendor/symfony/mime/Address.php +46
408 ->to(new Address($recoverMail['context']['recipient_mail'], $recoverMail['context']['recipient_name']))
410 ->subject($recoverMail['subject'])
412 //Set path to twig templates
413 ->htmlTemplate($recoverMail['html'])
414 ->textTemplate($recoverMail['text'])
417 //XXX: require recursive merge to avoid loosing subkeys
418 //['subject' => $recoverMail['subject']]+$recoverMail['context']+$this->config['recover']['view']['context']
419 ->context(array_replace_recursive($this->config
['recover']['view']['context'], $recoverMail['context'], ['subject' => $recoverMail['subject']]));
421 //Try sending message
422 //XXX: mail delivery may silently fail
425 $mailer->send($message);
427 //Redirect on the same route with sent=1 to cleanup form
428 return $this->redirectToRoute($request->get('_route'), ['sent' => 1]+
$request->get('_route_params'));
429 //Catch obvious transport exception
430 } catch(TransportExceptionInterface
$e) {
431 //Add error message mail unreachable
432 $form->get('mail')->addError(new FormError($this->translator
->trans('Account found but unable to contact: %mail%', array('%mail%' => $data['mail']))));
436 //Add error message to mail field
437 $form->get('mail')->addError(new FormError($this->translator
->trans('Unable to find account %mail%', ['%mail%' => $data['mail']])));
443 return $this->render(
445 $this->config
['recover']['view']['name'],
447 ['form' => $form->createView(), 'sent' => $request->query
->get('sent', 0)]+
$this->config
['recover']['view']['context']
452 if ($hash != $slugger->hash($mail.$pass)) {
454 throw new BadRequestHttpException($this->translator
->trans('Invalid %field% field: %value%', ['%field%' => 'hash', '%value%' => $hash]));
458 $mail = $slugger->unshort($smail = $mail);
461 if (filter_var($mail, FILTER_VALIDATE_EMAIL
) === false) {
463 //XXX: prevent slugger reverse engineering by not displaying decoded mail
464 throw new BadRequestHttpException($this->translator
->trans('Invalid %field% field: %value%', ['%field%' => 'mail', '%value%' => $smail]));
467 //With existing subscriber
468 if (empty($user = $doctrine->getRepository($this->config
['class']['user'])->findOneByMail($mail))) {
470 //XXX: prevent slugger reverse engineering by not displaying decoded mail
471 throw $this->createNotFoundException($this->translator
->trans('Unable to find account %mail%', ['%mail%' => $smail]));
474 //With unmatched pass
475 if ($pass != $slugger->hash($user->getPassword())) {
477 //XXX: prevent use of outdated recover link
478 throw $this->createNotFoundException($this->translator
->trans('Outdated recover link'));
481 //Create the LoginType form and give the proper parameters
482 $form = $this->createForm($this->config
['recover']['view']['form'], $user, [
483 //Set action to recover route name and context
484 'action' => $this->generateUrl($this->config
['route']['recover']['name'], ['mail' => $smail, 'pass' => $pass, 'hash' => $hash]+
$this->config
['route']['recover']['context']),
491 if ($request->isMethod('POST')) {
492 //Refill the fields in case the form is not valid.
493 $form->handleRequest($request);
495 if ($form->isValid()) {
497 $data = $form->getData();
499 //Set encoded password
500 $encoded = $encoder->encodePassword($user, $user->getPassword());
503 $pass = $slugger->hash($encoded);
506 $user->setPassword($encoded);
509 $manager->persist($user);
515 $this->addFlash('notice', $this->translator
->trans('Account %mail% password updated', ['%mail%' => $mail]));
517 //Redirect to user login
518 return $this->redirectToRoute($this->config
['route']['login']['name'], ['mail' => $smail, 'hash' => $slugger->hash($smail)]+
$this->config
['route']['login']['context']);
523 return $this->render(
525 $this->config
['recover']['view']['name'],
527 ['form' => $form->createView(), 'sent' => $request->query
->get('sent', 0)]+
$this->config
['recover']['view']['context']
532 * Register an account
534 * @param Request $request The request
535 * @param Registry $manager The doctrine registry
536 * @param UserPasswordEncoderInterface $encoder The password encoder
537 * @param EntityManagerInterface $manager The doctrine entity manager
538 * @param SluggerUtil $slugger The slugger
539 * @param MailerInterface $mailer The mailer
540 * @param LoggerInterface $logger The logger
541 * @param string $mail The shorted mail address
542 * @param string $field The serialized then shorted form field array
543 * @param string $hash The hashed serialized field array
544 * @return Response The response
546 public function register(Request
$request, Registry
$doctrine, UserPasswordEncoderInterface
$encoder, EntityManagerInterface
$manager, SluggerUtil
$slugger, MailerInterface
$mailer, LoggerInterface
$logger, $mail, $field, $hash): Response
{
548 if (!empty($_POST['register']['mail'])) {
551 $this->translator
->trans(
552 'register: mail=%mail% locale=%locale% confirm=%confirm%',
554 '%mail%' => $postMail = $_POST['register']['mail'],
555 '%locale%' => $request->getLocale(),
556 '%confirm%' => $this->get('router')->generate(
557 $this->config
['route']['confirm']['name'],
558 //Prepend subscribe context with tag
560 'mail' => $postSmail = $slugger->short($postMail),
561 'hash' => $slugger->hash($postSmail)
562 ]+
$this->config
['route']['confirm']['context'],
563 UrlGeneratorInterface
::ABSOLUTE_URL
570 //With mail and field
571 if (!empty($field) && !empty($hash)) {
573 if ($hash != $slugger->hash($mail.$field)) {
575 throw new BadRequestHttpException($this->translator
->trans('Invalid %field% field: %value%', ['%field%' => 'hash', '%value%' => $hash]));
581 $mail = $slugger->unshort($smail = $mail);
584 if (filter_var($mail, FILTER_VALIDATE_EMAIL
) === false) {
586 //XXX: prevent slugger reverse engineering by not displaying decoded mail
587 throw new BadRequestHttpException($this->translator
->trans('Invalid %field% field: %value%', ['%field%' => 'mail', '%value%' => $smail]));
590 //With existing registrant
591 if ($existing = $doctrine->getRepository($this->config
['class']['user'])->findOneByMail($mail)) {
592 //With disabled existing
593 if ($existing->isDisabled()) {
595 $response = $this->render(
597 $this->config
['register']['view']['name'],
599 ['title' => $this->translator
->trans('Access denied'), 'disabled' => 1]+
$this->config
['register']['view']['context']
603 $response->setStatusCode(403);
607 //With unactivated existing
608 } elseif (!$existing->isActivated()) {
610 $activateMail =& $this->config
['register']['mail'];
612 //Generate each route route
613 foreach($this->config
['register']['route'] as $route => $tag) {
614 //Only process defined routes
615 if (!empty($this->config
['route'][$route])) {
616 //Process for confirm url
617 if ($route == 'confirm') {
618 //Set the url in context
619 $activateMail['context'][$tag] = $this->get('router')->generate(
620 $this->config
['route'][$route]['name'],
621 //Prepend subscribe context with tag
623 'mail' => $smail = $slugger->short($existing->getMail()),
624 'hash' => $slugger->hash($smail)
625 ]+
$this->config
['route'][$route]['context'],
626 UrlGeneratorInterface
::ABSOLUTE_URL
633 $activateMail['context']['recipient_mail'] = $existing->getMail();
636 $activateMail['context']['recipient_name'] = $existing->getRecipientName();
638 //Init subject context
639 $subjectContext = $slugger->flatten(array_replace_recursive($this->config
['register']['view']['context'], $activateMail['context']), null, '.', '%', '%');
642 $activateMail['subject'] = ucfirst($this->translator
->trans($activateMail['subject'], $subjectContext));
645 $message = (new TemplatedEmail())
647 ->from(new Address($this->config
['contact']['mail'], $this->config
['contact']['title']))
649 //XXX: remove the debug set in vendor/symfony/mime/Address.php +46
650 ->to(new Address($activateMail['context']['recipient_mail'], $activateMail['context']['recipient_name']))
652 ->subject($activateMail['subject'])
654 //Set path to twig templates
655 ->htmlTemplate($activateMail['html'])
656 ->textTemplate($activateMail['text'])
659 ->context(['subject' => $activateMail['subject']]+
$activateMail['context']);
661 //Try sending message
662 //XXX: mail delivery may silently fail
665 $mailer->send($message);
666 //Catch obvious transport exception
667 } catch(TransportExceptionInterface
$e) {
668 //Add error message mail unreachable
669 $this->addFlash('error', $this->translator
->trans('Account %mail% tried activate but unable to contact', ['%mail%' => $existing->getMail()]));
673 $routeParams = $request->get('_route_params');
675 //Remove mail, field and hash from route params
676 unset($routeParams['mail'], $routeParams['field'], $routeParams['hash']);
678 //Redirect on the same route with sent=1 to cleanup form
679 return $this->redirectToRoute($request->get('_route'), ['sent' => 1]+
$routeParams);
682 //Add error message mail already exists
683 $this->addFlash('warning', $this->translator
->trans('Account %mail% already exists', ['%mail%' => $existing->getMail()]));
685 //Redirect to user view
686 return $this->redirectToRoute(
687 $this->config
['route']['edit']['name'],
689 'mail' => $smail = $slugger->short($existing->getMail()),
690 'hash' => $slugger->hash($smail)
691 ]+
$this->config
['route']['edit']['context']
702 //Unshort then unserialize field
703 $field = $slugger->unserialize($sfield = $field);
705 } catch (\Error
|\Exception
$e) {
707 throw new BadRequestHttpException($this->translator
->trans('Invalid %field% field: %value%', ['%field%' => 'field', '%value%' => $field]), $e);
710 //With non array field
711 if (!is_array($field)) {
713 throw new BadRequestHttpException($this->translator
->trans('Invalid %field% field: %value%', ['%field%' => 'field', '%value%' => $field]));
715 //Without field and hash
728 $reflection = new \
ReflectionClass($this->config
['class']['user']);
731 $user = $reflection->newInstance(strval($mail));
733 //Create the RegisterType form and give the proper parameters
734 $form = $this->createForm($this->config
['register']['view']['form'], $user, $field+
[
735 //Set action to register route name and context
736 'action' => $this->generateUrl($this->config
['route']['register']['name'], ['mail' => $smail, 'field' => $sfield, 'hash' => $hash]+
$this->config
['route']['register']['context']),
738 'civility_class' => $this->config
['class']['civility'],
739 //Set civility default
740 'civility_default' => $doctrine->getRepository($this->config
['class']['civility'])->findOneByTitle($this->config
['default']['civility']),
745 ]+
$this->config
['register']['field']);
747 if ($request->isMethod('POST')) {
748 //Refill the fields in case the form is not valid.
749 $form->handleRequest($request);
751 if ($form->isValid()) {
753 $data = $form->getData();
755 //With existing registrant
756 if ($doctrine->getRepository($this->config
['class']['user'])->findOneByMail($mail = $data->getMail())) {
757 //Add error message mail already exists
758 $this->addFlash('warning', $this->translator
->trans('Account %mail% already exists', ['%mail%' => $mail]));
760 //Redirect to user view
761 return $this->redirectToRoute(
762 $this->config
['route']['edit']['name'],
764 'mail' => $smail = $slugger->short($mail),
765 'hash' => $slugger->hash($smail)
766 ]+
$this->config
['route']['edit']['context']
771 $registerMail =& $this->config
['register']['mail'];
774 $user->setPassword($encoder->encodePassword($user, $user->getPassword()));
777 $manager->persist($user);
779 //Iterate on default group
780 foreach($this->config
['default']['group'] as $i => $groupTitle) {
782 if (($group = $doctrine->getRepository($this->config
['class']['group'])->findOneByTitle($groupTitle))) {
784 //XXX: see vendor/symfony/security-core/Role/Role.php
785 $user->addGroup($group);
789 //XXX: consider missing group as fatal
790 throw new \
Exception(sprintf('Group from rapsys_user.default.group[%d] not found by title: %s', $i, $groupTitle));
794 //Generate each route route
795 foreach($this->config
['register']['route'] as $route => $tag) {
796 //Only process defined routes
797 if (!empty($this->config
['route'][$route])) {
798 //Process for confirm url
799 if ($route == 'confirm') {
800 //Set the url in context
801 $registerMail['context'][$tag] = $this->get('router')->generate(
802 $this->config
['route'][$route]['name'],
803 //Prepend subscribe context with tag
805 'mail' => $smail = $slugger->short($data->getMail()),
806 'hash' => $slugger->hash($smail)
807 ]+
$this->config
['route'][$route]['context'],
808 UrlGeneratorInterface
::ABSOLUTE_URL
815 $registerMail['context']['recipient_mail'] = $data->getMail();
818 $registerMail['context']['recipient_name'] = $data->getRecipientName();
820 //Init subject context
821 $subjectContext = $slugger->flatten(array_replace_recursive($this->config
['register']['view']['context'], $registerMail['context']), null, '.', '%', '%');
824 $registerMail['subject'] = ucfirst($this->translator
->trans($registerMail['subject'], $subjectContext));
827 $message = (new TemplatedEmail())
829 ->from(new Address($this->config
['contact']['mail'], $this->config
['contact']['title']))
831 //XXX: remove the debug set in vendor/symfony/mime/Address.php +46
832 ->to(new Address($registerMail['context']['recipient_mail'], $registerMail['context']['recipient_name']))
834 ->subject($registerMail['subject'])
836 //Set path to twig templates
837 ->htmlTemplate($registerMail['html'])
838 ->textTemplate($registerMail['text'])
841 ->context(['subject' => $registerMail['subject']]+
$registerMail['context']);
843 //Try saving in database
848 //Add error message mail already exists
849 $this->addFlash('notice', $this->translator
->trans('Your account has been created'));
851 //Try sending message
852 //XXX: mail delivery may silently fail
855 $mailer->send($message);
857 //Redirect on the same route with sent=1 to cleanup form
858 return $this->redirectToRoute($request->get('_route'), ['sent' => 1]+
$request->get('_route_params'));
859 //Catch obvious transport exception
860 } catch(TransportExceptionInterface
$e) {
861 //Add error message mail unreachable
862 $form->get('mail')->addError(new FormError($this->translator
->trans('Account %mail% tried subscribe but unable to contact', ['%mail%' => $data->getMail()])));
864 //Catch double subscription
865 } catch (UniqueConstraintViolationException
$e) {
866 //Add error message mail already exists
867 $this->addFlash('error', $this->translator
->trans('Account %mail% already exists', ['%mail%' => $mail]));
873 return $this->render(
875 $this->config
['register']['view']['name'],
877 ['form' => $form->createView(), 'sent' => $request->query
->get('sent', 0)]+
$this->config
['register']['view']['context']