vendor/friendsofsymfony/jsrouting-bundle/Extractor/ExposedRoutesExtractor.php line 50

Open in your IDE?
  1. <?php
  2. declare(strict_types=1);
  3. /*
  4.  * This file is part of the FOSJsRoutingBundle package.
  5.  *
  6.  * (c) FriendsOfSymfony <http://friendsofsymfony.github.com/>
  7.  *
  8.  * For the full copyright and license information, please view the LICENSE
  9.  * file that was distributed with this source code.
  10.  */
  11. namespace FOS\JsRoutingBundle\Extractor;
  12. use JMS\I18nRoutingBundle\Router\I18nLoader;
  13. use Symfony\Component\Routing\Route;
  14. use Symfony\Component\Routing\RouteCollection;
  15. use Symfony\Component\Routing\RouterInterface;
  16. /**
  17.  * @author      William DURAND <william.durand1@gmail.com>
  18.  */
  19. class ExposedRoutesExtractor implements ExposedRoutesExtractorInterface
  20. {
  21.     protected string $pattern;
  22.     protected array $availableDomains;
  23.     /**
  24.      * Default constructor.
  25.      *
  26.      * @param array $routesToExpose some route names to expose
  27.      * @param array $bundles        list of loaded bundles to check when generating the prefix
  28.      *
  29.      * @throws \Exception
  30.      */
  31.     public function __construct(private RouterInterface $router, array $routesToExpose, private string $cacheDir, private array $bundles = [])
  32.     {
  33.         $domainPatterns $this->extractDomainPatterns($routesToExpose);
  34.         $this->availableDomains array_keys($domainPatterns);
  35.         $this->pattern $this->buildPattern($domainPatterns);
  36.     }
  37.     /**
  38.      * {@inheritDoc}
  39.      */
  40.     public function getRoutes(): RouteCollection
  41.     {
  42.         $collection $this->router->getRouteCollection();
  43.         $routes = new RouteCollection();
  44.         /** @var Route $route */
  45.         foreach ($collection->all() as $name => $route) {
  46.             if ($route->hasOption('expose')) {
  47.                 $expose $route->getOption('expose');
  48.                 if (false !== $expose && 'false' !== $expose) {
  49.                     $routes->add($name$route);
  50.                 }
  51.                 continue;
  52.             }
  53.             preg_match('#^'.$this->pattern.'$#'$name$matches);
  54.             if (=== count($matches)) {
  55.                 continue;
  56.             }
  57.             $domain $this->getDomainByRouteMatches($matches$name);
  58.             if (is_null($domain)) {
  59.                 continue;
  60.             }
  61.             $route = clone $route;
  62.             $route->setOption('expose'$domain);
  63.             $routes->add($name$route);
  64.         }
  65.         return $routes;
  66.     }
  67.     /**
  68.      * {@inheritDoc}
  69.      */
  70.     public function getBaseUrl(): string
  71.     {
  72.         return $this->router->getContext()->getBaseUrl() ?: '';
  73.     }
  74.     /**
  75.      * {@inheritDoc}
  76.      */
  77.     public function getPrefix(string $locale): string
  78.     {
  79.         if (isset($this->bundles['JMSI18nRoutingBundle'])) {
  80.             return $locale.I18nLoader::ROUTING_PREFIX;
  81.         }
  82.         return '';
  83.     }
  84.     /**
  85.      * {@inheritDoc}
  86.      */
  87.     public function getHost(): string
  88.     {
  89.         $requestContext $this->router->getContext();
  90.         $host $requestContext->getHost().
  91.             ('' === $this->getPort() ? $this->getPort() : ':'.$this->getPort());
  92.         return $host;
  93.     }
  94.     /**
  95.      * {@inheritDoc}
  96.      */
  97.     public function getPort(): ?string
  98.     {
  99.         $requestContext $this->router->getContext();
  100.         $port '';
  101.         if ($this->usesNonStandardPort()) {
  102.             $method sprintf('get%sPort'ucfirst($requestContext->getScheme()));
  103.             $port = (string) $requestContext->$method();
  104.         }
  105.         return $port;
  106.     }
  107.     /**
  108.      * {@inheritDoc}
  109.      */
  110.     public function getScheme(): string
  111.     {
  112.         return $this->router->getContext()->getScheme();
  113.     }
  114.     /**
  115.      * {@inheritDoc}
  116.      */
  117.     public function getCachePath(string $locale null): string
  118.     {
  119.         $cachePath $this->cacheDir.DIRECTORY_SEPARATOR.'fosJsRouting';
  120.         if (!file_exists($cachePath)) {
  121.             if (false === @mkdir($cachePath)) {
  122.                 throw new \RuntimeException('Unable to create Cache directory ' $cachePath);
  123.             }
  124.         }
  125.         if (isset($this->bundles['JMSI18nRoutingBundle'])) {
  126.             $cachePath $cachePath.DIRECTORY_SEPARATOR.'data.'.$locale.'.json';
  127.         } else {
  128.             $cachePath $cachePath.DIRECTORY_SEPARATOR.'data.json';
  129.         }
  130.         return $cachePath;
  131.     }
  132.     /**
  133.      * {@inheritDoc}
  134.      */
  135.     public function getResources(): array
  136.     {
  137.         return $this->router->getRouteCollection()->getResources();
  138.     }
  139.     /**
  140.      * {@inheritDoc}
  141.      */
  142.     public function isRouteExposed(Route $route$name): bool
  143.     {
  144.         if (false === $route->hasOption('expose')) {
  145.             return '' !== $this->pattern && preg_match('#^'.$this->pattern.'$#'$name);
  146.         }
  147.         $status $route->getOption('expose');
  148.         return false !== $status && 'false' !== $status;
  149.     }
  150.     protected function getDomainByRouteMatches($matches$name): int|string|null
  151.     {
  152.         $matches array_filter($matches, fn ($match) => !empty($match));
  153.         $matches array_flip(array_intersect_key($matchesarray_flip($this->availableDomains)));
  154.         return $matches[$name] ?? null;
  155.     }
  156.     protected function extractDomainPatterns($routesToExpose): array
  157.     {
  158.         $domainPatterns = [];
  159.         foreach ($routesToExpose as $item) {
  160.             if (is_string($item)) {
  161.                 $domainPatterns['default'][] = $item;
  162.                 continue;
  163.             }
  164.             if (is_array($item) && is_string($item['pattern'])) {
  165.                 if (!isset($item['domain'])) {
  166.                     $domainPatterns['default'][] = $item['pattern'];
  167.                     continue;
  168.                 } elseif (is_string($item['domain'])) {
  169.                     $domainPatterns[$item['domain']][] = $item['pattern'];
  170.                     continue;
  171.                 }
  172.             }
  173.             throw new \Exception('routes_to_expose definition is invalid');
  174.         }
  175.         return $domainPatterns;
  176.     }
  177.     /**
  178.      * Convert the routesToExpose array in a regular expression pattern.
  179.      *
  180.      * @throws \Exception
  181.      */
  182.     protected function buildPattern(array $domainPatterns): string
  183.     {
  184.         $patterns = [];
  185.         foreach ($domainPatterns as $domain => $items) {
  186.             $patterns[] = '(?P<'.$domain.'>'.implode('|'$items).')';
  187.         }
  188.         return implode('|'$patterns);
  189.     }
  190.     /**
  191.      * Check whether server is serving this request from a non-standard port.
  192.      */
  193.     private function usesNonStandardPort(): bool
  194.     {
  195.         return $this->usesNonStandardHttpPort() || $this->usesNonStandardHttpsPort();
  196.     }
  197.     /**
  198.      * Check whether server is serving HTTP over a non-standard port.
  199.      */
  200.     private function usesNonStandardHttpPort(): bool
  201.     {
  202.         return 'http' === $this->getScheme() && '80' != $this->router->getContext()->getHttpPort();
  203.     }
  204.     /**
  205.      * Check whether server is serving HTTPS over a non-standard port.
  206.      */
  207.     private function usesNonStandardHttpsPort(): bool
  208.     {
  209.         return 'https' === $this->getScheme() && '443' != $this->router->getContext()->getHttpsPort();
  210.     }
  211. }