vendor/pimcore/pimcore/bundles/CoreBundle/EventListener/Frontend/DocumentFallbackListener.php line 150

Open in your IDE?
  1. <?php
  2. /**
  3.  * Pimcore
  4.  *
  5.  * This source file is available under two different licenses:
  6.  * - GNU General Public License version 3 (GPLv3)
  7.  * - Pimcore Commercial License (PCL)
  8.  * Full copyright and license information is available in
  9.  * LICENSE.md which is distributed with this source code.
  10.  *
  11.  *  @copyright  Copyright (c) Pimcore GmbH (http://www.pimcore.org)
  12.  *  @license    http://www.pimcore.org/license     GPLv3 and PCL
  13.  */
  14. namespace Pimcore\Bundle\CoreBundle\EventListener\Frontend;
  15. use Pimcore\Bundle\CoreBundle\Controller\PublicServicesController;
  16. use Pimcore\Bundle\CoreBundle\EventListener\Traits\PimcoreContextAwareTrait;
  17. use Pimcore\Http\Request\Resolver\DocumentResolver;
  18. use Pimcore\Http\Request\Resolver\PimcoreContextResolver;
  19. use Pimcore\Http\Request\Resolver\SiteResolver;
  20. use Pimcore\Model\Document;
  21. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  22. use Symfony\Component\HttpFoundation\RequestStack;
  23. use Symfony\Component\HttpKernel\Event\ControllerEvent;
  24. use Symfony\Component\HttpKernel\Event\RequestEvent;
  25. use Symfony\Component\HttpKernel\KernelEvents;
  26. use Symfony\Component\OptionsResolver\OptionsResolver;
  27. /**
  28.  * If no document was found on the active request (not set by router or by initiator of a sub-request), try to find and
  29.  * set a fallback document:
  30.  *
  31.  *  - if request is a sub-request, try to read document from master request
  32.  *  - if all fails, try to find the nearest document by path
  33.  *
  34.  * @internal
  35.  */
  36. class DocumentFallbackListener implements EventSubscriberInterface
  37. {
  38.     use PimcoreContextAwareTrait;
  39.     /**
  40.      * @var array
  41.      */
  42.     protected array $options;
  43.     /**
  44.      * @var Document|null
  45.      */
  46.     private ?Document $fallbackDocument null;
  47.     public function __construct(
  48.         protected RequestStack $requestStack,
  49.         protected DocumentResolver $documentResolver,
  50.         protected SiteResolver $siteResolver,
  51.         protected Document\Service $documentService,
  52.         array $options = []
  53.     ) {
  54.         $optionsResolver = new OptionsResolver();
  55.         $this->configureOptions($optionsResolver);
  56.         $this->options $optionsResolver->resolve($options);
  57.     }
  58.     protected function configureOptions(OptionsResolver $optionsResolver)
  59.     {
  60.         $optionsResolver->setDefaults([
  61.             'nearestDocumentTypes' => ['page''snippet''hardlink''link''folder'],
  62.         ]);
  63.         $optionsResolver->setAllowedTypes('nearestDocumentTypes''array');
  64.     }
  65.     /**
  66.      * {@inheritdoc}
  67.      */
  68.     public static function getSubscribedEvents()
  69.     {
  70.         return [
  71.             // priority must be before
  72.             // -> Symfony\Component\HttpKernel\EventListener\LocaleListener::onKernelRequest()
  73.             // -> Pimcore\Bundle\CoreBundle\EventListener\Frontend\EditmodeListener::onKernelRequest()
  74.             KernelEvents::REQUEST => ['onKernelRequest'20],
  75.             KernelEvents::CONTROLLER => ['onKernelController'50],
  76.         ];
  77.     }
  78.     /**
  79.      * Finds the nearest document for the current request if the routing/document router didn't find one (e.g. static routes)
  80.      *
  81.      * @param RequestEvent $event
  82.      */
  83.     public function onKernelRequest(RequestEvent $event)
  84.     {
  85.         $request $event->getRequest();
  86.         if (!$this->matchesPimcoreContext($requestPimcoreContextResolver::CONTEXT_DEFAULT)) {
  87.             return;
  88.         }
  89.         if ($this->documentResolver->getDocument($request)) {
  90.             return;
  91.         }
  92.         if ($event->isMainRequest()) {
  93.             // no document found yet - try to find the nearest document by request path
  94.             // this is only done on the master request as a sub-request's pathInfo is _fragment when
  95.             // rendered via actions helper
  96.             $path null;
  97.             if ($this->siteResolver->isSiteRequest($request)) {
  98.                 $path $this->siteResolver->getSitePath($request);
  99.             } else {
  100.                 $path urldecode($request->getPathInfo());
  101.             }
  102.             $document $this->documentService->getNearestDocumentByPath($pathfalse$this->options['nearestDocumentTypes']);
  103.             if ($document) {
  104.                 $this->fallbackDocument $document;
  105.                 if ($document->getProperty('language')) {
  106.                     $request->setLocale($document->getProperty('language'));
  107.                 }
  108.             }
  109.         } else {
  110.             // if we're in a sub request and no explicit document is set - try to load document from
  111.             // parent and/or master request and set it on our sub-request
  112.             $parentRequest $this->requestStack->getParentRequest();
  113.             $masterRequest $this->requestStack->getMainRequest();
  114.             $eligibleRequests = [];
  115.             if (null !== $parentRequest) {
  116.                 $eligibleRequests[] = $parentRequest;
  117.             }
  118.             if ($masterRequest !== $parentRequest) {
  119.                 $eligibleRequests[] = $masterRequest;
  120.             }
  121.             foreach ($eligibleRequests as $eligibleRequest) {
  122.                 if ($document $this->documentResolver->getDocument($eligibleRequest)) {
  123.                     $this->documentResolver->setDocument($request$document);
  124.                     return;
  125.                 }
  126.             }
  127.         }
  128.     }
  129.     public function onKernelController(ControllerEvent $event)
  130.     {
  131.         $controller $event->getController();
  132.         if (is_array($controller) && isset($controller[0]) && $controller[0] instanceof PublicServicesController) {
  133.             // ignore PublicServicesController because this could lead to conflicts of Asset and Document paths, see #2704
  134.             return;
  135.         }
  136.         if ($this->fallbackDocument && $event->isMainRequest()) {
  137.             $this->documentResolver->setDocument($event->getRequest(), $this->fallbackDocument);
  138.         }
  139.     }
  140. }