diff options
Diffstat (limited to 'phpBB/phpbb/routing/router.php')
| -rw-r--r-- | phpBB/phpbb/routing/router.php | 406 | 
1 files changed, 406 insertions, 0 deletions
| diff --git a/phpBB/phpbb/routing/router.php b/phpBB/phpbb/routing/router.php new file mode 100644 index 0000000000..5d237b6433 --- /dev/null +++ b/phpBB/phpbb/routing/router.php @@ -0,0 +1,406 @@ +<?php +/** +* +* This file is part of the phpBB Forum Software package. +* +* @copyright (c) phpBB Limited <https://www.phpbb.com> +* @license       GNU General Public License, version 2 (GPL-2.0) +* +* For full copyright and license information, please see +* the docs/CREDITS.txt file. +* +*/ + +namespace phpbb\routing; + +use phpbb\routing\resources_locator\resources_locator_interface; +use Symfony\Component\Config\ConfigCache; +use Symfony\Component\Config\Loader\LoaderInterface; +use Symfony\Component\DependencyInjection\ContainerInterface; +use Symfony\Component\DependencyInjection\Exception\ParameterNotFoundException; +use Symfony\Component\DependencyInjection\Exception\RuntimeException; +use Symfony\Component\Filesystem\Exception\IOException; +use Symfony\Component\Routing\Generator\Dumper\PhpGeneratorDumper; +use Symfony\Component\Routing\Generator\UrlGenerator; +use Symfony\Component\Routing\Matcher\Dumper\PhpMatcherDumper; +use Symfony\Component\Routing\Matcher\UrlMatcher; +use Symfony\Component\Routing\RequestContext; +use Symfony\Component\Routing\RouteCollection; +use Symfony\Component\Routing\RouterInterface; + +/** + * Integration of all pieces of the routing system for easier use. + */ +class router implements RouterInterface +{ +	/** +	 * @var ContainerInterface +	 */ +	protected $container; + +	/** +	 * @var resources_locator_interface +	 */ +	protected $resources_locator; + +	/** +	 * @var LoaderInterface +	 */ +	protected $loader; + +	/** +	 * phpBB root path +	 * +	 * @var string +	 */ +	protected $phpbb_root_path; + +	/** +	 * PHP file extensions +	 * +	 * @var string +	 */ +	protected $php_ext; + +	/** +	 * Name of the current environment +	 * +	 * @var string +	 */ +	protected $environment; + +	/** +	 * @var \Symfony\Component\Routing\Matcher\UrlMatcherInterface|null +	 */ +	protected $matcher; + +	/** +	 * @var \Symfony\Component\Routing\Generator\UrlGeneratorInterface|null +	 */ +	protected $generator; + +	/** +	 * @var RequestContext +	 */ +	protected $context; + +	/** +	 * @var RouteCollection +	 */ +	protected $route_collection; + +	/** +	 * Construct method +	 * +	 * @param ContainerInterface			$container			DI container +	 * @param resources_locator_interface	$resources_locator	Resources locator +	 * @param LoaderInterface				$loader				Resources loader +	 * @param string						$phpbb_root_path	phpBB root path +	 * @param string						$php_ext			PHP file extension +	 * @param string						$environment		Name of the current environment +	 */ +	public function __construct(ContainerInterface $container, resources_locator_interface $resources_locator, LoaderInterface $loader, $phpbb_root_path, $php_ext, $environment) +	{ +		$this->container			= $container; +		$this->resources_locator	= $resources_locator; +		$this->loader				= $loader; +		$this->phpbb_root_path		= $phpbb_root_path; +		$this->php_ext				= $php_ext; +		$this->environment			= $environment; +		$this->context				= new RequestContext(); +	} + +	/** +	 * Get the list of routes +	 * +	 * @return RouteCollection Get the route collection +	 */ +	public function get_routes() +	{ +		if ($this->route_collection === null /*|| $this->route_collection->count() === 0*/) +		{ +			$this->route_collection = new RouteCollection; +			foreach ($this->resources_locator->locate_resources() as $resource) +			{ +				if (is_array($resource)) +				{ +					$this->route_collection->addCollection($this->loader->load($resource[0], $resource[1])); +				} +				else +				{ +					$this->route_collection->addCollection($this->loader->load($resource)); +				} +			} + +			$this->resolveParameters($this->route_collection); +		} + +		return $this->route_collection; +	} + +	/** +	 * {@inheritdoc} +	 */ +	public function getRouteCollection() +	{ +		return $this->get_routes(); +	} + +	/** +	 * {@inheritdoc} +	 */ +	public function setContext(RequestContext $context) +	{ +		$this->context = $context; + +		if ($this->matcher !== null) +		{ +			$this->get_matcher()->setContext($context); +		} +		if ($this->generator !== null) +		{ +			$this->get_generator()->setContext($context); +		} +	} + +	/** +	 * {@inheritdoc} +	 */ +	public function getContext() +	{ +		return $this->context; +	} + +	/** +	 * {@inheritdoc} +	 */ +	public function generate($name, $parameters = array(), $referenceType = self::ABSOLUTE_PATH) +	{ +		return $this->get_generator()->generate($name, $parameters, $referenceType); +	} + +	/** +	 * {@inheritdoc} +	 */ +	public function match($pathinfo) +	{ +		return $this->get_matcher()->match($pathinfo); +	} + +	/** +	 * Gets the UrlMatcher instance associated with this Router. +	 * +	 * @return \Symfony\Component\Routing\Matcher\UrlMatcherInterface A UrlMatcherInterface instance +	 */ +	public function get_matcher() +	{ +		if ($this->matcher !== null) +		{ +			return $this->matcher; +		} + +		$this->create_dumped_url_matcher(); + +		return $this->matcher; +	} + +	/** +	 * Creates a new dumped URL Matcher (dump it if necessary) +	 */ +	protected function create_dumped_url_matcher() +	{ +		try +		{ +			$cache = new ConfigCache("{$this->phpbb_root_path}cache/{$this->environment}/url_matcher.{$this->php_ext}", defined('DEBUG')); +			if (!$cache->isFresh()) +			{ +				$dumper = new PhpMatcherDumper($this->get_routes()); + +				$options = array( +					'class'      => 'phpbb_url_matcher', +					'base_class' => 'Symfony\\Component\\Routing\\Matcher\\UrlMatcher', +				); + +				$cache->write($dumper->dump($options), $this->get_routes()->getResources()); +			} + +			require_once($cache->getPath()); + +			$this->matcher = new \phpbb_url_matcher($this->context); +		} +		catch (IOException $e) +		{ +			$this->create_new_url_matcher(); +		} +	} + +	/** +	 * Creates a new URL Matcher +	 */ +	protected function create_new_url_matcher() +	{ +		$this->matcher = new UrlMatcher($this->get_routes(), $this->context); +	} + +	/** +	 * Gets the UrlGenerator instance associated with this Router. +	 * +	 * @return \Symfony\Component\Routing\Generator\UrlGeneratorInterface A UrlGeneratorInterface instance +	 */ +	public function get_generator() +	{ +		if ($this->generator !== null) +		{ +			return $this->generator; +		} + +		$this->create_dumped_url_generator(); + +		return $this->generator; +	} + +	/** +	 * Creates a new dumped URL Generator (dump it if necessary) +	 */ +	protected function create_dumped_url_generator() +	{ +		try +		{ +			$cache = new ConfigCache("{$this->phpbb_root_path}cache/{$this->environment}/url_generator.{$this->php_ext}", defined('DEBUG')); +			if (!$cache->isFresh()) +			{ +				$dumper = new PhpGeneratorDumper($this->get_routes()); + +				$options = array( +					'class'      => 'phpbb_url_generator', +					'base_class' => 'Symfony\\Component\\Routing\\Generator\\UrlGenerator', +				); + +				$cache->write($dumper->dump($options), $this->get_routes()->getResources()); +			} + +			require_once($cache->getPath()); + +			$this->generator = new \phpbb_url_generator($this->context); +		} +		catch (IOException $e) +		{ +			$this->create_new_url_generator(); +		} +	} + +	/** +	 * Creates a new URL Generator +	 */ +	protected function create_new_url_generator() +	{ +		$this->generator = new UrlGenerator($this->get_routes(), $this->context); +	} + +	/** +	 * Replaces placeholders with service container parameter values in: +	 * - the route defaults, +	 * - the route requirements, +	 * - the route path, +	 * - the route host, +	 * - the route schemes, +	 * - the route methods. +	 * +	 * @param RouteCollection $collection +	 */ +	protected function resolveParameters(RouteCollection $collection) +	{ +		/** @var \Symfony\Component\Routing\Route $route */ +		foreach ($collection as $route) +		{ +			foreach ($route->getDefaults() as $name => $value) +			{ +				$route->setDefault($name, $this->resolve($value)); +			} + +			$requirements = $route->getRequirements(); +			unset($requirements['_scheme']); +			unset($requirements['_method']); + +			foreach ($requirements as $name => $value) +			{ +				$route->setRequirement($name, $this->resolve($value)); +			} + +			$route->setPath($this->resolve($route->getPath())); +			$route->setHost($this->resolve($route->getHost())); + +			$schemes = array(); +			foreach ($route->getSchemes() as $scheme) +			{ +				$schemes = array_merge($schemes, explode('|', $this->resolve($scheme))); +			} + +			$route->setSchemes($schemes); +			$methods = array(); +			foreach ($route->getMethods() as $method) +			{ +				$methods = array_merge($methods, explode('|', $this->resolve($method))); +			} + +			$route->setMethods($methods); +			$route->setCondition($this->resolve($route->getCondition())); +		} +	} + +	/** +	 * Recursively replaces placeholders with the service container parameters. +	 * +	 * @param mixed $value The source which might contain "%placeholders%" +	 * +	 * @return mixed The source with the placeholders replaced by the container +	 *               parameters. Arrays are resolved recursively. +	 * +	 * @throws ParameterNotFoundException When a placeholder does not exist as a container parameter +	 * @throws RuntimeException           When a container value is not a string or a numeric value +	 */ +	private function resolve($value) +	{ +		if (is_array($value)) +		{ +			foreach ($value as $key => $val) +			{ +				$value[$key] = $this->resolve($val); +			} + +			return $value; +		} + +		if (!is_string($value)) +		{ +			return $value; +		} + +		$container = $this->container; +		$escapedValue = preg_replace_callback('/%%|%([^%\s]++)%/', function ($match) use ($container, $value) +		{ +			// skip %% +			if (!isset($match[1])) +			{ +				return '%%'; +			} + +			$resolved = $container->getParameter($match[1]); +			if (is_string($resolved) || is_numeric($resolved)) +			{ +				return (string) $resolved; +			} + +			throw new RuntimeException(sprintf( +					'The container parameter "%s", used in the route configuration value "%s", '. +					'must be a string or numeric, but it is of type %s.', +					$match[1], +					$value, +					gettype($resolved) +				) +			); +		}, $value); + +		return str_replace('%%', '%', $escapedValue); +	} +} | 
