route.php 8.71 KB
Newer Older
1 2 3
<?php namespace Laravel\Routing;

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 response to.
14 15 16
	 *
	 * @var string
	 */
17
	public $uri;
18 19

	/**
20
	 * The request method the route responds to.
21
	 *
22
	 * @var string
23
	 */
24
	public $method;
25 26

	/**
27 28 29 30 31 32 33 34
	 * The bundle in which the route was registered.
	 *
	 * @var string
	 */
	public $bundle;

	/**
	 * The action that is assigned to the route.
35 36 37
	 *
	 * @var mixed
	 */
38
	public $action;
39 40

	/**
41
	 * The parameters that will passed to the route callback.
42 43 44 45 46 47 48 49
	 *
	 * @var array
	 */
	public $parameters;

	/**
	 * Create a new Route instance.
	 *
50 51
	 * @param  string   $method
	 * @param  string   $uri
52
	 * @param  array    $action
53
	 * @param  array    $parameters
54 55
	 * @return void
	 */
56
	public function __construct($method, $uri, $action, $parameters = array())
57
	{
58 59
		$this->uri = $uri;
		$this->method = $method;
60
		$this->action = $action;
61

62
		// Determine the bundle in which the route was registered. We will know
Taylor Otwell committed
63 64
		// the bundle by using the bundle::handles method, which will return
		// the bundle assigned to that URI.
65
		$this->bundle = Bundle::handles($uri);
Taylor Otwell committed
66

67 68 69 70
		// We'll set the parameters based on the number of parameters passed
		// compared to the parameters that were needed. If more parameters
		// are needed, we'll merge in defaults.
		$this->parameters($uri, $action, $parameters);
71 72 73
	}

	/**
74
	 * Set the parameters array to the correct value.
75
	 *
Taylor Otwell committed
76
	 * @param  string  $uri
77
	 * @param  array   $action
Taylor Otwell committed
78
	 * @param  array   $parameters
79
	 * @return void
80
	 */
81
	protected function parameters($uri, $action, $parameters)
82
	{
83 84 85 86 87
		$defaults = (array) array_get($action, 'defaults');

		// If there are less parameters than wildcards, we will figure out how
		// many parameters we need to inject from the array of defaults and
		// merge them in into the main array for the route.
88
		if (count($defaults) > count($parameters))
89
		{
90
			$defaults = array_slice($defaults, count($parameters));
91 92 93 94 95

			$parameters = array_merge($parameters, $defaults);
		}

		$this->parameters = $parameters;
96 97 98 99 100 101 102 103 104
	}

	/**
	 * Call a given route and return the route's response.
	 *
	 * @return Response
	 */
	public function call()
	{
105
		// The route is responsible for running the global filters, and any
Taylor Otwell committed
106 107
		// filters defined on the route itself, since all incoming requests
		// come through a route (either defined or ad-hoc).
108
		$response = Filter::run($this->filters('before'), array(), true);
109

110
		if (is_null($response))
111
		{
112
			$response = $this->response();
113
		}
114

Taylor Otwell committed
115 116 117
		// We always return a Response instance from the route calls, so
		// we'll use the prepare method on the Response class to make
		// sure we have a valid Response isntance.
118
		$response = Response::prepare($response);
119

120
		Filter::run($this->filters('after'), array($response));
121

122
		return $response;
123 124 125
	}

	/**
126
	 * Execute the route action and return the response.
127
	 *
128
	 * Unlike the "call" method, none of the attached filters will be run.
129
	 *
130 131
	 * @return mixed
	 */
132
	public function response()
133
	{
134 135 136 137 138 139
		// If the action is a string, it is pointing the route to a controller
		// action, and we can just call the action and return its response.
		// We'll just pass the action off to the Controller class.
		$delegate = $this->delegate();

		if ( ! is_null($delegate))
140
		{
141
			return Controller::call($delegate, $this->parameters);
142
		}
143

144 145 146 147 148 149
		// If the route does not have a delegate, then it must be a Closure
		// instance or have a Closure in its action array, so we will try
		// to locate the Closure and call it directly.
		$handler = $this->handler();

		if ( ! is_null($handler))
150
		{
151
			return call_user_func_array($handler, $this->parameters);
152
		}
153
	}
154

155
	/**
156
	 * Get the filters that are attached to the route for a given event.
157
	 *
Phill Sparks committed
158
	 * @param  string  $event
159 160
	 * @return array
	 */
161
	protected function filters($event)
