3 namespace Rapsys\UserBundle\Controller
;
5 use Rapsys\UserBundle\Utils\Slugger
;
6 use Symfony\Bridge\Twig\Mime\TemplatedEmail
;
7 use Symfony\Bundle\FrameworkBundle\Controller\AbstractController
;
8 use Symfony\Component\DependencyInjection\ContainerInterface
;
9 use Symfony\Component\Form\FormError
;
10 use Symfony\Component\HttpFoundation\Request
;
11 use Symfony\Component\Mailer\Exception\TransportExceptionInterface
;
12 use Symfony\Component\Mailer\MailerInterface
;
13 use Symfony\Component\Mime\Address
;
14 use Symfony\Component\Routing\Generator\UrlGeneratorInterface
;
15 use Symfony\Component\Routing\RouterInterface
;
16 use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface
;
17 use Symfony\Component\Security\Http\Authentication\AuthenticationUtils
;
18 use Symfony\Component\Translation\TranslatorInterface
;
20 class DefaultController
extends AbstractController
{
25 protected $translator;
27 public function __construct(ContainerInterface
$container, TranslatorInterface
$translator, RouterInterface
$router) {
29 $this->config
= $container->getParameter($this->getAlias());
32 $this->translator
= $translator;
35 //XXX: we don't use this as it would be too slow, maybe ???
36 #$action = str_replace(self::getAlias().'_', '', $container->get('request_stack')->getCurrentRequest()->get('_route'));
38 //Inject every requested route in view and mail context
39 foreach($this->config
as $tag => $current) {
40 //Look for entry with route subkey
41 if (!empty($current['route'])) {
42 //Generate url for both view and mail
43 foreach(['view', 'mail'] as $view) {
44 //Check that context key is usable
45 if (isset($current[$view]['context']) && is_array($current[$view]['context'])) {
46 //Process every routes
47 foreach($current['route'] as $route => $key) {
48 //Skip recover_mail route as it requires some parameters
49 if ($route == 'recover_mail') {
52 //Check that key is empty
53 if (!isset($current[$view]['context'][$key])) {
55 $this->config
[$tag][$view]['context'][$key] = $router->generate(
56 $this->config
['route'][$route]['name'],
57 $this->config
['route'][$route]['context'],
58 //Generate absolute url for mails
59 $view=='mail'?UrlGeneratorInterface
::ABSOLUTE_URL
:UrlGeneratorInterface
::ABSOLUTE_PATH
69 public function login(Request
$request, AuthenticationUtils
$authenticationUtils) {
70 //Create the LoginType form and give the proper parameters
71 $login = $this->createForm($this->config
['login']['view']['form'], null, [
72 //Set action to login route name and context
73 'action' => $this->generateUrl($this->config
['route']['login']['name'], $this->config
['route']['login']['context']),
80 //Last username entered by the user
81 if ($lastUsername = $authenticationUtils->getLastUsername()) {
82 $login->get('mail')->setData($lastUsername);
85 //Get the login error if there is one
86 if ($error = $authenticationUtils->getLastAuthenticationError()) {
87 //Get translated error
88 $error = $this->translator
->trans($error->getMessageKey());
90 //Add error message to mail field
91 $login->get('mail')->addError(new FormError($error));
93 //Create the RecoverType form and give the proper parameters
94 $recover = $this->createForm($this->config
['recover']['view']['form'], null, [
95 //Set action to recover route name and context
96 'action' => $this->generateUrl($this->config
['route']['recover']['name'], $this->config
['route']['recover']['context']),
100 //Get recover mail entity
101 $recover->get('mail')
102 //Set mail from login form
103 ->setData($login->get('mail')->getData())
105 ->addError(new FormError($this->translator
->trans('Use this form to recover your account')));
107 //Add recover form to context
108 $context['recover'] = $recover->createView();
112 return $this->render(
114 $this->config
['login']['view']['name'],
116 ['login' => $login->createView()]+
$context+
$this->config
['login']['view']['context']
120 public function recover(Request
$request, Slugger
$slugger, MailerInterface
$mailer) {
121 //Create the RecoverType form and give the proper parameters
122 $form = $this->createForm($this->config
['recover']['view']['form'], null, array(
123 //Set action to recover route name and context
124 'action' => $this->generateUrl($this->config
['route']['recover']['name'], $this->config
['route']['recover']['context']),
128 if ($request->isMethod('POST')) {
129 //Refill the fields in case the form is not valid.
130 $form->handleRequest($request);
132 if ($form->isValid()) {
134 $doctrine = $this->getDoctrine();
137 $data = $form->getData();
140 if ($user = $doctrine->getRepository($this->config
['class']['user'])->findOneByMail($data['mail'])) {
142 $mail =& $this->config
['recover']['mail'];
144 //Generate each route route
145 foreach($this->config
['recover']['route'] as $route => $tag) {
146 //Only process defined routes
147 if (empty($mail['context'][$tag]) && !empty($this->config
['route'][$route])) {
148 //Process for recover mail url
149 if ($route == 'recover_mail') {
150 //Prepend recover context with tag
151 $this->config
['route'][$route]['context'] = [
152 'recipient' => $slugger->short($user->getMail()),
153 'hash' => $slugger->hash($user->getPassword())
154 ]+
$this->config
['route'][$route]['context'];
156 //Set the url in context
157 $mail['context'][$tag] = $this->get('router')->generate(
158 $this->config
['route'][$route]['name'],
159 $this->config
['route'][$route]['context'],
160 UrlGeneratorInterface
::ABSOLUTE_URL
167 $mail['context']['recipient_mail'] = $data['mail'];
170 $mail['context']['recipient_name'] = trim($user->getForename().' '.$user->getSurname().($user->getPseudonym()?' ('.$user->getPseudonym().')':''));
172 //Init subject context
173 $subjectContext = [];
175 //Process each context pair
176 foreach($mail['context']+
$this->config
['recover']['view']['context'] as $k => $v) {
177 //Reinsert each context pair with the key surrounded by %
178 $subjectContext['%'.$k.'%'] = $v;
182 $mail['subject'] = ucfirst($this->translator
->trans($mail['subject'], $subjectContext));
185 $message = (new TemplatedEmail())
187 ->from(new Address($this->config
['contact']['mail'], $this->config
['contact']['name']))
189 //XXX: remove the debug set in vendor/symfony/mime/Address.php +46
190 ->to(new Address($mail['context']['recipient_mail'], $mail['context']['recipient_name']))
192 ->subject($mail['subject'])
194 //Set path to twig templates
195 ->htmlTemplate($mail['html'])
196 ->textTemplate($mail['text'])
199 ->context(['subject' => $mail['subject']]+
$mail['context']+
$this->config
['recover']['view']['context']);
201 //Try sending message
202 //XXX: mail delivery may silently fail
205 $mailer->send($message);
207 //Redirect on the same route with sent=1 to cleanup form
208 #return $this->redirectToRoute('rapsys_user_register', array('sent' => 1));
209 return $this->redirectToRoute($request->get('_route'), ['sent' => 1]+
$request->get('_route_params'));
210 //Catch obvious transport exception
211 } catch(TransportExceptionInterface
$e) {
212 //Add error message mail unreachable
213 $form->get('mail')->addError(new FormError($this->translator
->trans('Account found but unable to contact: %mail%', array('%mail%' => $data['mail']))));
217 //Add error message to mail field
218 $form->get('mail')->addError(new FormError($this->translator
->trans('Unable to find account: %mail%', ['%mail%' => $data['mail']])));
224 return $this->render(
226 $this->config
['recover']['view']['name'],
228 ['form' => $form->createView(), 'sent' => $request->query
->get('sent', 0)]+
$this->config
['recover']['view']['context']
232 public function recoverMail(Request
$request, UserPasswordEncoderInterface
$encoder, Slugger
$slugger, MailerInterface
$mailer, $recipient, $hash) {
233 //Create the RecoverType form and give the proper parameters
234 $form = $this->createForm($this->config
['recover_mail']['view']['form'], null, array(
235 //Set action to recover route name and context
236 'action' => $this->generateUrl($this->config
['route']['recover_mail']['name'], ['recipient' => $recipient, 'hash' => $hash]+
$this->config
['route']['recover_mail']['context']),
241 $doctrine = $this->getDoctrine();
247 if (($user = $doctrine->getRepository($this->config
['class']['user'])->findOneByMail($slugger->unshort($recipient))) && $found = ($hash == $slugger->hash($user->getPassword()))) {
248 if ($request->isMethod('POST')) {
249 //Refill the fields in case the form is not valid.
250 $form->handleRequest($request);
252 if ($form->isValid()) {
254 $data = $form->getData();
256 //set encoded password
257 $encoded = $encoder->encodePassword($user, $data['password']);
260 $user->setPassword($encoded);
263 $manager = $doctrine->getManager();
266 $manager->persist($user);
272 $mail =& $this->config
['recover_mail']['mail'];
275 $hash = $slugger->hash($encoded);
277 //Generate each route route
278 foreach($this->config
['recover_mail']['route'] as $route => $tag) {
279 //Only process defined routes
280 if (empty($mail['context'][$tag]) && !empty($this->config
['route'][$route])) {
281 //Process for recover mail url
282 if ($route == 'recover_mail') {
283 //Prepend recover context with tag
284 $this->config
['route'][$route]['context'] = [
285 'recipient' => $recipient,
287 ]+
$this->config
['route'][$route]['context'];
289 //Set the url in context
290 $mail['context'][$tag] = $this->get('router')->generate(
291 $this->config
['route'][$route]['name'],
292 $this->config
['route'][$route]['context'],
293 UrlGeneratorInterface
::ABSOLUTE_URL
299 $mail['context']['recipient_mail'] = $user->getMail();
302 $mail['context']['recipient_name'] = trim($user->getForename().' '.$user->getSurname().($user->getPseudonym()?' ('.$user->getPseudonym().')':''));
304 //Init subject context
305 $subjectContext = [];
307 //Process each context pair
308 foreach($mail['context']+
$this->config
['recover_mail']['view']['context'] as $k => $v) {
309 //Reinsert each context pair with the key surrounded by %
310 $subjectContext['%'.$k.'%'] = $v;
314 $mail['subject'] = ucfirst($this->translator
->trans($mail['subject'], $subjectContext));
317 $message = (new TemplatedEmail())
319 ->from(new Address($this->config
['contact']['mail'], $this->config
['contact']['name']))
321 //XXX: remove the debug set in vendor/symfony/mime/Address.php +46
322 ->to(new Address($mail['context']['recipient_mail'], $mail['context']['recipient_name']))
324 ->subject($mail['subject'])
326 //Set path to twig templates
327 ->htmlTemplate($mail['html'])
328 ->textTemplate($mail['text'])
331 ->context(['subject' => $mail['subject']]+
$mail['context']+
$this->config
['recover_mail']['view']['context']);
333 //Try sending message
334 //XXX: mail delivery may silently fail
337 $mailer->send($message);
339 //Redirect on the same route with sent=1 to cleanup form
340 return $this->redirectToRoute($request->get('_route'), ['recipient' => $recipient, 'hash' => $hash, 'sent' => 1]+
$request->get('_route_params'));
341 //Catch obvious transport exception
342 } catch(TransportExceptionInterface
$e) {
343 //Add error message mail unreachable
344 $form->get('password')->get('first')->addError(new FormError($this->translator
->trans('Account password updated but unable to contact: %mail%', array('%mail%' => $mail['context']['recipient_mail']))));
350 //Add error message to mail field
351 $form->addError(new FormError($this->translator
->trans('Unable to find account: %mail%', ['%mail%' => $slugger->unshort($recipient)])));
355 return $this->render(
357 $this->config
['recover_mail']['view']['name'],
359 ['form' => $form->createView(), 'sent' => $request->query
->get('sent', 0), 'found' => $found]+
$this->config
['recover_mail']['view']['context']
363 public function register(Request
$request, UserPasswordEncoderInterface
$encoder, MailerInterface
$mailer) {
365 $doctrine = $this->getDoctrine();
367 //Create the RegisterType form and give the proper parameters
368 $form = $this->createForm($this->config
['register']['view']['form'], null, array(
369 'class_title' => $this->config
['class']['title'],
370 'title' => $doctrine->getRepository($this->config
['class']['title'])->findOneByTitle($this->config
['default']['title']),
371 //Set action to register route name and context
372 'action' => $this->generateUrl($this->config
['route']['register']['name'], $this->config
['route']['register']['context']),
376 if ($request->isMethod('POST')) {
377 //Refill the fields in case the form is not valid.
378 $form->handleRequest($request);
380 if ($form->isValid()) {
382 $data = $form->getData();
385 $mail =& $this->config
['register']['mail'];
387 //Generate each route route
388 foreach($this->config
['register']['route'] as $route => $tag) {
389 if (empty($mail['context'][$tag]) && !empty($this->config
['route'][$route])) {
390 $mail['context'][$tag] = $this->get('router')->generate(
391 $this->config
['route'][$route]['name'],
392 $this->config
['route'][$route]['context'],
393 UrlGeneratorInterface
::ABSOLUTE_URL
399 $mail['context']['recipient_mail'] = $data['mail'];
402 $mail['context']['recipient_name'] = trim($data['forename'].' '.$data['surname'].($data['pseudonym']?' ('.$data['pseudonym'].')':''));
404 //Init subject context
405 $subjectContext = [];
407 //Process each context pair
408 foreach($mail['context']+
$this->config
['register']['view']['context'] as $k => $v) {
409 //Reinsert each context pair with the key surrounded by %
410 $subjectContext['%'.$k.'%'] = $v;
414 $mail['subject'] = ucfirst($this->translator
->trans($mail['subject'], $subjectContext));
417 $message = (new TemplatedEmail())
419 ->from(new Address($this->config
['contact']['mail'], $this->config
['contact']['name']))
421 //XXX: remove the debug set in vendor/symfony/mime/Address.php +46
422 ->to(new Address($mail['context']['recipient_mail'], $mail['context']['recipient_name']))
424 ->subject($mail['subject'])
426 //Set path to twig templates
427 ->htmlTemplate($mail['html'])
428 ->textTemplate($mail['text'])
431 ->context(['subject' => $mail['subject']]+
$mail['context']+
$this->config
['register']['view']['context']);
434 $manager = $doctrine->getManager();
437 $reflection = new \
ReflectionClass($this->config
['class']['user']);
440 $user = $reflection->newInstance();
442 $user->setMail($data['mail']);
443 $user->setPseudonym($data['pseudonym']);
444 $user->setForename($data['forename']);
445 $user->setSurname($data['surname']);
446 $user->setPhone($data['phone']);
447 $user->setPassword($encoder->encodePassword($user, $data['password']));
448 $user->setActive(true);
449 $user->setTitle($data['title']);
451 //Iterate on default group
452 foreach($this->config
['default']['group'] as $i => $groupTitle) {
454 if (($group = $doctrine->getRepository($this->config
['class']['group'])->findOneByTitle($groupTitle))) {
456 //XXX: see vendor/symfony/security-core/Role/Role.php
457 $user->addGroup($group);
461 //XXX: consider missing group as fatal
462 throw new \
Exception(sprintf('Group from rapsys_user.default.group[%d] not found by title: %s', $i, $groupTitle));
466 $user->setCreated(new \
DateTime('now'));
467 $user->setUpdated(new \
DateTime('now'));
470 $manager->persist($user);
472 //Try saving in database
477 //Try sending message
478 //XXX: mail delivery may silently fail
481 $mailer->send($message);
483 //Redirect on the same route with sent=1 to cleanup form
484 #return $this->redirectToRoute('rapsys_user_register', array('sent' => 1));
485 return $this->redirectToRoute($request->get('_route'), ['sent' => 1]+
$request->get('_route_params'));
486 //Catch obvious transport exception
487 } catch(TransportExceptionInterface
$e) {
488 //Add error message mail unreachable
489 $form->get('mail')->addError(new FormError($this->translator
->trans('Account created but unable to contact: %mail%', array('%mail%' => $data['mail']))));
491 //Catch double subscription
492 } catch (\Doctrine\DBAL\Exception\UniqueConstraintViolationException
$e) {
493 //Add error message mail already exists
494 $form->get('mail')->addError(new FormError($this->translator
->trans('Account already exists: %mail%', ['%mail%' => $data['mail']])));
500 return $this->render(
502 $this->config
['register']['view']['name'],
504 ['form' => $form->createView(), 'sent' => $request->query
->get('sent', 0)]+
$this->config
['register']['view']['context']
511 public function getAlias() {
512 return 'rapsys_user';