PageRenderTime 59ms CodeModel.GetById 33ms RepoModel.GetById 1ms app.codeStats 0ms

/htdocs/symfony/2.0.4/vendor/symfony/src/Symfony/Component/Routing/Matcher/Dumper/PhpMatcherDumper.php

http://github.com/pmjones/php-framework-benchmarks
PHP | 294 lines | 210 code | 46 blank | 38 comment | 44 complexity | ae569da316781b496532b24fba1dec4a MD5 | raw file
Possible License(s): LGPL-3.0, Apache-2.0, BSD-3-Clause, ISC, AGPL-3.0, LGPL-2.1
  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\Matcher\Dumper;
  11. use Symfony\Component\Routing\Route;
  12. use Symfony\Component\Routing\RouteCollection;
  13. /**
  14. * PhpMatcherDumper creates a PHP class able to match URLs for a given set of routes.
  15. *
  16. * @author Fabien Potencier <fabien@symfony.com>
  17. */
  18. class PhpMatcherDumper extends MatcherDumper
  19. {
  20. /**
  21. * Dumps a set of routes to a PHP class.
  22. *
  23. * Available options:
  24. *
  25. * * class: The class name
  26. * * base_class: The base class name
  27. *
  28. * @param array $options An array of options
  29. *
  30. * @return string A PHP class representing the matcher class
  31. */
  32. public function dump(array $options = array())
  33. {
  34. $options = array_merge(array(
  35. 'class' => 'ProjectUrlMatcher',
  36. 'base_class' => 'Symfony\\Component\\Routing\\Matcher\\UrlMatcher',
  37. ), $options);
  38. // trailing slash support is only enabled if we know how to redirect the user
  39. $interfaces = class_implements($options['base_class']);
  40. $supportsRedirections = isset($interfaces['Symfony\Component\Routing\Matcher\RedirectableUrlMatcherInterface']);
  41. return
  42. $this->startClass($options['class'], $options['base_class']).
  43. $this->addConstructor().
  44. $this->addMatcher($supportsRedirections).
  45. $this->endClass()
  46. ;
  47. }
  48. private function addMatcher($supportsRedirections)
  49. {
  50. $code = implode("\n", $this->compileRoutes($this->getRoutes(), $supportsRedirections));
  51. return <<<EOF
  52. public function match(\$pathinfo)
  53. {
  54. \$allow = array();
  55. \$pathinfo = urldecode(\$pathinfo);
  56. $code
  57. throw 0 < count(\$allow) ? new MethodNotAllowedException(array_unique(\$allow)) : new ResourceNotFoundException();
  58. }
  59. EOF;
  60. }
  61. private function compileRoutes(RouteCollection $routes, $supportsRedirections, $parentPrefix = null)
  62. {
  63. $code = array();
  64. $routes = clone $routes;
  65. $routeIterator = $routes->getIterator();
  66. $keys = array_keys($routeIterator->getArrayCopy());
  67. $keysCount = count($keys);
  68. $i = 0;
  69. foreach ($routeIterator as $name => $route) {
  70. $i++;
  71. $route = clone $route;
  72. if ($route instanceof RouteCollection) {
  73. $prefix = $route->getPrefix();
  74. $optimizable = $prefix && count($route->all()) > 1 && false === strpos($route->getPrefix(), '{');
  75. $indent = '';
  76. if ($optimizable) {
  77. for ($j = $i; $j < $keysCount; $j++) {
  78. if ($keys[$j] === null) {
  79. continue;
  80. }
  81. $testRoute = $routeIterator->offsetGet($keys[$j]);
  82. $isCollection = ($testRoute instanceof RouteCollection);
  83. $testPrefix = $isCollection ? $testRoute->getPrefix() : $testRoute->getPattern();
  84. if (0 === strpos($testPrefix, $prefix)) {
  85. $routeIterator->offsetUnset($keys[$j]);
  86. if ($isCollection) {
  87. $route->addCollection($testRoute);
  88. } else {
  89. $route->add($keys[$j], $testRoute);
  90. }
  91. $i++;
  92. $keys[$j] = null;
  93. }
  94. }
  95. if ($prefix !== $parentPrefix) {
  96. $code[] = sprintf(" if (0 === strpos(\$pathinfo, %s)) {", var_export($prefix, true));
  97. $indent = ' ';
  98. }
  99. }
  100. foreach ($this->compileRoutes($route, $supportsRedirections, $prefix) as $line) {
  101. foreach (explode("\n", $line) as $l) {
  102. if ($l) {
  103. $code[] = $indent.$l;
  104. } else {
  105. $code[] = $l;
  106. }
  107. }
  108. }
  109. if ($optimizable && $prefix !== $parentPrefix) {
  110. $code[] = " }\n";
  111. }
  112. } else {
  113. foreach ($this->compileRoute($route, $name, $supportsRedirections, $parentPrefix) as $line) {
  114. $code[] = $line;
  115. }
  116. }
  117. }
  118. return $code;
  119. }
  120. private function compileRoute(Route $route, $name, $supportsRedirections, $parentPrefix = null)
  121. {
  122. $code = array();
  123. $compiledRoute = $route->compile();
  124. $conditions = array();
  125. $hasTrailingSlash = false;
  126. $matches = false;
  127. if (!count($compiledRoute->getVariables()) && false !== preg_match('#^(.)\^(?P<url>.*?)\$\1#', str_replace(array("\n", ' '), '', $compiledRoute->getRegex()), $m)) {
  128. if ($supportsRedirections && substr($m['url'], -1) === '/') {
  129. $conditions[] = sprintf("rtrim(\$pathinfo, '/') === %s", var_export(rtrim(str_replace('\\', '', $m['url']), '/'), true));
  130. $hasTrailingSlash = true;
  131. } else {
  132. $conditions[] = sprintf("\$pathinfo === %s", var_export(str_replace('\\', '', $m['url']), true));
  133. }
  134. } else {
  135. if ($compiledRoute->getStaticPrefix() && $compiledRoute->getStaticPrefix() != $parentPrefix) {
  136. $conditions[] = sprintf("0 === strpos(\$pathinfo, %s)", var_export($compiledRoute->getStaticPrefix(), true));
  137. }
  138. $regex = str_replace(array("\n", ' '), '', $compiledRoute->getRegex());
  139. if ($supportsRedirections && $pos = strpos($regex, '/$')) {
  140. $regex = substr($regex, 0, $pos).'/?$'.substr($regex, $pos + 2);
  141. $hasTrailingSlash = true;
  142. }
  143. $conditions[] = sprintf("preg_match(%s, \$pathinfo, \$matches)", var_export($regex, true));
  144. $matches = true;
  145. }
  146. $conditions = implode(' && ', $conditions);
  147. $gotoname = 'not_'.preg_replace('/[^A-Za-z0-9_]/', '', $name);
  148. $code[] = <<<EOF
  149. // $name
  150. if ($conditions) {
  151. EOF;
  152. if ($req = $route->getRequirement('_method')) {
  153. $methods = explode('|', strtoupper($req));
  154. // GET and HEAD are equivalent
  155. if (in_array('GET', $methods) && !in_array('HEAD', $methods)) {
  156. $methods[] = 'HEAD';
  157. }
  158. if (1 === count($methods)) {
  159. $code[] = <<<EOF
  160. if (\$this->context->getMethod() != '$methods[0]') {
  161. \$allow[] = '$methods[0]';
  162. goto $gotoname;
  163. }
  164. EOF;
  165. } else {
  166. $methods = implode('\', \'', $methods);
  167. $code[] = <<<EOF
  168. if (!in_array(\$this->context->getMethod(), array('$methods'))) {
  169. \$allow = array_merge(\$allow, array('$methods'));
  170. goto $gotoname;
  171. }
  172. EOF;
  173. }
  174. }
  175. if ($hasTrailingSlash) {
  176. $code[] = sprintf(<<<EOF
  177. if (substr(\$pathinfo, -1) !== '/') {
  178. return \$this->redirect(\$pathinfo.'/', '%s');
  179. }
  180. EOF
  181. , $name);
  182. }
  183. if ($scheme = $route->getRequirement('_scheme')) {
  184. if (!$supportsRedirections) {
  185. throw new \LogicException('The "_scheme" requirement is only supported for route dumper that implements RedirectableUrlMatcherInterface.');
  186. }
  187. $code[] = sprintf(<<<EOF
  188. if (\$this->context->getScheme() !== '$scheme') {
  189. return \$this->redirect(\$pathinfo, '%s', '$scheme');
  190. }
  191. EOF
  192. , $name);
  193. }
  194. // optimize parameters array
  195. if (true === $matches && $compiledRoute->getDefaults()) {
  196. $code[] = sprintf(" return array_merge(\$this->mergeDefaults(\$matches, %s), array('_route' => '%s'));"
  197. , str_replace("\n", '', var_export($compiledRoute->getDefaults(), true)), $name);
  198. } elseif (true === $matches) {
  199. $code[] = sprintf(" \$matches['_route'] = '%s';", $name);
  200. $code[] = sprintf(" return \$matches;", $name);
  201. } elseif ($compiledRoute->getDefaults()) {
  202. $code[] = sprintf(' return %s;', str_replace("\n", '', var_export(array_merge($compiledRoute->getDefaults(), array('_route' => $name)), true)));
  203. } else {
  204. $code[] = sprintf(" return array('_route' => '%s');", $name);
  205. }
  206. $code[] = " }";
  207. if ($req) {
  208. $code[] = " $gotoname:";
  209. }
  210. $code[] = '';
  211. return $code;
  212. }
  213. private function startClass($class, $baseClass)
  214. {
  215. return <<<EOF
  216. <?php
  217. use Symfony\Component\Routing\Exception\MethodNotAllowedException;
  218. use Symfony\Component\Routing\Exception\ResourceNotFoundException;
  219. use Symfony\Component\Routing\RequestContext;
  220. /**
  221. * $class
  222. *
  223. * This class has been auto-generated
  224. * by the Symfony Routing Component.
  225. */
  226. class $class extends $baseClass
  227. {
  228. EOF;
  229. }
  230. private function addConstructor()
  231. {
  232. return <<<EOF
  233. /**
  234. * Constructor.
  235. */
  236. public function __construct(RequestContext \$context)
  237. {
  238. \$this->context = \$context;
  239. }
  240. EOF;
  241. }
  242. private function endClass()
  243. {
  244. return <<<EOF
  245. }
  246. EOF;
  247. }
  248. }