162
	{
163 164 165
		$global = Bundle::prefix($this->bundle).$event;

		$filters = array_unique(array($event, $global));
166

167 168 169
		// Next we will check to see if there are any filters attached to
		// the route for the given event. If there are, we'll merge them
		// in with the global filters for the event.
170
		if (isset($this->action[$event]))
171
		{
172 173 174
			$assigned = Filter::parse($this->action[$event]);

			$filters = array_merge($filters, $assigned);
175 176
		}

177 178 179 180 181 182 183 184
		// Next we will attach any pattern type filters to the array of
		// filters as these are matched to the route by the route's
		// URI and not explicitly attached to routes.
		if ($event == 'before')
		{
			$filters = array_merge($filters, $this->patterns());
		}

185 186 187 188
		return array(new Filter_Collection($filters));
	}

	/**
189 190 191 192 193 194
	 * Get the pattern filters for the route.
	 *
	 * @return array
	 */
	protected function patterns()
	{
Taylor Otwell committed
195 196
		$filters = array();

197 198 199 200 201
		// We will simply iterate through the registered patterns and
		// check the URI pattern against the URI for the route and
		// if they match we'll attach the filter.
		foreach (Filter::$patterns as $pattern => $filter)
		{
202
			if (Str::is($pattern, $this->uri))
203 204 205 206 207 208 209 210 211
			{
				$filters[] = $filter;
			}
		}

		return (array) $filters;
	}

	/**
212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233
	 * Get the controller action delegate assigned to the route.
	 *
	 * If no delegate is assigned, null will be returned by the method.
	 *
	 * @return string
	 */
	protected function delegate()
	{
		return array_get($this->action, 'uses');
	}

	/**
	 * Get the anonymous function assigned to handle the route.
	 *
	 * @return Closure
	 */
	protected function handler()
	{
		return array_first($this->action, function($key, $value)
		{
			return $value instanceof Closure;
		});
234 235
	}

236
	/**
237
	 * Determine if the route has a given name.
238
	 *
239 240 241 242 243
	 * <code>
	 *		// Determine if the route is the "login" route
	 *		$login = Request::route()->is('login');
	 * </code>
	 *
244
	 * @param  string  $name
245 246 247 248
	 * @return bool
	 */
	public function is($name)
	{
249
		return array_get($this->action, 'as') === $name;
250 251 252
	}

	/**
253
	 * Register a controller with the router.
254
	 *
255 256 257
	 * @param  string|array  $controller
	 * @param  string|array  $defaults
	 * @return void
258
	 */
259
	public static function controller($controllers, $defaults = 'index')
260
	{
261 262
		Router::controller($controllers, $defaults);
	}
263

264 265 266 267 268 269 270 271 272 273
	/**
	 * Register a secure controller with the router.
	 *
	 * @param  string|array  $controllers
	 * @param  string|array  $defaults
	 * @return void
	 */
	public static function secure_controller($controllers, $defaults = 'index')
	{
		Router::controller($controllers, $defaults, true);
274 275
	}

276
	/**
277
	 * Register a GET route with the router.
Taylor Otwell committed
278
	 *
279 280 281 282 283 284 285 286 287 288 289
	 * @param  string|array  $route
	 * @param  mixed         $action
	 * @return void
	 */
	public static function get($route, $action)
	{
		Router::register('GET', $route, $action);
	}

	/**
	 * Register a POST route with the router.
Taylor Otwell committed
290
	 *
291 292 293 294 295 296 297 298 299 300 301
	 * @param  string|array  $route
	 * @param  mixed         $action
	 * @return void
	 */
	public static function post($route, $action)
	{
		Router::register('POST', $route, $action);
	}

	/**
	 * Register a PUT route with the router.
Taylor Otwell committed
302 303 304 305 306
	 *
	 * @param  string|array  $route
	 * @param  mixed         $action
	 * @return void
	 */
307
	public static function put($route, $action)
Taylor Otwell committed
308
	{
309
		Router::register('PUT', $route, $action);
Taylor Otwell committed
310 311 312
	}

	/**
313
	 * Register a DELETE route with the router.
Taylor Otwell committed
314 315 316 317 318
	 *
	 * @param  string|array  $route
	 * @param  mixed         $action
	 * @return void
	 */
319
	public static function delete($route, $action)
Taylor Otwell committed
320
	{
321
		Router::register('DELETE', $route, $action);
Taylor Otwell committed
322 323 324
	}

	/**
325
	 * Register a route that handles any request method.
326
	 *
327 328 329 330 331 332 333 334 335 336 337
	 * @param  string|array  $route
	 * @param  mixed         $action
	 * @return void
	 */
	public static function any($route, $action)
	{
		Router::register('*', $route, $action);
	}

	/**
	 * Register a group of routes that share attributes.
338
	 *
339 340 341 342 343 344 345 346 347 348
	 * @param  array    $attributes
	 * @param  Closure  $callback
	 * @return void
	 */
	public static function group($attributes, Closure $callback)
	{
		Router::group($attributes, $callback);
	}

	/**
349 350 351 352 353 354 355 356 357 358 359 360
	 * Register many request URIs to a single action.
	 *
	 * @param  array  $routes
	 * @param  mixed  $action
	 * @return void
	 */
	public static function share($routes, $action)
	{
		Router::share($routes, $action);
	}

	/**
361 362 363 364 365 366
	 * Register a HTTPS route with the router.
	 *
	 * @param  string        $method
	 * @param  string|array  $route
	 * @param  mixed         $action
	 * @return void
367
	 */
368
	public static function secure($method, $route, $action)
369
	{
370
		Router::secure($method, $route, $action);
371 372
	}

373 374 375
	/**
	 * Register a route filter.
	 *
376 377
	 * @param  string  $name
	 * @param  mixed   $callback
378 379
	 * @return void
	 */
380
	public static function filter($name, $callback)
381 382 383
	{
		Filter::register($name, $callback);
	}
384

385 386 387 388 389 390 391
	/**
	 * Calls the specified route and returns its response.
	 *
	 * @param  string    $method
	 * @param  string    $uri
	 * @return Response
	 */
392
	public static function forward($method, $uri)
393 394 395
	{
		return Router::route(strtoupper($method), $uri)->call();
	}
396

397
}