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 Doctrine\ORM\EntityManagerInterface
; 
  15 use Doctrine\Persistence\ManagerRegistry
; 
  16 use Psr\Log\LoggerInterface
; 
  17 use Symfony\Bundle\FrameworkBundle\Controller\AbstractController 
as BaseAbstractController
; 
  18 use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface
; 
  19 use Symfony\Component\Asset\PackageInterface
; 
  20 use Symfony\Component\DependencyInjection\ContainerInterface
; 
  21 use Symfony\Component\Filesystem\Exception\IOExceptionInterface
; 
  22 use Symfony\Component\Filesystem\Filesystem
; 
  23 use Symfony\Component\Form\FormFactoryInterface
; 
  24 use Symfony\Component\HttpFoundation\RequestStack
; 
  25 use Symfony\Component\HttpFoundation\Response
; 
  26 use Symfony\Component\Mailer\MailerInterface
; 
  27 use Symfony\Component\Routing\Generator\UrlGeneratorInterface
; 
  28 use Symfony\Component\Routing\RouterInterface
; 
  29 use Symfony\Component\Security\Core\Authorization\AccessDecisionManagerInterface
; 
  30 use Symfony\Contracts\Translation\TranslatorInterface
; 
  31 use Symfony\Contracts\Service\ServiceSubscriberInterface
; 
  33 use Rapsys\AirBundle\Entity\Dance
; 
  34 use Rapsys\AirBundle\Entity\Location
; 
  35 use Rapsys\AirBundle\Entity\Slot
; 
  36 use Rapsys\AirBundle\Entity\User
; 
  37 use Rapsys\AirBundle\RapsysAirBundle
; 
  39 use Rapsys\PackBundle\Util\FacebookUtil
; 
  40 use Rapsys\PackBundle\Util\ImageUtil
; 
  41 use Rapsys\PackBundle\Util\MapUtil
; 
  42 use Rapsys\PackBundle\Util\SluggerUtil
; 
  45  * Provides common features needed in controllers. 
  49 abstract class AbstractController 
