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
); 
  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->osm->getMultiImage($city['link'], $city['osm'], $this->modified->getTimestamp(), $city['latitude'], $city['longitude'], $city['locations'], $this->osm->getMultiZoom($city['latitude'], $city['longitude'], $city['locations'], 16)); 
  48                         $this->context
['cities'][$id]['multimap'] = $this->map
->getMultiMap($city['multimap'], $this->modified
->getTimestamp(), $city['latitude'], $city['longitude'], $city['locations'], $this->map
->getMultiZoom($city['latitude'], $city['longitude'], $city['locations'])); 
  52                 if ($this->isGranted('IS_AUTHENTICATED_REMEMBERED')) { 
  54                         $response->setLastModified(new \
DateTime('-1 year')); 
  57                         $response->setPrivate(); 
  61                         //XXX: only for public to force revalidation by last modified 
  62                         $response->setEtag(md5(serialize(array_merge($this->context
['cities'], $this->context
['dances'])))); 
  65                         $response->setLastModified($this->modified
); 
  68                         $response->setPublic(); 
  70                         //Without role and modification 
  71                         if ($response->isNotModified($request)) { 
  78                 $this->context
['title'] = $this->translator
->trans('Libre Air cities'); 
  81                 $this->context
['description'] = $this->translator
->trans('Libre Air city list'); 
  84                 $cities = array_map(function ($v) { return $v
['in']; }, $this->context
['cities']); 
  87                 $dances = array_map(function ($v) { return $v
['name']; }, $this->context
['dances']); 
  90                 $indoors = array_reduce($this->context
['cities'], function ($c, $v) { return array_merge($c
, $v
['indoors']); }, []); 
  93                 $this->context
['keywords'] = array_values( 
  96                                         $this->translator
->trans('Cities'), 
  97                                         $this->translator
->trans('City list'), 
  98                                         $this->translator
->trans('Listing'), 
 103                                         $this->translator
->trans('calendar'), 
 104                                         $this->translator
->trans('Libre Air') 
 110                 return $this->render('@RapsysAir/location/cities.html.twig', $this->context
, $response); 
 116          * @todo XXX: TODO: add <link rel="prev|next" for sessions or classes ? /> 
 117          * @todo XXX: TODO: like described in: https://www.alsacreations.com/article/lire/1400-attribut-rel-relations.html#xnf-rel-attribute 
 118          * @todo XXX: TODO: or here: http://microformats.org/wiki/existing-rel-values#HTML5_link_type_extensions 
 120          * @param Request $request The request instance 
 121          * @param float $latitude The city latitude 
 122          * @param float $longitude The city longitude 
 123          * @return Response The rendered view 
 125         public function city(Request 
$request, float $latitude, float $longitude, string $city): Response 
{ 
 127                 if (!($this->context
['city'] = $this->doctrine
->getRepository(Location
::class)->findCityByLatitudeLongitudeAsArray(floatval($latitude), floatval($longitude)))) { 
 128                         throw $this->createNotFoundException($this->translator
->trans('Unable to find city: %latitude%,%longitude%', ['%latitude%' => $latitude, '%longitude%' => $longitude])); 
 132                 $this->context
['calendar'] = $this->doctrine
->getRepository(Session
::class)->findAllByPeriodAsArray($this->period
, $request->getLocale(), !$this->isGranted('IS_AUTHENTICATED_REMEMBERED'), floatval($latitude), floatval($longitude)); 
 135                 $this->context
['dances'] = []; 
 137                 //Iterate on each calendar 
 138                 foreach($this->context
['calendar'] as $date => $calendar) { 
 139                         //Iterate on each session 
 140                         foreach($calendar['sessions'] as $sessionId => $session) { 
 141                                 //Session with application dance 
 142                                 if (!empty($session['application']['dance'])) { 
 144                                         $this->context
['dances'][$session['application']['dance']['id']] = $session['application']['dance']; 
 150                 $this->context
['locations'] = $this->doctrine
->getRepository(Location
::class)->findAllByLatitudeLongitudeAsArray(floatval($latitude), floatval($longitude), $this->period
); 
 153                 //XXX: dance modified is already computed inside calendar modified 
 154                 $this->modified 
= max(array_merge([$this->context
['city']['updated']], array_map(function ($v) { return $v
['modified']; }, array_merge($this->context
['calendar'], $this->context
['locations'])))); 
 157                 $response = new Response(); 
 160                 if ($this->isGranted('IS_AUTHENTICATED_REMEMBERED')) { 
 162                         $response->setLastModified(new \
DateTime('-1 year')); 
 165                         $response->setPrivate(); 
 166                 //Without logged user 
 169                         //XXX: only for public to force revalidation by last modified 
 170                         $response->setEtag(md5(serialize(array_merge($this->context
['city'], $this->context
['dances'], $this->context
['calendar'], $this->context
['locations'])))); 
 173                         $response->setLastModified($this->modified
); 
 176                         $response->setPublic(); 
 178                         //Without role and modification 
 179                         if ($response->isNotModified($request)) { 
 180                                 //Return 304 response 
 186                 $this->context
['multimap'] = $this->map
->getMultiMap($this->context
['city']['multimap'], $this->modified
->getTimestamp(), $latitude, $longitude, $this->context
['locations'], $this->map
->getMultiZoom($latitude, $longitude, $this->context
['locations'])); 
 189                 $this->context
['keywords'] = [ 
 190                         $this->context
['city']['city'], 
 191                         $this->translator
->trans('Indoor'), 
 192                         $this->translator
->trans('Outdoor'), 
 193                         $this->translator
->trans('Calendar'), 
 194                         $this->translator
->trans('Libre Air') 
 197                 //With context dances 
 198                 if (!empty($this->context
['dances'])) { 
 200                         $dances = array_map(function ($v) { return $v
['name']; }, $this->context
['dances']); 
 202                         //Insert dances in keywords 
 203                         array_splice($this->context
['keywords'], 1, 0, $dances); 
 206                         $dances = implode($this->translator
->trans(' and '), array_filter(array_merge([implode(', ', array_slice($dances, 0, -1))], array_slice($dances, -1)), 'strlen')); 
 209                         $this->context
['title'] = $this->translator
->trans('%dances% %city%', ['%dances%' => $dances, '%city%' => $this->context
['city']['in']]); 
 212                         $this->context
['description'] = $this->translator
->trans('%dances% indoor and outdoor calendar %city%', ['%dances%' => $dances, '%city%' => $this->context
['city']['in']]); 
 215                         $this->context
['title'] = $this->translator
->trans('Dance %city%', ['%city%' => $this->context
['city']['in']]); 
 218                         $this->context
['description'] = $this->translator
->trans('Indoor and outdoor dance calendar %city%', ['%city%' => $this->context
['city']['in']]); 
 221                 //Set locations description 
 222                 $this->context
['locations_description'] = $this->translator
->trans('Libre Air location list %city%', ['%city%' => $this->context
['city']['in']]); 
 225                 return $this->render('@RapsysAir/location/city.html.twig', $this->context
, $response); 
 231          * @desc Display all locations 
 233          * @param Request $request The request instance 
 235          * @return Response The rendered view 
 237         public function index(Request 
$request): Response 
{ 
 239                 $this->context
['locations'] = $this->doctrine
->getRepository(Location
::class)->findAllAsArray($this->period
); 
 242                 $this->modified 
= max(array_map(function ($v) { return $v
['updated']; }, $this->context
['locations'])); 
 245                 $response = new Response(); 
 248                 if ($this->isGranted('IS_AUTHENTICATED_REMEMBERED')) { 
 250                         $response->setLastModified(new \
DateTime('-1 year')); 
 253                         $response->setPrivate(); 
 254                 //Without logged user 
 257                         //XXX: only for public to force revalidation by last modified 
 258                         $response->setEtag(md5(serialize($this->context
['locations']))); 
 261                         $response->setLastModified($this->modified
); 
 264                         $response->setPublic(); 
 266                         //Without role and modification 
 267                         if ($response->isNotModified($request)) { 
 268                                 //Return 304 response 
 274                 $latitudes = array_map(function ($v) { return $v
['latitude']; }, $this->context
['locations']); 
 277                 $latitude = round(array_sum($latitudes)/count($latitudes), 6); 
 280                 $longitudes = array_map(function ($v) { return $v
['longitude']; }, $this->context
['locations']); 
 283                 $longitude = round(array_sum($longitudes)/count($longitudes), 6); 
 286                 $this->context
['multimap'] = $this->map
->getMultiMap($this->translator
->trans('Libre Air locations sector map'), $this->modified
->getTimestamp(), $latitude, $longitude, $this->context
['locations'], $this->map
->getMultiZoom($latitude, $longitude, $this->context
['locations'])); 
 289                 $this->context
['title'] = $this->translator
->trans('Libre Air locations'); 
 292                 $this->context
['description'] = $this->translator
->trans('Libre Air location list'); 
 295                 $this->context
['keywords'] = [ 
 296                         $this->translator
->trans('locations'), 
 297                         $this->translator
->trans('location list'), 
 298                         $this->translator
->trans('listing'), 
 299                         $this->translator
->trans('Libre Air') 
 302                 //Create location forms for role_admin 
 303                 if ($this->isGranted('ROLE_ADMIN')) { 
 304                         //Fetch all locations 
 305                         $locations = $this->doctrine
->getRepository(Location
::class)->findAll(); 
 307                         //Init locations to context 
 308                         $this->context
['forms']['locations'] = []; 
 310                         //Iterate on locations 
 311                         foreach($this->context
['locations'] as $id => $location) { 
 312                                 //Create LocationType form 
 313                                 $form = $this->factory
->createNamed( 
 317                                         'Rapsys\AirBundle\Form\LocationType', 
 319                                         $locations[$location['id']], 
 320                                         //Set the form attributes 
 324                                 //Refill the fields in case of invalid form 
 325                                 $form->handleRequest($request); 
 328                                 if ($form->isSubmitted() && $form->isValid()) { 
 330                                         $data = $form->getData(); 
 333                                         $data->setUpdated(new \
DateTime('now')); 
 335                                         //Queue location save 
 336                                         $this->manager
->persist($data); 
 338                                         //Flush to get the ids 
 339                                         $this->manager
->flush(); 
 342                                         $this->addFlash('notice', $this->translator
->trans('Location %id% updated', ['%id%' => $location['id']])); 
 344                                         //Redirect to cleanup the form 
 345                                         return $this->redirectToRoute('rapsys_air_location', ['location' => $location['id']]); 
 348                                 //Add form to context 
 349                                 $this->context
['forms']['locations'][$id] = $form->createView(); 
 352                         //Create LocationType form 
 353                         $form = $this->factory
->createNamed( 
 357                                 'Rapsys\AirBundle\Form\LocationType', 
 360                                 //Set the form attributes 
 361                                 ['attr' => ['class' => 'col']] 
 364                         //Refill the fields in case of invalid form 
 365                         $form->handleRequest($request); 
 368                         if ($form->isSubmitted() && $form->isValid()) { 
 370                                 $data = $form->getData(); 
 372                                 //Queue location save 
 373                                 $this->manager
->persist($data); 
 375                                 //Flush to get the ids 
 376                                 $this->manager
->flush(); 
 379                                 $this->addFlash('notice', $this->translator
->trans('Location created')); 
 381                                 //Redirect to cleanup the form 
 382                                 return $this->redirectToRoute('rapsys_air_location', ['location' => $data->getId()]); 
 385                         //Add form to context 
 386                         $this->context
['forms']['location'] = $form->createView(); 
 390                 return $this->render('@RapsysAir/location/index.html.twig', $this->context
); 
 394          * List all sessions for the location 
 396          * Display all sessions for the location with an application or login form 
 398          * @TODO: add location edit form ??? 
 400          * @param Request $request The request instance 
 401          * @param int $id The location id 
 403          * @return Response The rendered view 
 405         public function view(Request 
$request, int $id): Response 
{ 
 407                 if (empty($this->context
['location'] = $this->doctrine
->getRepository(Location
::class)->findOneByIdAsArray($id, $this->locale
))) { 
 409                         throw $this->createNotFoundException($this->translator
->trans('Unable to find location: %id%', ['%id%' => $id])); 
 413                 $this->context
['calendar'] = $this->doctrine
->getRepository(Session
::class)->findAllByPeriodAsArray($this->period
, $this->locale
, !$this->isGranted('IS_AUTHENTICATED_REMEMBERED'), $this->context
['location']['latitude'], $this->context
['location']['longitude']); 
 416                 $this->context
['dances'] = []; 
 418                 //Iterate on each calendar 
 419                 foreach($this->context
['calendar'] as $date => $calendar) { 
 420                         //Iterate on each session 
 421                         foreach($calendar['sessions'] as $sessionId => $session) { 
 422                                 //Session with application dance 
 423                                 if (!empty($session['application']['dance'])) { 
 425                                         $this->context
['dances'][$session['application']['dance']['id']] = $session['application']['dance']; 
 430                 //Get locations at less than 2 km 
 431                 $this->context
['locations'] = $this->doctrine
->getRepository(Location
::class)->findAllByLatitudeLongitudeAsArray($this->context
['location']['latitude'], $this->context
['location']['longitude'], $this->period
, 2); 
 434                 //XXX: dance modified is already computed inside calendar modified 
 435                 $this->modified 
= max(array_merge([$this->context
['location']['updated']], array_map(function ($v) { return $v
['modified']; }, array_merge($this->context
['calendar'], $this->context
['locations'])))); 
 438                 $response = new Response(); 
 441                 if ($this->isGranted('IS_AUTHENTICATED_REMEMBERED')) { 
 443                         $response->setLastModified(new \
DateTime('-1 year')); 
 446                         $response->setPrivate(); 
 447                 //Without logged user 
 450                         //XXX: only for public to force revalidation by last modified 
 451                         $response->setEtag(md5(serialize(array_merge($this->context
['location'], $this->context
['calendar'], $this->context
['locations'])))); 
 454                         $response->setLastModified($this->modified
); 
 457                         $response->setPublic(); 
 459                         //Without role and modification 
 460                         if ($response->isNotModified($request)) { 
 461                                 //Return 304 response 
 467                 $this->context
['multimap'] = $this->map
->getMultiMap($this->context
['location']['multimap'], $this->modified
->getTimestamp(), $this->context
['location']['latitude'], $this->context
['location']['longitude'], $this->context
['locations'], $this->map
->getMultiZoom($this->context
['location']['latitude'], $this->context
['location']['longitude'], $this->context
['locations'])); 
 470                 $this->context
['keywords'] = [ 
 471                         $this->context
['location']['title'], 
 472                         $this->context
['location']['city'], 
 473                         $this->translator
->trans($this->context
['location']['indoor']?'Indoor':'Outdoor'), 
 474                         $this->translator
->trans('Calendar'), 
 475                         $this->translator
->trans('Libre Air') 
 479                 if (!empty($this->context
['dances'])) { 
 481                         $dances = array_map(function ($v) { return $v
['name']; }, $this->context
['dances']); 
 483                         //Insert dances in keywords 
 484                         array_splice($this->context
['keywords'], 2, 0, $dances); 
 487                         $dances = implode($this->translator
->trans(' and '), array_filter(array_merge([implode(', ', array_slice($dances, 0, -1))], array_slice($dances, -1)), 'strlen')); 
 490                         $this->context
['title'] = $this->translator
->trans('%dances% %location%', ['%dances%' => $dances, '%location%' => $this->context
['location']['atin']]); 
 493                         $this->context
['description'] = $this->translator
->trans('%dances% indoor and outdoor calendar %location%', ['%dances%' => $dances, '%location%' => $this->context
['location']['at']]); 
 497                         $this->context
['title'] = $this->translator
->trans('Dance %location%', ['%location%' => $this->context
['location']['atin']]); 
 500                         $this->context
['description'] = $this->translator
->trans('Indoor and outdoor dance calendar %location%', [ '%location%' => $this->context
['location']['at'] ]); 
 503                 //Set locations description 
 504                 $this->context
['locations_description'] = $this->translator
->trans('Libre Air location list %location%', ['%location%' => $this->context
['location']['atin']]); 
 507                 $this->context
['alternates'] +
= $this->context
['location']['alternates']; 
 510                 return $this->render('@RapsysAir/location/view.html.twig', $this->context
, $response);