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\Bundle\SecurityBundle\Security
; 
  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\Request
; 
  25 use Symfony\Component\HttpFoundation\RequestStack
; 
  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\Component\Security\Core\Authorization\AuthorizationCheckerInterface
; 
  32 use Symfony\Component\Security\Core\User\UserInterface
; 
  33 use Symfony\Contracts\Service\ServiceSubscriberInterface
; 
  34 use Symfony\Contracts\Translation\TranslatorInterface
; 
  37 use Rapsys\BlogBundle\Entity\Dance
; 
  38 use Rapsys\BlogBundle\Entity\Location
; 
  39 use Rapsys\BlogBundle\Entity\Slot
; 
  40 use Rapsys\BlogBundle\Entity\User
; 
  41 use Rapsys\BlogBundle\RapsysBlogBundle
; 
  43 use Rapsys\PackBundle\Util\FacebookUtil
; 
  44 use Rapsys\PackBundle\Util\ImageUtil
; 
  45 use Rapsys\PackBundle\Util\SluggerUtil
; 
  48  * Provides common features needed in controllers. 
  52 abstract class AbstractController 
extends BaseAbstractController 
implements ServiceSubscriberInterface 
{ 
  56         protected array $config; 
  66         protected array $context; 
  76         protected string $locale; 
  81         protected \DateTime 
$modified; 
  91         protected string $route; 
  96         protected array $routeParams; 
  99          * AuthorizationCheckerInterface instance 
 101         protected AuthorizationCheckerInterface 
$checker; 
 104          * AccessDecisionManagerInterface instance 
 106         protected AccessDecisionManagerInterface 
$decision; 
 109          * ManagerRegistry instance 
 111         protected ManagerRegistry 
$doctrine; 
 114          * FacebookUtil instance 
 116         protected FacebookUtil 
$facebook; 
 119          * FormFactoryInterface instance 
 121         protected FormFactoryInterface 
$factory; 
 124          * Image util instance 
 126         protected ImageUtil 
$image; 
 129          * MailerInterface instance 
 131         protected MailerInterface 
$mailer; 
 134          * EntityManagerInterface instance 
 136         protected EntityManagerInterface 
$manager; 
 139          * PackageInterface instance 
 141         protected PackageInterface 
$package; 
 146         protected Request 
$request; 
 151         protected RouterInterface 
$router; 
 154          * Slugger util instance 
 156         protected SluggerUtil 
$slugger; 
 161         protected Security 
$security; 
 164          * RequestStack instance 
 166         protected RequestStack 
$stack; 
 169          * Translator instance 
 171         protected TranslatorInterface 
$translator; 
 174          * Twig\Environment instance 
 176         protected Environment 
$twig; 
 179          * Abstract constructor 
 181          * @param AuthorizationCheckerInterface $checker The container instance 
 182          * @param ContainerInterface $container The container instance 
 183          * @param AccessDecisionManagerInterface $decision The decision instance 
 184          * @param ManagerRegistry $doctrine The doctrine instance 
 185          * @param FacebookUtil $facebook The facebook instance 
 186          * @param FormFactoryInterface $factory The factory instance 
 187          * @param ImageUtil $image The image instance 
 188          * @param MailerInterface $mailer The mailer instance 
 189          * @param EntityManagerInterface $manager The manager instance 
 190          * @param PackageInterface $package The package instance 
 191          * @param RouterInterface $router The router instance 
 192          * @param SluggerUtil $slugger The slugger instance 
 193          * @param Security $security The security instance 
 194          * @param RequestStack $stack The stack instance 
 195          * @param TranslatorInterface $translator The translator instance 
 196          * @param Environment $twig The twig environment instance 
 197          * @param integer $limit The page limit 
 199          * @TODO move all that stuff to setSlugger('@slugger') setters with a calls: [ setSlugger: [ '@slugger' ] ] to unbload classes ??? 
 200          * @TODO add a calls: [ ..., prepare: ['@???'] ] that do all the logic that can't be done in constructor because various things are not available 
 202         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, Security 
$security, RequestStack 
$stack, TranslatorInterface 
$translator, Environment 
$twig, int $limit = 5) { 
 204                 $this->checker 
= $checker; 
 207                 $this->config 
= $container->getParameter(RapsysBlogBundle
::getAlias()); 
 210                 $this->container 
= $container; 
 213                 $this->decision 
= $decision; 
 216                 $this->doctrine 
= $doctrine; 
 219                 $this->facebook 
= $facebook; 
 222                 $this->factory 
= $factory; 
 225                 $this->image 
= $image; 
 228                 $this->limit 
= $limit; 
 231                 $this->mailer 
= $mailer; 
 234                 $this->manager 
= $manager; 
 237                 $this->package 
= $package; 
 240                 $this->router 
= $router; 
 243                 $this->slugger 
= $slugger; 
 246                 $this->security 
= $security; 
 249                 $this->stack 
= $stack; 
 252                 $this->translator 
= $translator; 
 258                 $this->request 
= $this->stack
->getCurrentRequest(); 
 261                 $this->locale 
= $this->request
->getLocale(); 
 270                 $this->page 
= (int) $this->request
->query
->get('page'); 
 273                 if ($this->page 
< 0) { 
 278                 //TODO: default to not found route ??? 
 279                 //TODO: when url not found, this attribute is not defined, how do we handle it ??? 
 280                 //XXX: do we generate a dummy default route by default ??? 
 281                 $this->route 
= $this->request
->attributes
->get('_route'); 
 284                 $this->routeParams 
= $this->request
->attributes
->get('_route_params'); 
 286                 //With route and routeParams 
 287                 if ($this->route 
!== null && $this->routeParams 
!== null) { 
 289                         $canonical = $this->router
->generate($this->route
, $this->routeParams
, UrlGeneratorInterface
::ABSOLUTE_URL
); 
 297                         'alternates' => $alternates, 
 298                         'canonical' => $canonical, 
 300                                 'address' => $this->config
['contact']['address'], 
 301                                 'name' => $this->translator
->trans($this->config
['contact']['name']) 
 304                                 'by' => $this->translator
->trans($this->config
['copy']['by']), 
 305                                 'link' => $this->config
['copy']['link'], 
 306                                 'long' => $this->translator
->trans($this->config
['copy']['long']), 
 307                                 'short' => $this->translator
->trans($this->config
['copy']['short']), 
 308                                 'title' => $this->config
['copy']['title'] 
 310                         'description' => null, 
 311                         'donate' => $this->config
['donate'], 
 313                                 'og:type' => 'article', 
 314                                 'og:site_name' => $title = $this->translator
->trans($this->config
['title']), 
 315                                 'og:url' => $canonical, 
 316                                 #'fb:admins' => $this->config['facebook']['admins'], 
 317                                 'fb:app_id' => $this->config
['facebook']['apps'] 
 319                         //XXX: TODO: only generate it when fb robot request the url ??? 
 323                                                 //'font' => 'irishgrover', 
 329                         'icon' => $this->config
['icon'], 
 331                         'locale' => str_replace('_', '-', $this->locale
), 
 333                         #       'png' => $this->config['logo']['png'], 
 334                         #       'svg' => $this->config['logo']['svg'], 
 335                         #       'alt' => $this->translator->trans($this->config['logo']['alt']) 
 337                         'logo' => $this->config
['logo'], 
 340                         'root' => $this->router
->generate($this->config
['root']), 
 354         protected function render(string $view, array $parameters = [], Response 
$response = null): Response 
{ 
 355                 //Create response when null 
 356                 $response ??= new Response(); 
 359                 if (count($parameters['alternates']) <= 1) { 
 360                         //Iterate on locales excluding current one 
 361                         foreach($this->config
['locales'] as $locale) { 
 363                                 $routeParams = $this->routeParams
; 
 365                                 //With current locale 
 366                                 if ($locale !== $this->locale
) { 
 370                                         //Set route params locale 
 371                                         $routeParams['_locale'] = $locale; 
 374                                         //XXX: slug is in current locale, better use a simple redirect for invalid slug than implement a hard to get translation here 
 375                                         unset($routeParams['slug']); 
 377                                         //Iterate on other locales 
 378                                         foreach(array_diff($this->config
['locales'], [$locale]) as $other) { 
 379                                                 //Set other locale title 
 380                                                 $titles[$other] = $this->translator
->trans($this->config
['languages'][$locale], [], null, $other); 
 383                                         //Set locale locales context 
 384                                         $parameters['alternates'][str_replace('_', '-', $locale)] = [ 
 385                                                 'absolute' => $this->router
->generate($this->route
, $routeParams, UrlGeneratorInterface
::ABSOLUTE_URL
), 
 386                                                 'relative' => $this->router
->generate($this->route
, $routeParams), 
 387                                                 'title' => implode('/', $titles), 
 388                                                 'translated' => $this->translator
->trans($this->config
['languages'][$locale], [], null, $locale) 
 392                                         if (empty($parameters['alternates'][$shortCurrent = substr($locale, 0, 2)])) { 
 393                                                 //Set locale locales context 
 394                                                 $parameters['alternates'][$shortCurrent] = $parameters['alternates'][str_replace('_', '-', $locale)]; 
 401                 if (!empty($parameters['canonical'])) { 
 403                         $parameters['facebook']['og:url'] = $parameters['canonical']; 
 406                 //With empty facebook title and title 
 407                 if (empty($parameters['facebook']['og:title']) && !empty($parameters['title']['page'])) { 
 409                         $parameters['facebook']['og:title'] = $parameters['title']['page']; 
 412                 //With empty facebook description and description 
 413                 if (empty($parameters['facebook']['og:description']) && !empty($parameters['description'])) { 
 414                         //Set facebook description 
 415                         $parameters['facebook']['og:description'] = $parameters['description']; 
 419                 if (!empty($this->locale
)) { 
 420                         //Set facebook locale 
 421                         $parameters['facebook']['og:locale'] = $this->locale
; 
 424                         //XXX: locale change when fb_locale=xx_xx is provided is done in FacebookSubscriber 
 425                         //XXX: see https://stackoverflow.com/questions/20827882/in-open-graph-markup-whats-the-use-of-oglocalealternate-without-the-locati 
 426                         if (!empty($parameters['alternates'])) { 
 427                                 //Iterate on alternates 
 428                                 foreach($parameters['alternates'] as $lang => $alternate) { 
 429                                         if (strlen($lang) == 5) { 
 430                                                 //Set facebook locale alternate 
 431                                                 $parameters['facebook']['og:locale:alternate'] = str_replace('-', '_', $lang); 
 437                 //Without facebook image defined and texts 
 438                 if (empty($parameters['facebook']['og:image']) && !empty($this->request
) && !empty($parameters['fbimage']['texts']) && !empty($this->modified
)) { 
 440                         //XXX: decode getPathInfo (see https://github.com/symfony/symfony/issues/2579) 
 441                         $parameters['facebook'] +
= $this->image
->getFacebook(urldecode($this->request
->getPathInfo()), $parameters['fbimage']['texts'], $this->modified
->getTimestamp()); 
 445                 if (!empty($this->count
)) { 
 447                         if ($this->page 
> 0) { 
 449                                 $parameters['prev'] = $this->generateUrl($this->request
->get('_route'), ['page' => $this->page 
- 1]+
$this->request
->get('_route_params')); 
 453                         if ($this->count 
> ($this->page + 
1) * $this->limit
) { 
 455                                 $parameters['next'] = $this->generateUrl($this->request
->get('_route'), ['page' => $this->page + 
1]+
$this->request
->get('_route_params')); 
 459                 //Call twig render method 
 460                 $content = $this->twig
->render($view, $parameters); 
 462                 //Invalidate OK response on invalid form 
 463                 if (200 === $response->getStatusCode()) { 
 464                         foreach ($parameters as $v) { 
 465                                 if ($v instanceof FormInterface 
&& $v->isSubmitted() && !$v->isValid()) { 
 466                                         $response->setStatusCode(422); 
 472                 //Store content in response 
 473                 $response->setContent($content); 
 482          * @see vendor/symfony/framework-bundle/Controller/AbstractController.php 
 484         public static function getSubscribedServices(): array { 
 485                 //Return subscribed services 
 487                         'security.authorization_checker' => AuthorizationCheckerInterface
::class, 
 488                         'service_container' => ContainerInterface
::class, 
 489                         'rapsys_user.access_decision_manager' => AccessDecisionManagerInterface
::class, 
 490                         'doctrine' => ManagerRegistry
::class, 
 491                         'rapsys_pack.facebook_util' => FacebookUtil
::class, 
 492                         'form.factory' => FormFactoryInterface
::class, 
 493                         'rapsys_pack.image_util' => ImageUtil
::class, 
 494                         'mailer.mailer' => MailerInterface
::class, 
 495                         'doctrine.orm.default_entity_manager' => EntityManagerInterface
::class, 
 496                         'rapsys_pack.path_package' => PackageInterface
::class, 
 497                         'router' => RouterInterface
::class, 
 498                         'rapsys_pack.slugger_util' => SluggerUtil
::class, 
 499                         'security' => Security
::class, 
 500                         'stack' => RequestStack
::class, 
 501                         'translator' => TranslatorInterface
::class, 
 502                         'twig' => Environment
::class,