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\Component\HttpFoundation\Request
; 
  15 use Symfony\Component\HttpFoundation\Response
; 
  17 use Rapsys\AirBundle\Entity\Dance
; 
  18 use Rapsys\AirBundle\Entity\Location
; 
  19 use Rapsys\AirBundle\Entity\Session
; 
  24 class LocationController 
extends DefaultController 
{ 
  28          * @param Request $request The request instance 
  29          * @return Response The rendered view 
  31         public function cities(Request 
$request): Response 
{ 
  33                 $this->context
['cities'] = $this->doctrine
->getRepository(Location
::class)->findCitiesAsArray($this->period
, 0); 
  36                 $this->context
['dances'] = $this->doctrine
->getRepository(Dance
::class)->findNamesAsArray(); 
  39                 $response = new Response(); 
  42                 $this->modified 
= max(array_map(function ($v) { return $v
['modified']; }, array_merge($this->context
['cities'], $this->context
['dances']))); 
  45                 foreach($this->context
['cities'] as $id => $city) { 
  47                         $this->context
['cities'][$id]['multimap'] = $this->map
->getMultiMap($city['multimap'], $this->modified
->getTimestamp(), $city['locations']); 
  51                 if ($this->checker
->isGranted('IS_AUTHENTICATED_REMEMBERED')) { 
  53                         $response->setLastModified(new \
DateTime('-1 year')); 
  56                         $response->setPrivate(); 
  60                         //XXX: only for public to force revalidation by last modified 
  61                         $response->setEtag(md5(serialize(array_merge($this->context
['cities'], $this->context
['dances'])))); 
  64                         $response->setLastModified($this->modified
); 
  67                         $response->setPublic(); 
  69                         //Without role and modification 
  70                         if ($response->isNotModified($request)) { 
  77                 $this->context
['title']['page'] = $this->translator
->trans('Libre Air cities'); 
  80                 $this->context
['description'] = $this->translator
->trans('Libre Air city list'); 
  83                 $cities = array_map(function ($v) { return $v
['in']; }, $this->context
['cities']); 
  86                 $dances = array_map(function ($v) { return $v
['name']; }, $this->context
['dances']); 
  89                 $indoors = array_reduce($this->context
['cities'], function ($c, $v) { return array_merge($c
, $v
['indoors']); }, []); 
  92                 $this->context
['keywords'] = array_values( 
  95                                         $this->translator
->trans('Cities'), 
  96                                         $this->translator
->trans('City list'), 
  97                                         $this->translator
->trans('Listing'), 
 102                                         $this->translator
->trans('calendar'), 
 103                                         $this->translator
->trans('Libre Air') 
 109                 return $this->render('@RapsysAir/location/cities.html.twig', $this->context
, $response); 
 115          * @todo XXX: TODO: add <link rel="prev|next" for sessions or classes ? /> 
 116          * @todo XXX: TODO: like described in: https://www.alsacreations.com/article/lire/1400-attribut-rel-relations.html#xnf-rel-attribute 
 117          * @todo XXX: TODO: or here: http://microformats.org/wiki/existing-rel-values#HTML5_link_type_extensions 
 119          * @param Request $request The request instance 
 120          * @param float $latitude The city latitude 
 121          * @param float $longitude The city longitude 
 122          * @return Response The rendered view 
 124         public function city(Request 
$request, float $latitude, float $longitude, string $city): Response 
{ 
 126                 if (!($this->context
['city'] = $this->doctrine
->getRepository(Location
::class)->findCityByLatitudeLongitudeAsArray(floatval($latitude), floatval($longitude)))) { 
 127                         throw $this->createNotFoundException($this->translator
->trans('Unable to find city: %latitude%,%longitude%', ['%latitude%' => $latitude, '%longitude%' => $longitude])); 
 131                 $this->context
['calendar'] = $this->doctrine
->getRepository(Session
::class)->findAllByPeriodAsCalendarArray($this->period
, !$this->checker
->isGranted('IS_AUTHENTICATED_REMEMBERED'), floatval($latitude), floatval($longitude)); 
 134                 $this->context
['dances'] = []; 
 136                 //Iterate on each calendar 
 137                 foreach($this->context
['calendar'] as $date => $calendar) { 
 138                         //Iterate on each session 
 139                         foreach($calendar['sessions'] as $sessionId => $session) { 
 140                                 //Session with application dance 
 141                                 if (!empty($session['application']['dance'])) { 
 143                                         $this->context
['dances'][$session['application']['dance']['id']] = $session['application']['dance']; 
 149                 $this->context
['locations'] = $this->doctrine
->getRepository(Location
::class)->findAllByLatitudeLongitudeAsArray(floatval($latitude), floatval($longitude), $this->period
, 0); 
 152                 //XXX: dance modified is already computed inside calendar modified 
 153                 $this->modified 
= max(array_merge([$this->context
['city']['updated']], array_map(function ($v) { return $v
['modified']; }, array_merge($this->context
['calendar'], $this->context
['locations'])))); 
 156                 $response = new Response(); 
 159                 if ($this->checker
->isGranted('IS_AUTHENTICATED_REMEMBERED')) { 
 161                         $response->setLastModified(new \
DateTime('-1 year')); 
 164                         $response->setPrivate(); 
 165                 //Without logged user 
 168                         //XXX: only for public to force revalidation by last modified 
 169                         $response->setEtag(md5(serialize(array_merge($this->context
['city'], $this->context
['dances'], $this->context
['calendar'], $this->context
['locations'])))); 
 172                         $response->setLastModified($this->modified
); 
 175                         $response->setPublic(); 
 177                         //Without role and modification 
 178                         if ($response->isNotModified($request)) { 
 179                                 //Return 304 response 
 185                 $this->context
['multimap'] = $this->map
->getMultiMap($this->context
['city']['multimap'], $this->modified
->getTimestamp(), $this->context
['locations']); 
 188                 $this->context
['keywords'] = [ 
 189                         $this->context
['city']['city'], 
 190                         $this->translator
->trans('Indoor'), 
 191                         $this->translator
->trans('Outdoor'), 
 192                         $this->translator
->trans('Calendar'), 
 193                         $this->translator
->trans('Libre Air') 
 196                 //With context dances 
 197                 if (!empty($this->context
['dances'])) { 
 199                         $dances = array_map(function ($v) { return $v
['name']; }, $this->context
['dances']); 
 201                         //Insert dances in keywords 
 202                         array_splice($this->context
['keywords'], 1, 0, $dances); 
 205                         $dances = implode($this->translator
->trans(' and '), array_filter(array_merge([implode(', ', array_slice($dances, 0, -1))], array_slice($dances, -1)), 'strlen')); 
 208                         $this->context
['title']['page'] = $this->translator
->trans('%dances% %city%', ['%dances%' => $dances, '%city%' => $this->context
['city']['in']]); 
 211                         $this->context
['description'] = $this->translator
->trans('%dances% indoor and outdoor calendar %city%', ['%dances%' => $dances, '%city%' => $this->context
['city']['in']]); 
 214                         $this->context
['title']['page'] = $this->translator
->trans('Dance %city%', ['%city%' => $this->context
['city']['in']]); 
 217                         $this->context
['description'] = $this->translator
->trans('Indoor and outdoor dance calendar %city%', ['%city%' => $this->context
['city']['in']]); 
 220                 //Set locations description 
 221                 $this->context
['locations_description'] = $this->translator
->trans('Libre Air location list %city%', ['%city%' => $this->context
['city']['in']]); 
 224                 return $this->render('@RapsysAir/location/city.html.twig', $this->context
, $response); 
 230          * @desc Display all locations 
 232          * @param Request $request The request instance 
 234          * @return Response The rendered view 
 236         public function index(Request 
$request): Response 
{ 
 238                 $this->context
['locations'] = $this->doctrine
->getRepository(Location
::class)->findAllAsArray($this->period
); 
 241                 $this->modified 
= max(array_map(function ($v) { return $v
['updated']; }, $this->context
['locations'])); 
 244                 $response = new Response(); 
 247                 if ($this->checker
->isGranted('IS_AUTHENTICATED_REMEMBERED')) { 
 249                         $response->setLastModified(new \
DateTime('-1 year')); 
 252                         $response->setPrivate(); 
 253                 //Without logged user 
 256                         //XXX: only for public to force revalidation by last modified 
 257                         $response->setEtag(md5(serialize($this->context
['locations']))); 
 260                         $response->setLastModified($this->modified
); 
 263                         $response->setPublic(); 
 265                         //Without role and modification 
 266                         if ($response->isNotModified($request)) { 
 267                                 //Return 304 response 
 273                 $this->context
['multimap'] = $this->map
->getMultiMap($this->translator
->trans('Libre Air locations sector map'), $this->modified
->getTimestamp(), $this->context
['locations']); 
 276                 $this->context
['title']['page'] = $this->translator
->trans('Libre Air locations'); 
 279                 $this->context
['description'] = $this->translator
->trans('Libre Air location list'); 
 282                 $this->context
['keywords'] = [ 
 283                         $this->translator
->trans('locations'), 
 284                         $this->translator
->trans('location list'), 
 285                         $this->translator
->trans('listing'), 
 286                         $this->translator
->trans('Libre Air') 
 289                 //Create location forms for role_admin 
 290                 if ($this->checker
->isGranted('ROLE_ADMIN')) { 
 291                         //Fetch all locations 
 292                         $locations = $this->doctrine
->getRepository(Location
::class)->findAll(); 
 294                         //Init locations to context 
 295                         $this->context
['forms']['locations'] = []; 
 297                         //Iterate on locations 
 298                         foreach($this->context
['locations'] as $id => $location) { 
 299                                 //Create LocationType form 
 300                                 $form = $this->factory
->createNamed( 
 304                                         'Rapsys\AirBundle\Form\LocationType', 
 306                                         $locations[$location['id']], 
 307                                         //Set the form attributes 
 311                                 //Refill the fields in case of invalid form 
 312                                 $form->handleRequest($request); 
 315                                 if ($form->isSubmitted() && $form->isValid()) { 
 317                                         $data = $form->getData(); 
 320                                         $data->setUpdated(new \
DateTime('now')); 
 322                                         //Queue location save 
 323                                         $this->manager
->persist($data); 
 325                                         //Flush to get the ids 
 326                                         $this->manager
->flush(); 
 329                                         $this->addFlash('notice', $this->translator
->trans('Location %id% updated', ['%id%' => $location['id']])); 
 331                                         //Redirect to cleanup the form 
 332                                         return $this->redirectToRoute('rapsys_air_location', ['location' => $location['id']]); 
 335                                 //Add form to context 
 336                                 $this->context
['forms']['locations'][$id] = $form->createView(); 
 339                         //Create LocationType form 
 340                         $form = $this->factory
->createNamed( 
 344                                 'Rapsys\AirBundle\Form\LocationType', 
 347                                 //Set the form attributes 
 348                                 ['attr' => ['class' => 'col']] 
 351                         //Refill the fields in case of invalid form 
 352                         $form->handleRequest($request); 
 355                         if ($form->isSubmitted() && $form->isValid()) { 
 357                                 $data = $form->getData(); 
 359                                 //Queue location save 
 360                                 $this->manager
->persist($data); 
 362                                 //Flush to get the ids 
 363                                 $this->manager
->flush(); 
 366                                 $this->addFlash('notice', $this->translator
->trans('Location created')); 
 368                                 //Redirect to cleanup the form 
 369                                 return $this->redirectToRoute('rapsys_air_location', ['location' => $data->getId()]); 
 372                         //Add form to context 
 373                         $this->context
['forms']['location'] = $form->createView(); 
 377                 return $this->render('@RapsysAir/location/index.html.twig', $this->context
); 
 381          * List all sessions for the location 
 383          * Display all sessions for the location with an application or login form 
 385          * @TODO: add location edit form ??? 
 387          * @param Request $request The request instance 
 388          * @param int $id The location id 
 389          * @param ?string $location The location slug 
 391          * @return Response The rendered view 
 393         public function view(Request 
$request, int $id, ?string $location): Response 
{ 
 395                 if (empty($this->context
['location'] = $this->doctrine
->getRepository(Location
::class)->findOneByIdAsArray($id, $this->locale
))) { 
 397                         throw $this->createNotFoundException($this->translator
->trans('Unable to find location: %id%', ['%id%' => $id])); 
 401                 if ($location !== $this->context
['location']['slug']) { 
 402                         //Redirect on correctly spelled location 
 403                         return $this->redirectToRoute('rapsys_air_location_view', ['id' => $this->context
['location']['id'], 'location' => $this->context
['location']['slug']], Response
::HTTP_MOVED_PERMANENTLY
); 
 407                 $this->context
['calendar'] = $this->doctrine
->getRepository(Session
::class)->findAllByPeriodAsCalendarArray($this->period
, !$this->checker
->isGranted('IS_AUTHENTICATED_REMEMBERED'), $this->context
['location']['latitude'], $this->context
['location']['longitude']); 
 410                 $this->context
['dances'] = []; 
 412                 //Iterate on each calendar 
 413                 foreach($this->context
['calendar'] as $date => $calendar) { 
 414                         //Iterate on each session 
 415                         foreach($calendar['sessions'] as $sessionId => $session) { 
 416                                 //Session with application dance 
 417                                 if (!empty($session['application']['dance'])) { 
 419                                         $this->context
['dances'][$session['application']['dance']['id']] = $session['application']['dance']; 
 424                 //Get locations at less than 2 km 
 425                 $this->context
['locations'] = $this->doctrine
->getRepository(Location
::class)->findAllByLatitudeLongitudeAsArray($this->context
['location']['latitude'], $this->context
['location']['longitude'], $this->period
, 2); 
 428                 //XXX: dance modified is already computed inside calendar modified 
 429                 $this->modified 
= max(array_merge([$this->context
['location']['updated']], array_map(function ($v) { return $v
['modified']; }, array_merge($this->context
['calendar'], $this->context
['locations'])))); 
 432                 $response = new Response(); 
 435                 if ($this->checker
->isGranted('IS_AUTHENTICATED_REMEMBERED')) { 
 437                         $response->setLastModified(new \
DateTime('-1 year')); 
 440                         $response->setPrivate(); 
 441                 //Without logged user 
 444                         //XXX: only for public to force revalidation by last modified 
 445                         $response->setEtag(md5(serialize(array_merge($this->context
['location'], $this->context
['calendar'], $this->context
['locations'])))); 
 448                         $response->setLastModified($this->modified
); 
 451                         $response->setPublic(); 
 453                         //Without role and modification 
 454                         if ($response->isNotModified($request)) { 
 455                                 //Return 304 response 
 461                 $this->context
['multimap'] = $this->map
->getMultiMap($this->context
['location']['multimap'], $this->modified
->getTimestamp(), $this->context
['locations']); 
 464                 $this->context
['keywords'] = [ 
 465                         $this->context
['location']['title'], 
 466                         $this->context
['location']['city']['title'], 
 467                         $this->translator
->trans($this->context
['location']['indoor']?'Indoor':'Outdoor'), 
 468                         $this->translator
->trans('Calendar'), 
 469                         $this->translator
->trans('Libre Air') 
 473                 if (!empty($this->context
['dances'])) { 
 475                         $dances = array_map(function ($v) { return $v
['name']; }, $this->context
['dances']); 
 477                         //Insert dances in keywords 
 478                         array_splice($this->context
['keywords'], 2, 0, $dances); 
 481                         $dances = implode($this->translator
->trans(' and '), array_filter(array_merge([implode(', ', array_slice($dances, 0, -1))], array_slice($dances, -1)), 'strlen')); 
 484                         $this->context
['title']['page'] = $this->translator
->trans('%dances% %location%', ['%dances%' => $dances, '%location%' => $this->context
['location']['atin']]); 
 487                         $this->context
['description'] = $this->translator
->trans('%dances% indoor and outdoor calendar %location%', ['%dances%' => $dances, '%location%' => $this->context
['location']['at']]); 
 491                         $this->context
['title']['page'] = $this->translator
->trans('Dance %location%', ['%location%' => $this->context
['location']['atin']]); 
 494                         $this->context
['description'] = $this->translator
->trans('Indoor and outdoor dance calendar %location%', ['%location%' => $this->context
['location']['at']]); 
 497                 //Set locations description 
 498                 $this->context
['locations_description'] = $this->translator
->trans('Libre Air location list %location% %city%', ['%location%' => $this->context
['location']['around'], '%city%' => $this->context
['location']['city']['in']]); 
 501                 $this->context
['locations_link'] = $this->context
['location']['city']['link']; 
 503                 //Set locations title 
 504                 $this->context
['locations_title'] = $this->context
['location']['city']['title'].' ('.$this->context
['location']['city']['id'].')'; 
 507                 $this->context
['alternates'] +
= $this->context
['location']['alternates']; 
 510                 return $this->render('@RapsysAir/location/view.html.twig', $this->context
, $response);