1 <?php 
declare(strict_types
=1); 
   4  * This file is part of the Rapsys TreeBundle 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\TreeBundle\Controller
; 
  14 use Doctrine\Persistence\ManagerRegistry
; 
  16 use Psr\Container\ContainerInterface
; 
  18 use Rapsys\PackBundle\Util\FacebookUtil
; 
  19 use Rapsys\TreeBundle\Entity\Album
; 
  20 use Rapsys\TreeBundle\RapsysTreeBundle
; 
  22 use Symfony\Bundle\FrameworkBundle\Controller\AbstractController
; 
  23 use Symfony\Bundle\SecurityBundle\Security
; 
  24 use Symfony\Component\HttpFoundation\Request
; 
  25 use Symfony\Component\HttpFoundation\RequestStack
; 
  26 use Symfony\Component\HttpFoundation\Response
; 
  27 use Symfony\Component\Routing\Generator\UrlGeneratorInterface
; 
  28 use Symfony\Component\Routing\RouterInterface
; 
  29 use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface
; 
  31 use Symfony\Contracts\Translation\TranslatorInterface
; 
  38 class TreeController 
extends AbstractController 
{ 
  42         protected array $config; 
  47         protected array $context = []; 
  57         protected string $locale; 
  67         protected Request 
$request; 
  72         protected string $route; 
  77         protected array $routeParams; 
  80          * Creates a new tree controller 
  82          * @param AuthorizationCheckerInterface $checker The container instance 
  83          * @param ContainerInterface $container The ContainerInterface instance 
  84          * @param ManagerRegistry $doctrine The doctrine instance 
  85          * @param FacebookUtil $facebook The facebook instance 
  86          * @param RouterInterface $router The router instance 
  87          * @param Security $security The security instance 
  88          * @param RequestStack $stack The stack instance 
  89          * @param TranslatorInterface $translator The translator instance 
  90          * @param Environment $twig The twig environment instance 
  91          * @param integer $limit The page limit 
  93         function __construct(protected AuthorizationCheckerInterface 
$checker, protected ContainerInterface 
$container, protected ManagerRegistry 
$doctrine, protected FacebookUtil 
$facebook, protected RouterInterface 
$router, protected Security 
$security, protected RequestStack 
$stack, protected TranslatorInterface 
$translator, protected Environment 
$twig, protected int $limit = 5) { 
  95                 $this->config 
= $container->getParameter(RapsysTreeBundle
::getAlias()); 
  98                 $this->request 
= $this->stack
->getMainRequest(); 
 101                 $this->locale 
= $this->request
->getLocale(); 
 110                 $this->page 
= (int) $this->request
->query
->get('page'); 
 113                 if ($this->page 
< 0) { 
 118                 //TODO: default to not found route ??? 
 119                 //TODO: pour une url not found, cet attribut n'est pas défini, comment on fait ??? 
 120                 //XXX: on génère une route bidon par défaut ??? 
 121                 $this->route 
= $this->request
->attributes
->get('_route'); 
 124                 $this->routeParams 
= $this->request
->attributes
->get('_route_params'); 
 126                 //With route and routeParams 
 127                 if ($this->route 
!== null && $this->routeParams 
!== null) { 
 129                         $canonical = $this->router
->generate($this->route
, $this->routeParams
, UrlGeneratorInterface
::ABSOLUTE_URL
); 
 133                                 substr($this->locale
, 0, 2) => [ 
 134                                         'absolute' => $canonical 
 141                         'alternates' => $alternates, 
 142                         'canonical' => $canonical, 
 144                                 'address' => $this->config
['contact']['address'], 
 145                                 'name' => $this->translator
->trans($this->config
['contact']['name']) 
 148                                 'by' => $this->translator
->trans($this->config
['copy']['by']), 
 149                                 'link' => $this->config
['copy']['link'], 
 150                                 'long' => $this->translator
->trans($this->config
['copy']['long']), 
 151                                 'short' => $this->translator
->trans($this->config
['copy']['short']), 
 152                                 'title' => $this->config
['copy']['title'] 
 154                         'description' => null, 
 155                         'donate' => $this->config
['donate'], 
 157                                 'og:type' => 'article', 
 158                                 'og:site_name' => $title = $this->translator
->trans($this->config
['title']), 
 159                                 'og:url' => $canonical, 
 160                                 #'fb:admins' => $this->config['facebook']['admins'], 
 161                                 'fb:app_id' => $this->config
['facebook']['apps'] 
 163                         //XXX: TODO: only generate it when fb robot request the url ??? 
 167                                                 'font' => 'irishgrover', 
 172                         'icon' => $this->config
['icon'], 
 174                         'locale' => str_replace('_', '-', $this->locale
), 
 175                         'logo' => $this->config
['logo'], 
 177                         'root' => $this->router
->generate($this->config
['root']), 
 191          * @param Request $request The request instance 
 192          * @return Response The rendered view 
 194         public function index(Request 
$request): Response 
{ 
 196                 $user = $this->security
->getUser(); 
 198                 //With not enough albums 
 199                 if (($this->count 
= $this->doctrine
->getRepository(Album
::class)->findCountAsInt($user?->getId())) < $this->page 
* $this->limit
) { 
 201                         throw $this->createNotFoundException($this->translator
->trans('Unable to find albums')); 
 205                 if ($this->context
['albums'] = $this->doctrine
->getRepository(Album
::class)->findAllAsArray($user?->getId(), $this->page
, $this->limit
)) { 
 207                         $this->modified 
= max(array_map(function ($v) { return $v
['modified']; }, $this->context
['albums'])); 
 211                         $this->modified 
= new \
DateTime('-1 year'); 
 214                 /*header('Content-Type: text/plain'); 
 215                 var_dump($this->context['albums']); 
 219                 $response = new Response(); 
 222                 if ($this->checker
->isGranted('IS_AUTHENTICATED_REMEMBERED')) { 
 224                         $response->setLastModified(new \
DateTime('-1 year')); 
 227                         $response->setPrivate(); 
 228                 //Without logged user 
 231                         //XXX: only for public to force revalidation by last modified 
 232                         $response->setEtag(md5(serialize($this->context
['albums']))); 
 235                         $response->setLastModified($this->modified
); 
 238                         $response->setPublic(); 
 240                         //Without role and modification 
 241                         if ($response->isNotModified($request)) { 
 242                                 //Return 304 response 
 248                 /*$this->context['head']['keywords'] = implode( 
 250                         //Use closure to extract each unique article keywords sorted 
 255                                 //Iterate on articles 
 258                                         if (!empty($a['keywords'])) { 
 259                                                 //Iterate on keywords 
 260                                                 foreach($a['keywords'] as $k) { 
 262                                                         $r[$k['title']] = $k['title']; 
 272                         })($this->context['articles']) 
 275                 $this->context['albums'] = $this->config['albums'];*/ 
 277                 //Return rendered response 
 278                 return $this->render('@RapsysTree/index.html.twig', $this->context
, $response); 
 286          * @param Request $request The request instance 
 287          * @param string $path The directory path 
 288          * @return Response The rendered view 
 290         public function directory(Request 
$request, string $path): Response 
{ 
 291                 header('Content-Type: text/plain'); 
 296                 $response = $this->render('@RapsysTree/directory.html.twig', $this->context
); 
 298                 $response->setEtag(md5($response->getContent())); 
 299                 $response->setPublic(); 
 300                 $response->isNotModified($request); 
 311          * @param Request $request The request instance 
 312          * @param string $path The directory path 
 313          * @return Response The rendered view 
 315         public function document(Request 
$request, string $path): Response 
{ 
 317                 $response = $this->render('@RapsysTree/document.html.twig', $this->context
); 
 319                 $response->setEtag(md5($response->getContent())); 
 320                 $response->setPublic(); 
 321                 $response->isNotModified($request); 
 332         protected function render(string $view, array $parameters = [], Response 
$response = null): Response 
{ 
 333                 //Create response when null 
 334                 $response ??= new Response(); 
 337                 if (count($parameters['alternates']) <= 1) { 
 339                         $routeParams = $this->routeParams
; 
 341                         //Iterate on locales excluding current one 
 342                         foreach($this->config
['locales'] as $locale) { 
 343                                 //With current locale 
 344                                 if ($locale !== $this->locale
) { 
 348                                         //Set route params locale 
 349                                         $routeParams['_locale'] = $locale; 
 351                                         //Iterate on other locales 
 352                                         foreach(array_diff($this->config
['locales'], [$locale]) as $other) { 
 353                                                 //Set other locale title 
 354                                                 $titles[$other] = $this->translator
->trans($this->config
['languages'][$locale], [], null, $other); 
 357                                         //Set locale locales context 
 358                                         $parameters['alternates'][str_replace('_', '-', $locale)] = [ 
 359                                                 'absolute' => $this->router
->generate($this->route
, $routeParams, UrlGeneratorInterface
::ABSOLUTE_URL
), 
 360                                                 'relative' => $this->router
->generate($this->route
, $routeParams), 
 361                                                 'title' => implode('/', $titles), 
 362                                                 'translated' => $this->translator
->trans($this->config
['languages'][$locale], [], null, $locale) 
 366                                         if (empty($parameters['alternates'][$shortCurrent = substr($locale, 0, 2)])) { 
 367                                                 //Set locale locales context 
 368                                                 $parameters['alternates'][$shortCurrent] = $parameters['alternates'][str_replace('_', '-', $locale)]; 
 375                 if (!empty($parameters['canonical'])) { 
 377                         $parameters['facebook']['og:url'] = $parameters['canonical']; 
 380                 //With empty facebook title and title 
 381                 if (empty($parameters['facebook']['og:title']) && !empty($parameters['title']['page'])) { 
 383                         $parameters['facebook']['og:title'] = $parameters['title']['page']; 
 386                 //With empty facebook description and description 
 387                 if (empty($parameters['facebook']['og:description']) && !empty($parameters['description'])) { 
 388                         //Set facebook description 
 389                         $parameters['facebook']['og:description'] = $parameters['description']; 
 393                 if (!empty($this->locale
)) { 
 394                         //Set facebook locale 
 395                         $parameters['facebook']['og:locale'] = $this->locale
; 
 398                         //XXX: locale change when fb_locale=xx_xx is provided is done in FacebookSubscriber 
 399                         //XXX: see https://stackoverflow.com/questions/20827882/in-open-graph-markup-whats-the-use-of-oglocalealternate-without-the-locati 
 400                         if (!empty($parameters['alternates'])) { 
 401                                 //Iterate on alternates 
 402                                 foreach($parameters['alternates'] as $lang => $alternate) { 
 403                                         if (strlen($lang) == 5) { 
 404                                                 //Set facebook locale alternate 
 405                                                 $parameters['facebook']['og:locale:alternate'] = str_replace('-', '_', $lang); 
 411                 //Without facebook image defined and texts 
 412                 if (empty($parameters['facebook']['og:image']) && !empty($this->request
) && !empty($parameters['fbimage']['texts']) && !empty($this->modified
)) { 
 414                         $parameters['facebook'] +
= $this->facebook
->getImage($this->request
->getPathInfo(), $parameters['fbimage']['texts'], $this->modified
->getTimestamp()); 
 417                 //Call twig render method 
 418                 $content = $this->twig
->render($view, $parameters); 
 420                 //Invalidate OK response on invalid form 
 421                 if (200 === $response->getStatusCode()) { 
 422                         foreach ($parameters as $v) { 
 423                                 if ($v instanceof FormInterface 
&& $v->isSubmitted() && !$v->isValid()) { 
 424                                         $response->setStatusCode(422); 
 430                 //Store content in response 
 431                 $response->setContent($content);