vendor/sulu/sulu/src/Sulu/Bundle/WebsiteBundle/Routing/ContentRouteProvider.php line 101

Open in your IDE?
  1. <?php
  2. /*
  3.  * This file is part of Sulu.
  4.  *
  5.  * (c) Sulu GmbH
  6.  *
  7.  * This source file is subject to the MIT license that is bundled
  8.  * with this source code in the file LICENSE.
  9.  */
  10. namespace Sulu\Bundle\WebsiteBundle\Routing;
  11. use PHPCR\RepositoryException;
  12. use Sulu\Bundle\DocumentManagerBundle\Bridge\DocumentInspector;
  13. use Sulu\Bundle\PageBundle\Document\PageDocument;
  14. use Sulu\Component\Content\Compat\Structure\PageBridge;
  15. use Sulu\Component\Content\Compat\StructureManagerInterface;
  16. use Sulu\Component\Content\Document\Behavior\ExtensionBehavior;
  17. use Sulu\Component\Content\Document\RedirectType;
  18. use Sulu\Component\Content\Exception\ResourceLocatorMovedException;
  19. use Sulu\Component\Content\Exception\ResourceLocatorNotFoundException;
  20. use Sulu\Component\Content\Types\ResourceLocator\Strategy\ResourceLocatorStrategyPoolInterface;
  21. use Sulu\Component\DocumentManager\DocumentManagerInterface;
  22. use Sulu\Component\Security\Authorization\PermissionTypes;
  23. use Sulu\Component\Security\Authorization\SecurityCheckerInterface;
  24. use Sulu\Component\Security\Authorization\SecurityCondition;
  25. use Sulu\Component\Webspace\Analyzer\Attributes\RequestAttributes;
  26. use Sulu\Component\Webspace\Analyzer\RequestAnalyzerInterface;
  27. use Sulu\Component\Webspace\Manager\WebspaceManagerInterface;
  28. use Symfony\Cmf\Component\Routing\RouteProviderInterface;
  29. use Symfony\Component\HttpFoundation\Request;
  30. use Symfony\Component\Routing\Route;
  31. use Symfony\Component\Routing\RouteCollection;
  32. /**
  33.  * The PortalRouteProvider should load the dynamic routes created by Sulu.
  34.  */
  35. class ContentRouteProvider implements RouteProviderInterface
  36. {
  37.     /**
  38.      * @var DocumentManagerInterface
  39.      */
  40.     private $documentManager;
  41.     /**
  42.      * @var DocumentInspector
  43.      */
  44.     private $documentInspector;
  45.     /**
  46.      * @var ResourceLocatorStrategyPoolInterface
  47.      */
  48.     private $resourceLocatorStrategyPool;
  49.     /**
  50.      * @var StructureManagerInterface
  51.      */
  52.     private $structureManager;
  53.     /**
  54.      * @var WebspaceManagerInterface
  55.      */
  56.     private $webspaceManager;
  57.     /**
  58.      * @var RequestAnalyzerInterface
  59.      */
  60.     private $requestAnalyzer;
  61.     /**
  62.      * @var SecurityCheckerInterface|null
  63.      */
  64.     private $securityChecker;
  65.     /**
  66.      * @var array
  67.      */
  68.     private $defaultOptions;
  69.     public function __construct(
  70.         DocumentManagerInterface $documentManager,
  71.         DocumentInspector $documentInspector,
  72.         ResourceLocatorStrategyPoolInterface $resourceLocatorStrategyPool,
  73.         StructureManagerInterface $structureManager,
  74.         WebspaceManagerInterface $webspaceManager,
  75.         RequestAnalyzerInterface $requestAnalyzer,
  76.         SecurityCheckerInterface $securityChecker null,
  77.         array $defaultOptions = []
  78.     ) {
  79.         $this->documentManager $documentManager;
  80.         $this->documentInspector $documentInspector;
  81.         $this->resourceLocatorStrategyPool $resourceLocatorStrategyPool;
  82.         $this->structureManager $structureManager;
  83.         $this->webspaceManager $webspaceManager;
  84.         $this->requestAnalyzer $requestAnalyzer;
  85.         $this->securityChecker $securityChecker;
  86.         $this->defaultOptions $defaultOptions;
  87.     }
  88.     public function getRouteCollectionForRequest(Request $request)
  89.     {
  90.         $collection = new RouteCollection();
  91.         if ('' === $request->getRequestFormat()) {
  92.             return $collection;
  93.         }
  94.         /** @var RequestAttributes $attributes */
  95.         $attributes $request->attributes->get('_sulu');
  96.         if (!$attributes) {
  97.             return $collection;
  98.         }
  99.         $matchType $attributes->getAttribute('matchType');
  100.         // no portal information without localization supported
  101.         if (null === $attributes->getAttribute('localization')
  102.             && RequestAnalyzerInterface::MATCH_TYPE_PARTIAL !== $matchType
  103.             && RequestAnalyzerInterface::MATCH_TYPE_REDIRECT !== $matchType
  104.         ) {
  105.             return $collection;
  106.         }
  107.         $resourceLocator $this->decodePathInfo($attributes->getAttribute('resourceLocator'));
  108.         $prefix $attributes->getAttribute('resourceLocatorPrefix');
  109.         $pathInfo $this->decodePathInfo($request->getPathInfo());
  110.         $htmlRedirect $pathInfo !== $prefix $resourceLocator
  111.                         && \in_array($request->getRequestFormat(), ['htm''html']);
  112.         if ($htmlRedirect
  113.             || RequestAnalyzerInterface::MATCH_TYPE_REDIRECT == $matchType
  114.             || RequestAnalyzerInterface::MATCH_TYPE_PARTIAL == $matchType
  115.         ) {
  116.             return $collection;
  117.         }
  118.         // just show the page
  119.         $portal $attributes->getAttribute('portal');
  120.         $locale $attributes->getAttribute('localization')->getLocale();
  121.         $resourceLocatorStrategy $this->resourceLocatorStrategyPool->getStrategyByWebspaceKey(
  122.             $portal->getWebspace()->getKey()
  123.         );
  124.         try {
  125.             // load content by url ignore ending trailing slash
  126.             /** @var PageDocument $document */
  127.             $document $this->documentManager->find(
  128.                 $resourceLocatorStrategy->loadByResourceLocator(
  129.                     \rtrim($resourceLocator'/'),
  130.                     $portal->getWebspace()->getKey(),
  131.                     $locale
  132.                 ),
  133.                 $locale,
  134.                 [
  135.                     'load_ghost_content' => false,
  136.                 ]
  137.             );
  138.             if (!$document->getTitle()) {
  139.                 // If the title is empty the document does not exist in this locale
  140.                 // Necessary because of https://github.com/sulu/sulu/issues/2724, otherwise locale could be checked
  141.                 return $collection;
  142.             }
  143.             if ($this->securityChecker && $portal->getWebspace()->hasWebsiteSecurity()) {
  144.                 $this->securityChecker->checkPermission(
  145.                     new SecurityCondition(
  146.                         'sulu.webspaces.' $document->getWebspaceName(),
  147.                         $document->getLocale(),
  148.                         \get_class($document),
  149.                         $document->getUuid()
  150.                     ),
  151.                     PermissionTypes::VIEW
  152.                 );
  153.             }
  154.             if (\preg_match('/\/$/'$resourceLocator) && ('/' !== $resourceLocator || $prefix)) {
  155.                 // redirect page to page without slash at the end
  156.                 $url $prefix \rtrim($resourceLocator'/');
  157.                 if ($request->getQueryString()) {
  158.                     $url .= '?' $request->getQueryString();
  159.                 }
  160.                 $collection->add('redirect_' \uniqid(), $this->getRedirectRoute($request$url));
  161.             } elseif (RedirectType::INTERNAL === $document->getRedirectType()) {
  162.                 $redirectUrl $this->webspaceManager->findUrlByResourceLocator(
  163.                     $document->getRedirectTarget()->getResourceSegment(),
  164.                     null,
  165.                     $document->getLocale(),
  166.                     $document->getRedirectTarget()->getWebspaceName()
  167.                 );
  168.                 if ($request->getQueryString()) {
  169.                     $redirectUrl .= '?' $request->getQueryString();
  170.                 }
  171.                 $collection->add(
  172.                     $document->getStructureType() . '_' $document->getUuid(),
  173.                     $this->getRedirectRoute($request$redirectUrl)
  174.                 );
  175.             } elseif (RedirectType::EXTERNAL === $document->getRedirectType()) {
  176.                 $collection->add(
  177.                     $document->getStructureType() . '_' $document->getUuid(),
  178.                     $this->getRedirectRoute($request$document->getRedirectExternal())
  179.                 );
  180.             } elseif (!$this->checkResourceLocator($resourceLocator$prefix)) {
  181.                 return $collection;
  182.             } else {
  183.                 if ($document instanceof ExtensionBehavior) {
  184.                     $documentSegments $document->getExtensionsData()['excerpt']['segments'] ?? [];
  185.                     $documentSegmentKey $documentSegments[$portal->getWebspace()->getKey()] ?? null;
  186.                     $segment $this->requestAnalyzer->getSegment();
  187.                     if ($segment && $documentSegmentKey && $segment->getKey() !== $documentSegmentKey) {
  188.                         $this->requestAnalyzer->changeSegment($documentSegmentKey);
  189.                     }
  190.                 }
  191.                 // convert the page to a StructureBridge because of BC
  192.                 $metadata $this->documentInspector->getStructureMetadata($document);
  193.                 if (!$metadata) {
  194.                     return $collection;
  195.                 }
  196.                 /** @var PageBridge $structure */
  197.                 $structure $this->structureManager->wrapStructure(
  198.                     $this->documentInspector->getMetadata($document)->getAlias(),
  199.                     $metadata
  200.                 );
  201.                 $structure->setDocument($document);
  202.                 // show the page
  203.                 $collection->add(
  204.                     $document->getStructureType() . '_' $document->getUuid(),
  205.                     $this->getStructureRoute($request$structure)
  206.                 );
  207.             }
  208.         } catch (ResourceLocatorNotFoundException $exc) {
  209.             // just do not add any routes to the collection
  210.         } catch (ResourceLocatorMovedException $exc) {
  211.             // old url resource was moved
  212.             $collection->add(
  213.                 $exc->getNewResourceLocatorUuid() . '_' \uniqid(),
  214.                 $this->getRedirectRoute($request$prefix $exc->getNewResourceLocator())
  215.             );
  216.         } catch (RepositoryException $exc) {
  217.             // just do not add any routes to the collection
  218.         }
  219.         return $collection;
  220.     }
  221.     public function getRouteByName($name$parameters = [])
  222.     {
  223.         // TODO: Implement getRouteByName() method.
  224.     }
  225.     public function getRoutesByNames($names$parameters = [])
  226.     {
  227.         // TODO
  228.         return [];
  229.     }
  230.     /**
  231.      * Checks if the resource locator is valid.
  232.      * A resource locator with a slash only is not allowed, the only exception is when it is a single language
  233.      * website, where the browser automatically adds the slash.
  234.      *
  235.      * @param string $resourceLocator
  236.      * @param string $resourceLocatorPrefix
  237.      *
  238.      * @return bool
  239.      */
  240.     private function checkResourceLocator($resourceLocator$resourceLocatorPrefix)
  241.     {
  242.         return !('/' === $resourceLocator && $resourceLocatorPrefix);
  243.     }
  244.     /**
  245.      * @param string $url
  246.      *
  247.      * @return Route
  248.      */
  249.     protected function getRedirectRoute(Request $request$url)
  250.     {
  251.         $requestFormat $request->getRequestFormat(null);
  252.         $formatSuffix $requestFormat '.' $requestFormat '';
  253.         // redirect to linked page
  254.         return new Route(
  255.             $this->decodePathInfo($request->getPathInfo()),
  256.             [
  257.                 '_controller' => 'sulu_website.redirect_controller::redirectAction',
  258.                 'url' => $url $formatSuffix,
  259.             ],
  260.             [],
  261.             $this->defaultOptions
  262.         );
  263.     }
  264.     /**
  265.      * @return Route
  266.      */
  267.     protected function getStructureRoute(Request $requestPageBridge $content)
  268.     {
  269.         return new Route(
  270.             $this->decodePathInfo($request->getPathInfo()),
  271.             [
  272.                 '_controller' => $content->getController(),
  273.                 'structure' => $content,
  274.                 'partial' => 'true' === $request->get('partial''false'),
  275.             ],
  276.             [],
  277.             $this->defaultOptions
  278.         );
  279.     }
  280.     /**
  281.      * Server encodes the url and symfony does not encode it
  282.      * Symfony decodes this data here https://github.com/symfony/symfony/blob/3.3/src/Symfony/Component/Routing/Matcher/UrlMatcher.php#L91.
  283.      *
  284.      * @param string $pathInfo
  285.      *
  286.      * @return string
  287.      */
  288.     private function decodePathInfo($pathInfo)
  289.     {
  290.         if (null === $pathInfo || '' === $pathInfo) {
  291.             return '';
  292.         }
  293.         return '/' \ltrim(\rawurldecode($pathInfo), '/');
  294.     }
  295. }