1: <?php
2:
3: 4: 5: 6: 7: 8: 9: 10:
11:
12: namespace Symfony\Component\Routing;
13:
14: use Symfony\Component\Config\Loader\LoaderInterface;
15: use Symfony\Component\Config\ConfigCacheInterface;
16: use Symfony\Component\Config\ConfigCacheFactoryInterface;
17: use Symfony\Component\Config\ConfigCacheFactory;
18: use Psr\Log\LoggerInterface;
19: use Symfony\Component\Routing\Generator\ConfigurableRequirementsInterface;
20: use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
21: use Symfony\Component\Routing\Generator\Dumper\GeneratorDumperInterface;
22: use Symfony\Component\Routing\Matcher\RequestMatcherInterface;
23: use Symfony\Component\Routing\Matcher\UrlMatcherInterface;
24: use Symfony\Component\Routing\Matcher\Dumper\MatcherDumperInterface;
25: use Symfony\Component\HttpFoundation\Request;
26: use Symfony\Component\ExpressionLanguage\ExpressionFunctionProviderInterface;
27:
28: 29: 30: 31: 32: 33:
34: class Router implements RouterInterface, RequestMatcherInterface
35: {
36: 37: 38:
39: protected $matcher;
40:
41: 42: 43:
44: protected $generator;
45:
46: 47: 48:
49: protected $context;
50:
51: 52: 53:
54: protected $loader;
55:
56: 57: 58:
59: protected $collection;
60:
61: 62: 63:
64: protected $resource;
65:
66: 67: 68:
69: protected $options = array();
70:
71: 72: 73:
74: protected $logger;
75:
76: 77: 78:
79: private $configCacheFactory;
80:
81: 82: 83:
84: private $expressionLanguageProviders = array();
85:
86: 87: 88: 89: 90: 91: 92: 93: 94:
95: public function __construct(LoaderInterface $loader, $resource, array $options = array(), RequestContext $context = null, LoggerInterface $logger = null)
96: {
97: $this->loader = $loader;
98: $this->resource = $resource;
99: $this->logger = $logger;
100: $this->context = $context ?: new RequestContext();
101: $this->setOptions($options);
102: }
103:
104: 105: 106: 107: 108: 109: 110: 111: 112: 113: 114: 115: 116: 117: 118: 119: 120: 121: 122: 123: 124: 125: 126:
127: public function setOptions(array $options)
128: {
129: $this->options = array(
130: 'cache_dir' => null,
131: 'debug' => false,
132: 'generator_class' => 'Symfony\\Component\\Routing\\Generator\\UrlGenerator',
133: 'generator_base_class' => 'Symfony\\Component\\Routing\\Generator\\UrlGenerator',
134: 'generator_dumper_class' => 'Symfony\\Component\\Routing\\Generator\\Dumper\\PhpGeneratorDumper',
135: 'generator_cache_class' => 'ProjectUrlGenerator',
136: 'matcher_class' => 'Symfony\\Component\\Routing\\Matcher\\UrlMatcher',
137: 'matcher_base_class' => 'Symfony\\Component\\Routing\\Matcher\\UrlMatcher',
138: 'matcher_dumper_class' => 'Symfony\\Component\\Routing\\Matcher\\Dumper\\PhpMatcherDumper',
139: 'matcher_cache_class' => 'ProjectUrlMatcher',
140: 'resource_type' => null,
141: 'strict_requirements' => true,
142: );
143:
144:
145: $invalid = array();
146: foreach ($options as $key => $value) {
147: if (array_key_exists($key, $this->options)) {
148: $this->options[$key] = $value;
149: } else {
150: $invalid[] = $key;
151: }
152: }
153:
154: if ($invalid) {
155: throw new \InvalidArgumentException(sprintf('The Router does not support the following options: "%s".', implode('", "', $invalid)));
156: }
157: }
158:
159: 160: 161: 162: 163: 164: 165: 166:
167: public function setOption($key, $value)
168: {
169: if (!array_key_exists($key, $this->options)) {
170: throw new \InvalidArgumentException(sprintf('The Router does not support the "%s" option.', $key));
171: }
172:
173: $this->options[$key] = $value;
174: }
175:
176: 177: 178: 179: 180: 181: 182: 183: 184:
185: public function getOption($key)
186: {
187: if (!array_key_exists($key, $this->options)) {
188: throw new \InvalidArgumentException(sprintf('The Router does not support the "%s" option.', $key));
189: }
190:
191: return $this->options[$key];
192: }
193:
194: 195: 196:
197: public function getRouteCollection()
198: {
199: if (null === $this->collection) {
200: $this->collection = $this->loader->load($this->resource, $this->options['resource_type']);
201: }
202:
203: return $this->collection;
204: }
205:
206: 207: 208:
209: public function setContext(RequestContext $context)
210: {
211: $this->context = $context;
212:
213: if (null !== $this->matcher) {
214: $this->getMatcher()->setContext($context);
215: }
216: if (null !== $this->generator) {
217: $this->getGenerator()->setContext($context);
218: }
219: }
220:
221: 222: 223:
224: public function getContext()
225: {
226: return $this->context;
227: }
228:
229: 230: 231: 232: 233:
234: public function setConfigCacheFactory(ConfigCacheFactoryInterface $configCacheFactory)
235: {
236: $this->configCacheFactory = $configCacheFactory;
237: }
238:
239: 240: 241:
242: public function generate($name, $parameters = array(), $referenceType = self::ABSOLUTE_PATH)
243: {
244: return $this->getGenerator()->generate($name, $parameters, $referenceType);
245: }
246:
247: 248: 249:
250: public function match($pathinfo)
251: {
252: return $this->getMatcher()->match($pathinfo);
253: }
254:
255: 256: 257:
258: public function matchRequest(Request $request)
259: {
260: $matcher = $this->getMatcher();
261: if (!$matcher instanceof RequestMatcherInterface) {
262:
263: return $matcher->match($request->getPathInfo());
264: }
265:
266: return $matcher->matchRequest($request);
267: }
268:
269: 270: 271: 272: 273:
274: public function getMatcher()
275: {
276: if (null !== $this->matcher) {
277: return $this->matcher;
278: }
279:
280: if (null === $this->options['cache_dir'] || null === $this->options['matcher_cache_class']) {
281: $this->matcher = new $this->options['matcher_class']($this->getRouteCollection(), $this->context);
282: if (method_exists($this->matcher, 'addExpressionLanguageProvider')) {
283: foreach ($this->expressionLanguageProviders as $provider) {
284: $this->matcher->addExpressionLanguageProvider($provider);
285: }
286: }
287:
288: return $this->matcher;
289: }
290:
291: $class = $this->options['matcher_cache_class'];
292: $baseClass = $this->options['matcher_base_class'];
293: $expressionLanguageProviders = $this->expressionLanguageProviders;
294: $that = $this;
295:
296: $cache = $this->getConfigCacheFactory()->cache($this->options['cache_dir'].'/'.$class.'.php',
297: function (ConfigCacheInterface $cache) use ($that, $class, $baseClass, $expressionLanguageProviders) {
298: $dumper = $that->getMatcherDumperInstance();
299: if (method_exists($dumper, 'addExpressionLanguageProvider')) {
300: foreach ($expressionLanguageProviders as $provider) {
301: $dumper->addExpressionLanguageProvider($provider);
302: }
303: }
304:
305: $options = array(
306: 'class' => $class,
307: 'base_class' => $baseClass,
308: );
309:
310: $cache->write($dumper->dump($options), $that->getRouteCollection()->getResources());
311: }
312: );
313:
314: require_once $cache->getPath();
315:
316: return $this->matcher = new $class($this->context);
317: }
318:
319: 320: 321: 322: 323:
324: public function getGenerator()
325: {
326: if (null !== $this->generator) {
327: return $this->generator;
328: }
329:
330: if (null === $this->options['cache_dir'] || null === $this->options['generator_cache_class']) {
331: $this->generator = new $this->options['generator_class']($this->getRouteCollection(), $this->context, $this->logger);
332: } else {
333: $class = $this->options['generator_cache_class'];
334: $baseClass = $this->options['generator_base_class'];
335: $that = $this;
336: $cache = $this->getConfigCacheFactory()->cache($this->options['cache_dir'].'/'.$class.'.php',
337: function (ConfigCacheInterface $cache) use ($that, $class, $baseClass) {
338: $dumper = $that->getGeneratorDumperInstance();
339:
340: $options = array(
341: 'class' => $class,
342: 'base_class' => $baseClass,
343: );
344:
345: $cache->write($dumper->dump($options), $that->getRouteCollection()->getResources());
346: }
347: );
348:
349: require_once $cache->getPath();
350:
351: $this->generator = new $class($this->context, $this->logger);
352: }
353:
354: if ($this->generator instanceof ConfigurableRequirementsInterface) {
355: $this->generator->setStrictRequirements($this->options['strict_requirements']);
356: }
357:
358: return $this->generator;
359: }
360:
361: public function addExpressionLanguageProvider(ExpressionFunctionProviderInterface $provider)
362: {
363: $this->expressionLanguageProviders[] = $provider;
364: }
365:
366: 367: 368: 369: 370: 371: 372:
373: public function getGeneratorDumperInstance()
374: {
375: return new $this->options['generator_dumper_class']($this->getRouteCollection());
376: }
377:
378: 379: 380: 381: 382: 383: 384:
385: public function getMatcherDumperInstance()
386: {
387: return new $this->options['matcher_dumper_class']($this->getRouteCollection());
388: }
389:
390: 391: 392: 393: 394: 395:
396: private function getConfigCacheFactory()
397: {
398: if (null === $this->configCacheFactory) {
399: $this->configCacheFactory = new ConfigCacheFactory($this->options['debug']);
400: }
401:
402: return $this->configCacheFactory;
403: }
404: }
405: