1 <?php 
declare(strict_types
=1); 
   4  * This file is part of the Rapsys AirBundle package. 
   6  * (c) Raphaël Gertz <symfony@rapsys.eu> 
   8  * For the full copyright and license information, please view the LICENSE 
   9  * file that was distributed with this source code. 
  12 namespace Rapsys\AirBundle\Controller
; 
  14 use Symfony\Bridge\Twig\Mime\TemplatedEmail
; 
  15 use Symfony\Component\Filesystem\Exception\IOExceptionInterface
; 
  16 use Symfony\Component\Filesystem\Filesystem
; 
  17 use Symfony\Component\Form\FormError
; 
  18 use Symfony\Component\HttpFoundation\Request
; 
  19 use Symfony\Component\HttpFoundation\Response
; 
  20 use Symfony\Component\HttpKernel\Exception\NotFoundHttpException
; 
  21 use Symfony\Component\Mailer\Exception\TransportExceptionInterface
; 
  22 use Symfony\Component\Mime\Address
; 
  23 use Symfony\Component\Security\Core\Exception\AccessDeniedException
; 
  25 use Rapsys\AirBundle\Entity\Dance
; 
  26 use Rapsys\AirBundle\Entity\Location
; 
  27 use Rapsys\AirBundle\Entity\Session
; 
  28 use Rapsys\AirBundle\Entity\Snippet
; 
  29 use Rapsys\AirBundle\Entity\User
; 
  30 use Rapsys\AirBundle\Token\AnonymousToken
; 
  35 class DefaultController 
