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'), 
 140                         'slug' => $this->isGranted('ROLE_ADMIN'), 
 148                 if ($this->isGranted('ROLE_ADMIN')) { 
 149                         //Create the LoginType form and give the proper parameters 
 150                         $reset = $this->createForm($this->config
['edit']['view']['reset'], $user, [ 
 151                                 //Set action to register route name and context 
 152                                 'action' => $this->generateUrl($this->config
['route']['edit']['name'], ['mail' => $smail, 'hash' => $slugger->hash($smail)]+
$this->config
['route']['edit']['context']), 
 160                         if ($request->isMethod('POST')) { 
 161                                 //Refill the fields in case the form is not valid. 
 162                                 $reset->handleRequest($request); 
 164                                 //With reset submitted and valid 
 165                                 if ($reset->isSubmitted() && $reset->isValid()) { 
 167                                         $data = $reset->getData(); 
 170                                         $data->setPassword($encoder->encodePassword($data, $data->getPassword())); 
 173                                         $manager->persist($data); 
 175                                         //Flush to get the ids 
 179                                         $this->addFlash('notice', $this->translator
->trans('Account %mail% password updated', ['%mail%' => $mail = $data->getMail()])); 
 181                                         //Redirect to cleanup the form 
 182                                         return $this->redirectToRoute($this->config
['route']['edit']['name'], ['mail' => $smail = $slugger->short($mail), 'hash' => $slugger->hash($smail)]+
$this->config
['route']['edit']['context']); 
 187                         $this->config
['edit']['view']['context']['reset'] = $reset->createView(); 
 189                 //XXX: prefer a reset on login to force user unspam action 
 192                         $this->addFlash('notice', $this->translator
->trans('To change your password login with your mail and any password then follow the procedure')); 
 196                 if ($request->isMethod('POST')) { 
 197                         //Refill the fields in case the form is not valid. 
 198                         $edit->handleRequest($request); 
 200                         //With edit submitted and valid 
 201                         if ($edit->isSubmitted() && $edit->isValid()) { 
 203                                 $data = $edit->getData(); 
 209                                 if ($this->isGranted('ROLE_ADMIN')) { 
 211                                         if (!empty($data->getSlug())) { 
 213                                                 $slug = $slugger->slug($data->getPseudonym()); 
 217                                         $data->setSlug($slug); 
 221                                 $manager->persist($data); 
 223                                 //Try saving in database 
 225                                         //Flush to get the ids 
 229                                         $this->addFlash('notice', $this->translator
->trans('Account %mail% updated', ['%mail%' => $mail = $data->getMail()])); 
 231                                         //Redirect to cleanup the form 
 232                                         return $this->redirectToRoute($this->config
['route']['edit']['name'], ['mail' => $smail = $slugger->short($mail), 'hash' => $slugger->hash($smail)]+
$this->config
['route']['edit']['context']); 
 233                                 //Catch double slug or mail 
 234                                 } catch (UniqueConstraintViolationException 
$e) { 
 235                                         //Add error message mail already exists 
 236                                         $this->addFlash('error', $this->translator
->trans('Account %mail% or with slug %slug% already exists', ['%mail%' => $data->getMail(), '%slug%' => $slug])); 
 242                 return $this->render( 
 244                         $this->config
['edit']['view']['name'], 
 246                         ['edit' => $edit->createView(), 'sent' => $request->query
->get('sent', 0)]+
$this->config
['edit']['view']['context'] 
 253          * @param Request $request The request 
 254          * @param AuthenticationUtils $authenticationUtils The authentication utils 
 255          * @param RouterInterface $router The router instance 
 256          * @param SluggerUtil $slugger The slugger 
 257          * @param string $mail The shorted mail address 
 258          * @param string $hash The hashed password 
 259          * @return Response The response 
 261         public function login(Request 
$request, AuthenticationUtils 
$authenticationUtils, RouterInterface 
$router, SluggerUtil 
$slugger, $mail, $hash): Response 
{ 
 262                 //Create the LoginType form and give the proper parameters 
 263                 $login = $this->createForm($this->config
['login']['view']['form'], null, [ 
 264                         //Set action to login route name and context 
 265                         'action' => $this->generateUrl($this->config
['route']['login']['name'], $this->config
['route']['login']['context']), 
 266                         //Disable repeated password 
 267                         'password_repeated' => false, 
 276                 if (!empty($mail) && !empty($hash)) { 
 278                         if ($hash != $slugger->hash($mail)) { 
 280                                 throw new BadRequestHttpException($this->translator
->trans('Invalid %field% field: %value%', ['%field%' => 'hash', '%value%' => $hash])); 
 284                         $mail = $slugger->unshort($smail = $mail); 
 287                         if (filter_var($mail, FILTER_VALIDATE_EMAIL
) === false) { 
 289                                 throw new BadRequestHttpException($this->translator
->trans('Invalid %field% field: %value%', ['%field%' => 'mail', '%value%' => $smail])); 
 293                         $login->get('mail')->setData($mail); 
 294                 //Last username entered by the user 
 295                 } elseif ($lastUsername = $authenticationUtils->getLastUsername()) { 
 296                         $login->get('mail')->setData($lastUsername); 
 299                 //Get the login error if there is one 
 300                 if ($error = $authenticationUtils->getLastAuthenticationError()) { 
 301                         //Get translated error 
 302                         $error = $this->translator
->trans($error->getMessageKey()); 
 304                         //Add error message to mail field 
 305                         $login->get('mail')->addError(new FormError($error)); 
 307                         //Create the LoginType form and give the proper parameters 
 308                         $recover = $this->createForm($this->config
['recover']['view']['form'], null, [ 
 309                                 //Set action to recover route name and context 
 310                                 'action' => $this->generateUrl($this->config
['route']['recover']['name'], $this->config
['route']['recover']['context']), 
 317                         //Get recover mail entity 
 318                         $recover->get('mail') 
 319                                 //Set mail from login form 
 320                                 ->setData($login->get('mail')->getData()) 
 322                                 ->addError(new FormError($this->translator
->trans('Use this form to recover your account'))); 
 324                         //Add recover form to context 
 325                         $context['recover'] = $recover->createView(); 
 328                         $this->addFlash('notice', $this->translator
->trans('To change your password login with your mail and any password then follow the procedure')); 
 332                 return $this->render( 
 334                         $this->config
['login']['view']['name'], 
 336                         ['login' => $login->createView()]+
$context+
$this->config
['login']['view']['context'] 
 343          * @param Request $request The request 
 344          * @param Registry $manager The doctrine registry 
 345          * @param UserPasswordEncoderInterface $encoder The password encoder 
 346          * @param EntityManagerInterface $manager The doctrine entity manager 
 347          * @param SluggerUtil $slugger The slugger 
 348          * @param MailerInterface $mailer The mailer 
 349          * @param string $mail The shorted mail address 
 350          * @param string $pass The shorted password 
 351          * @param string $hash The hashed password 
 352          * @return Response The response 
 354         public function recover(Request 
$request, Registry 
$doctrine, UserPasswordEncoderInterface 
$encoder, EntityManagerInterface 
$manager, SluggerUtil 
$slugger, MailerInterface 
$mailer, $mail, $pass, $hash): Response 
{ 
 355                 //Without mail, pass and hash 
 356                 if (empty($mail) && empty($pass) && empty($hash)) { 
 357                         //Create the LoginType form and give the proper parameters 
 358                         $form = $this->createForm($this->config
['recover']['view']['form'], null, [ 
 359                                 //Set action to recover route name and context 
 360                                 'action' => $this->generateUrl($this->config
['route']['recover']['name'], $this->config
['route']['recover']['context']), 
 367                         if ($request->isMethod('POST')) { 
 368                                 //Refill the fields in case the form is not valid. 
 369                                 $form->handleRequest($request); 
 371                                 if ($form->isValid()) { 
 373                                         $data = $form->getData(); 
 375                                         //Find user by data mail 
 376                                         if ($user = $doctrine->getRepository($this->config
['class']['user'])->findOneByMail($data['mail'])) { 
 378                                                 $recoverMail =& $this->config
['recover']['mail']; 
 381                                                 $mail = $slugger->short($user->getMail()); 
 384                                                 $pass = $slugger->hash($user->getPassword()); 
 386                                                 //Generate each route route 
 387                                                 foreach($this->config
['recover']['route'] as $route => $tag) { 
 388                                                         //Only process defined routes 
 389                                                         if (!empty($this->config
['route'][$route])) { 
 390                                                                 //Process for recover mail url 
 391                                                                 if ($route == 'recover') { 
 392                                                                         //Set the url in context 
 393                                                                         $recoverMail['context'][$tag] = $this->get('router')->generate( 
 394                                                                                 $this->config
['route'][$route]['name'], 
 395                                                                                 //Prepend recover context with tag 
 399                                                                                         'hash' => $slugger->hash($mail.$pass) 
 400                                                                                 ]+
$this->config
['route'][$route]['context'], 
 401                                                                                 UrlGeneratorInterface
::ABSOLUTE_URL
 
 408                                                 $recoverMail['context']['recipient_mail'] = $user->getMail(); 
 411                                                 $recoverMail['context']['recipient_name'] = trim($user->getForename().' '.$user->getSurname().($user->getPseudonym()?' ('.$user->getPseudonym().')':'')); 
 413                                                 //Init subject context 
 414                                                 $subjectContext = $slugger->flatten(array_replace_recursive($this->config
['recover']['view']['context'], $recoverMail['context']), null, '.', '%', '%'); 
 417                                                 $recoverMail['subject'] = ucfirst($this->translator
->trans($recoverMail['subject'], $subjectContext)); 
 420                                                 $message = (new TemplatedEmail()) 
 422                                                         ->from(new Address($this->config
['contact']['mail'], $this->config
['contact']['title'])) 
 424                                                         //XXX: remove the debug set in vendor/symfony/mime/Address.php +46 
 425                                                         ->to(new Address($recoverMail['context']['recipient_mail'], $recoverMail['context']['recipient_name'])) 
 427                                                         ->subject($recoverMail['subject']) 
 429                                                         //Set path to twig templates 
 430                                                         ->htmlTemplate($recoverMail['html']) 
 431                                                         ->textTemplate($recoverMail['text']) 
 434                                                         //XXX: require recursive merge to avoid loosing subkeys 
 435                                                         //['subject' => $recoverMail['subject']]+$recoverMail['context']+$this->config['recover']['view']['context'] 
 436                                                         ->context(array_replace_recursive($this->config
['recover']['view']['context'], $recoverMail['context'], ['subject' => $recoverMail['subject']])); 
 438                                                 //Try sending message 
 439                                                 //XXX: mail delivery may silently fail 
 442                                                         $mailer->send($message); 
 444                                                         //Redirect on the same route with sent=1 to cleanup form 
 445                                                         return $this->redirectToRoute($request->get('_route'), ['sent' => 1]+
$request->get('_route_params')); 
 446                                                 //Catch obvious transport exception 
 447                                                 } catch(TransportExceptionInterface 
$e) { 
 448                                                         //Add error message mail unreachable 
 449                                                         $form->get('mail')->addError(new FormError($this->translator
->trans('Account found but unable to contact: %mail%', array('%mail%' => $data['mail'])))); 
 453                                                 //Add error message to mail field 
 454                                                 $form->get('mail')->addError(new FormError($this->translator
->trans('Unable to find account %mail%', ['%mail%' => $data['mail']]))); 
 460                         return $this->render( 
 462                                 $this->config
['recover']['view']['name'], 
 464                                 ['form' => $form->createView(), 'sent' => $request->query
->get('sent', 0)]+
$this->config
['recover']['view']['context'] 
 469                 if ($hash != $slugger->hash($mail.$pass)) { 
 471                         throw new BadRequestHttpException($this->translator
->trans('Invalid %field% field: %value%', ['%field%' => 'hash', '%value%' => $hash])); 
 475                 $mail = $slugger->unshort($smail = $mail); 
 478                 if (filter_var($mail, FILTER_VALIDATE_EMAIL
) === false) { 
 480                         //XXX: prevent slugger reverse engineering by not displaying decoded mail 
 481                         throw new BadRequestHttpException($this->translator
->trans('Invalid %field% field: %value%', ['%field%' => 'mail', '%value%' => $smail])); 
 484                 //With existing subscriber 
 485                 if (empty($user = $doctrine->getRepository($this->config
['class']['user'])->findOneByMail($mail))) { 
 487                         //XXX: prevent slugger reverse engineering by not displaying decoded mail 
 488                         throw $this->createNotFoundException($this->translator
->trans('Unable to find account %mail%', ['%mail%' => $smail])); 
 491                 //With unmatched pass 
 492                 if ($pass != $slugger->hash($user->getPassword())) { 
 494                         //XXX: prevent use of outdated recover link 
 495                         throw $this->createNotFoundException($this->translator
->trans('Outdated recover link')); 
 498                 //Create the LoginType form and give the proper parameters 
 499                 $form = $this->createForm($this->config
['recover']['view']['form'], $user, [ 
 500                         //Set action to recover route name and context 
 501                         'action' => $this->generateUrl($this->config
['route']['recover']['name'], ['mail' => $smail, 'pass' => $pass, 'hash' => $hash]+
$this->config
['route']['recover']['context']), 
 508                 if ($request->isMethod('POST')) { 
 509                         //Refill the fields in case the form is not valid. 
 510                         $form->handleRequest($request); 
 512                         if ($form->isValid()) { 
 514                                 $data = $form->getData(); 
 516                                 //Set encoded password 
 517                                 $encoded = $encoder->encodePassword($user, $user->getPassword()); 
 520                                 $pass = $slugger->hash($encoded); 
 523                                 $user->setPassword($encoded); 
 526                                 $manager->persist($user); 
 532                                 $this->addFlash('notice', $this->translator
->trans('Account %mail% password updated', ['%mail%' => $mail])); 
 534                                 //Redirect to user login 
 535                                 return $this->redirectToRoute($this->config
['route']['login']['name'], ['mail' => $smail, 'hash' => $slugger->hash($smail)]+
$this->config
['route']['login']['context']); 
 540                 return $this->render( 
 542                         $this->config
['recover']['view']['name'], 
 544                         ['form' => $form->createView(), 'sent' => $request->query
->get('sent', 0)]+
$this->config
['recover']['view']['context'] 
 549          * Register an account 
 551          * @param Request $request The request 
 552          * @param Registry $manager The doctrine registry 
 553          * @param UserPasswordEncoderInterface $encoder The password encoder 
 554          * @param EntityManagerInterface $manager The doctrine entity manager 
 555          * @param SluggerUtil $slugger The slugger 
 556          * @param MailerInterface $mailer The mailer 
 557          * @param LoggerInterface $logger The logger 
 558          * @param string $mail The shorted mail address 
 559          * @param string $field The serialized then shorted form field array 
 560          * @param string $hash The hashed serialized field array 
 561          * @return Response The response 
 563         public function register(Request 
$request, Registry 
$doctrine, UserPasswordEncoderInterface 
$encoder, EntityManagerInterface 
$manager, SluggerUtil 
$slugger, MailerInterface 
$mailer, LoggerInterface 
$logger, $mail, $field, $hash): Response 
{ 
 565                 if (!empty($_POST['register']['mail'])) { 
 568                                 $this->translator
->trans( 
 569                                         'register: mail=%mail% locale=%locale% confirm=%confirm%', 
 571                                                 '%mail%' => $postMail = $_POST['register']['mail'], 
 572                                                 '%locale%' => $request->getLocale(), 
 573                                                 '%confirm%' => $this->get('router')->generate( 
 574                                                         $this->config
['route']['confirm']['name'], 
 575                                                         //Prepend subscribe context with tag 
 577                                                                 'mail' => $postSmail = $slugger->short($postMail), 
 578                                                                 'hash' => $slugger->hash($postSmail) 
 579                                                         ]+
$this->config
['route']['confirm']['context'], 
 580                                                         UrlGeneratorInterface
::ABSOLUTE_URL
 
 587                 //With mail and field 
 588                 if (!empty($field) && !empty($hash)) { 
 590                         if ($hash != $slugger->hash($mail.$field)) { 
 592                                 throw new BadRequestHttpException($this->translator
->trans('Invalid %field% field: %value%', ['%field%' => 'hash', '%value%' => $hash])); 
 598                                 $mail = $slugger->unshort($smail = $mail); 
 601                                 if (filter_var($mail, FILTER_VALIDATE_EMAIL
) === false) { 
 603                                         //XXX: prevent slugger reverse engineering by not displaying decoded mail 
 604                                         throw new BadRequestHttpException($this->translator
->trans('Invalid %field% field: %value%', ['%field%' => 'mail', '%value%' => $smail])); 
 607                                 //With existing registrant 
 608                                 if ($existing = $doctrine->getRepository($this->config
['class']['user'])->findOneByMail($mail)) { 
 609                                         //With disabled existing 
 610                                         if ($existing->isDisabled()) { 
 612                                                 return $this->render( 
 614                                                         $this->config
['register']['view']['name'], 
 616                                                         ['title' => $this->translator
->trans('Access denied'), 'disabled' => 1]+
$this->config
['register']['view']['context'], 
 618                                                         new Response('', 403) 
 620                                         //With unactivated existing 
 621                                         } elseif (!$existing->isActivated()) { 
 623                                                 //TODO: change for activate ??? 
 624                                                 $activateMail =& $this->config
['register']['mail']; 
 626                                                 //Generate each route route 
 627                                                 foreach($this->config
['register']['route'] as $route => $tag) { 
 628                                                         //Only process defined routes 
 629                                                         if (!empty($this->config
['route'][$route])) { 
 630                                                                 //Process for confirm url 
 631                                                                 if ($route == 'confirm') { 
 632                                                                         //Set the url in context 
 633                                                                         $activateMail['context'][$tag] = $this->get('router')->generate( 
 634                                                                                 $this->config
['route'][$route]['name'], 
 635                                                                                 //Prepend subscribe context with tag 
 637                                                                                         'mail' => $smail = $slugger->short($existing->getMail()), 
 638                                                                                         'hash' => $slugger->hash($smail) 
 639                                                                                 ]+
$this->config
['route'][$route]['context'], 
 640                                                                                 UrlGeneratorInterface
::ABSOLUTE_URL
 
 647                                                 $activateMail['context']['recipient_mail'] = $existing->getMail(); 
 650                                                 $activateMail['context']['recipient_name'] = implode(' ', [$existing->getForename(), $existing->getSurname(), $existing->getPseudonym()?'('.$existing->getPseudonym().')':'']); 
 652                                                 //Init subject context 
 653                                                 $subjectContext = $slugger->flatten(array_replace_recursive($this->config
['register']['view']['context'], $activateMail['context']), null, '.', '%', '%'); 
 656                                                 $activateMail['subject'] = ucfirst($this->translator
->trans($activateMail['subject'], $subjectContext)); 
 659                                                 $message = (new TemplatedEmail()) 
 661                                                         ->from(new Address($this->config
['contact']['mail'], $this->config
['contact']['title'])) 
 663                                                         //XXX: remove the debug set in vendor/symfony/mime/Address.php +46 
 664                                                         ->to(new Address($activateMail['context']['recipient_mail'], $activateMail['context']['recipient_name'])) 
 666                                                         ->subject($activateMail['subject']) 
 668                                                         //Set path to twig templates 
 669                                                         ->htmlTemplate($activateMail['html']) 
 670                                                         ->textTemplate($activateMail['text']) 
 673                                                         ->context(['subject' => $activateMail['subject']]+
$activateMail['context']); 
 675                                                 //Try sending message 
 676                                                 //XXX: mail delivery may silently fail 
 679                                                         $mailer->send($message); 
 680                                                 //Catch obvious transport exception 
 681                                                 } catch(TransportExceptionInterface 
$e) { 
 682                                                         //Add error message mail unreachable 
 683                                                         $this->addFlash('error', $this->translator
->trans('Account %mail% tried activate but unable to contact', ['%mail%' => $existing->getMail()])); 
 687                                                 $routeParams = $request->get('_route_params'); 
 689                                                 //Remove mail, field and hash from route params 
 690                                                 unset($routeParams['mail'], $routeParams['field'], $routeParams['hash']); 
 692                                                 //Redirect on the same route with sent=1 to cleanup form 
 693                                                 return $this->redirectToRoute($request->get('_route'), ['sent' => 1]+
$routeParams); 
 696                                         //Add error message mail already exists 
 697                                         $this->addFlash('warning', $this->translator
->trans('Account %mail% already exists', ['%mail%' => $existing->getMail()])); 
 699                                         //Redirect to user view 
 700                                         return $this->redirectToRoute( 
 701                                                 $this->config
['route']['edit']['name'], 
 703                                                         'mail' => $smail = $slugger->short($existing->getMail()), 
 704                                                         'hash' => $slugger->hash($smail) 
 705                                                 ]+
$this->config
['route']['edit']['context'] 
 716                                 //Unshort then unserialize field 
 717                                 $field = $slugger->unserialize($sfield = $field); 
 719                         } catch (\Error
|\Exception 
$e) { 
 721                                 throw new BadRequestHttpException($this->translator
->trans('Invalid %field% field: %value%', ['%field%' => 'field', '%value%' => $field]), $e); 
 724                         //With non array field 
 725                         if (!is_array($field)) { 
 727                                 throw new BadRequestHttpException($this->translator
->trans('Invalid %field% field: %value%', ['%field%' => 'field', '%value%' => $field])); 
 729                 //Without field and hash 
 745                 $reflection = new \
ReflectionClass($this->config
['class']['user']); 
 748                 $user = $reflection->newInstance(strval($mail)); 
 750                 //Create the RegisterType form and give the proper parameters 
 751                 $form = $this->createForm($this->config
['register']['view']['form'], $user, $field+
[ 
 752                         //Set action to register route name and context 
 753                         'action' => $this->generateUrl($this->config
['route']['register']['name'], ['mail' => $smail, 'field' => $sfield, 'hash' => $hash]+
$this->config
['route']['register']['context']), 
 755                         'civility_class' => $this->config
['class']['civility'], 
 756                         //Set civility default 
 757                         'civility_default' => $doctrine->getRepository($this->config
['class']['civility'])->findOneByTitle($this->config
['default']['civility']), 
 764                 if ($request->isMethod('POST')) { 
 765                         //Refill the fields in case the form is not valid. 
 766                         $form->handleRequest($request); 
 768                         if ($form->isValid()) { 
 770                                 $data = $form->getData(); 
 772                                 //With existing registrant 
 773                                 if ($doctrine->getRepository($this->config
['class']['user'])->findOneByMail($mail = $data->getMail())) { 
 774                                         //Add error message mail already exists 
 775                                         $this->addFlash('warning', $this->translator
->trans('Account %mail% already exists', ['%mail%' => $mail])); 
 777                                         //Redirect to user view 
 778                                         return $this->redirectToRoute( 
 779                                                 $this->config
['route']['edit']['name'], 
 781                                                         'mail' => $smail = $slugger->short($mail), 
 782                                                         'hash' => $slugger->hash($smail) 
 783                                                 ]+
$this->config
['route']['edit']['context'] 
 788                                 $registerMail =& $this->config
['register']['mail']; 
 790                                 //Extract names and pseudonym from mail 
 791                                 $names = explode(' ', $pseudonym = ucwords(trim(preg_replace('/[^a-zA-Z]+/', ' ', current(explode('@', $data->getMail())))))); 
 794                                 $user->setPseudonym($user->getPseudonym()??$pseudonym); 
 797                                 $user->setForename($user->getForename()??$names[0]); 
 800                                 $user->setSurname($user->getSurname()??$names[1]??$names[0]); 
 803                                 $user->setPassword($encoder->encodePassword($user, $user->getPassword()??$data->getMail())); 
 806                                 $user->setCreated(new \
DateTime('now')); 
 809                                 $user->setUpdated(new \
DateTime('now')); 
 812                                 $manager->persist($user); 
 814                                 //Iterate on default group 
 815                                 foreach($this->config
['default']['group'] as $i => $groupTitle) { 
 817                                         if (($group = $doctrine->getRepository($this->config
['class']['group'])->findOneByTitle($groupTitle))) { 
 819                                                 //XXX: see vendor/symfony/security-core/Role/Role.php 
 820                                                 $user->addGroup($group); 
 824                                                 //XXX: consider missing group as fatal 
 825                                                 throw new \
Exception(sprintf('Group from rapsys_user.default.group[%d] not found by title: %s', $i, $groupTitle)); 
 829                                 //Generate each route route 
 830                                 foreach($this->config
['register']['route'] as $route => $tag) { 
 831                                         //Only process defined routes 
 832                                         if (!empty($this->config
['route'][$route])) { 
 833                                                 //Process for confirm url 
 834                                                 if ($route == 'confirm') { 
 835                                                         //Set the url in context 
 836                                                         $registerMail['context'][$tag] = $this->get('router')->generate( 
 837                                                                 $this->config
['route'][$route]['name'], 
 838                                                                 //Prepend subscribe context with tag 
 840                                                                         'mail' => $smail = $slugger->short($data->getMail()), 
 841                                                                         'hash' => $slugger->hash($smail) 
 842                                                                 ]+
$this->config
['route'][$route]['context'], 
 843                                                                 UrlGeneratorInterface
::ABSOLUTE_URL
 
 849                                 //XXX: DEBUG: remove me 
 850                                 //die($registerMail['context']['confirm_url']); 
 853                                 $registerMail['context']['recipient_mail'] = $data->getMail(); 
 856                                 $registerMail['context']['recipient_name'] = ''; 
 859                                 $registerMail['context']['recipient_name'] = implode(' ', [$data->getForename(), $data->getSurname(), $data->getPseudonym()?'('.$data->getPseudonym().')':'']); 
 861                                 //Init subject context 
 862                                 $subjectContext = $slugger->flatten(array_replace_recursive($this->config
['register']['view']['context'], $registerMail['context']), null, '.', '%', '%'); 
 865                                 $registerMail['subject'] = ucfirst($this->translator
->trans($registerMail['subject'], $subjectContext)); 
 868                                 $message = (new TemplatedEmail()) 
 870                                         ->from(new Address($this->config
['contact']['mail'], $this->config
['contact']['title'])) 
 872                                         //XXX: remove the debug set in vendor/symfony/mime/Address.php +46 
 873                                         ->to(new Address($registerMail['context']['recipient_mail'], $registerMail['context']['recipient_name'])) 
 875                                         ->subject($registerMail['subject']) 
 877                                         //Set path to twig templates 
 878                                         ->htmlTemplate($registerMail['html']) 
 879                                         ->textTemplate($registerMail['text']) 
 882                                         ->context(['subject' => $registerMail['subject']]+
$registerMail['context']); 
 884                                 //Try saving in database 
 889                                         //Add error message mail already exists 
 890                                         $this->addFlash('notice', $this->translator
->trans('Your account has been created')); 
 892                                         //Try sending message 
 893                                         //XXX: mail delivery may silently fail 
 896                                                 $mailer->send($message); 
 898                                                 //Redirect on the same route with sent=1 to cleanup form 
 899                                                 return $this->redirectToRoute($request->get('_route'), ['sent' => 1]+
$request->get('_route_params')); 
 900                                         //Catch obvious transport exception 
 901                                         } catch(TransportExceptionInterface 
$e) { 
 902                                                 //Add error message mail unreachable 
 903                                                 $form->get('mail')->addError(new FormError($this->translator
->trans('Account %mail% tried subscribe but unable to contact', ['%mail%' => $data->getMail()]))); 
 905                                 //Catch double subscription 
 906                                 } catch (UniqueConstraintViolationException 
$e) { 
 907                                         //Add error message mail already exists 
 908                                         $this->addFlash('error', $this->translator
->trans('Account %mail% already exists', ['%mail%' => $mail])); 
 914                 return $this->render( 
 916                         $this->config
['register']['view']['name'], 
 918                         ['form' => $form->createView(), 'sent' => $request->query
->get('sent', 0)]+
$this->config
['register']['view']['context']