route.php 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397
  1. <?php namespace Laravel\Routing;
  2. use Closure;
  3. use Laravel\Str;
  4. use Laravel\URI;
  5. use Laravel\Bundle;
  6. use Laravel\Request;
  7. use Laravel\Response;
  8. class Route {
  9. /**
  10. * The URI the route response to.
  11. *
  12. * @var string
  13. */
  14. public $uri;
  15. /**
  16. * The request method the route responds to.
  17. *
  18. * @var string
  19. */
  20. public $method;
  21. /**
  22. * The bundle in which the route was registered.
  23. *
  24. * @var string
  25. */
  26. public $bundle;
  27. /**
  28. * The action that is assigned to the route.
  29. *
  30. * @var mixed
  31. */
  32. public $action;
  33. /**
  34. * The parameters that will passed to the route callback.
  35. *
  36. * @var array
  37. */
  38. public $parameters;
  39. /**
  40. * Create a new Route instance.
  41. *
  42. * @param string $method
  43. * @param string $uri
  44. * @param array $action
  45. * @param array $parameters
  46. * @return void
  47. */
  48. public function __construct($method, $uri, $action, $parameters = array())
  49. {
  50. $this->uri = $uri;
  51. $this->method = $method;
  52. $this->action = $action;
  53. // Determine the bundle in which the route was registered. We will know
  54. // the bundle by using the bundle::handles method, which will return
  55. // the bundle assigned to that URI.
  56. $this->bundle = Bundle::handles($uri);
  57. // We'll set the parameters based on the number of parameters passed
  58. // compared to the parameters that were needed. If more parameters
  59. // are needed, we'll merge in defaults.
  60. $this->parameters($uri, $action, $parameters);
  61. }
  62. /**
  63. * Set the parameters array to the correct value.
  64. *
  65. * @param string $uri
  66. * @param array $action
  67. * @param array $parameters
  68. * @return void
  69. */
  70. protected function parameters($uri, $action, $parameters)
  71. {
  72. $defaults = (array) array_get($action, 'defaults');
  73. // If there are less parameters than wildcards, we will figure out how
  74. // many parameters we need to inject from the array of defaults and
  75. // merge them in into the main array for the route.
  76. if (count($defaults) > count($parameters))
  77. {
  78. $defaults = array_slice($defaults, count($parameters));
  79. $parameters = array_merge($parameters, $defaults);
  80. }
  81. $this->parameters = $parameters;
  82. }
  83. /**
  84. * Call a given route and return the route's response.
  85. *
  86. * @return Response
  87. */
  88. public function call()
  89. {
  90. // The route is responsible for running the global filters, and any
  91. // filters defined on the route itself, since all incoming requests
  92. // come through a route (either defined or ad-hoc).
  93. $response = Filter::run($this->filters('before'), array(), true);
  94. if (is_null($response))
  95. {
  96. $response = $this->response();
  97. }
  98. // We always return a Response instance from the route calls, so
  99. // we'll use the prepare method on the Response class to make
  100. // sure we have a valid Response isntance.
  101. $response = Response::prepare($response);
  102. Filter::run($this->filters('after'), array($response));
  103. return $response;
  104. }
  105. /**
  106. * Execute the route action and return the response.
  107. *
  108. * Unlike the "call" method, none of the attached filters will be run.
  109. *
  110. * @return mixed
  111. */
  112. public function response()
  113. {
  114. // If the action is a string, it is pointing the route to a controller
  115. // action, and we can just call the action and return its response.
  116. // We'll just pass the action off to the Controller class.
  117. $delegate = $this->delegate();
  118. if ( ! is_null($delegate))
  119. {
  120. return Controller::call($delegate, $this->parameters);
  121. }
  122. // If the route does not have a delegate, then it must be a Closure
  123. // instance or have a Closure in its action array, so we will try
  124. // to locate the Closure and call it directly.
  125. $handler = $this->handler();
  126. if ( ! is_null($handler))
  127. {
  128. return call_user_func_array($handler, $this->parameters);
  129. }
  130. }
  131. /**
  132. * Get the filters that are attached to the route for a given event.
  133. *
  134. * @param string $event
  135. * @return array
  136. */
  137. protected function filters($event)
  138. {
  139. $global = Bundle::prefix($this->bundle).$event;
  140. $filters = array_unique(array($event, $global));
  141. // Next we will check to see if there are any filters attached to
  142. // the route for the given event. If there are, we'll merge them
  143. // in with the global filters for the event.
  144. if (isset($this->action[$event]))
  145. {
  146. $assigned = Filter::parse($this->action[$event]);
  147. $filters = array_merge($filters, $assigned);
  148. }
  149. // Next we will attach any pattern type filters to the array of
  150. // filters as these are matched to the route by the route's
  151. // URI and not explicitly attached to routes.
  152. if ($event == 'before')
  153. {
  154. $filters = array_merge($filters, $this->patterns());
  155. }
  156. return array(new Filter_Collection($filters));
  157. }
  158. /**
  159. * Get the pattern filters for the route.
  160. *
  161. * @return array
  162. */
  163. protected function patterns()
  164. {
  165. $filters = array();
  166. // We will simply iterate through the registered patterns and
  167. // check the URI pattern against the URI for the route and
  168. // if they match we'll attach the filter.
  169. foreach (Filter::$patterns as $pattern => $filter)
  170. {
  171. if (Str::is($pattern, $this->uri))
  172. {
  173. $filters[] = $filter;
  174. }
  175. }
  176. return (array) $filters;
  177. }
  178. /**
  179. * Get the controller action delegate assigned to the route.
  180. *
  181. * If no delegate is assigned, null will be returned by the method.
  182. *
  183. * @return string
  184. */
  185. protected function delegate()
  186. {
  187. return array_get($this->action, 'uses');
  188. }
  189. /**
  190. * Get the anonymous function assigned to handle the route.
  191. *
  192. * @return Closure
  193. */
  194. protected function handler()
  195. {
  196. return array_first($this->action, function($key, $value)
  197. {
  198. return $value instanceof Closure;
  199. });
  200. }
  201. /**
  202. * Determine if the route has a given name.
  203. *
  204. * <code>
  205. * // Determine if the route is the "login" route
  206. * $login = Request::route()->is('login');
  207. * </code>
  208. *
  209. * @param string $name
  210. * @return bool
  211. */
  212. public function is($name)
  213. {
  214. return array_get($this->action, 'as') === $name;
  215. }
  216. /**
  217. * Register a controller with the router.
  218. *
  219. * @param string|array $controller
  220. * @param string|array $defaults
  221. * @return void
  222. */
  223. public static function controller($controllers, $defaults = 'index')
  224. {
  225. Router::controller($controllers, $defaults);
  226. }
  227. /**
  228. * Register a secure controller with the router.
  229. *
  230. * @param string|array $controllers
  231. * @param string|array $defaults
  232. * @return void
  233. */
  234. public static function secure_controller($controllers, $defaults = 'index')
  235. {
  236. Router::controller($controllers, $defaults, true);
  237. }
  238. /**
  239. * Register a GET route with the router.
  240. *
  241. * @param string|array $route
  242. * @param mixed $action
  243. * @return void
  244. */
  245. public static function get($route, $action)
  246. {
  247. Router::register('GET', $route, $action);
  248. }
  249. /**
  250. * Register a POST route with the router.
  251. *
  252. * @param string|array $route
  253. * @param mixed $action
  254. * @return void
  255. */
  256. public static function post($route, $action)
  257. {
  258. Router::register('POST', $route, $action);
  259. }
  260. /**
  261. * Register a PUT route with the router.
  262. *
  263. * @param string|array $route
  264. * @param mixed $action
  265. * @return void
  266. */
  267. public static function put($route, $action)
  268. {
  269. Router::register('PUT', $route, $action);
  270. }
  271. /**
  272. * Register a DELETE route with the router.
  273. *
  274. * @param string|array $route
  275. * @param mixed $action
  276. * @return void
  277. */
  278. public static function delete($route, $action)
  279. {
  280. Router::register('DELETE', $route, $action);
  281. }
  282. /**
  283. * Register a route that handles any request method.
  284. *
  285. * @param string|array $route
  286. * @param mixed $action
  287. * @return void
  288. */
  289. public static function any($route, $action)
  290. {
  291. Router::register('*', $route, $action);
  292. }
  293. /**
  294. * Register a group of routes that share attributes.
  295. *
  296. * @param array $attributes
  297. * @param Closure $callback
  298. * @return void
  299. */
  300. public static function group($attributes, Closure $callback)
  301. {
  302. Router::group($attributes, $callback);
  303. }
  304. /**
  305. * Register many request URIs to a single action.
  306. *
  307. * @param array $routes
  308. * @param mixed $action
  309. * @return void
  310. */
  311. public static function share($routes, $action)
  312. {
  313. Router::share($routes, $action);
  314. }
  315. /**
  316. * Register a HTTPS route with the router.
  317. *
  318. * @param string $method
  319. * @param string|array $route
  320. * @param mixed $action
  321. * @return void
  322. */
  323. public static function secure($method, $route, $action)
  324. {
  325. Router::secure($method, $route, $action);
  326. }
  327. /**
  328. * Register a route filter.
  329. *
  330. * @param string $name
  331. * @param mixed $callback
  332. * @return void
  333. */
  334. public static function filter($name, $callback)
  335. {
  336. Filter::register($name, $callback);
  337. }
  338. /**
  339. * Calls the specified route and returns its response.
  340. *
  341. * @param string $method
  342. * @param string $uri
  343. * @return Response
  344. */
  345. public static function forward($method, $uri)
  346. {
  347. return Router::route(strtoupper($method), $uri)->call();
  348. }
  349. }