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 //Set mail from login form
101 $recover->get('mail')->setData($login->get('mail')->getData());
104 $recover->addError(new FormError(
105 $this->translator
->trans('Use this form to recover your account')
108 //Add recover form to context
109 $context['recover'] = $recover->createView();
113 return $this->render(
115 $this->config
['login']['view']['name'],
117 ['login' => $login->createView()]+
$context+
$this->config
['login']['view']['context']
121 public function recover(Request
$request, Slugger
$slugger, MailerInterface
$mailer) {
122 //Create the RecoverType form and give the proper parameters
123 $form = $this->createForm($this->config
['recover']['view']['form'], null, array(
124 //Set action to recover route name and context
125 'action' => $this->generateUrl($this->config
['route']['recover']['name'], $this->config
['route']['recover']['context']),
129 if ($request->isMethod('POST')) {
130 //Refill the fields in case the form is not valid.
131 $form->handleRequest($request);
133 if ($form->isValid()) {
135 $doctrine = $this->getDoctrine();
138 $data = $form->getData();
141 if ($user = $doctrine->getRepository($this->config
['class']['user'])->findOneByMail($data['mail'])) {
143 $mail =& $this->config
['recover']['mail'];
145 //Generate each route route
146 foreach($this->config
['recover']['route'] as $route => $tag) {
147 //Only process defined routes
148 if (empty($mail['context'][$tag]) && !empty($this->config
['route'][$route])) {
149 //Process for recover mail url
150 if ($route == 'recover_mail') {
151 //Prepend recover context with tag
152 $this->config
['route'][$route]['context'] = [
153 'recipient' => $slugger->short($user->getMail()),
154 'hash' => $slugger->hash($user->getPassword())
155 ]+
$this->config
['route'][$route]['context'];
157 //Set the url in context
158 $mail['context'][$tag] = $this->get('router')->generate(
159 $this->config
['route'][$route]['name'],
160 $this->config
['route'][$route]['context'],
161 UrlGeneratorInterface
::ABSOLUTE_URL
168 $mail['context']['recipient_mail'] = $data['mail'];
171 $mail['context']['recipient_name'] = trim($user->getForename().' '.$user->getSurname().($user->getPseudonym()?' ('.$user->getPseudonym().')':''));
173 //Init subject context
174 $subjectContext = [];
176 //Process each context pair
177 foreach($mail['context']+
$this->config
['recover']['view']['context'] as $k => $v) {
178 //Reinsert each context pair with the key surrounded by %
179 $subjectContext['%'.$k.'%'] = $v;
183 $mail['subject'] = ucfirst($this->translator
->trans($mail['subject'], $subjectContext));
186 $message = (new TemplatedEmail())
188 ->from(new Address($this->config
['contact']['mail'], $this->config
['contact']['name']))
190 //XXX: remove the debug set in vendor/symfony/mime/Address.php +46
191 ->to(new Address($mail['context']['recipient_mail'], $mail['context']['recipient_name']))
193 ->subject($mail['subject'])
195 //Set path to twig templates
196 ->htmlTemplate($mail['html'])
197 ->textTemplate($mail['text'])
200 ->context(['subject' => $mail['subject']]+
$mail['context']+
$this->config
['recover']['view']['context']);
202 //Try sending message
203 //XXX: mail delivery may silently fail
206 $mailer->send($message);
208 //Redirect on the same route with sent=1 to cleanup form
209 #return $this->redirectToRoute('rapsys_user_register', array('sent' => 1));
210 return $this->redirectToRoute($request->get('_route'), ['sent' => 1]+
$request->get('_route_params'));
211 //Catch obvious transport exception
212 } catch(TransportExceptionInterface
$e) {
213 //Add error message mail unreachable
214 $form->get('mail')->addError(new FormError($this->translator
->trans('Account found but unable to contact: %mail%', array('%mail%' => $data['mail']))));
218 //Add error message to mail field
219 $form->get('mail')->addError(new FormError($this->translator
->trans('Unable to find account: %mail%', ['%mail%' => $data['mail']])));
225 return $this->render(
227 $this->config
['recover']['view']['name'],
229 ['form' => $form->createView(), 'sent' => $request->query
->get('sent', 0)]+
$this->config
['recover']['view']['context']
233 public function recoverMail(Request
$request, UserPasswordEncoderInterface
$encoder, Slugger
$slugger, MailerInterface
$mailer, $recipient, $hash) {
234 //Create the RecoverType form and give the proper parameters
235 $form = $this->createForm($this->config
['recover_mail']['view']['form'], null, array(
236 //Set action to recover route name and context
237 'action' => $this->generateUrl($this->config
['route']['recover_mail']['name'], ['recipient' => $recipient, 'hash' => $hash]+
$this->config
['route']['recover_mail']['context']),
242 $doctrine = $this->getDoctrine();
248 if (($user = $doctrine->getRepository($this->config
['class']['user'])->findOneByMail($slugger->unshort($recipient))) && $found = ($hash == $slugger->hash($user->getPassword()))) {
249 if ($request->isMethod('POST')) {
250 //Refill the fields in case the form is not valid.
251 $form->handleRequest($request);
253 if ($form->isValid()) {
255 $data = $form->getData();
257 //set encoded password
258 $encoded = $encoder->encodePassword($user, $data['password']);
261 $user->setPassword($encoded);
264 $manager = $doctrine->getManager();
267 $manager->persist($user);
273 $mail =& $this->config
['recover_mail']['mail'];
276 $hash = $slugger->hash($encoded);
278 //Generate each route route
279 foreach($this->config
['recover_mail']['route'] as $route => $tag) {
280 //Only process defined routes
281 if (empty($mail['context'][$tag]) && !empty($this->config
['route'][$route])) {
282 //Process for recover mail url
283 if ($route == 'recover_mail') {
284 //Prepend recover context with tag
285 $this->config
['route'][$route]['context'] = [
286 'recipient' => $recipient,
288 ]+
$this->config
['route'][$route]['context'];
290 //Set the url in context
291 $mail['context'][$tag] = $this->get('router')->generate(
292 $this->config
['route'][$route]['name'],
293 $this->config
['route'][$route]['context'],
294 UrlGeneratorInterface
::ABSOLUTE_URL
300 $mail['context']['recipient_mail'] = $user->getMail();
303 $mail['context']['recipient_name'] = trim($user->getForename().' '.$user->getSurname().($user->getPseudonym()?' ('.$user->getPseudonym().')':''));
305 //Init subject context
306 $subjectContext = [];
308 //Process each context pair
309 foreach($mail['context']+
$this->config
['recover_mail']['view']['context'] as $k => $v) {
310 //Reinsert each context pair with the key surrounded by %
311 $subjectContext['%'.$k.'%'] = $v;
315 $mail['subject'] = ucfirst($this->translator
->trans($mail['subject'], $subjectContext));
318 $message = (new TemplatedEmail())
320 ->from(new Address($this->config
['contact']['mail'], $this->config
['contact']['name']))
322 //XXX: remove the debug set in vendor/symfony/mime/Address.php +46
323 ->to(new Address($mail['context']['recipient_mail'], $mail['context']['recipient_name']))
325 ->subject($mail['subject'])
327 //Set path to twig templates
328 ->htmlTemplate($mail['html'])
329 ->textTemplate($mail['text'])
332 ->context(['subject' => $mail['subject']]+
$mail['context']+
$this->config
['recover_mail']['view']['context']);
334 //Try sending message
335 //XXX: mail delivery may silently fail
338 $mailer->send($message);
340 //Redirect on the same route with sent=1 to cleanup form
341 return $this->redirectToRoute($request->get('_route'), ['recipient' => $recipient, 'hash' => $hash, 'sent' => 1]+
$request->get('_route_params'));
342 //Catch obvious transport exception
343 } catch(TransportExceptionInterface
$e) {
344 //Add error message mail unreachable
345 $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']))));
351 //Add error message to mail field
352 $form->addError(new FormError($this->translator
->trans('Unable to find account: %mail%', ['%mail%' => $slugger->unshort($recipient)])));
356 return $this->render(
358 $this->config
['recover_mail']['view']['name'],
360 ['form' => $form->createView(), 'sent' => $request->query
->get('sent', 0), 'found' => $found]+
$this->config
['recover_mail']['view']['context']
364 public function register(Request
$request, UserPasswordEncoderInterface
$encoder, MailerInterface
$mailer) {
365 //Create the RegisterType form and give the proper parameters
366 $form = $this->createForm($this->config
['register']['view']['form'], null, array(
367 'class_title' => $this->config
['class']['title'],
368 //Set action to register route name and context
369 'action' => $this->generateUrl($this->config
['route']['register']['name'], $this->config
['route']['register']['context']),
373 if ($request->isMethod('POST')) {
374 //Refill the fields in case the form is not valid.
375 $form->handleRequest($request);
377 if ($form->isValid()) {
379 $data = $form->getData();
382 $mail =& $this->config
['register']['mail'];
384 //Generate each route route
385 foreach($this->config
['register']['route'] as $route => $tag) {
386 if (empty($mail['context'][$tag]) && !empty($this->config
['route'][$route])) {
387 $mail['context'][$tag] = $this->get('router')->generate(
388 $this->config
['route'][$route]['name'],
389 $this->config
['route'][$route]['context'],
390 UrlGeneratorInterface
::ABSOLUTE_URL
396 $mail['context']['recipient_mail'] = $data['mail'];
399 $mail['context']['recipient_name'] = trim($data['forename'].' '.$data['surname'].($data['pseudonym']?' ('.$data['pseudonym'].')':''));
401 //Init subject context
402 $subjectContext = [];
404 //Process each context pair
405 foreach($mail['context']+
$this->config
['register']['view']['context'] as $k => $v) {
406 //Reinsert each context pair with the key surrounded by %
407 $subjectContext['%'.$k.'%'] = $v;
411 $mail['subject'] = ucfirst($this->translator
->trans($mail['subject'], $subjectContext));
414 $message = (new TemplatedEmail())
416 ->from(new Address($this->config
['contact']['mail'], $this->config
['contact']['name']))
418 //XXX: remove the debug set in vendor/symfony/mime/Address.php +46
419 ->to(new Address($mail['context']['recipient_mail'], $mail['context']['recipient_name']))
421 ->subject($mail['subject'])
423 //Set path to twig templates
424 ->htmlTemplate($mail['html'])
425 ->textTemplate($mail['text'])
428 ->context(['subject' => $mail['subject']]+
$mail['context']+
$this->config
['register']['view']['context']);
431 $doctrine = $this->getDoctrine();
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 //XXX: For now there is no point in setting a role at subscription
452 //TODO: see if we can't modify group constructor to set role directly from args
453 //XXX: see vendor/symfony/symfony/src/Symfony/Component/Security/Core/Role/Role.php
454 #$user->addGroup($doctrine->getRepository($this->config['class']['group'])->findOneByRole('ROLE_USER'));
456 $user->setCreated(new \
DateTime('now'));
457 $user->setUpdated(new \
DateTime('now'));
460 $manager->persist($user);
462 //Try saving in database
467 //Try sending message
468 //XXX: mail delivery may silently fail
471 $mailer->send($message);
473 //Redirect on the same route with sent=1 to cleanup form
474 #return $this->redirectToRoute('rapsys_user_register', array('sent' => 1));
475 return $this->redirectToRoute($request->get('_route'), ['sent' => 1]+
$request->get('_route_params'));
476 //Catch obvious transport exception
477 } catch(TransportExceptionInterface
$e) {
478 //Add error message mail unreachable
479 $form->get('mail')->addError(new FormError($this->translator
->trans('Account created but unable to contact: %mail%', array('%mail%' => $data['mail']))));
481 //Catch double subscription
482 } catch (\Doctrine\DBAL\Exception\UniqueConstraintViolationException
$e) {
483 //Add error message mail already exists
484 $form->get('mail')->addError(new FormError($this->translator
->trans('Account already exists: %mail%', ['%mail%' => $data['mail']])));
490 return $this->render(
492 $this->config
['register']['view']['name'],
494 ['form' => $form->createView(), 'sent' => $request->query
->get('sent', 0)]+
$this->config
['register']['view']['context']
501 public function getAlias() {
502 return 'rapsys_user';