Router.php 8.3 KB

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