/vendor/symfony/symfony/src/Symfony/Bundle/FrameworkBundle/Routing/Router.php

https://github.com/nattaphat/hgis · PHP · 158 lines · 83 code · 26 blank · 49 comment · 7 complexity · 04678f6879452d110b5874ace0960fa3 MD5 · raw file

  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\Bundle\FrameworkBundle\Routing;
  11. use Symfony\Component\Routing\Router as BaseRouter;
  12. use Symfony\Component\Routing\RequestContext;
  13. use Symfony\Component\DependencyInjection\ContainerInterface;
  14. use Symfony\Component\Routing\RouteCollection;
  15. use Symfony\Component\HttpKernel\CacheWarmer\WarmableInterface;
  16. use Symfony\Component\DependencyInjection\Exception\ParameterNotFoundException;
  17. use Symfony\Component\DependencyInjection\Exception\RuntimeException;
  18. /**
  19. * This Router creates the Loader only when the cache is empty.
  20. *
  21. * @author Fabien Potencier <fabien@symfony.com>
  22. */
  23. class Router extends BaseRouter implements WarmableInterface
  24. {
  25. private $container;
  26. /**
  27. * Constructor.
  28. *
  29. * @param ContainerInterface $container A ContainerInterface instance
  30. * @param mixed $resource The main resource to load
  31. * @param array $options An array of options
  32. * @param RequestContext $context The context
  33. */
  34. public function __construct(ContainerInterface $container, $resource, array $options = array(), RequestContext $context = null)
  35. {
  36. $this->container = $container;
  37. $this->resource = $resource;
  38. $this->context = null === $context ? new RequestContext() : $context;
  39. $this->setOptions($options);
  40. }
  41. /**
  42. * {@inheritdoc}
  43. */
  44. public function getRouteCollection()
  45. {
  46. if (null === $this->collection) {
  47. $this->collection = $this->container->get('routing.loader')->load($this->resource, $this->options['resource_type']);
  48. $this->resolveParameters($this->collection);
  49. }
  50. return $this->collection;
  51. }
  52. /**
  53. * {@inheritdoc}
  54. */
  55. public function warmUp($cacheDir)
  56. {
  57. $currentDir = $this->getOption('cache_dir');
  58. // force cache generation
  59. $this->setOption('cache_dir', $cacheDir);
  60. $this->getMatcher();
  61. $this->getGenerator();
  62. $this->setOption('cache_dir', $currentDir);
  63. }
  64. /**
  65. * Replaces placeholders with service container parameter values in:
  66. * - the route defaults,
  67. * - the route requirements,
  68. * - the route pattern.
  69. * - the route host.
  70. *
  71. * @param RouteCollection $collection
  72. */
  73. private function resolveParameters(RouteCollection $collection)
  74. {
  75. foreach ($collection as $route) {
  76. foreach ($route->getDefaults() as $name => $value) {
  77. $route->setDefault($name, $this->resolve($value));
  78. }
  79. foreach ($route->getRequirements() as $name => $value) {
  80. $route->setRequirement($name, $this->resolve($value));
  81. }
  82. $route->setPath($this->resolve($route->getPath()));
  83. $route->setHost($this->resolve($route->getHost()));
  84. }
  85. }
  86. /**
  87. * Recursively replaces placeholders with the service container parameters.
  88. *
  89. * @param mixed $value The source which might contain "%placeholders%"
  90. *
  91. * @return mixed The source with the placeholders replaced by the container
  92. * parameters. Array are resolved recursively.
  93. *
  94. * @throws ParameterNotFoundException When a placeholder does not exist as a container parameter
  95. * @throws RuntimeException When a container value is not a string or a numeric value
  96. */
  97. private function resolve($value)
  98. {
  99. if (is_array($value)) {
  100. foreach ($value as $key => $val) {
  101. $value[$key] = $this->resolve($val);
  102. }
  103. return $value;
  104. }
  105. if (!is_string($value)) {
  106. return $value;
  107. }
  108. $container = $this->container;
  109. $escapedValue = preg_replace_callback('/%%|%([^%\s]+)%/', function ($match) use ($container, $value) {
  110. // skip %%
  111. if (!isset($match[1])) {
  112. return '%%';
  113. }
  114. $key = strtolower($match[1]);
  115. if (!$container->hasParameter($key)) {
  116. throw new ParameterNotFoundException($key);
  117. }
  118. $resolved = $container->getParameter($key);
  119. if (is_string($resolved) || is_numeric($resolved)) {
  120. return (string) $resolved;
  121. }
  122. throw new RuntimeException(sprintf(
  123. 'A string value must be composed of strings and/or numbers,' .
  124. 'but found parameter "%s" of type %s inside string value "%s".',
  125. $key,
  126. gettype($resolved),
  127. $value)
  128. );
  129. }, $value);
  130. return str_replace('%%', '%', $escapedValue);
  131. }
  132. }