1 <?php 
declare(strict_types
=1); 
   4  * This file is part of the Rapsys BlogBundle 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\BlogBundle\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\Request
; 
  26 use Symfony\Component\HttpFoundation\Response
; 
  27 use Symfony\Component\Mailer\MailerInterface
; 
  28 use Symfony\Component\Routing\Generator\UrlGeneratorInterface
; 
  29 use Symfony\Component\Routing\RouterInterface
; 
  30 use Symfony\Component\Security\Core\Authorization\AccessDecisionManagerInterface
; 
  31 use Symfony\Contracts\Translation\TranslatorInterface
; 
  32 use Symfony\Contracts\Service\ServiceSubscriberInterface
; 
  35 use Rapsys\BlogBundle\Entity\Dance
; 
  36 use Rapsys\BlogBundle\Entity\Location
; 
  37 use Rapsys\BlogBundle\Entity\Slot
; 
  38 use Rapsys\BlogBundle\Entity\User
; 
  39 use Rapsys\BlogBundle\RapsysBlogBundle
; 
  41 use Rapsys\PackBundle\Util\FacebookUtil
; 
  42 use Rapsys\PackBundle\Util\ImageUtil
; 
  43 use Rapsys\PackBundle\Util\SluggerUtil
; 
  46  * Provides common features needed in controllers. 
  50 abstract class AbstractController 
