]> Raphaël G. Git Repositories - airbundle/blob - Controller/DefaultController.php
Update logo
[airbundle] / Controller / DefaultController.php
1 <?php declare(strict_types=1);
2
3 /*
4 * This file is part of the Rapsys AirBundle package.
5 *
6 * (c) Raphaël Gertz <symfony@rapsys.eu>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12 namespace Rapsys\AirBundle\Controller;
13
14 use Symfony\Bridge\Twig\Mime\TemplatedEmail;
15 use Symfony\Component\Form\FormError;
16 use Symfony\Component\HttpFoundation\Request;
17 use Symfony\Component\HttpFoundation\Response;
18 use Symfony\Component\Mailer\Exception\TransportExceptionInterface;
19 use Symfony\Component\Mailer\MailerInterface;
20 use Symfony\Component\Mime\Address;
21 use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken;
22
23 use Rapsys\AirBundle\Entity\Civility;
24 use Rapsys\AirBundle\Entity\Location;
25 use Rapsys\AirBundle\Entity\Session;
26 use Rapsys\AirBundle\Entity\Snippet;
27 use Rapsys\AirBundle\Entity\User;
28 use Rapsys\AirBundle\Pdf\DisputePdf;
29
30 /**
31 * {@inheritdoc}
32 */
33 class DefaultController extends AbstractController {
34 /**
35 * The about page
36 *
37 * @desc Display the about informations
38 *
39 * @param Request $request The request instance
40 * @return Response The rendered view
41 */
42 public function about(Request $request): Response {
43 //Set page
44 $this->context['title'] = $this->translator->trans('About');
45
46 //Set description
47 $this->context['description'] = $this->translator->trans('Libre Air about');
48
49 //Set keywords
50 $this->context['keywords'] = [
51 $this->translator->trans('about'),
52 $this->translator->trans('Libre Air')
53 ];
54
55 //Render template
56 $response = $this->render('@RapsysAir/default/about.html.twig', $this->context);
57 $response->setEtag(md5($response->getContent()));
58 $response->setPublic();
59 $response->isNotModified($request);
60
61 //Return response
62 return $response;
63 }
64
65 /**
66 * The contact page
67 *
68 * @desc Send a contact mail to configured contact
69 *
70 * @param Request $request The request instance
71 * @param MailerInterface $mailer The mailer instance
72 *
73 * @return Response The rendered view or redirection
74 */
75 public function contact(Request $request, MailerInterface $mailer): Response {
76 //Set page
77 $this->context['title'] = $this->translator->trans('Contact');
78
79 //Set description
80 $this->context['description'] = $this->translator->trans('Contact Libre Air');
81
82 //Set keywords
83 $this->context['keywords'] = [
84 $this->translator->trans('contact'),
85 $this->translator->trans('Libre Air'),
86 $this->translator->trans('outdoor'),
87 $this->translator->trans('Argentine Tango'),
88 $this->translator->trans('calendar')
89 ];
90
91 //Create the form according to the FormType created previously.
92 //And give the proper parameters
93 $form = $this->createForm('Rapsys\AirBundle\Form\ContactType', null, [
94 'action' => $this->generateUrl('rapsys_air_contact'),
95 'method' => 'POST'
96 ]);
97
98 if ($request->isMethod('POST')) {
99 // Refill the fields in case the form is not valid.
100 $form->handleRequest($request);
101
102 if ($form->isValid()) {
103 //Get data
104 $data = $form->getData();
105
106 //Create message
107 $message = (new TemplatedEmail())
108 //Set sender
109 ->from(new Address($data['mail'], $data['name']))
110 //Set recipient
111 ->to(new Address($this->context['contact']['mail'], $this->context['contact']['title']))
112 //Set subject
113 ->subject($data['subject'])
114
115 //Set path to twig templates
116 ->htmlTemplate('@RapsysAir/mail/contact.html.twig')
117 ->textTemplate('@RapsysAir/mail/contact.text.twig')
118
119 //Set context
120 ->context(
121 [
122 'subject' => $data['subject'],
123 'message' => strip_tags($data['message']),
124 ]+$this->context
125 );
126
127 //Try sending message
128 //XXX: mail delivery may silently fail
129 try {
130 //Send message
131 $mailer->send($message);
132
133 //Redirect on the same route with sent=1 to cleanup form
134 return $this->redirectToRoute($request->get('_route'), ['sent' => 1]+$request->get('_route_params'));
135 //Catch obvious transport exception
136 } catch(TransportExceptionInterface $e) {
137 if ($message = $e->getMessage()) {
138 //Add error message mail unreachable
139 $form->get('mail')->addError(new FormError($this->translator->trans('Unable to contact: %mail%: %message%', ['%mail%' => $this->context['contact']['mail'], '%message%' => $this->translator->trans($message)])));
140 } else {
141 //Add error message mail unreachable
142 $form->get('mail')->addError(new FormError($this->translator->trans('Unable to contact: %mail%', ['%mail%' => $this->context['contact']['mail']])));
143 }
144 }
145 }
146 }
147
148 //Render template
149 return $this->render('@RapsysAir/form/contact.html.twig', ['form' => $form->createView(), 'sent' => $request->query->get('sent', 0)]+$this->context);
150 }
151
152 /**
153 * The dispute page
154 *
155 * @desc Generate a dispute document
156 *
157 * @param Request $request The request instance
158 * @param MailerInterface $mailer The mailer instance
159 *
160 * @return Response The rendered view or redirection
161 */
162 public function dispute(Request $request, MailerInterface $mailer): Response {
163 //Prevent non-guest to access here
164 $this->denyAccessUnlessGranted('ROLE_USER', null, $this->translator->trans('Unable to access this page without role %role%!', ['%role%' => $this->translator->trans('User')]));
165
166 //Set page
167 $this->context['title'] = $this->translator->trans('Dispute');
168
169 //Set description
170 $this->context['description'] = $this->translator->trans('Libre Air dispute');
171
172 //Set keywords
173 $this->context['keywords'] = [
174 $this->translator->trans('dispute'),
175 $this->translator->trans('Libre Air'),
176 $this->translator->trans('outdoor'),
177 $this->translator->trans('Argentine Tango'),
178 $this->translator->trans('calendar')
179 ];
180
181 //Create the form according to the FormType created previously.
182 //And give the proper parameters
183 $form = $this->createForm('Rapsys\AirBundle\Form\DisputeType', ['court' => 'Paris', 'abstract' => 'Pour constater cette prétendue infraction, les agents verbalisateurs ont pénétré dans un jardin privatif, sans visibilité depuis la voie publique, situé derrière un batiment privé, pour ce faire ils ont franchi au moins un grillage de chantier ou des potteaux métalliques séparant le terrain privé de la voie publique de l\'autre côté du batiment.'], [
184 'action' => $this->generateUrl('rapsys_air_dispute'),
185 'method' => 'POST'
186 ]);
187
188 if ($request->isMethod('POST')) {
189 // Refill the fields in case the form is not valid.
190 $form->handleRequest($request);
191
192 if ($form->isValid()) {
193 //Get data
194 $data = $form->getData();
195
196 //Gathering offense
197 if (!empty($data['offense']) && $data['offense'] == 'gathering') {
198 //Add gathering
199 $output = DisputePdf::genGathering($data['court'], $data['notice'], $data['agent'], $data['service'], $data['abstract'], $this->translator->trans($this->getUser()->getCivility()->getTitle()), $this->getUser()->getForename(), $this->getUser()->getSurname());
200 //Traffic offense
201 } elseif (!empty($data['offense'] && $data['offense'] == 'traffic')) {
202 //Add traffic
203 $output = DisputePdf::genTraffic($data['court'], $data['notice'], $data['agent'], $data['service'], $data['abstract'], $this->translator->trans($this->getUser()->getCivility()->getTitle()), $this->getUser()->getForename(), $this->getUser()->getSurname());
204 //Unsupported offense
205 } else {
206 header('Content-Type: text/plain');
207 die('TODO');
208 exit;
209 }
210
211 //Send common headers
212 header('Content-Type: application/pdf');
213
214 //Send remaining headers
215 header('Cache-Control: private, max-age=0, must-revalidate');
216 header('Pragma: public');
217
218 //Send content-length
219 header('Content-Length: '.strlen($output));
220
221 //Display the pdf
222 echo $output;
223
224 //Die for now
225 exit;
226
227 # //Create message
228 # $message = (new TemplatedEmail())
229 # //Set sender
230 # ->from(new Address($data['mail'], $data['name']))
231 # //Set recipient
232 # //XXX: remove the debug set in vendor/symfony/mime/Address.php +46
233 # ->to(new Address($this->config['contact']['mail'], $this->config['contact']['title']))
234 # //Set subject
235 # ->subject($data['subject'])
236 #
237 # //Set path to twig templates
238 # ->htmlTemplate('@RapsysAir/mail/contact.html.twig')
239 # ->textTemplate('@RapsysAir/mail/contact.text.twig')
240 #
241 # //Set context
242 # ->context(
243 # [
244 # 'subject' => $data['subject'],
245 # 'message' => strip_tags($data['message']),
246 # ]+$this->context
247 # );
248 #
249 # //Try sending message
250 # //XXX: mail delivery may silently fail
251 # try {
252 # //Send message
253 # $mailer->send($message);
254 #
255 # //Redirect on the same route with sent=1 to cleanup form
256 # return $this->redirectToRoute($request->get('_route'), ['sent' => 1]+$request->get('_route_params'));
257 # //Catch obvious transport exception
258 # } catch(TransportExceptionInterface $e) {
259 # if ($message = $e->getMessage()) {
260 # //Add error message mail unreachable
261 # $form->get('mail')->addError(new FormError($this->translator->trans('Unable to contact: %mail%: %message%', ['%mail%' => $this->config['contact']['mail'], '%message%' => $this->translator->trans($message)])));
262 # } else {
263 # //Add error message mail unreachable
264 # $form->get('mail')->addError(new FormError($this->translator->trans('Unable to contact: %mail%', ['%mail%' => $this->config['contact']['mail']])));
265 # }
266 # }
267 }
268 }
269
270 //Render template
271 return $this->render('@RapsysAir/default/dispute.html.twig', ['form' => $form->createView(), 'sent' => $request->query->get('sent', 0)]+$this->context);
272 }
273
274 /**
275 * The index page
276 *
277 * @desc Display all granted sessions with an application or login form
278 *
279 * @param Request $request The request instance
280 * @return Response The rendered view
281 */
282 public function index(Request $request): Response {
283 //Fetch doctrine
284 $doctrine = $this->getDoctrine();
285
286 //Set page
287 $this->context['title'] = $this->translator->trans('Argentine Tango in Paris');
288
289 //Set description
290 $this->context['description'] = $this->translator->trans('Outdoor Argentine Tango session calendar in Paris');
291
292 //Set keywords
293 $this->context['keywords'] = [
294 $this->translator->trans('Argentine Tango'),
295 $this->translator->trans('Paris'),
296 $this->translator->trans('outdoor'),
297 $this->translator->trans('calendar'),
298 $this->translator->trans('Libre Air')
299 ];
300
301 //Set facebook type
302 //XXX: only valid for home page
303 $this->context['facebook']['metas']['og:type'] = 'website';
304
305 //Compute period
306 $period = new \DatePeriod(
307 //Start from first monday of week
308 new \DateTime('Monday this week'),
309 //Iterate on each day
310 new \DateInterval('P1D'),
311 //End with next sunday and 4 weeks
312 new \DateTime(
313 $this->isGranted('IS_AUTHENTICATED_REMEMBERED')?'Monday this week + 3 week':'Monday this week + 2 week'
314 )
315 );
316
317 //Fetch calendar
318 $calendar = $doctrine->getRepository(Session::class)->fetchCalendarByDatePeriod($this->translator, $period, null, $request->get('session'), !$this->isGranted('IS_AUTHENTICATED_REMEMBERED'), $request->getLocale());
319
320 //Fetch locations
321 //XXX: we want to display all active locations anyway
322 $locations = $doctrine->getRepository(Location::class)->findTranslatedSortedByPeriod($this->translator, $period);
323
324 //Render the view
325 return $this->render('@RapsysAir/default/index.html.twig', ['calendar' => $calendar, 'locations' => $locations]+$this->context);
326
327 //Set Cache-Control must-revalidate directive
328 //TODO: add a javascript forced refresh after 1h ? or header refresh ?
329 #$response->setPublic(true);
330 #$response->setMaxAge(300);
331 #$response->mustRevalidate();
332 ##$response->setCache(['public' => true, 'max_age' => 300]);
333
334 //Return the response
335 #return $response;
336 }
337
338 /**
339 * The organizer regulation page
340 *
341 * @desc Display the organizer regulation policy
342 *
343 * @param Request $request The request instance
344 * @return Response The rendered view
345 */
346 public function organizerRegulation(Request $request): Response {
347 //Set page
348 $this->context['title'] = $this->translator->trans('Organizer regulation');
349
350 //Set description
351 $this->context['description'] = $this->translator->trans('Libre Air organizer regulation');
352
353 //Set keywords
354 $this->context['keywords'] = [
355 $this->translator->trans('organizer regulation'),
356 $this->translator->trans('Libre Air')
357 ];
358
359 //Render template
360 $response = $this->render('@RapsysAir/default/organizer_regulation.html.twig', $this->context);
361
362 //Set as cachable
363 $response->setEtag(md5($response->getContent()));
364 $response->setPublic();
365 $response->isNotModified($request);
366
367 //Return response
368 return $response;
369 }
370
371 /**
372 * The terms of service page
373 *
374 * @desc Display the terms of service policy
375 *
376 * @param Request $request The request instance
377 * @return Response The rendered view
378 */
379 public function termsOfService(Request $request): Response {
380 //Set page
381 $this->context['title'] = $this->translator->trans('Terms of service');
382
383 //Set description
384 $this->context['description'] = $this->translator->trans('Libre Air terms of service');
385
386 //Set keywords
387 $this->context['keywords'] = [
388 $this->translator->trans('terms of service'),
389 $this->translator->trans('Libre Air')
390 ];
391
392 //Render template
393 $response = $this->render('@RapsysAir/default/terms_of_service.html.twig', $this->context);
394
395 //Set as cachable
396 $response->setEtag(md5($response->getContent()));
397 $response->setPublic();
398 $response->isNotModified($request);
399
400 //Return response
401 return $response;
402 }
403
404 /**
405 * The frequently asked questions page
406 *
407 * @desc Display the frequently asked questions
408 *
409 * @param Request $request The request instance
410 * @return Response The rendered view
411 */
412 public function frequentlyAskedQuestions(Request $request): Response {
413 //Set page
414 $this->context['title'] = $this->translator->trans('Frequently asked questions');
415
416 //Set description
417 $this->context['description'] = $this->translator->trans('Libre Air frequently asked questions');
418
419 //Set keywords
420 $this->context['keywords'] = [
421 $this->translator->trans('frequently asked questions'),
422 $this->translator->trans('faq'),
423 $this->translator->trans('Libre Air')
424 ];
425
426 //Render template
427 $response = $this->render('@RapsysAir/default/frequently_asked_questions.html.twig', $this->context);
428
429 //Set as cachable
430 $response->setEtag(md5($response->getContent()));
431 $response->setPublic();
432 $response->isNotModified($request);
433
434 //Return response
435 return $response;
436 }
437
438 /**
439 * List all users
440 *
441 * @desc Display all user with a group listed as users
442 *
443 * @param Request $request The request instance
444 *
445 * @return Response The rendered view
446 */
447 public function userIndex(Request $request): Response {
448 //Fetch doctrine
449 $doctrine = $this->getDoctrine();
450
451 //With admin role
452 if ($this->isGranted('ROLE_ADMIN')) {
453 //Set section
454 $section = $this->translator->trans('Libre Air users');
455
456 //Set description
457 $this->context['description'] = $this->translator->trans('Libre Air user list');
458 //Without admin role
459 } else {
460 //Set section
461 $section = $this->translator->trans('Libre Air organizers');
462
463 //Set description
464 $this->context['description'] = $this->translator->trans('Libre Air organizers list');
465 }
466
467 //Set keywords
468 $this->context['keywords'] = [
469 $this->translator->trans('users'),
470 $this->translator->trans('user list'),
471 $this->translator->trans('listing'),
472 $this->translator->trans('Libre Air')
473 ];
474
475 //Set title
476 $title = $this->translator->trans($this->config['site']['title']).' - '.$section;
477
478 //Fetch users
479 $users = $doctrine->getRepository(User::class)->findUserGroupedByTranslatedGroup($this->translator);
480
481 //Compute period
482 $period = new \DatePeriod(
483 //Start from first monday of week
484 new \DateTime('Monday this week'),
485 //Iterate on each day
486 new \DateInterval('P1D'),
487 //End with next sunday and 4 weeks
488 new \DateTime(
489 $this->isGranted('IS_AUTHENTICATED_REMEMBERED')?'Monday this week + 3 week':'Monday this week + 2 week'
490 )
491 );
492
493 //With admin role
494 if ($this->isGranted('ROLE_ADMIN')) {
495 //Display all users
496 $this->context['groups'] = $users;
497 //Without admin role
498 } else {
499 //Only display senior organizers
500 $this->context['users'] = $users[$this->translator->trans('Senior')];
501 }
502
503 //Fetch locations
504 //XXX: we want to display all active locations anyway
505 $locations = $doctrine->getRepository(Location::class)->findTranslatedSortedByPeriod($this->translator, $period);
506
507 //Render the view
508 return $this->render('@RapsysAir/user/index.html.twig', ['title' => $title, 'section' => $section, 'locations' => $locations]+$this->context);
509 }
510
511 /**
512 * List all sessions for the user
513 *
514 * @desc Display all sessions for the user with an application or login form
515 *
516 * @param Request $request The request instance
517 * @param int $id The user id
518 *
519 * @return Response The rendered view
520 */
521 public function userView(Request $request, $id): Response {
522 //Fetch doctrine
523 $doctrine = $this->getDoctrine();
524
525 //Fetch user
526 if (empty($user = $doctrine->getRepository(User::class)->findOneById($id))) {
527 throw $this->createNotFoundException($this->translator->trans('Unable to find user: %id%', ['%id%' => $id]));
528 }
529
530 //Get user token
531 $token = new UsernamePasswordToken($user, null, 'none', $user->getRoles());
532
533 //Check if guest
534 $isGuest = $this->get('rapsys_user.access_decision_manager')->decide($token, ['ROLE_GUEST']);
535
536 //Prevent access when not admin, user is not guest and not currently logged user
537 if (!$this->isGranted('ROLE_ADMIN') && empty($isGuest) && $user != $this->getUser()) {
538 throw $this->createAccessDeniedException($this->translator->trans('Unable to access user: %id%', ['%id%' => $id]));
539 }
540
541 //Set section
542 $section = $user->getPseudonym();
543
544 //Set title
545 $title = $this->translator->trans($this->config['site']['title']).' - '.$section;
546
547 //Set description
548 $this->context['description'] = $this->translator->trans('%pseudonym% outdoor Argentine Tango session calendar', [ '%pseudonym%' => $user->getPseudonym() ]);
549
550 //Set keywords
551 $this->context['keywords'] = [
552 $user->getPseudonym(),
553 $this->translator->trans('outdoor'),
554 $this->translator->trans('Argentine Tango'),
555 $this->translator->trans('calendar')
556 ];
557
558 //Compute period
559 $period = new \DatePeriod(
560 //Start from first monday of week
561 new \DateTime('Monday this week'),
562 //Iterate on each day
563 new \DateInterval('P1D'),
564 //End with next sunday and 4 weeks
565 new \DateTime(
566 $this->isGranted('IS_AUTHENTICATED_REMEMBERED')?'Monday this week + 3 week':'Monday this week + 2 week'
567 )
568 );
569
570 //Fetch calendar
571 //TODO: highlight with current session route parameter
572 $calendar = $doctrine->getRepository(Session::class)->fetchUserCalendarByDatePeriod($this->translator, $period, $isGuest?$id:null, $request->get('session'), $request->getLocale());
573
574 //Fetch locations
575 //XXX: we want to display all active locations anyway
576 $locations = $doctrine->getRepository(Location::class)->findTranslatedSortedByPeriod($this->translator, $period, $id);
577
578 //Create user form for admin or current user
579 if ($this->isGranted('ROLE_ADMIN') || $user == $this->getUser()) {
580 //Create SnippetType form
581 $userForm = $this->createForm('Rapsys\AirBundle\Form\RegisterType', $user, [
582 //Set action
583 'action' => $this->generateUrl('rapsys_air_user_view', ['id' => $id]),
584 //Set the form attribute
585 'attr' => [ 'class' => 'col' ],
586 //Set civility class
587 'civility_class' => Civility::class,
588 //Disable mail
589 'mail' => $this->isGranted('ROLE_ADMIN'),
590 //Disable password
591 'password' => false
592 ]);
593
594 //Init user to context
595 $this->context['forms']['user'] = $userForm->createView();
596
597 //Check if submitted
598 if ($request->isMethod('POST')) {
599 //Refill the fields in case the form is not valid.
600 $userForm->handleRequest($request);
601
602 //Handle invalid form
603 if (!$userForm->isSubmitted() || !$userForm->isValid()) {
604 //Render the view
605 return $this->render('@RapsysAir/user/view.html.twig', ['id' => $id, 'title' => $title, 'section' => $section, 'calendar' => $calendar, 'locations' => $locations]+$this->context);
606 }
607
608 //Get data
609 $data = $userForm->getData();
610
611 //Get manager
612 $manager = $doctrine->getManager();
613
614 //Queue snippet save
615 $manager->persist($data);
616
617 //Flush to get the ids
618 $manager->flush();
619
620 //Add notice
621 $this->addFlash('notice', $this->translator->trans('User %id% updated', ['%id%' => $id]));
622
623 //Extract and process referer
624 if ($referer = $request->headers->get('referer')) {
625 //Create referer request instance
626 $req = Request::create($referer);
627
628 //Get referer path
629 $path = $req->getPathInfo();
630
631 //Get referer query string
632 $query = $req->getQueryString();
633
634 //Remove script name
635 $path = str_replace($request->getScriptName(), '', $path);
636
637 //Try with referer path
638 try {
639 //Save old context
640 $oldContext = $this->router->getContext();
641
642 //Force clean context
643 //XXX: prevent MethodNotAllowedException because current context method is POST in onevendor/symfony/routing/Matcher/Dumper/CompiledUrlMatcherTrait.php+42
644 $this->router->setContext(new RequestContext());
645
646 //Retrieve route matching path
647 $route = $this->router->match($path);
648
649 //Reset context
650 $this->router->setContext($oldContext);
651
652 //Clear old context
653 unset($oldContext);
654
655 //Extract name
656 $name = $route['_route'];
657
658 //Remove route and controller from route defaults
659 unset($route['_route'], $route['_controller']);
660
661 //Check if user view route
662 if ($name == 'rapsys_air_user_view' && !empty($route['id'])) {
663 //Replace id
664 $route['id'] = $data->getId();
665 //Other routes
666 } else {
667 //Set user
668 $route['user'] = $data->getId();
669 }
670
671 //Generate url
672 return $this->redirectToRoute($name, $route);
673 //No route matched
674 } catch(MethodNotAllowedException|ResourceNotFoundException $e) {
675 //Unset referer to fallback to default route
676 unset($referer);
677 }
678 }
679
680 //Redirect to cleanup the form
681 return $this->redirectToRoute('rapsys_air', ['user' => $data->getId()]);
682 }
683 }
684
685 //Create snippet forms for role_guest
686 if ($this->isGranted('ROLE_ADMIN') || ($this->isGranted('ROLE_GUEST') && $user == $this->getUser())) {
687 //Fetch all user snippet
688 $snippets = $doctrine->getRepository(Snippet::class)->findByLocaleUserId($request->getLocale(), $id);
689
690 //Rekey by location id
691 $snippets = array_reduce($snippets, function($carry, $item){$carry[$item->getLocation()->getId()] = $item; return $carry;}, []);
692
693 //Init snippets to context
694 $this->context['forms']['snippets'] = [];
695
696 //Iterate on locations
697 foreach($locations as $locationId => $location) {
698 //Init snippet
699 $snippet = new Snippet();
700
701 //Set default locale
702 $snippet->setLocale($request->getLocale());
703
704 //Set default user
705 $snippet->setUser($user);
706
707 //Set default location
708 $snippet->setLocation($doctrine->getRepository(Location::class)->findOneById($locationId));
709
710 //With existing snippet
711 if (!empty($snippets[$locationId])) {
712 $snippet = $snippets[$locationId];
713 $action = $this->generateUrl('rapsys_air_snippet_edit', ['id' => $snippet->getId()]);
714 //Without snippet
715 } else {
716 $action = $this->generateUrl('rapsys_air_snippet_add', ['location' => $locationId]);
717 }
718
719 //Create SnippetType form
720 $form = $this->container->get('form.factory')->createNamed('snipped_'.$request->getLocale().'_'.$locationId, 'Rapsys\AirBundle\Form\SnippetType', $snippet, [
721 //Set the action
722 'action' => $action,
723 //Set the form attribute
724 'attr' => []
725 ]);
726
727 //Add form to context
728 $this->context['forms']['snippets'][$locationId] = $form->createView();
729 }
730 }
731
732 //Render the view
733 return $this->render('@RapsysAir/user/view.html.twig', ['id' => $id, 'title' => $title, 'section' => $section, 'calendar' => $calendar, 'locations' => $locations]+$this->context);
734 }
735 }