Router.php 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254
  1. <?php
  2. /*
  3. * This file is part of the Symfony package.
  4. *
  5. * (c) Fabien Potencier <fabien@symfony.com>
  6. *
  7. * For the full copyright and license information, please view the LICENSE
  8. * file that was distributed with this source code.
  9. */
  10. namespace Symfony\Component\Routing;
  11. use Symfony\Component\Config\Loader\LoaderInterface;
  12. use Symfony\Component\Config\ConfigCache;
  13. /**
  14. * The Router class is an example of the integration of all pieces of the
  15. * routing system for easier use.
  16. *
  17. * @author Fabien Potencier <fabien@symfony.com>
  18. */
  19. class Router implements RouterInterface
  20. {
  21. private $matcher;
  22. private $generator;
  23. private $defaults;
  24. private $context;
  25. private $loader;
  26. private $collection;
  27. private $resource;
  28. protected $options;
  29. /**
  30. * Constructor.
  31. *
  32. * Available options:
  33. *
  34. * * cache_dir: The cache directory (or null to disable caching)
  35. * * debug: Whether to enable debugging or not (false by default)
  36. * * resource_type: Type hint for the main resource (optional)
  37. *
  38. * @param LoaderInterface $loader A LoaderInterface instance
  39. * @param mixed $resource The main resource to load
  40. * @param array $options An array of options
  41. * @param RequestContext $context The context
  42. * @param array $defaults The default values
  43. *
  44. * @throws \InvalidArgumentException When unsupported option is provided
  45. */
  46. public function __construct(LoaderInterface $loader, $resource, array $options = array(), RequestContext $context = null, array $defaults = array())
  47. {
  48. $this->loader = $loader;
  49. $this->resource = $resource;
  50. $this->context = null === $context ? new RequestContext() : $context;
  51. $this->defaults = $defaults;
  52. $this->options = array(
  53. 'cache_dir' => null,
  54. 'debug' => false,
  55. 'generator_class' => 'Symfony\\Component\\Routing\\Generator\\UrlGenerator',
  56. 'generator_base_class' => 'Symfony\\Component\\Routing\\Generator\\UrlGenerator',
  57. 'generator_dumper_class' => 'Symfony\\Component\\Routing\\Generator\\Dumper\\PhpGeneratorDumper',
  58. 'generator_cache_class' => 'ProjectUrlGenerator',
  59. 'matcher_class' => 'Symfony\\Component\\Routing\\Matcher\\UrlMatcher',
  60. 'matcher_base_class' => 'Symfony\\Component\\Routing\\Matcher\\UrlMatcher',
  61. 'matcher_dumper_class' => 'Symfony\\Component\\Routing\\Matcher\\Dumper\\PhpMatcherDumper',
  62. 'matcher_cache_class' => 'ProjectUrlMatcher',
  63. 'resource_type' => null,
  64. );
  65. // check option names and live merge, if errors are encountered Exception will be thrown
  66. $invalid = array();
  67. $isInvalid = false;
  68. foreach ($options as $key => $value) {
  69. if (array_key_exists($key, $this->options)) {
  70. $this->options[$key] = $value;
  71. } else {
  72. $isInvalid = true;
  73. $invalid[] = $key;
  74. }
  75. }
  76. if ($isInvalid) {
  77. throw new \InvalidArgumentException(sprintf('The Router does not support the following options: "%s".', implode('\', \'', $invalid)));
  78. }
  79. }
  80. /**
  81. * Sets an option.
  82. *
  83. * @param string $key The key
  84. * @param mixed $value The value
  85. *
  86. * @throw \InvalidArgumentException
  87. */
  88. public function setOption($key, $value)
  89. {
  90. if (!array_key_exists($key, $this->options)) {
  91. throw new \InvalidArgumentException(sprintf('The Router does not support the "%s" option.', $key));
  92. }
  93. $this->options[$key] = $value;
  94. }
  95. /**
  96. * Gets an option value.
  97. *
  98. * @param string $key The key
  99. *
  100. * @return mixed The value
  101. *
  102. * @throw \InvalidArgumentException
  103. */
  104. public function getOption($key)
  105. {
  106. if (!array_key_exists($key, $this->options)) {
  107. throw new \InvalidArgumentException(sprintf('The Router does not support the "%s" option.', $key));
  108. }
  109. return $this->options[$key];
  110. }
  111. /**
  112. * Gets the RouteCollection instance associated with this Router.
  113. *
  114. * @return RouteCollection A RouteCollection instance
  115. */
  116. public function getRouteCollection()
  117. {
  118. if (null === $this->collection) {
  119. $this->collection = $this->loader->load($this->resource, $this->options['resource_type']);
  120. }
  121. return $this->collection;
  122. }
  123. /**
  124. * Sets the request context.
  125. *
  126. * @param RequestContext $context The context
  127. */
  128. public function setContext(RequestContext $context)
  129. {
  130. $this->context = $context;
  131. $this->getMatcher()->setContext($context);
  132. $this->getGenerator()->setContext($context);
  133. }
  134. /**
  135. * Gets the request context.
  136. *
  137. * @return RequestContext The context
  138. */
  139. public function getContext()
  140. {
  141. return $this->context;
  142. }
  143. /**
  144. * Generates a URL from the given parameters.
  145. *
  146. * @param string $name The name of the route
  147. * @param array $parameters An array of parameters
  148. * @param Boolean $absolute Whether to generate an absolute URL
  149. *
  150. * @return string The generated URL
  151. */
  152. public function generate($name, array $parameters = array(), $absolute = false)
  153. {
  154. return $this->getGenerator()->generate($name, $parameters, $absolute);
  155. }
  156. /**
  157. * Tries to match a URL with a set of routes.
  158. *
  159. * Returns false if no route matches the URL.
  160. *
  161. * @param string $url URL to be parsed
  162. *
  163. * @return array|false An array of parameters or false if no route matches
  164. */
  165. public function match($url)
  166. {
  167. return $this->getMatcher()->match($url);
  168. }
  169. /**
  170. * Gets the UrlMatcher instance associated with this Router.
  171. *
  172. * @return UrlMatcherInterface A UrlMatcherInterface instance
  173. */
  174. public function getMatcher()
  175. {
  176. if (null !== $this->matcher) {
  177. return $this->matcher;
  178. }
  179. if (null === $this->options['cache_dir'] || null === $this->options['matcher_cache_class']) {
  180. return $this->matcher = new $this->options['matcher_class']($this->getRouteCollection(), $this->context, $this->defaults);
  181. }
  182. $class = $this->options['matcher_cache_class'];
  183. $cache = new ConfigCache($this->options['cache_dir'].'/'.$class.'.php', $this->options['debug']);
  184. if (!$cache->isFresh($class)) {
  185. $dumper = new $this->options['matcher_dumper_class']($this->getRouteCollection());
  186. $options = array(
  187. 'class' => $class,
  188. 'base_class' => $this->options['matcher_base_class'],
  189. );
  190. $cache->write($dumper->dump($options), $this->getRouteCollection()->getResources());
  191. }
  192. require_once $cache;
  193. return $this->matcher = new $class($this->context, $this->defaults);
  194. }
  195. /**
  196. * Gets the UrlGenerator instance associated with this Router.
  197. *
  198. * @return UrlGeneratorInterface A UrlGeneratorInterface instance
  199. */
  200. public function getGenerator()
  201. {
  202. if (null !== $this->generator) {
  203. return $this->generator;
  204. }
  205. if (null === $this->options['cache_dir'] || null === $this->options['generator_cache_class']) {
  206. return $this->generator = new $this->options['generator_class']($this->getRouteCollection(), $this->context, $this->defaults);
  207. }
  208. $class = $this->options['generator_cache_class'];
  209. $cache = new ConfigCache($this->options['cache_dir'].'/'.$class.'.php', $this->options['debug']);
  210. if (!$cache->isFresh($class)) {
  211. $dumper = new $this->options['generator_dumper_class']($this->getRouteCollection());
  212. $options = array(
  213. 'class' => $class,
  214. 'base_class' => $this->options['generator_base_class'],
  215. );
  216. $cache->write($dumper->dump($options), $this->getRouteCollection()->getResources());
  217. }
  218. require_once $cache;
  219. return $this->generator = new $class($this->context, $this->defaults);
  220. }
  221. }