router.php 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  1. <?php namespace System;
  2. class Router {
  3. /**
  4. * All of the loaded routes.
  5. *
  6. * @var array
  7. */
  8. public static $routes;
  9. /**
  10. * The named routes that have been found so far.
  11. *
  12. * @var array
  13. */
  14. public static $names = array();
  15. /**
  16. * Search a set of routes for the route matching a method and URI.
  17. *
  18. * @param string $method
  19. * @param string $uri
  20. * @return Route
  21. */
  22. public static function route($method, $uri)
  23. {
  24. // --------------------------------------------------------------
  25. // Add a forward slash to the URI if necessary.
  26. // --------------------------------------------------------------
  27. $uri = ($uri != '/') ? '/'.$uri : $uri;
  28. // --------------------------------------------------------------
  29. // Load all of the application routes.
  30. // --------------------------------------------------------------
  31. static::$routes = require APP_PATH.'routes'.EXT;
  32. // --------------------------------------------------------------
  33. // Is there an exact match for the request?
  34. // --------------------------------------------------------------
  35. if (isset(static::$routes[$method.' '.$uri]))
  36. {
  37. return new Route(static::$routes[$method.' '.$uri]);
  38. }
  39. // --------------------------------------------------------------
  40. // No exact match... check each route individually.
  41. // --------------------------------------------------------------
  42. foreach (static::$routes as $keys => $callback)
  43. {
  44. // --------------------------------------------------------------
  45. // Only check routes that have multiple URIs or wildcards.
  46. // All other routes would have been caught by a literal match.
  47. // --------------------------------------------------------------
  48. if (strpos($keys, '(') !== false or strpos($keys, ',') !== false )
  49. {
  50. // --------------------------------------------------------------
  51. // Multiple routes can be assigned to a callback using commas.
  52. // --------------------------------------------------------------
  53. foreach (explode(', ', $keys) as $route)
  54. {
  55. // --------------------------------------------------------------
  56. // Change wildcards into regular expressions.
  57. // --------------------------------------------------------------
  58. $route = str_replace(':num', '[0-9]+', str_replace(':any', '.+', $route));
  59. // --------------------------------------------------------------
  60. // Test the route for a match.
  61. // --------------------------------------------------------------
  62. if (preg_match('#^'.$route.'$#', $method.' '.$uri))
  63. {
  64. return new Route($callback, static::parameters(explode('/', $uri), explode('/', $route)));
  65. }
  66. }
  67. }
  68. }
  69. }
  70. /**
  71. * Find a route by name.
  72. *
  73. * @param string $name
  74. * @return array
  75. */
  76. public static function find($name)
  77. {
  78. // ----------------------------------------------------
  79. // Have we already looked up this named route?
  80. // ----------------------------------------------------
  81. if (array_key_exists($name, static::$names))
  82. {
  83. return static::$names[$name];
  84. }
  85. // ----------------------------------------------------
  86. // Instantiate the recursive array iterator.
  87. // ----------------------------------------------------
  88. $arrayIterator = new \RecursiveArrayIterator(static::$routes);
  89. // ----------------------------------------------------
  90. // Instantiate the recursive iterator iterator.
  91. // ----------------------------------------------------
  92. $recursiveIterator = new \RecursiveIteratorIterator($arrayIterator);
  93. // ----------------------------------------------------
  94. // Iterate through the routes searching for a route
  95. // name that matches the given name.
  96. // ----------------------------------------------------
  97. foreach ($recursiveIterator as $iterator)
  98. {
  99. $route = $recursiveIterator->getSubIterator();
  100. if ($route['name'] == $name)
  101. {
  102. return static::$names[$name] = array($arrayIterator->key() => iterator_to_array($route));
  103. }
  104. }
  105. }
  106. /**
  107. * Get the parameters that should be passed to the route callback.
  108. *
  109. * @param array $uri_segments
  110. * @param array $route_segments
  111. * @return array
  112. */
  113. private static function parameters($uri_segments, $route_segments)
  114. {
  115. $parameters = array();
  116. // --------------------------------------------------------------
  117. // Spin through the route segments looking for parameters.
  118. // --------------------------------------------------------------
  119. for ($i = 0; $i < count($route_segments); $i++)
  120. {
  121. // --------------------------------------------------------------
  122. // Any segment wrapped in parentheses is a parameter.
  123. // --------------------------------------------------------------
  124. if (strpos($route_segments[$i], '(') === 0)
  125. {
  126. $parameters[] = $uri_segments[$i];
  127. }
  128. }
  129. return $parameters;
  130. }
  131. }