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