extends BaseAbstractController 
implements ServiceSubscriberInterface 
{ 
  50         ///AuthorizationCheckerInterface instance 
  56         ///ContainerInterface instance 
  62         ///AccessDecisionManagerInterface instance 
  65         ///ManagerRegistry instance 
  68         ///FacebookUtil instance 
  71         ///FormFactoryInterface instance 
  74         ///Image util instance 
  80         ///MailerInterface instance 
  83         ///EntityManagerInterface instance 
  92         ///PackageInterface instance 
  95         ///DatePeriod instance 
 104         ///Route params array 
 105         protected $routeParams; 
 110         ///Slugger util instance 
 113         ///RequestStack instance 
 116         ///Translator instance 
 117         protected $translator; 
 120          * Abstract constructor 
 122          * @param AuthorizationCheckerInterface $checker The container instance 
 123          * @param ContainerInterface $container The container instance 
 124          * @param AccessDecisionManagerInterface $decision The decision instance 
 125          * @param ManagerRegistry $doctrine The doctrine instance 
 126          * @param FacebookUtil $facebook The facebook instance 
 127          * @param FormFactoryInterface $factory The factory instance 
 128          * @param ImageUtil $image The image instance 
 129          * @param MailerInterface $mailer The mailer instance 
 130          * @param EntityManagerInterface $manager The manager instance 
 131          * @param MapUtil $map The map instance 
 132          * @param PackageInterface $package The package instance 
 133          * @param RouterInterface $router The router instance 
 134          * @param SluggerUtil $slugger The slugger instance 
 135          * @param RequestStack $stack The stack instance 
 136          * @param TranslatorInterface $translator The translator instance 
 138          * @TODO move all that stuff to setSlugger('@slugger') setters with a calls: [ setSlugger: [ '@slugger' ] ] to unbload classes ??? 
 139          * @TODO add a calls: [ ..., prepare: ['@???'] ] that do all the logic that can't be done in constructor because various things are not available 
 141         public function __construct(AuthorizationCheckerInterface 
$checker, ContainerInterface 
$container, AccessDecisionManagerInterface 
$decision, ManagerRegistry 
$doctrine, FacebookUtil 
$facebook, FormFactoryInterface 
$factory, ImageUtil 
$image, MailerInterface 
$mailer, EntityManagerInterface 
$manager, MapUtil 
$map, PackageInterface 
$package, RouterInterface 
$router, SluggerUtil 
$slugger, RequestStack 
$stack, TranslatorInterface 
$translator) { 
 143                 $this->checker 
= $checker; 
 146                 $this->config 
= $container->getParameter(RapsysAirBundle
::getAlias()); 
 149                 $this->container 
= $container; 
 152                 $this->decision 
= $decision; 
 155                 $this->doctrine 
= $doctrine; 
 158                 $this->facebook 
= $facebook; 
 161                 $this->factory 
= $factory; 
 164                 $this->image 
= $image; 
 167                 $this->mailer 
= $mailer; 
 170                 $this->manager 
= $manager; 
 176                 $this->package 
= $package; 
 179                 $this->period 
= new \
DatePeriod( 
 180                         //Start from first monday of week 
 181                         new \
DateTime('Monday this week'), 
 182                         //Iterate on each day 
 183                         new \
DateInterval('P1D'), 
 184                         //End with next sunday and 4 weeks 
 185                         //XXX: we can't use isGranted here as AuthenticatedVoter deny access because user is likely not authenticated yet :'( 
 186                         new \
DateTime('Monday this week + 2 week') 
 191                 $this->router 
= $router; 
 194                 $this->slugger 
= $slugger; 
 197                 $this->stack 
= $stack; 
 200                 $this->translator 
= $translator; 
 203                 $this->request 
= $this->stack
->getMainRequest(); 
 206                 $this->locale 
= $this->request
->getLocale(); 
 215                 //TODO: default to not found route ??? 
 216                 //TODO: pour une url not found, cet attribut n'est pas défini, comment on fait ??? 
 217                 //XXX: on génère une route bidon par défaut ??? 
 218                 $this->route 
= $this->request
->attributes
->get('_route'); 
 221                 $this->routeParams 
= $this->request
->attributes
->get('_route_params'); 
 223                 //With route and routeParams 
 224                 if ($this->route 
!== null && $this->routeParams 
!== null) { 
 226                         $canonical = $this->router
->generate($this->route
, $this->routeParams
, UrlGeneratorInterface
::ABSOLUTE_URL
); 
 230                                 substr($this->locale
, 0, 2) => [ 
 231                                         'absolute' => $canonical 
 238                         'description' => null, 
 241                         'locale' => str_replace('_', '-', $this->locale
), 
 243                                 'title' => $this->translator
->trans($this->config
['contact']['title']), 
 244                                 'mail' => $this->config
['contact']['mail'] 
 247                                 'by' => $this->translator
->trans($this->config
['copy']['by']), 
 248                                 'link' => $this->config
['copy']['link'], 
 249                                 'long' => $this->translator
->trans($this->config
['copy']['long']), 
 250                                 'short' => $this->translator
->trans($this->config
['copy']['short']), 
 251                                 'title' => $this->config
['copy']['title'] 
 254                                 'donate' => $this->config
['site']['donate'], 
 255                                 'icon' => $this->config
['site']['icon'], 
 256                                 'logo' => $this->config
['site']['logo'], 
 257                                 'png' => $this->config
['site']['png'], 
 258                                 'title' => $title = $this->translator
->trans($this->config
['site']['title']), 
 259                                 'url' => $this->router
->generate($this->config
['site']['url']) 
 261                         'canonical' => $canonical, 
 262                         'alternates' => $alternates, 
 265                                         'og:type' => 'article', 
 266                                         'og:site_name' => $title, 
 267                                         'og:url' => $canonical, 
 268                                         #'fb:admins' => $this->config['facebook']['admins'], 
 269                                         'fb:app_id' => $this->config
['facebook']['apps'] 
 272                                         $this->translator
->trans($this->config
['site']['title']) => [ 
 273                                                 'font' => 'irishgrover', 
 287         protected function render(string $view, array $parameters = [], Response 
$response = null): Response 
{ 
 288                 //Create application form for role_guest 
 289                 if ($this->isGranted('ROLE_GUEST')) { 
 290                         //Without application form 
 291                         if (empty($parameters['forms']['application'])) { 
 292                                 //Get favorites dances 
 293                                 $danceFavorites = $this->doctrine
->getRepository(Dance
::class)->findByUserId($this->getUser()->getId()); 
 296                                 $danceDefault = !empty($danceFavorites)?current($danceFavorites):null; 
 298                                 //Get favorites locations 
 299                                 $locationFavorites = $this->doctrine
->getRepository(Location
::class)->findByUserId($this->getUser()->getId()); 
 301                                 //Set location default 
 302                                 $locationDefault = !empty($locationFavorites)?current($locationFavorites):null; 
 305                                 if ($this->checker
->isGranted('ROLE_ADMIN')) { 
 307                                         $dances = $this->doctrine
->getRepository(Dance
::class)->findAll(); 
 310                                         $locations = $this->doctrine
->getRepository(Location
::class)->findAll(); 
 313                                         //Restrict to favorite dances 
 314                                         $dances = $danceFavorites; 
 317                                         $danceFavorites = []; 
 319                                         //Restrict to favorite locations 
 320                                         $locations = $locationFavorites; 
 323                                         $locationFavorites = []; 
 326                                 //With session application dance id 
 327                                 if (!empty($parameters['session']['application']['dance']['id'])) { 
 328                                         //Iterate on each dance 
 329                                         foreach($dances as $dance) { 
 331                                                 if ($dance->getId() == $parameters['session']['application']['dance']['id']) { 
 332                                                         //Set dance as default 
 333                                                         $danceDefault = $dance; 
 341                                 //With session location id 
 342                                 //XXX: set in session controller 
 343                                 //TODO: with new findAll that key by id, it should be as simple as isset($locations[$id]) ? 
 344                                 if (!empty($parameters['session']['location']['id'])) { 
 345                                         //Iterate on each location 
 346                                         foreach($locations as $location) { 
 348                                                 if ($location->getId() == $parameters['session']['location']['id']) { 
 349                                                         //Set location as default 
 350                                                         $locationDefault = $location; 
 358                                 //Create ApplicationType form 
 359                                 $application = $this->createForm('Rapsys\AirBundle\Form\ApplicationType', null, [ 
 361                                         'action' => $this->generateUrl('rapsys_air_application_add'), 
 362                                         //Set the form attribute 
 363                                         'attr' => [ 'class' => 'col' ], 
 365                                         'dance_choices' => $dances, 
 367                                         'dance_default' => $danceDefault, 
 368                                         //Set dance favorites 
 369                                         'dance_favorites' => $danceFavorites, 
 370                                         //Set location choices 
 371                                         'location_choices' => $locations, 
 372                                         //Set location default 
 373                                         'location_default' => $locationDefault, 
 374                                         //Set location favorites 
 375                                         'location_favorites' => $locationFavorites, 
 377                                         'user' => $this->checker
->isGranted('ROLE_ADMIN'), 
 379                                         'user_choices' => $this->doctrine
->getRepository(User
::class)->findIndexByGroupPseudonym(), 
 380                                         //Set default user to current 
 381                                         'user_default' => $this->getUser()->getId(), 
 382                                         //Set to session slot or evening by default 
 383                                         //XXX: default to Evening (3) 
 384                                         'slot_default' => $this->doctrine
->getRepository(Slot
::class)->findOneById($parameters['session']['slot']['id']??3) 
 387                                 //Add form to context 
 388                                 $parameters['forms']['application'] = $application->createView(); 
 391                 #XXX: removed because it fucks up the seo by displaying register and login form instead of content 
 392                 #XXX: until we find a better way, removed !!! 
 393                 //Create login form for anonymous 
 394                 elseif (!$this->checker->isGranted('IS_AUTHENTICATED_REMEMBERED')) { 
 395                         //Create LoginType form 
 396                         $login = $this->createForm('Rapsys\UserBundle\Form\LoginType', null, [ 
 398                                 'action' => $this->generateUrl('rapsys_user_login'), 
 399                                 //Disable password repeated 
 400                                 'password_repeated' => false, 
 401                                 //Set the form attribute 
 402                                 'attr' => [ 'class' => 'col' ] 
 405                         //Add form to context 
 406                         $parameters['forms']['login'] = $login->createView(); 
 415                                 'pseudonym' => false, 
 428                         //Create RegisterType form 
 429                         $register = $this->createForm('Rapsys\AirBundle\Form\RegisterType', null, $field+[ 
 431                                 'action' => $this->generateUrl( 
 432                                         'rapsys_user_register', 
 434                                                 'mail' => $smail = $this->slugger->short(''), 
 435                                                 'field' => $sfield = $this->slugger->serialize($field), 
 436                                                 'hash' => $this->slugger->hash($smail.$sfield) 
 439                                 //Set the form attribute 
 440                                 'attr' => [ 'class' => 'col' ] 
 443                         //Add form to context 
 444                         $parameters['forms']['register'] = $register->createView(); 
 448                 if (count($parameters['alternates']) <= 1) { 
 450                         $routeParams = $this->routeParams
; 
 452                         //Iterate on locales excluding current one 
 453                         foreach($this->config
['locales'] as $locale) { 
 454                                 //With current locale 
 455                                 if ($locale !== $this->locale
) { 
 459                                         //Set route params locale 
 460                                         $routeParams['_locale'] = $locale; 
 462                                         //Iterate on other locales 
 463                                         foreach(array_diff($this->config
['locales'], [$locale]) as $other) { 
 464                                                 //Set other locale title 
 465                                                 $titles[$other] = $this->translator
->trans($this->config
['languages'][$locale], [], null, $other); 
 468                                         //Set locale locales context 
 469                                         $parameters['alternates'][str_replace('_', '-', $locale)] = [ 
 470                                                 'absolute' => $this->router
->generate($this->route
, $routeParams, UrlGeneratorInterface
::ABSOLUTE_URL
), 
 471                                                 'relative' => $this->router
->generate($this->route
, $routeParams), 
 472                                                 'title' => implode('/', $titles), 
 473                                                 'translated' => $this->translator
->trans($this->config
['languages'][$locale], [], null, $locale) 
 477                                         if (empty($parameters['alternates'][$shortCurrent = substr($locale, 0, 2)])) { 
 478                                                 //Set locale locales context 
 479                                                 $parameters['alternates'][$shortCurrent] = $parameters['alternates'][str_replace('_', '-', $locale)]; 
 485                 //With page infos and without facebook texts 
 486                 if (count($parameters['facebook']['texts']) <= 1 && isset($parameters['title']) && isset($this->route
) && isset($this->routeParams
)) { 
 487                         //Append facebook image texts 
 488                         $parameters['facebook']['texts'] +
= [ 
 489                                 $parameters['title'] => [ 
 490                                         'font' => 'irishgrover', 
 492                                 ]/*XXX: same problem as url, too long :'(, 
 493                                 $parameters['description'] => [ 
 496                                         'font' => 'labelleaurore', 
 501                         /*With short path info 
 502                         We don't add this stupid url in image !!! 
 503                         if (strlen($pathInfo = $this->router->generate($this->route, $this->routeParams)) <= 64) { 
 507                                         'font' => 'labelleaurore', 
 513                 //With empty locations link 
 514                 if (empty($parameters['locations_link'])) { 
 516                         $parameters['locations_link'] = $this->router
->generate('rapsys_air_location'); 
 519                 //With empty locations title 
 520                 if (empty($parameters['locations_title'])) { 
 521                         //Set locations title 
 522                         $parameters['locations_title'] = $this->translator
->trans('Locations', [], null, $this->locale
); 
 526                 if (!empty($parameters['canonical'])) { 
 528                         $parameters['facebook']['metas']['og:url'] = $parameters['canonical']; 
 531                 //With empty facebook title and title 
 532                 if (empty($parameters['facebook']['metas']['og:title']) && !empty($parameters['title'])) { 
 534                         $parameters['facebook']['metas']['og:title'] = $parameters['title']; 
 537                 //With empty facebook description and description 
 538                 if (empty($parameters['facebook']['metas']['og:description']) && !empty($parameters['description'])) { 
 539                         //Set facebook description 
 540                         $parameters['facebook']['metas']['og:description'] = $parameters['description']; 
 544                 if (!empty($this->locale
)) { 
 545                         //Set facebook locale 
 546                         $parameters['facebook']['metas']['og:locale'] = $this->locale
; 
 549                         //XXX: locale change when fb_locale=xx_xx is provided is done in FacebookSubscriber 
 550                         //XXX: see https://stackoverflow.com/questions/20827882/in-open-graph-markup-whats-the-use-of-oglocalealternate-without-the-locati 
 551                         if (!empty($parameters['alternates'])) { 
 552                                 //Iterate on alternates 
 553                                 foreach($parameters['alternates'] as $lang => $alternate) { 
 554                                         if (strlen($lang) == 5) { 
 555                                                 //Set facebook locale alternate 
 556                                                 $parameters['facebook']['metas']['og:locale:alternate'] = str_replace('-', '_', $lang); 
 562                 //Without facebook image defined and texts 
 563                 if (empty($parameters['facebook']['metas']['og:image']) && !empty($this->request
) && !empty($parameters['facebook']['texts']) && !empty($this->modified
)) { 
 565                         $parameters['facebook']['metas'] +
= $this->facebook
->getImage($this->request
->getPathInfo(), $parameters['facebook']['texts'], $this->modified
->getTimestamp()); 
 569                 return parent
::render($view, $parameters, $response); 
 575          * @see vendor/symfony/framework-bundle/Controller/AbstractController.php 
 577         public static function getSubscribedServices(): array { 
 578                 //Return subscribed services 
 580                         'doctrine' => ManagerRegistry
::class, 
 581                         'doctrine.orm.default_entity_manager' => EntityManagerInterface
::class, 
 582                         'form.factory' => FormFactoryInterface
::class, 
 583                         'mailer.mailer' => MailerInterface
::class, 
 584                         'rapsys_air.facebook_util' => FacebookUtil
::class, 
 585                         'rapsys_pack.image_util' => ImageUtil
::class, 
 586                         'rapsys_pack.map_util' => MapUtil
::class, 
 587                         'rapsys_pack.path_package' => PackageInterface
::class, 
 588                         'rapsys_pack.slugger_util' => SluggerUtil
::class, 
 589                         'rapsys_user.access_decision_manager' => AccessDecisionManagerInterface
::class, 
 590                         'request_stack' => RequestStack
::class, 
 591                         'router' => RouterInterface
::class, 
 592                         'security.authorization_checker' => AuthorizationCheckerInterface
::class, 
 593                         'service_container' => ContainerInterface
::class, 
 594                         'translator' => TranslatorInterface
::class