extends BaseAbstractController 
implements ServiceSubscriberInterface 
{ 
  51         ///AuthorizationCheckerInterface instance 
  52         protected AuthorizationCheckerInterface 
$checker; 
  55         protected array $config; 
  58         protected array $context; 
  60         ///AccessDecisionManagerInterface instance 
  61         protected AccessDecisionManagerInterface 
$decision; 
  63         ///ManagerRegistry instance 
  64         protected ManagerRegistry 
$doctrine; 
  66         ///FacebookUtil instance 
  67         protected FacebookUtil 
$facebook; 
  69         ///FormFactoryInterface instance 
  70         protected FormFactoryInterface 
$factory; 
  72         ///Image util instance 
  73         protected ImageUtil 
$image; 
  79         protected string $locale; 
  81         ///MailerInterface instance 
  82         protected MailerInterface 
$mailer; 
  84         ///EntityManagerInterface instance 
  85         protected EntityManagerInterface 
$manager; 
  88         protected \DateTime 
$modified; 
  90         ///PackageInterface instance 
  91         protected PackageInterface 
$package; 
  94         protected Request 
$request; 
  97         protected string $route; 
 100         protected array $routeParams; 
 103         protected RouterInterface 
$router; 
 105         ///Slugger util instance 
 106         protected SluggerUtil 
$slugger; 
 108         ///RequestStack instance 
 109         protected RequestStack 
$stack; 
 111         ///Translator instance 
 112         protected TranslatorInterface 
$translator; 
 114         ///Twig\Environment instance 
 115         protected Environment 
$twig; 
 118          * Abstract constructor 
 120          * @param AuthorizationCheckerInterface $checker The container instance 
 121          * @param ContainerInterface $container The container instance 
 122          * @param AccessDecisionManagerInterface $decision The decision instance 
 123          * @param ManagerRegistry $doctrine The doctrine instance 
 124          * @param FacebookUtil $facebook The facebook instance 
 125          * @param FormFactoryInterface $factory The factory instance 
 126          * @param ImageUtil $image The image instance 
 127          * @param MailerInterface $mailer The mailer instance 
 128          * @param EntityManagerInterface $manager The manager instance 
 129          * @param PackageInterface $package The package instance 
 130          * @param RouterInterface $router The router instance 
 131          * @param SluggerUtil $slugger The slugger instance 
 132          * @param RequestStack $stack The stack instance 
 133          * @param TranslatorInterface $translator The translator instance 
 134          * @param Environment $twig The twig environment instance 
 135          * @param integer $limit The page limit 
 137          * @TODO move all that stuff to setSlugger('@slugger') setters with a calls: [ setSlugger: [ '@slugger' ] ] to unbload classes ??? 
 138          * @TODO add a calls: [ ..., prepare: ['@???'] ] that do all the logic that can't be done in constructor because various things are not available 
 140         public function __construct(AuthorizationCheckerInterface 
$checker, ContainerInterface 
$container, AccessDecisionManagerInterface 
$decision, ManagerRegistry 
$doctrine, FacebookUtil 
$facebook, FormFactoryInterface 
$factory, ImageUtil 
$image, MailerInterface 
$mailer, EntityManagerInterface 
$manager, PackageInterface 
$package, RouterInterface 
$router, SluggerUtil 
$slugger, RequestStack 
$stack, TranslatorInterface 
$translator, Environment 
$twig, int $limit = 5) { 
 142                 $this->checker 
= $checker; 
 145                 $this->config 
= $container->getParameter(RapsysBlogBundle
::getAlias()); 
 148                 $this->container 
= $container; 
 151                 $this->decision 
= $decision; 
 154                 $this->doctrine 
= $doctrine; 
 157                 $this->facebook 
= $facebook; 
 160                 $this->factory 
= $factory; 
 163                 $this->image 
= $image; 
 166                 $this->limit 
= $limit; 
 169                 $this->mailer 
= $mailer; 
 172                 $this->manager 
= $manager; 
 175                 $this->package 
= $package; 
 178                 $this->router 
= $router; 
 181                 $this->slugger 
= $slugger; 
 184                 $this->stack 
= $stack; 
 187                 $this->translator 
= $translator; 
 193                 $this->request 
= $this->stack
->getMainRequest(); 
 196                 $this->locale 
= $this->request
->getLocale(); 
 205                 //TODO: default to not found route ??? 
 206                 //TODO: when url not found, this attribute is not defined, how do we handle it ??? 
 207                 //XXX: do we generate a dummy default route by default ??? 
 208                 $this->route 
= $this->request
->attributes
->get('_route'); 
 211                 $this->routeParams 
= $this->request
->attributes
->get('_route_params'); 
 213                 //With route and routeParams 
 214                 if ($this->route 
!== null && $this->routeParams 
!== null) { 
 216                         $canonical = $this->router
->generate($this->route
, $this->routeParams
, UrlGeneratorInterface
::ABSOLUTE_URL
); 
 224                         //TODO: review the structure 
 225                         #'title' => $this->translator->trans($this->config['title']), 
 226                         #'og:site_name' => $this->translator->trans($this->config['title']), 
 228                         #       'donate' => $this->config['donate'], 
 229                         #       'title' => $title = $this->translator->trans($this->config['site']['title']), 
 232                                 'alternates' => $alternates, 
 233                                 'canonical' => $canonical, 
 234                                 'icon' => $this->config
['icon'], 
 236                                 'locale' => str_replace('_', '-', $this->locale
), 
 238                                         'png' => $this->config
['logo']['png'], 
 239                                         'svg' => $this->config
['logo']['svg'], 
 240                                         'alt' => $this->translator
->trans($this->config
['logo']['alt']) 
 242                                 'root' => $this->config
['root'], 
 245                                                 'og:type' => 'article', 
 246                                                 'og:site_name' => $this->translator
->trans($this->config
['title']), 
 247                                                 'og:url' => $canonical, 
 248                                                 //TODO: review this value 
 249                                                 'fb:app_id' => $this->config
['facebook']['apps'] 
 253                                                 $this->translator
->trans($this->config
['title']) => [ 
 254                                                         'font' => 'irishgrover', 
 261                                 'name' => $this->translator
->trans($this->config
['contact']['name']), 
 262                                 'mail' => $this->config
['contact']['mail'] 
 265                                 'by' => $this->translator
->trans($this->config
['copy']['by']), 
 266                                 'link' => $this->config
['copy']['link'], 
 267                                 'long' => $this->translator
->trans($this->config
['copy']['long']), 
 268                                 'short' => $this->translator
->trans($this->config
['copy']['short']), 
 269                                 'title' => $this->config
['copy']['title'] 
 273                         'description' => null, 
 276                                 'icon' => $this->config
['icon'], 
 278                                         'png' => $this->config
['logo']['png'], 
 279                                         'svg' => $this->config
['logo']['svg'], 
 280                                         'alt' => $this->translator
->trans($this->config
['logo']['alt']) 
 282                                 'path' => $this->config
['path'], 
 283                                 'root' => $this->config
['root'], 
 284                                 'title' => $this->translator
->trans($this->config
['title']) 
 294         protected function render(string $view, array $parameters = [], Response 
$response = null): Response 
{ 
 295                 //Create response when null 
 296         $response ??= new Response(); 
 299                 if (empty($parameters['head']['alternates'])) { 
 300                         //Iterate on locales excluding current one 
 301                         foreach($this->config
['locales'] as $locale) { 
 303                                 $routeParams = $this->routeParams
; 
 305                                 //With current locale 
 306                                 if ($locale !== $this->locale
) { 
 310                                         //Set route params locale 
 311                                         $routeParams['_locale'] = $locale; 
 314                                         //XXX: slug is in current locale, better use a simple redirect for invalid slug than implement a hard to get translation here 
 315                                         unset($routeParams['slug']); 
 317                                         //Iterate on other locales 
 318                                         foreach(array_diff($this->config
['locales'], [$locale]) as $other) { 
 319                                                 //Set other locale title 
 320                                                 $titles[$other] = $this->translator
->trans($this->config
['languages'][$locale], [], null, $other); 
 323                                         //Set locale locales context 
 324                                         $parameters['head']['alternates'][str_replace('_', '-', $locale)] = [ 
 325                                                 'absolute' => $this->router
->generate($this->route
, $routeParams, UrlGeneratorInterface
::ABSOLUTE_URL
), 
 326                                                 'relative' => $this->router
->generate($this->route
, $routeParams), 
 327                                                 'title' => implode('/', $titles), 
 328                                                 'translated' => $this->translator
->trans($this->config
['languages'][$locale], [], null, $locale) 
 332                                         if (empty($parameters['head']['alternates'][$shortCurrent = substr($locale, 0, 2)])) { 
 333                                                 //Set locale locales context 
 334                                                 $parameters['head']['alternates'][$shortCurrent] = $parameters['head']['alternates'][str_replace('_', '-', $locale)]; 
 337                                 } elseif (empty($parameters['head']['alternates'][$shortCurrent = substr($locale, 0, 2)])) { 
 341                                         //Set route params locale 
 342                                         $routeParams['_locale'] = $locale; 
 344                                         //Iterate on other locales 
 345                                         foreach(array_diff($this->config
['locales'], [$locale]) as $other) { 
 346                                                 //Set other locale title 
 347                                                 $titles[$other] = $this->translator
->trans($this->config
['languages'][$locale], [], null, $other); 
 350                                         //Set locale locales context 
 351                                         $parameters['head']['alternates'][$shortCurrent] = [ 
 352                                                 'absolute' => $this->router
->generate($this->route
, $routeParams, UrlGeneratorInterface
::ABSOLUTE_URL
), 
 353                                                 'relative' => $this->router
->generate($this->route
, $routeParams), 
 354                                                 'title' => implode('/', $titles), 
 355                                                 'translated' => $this->translator
->trans($this->config
['languages'][$locale], [], null, $locale) 
 361                 //With empty head title and section 
 362                 if (empty($parameters['head']['title']) && !empty($parameters['section'])) { 
 364                         $parameters['head']['title'] = implode(' - ', [$parameters['title'], $parameters['section'], $this->translator
->trans($this->config
['title'])]); 
 365                 //With empty head title 
 366                 } elseif (empty($parameters['head']['title'])) { 
 368                         $parameters['head']['title'] = implode(' - ', [$parameters['title'], $this->translator
->trans($this->config
['title'])]); 
 371                 //With empty head description and description 
 372                 if (empty($parameters['head']['description']) && !empty($parameters['description'])) { 
 373                         //Set head description 
 374                         $parameters['head']['description'] = $parameters['description']; 
 377                 //With empty facebook title and title 
 378                 if (empty($parameters['head']['facebook']['og:title']) && !empty($parameters['title'])) { 
 380                         $parameters['head']['facebook']['og:title'] = $parameters['title']; 
 383                 //With empty facebook description and description 
 384                 if (empty($parameters['head']['facebook']['og:description']) && !empty($parameters['description'])) { 
 385                         //Set facebook description 
 386                         $parameters['head']['facebook']['og:description'] = $parameters['description']; 
 390                 if (!empty($this->locale
)) { 
 391                         //Set facebook locale 
 392                         $parameters['head']['facebook']['og:locale'] = $this->locale
; 
 395                         //XXX: locale change when fb_locale=xx_xx is provided is done in FacebookSubscriber 
 396                         //XXX: see https://stackoverflow.com/questions/20827882/in-open-graph-markup-whats-the-use-of-oglocalealternate-without-the-locati 
 397                         if (!empty($parameters['head']['alternates'])) { 
 398                                 //Iterate on alternates 
 399                                 foreach($parameters['head']['alternates'] as $lang => $alternate) { 
 400                                         if (strlen($lang) == 5) { 
 401                                                 //Set facebook locale alternate 
 402                                                 $parameters['head']['facebook']['og:locale:alternate'] = str_replace('-', '_', $lang); 
 408                 //Without facebook image defined and texts 
 409                 if (empty($parameters['head']['facebook']['og:image']) && !empty($this->request
) && !empty($parameters['head']['fbimage']['texts']) && !empty($this->modified
)) { 
 411                         $parameters['head']['facebook'] +
= $this->facebook
->getImage($this->request
->getPathInfo(), $parameters['head']['fbimage']['texts'], $this->modified
->getTimestamp()); 
 414                 //Call twig render method 
 415                 $content = $this->twig
->render($view, $parameters); 
 417                 //Invalidate OK response on invalid form 
 418         if (200 === $response->getStatusCode()) { 
 419             foreach ($parameters as $v) { 
 420                 if ($v instanceof FormInterface 
&& $v->isSubmitted() && !$v->isValid()) { 
 421                     $response->setStatusCode(422); 
 427                 //Store content in response 
 428         $response->setContent($content); 
 437          * @see vendor/symfony/framework-bundle/Controller/AbstractController.php 
 439         public static function getSubscribedServices(): array { 
 440                 //Return subscribed services 
 442                         'security.authorization_checker' => AuthorizationCheckerInterface
::class, 
 443                         'service_container' => ContainerInterface
::class, 
 444                         'rapsys_user.access_decision_manager' => AccessDecisionManagerInterface
::class, 
 445                         'doctrine' => ManagerRegistry
::class, 
 446                         'rapsys_pack.facebook_util' => FacebookUtil
::class, 
 447                         'form.factory' => FormFactoryInterface
::class, 
 448                         'rapsys_pack.image_util' => ImageUtil
::class, 
 449                         'mailer.mailer' => MailerInterface
::class, 
 450                         'doctrine.orm.default_entity_manager' => EntityManagerInterface
::class, 
 451                         'rapsys_pack.path_package' => PackageInterface
::class, 
 452                         'router' => RouterInterface
::class, 
 453                         'rapsys_pack.slugger_util' => SluggerUtil
::class, 
 454                         'request_stack' => RequestStack
::class, 
 455                         'translator' => TranslatorInterface
::class, 
 456                         'twig' => Environment
::class,