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';