3 namespace Rapsys\UserBundle\Controller
; 
   5 use Symfony\Bridge\Twig\Mime\TemplatedEmail
; 
   6 use Symfony\Bundle\FrameworkBundle\Controller\AbstractController
; 
   7 use Symfony\Component\DependencyInjection\ContainerInterface
; 
   8 use Symfony\Component\HttpKernel\Exception\BadRequestHttpException
; 
   9 use Symfony\Component\Form\FormError
; 
  10 use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken
; 
  11 use Symfony\Component\HttpFoundation\Request
; 
  12 use Symfony\Component\Mailer\Exception\TransportExceptionInterface
; 
  13 use Symfony\Component\Mailer\MailerInterface
; 
  14 use Symfony\Component\Mime\Address
; 
  15 use Symfony\Component\Routing\Generator\UrlGeneratorInterface
; 
  16 use Symfony\Component\Routing\RouterInterface
; 
  17 use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface
; 
  18 use Symfony\Component\Security\Http\Authentication\AuthenticationUtils
; 
  19 use Symfony\Component\Translation\TranslatorInterface
; 
  20 use Psr\Log\LoggerInterface
; 
  22 use Rapsys\PackBundle\Util\SluggerUtil
; 
  24 class DefaultController 
extends AbstractController 
{ 
  29         protected $translator; 
  34          * @TODO: move all canonical and other view related stuff in an user AbstractController like in RapsysAir render feature !!!! 
  36          * @param ContainerInterface $container The containter instance 
  37          * @param RouterInterface $router The router instance 
  38          * @param TranslatorInterface $translator The translator instance 
  40         public function __construct(ContainerInterface 
$container, RouterInterface 
$router, TranslatorInterface 
$translator) { 
  42                 $this->config 
= $container->getParameter($this->getAlias()); 
  45                 $this->translator 
= $translator; 
  48                 $stack = $container->get('request_stack'); 
  51                 $request = $stack->getCurrentRequest(); 
  54                 $currentLocale = $request->getLocale(); 
  57                 $this->config
['context']['locale'] = str_replace('_', '-', $currentLocale); 
  62                 //Look for keys to translate 
  63                 if (!empty($this->config
['translate'])) { 
  64                         //Iterate on keys to translate 
  65                         foreach($this->config
['translate'] as $translate) { 
  69                                 foreach(array_reverse(explode('.', $translate)) as $curkey) { 
  70                                         $tmp = array_combine([$curkey], [$tmp]); 
  73                                 $translates = array_replace_recursive($translates, $tmp); 
  77                 //Inject every requested route in view and mail context 
  78                 foreach($this->config 
as $tag => $current) { 
  79                         //Look for entry with title subkey 
  80                         if (!empty($current['title'])) { 
  81                                 //Translate title value 
  82                                 $this->config
[$tag]['title'] = $translator->trans($current['title']); 
  85                         //Look for entry with route subkey 
  86                         if (!empty($current['route'])) { 
  87                                 //Generate url for both view and mail 
  88                                 foreach(['view', 'mail'] as $view) { 
  89                                         //Check that context key is usable 
  90                                         if (isset($current[$view]['context']) && is_array($current[$view]['context'])) { 
  91                                                 //Merge with global context 
  92                                                 $this->config
[$tag][$view]['context'] = array_replace_recursive($this->config
['context'], $this->config
[$tag][$view]['context']); 
  94                                                 //Process every routes 
  95                                                 foreach($current['route'] as $route => $key) { 
  97                                                         if ($route == 'confirm') { 
  98                                                                 //Skip route as it requires some parameters 
 103                                                         $value = $router->generate( 
 104                                                                 $this->config
['route'][$route]['name'], 
 105                                                                 $this->config
['route'][$route]['context'], 
 106                                                                 //Generate absolute url for mails 
 107                                                                 $view=='mail'?UrlGeneratorInterface
::ABSOLUTE_URL
:UrlGeneratorInterface
::ABSOLUTE_PATH
 
 111                                                         if (strpos($key, '.') !== false) { 
 116                                                                 foreach(array_reverse(explode('.', $key)) as $curkey) { 
 117                                                                         $tmp = array_combine([$curkey], [$tmp]); 
 121                                                                 $this->config
[$tag][$view]['context'] = array_replace_recursive($this->config
[$tag][$view]['context'], $tmp); 
 125                                                                 $this->config
[$tag][$view]['context'][$key] = $value; 
 129                                                 //Look for successful intersections 
 130                                                 if (!empty(array_intersect_key($translates, $this->config
[$tag][$view]['context']))) { 
 131                                                         //Iterate on keys to translate 
 132                                                         foreach($this->config
['translate'] as $translate) { 
 134                                                                 $keys = explode('.', $translate); 
 137                                                                 $tmp = $this->config
[$tag][$view]['context']; 
 140                                                                 foreach($keys as $curkey) { 
 142                                                                         if (!isset($tmp[$curkey])) { 
 148                                                                         $tmp = $tmp[$curkey]; 
 151                                                                 //Translate tmp value 
 152                                                                 $tmp = $translator->trans($tmp); 
 155                                                                 foreach(array_reverse($keys) as $curkey) { 
 157                                                                         $tmp = array_combine([$curkey], [$tmp]); 
 161                                                                 $this->config
[$tag][$view]['context'] = array_replace_recursive($this->config
[$tag][$view]['context'], $tmp); 
 166                                                 if ($view == 'view') { 
 168                                                         $pathInfo = $router->getContext()->getPathInfo(); 
 170                                                         //Iterate on locales excluding current one 
 171                                                         foreach($this->config
['locales'] as $locale) { 
 175                                                                 //Iterate on other locales 
 176                                                                 foreach(array_diff($this->config
['locales'], [$locale]) as $other) { 
 177                                                                         $titles[$other] = $translator->trans($this->config
['languages'][$locale], [], null, $other); 
 180                                                                 //Retrieve route matching path 
 181                                                                 $route = $router->match($pathInfo); 
 184                                                                 $name = $route['_route']; 
 187                                                                 unset($route['_route']); 
 189                                                                 //With current locale 
 190                                                                 if ($locale == $currentLocale) { 
 191                                                                         //Set locale locales context 
 192                                                                         $this->config
[$tag][$view]['context']['canonical'] = $router->generate($name, ['_locale' => $locale]+
$route, UrlGeneratorInterface
::ABSOLUTE_URL
); 
 194                                                                         //Set locale locales context 
 195                                                                         $this->config
[$tag][$view]['context']['alternates'][$locale] = [ 
 196                                                                                 'absolute' => $router->generate($name, ['_locale' => $locale]+
$route, UrlGeneratorInterface
::ABSOLUTE_URL
), 
 197                                                                                 'relative' => $router->generate($name, ['_locale' => $locale]+
$route), 
 198                                                                                 'title' => implode('/', $titles), 
 199                                                                                 'translated' => $translator->trans($this->config
['languages'][$locale], [], null, $locale) 
 204                                                                 if (empty($this->config
[$tag][$view]['context']['alternates'][$slocale = substr($locale, 0, 2)])) { 
 206                                                                         $this->config
[$tag][$view]['context']['alternates'][$slocale] = [ 
 207                                                                                 'absolute' => $router->generate($name, ['_locale' => $locale]+
$route, UrlGeneratorInterface
::ABSOLUTE_URL
), 
 208                                                                                 'relative' => $router->generate($name, ['_locale' => $locale]+
$route), 
 209                                                                                 'title' => implode('/', $titles), 
 210                                                                                 'translated' => $translator->trans($this->config
['languages'][$locale], [], null, $locale) 
 222          * Confirm account from mail link 
 224          * @param Request $request The request 
 225          * @param UserPasswordEncoderInterface $encoder The password encoder 
 226          * @param SluggerUtil $slugger The slugger 
 227          * @param MailerInterface $mailer The mailer 
 228          * @param string $mail The shorted mail address 
 229          * @param string $extra The serialized then shorted extra array 
 230          * @param string $hash The hashed password 
 231          * @return Response The response 
 233         public function confirm(Request 
$request, UserPasswordEncoderInterface 
$encoder, SluggerUtil 
$slugger, MailerInterface 
$mailer, $mail, $extra, $hash) { 
 235                 $doctrine = $this->getDoctrine(); 
 238                 if ($hash != $slugger->hash($mail.$extra)) { 
 240                         throw new BadRequestHttpException($this->translator
->trans('Invalid %field% field: %value%', ['%field%' => 'hash', '%value%' => $hash])); 
 244                 $mail = $slugger->unshort($smail = $mail); 
 247                 if (filter_var($mail, FILTER_VALIDATE_EMAIL
) === false) { 
 249                         throw new BadRequestHttpException($this->translator
->trans('Invalid %field% field: %value%', ['%field%' => 'mail', '%value%' => $mail])); 
 252                 //With existing subscriber 
 253                 if ($doctrine->getRepository($this->config
['class']['user'])->findOneByMail($mail)) { 
 254                         //Add error message mail already exists 
 255                         $this->addFlash('error', $this->translator
->trans('Account %mail% already exists', ['%mail%' => $mail])); 
 257                         //Redirect to user view 
 258                         return $this->redirectToRoute($this->config
['route']['edit']['name'], ['mail' => $smail]+
$this->config
['route']['edit']['context']); 
 262                 $extra = $slugger->unserialize($sextra = $extra); 
 264                 //Without valid extra 
 265                 if (!is_array($extra)) { 
 267                         throw new BadRequestHttpException($this->translator
->trans('Invalid %field% field: %value%', ['%field%' => 'extra', '%value%' => $sextra])); 
 270                 //Extract names and pseudonym from mail 
 271                 $names = explode(' ', $pseudonym = ucwords(trim(preg_replace('/[^a-zA-Z]+/', ' ', current(explode('@', $mail)))))); 
 274                 $manager = $doctrine->getManager(); 
 277                 $reflection = new \
ReflectionClass($this->config
['class']['user']); 
 280                 $user = $reflection->newInstance(); 
 283                 $user->setMail($mail); 
 287                         'civility(title)' => $this->config
['default']['civility'], 
 288                         'pseudonym' => $pseudonym, 
 289                         'forename' => $names[0]??$pseudonym, 
 290                         'surname' => $names[1]??$pseudonym, 
 291                         'password' => $encoder->encodePassword($user, $mail), 
 295                 //Iterate on each default value 
 296                 //TODO: store add/set action between [] ??? 
 297                 foreach($extra+
$default as $key => $value) { 
 302                         if (substr($key, -strlen('(title)')) === '(title)') { 
 304                                 $member = substr($member, 0, -strlen('(title)')); 
 306                                 //Get object as value 
 307                                 $value = $doctrine->getRepository($this->config
['class'][$member])->findOneByTitle($value); 
 309                         } elseif (substr($key, -strlen('(id)')) === '(id)') { 
 311                                 $member = substr($member, 0, -strlen('(id)')); 
 313                                 //Get object as value 
 314                                 $value = $doctrine->getRepository($this->config
['class'][$key])->findOneById($value); 
 318                         $user->{'set'.ucfirst($member
)}($value); 
 324                 //Iterate on default group 
 325                 foreach($this->config
['default']['group'] as $i => $groupTitle) { 
 327                         if (($group = $doctrine->getRepository($this->config
['class']['group'])->findOneByTitle($groupTitle))) { 
 329                                 //XXX: see vendor/symfony/security-core/Role/Role.php 
 330                                 $user->addGroup($group); 
 334                                 //XXX: consider missing group as fatal 
 335                                 throw new \
Exception(sprintf('Group from rapsys_user.default.group[%d] not found by title: %s', $i, $groupTitle)); 
 339                 $user->setCreated(new \
DateTime('now')); 
 340                 $user->setUpdated(new \
DateTime('now')); 
 343                 $manager->persist($user); 
 345                 //Try saving in database 
 350                         //Add error message mail already exists 
 351                         $this->addFlash('notice', $this->translator
->trans('Your account has been created')); 
 352                 //Catch double subscription 
 353                 } catch (\Doctrine\DBAL\Exception\UniqueConstraintViolationException 
$e) { 
 354                         //Add error message mail already exists 
 355                         $this->addFlash('error', $this->translator
->trans('Account %mail% already exists', ['%mail%' => $mail])); 
 358                 //Redirect to user view 
 359                 return $this->redirectToRoute($this->config
['route']['edit']['name'], ['mail' => $smail]+
$this->config
['route']['edit']['context']); 
 363          * Edit account by shorted mail 
 365          * @param Request $request The request 
 366          * @param SluggerUtil $slugger The slugger 
 367          * @param string $mail The shorted mail address 
 368          * @return Response The response 
 370         public function edit(Request 
$request, SluggerUtil 
$slugger, $mail) { 
 372                 $doctrine = $this->getDoctrine(); 
 375                 $mail = $slugger->unshort($smail = $mail); 
 377                 //With existing subscriber 
 378                 if (empty($user = $doctrine->getRepository($this->config
['class']['user'])->findOneByMail($mail))) { 
 381                         //XXX: prevent slugger reverse engineering by not displaying decoded mail 
 382                         throw $this->createNotFoundException($this->translator
->trans('Unable to find account %mail%', ['%mail%' => $smail])); 
 386                 $token = new UsernamePasswordToken($user, null, 'none', $user->getRoles()); 
 389                 $isGuest = $this->get('rapsys_user.access_decision_manager')->decide($token, ['ROLE_GUEST']); 
 391                 //Prevent access when not admin, user is not guest and not currently logged user 
 392                 if (!$this->isGranted('ROLE_ADMIN') && empty($isGuest) && $user != $this->getUser()) { 
 393                         //Throw access denied 
 394                         //XXX: prevent slugger reverse engineering by not displaying decoded mail 
 395                         throw $this->createAccessDeniedException($this->translator
->trans('Unable to access user: %mail%', ['%mail%' => $smail])); 
 398                 //Create the RegisterType form and give the proper parameters 
 399                 $form = $this->createForm($this->config
['register']['view']['form'], $user, [ 
 400                         //Set action to register route name and context 
 401                         'action' => $this->generateUrl($this->config
['route']['edit']['name'], ['mail' => $smail]+
$this->config
['route']['edit']['context']), 
 403                         'civility_class' => $this->config
['class']['civility'], 
 404                         //Set civility default 
 405                         'civility_default' => $doctrine->getRepository($this->config
['class']['civility'])->findOneByTitle($this->config
['default']['civility']), 
 407                         'mail' => $this->isGranted('ROLE_ADMIN'), 
 409                         //XXX: prefer a reset on login to force user unspam action 
 415                 if ($request->isMethod('POST')) { 
 416                         //Refill the fields in case the form is not valid. 
 417                         $form->handleRequest($request); 
 419                         if ($form->isValid()) { 
 421                                 $data = $form->getData(); 
 424                                 $manager = $doctrine->getManager(); 
 427                                 $manager->persist($data); 
 429                                 //Flush to get the ids 
 433                                 $this->addFlash('notice', $this->translator
->trans('Account %mail% updated', ['%mail%' => $mail])); 
 435                                 //Redirect to user view 
 436                                 //TODO: extract referer ??? or useless ??? 
 437                                 return $this->redirectToRoute($this->config
['route']['edit']['name'], ['mail' => $smail]+
$this->config
['route']['edit']['context']); 
 439                                 //Redirect to cleanup the form 
 440                                 return $this->redirectToRoute('rapsys_air', ['user' => $data->getId()]); 
 444                         $this->addFlash('notice', $this->translator
->trans('To change your password login with your mail %mail% and any password then follow the procedure', ['%mail%' => $mail])); 
 448                 return $this->render( 
 450                         $this->config
['edit']['view']['name'], 
 452                         ['form' => $form->createView(), 'sent' => $request->query
->get('sent', 0)]+
$this->config
['edit']['view']['context'] 
 459          * @param Request $request The request 
 460          * @param AuthenticationUtils $authenticationUtils The authentication utils 
 461          * @return Response The response 
 463         public function login(Request 
$request, AuthenticationUtils 
$authenticationUtils) { 
 464                 //Create the LoginType form and give the proper parameters 
 465                 $login = $this->createForm($this->config
['login']['view']['form'], null, [ 
 466                         //Set action to login route name and context 
 467                         'action' => $this->generateUrl($this->config
['route']['login']['name'], $this->config
['route']['login']['context']), 
 474                 //Last username entered by the user 
 475                 if ($lastUsername = $authenticationUtils->getLastUsername()) { 
 476                         $login->get('mail')->setData($lastUsername); 
 479                 //Get the login error if there is one 
 480                 if ($error = $authenticationUtils->getLastAuthenticationError()) { 
 481                         //Get translated error 
 482                         $error = $this->translator
->trans($error->getMessageKey()); 
 484                         //Add error message to mail field 
 485                         $login->get('mail')->addError(new FormError($error)); 
 487                         //Create the RecoverType form and give the proper parameters 
 488                         $recover = $this->createForm($this->config
['recover']['view']['form'], null, [ 
 489                                 //Set action to recover route name and context 
 490                                 'action' => $this->generateUrl($this->config
['route']['recover']['name'], $this->config
['route']['recover']['context']), 
 497                         //Get recover mail entity 
 498                         $recover->get('mail') 
 499                                 //Set mail from login form 
 500                                 ->setData($login->get('mail')->getData()) 
 502                                 ->addError(new FormError($this->translator
->trans('Use this form to recover your account'))); 
 504                         //Add recover form to context 
 505                         $context['recover'] = $recover->createView(); 
 508                         $this->addFlash('notice', $this->translator
->trans('To change your password login with your mail and any password then follow the procedure')); 
 512                 return $this->render( 
 514                         $this->config
['login']['view']['name'], 
 516                         ['login' => $login->createView()]+
$context+
$this->config
['login']['view']['context'] 
 523          * @param Request $request The request 
 524          * @param UserPasswordEncoderInterface $encoder The password encoder 
 525          * @param SluggerUtil $slugger The slugger 
 526          * @param MailerInterface $mailer The mailer 
 527          * @param string $mail The shorted mail address 
 528          * @param string $pass The shorted password 
 529          * @param string $hash The hashed password 
 530          * @return Response The response 
 532         public function recover(Request 
$request, UserPasswordEncoderInterface 
$encoder, SluggerUtil 
$slugger, MailerInterface 
$mailer, $mail, $pass, $hash) { 
 534                 $doctrine = $this->getDoctrine(); 
 536                 //Without mail, pass and hash 
 537                 if (empty($mail) && empty($pass) && empty($hash)) { 
 538                         //Create the RecoverType form and give the proper parameters 
 539                         $form = $this->createForm($this->config
['recover']['view']['form'], null, [ 
 540                                 //Set action to recover route name and context 
 541                                 'action' => $this->generateUrl($this->config
['route']['recover']['name'], $this->config
['route']['recover']['context']), 
 548                         if ($request->isMethod('POST')) { 
 549                                 //Refill the fields in case the form is not valid. 
 550                                 $form->handleRequest($request); 
 552                                 if ($form->isValid()) { 
 554                                         $data = $form->getData(); 
 556                                         //Find user by data mail 
 557                                         if ($user = $doctrine->getRepository($this->config
['class']['user'])->findOneByMail($data['mail'])) { 
 559                                                 $recoverMail =& $this->config
['recover']['mail']; 
 562                                                 $mail = $slugger->short($user->getMail()); 
 565                                                 $pass = $slugger->hash($user->getPassword()); 
 567                                                 //Generate each route route 
 568                                                 foreach($this->config
['recover']['route'] as $route => $tag) { 
 569                                                         //Only process defined routes 
 570                                                         if (!empty($this->config
['route'][$route])) { 
 571                                                                 //Process for recover mail url 
 572                                                                 if ($route == 'recover') { 
 573                                                                         //Set the url in context 
 574                                                                         $recoverMail['context'][$tag] = $this->get('router')->generate( 
 575                                                                                 $this->config
['route'][$route]['name'], 
 576                                                                                 //Prepend recover context with tag 
 580                                                                                         'hash' => $slugger->hash($mail.$pass) 
 581                                                                                 ]+
$this->config
['route'][$route]['context'], 
 582                                                                                 UrlGeneratorInterface
::ABSOLUTE_URL
 
 589                                                 $recoverMail['context']['recipient_mail'] = $user->getMail(); 
 592                                                 $recoverMail['context']['recipient_name'] = trim($user->getForename().' '.$user->getSurname().($user->getPseudonym()?' ('.$user->getPseudonym().')':'')); 
 594                                                 //Init subject context 
 595                                                 $subjectContext = $slugger->flatten(array_replace_recursive($this->config
['recover']['view']['context'], $recoverMail['context']), null, '.', '%', '%'); 
 598                                                 $recoverMail['subject'] = ucfirst($this->translator
->trans($recoverMail['subject'], $subjectContext)); 
 601                                                 $message = (new TemplatedEmail()) 
 603                                                         ->from(new Address($this->config
['contact']['mail'], $this->config
['contact']['title'])) 
 605                                                         //XXX: remove the debug set in vendor/symfony/mime/Address.php +46 
 606                                                         ->to(new Address($recoverMail['context']['recipient_mail'], $recoverMail['context']['recipient_name'])) 
 608                                                         ->subject($recoverMail['subject']) 
 610                                                         //Set path to twig templates 
 611                                                         ->htmlTemplate($recoverMail['html']) 
 612                                                         ->textTemplate($recoverMail['text']) 
 615                                                         //XXX: require recursive merge to avoid loosing subkeys 
 616                                                         //['subject' => $recoverMail['subject']]+$recoverMail['context']+$this->config['recover']['view']['context'] 
 617                                                         ->context(array_replace_recursive($this->config
['recover']['view']['context'], $recoverMail['context'], ['subject' => $recoverMail['subject']])); 
 619                                                 //Try sending message 
 620                                                 //XXX: mail delivery may silently fail 
 623                                                         $mailer->send($message); 
 625                                                         //Redirect on the same route with sent=1 to cleanup form 
 626                                                         return $this->redirectToRoute($request->get('_route'), ['sent' => 1]+
$request->get('_route_params')); 
 627                                                 //Catch obvious transport exception 
 628                                                 } catch(TransportExceptionInterface 
$e) { 
 629                                                         //Add error message mail unreachable 
 630                                                         $form->get('mail')->addError(new FormError($this->translator
->trans('Account found but unable to contact: %mail%', array('%mail%' => $data['mail'])))); 
 634                                                 //Add error message to mail field 
 635                                                 $form->get('mail')->addError(new FormError($this->translator
->trans('Unable to find account %mail%', ['%mail%' => $data['mail']]))); 
 641                         return $this->render( 
 643                                 $this->config
['recover']['view']['name'], 
 645                                 ['form' => $form->createView(), 'sent' => $request->query
->get('sent', 0)]+
$this->config
['recover']['view']['context'] 
 650                 if ($hash != $slugger->hash($mail.$pass)) { 
 652                         throw new BadRequestHttpException($this->translator
->trans('Invalid %field% field: %value%', ['%field%' => 'hash', '%value%' => $hash])); 
 656                 $mail = $slugger->unshort($smail = $mail); 
 659                 if (filter_var($mail, FILTER_VALIDATE_EMAIL
) === false) { 
 661                         throw new BadRequestHttpException($this->translator
->trans('Invalid %field% field: %value%', ['%field%' => 'mail', '%value%' => $mail])); 
 664                 //With existing subscriber 
 665                 if (empty($user = $doctrine->getRepository($this->config
['class']['user'])->findOneByMail($mail))) { 
 667                         //XXX: prevent slugger reverse engineering by not displaying decoded mail 
 668                         throw $this->createNotFoundException($this->translator
->trans('Unable to find account %mail%', ['%mail%' => $smail])); 
 671                 //With unmatched pass 
 672                 if ($pass != $slugger->hash($user->getPassword())) { 
 674                         //XXX: prevent use of outdated recover link 
 675                         throw $this->createNotFoundException($this->translator
->trans('Outdated recover link')); 
 678                 //Create the RecoverType form and give the proper parameters 
 679                 $form = $this->createForm($this->config
['recover']['view']['form'], $user, [ 
 680                         //Set action to recover route name and context 
 681                         'action' => $this->generateUrl($this->config
['route']['recover']['name'], ['mail' => $smail, 'pass' => $pass, 'hash' => $hash]+
$this->config
['route']['recover']['context']), 
 688                 if ($request->isMethod('POST')) { 
 689                         //Refill the fields in case the form is not valid. 
 690                         $form->handleRequest($request); 
 692                         if ($form->isValid()) { 
 694                                 $data = $form->getData(); 
 696                                 //Set encoded password 
 697                                 $encoded = $encoder->encodePassword($user, $user->getPassword()); 
 700                                 $pass = $slugger->hash($encoded); 
 703                                 $user->setPassword($encoded); 
 706                                 $user->setUpdated(new \
DateTime('now')); 
 709                                 $manager = $doctrine->getManager(); 
 712                                 $manager->persist($user); 
 718                                 $this->addFlash('notice', $this->translator
->trans('Account %mail% password updated', ['%mail%' => $mail])); 
 720                                 //Redirect to user login 
 721                                 return $this->redirectToRoute($this->config
['route']['login']['name'], ['mail' => $smail, 'hash' => $slugger->hash($smail)]+
$this->config
['route']['login']['context']); 
 726                 return $this->render( 
 728                         $this->config
['recover']['view']['name'], 
 730                         ['form' => $form->createView(), 'sent' => $request->query
->get('sent', 0)]+
$this->config
['recover']['view']['context'] 
 735          * Register an account 
 737          * @param Request $request The request 
 738          * @param UserPasswordEncoderInterface $encoder The password encoder 
 739          * @param SluggerUtil $slugger The slugger 
 740          * @param MailerInterface $mailer The mailer 
 741          * @param LoggerInterface $logger The logger 
 742          * @param string $field The serialized then shorted form field array 
 743          * @param string $hash The hashed serialized field array 
 744          * @return Response The response 
 746         public function register(Request 
$request, UserPasswordEncoderInterface 
$encoder, SluggerUtil 
$slugger, MailerInterface 
$mailer, LoggerInterface 
$logger, $field, $hash) { 
 748                 $doctrine = $this->getDoctrine(); 
 751                 if (!empty($field) && !empty($hash)) { 
 753                         if ($hash != $slugger->hash($field)) { 
 755                                 throw new BadRequestHttpException($this->translator
->trans('Invalid %field% field: %value%', ['%field%' => 'hash', '%value%' => $hash])); 
 760                                 //Unshort then unserialize field 
 761                                 $field = $slugger->unserialize($field); 
 763                         } catch (\Error
|\Exception 
$e) { 
 765                                 throw new BadRequestHttpException($this->translator
->trans('Invalid %field% field: %value%', ['%field%' => 'field', '%value%' => $field]), $e); 
 768                         //With non array field 
 769                         if (!is_array($field)) { 
 771                                 throw new BadRequestHttpException($this->translator
->trans('Invalid %field% field: %value%', ['%field%' => 'field', '%value%' => $field])); 
 773                 //Without field and hash 
 779                 //Create the RegisterType form and give the proper parameters 
 780                 $form = $this->createForm($this->config
['register']['view']['form'], null, $field+
[ 
 781                         //Set action to register route name and context 
 782                         'action' => $this->generateUrl($this->config
['route']['register']['name'], $this->config
['route']['register']['context']), 
 784                         'civility_class' => $this->config
['class']['civility'], 
 785                         //Set civility default 
 786                         'civility_default' => $doctrine->getRepository($this->config
['class']['civility'])->findOneByTitle($this->config
['default']['civility']), 
 793                 if ($request->isMethod('POST')) { 
 794                         //Refill the fields in case the form is not valid. 
 795                         $form->handleRequest($request); 
 797                         if ($form->isValid()) { 
 799                                 $data = $form->getData(); 
 802                                 $registerMail =& $this->config
['register']['mail']; 
 808                                 $reflection = new \
ReflectionClass($this->config
['class']['user']); 
 811                                 $user = $reflection->newInstance(); 
 813                                 //Iterate on each entry 
 814                                 //TODO: store add/set action between [] ??? 
 815                                 foreach($data as $key => $value) { 
 817                                         if ($key == 'mail') { 
 819                                         //Store shorted title 
 820                                         } elseif (is_callable([$value, 'getTitle'])) { 
 821                                                 $extra[$key.'(title)'] = $value->getTitle(); 
 823                                         } elseif (is_callable([$value, 'getId'])) { 
 824                                                 $extra[$key.'(id)'] = $value->getId(); 
 825                                         //Store encoded password 
 826                                         } elseif(!empty($value) && $key == 'password') { 
 827                                                 $extra['password'] = $encoder->encodePassword($user, $value); 
 828                                         //Store shorted value 
 829                                         } elseif (!empty($value)) { 
 830                                                 $extra[$key] = $value; 
 835                                 $mail = $slugger->short($data['mail']); 
 838                                 $extra = $slugger->serialize($extra); 
 840                                 //Generate each route route 
 841                                 foreach($this->config
['register']['route'] as $route => $tag) { 
 842                                         //Only process defined routes 
 843                                         if (!empty($this->config
['route'][$route])) { 
 844                                                 //Process for confirm url 
 845                                                 if ($route == 'confirm') { 
 846                                                         //Set the url in context 
 847                                                         $registerMail['context'][$tag] = $this->get('router')->generate( 
 848                                                                 $this->config
['route'][$route]['name'], 
 849                                                                 //Prepend subscribe context with tag 
 853                                                                         'hash' => $slugger->hash($mail.$extra) 
 854                                                                 ]+
$this->config
['route'][$route]['context'], 
 855                                                                 UrlGeneratorInterface
::ABSOLUTE_URL
 
 863                                         $this->translator
->trans( 
 864                                                 'newuser:mail=%mail%|locale=%locale%|confirm=%confirm%', 
 866                                                         '%mail%' => $data['mail'], 
 867                                                         '%locale%' => $request->getLocale(), 
 868                                                         '%confirm%' => $registerMail['context'][$this->config
['register']['route']['confirm']] 
 874                                 $registerMail['context']['recipient_mail'] = $data['mail']; 
 877                                 $registerMail['context']['recipient_name'] = ''; 
 879                                 //With forename, surname and pseudonym 
 880                                 if (isset($data['forename']) && isset($data['surname']) && isset($data['pseudonym'])) { 
 882                                         $registerMail['context']['recipient_name'] = implode(' ', [$data['forename'], $data['surname'], $data['pseudonym']?'('.$data['pseudonym'].')':'']); 
 884                                 } elseif (isset($data['pseudonym'])) { 
 886                                         $registerMail['context']['recipient_name'] = $data['pseudonym']; 
 889                                 //Init subject context 
 890                                 $subjectContext = $slugger->flatten(array_replace_recursive($this->config
['register']['view']['context'], $registerMail['context']), null, '.', '%', '%'); 
 893                                 $registerMail['subject'] = ucfirst($this->translator
->trans($registerMail['subject'], $subjectContext)); 
 896                                 $message = (new TemplatedEmail()) 
 898                                         ->from(new Address($this->config
['contact']['mail'], $this->config
['contact']['title'])) 
 900                                         //XXX: remove the debug set in vendor/symfony/mime/Address.php +46 
 901                                         ->to(new Address($registerMail['context']['recipient_mail'], $registerMail['context']['recipient_name'])) 
 903                                         ->subject($registerMail['subject']) 
 905                                         //Set path to twig templates 
 906                                         ->htmlTemplate($registerMail['html']) 
 907                                         ->textTemplate($registerMail['text']) 
 910                                         ->context(['subject' => $registerMail['subject']]+
$registerMail['context']); 
 912                                 //Try sending message 
 913                                 //XXX: mail delivery may silently fail 
 916                                         $mailer->send($message); 
 918                                         //Redirect on the same route with sent=1 to cleanup form 
 919                                         return $this->redirectToRoute($request->get('_route'), ['sent' => 1]+
$request->get('_route_params')); 
 920                                 //Catch obvious transport exception 
 921                                 } catch(TransportExceptionInterface 
$e) { 
 922                                         //Add error message mail unreachable 
 923                                         $form->get('mail')->addError(new FormError($this->translator
->trans('Account %mail% tried subscribe but unable to contact', array('%mail%' => $data['mail'])))); 
 929                 return $this->render( 
 931                         $this->config
['register']['view']['name'], 
 933                         ['form' => $form->createView(), 'sent' => $request->query
->get('sent', 0)]+
$this->config
['register']['view']['context'] 
 940         public function getAlias() { 
 941                 return 'rapsys_user';