]> Raphaƫl G. Git Repositories - userbundle/blob - Controller/DefaultController.php
Move recover global form error message to mail entity
[userbundle] / Controller / DefaultController.php
1 <?php
2
3 namespace Rapsys\UserBundle\Controller;
4
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;
19
20 class DefaultController extends AbstractController {
21 //Config array
22 protected $config;
23
24 //Translator instance
25 protected $translator;
26
27 public function __construct(ContainerInterface $container, TranslatorInterface $translator, RouterInterface $router) {
28 //Retrieve config
29 $this->config = $container->getParameter($this->getAlias());
30
31 //Set the translator
32 $this->translator = $translator;
33
34 //Get current action
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'));
37
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') {
50 continue;
51 }
52 //Check that key is empty
53 if (!isset($current[$view]['context'][$key])) {
54 //Generate the route
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
60 );
61 }
62 }
63 }
64 }
65 }
66 }
67 }
68
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']),
74 'method' => 'POST'
75 ]);
76
77 //Init context
78 $context = [];
79
80 //Last username entered by the user
81 if ($lastUsername = $authenticationUtils->getLastUsername()) {
82 $login->get('mail')->setData($lastUsername);
83 }
84
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());
89
90 //Add error message to mail field
91 $login->get('mail')->addError(new FormError($error));
92
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']),
97 'method' => 'POST'
98 ]);
99
100 //Get recover mail entity
101 $recover->get('mail')
102 //Set mail from login form
103 ->setData($login->get('mail')->getData())
104 //Add recover error
105 ->addError(new FormError($this->translator->trans('Use this form to recover your account')));
106
107 //Add recover form to context
108 $context['recover'] = $recover->createView();
109 }
110
111 //Render view
112 return $this->render(
113 //Template
114 $this->config['login']['view']['name'],
115 //Context
116 ['login' => $login->createView()]+$context+$this->config['login']['view']['context']
117 );
118 }
119
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']),
125 'method' => 'POST'
126 ));
127
128 if ($request->isMethod('POST')) {
129 //Refill the fields in case the form is not valid.
130 $form->handleRequest($request);
131
132 if ($form->isValid()) {
133 //Get doctrine
134 $doctrine = $this->getDoctrine();
135
136 //Set data
137 $data = $form->getData();
138
139 //Try to find user
140 if ($user = $doctrine->getRepository($this->config['class']['user'])->findOneByMail($data['mail'])) {
141 //Set mail shortcut
142 $mail =& $this->config['recover']['mail'];
143
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'];
155 }
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
161 );
162
163 }
164 }
165
166 //Set recipient_name
167 $mail['context']['recipient_mail'] = $data['mail'];
168
169 //Set recipient_name
170 $mail['context']['recipient_name'] = trim($user->getForename().' '.$user->getSurname().($user->getPseudonym()?' ('.$user->getPseudonym().')':''));
171
172 //Init subject context
173 $subjectContext = [];
174
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;
179 }
180
181 //Translate subject
182 $mail['subject'] = ucfirst($this->translator->trans($mail['subject'], $subjectContext));
183
184 //Create message
185 $message = (new TemplatedEmail())
186 //Set sender
187 ->from(new Address($this->config['contact']['mail'], $this->config['contact']['name']))
188 //Set recipient
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']))
191 //Set subject
192 ->subject($mail['subject'])
193
194 //Set path to twig templates
195 ->htmlTemplate($mail['html'])
196 ->textTemplate($mail['text'])
197
198 //Set context
199 ->context(['subject' => $mail['subject']]+$mail['context']+$this->config['recover']['view']['context']);
200
201 //Try sending message
202 //XXX: mail delivery may silently fail
203 try {
204 //Send message
205 $mailer->send($message);
206
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']))));
214 }
215 //Accout not found
216 } else {
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']])));
219 }
220 }
221 }
222
223 //Render view
224 return $this->render(
225 //Template
226 $this->config['recover']['view']['name'],
227 //Context
228 ['form' => $form->createView(), 'sent' => $request->query->get('sent', 0)]+$this->config['recover']['view']['context']
229 );
230 }
231
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']),
237 'method' => 'POST'
238 ));
239
240 //Get doctrine
241 $doctrine = $this->getDoctrine();
242
243 //Init found
244 $found = false;
245
246 //Retrieve user
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);
251
252 if ($form->isValid()) {
253 //Set data
254 $data = $form->getData();
255
256 //set encoded password
257 $encoded = $encoder->encodePassword($user, $data['password']);
258
259 //Set user password
260 $user->setPassword($encoded);
261
262 //Get manager
263 $manager = $doctrine->getManager();
264
265 //Persist user
266 $manager->persist($user);
267
268 //Send to database
269 $manager->flush();
270
271 //Set mail shortcut
272 $mail =& $this->config['recover_mail']['mail'];
273
274 //Regen hash
275 $hash = $slugger->hash($encoded);
276
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,
286 'hash' => $hash
287 ]+$this->config['route'][$route]['context'];
288 }
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
294 );
295 }
296 }
297
298 //Set recipient_name
299 $mail['context']['recipient_mail'] = $user->getMail();
300
301 //Set recipient_name
302 $mail['context']['recipient_name'] = trim($user->getForename().' '.$user->getSurname().($user->getPseudonym()?' ('.$user->getPseudonym().')':''));
303
304 //Init subject context
305 $subjectContext = [];
306
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;
311 }
312
313 //Translate subject
314 $mail['subject'] = ucfirst($this->translator->trans($mail['subject'], $subjectContext));
315
316 //Create message
317 $message = (new TemplatedEmail())
318 //Set sender
319 ->from(new Address($this->config['contact']['mail'], $this->config['contact']['name']))
320 //Set recipient
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']))
323 //Set subject
324 ->subject($mail['subject'])
325
326 //Set path to twig templates
327 ->htmlTemplate($mail['html'])
328 ->textTemplate($mail['text'])
329
330 //Set context
331 ->context(['subject' => $mail['subject']]+$mail['context']+$this->config['recover_mail']['view']['context']);
332
333 //Try sending message
334 //XXX: mail delivery may silently fail
335 try {
336 //Send message
337 $mailer->send($message);
338
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']))));
345 }
346 }
347 }
348 //Accout not found
349 } else {
350 //Add error message to mail field
351 $form->addError(new FormError($this->translator->trans('Unable to find account: %mail%', ['%mail%' => $slugger->unshort($recipient)])));
352 }
353
354 //Render view
355 return $this->render(
356 //Template
357 $this->config['recover_mail']['view']['name'],
358 //Context
359 ['form' => $form->createView(), 'sent' => $request->query->get('sent', 0), 'found' => $found]+$this->config['recover_mail']['view']['context']
360 );
361 }
362
363 public function register(Request $request, UserPasswordEncoderInterface $encoder, MailerInterface $mailer) {
364 //Get doctrine
365 $doctrine = $this->getDoctrine();
366
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']),
373 'method' => 'POST'
374 ));
375
376 if ($request->isMethod('POST')) {
377 //Refill the fields in case the form is not valid.
378 $form->handleRequest($request);
379
380 if ($form->isValid()) {
381 //Set data
382 $data = $form->getData();
383
384 //Set mail shortcut
385 $mail =& $this->config['register']['mail'];
386
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
394 );
395 }
396 }
397
398 //Set recipient_name
399 $mail['context']['recipient_mail'] = $data['mail'];
400
401 //Set recipient_name
402 $mail['context']['recipient_name'] = trim($data['forename'].' '.$data['surname'].($data['pseudonym']?' ('.$data['pseudonym'].')':''));
403
404 //Init subject context
405 $subjectContext = [];
406
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;
411 }
412
413 //Translate subject
414 $mail['subject'] = ucfirst($this->translator->trans($mail['subject'], $subjectContext));
415
416 //Create message
417 $message = (new TemplatedEmail())
418 //Set sender
419 ->from(new Address($this->config['contact']['mail'], $this->config['contact']['name']))
420 //Set recipient
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']))
423 //Set subject
424 ->subject($mail['subject'])
425
426 //Set path to twig templates
427 ->htmlTemplate($mail['html'])
428 ->textTemplate($mail['text'])
429
430 //Set context
431 ->context(['subject' => $mail['subject']]+$mail['context']+$this->config['register']['view']['context']);
432
433 //Get manager
434 $manager = $doctrine->getManager();
435
436 //Init reflection
437 $reflection = new \ReflectionClass($this->config['class']['user']);
438
439 //Create new user
440 $user = $reflection->newInstance();
441
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']);
450
451 //Iterate on default group
452 foreach($this->config['default']['group'] as $i => $groupTitle) {
453 //Fetch group
454 if (($group = $doctrine->getRepository($this->config['class']['group'])->findOneByTitle($groupTitle))) {
455 //Set default group
456 //XXX: see vendor/symfony/security-core/Role/Role.php
457 $user->addGroup($group);
458 //Group not found
459 } else {
460 //Throw exception
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));
463 }
464 }
465
466 $user->setCreated(new \DateTime('now'));
467 $user->setUpdated(new \DateTime('now'));
468
469 //Persist user
470 $manager->persist($user);
471
472 //Try saving in database
473 try {
474 //Send to database
475 $manager->flush();
476
477 //Try sending message
478 //XXX: mail delivery may silently fail
479 try {
480 //Send message
481 $mailer->send($message);
482
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']))));
490 }
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']])));
495 }
496 }
497 }
498
499 //Render view
500 return $this->render(
501 //Template
502 $this->config['register']['view']['name'],
503 //Context
504 ['form' => $form->createView(), 'sent' => $request->query->get('sent', 0)]+$this->config['register']['view']['context']
505 );
506 }
507
508 /**
509 * {@inheritdoc}
510 */
511 public function getAlias() {
512 return 'rapsys_user';
513 }
514 }