<?php
declare(strict_types=1);
namespace Hitso\Bundle\RoutingBundle\Provider;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Persistence\ManagerRegistry;
use Doctrine\Common\Util\ClassUtils;
use Doctrine\Common\Util\Debug;
use Hitso\Bundle\MultiSiteBundle\MultiSite\SiteCollection;
use Hitso\Bundle\MultiSiteBundle\MultiSite\SiteContext;
use Hitso\Bundle\RoutingBundle\Entity\Route;
use Symfony\Cmf\Component\Routing\RouteProviderInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Route as SymfonyRoute;
use Symfony\Component\Routing\RouteCollection;
class RouteProvider implements RouteProviderInterface
{
const DYNAMIC_PREFIX = 'dynamic_';
const PATH_PARAMS_SEPARATOR = ',';
/**
* @var ManagerRegistry
*/
private $managerRegistry;
/**
* @var \Hitso\Bundle\MultiSiteBundle\MultiSite\SiteCollection
*/
private $sites;
/**
* @var array
*/
private $routingGeneratorMap;
/**
* @var SiteContext
*/
private $context;
public function __construct(
ManagerRegistry $managerRegistry,
array $routingGeneratorMap = [],
SiteCollection $sites,
SiteContext $context
) {
$this->managerRegistry = $managerRegistry;
$this->routingGeneratorMap = $routingGeneratorMap;
$this->sites = $sites;
$this->context = $context;
}
/**
* {@inheritdoc}
*/
public function getRouteCollectionForRequest(Request $request)
{
$collection = new RouteCollection();
$repository = $this->getRouteRepository();
$path = $this->getNormalizedPath($request);
$siteId = $this->context->getContentSite()->getId();
$resource = $repository->findOneBy(['path' => $path, 'siteId' => $siteId]);
if ($resource instanceof Route) {
$route = $this->createRoute($resource);
$collection->add(
self::DYNAMIC_PREFIX . $resource->getId(),
$route
);
}
return $collection;
}
private function createRoute(Route $resource): SymfonyRoute
{
$settings = $this->getRouteGenerationSettings($resource);
$settings['defaults']['id'] = $resource->getIdentifier()->getId();
$site = $this->sites->get($resource->getSiteId());
$settings['defaults']['_locale'] = $site->getLocale();
return new SymfonyRoute(
$this->getPath($resource, $settings['pattern']),
$settings['defaults'],
$settings['requirements'],
$settings['options'],
$site->getHost()
);
}
public function getRouteByName($identifier)
{
$id = str_replace(self::DYNAMIC_PREFIX, '', $identifier);
$resource = $this->getRouteRepository()->find($id);
if ($resource instanceof Route) {
return $this->createRoute($resource);
}
return null;
}
public function getRoutesByNames($names, $parameters = [])
{
return new ArrayCollection();
}
protected function getRouteRepository()
{
return $this->managerRegistry->getRepository(Route::class);
}
private function getRouteGenerationSettings(Route $resource): array
{
$class = ClassUtils::getRealClass(get_class($resource));
if (!isset($this->routingGeneratorMap[$class])) {
throw new \InvalidArgumentException(
sprintf('Route resource of type "%s" has invalid/missing configuration.', $class)
);
}
return $this->routingGeneratorMap[$class];
}
private function getNormalizedPath(Request $request)
{
$path = ltrim($request->getPathInfo(), '/');
$paths = explode(self::PATH_PARAMS_SEPARATOR, $path);
return current($paths);
}
private function getPath(Route $resource, string $pattern): string
{
if (strlen($pattern)) {
return $resource->getPath() . self::PATH_PARAMS_SEPARATOR . $pattern;
}
return $resource->getPath();
}
}