route.php 9.1 KB

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