]>
Commit | Line | Data |
---|---|---|
4f5b44bd NL |
1 | <?php |
2 | ||
3 | /* | |
4 | * This file is part of the Symfony package. | |
5 | * | |
6 | * (c) Fabien Potencier <fabien@symfony.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 | ||
12 | namespace Symfony\Component\Routing; | |
13 | ||
14 | use Symfony\Component\Config\Loader\LoaderInterface; | |
15 | use Symfony\Component\Config\ConfigCache; | |
16 | use Psr\Log\LoggerInterface; | |
17 | use Symfony\Component\Routing\Generator\ConfigurableRequirementsInterface; | |
18 | use Symfony\Component\Routing\Generator\UrlGeneratorInterface; | |
19 | use Symfony\Component\Routing\Matcher\UrlMatcherInterface; | |
20 | ||
21 | /** | |
22 | * The Router class is an example of the integration of all pieces of the | |
23 | * routing system for easier use. | |
24 | * | |
25 | * @author Fabien Potencier <fabien@symfony.com> | |
26 | */ | |
27 | class Router implements RouterInterface | |
28 | { | |
29 | /** | |
30 | * @var UrlMatcherInterface|null | |
31 | */ | |
32 | protected $matcher; | |
33 | ||
34 | /** | |
35 | * @var UrlGeneratorInterface|null | |
36 | */ | |
37 | protected $generator; | |
38 | ||
39 | /** | |
40 | * @var RequestContext | |
41 | */ | |
42 | protected $context; | |
43 | ||
44 | /** | |
45 | * @var LoaderInterface | |
46 | */ | |
47 | protected $loader; | |
48 | ||
49 | /** | |
50 | * @var RouteCollection|null | |
51 | */ | |
52 | protected $collection; | |
53 | ||
54 | /** | |
55 | * @var mixed | |
56 | */ | |
57 | protected $resource; | |
58 | ||
59 | /** | |
60 | * @var array | |
61 | */ | |
62 | protected $options = array(); | |
63 | ||
64 | /** | |
65 | * @var LoggerInterface|null | |
66 | */ | |
67 | protected $logger; | |
68 | ||
69 | /** | |
70 | * Constructor. | |
71 | * | |
72 | * @param LoaderInterface $loader A LoaderInterface instance | |
73 | * @param mixed $resource The main resource to load | |
74 | * @param array $options An array of options | |
75 | * @param RequestContext $context The context | |
76 | * @param LoggerInterface $logger A logger instance | |
77 | */ | |
78 | public function __construct(LoaderInterface $loader, $resource, array $options = array(), RequestContext $context = null, LoggerInterface $logger = null) | |
79 | { | |
80 | $this->loader = $loader; | |
81 | $this->resource = $resource; | |
82 | $this->logger = $logger; | |
83 | $this->context = null === $context ? new RequestContext() : $context; | |
84 | $this->setOptions($options); | |
85 | } | |
86 | ||
87 | /** | |
88 | * Sets options. | |
89 | * | |
90 | * Available options: | |
91 | * | |
92 | * * cache_dir: The cache directory (or null to disable caching) | |
93 | * * debug: Whether to enable debugging or not (false by default) | |
94 | * * resource_type: Type hint for the main resource (optional) | |
95 | * | |
96 | * @param array $options An array of options | |
97 | * | |
98 | * @throws \InvalidArgumentException When unsupported option is provided | |
99 | */ | |
100 | public function setOptions(array $options) | |
101 | { | |
102 | $this->options = array( | |
103 | 'cache_dir' => null, | |
104 | 'debug' => false, | |
105 | 'generator_class' => 'Symfony\\Component\\Routing\\Generator\\UrlGenerator', | |
106 | 'generator_base_class' => 'Symfony\\Component\\Routing\\Generator\\UrlGenerator', | |
107 | 'generator_dumper_class' => 'Symfony\\Component\\Routing\\Generator\\Dumper\\PhpGeneratorDumper', | |
108 | 'generator_cache_class' => 'ProjectUrlGenerator', | |
109 | 'matcher_class' => 'Symfony\\Component\\Routing\\Matcher\\UrlMatcher', | |
110 | 'matcher_base_class' => 'Symfony\\Component\\Routing\\Matcher\\UrlMatcher', | |
111 | 'matcher_dumper_class' => 'Symfony\\Component\\Routing\\Matcher\\Dumper\\PhpMatcherDumper', | |
112 | 'matcher_cache_class' => 'ProjectUrlMatcher', | |
113 | 'resource_type' => null, | |
114 | 'strict_requirements' => true, | |
115 | ); | |
116 | ||
117 | // check option names and live merge, if errors are encountered Exception will be thrown | |
118 | $invalid = array(); | |
119 | foreach ($options as $key => $value) { | |
120 | if (array_key_exists($key, $this->options)) { | |
121 | $this->options[$key] = $value; | |
122 | } else { | |
123 | $invalid[] = $key; | |
124 | } | |
125 | } | |
126 | ||
127 | if ($invalid) { | |
128 | throw new \InvalidArgumentException(sprintf('The Router does not support the following options: "%s".', implode('", "', $invalid))); | |
129 | } | |
130 | } | |
131 | ||
132 | /** | |
133 | * Sets an option. | |
134 | * | |
135 | * @param string $key The key | |
136 | * @param mixed $value The value | |
137 | * | |
138 | * @throws \InvalidArgumentException | |
139 | */ | |
140 | public function setOption($key, $value) | |
141 | { | |
142 | if (!array_key_exists($key, $this->options)) { | |
143 | throw new \InvalidArgumentException(sprintf('The Router does not support the "%s" option.', $key)); | |
144 | } | |
145 | ||
146 | $this->options[$key] = $value; | |
147 | } | |
148 | ||
149 | /** | |
150 | * Gets an option value. | |
151 | * | |
152 | * @param string $key The key | |
153 | * | |
154 | * @return mixed The value | |
155 | * | |
156 | * @throws \InvalidArgumentException | |
157 | */ | |
158 | public function getOption($key) | |
159 | { | |
160 | if (!array_key_exists($key, $this->options)) { | |
161 | throw new \InvalidArgumentException(sprintf('The Router does not support the "%s" option.', $key)); | |
162 | } | |
163 | ||
164 | return $this->options[$key]; | |
165 | } | |
166 | ||
167 | /** | |
168 | * {@inheritdoc} | |
169 | */ | |
170 | public function getRouteCollection() | |
171 | { | |
172 | if (null === $this->collection) { | |
173 | $this->collection = $this->loader->load($this->resource, $this->options['resource_type']); | |
174 | } | |
175 | ||
176 | return $this->collection; | |
177 | } | |
178 | ||
179 | /** | |
180 | * {@inheritdoc} | |
181 | */ | |
182 | public function setContext(RequestContext $context) | |
183 | { | |
184 | $this->context = $context; | |
185 | ||
186 | if (null !== $this->matcher) { | |
187 | $this->getMatcher()->setContext($context); | |
188 | } | |
189 | if (null !== $this->generator) { | |
190 | $this->getGenerator()->setContext($context); | |
191 | } | |
192 | } | |
193 | ||
194 | /** | |
195 | * {@inheritdoc} | |
196 | */ | |
197 | public function getContext() | |
198 | { | |
199 | return $this->context; | |
200 | } | |
201 | ||
202 | /** | |
203 | * {@inheritdoc} | |
204 | */ | |
205 | public function generate($name, $parameters = array(), $referenceType = self::ABSOLUTE_PATH) | |
206 | { | |
207 | return $this->getGenerator()->generate($name, $parameters, $referenceType); | |
208 | } | |
209 | ||
210 | /** | |
211 | * {@inheritdoc} | |
212 | */ | |
213 | public function match($pathinfo) | |
214 | { | |
215 | return $this->getMatcher()->match($pathinfo); | |
216 | } | |
217 | ||
218 | /** | |
219 | * Gets the UrlMatcher instance associated with this Router. | |
220 | * | |
221 | * @return UrlMatcherInterface A UrlMatcherInterface instance | |
222 | */ | |
223 | public function getMatcher() | |
224 | { | |
225 | if (null !== $this->matcher) { | |
226 | return $this->matcher; | |
227 | } | |
228 | ||
229 | if (null === $this->options['cache_dir'] || null === $this->options['matcher_cache_class']) { | |
230 | return $this->matcher = new $this->options['matcher_class']($this->getRouteCollection(), $this->context); | |
231 | } | |
232 | ||
233 | $class = $this->options['matcher_cache_class']; | |
234 | $cache = new ConfigCache($this->options['cache_dir'].'/'.$class.'.php', $this->options['debug']); | |
235 | if (!$cache->isFresh($class)) { | |
236 | $dumper = new $this->options['matcher_dumper_class']($this->getRouteCollection()); | |
237 | ||
238 | $options = array( | |
239 | 'class' => $class, | |
240 | 'base_class' => $this->options['matcher_base_class'], | |
241 | ); | |
242 | ||
243 | $cache->write($dumper->dump($options), $this->getRouteCollection()->getResources()); | |
244 | } | |
245 | ||
246 | require_once $cache; | |
247 | ||
248 | return $this->matcher = new $class($this->context); | |
249 | } | |
250 | ||
251 | /** | |
252 | * Gets the UrlGenerator instance associated with this Router. | |
253 | * | |
254 | * @return UrlGeneratorInterface A UrlGeneratorInterface instance | |
255 | */ | |
256 | public function getGenerator() | |
257 | { | |
258 | if (null !== $this->generator) { | |
259 | return $this->generator; | |
260 | } | |
261 | ||
262 | if (null === $this->options['cache_dir'] || null === $this->options['generator_cache_class']) { | |
263 | $this->generator = new $this->options['generator_class']($this->getRouteCollection(), $this->context, $this->logger); | |
264 | } else { | |
265 | $class = $this->options['generator_cache_class']; | |
266 | $cache = new ConfigCache($this->options['cache_dir'].'/'.$class.'.php', $this->options['debug']); | |
267 | if (!$cache->isFresh($class)) { | |
268 | $dumper = new $this->options['generator_dumper_class']($this->getRouteCollection()); | |
269 | ||
270 | $options = array( | |
271 | 'class' => $class, | |
272 | 'base_class' => $this->options['generator_base_class'], | |
273 | ); | |
274 | ||
275 | $cache->write($dumper->dump($options), $this->getRouteCollection()->getResources()); | |
276 | } | |
277 | ||
278 | require_once $cache; | |
279 | ||
280 | $this->generator = new $class($this->context, $this->logger); | |
281 | } | |
282 | ||
283 | if ($this->generator instanceof ConfigurableRequirementsInterface) { | |
284 | $this->generator->setStrictRequirements($this->options['strict_requirements']); | |
285 | } | |
286 | ||
287 | return $this->generator; | |
288 | } | |
289 | } |