extends AbstractController 
{ 
  39          * @desc Display the about informations 
  41          * @param Request $request The request instance 
  42          * @return Response The rendered view 
  44         public function about(Request 
$request): Response 
{ 
  46                 $this->context
['title']['page'] = $this->translator
->trans('About'); 
  49                 $this->context
['description'] = $this->translator
->trans('Libre Air about'); 
  52                 $this->context
['keywords'] = [ 
  53                         $this->translator
->trans('about'), 
  54                         $this->translator
->trans('Libre Air') 
  58                 $response = $this->render('@RapsysAir/default/about.html.twig', $this->context
); 
  59                 $response->setEtag(md5($response->getContent())); 
  60                 $response->setPublic(); 
  61                 $response->isNotModified($request); 
  70          * @desc Send a contact mail to configured contact 
  72          * @param Request $request The request instance 
  74          * @return Response The rendered view or redirection 
  76         public function contact(Request 
$request): Response 
{ 
  78                 $this->context
['title']['page'] = $this->translator
->trans('Contact'); 
  81                 $this->context
['description'] = $this->translator
->trans('Contact Libre Air'); 
  84                 $this->context
['keywords'] = [ 
  85                         $this->translator
->trans('contact'), 
  86                         $this->translator
->trans('Libre Air'), 
  87                         $this->translator
->trans('outdoor'), 
  88                         $this->translator
->trans('Argentine Tango'), 
  89                         $this->translator
->trans('calendar') 
  96                 if ($user = $this->security
->getUser()) { 
  99                                 'name' => $user->getRecipientName(), 
 100                                 'mail' => $user->getMail() 
 104                 //Create the form according to the FormType created previously. 
 105                 //And give the proper parameters 
 106                 $form = $this->factory
->create('Rapsys\AirBundle\Form\ContactType', $data, [ 
 107                         'action' => $this->generateUrl('rapsys_air_contact'), 
 111                 if ($request->isMethod('POST')) { 
 112                         // Refill the fields in case the form is not valid. 
 113                         $form->handleRequest($request); 
 115                         if ($form->isSubmitted() && $form->isValid()) { 
 117                                 $data = $form->getData(); 
 120                                 $message = (new TemplatedEmail()) 
 122                                         ->from(new Address($data['mail'], $data['name'])) 
 124                                         ->to(new Address($this->context
['contact']['address'], $this->context
['contact']['name'])) 
 126                                         ->subject($data['subject']) 
 128                                         //Set path to twig templates 
 129                                         ->htmlTemplate('@RapsysAir/mail/contact.html.twig') 
 130                                         ->textTemplate('@RapsysAir/mail/contact.text.twig') 
 135                                                         'subject' => $data['subject'], 
 136                                                         'message' => strip_tags($data['message']), 
 140                                 //Try sending message 
 141                                 //XXX: mail delivery may silently fail 
 144                                         $this->mailer
->send($message); 
 146                                         //Redirect on the same route with sent=1 to cleanup form 
 147                                         return $this->redirectToRoute($request->get('_route'), ['sent' => 1]+
$request->get('_route_params')); 
 148                                 //Catch obvious transport exception 
 149                                 } catch(TransportExceptionInterface 
$e) { 
 150                                         if ($message = $e->getMessage()) { 
 151                                                 //Add error message mail unreachable 
 152                                                 $form->get('mail')->addError(new FormError($this->translator
->trans('Unable to contact: %mail%: %message%', ['%mail%' => $this->context
['contact']['address'], '%message%' => $this->translator
->trans($message)]))); 
 154                                                 //Add error message mail unreachable 
 155                                                 $form->get('mail')->addError(new FormError($this->translator
->trans('Unable to contact: %mail%', ['%mail%' => $this->context
['contact']['address']]))); 
 162                 return $this->render('@RapsysAir/form/contact.html.twig', ['form' => $form->createView(), 'sent' => $request->query
->get('sent', 0)]+
$this->context
); 
 168          * Display session calendar 
 170          * @param Request $request The request instance 
 171          * @return Response The rendered view 
 173         public function index(Request 
$request): Response 
{ 
 175                 $this->context
['cities'] = $this->doctrine
->getRepository(Location
::class)->findCitiesAsArray($this->period
); 
 178                 $this->context
['calendar'] = $this->doctrine
->getRepository(Session
::class)->findAllByPeriodAsCalendarArray($this->period
, !$this->checker
->isGranted('IS_AUTHENTICATED_REMEMBERED')); 
 181                 $this->context
['dances'] = $this->doctrine
->getRepository(Dance
::class)->findNamesAsArray(); 
 184                 $this->modified 
= max(array_map(function ($v) { return $v
['modified']; }, array_merge($this->context
['calendar'], $this->context
['cities'], $this->context
['dances']))); 
 187                 $response = new Response(); 
 190                 if ($this->checker
->isGranted('IS_AUTHENTICATED_REMEMBERED')) { 
 192                         $response->setLastModified(new \
DateTime('-1 year')); 
 195                         $response->setPrivate(); 
 196                 //Without logged user 
 199                         //XXX: only for public to force revalidation by last modified 
 200                         $response->setEtag(md5(serialize(array_merge($this->context
['calendar'], $this->context
['cities'], $this->context
['dances'])))); 
 203                         $response->setLastModified($this->modified
); 
 206                         $response->setPublic(); 
 208                         //Without role and modification 
 209                         if ($response->isNotModified($request)) { 
 210                                 //Return 304 response 
 216                 if (!empty($this->context
['cities'])) { 
 220                         //Iterate on each cities 
 221                         foreach($this->context
['cities'] as $city) { 
 222                                 //Iterate on each locations 
 223                                 foreach($city['locations'] as $location) { 
 225                                         $locations[$location['id']] = $location; 
 230                         $this->context
['multimap'] = $this->map
->getMultiMap($this->translator
->trans('Libre Air cities sector map'), $this->modified
->getTimestamp(), $locations); 
 233                         $cities = array_map(function ($v) { return $v
['in']; }, $this->context
['cities']); 
 236                         $dances = array_map(function ($v) { return $v
['name']; }, $this->context
['dances']); 
 246                 //TODO: use splice instead of that shit !!! 
 247                 //TODO: handle smartly indoor and outdoor !!! 
 248                 $this->context
['keywords'] = array_values( 
 253                                         $this->translator
->trans('indoor'), 
 254                                         $this->translator
->trans('outdoor'), 
 255                                         $this->translator
->trans('calendar'), 
 256                                         $this->translator
->trans('Libre Air') 
 262                 $cities = implode($this->translator
->trans(' and '), array_filter(array_merge([implode(', ', array_slice($cities, 0, -1))], array_slice($cities, -1)), 'strlen')); 
 265                 $dances = implode($this->translator
->trans(' and '), array_filter(array_merge([implode(', ', array_slice($dances, 0, -1))], array_slice($dances, -1)), 'strlen')); 
 268                 $this->context
['title']['page'] = $this->translator
->trans('%dances% %cities%', ['%dances%' => $dances, '%cities%' => $cities]); 
 271                 //TODO: handle french translation when city start with a A, change à in en ! 
 272                 $this->context
['description'] = $this->translator
->trans('%dances% indoor and outdoor calendar %cities%', ['%dances%' => $dances, '%cities%' => $cities]); 
 275                 //XXX: only valid for home page 
 276                 $this->context
['facebook']['metas']['og:type'] = 'website'; 
 279                 return $this->render('@RapsysAir/default/index.html.twig', $this->context
, $response); 
 283          * The organizer regulation page 
 285          * @desc Display the organizer regulation policy 
 287          * @param Request $request The request instance 
 288          * @return Response The rendered view 
 290         public function organizerRegulation(Request 
$request): Response 
{ 
 292                 $this->context
['title']['page'] = $this->translator
->trans('Organizer regulation'); 
 295                 $this->context
['description'] = $this->translator
->trans('Libre Air organizer regulation'); 
 298                 $this->context
['keywords'] = [ 
 299                         $this->translator
->trans('organizer regulation'), 
 300                         $this->translator
->trans('Libre Air') 
 304                 $response = $this->render('@RapsysAir/default/organizer_regulation.html.twig', $this->context
); 
 307                 $response->setEtag(md5($response->getContent())); 
 308                 $response->setPublic(); 
 309                 $response->isNotModified($request); 
 316          * The terms of service page 
 318          * @desc Display the terms of service policy 
 320          * @param Request $request The request instance 
 321          * @return Response The rendered view 
 323         public function termsOfService(Request 
$request): Response 
{ 
 325                 $this->context
['title']['page'] = $this->translator
->trans('Terms of service'); 
 328                 $this->context
['description'] = $this->translator
->trans('Libre Air terms of service'); 
 331                 $this->context
['keywords'] = [ 
 332                         $this->translator
->trans('terms of service'), 
 333                         $this->translator
->trans('Libre Air') 
 337                 $response = $this->render('@RapsysAir/default/terms_of_service.html.twig', $this->context
); 
 340                 $response->setEtag(md5($response->getContent())); 
 341                 $response->setPublic(); 
 342                 $response->isNotModified($request); 
 349          * The frequently asked questions page 
 351          * @desc Display the frequently asked questions 
 353          * @param Request $request The request instance 
 354          * @return Response The rendered view 
 356         public function frequentlyAskedQuestions(Request 
$request): Response 
{ 
 358                 $this->context
['title']['page'] = $this->translator
->trans('Frequently asked questions'); 
 361                 $this->context
['description'] = $this->translator
->trans('Libre Air frequently asked questions'); 
 364                 $this->context
['keywords'] = [ 
 365                         $this->translator
->trans('frequently asked questions'), 
 366                         $this->translator
->trans('faq'), 
 367                         $this->translator
->trans('Libre Air') 
 371                 $response = $this->render('@RapsysAir/default/frequently_asked_questions.html.twig', $this->context
); 
 374                 $response->setEtag(md5($response->getContent())); 
 375                 $response->setPublic(); 
 376                 $response->isNotModified($request); 
 385          * @desc Display all user with a group listed as users 
 387          * @param Request $request The request instance 
 389          * @return Response The rendered view 
 391         public function userIndex(Request 
$request): Response 
{ 
 393                 if ($this->checker
->isGranted('ROLE_ADMIN')) { 
 395                         $this->context
['title']['page'] = $this->translator
->trans('Libre Air user list'); 
 398                         $this->context
['title']['section'] = $this->translator
->trans('User'); 
 401                         $this->context
['description'] = $this->translator
->trans('Lists Libre air users'); 
 405                         $this->context
['title']['page'] = $this->translator
->trans('Libre Air organizer list'); 
 408                         $this->context
['title']['section'] = $this->translator
->trans('Organizer'); 
 411                         $this->context
['description'] = $this->translator
->trans('Lists Libre air organizers'); 
 415                 $this->context
['keywords'] = [ 
 416                         $this->translator
->trans('users'), 
 417                         $this->translator
->trans('user list'), 
 418                         $this->translator
->trans('listing'), 
 419                         $this->translator
->trans('Libre Air') 
 423                 $users = $this->doctrine
->getRepository(User
::class)->findIndexByGroupId(); 
 426                 if ($this->checker
->isGranted('ROLE_ADMIN')) { 
 428                         $this->context
['groups'] = $users; 
 431                         //Only display senior organizers 
 432                         $this->context
['users'] = $users[$this->translator
->trans('Senior')]; 
 436                 return $this->render('@RapsysAir/user/index.html.twig', $this->context
); 
 440          * List all sessions for the user 
 442          * @desc Display all sessions for the user with an application or login form 
 444          * @param Request $request The request instance 
 445          * @param int $id The user id 
 447          * @return Response The rendered view 
 449         public function userView(Request 
$request, int $id, ?string $user): Response 
{ 
 451                 if (empty($this->context
['user'] = $this->doctrine
->getRepository(User
::class)->findOneByIdAsArray($id, $this->locale
))) { 
 453                         throw new NotFoundHttpException($this->translator
->trans('Unable to find user: %id%', ['%id%' => $id])); 
 457                 $token = new AnonymousToken($this->context
['user']['roles']); 
 459                 //Prevent access when not admin, user is not guest and not currently logged user 
 460                 if (!($isAdmin = $this->checker
->isGranted('ROLE_ADMIN')) && !($isGuest = $this->decision
->decide($token, ['ROLE_GUEST']))) { 
 461                         //Throw access denied 
 462                         throw new AccessDeniedException($this->translator
->trans('Unable to access user: %id%', ['%id%' => $id])); 
 465                 //With invalid user slug 
 466                 if ($this->context
['user']['slug'] !== $user) { 
 467                         //Redirect to cleaned url 
 468                         return $this->redirectToRoute('rapsys_air_user_view', ['id' => $id, 'user' => $this->context
['user']['slug']]); 
 472                 $this->context
['calendar'] = $this->doctrine
->getRepository(Session
::class)->findAllByPeriodAsCalendarArray($this->period
, !$this->checker
->isGranted('IS_AUTHENTICATED_REMEMBERED'), null, null, $id); 
 474                 //Get locations at less than 2 km 
 475                 $this->context
['locations'] = $this->doctrine
->getRepository(Location
::class)->findAllByUserIdAsArray($id, $this->period
, 2); 
 498                 //Iterate on each calendar 
 499                 foreach($this->context
['calendar'] as $date => $calendar) { 
 500                         //Iterate on each session 
 501                         foreach($calendar['sessions'] as $sessionId => $session) { 
 503                                 $dances[$session['application']['dance']['name']] = $session['application']['dance']['name']; 
 506                                 $types[$session['application']['dance']['type']] = lcfirst($session['application']['dance']['type']); 
 509                                 $indoors[$session['location']['indoor']?'indoor':'outdoor'] = $this->translator
->trans($session['location']['indoor']?'indoor':'outdoor'); 
 512                                 $insides[$session['location']['indoor']?'inside':'outside'] = $this->translator
->trans($session['location']['indoor']?'inside':'outside'); 
 515                                 $ats[$session['location']['id']] = $session['location']['at']; 
 518                                 $ins[$session['location']['id']] = $session['location']['in']; 
 520                                 //Session with application user id 
 521                                 if (!empty($session['application']['user']['id']) && $session['application']['user']['id'] == $id) { 
 523                                         $locations[$session['location']['id']] = $session['location']; 
 529                 //XXX: dance modified is already computed inside calendar modified 
 530                 $this->modified 
= max(array_merge([$this->context
['user']['modified']], array_map(function ($v) { return $v
['modified']; }, array_merge($this->context
['calendar'], $this->context
['locations'])))); 
 533                 $response = new Response(); 
 536                 if ($this->checker
->isGranted('IS_AUTHENTICATED_REMEMBERED')) { 
 538                         $response->setLastModified(new \
DateTime('-1 year')); 
 541                         $response->setPrivate(); 
 542                 //Without logged user 
 545                         //XXX: only for public to force revalidation by last modified 
 546                         $response->setEtag(md5(serialize(array_merge($this->context
['user'], $this->context
['calendar'], $this->context
['locations'])))); 
 549                         $response->setLastModified($this->modified
); 
 552                         $response->setPublic(); 
 554                         //Without role and modification 
 555                         if ($response->isNotModified($request)) { 
 556                                 //Return 304 response 
 562                 $this->context
['multimap'] = $this->map
->getMultiMap($this->context
['user']['multimap'], $this->modified
->getTimestamp(), $this->context
['locations']); 
 565                 $this->context
['keywords'] = [ 
 566                         $this->context
['user']['pseudonym'], 
 567                         $this->translator
->trans('calendar'), 
 568                         $this->translator
->trans('Libre Air') 
 572                 $cities = array_unique(array_map(function ($v) { return $v
['city']; }, $locations)); 
 575                 $titles = array_map(function ($v) { return $v
['title']; }, $locations); 
 577                 //Insert dances in keywords 
 578                 array_splice($this->context
['keywords'], 1, 0, array_merge($types, $dances, $indoors, $insides, $titles, $cities)); 
 581                 $ins = array_unique($ins); 
 584                 $dances = implode($this->translator
->trans(' and '), array_filter(array_merge([implode(', ', array_slice($dances, 0, -1))], array_slice($dances, -1)), 'strlen')); 
 587                 $types = implode($this->translator
->trans(' and '), array_filter(array_merge([implode(', ', array_slice($types, 0, -1))], array_slice($types, -1)), 'strlen')); 
 589                 //Get textual indoors 
 590                 $indoors = implode($this->translator
->trans(' and '), array_filter(array_merge([implode(', ', array_slice($indoors, 0, -1))], array_slice($indoors, -1)), 'strlen')); 
 593                 $ats = implode($this->translator
->trans(' and '), array_filter(array_merge([implode(', ', array_slice($ats, 0, -1))], array_slice($ats, -1)), 'strlen')); 
 596                 $ins = implode($this->translator
->trans(' and '), array_filter(array_merge([implode(', ', array_slice($ins, 0, -1))], array_slice($ins, -1)), 'strlen')); 
 599                 $this->context
['title']['page'] = $this->translator
->trans('%pseudonym% organizer', ['%pseudonym%' => $this->context
['user']['pseudonym']]); 
 602                 $this->context
['title']['section'] = $this->translator
->trans('User'); 
 605                 if (!empty($locations)) { 
 607                         $this->context
['description'] = ucfirst($this->translator
->trans('%dances% %types% %indoors% calendar %ats% %ins% %pseudonym%', ['%dances%' => $dances, '%types%' => $types, '%indoors%' => $indoors, '%ats%' => $ats, '%ins%' => $ins, '%pseudonym%' => $this->translator
->trans('by %pseudonym%', ['%pseudonym%' => $this->context
['user']['pseudonym']])])); 
 611                         $this->context
['description'] = $this->translator
->trans('%pseudonym% calendar', ['%pseudonym%' => $this->context
['user']['pseudonym']]); 
 614                 //Set user description 
 615                 $this->context
['locations_description'] = $this->translator
->trans('Libre Air %pseudonym% location list', ['%pseudonym%' => $this->translator
->trans('by %pseudonym%', ['%pseudonym%' => $this->context
['user']['pseudonym']])]); 
 618                 $this->context
['alternates'] +
= $this->context
['user']['alternates']; 
 620                 //Create snippet forms for role_guest 
 621                 //TODO: optimize this call 
 622                 if ($isAdmin || $isGuest && $this->security
->getUser() && $this->context
['user']['id'] == $this->security
->getUser()->getId()) { 
 623                         //Fetch all user snippet 
 624                         $snippets = $this->doctrine
->getRepository(Snippet
::class)->findByUserIdLocaleIndexByLocationId($id, $this->locale
); 
 627                         $user = $this->doctrine
->getRepository(User
::class)->findOneById($id); 
 629                         //Iterate on locations 
 630                         foreach($this->context
['locations'] as $locationId => $location) { 
 631                                 //With existing snippet 
 632                                 if (isset($snippets[$location['id']])) { 
 633                                         //Set existing in current 
 634                                         $current = $snippets[$location['id']]; 
 635                                 //Without existing snippet 
 638                                         $current = new Snippet(); 
 641                                         $current->setLocale($this->locale
); 
 644                                         $current->setUser($user); 
 646                                         //Set default location 
 647                                         $current->setLocation($this->doctrine
->getRepository(Location
::class)->findOneById($location['id'])); 
 650                                 //Create SnippetType form 
 651                                 $form = $this->factory
->createNamed( 
 653                                         'snippet_'.$locationId.'_'.$id.'_'.$this->locale
, 
 655                                         'Rapsys\AirBundle\Form\SnippetType', 
 660                                 //Refill the fields in case of invalid form 
 661                                 $form->handleRequest($request); 
 663                                 //Handle submitted and valid form 
 664                                 //TODO: add a delete snippet ? 
 665                                 if ($form->isSubmitted() && $form->isValid()) { 
 667                                         $snippet = $form->getData(); 
 670                                         $this->manager
->persist($snippet); 
 672                                         //Flush to get the ids 
 673                                         $this->manager
->flush(); 
 676                                         $this->addFlash('notice', $this->translator
->trans('Snippet for %user% %location% updated', ['%location%' => $location['at'], '%user%' => $this->context
['user']['pseudonym']])); 
 678                                         //Redirect to cleaned url 
 679                                         return $this->redirectToRoute('rapsys_air_user_view', ['id' => $id, 'user' => $this->context
['user']['slug']]); 
 682                                 //Add form to context 
 683                                 $this->context
['forms']['snippets'][$locationId] = $form->createView(); 
 685                                 //With location user source image 
 686                                 if (($isFile = is_file($source = $this->config
['path'].'/location/'.$location['id'].'/'.$id.'.png')) && ($mtime = stat($source)['mtime'])) { 
 688                                         $this->context
['locations'][$locationId]['image'] = $this->image
->getThumb($location['miniature'], $mtime, $source); 
 691                                 //Create ImageType form 
 692                                 $form = $this->factory
->createNamed( 
 694                                         'image_'.$locationId.'_'.$id, 
 696                                         'Rapsys\AirBundle\Form\ImageType', 
 700                                                 'location' => $location['id'], 
 704                                         //Set form attributes 
 706                                                 //Enable delete with image 
 707                                                 'delete' => isset($this->context
['locations'][$locationId]['image']) 
 711                                 //Refill the fields in case of invalid form 
 712                                 $form->handleRequest($request); 
 714                                 //Handle submitted and valid form 
 715                                 if ($form->isSubmitted() && $form->isValid()) { 
 717                                         if ($form->has('delete') && $form->get('delete')->isClicked()) { 
 718                                                 //With source and mtime 
 719                                                 if ($isFile && !empty($source) && !empty($mtime)) { 
 721                                                         $this->image
->remove($mtime, $source); 
 724                                                         unlink($this->config
['path'].'/location/'.$location['id'].'/'.$id.'.png'); 
 727                                                         $this->addFlash('notice', $this->translator
->trans('Image for %user% %location% deleted', ['%location%' => $location['at'], '%user%' => $this->context
['user']['pseudonym']])); 
 729                                                         //Redirect to cleaned url 
 730                                                         return $this->redirectToRoute('rapsys_air_user_view', ['id' => $id, 'user' => $this->context
['user']['slug']]); 
 735                                         if ($image = $form->get('image')->getData()) { 
 737                                                 if (!is_dir($dir = dirname($source))) { 
 738                                                         //Create filesystem object 
 739                                                         $filesystem = new Filesystem(); 
 743                                                                 //XXX: set as 0775, symfony umask (0022) will reduce rights (0755) 
 744                                                                 $filesystem->mkdir($dir, 0775); 
 745                                                         } catch (IOExceptionInterface 
$e) { 
 747                                                                 throw new \
Exception(sprintf('Output directory "%s" do not exists and unable to create it', $dir), 0, $e); 
 752                                                 $source = realpath($dir).'/'.basename($source); 
 754                                                 //Create imagick object 
 755                                                 $imagick = new \
Imagick(); 
 758                                                 $imagick->readImage($image->getRealPath()); 
 761                                                 if (!$imagick->writeImage($source)) { 
 763                                                         throw new \
Exception(sprintf('Unable to write image "%s"', $source)); 
 767                                                 $this->addFlash('notice', $this->translator
->trans('Image for %user% %location% updated', ['%location%' => $location['at'], '%user%' => $this->context
['user']['pseudonym']])); 
 769                                                 //Redirect to cleaned url 
 770                                                 return $this->redirectToRoute('rapsys_air_user_view', ['id' => $id, 'user' => $this->context
['user']['slug']]); 
 774                                 //Add form to context 
 775                                 $this->context
['forms']['images'][$locationId] = $form->createView(); 
 780                 return $this->render('@RapsysAir/user/view.html.twig', ['id' => $id]+
$this->context
);