2011-10-13 21:32:11 -05:00
|
|
|
<?php namespace Laravel\Routing;
|
|
|
|
|
|
|
|
|
|
use Closure;
|
|
|
|
|
use Laravel\Arr;
|
|
|
|
|
use Laravel\Response;
|
2011-07-31 14:48:17 -05:00
|
|
|
|
2011-10-04 21:43:39 -05:00
|
|
|
class Route {
|
2011-06-08 23:45:08 -05:00
|
|
|
|
2011-06-18 12:00:52 -05:00
|
|
|
/**
|
|
|
|
|
* The route key, including request method and URI.
|
|
|
|
|
*
|
|
|
|
|
* @var string
|
|
|
|
|
*/
|
|
|
|
|
public $key;
|
|
|
|
|
|
2011-08-31 23:51:52 -05:00
|
|
|
/**
|
|
|
|
|
* The URIs the route responds to.
|
|
|
|
|
*
|
|
|
|
|
* @var array
|
|
|
|
|
*/
|
|
|
|
|
public $uris;
|
|
|
|
|
|
2011-06-08 23:45:08 -05:00
|
|
|
/**
|
|
|
|
|
* The route callback or array.
|
|
|
|
|
*
|
|
|
|
|
* @var mixed
|
|
|
|
|
*/
|
2011-06-18 12:00:52 -05:00
|
|
|
public $callback;
|
2011-06-08 23:45:08 -05:00
|
|
|
|
|
|
|
|
/**
|
2011-09-09 20:55:24 -05:00
|
|
|
* The parameters that will passed to the route callback.
|
2011-06-08 23:45:08 -05:00
|
|
|
*
|
|
|
|
|
* @var array
|
|
|
|
|
*/
|
|
|
|
|
public $parameters;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Create a new Route instance.
|
|
|
|
|
*
|
2011-08-26 21:42:04 -05:00
|
|
|
* @param string $key
|
|
|
|
|
* @param mixed $callback
|
|
|
|
|
* @param array $parameters
|
2011-06-08 23:45:08 -05:00
|
|
|
* @return void
|
|
|
|
|
*/
|
2011-09-06 22:04:52 -05:00
|
|
|
public function __construct($key, $callback, $parameters = array())
|
2011-06-08 23:45:08 -05:00
|
|
|
{
|
2011-06-18 12:00:52 -05:00
|
|
|
$this->key = $key;
|
|
|
|
|
$this->callback = $callback;
|
2011-06-08 23:45:08 -05:00
|
|
|
$this->parameters = $parameters;
|
2011-09-09 20:55:24 -05:00
|
|
|
|
2011-10-13 21:32:11 -05:00
|
|
|
// Extract each URI from the route key. Since the route key has the
|
|
|
|
|
// request method, we will extract that from the string. If the URI
|
|
|
|
|
// points to the root of the application, a single forward slash
|
2011-11-20 22:51:31 -06:00
|
|
|
// will be returned since that is used for the root route.
|
2011-09-13 22:35:27 -05:00
|
|
|
if (strpos($key, ', ') === false)
|
|
|
|
|
{
|
2011-10-13 21:32:11 -05:00
|
|
|
$this->uris = array($this->extract($this->key));
|
2011-09-13 22:35:27 -05:00
|
|
|
}
|
|
|
|
|
else
|
2011-09-09 20:55:24 -05:00
|
|
|
{
|
2011-10-13 21:32:11 -05:00
|
|
|
$this->uris = array_map(array($this, 'extract'), explode(', ', $key));
|
2011-09-13 21:47:25 -05:00
|
|
|
}
|
|
|
|
|
|
2011-11-23 08:49:09 -06:00
|
|
|
if ( ! $this->callable($callback))
|
2011-09-13 21:47:25 -05:00
|
|
|
{
|
2011-11-15 12:35:04 +00:00
|
|
|
throw new \InvalidArgumentException('Invalid route defined for URI ['.$this->key.']');
|
2011-09-13 21:47:25 -05:00
|
|
|
}
|
2011-09-09 20:55:24 -05:00
|
|
|
}
|
|
|
|
|
|
2011-11-23 08:49:09 -06:00
|
|
|
/**
|
|
|
|
|
* Determine if the given route callback is callable.
|
|
|
|
|
*
|
|
|
|
|
* Route callbacks must be either a Closure, array, or string.
|
|
|
|
|
*
|
|
|
|
|
* @param mixed $callback
|
|
|
|
|
* @return bool
|
|
|
|
|
*/
|
|
|
|
|
protected function callable($callback)
|
|
|
|
|
{
|
|
|
|
|
return $callback instanceof Closure or is_array($callback) or is_string($callback);
|
|
|
|
|
}
|
|
|
|
|
|
2011-10-13 21:32:11 -05:00
|
|
|
/**
|
|
|
|
|
* Retrieve the URI from a given route destination.
|
|
|
|
|
*
|
|
|
|
|
* If the request is to the root of the application, a single slash
|
|
|
|
|
* will be returned, otherwise the leading slash will be removed.
|
|
|
|
|
*
|
|
|
|
|
* @param string $segment
|
|
|
|
|
* @return string
|
|
|
|
|
*/
|
|
|
|
|
protected function extract($segment)
|
|
|
|
|
{
|
|
|
|
|
$segment = substr($segment, strpos($segment, ' ') + 1);
|
|
|
|
|
|
|
|
|
|
return ($segment !== '/') ? trim($segment, '/') : $segment;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Call a given route and return the route's response.
|
|
|
|
|
*
|
|
|
|
|
* @return Response
|
|
|
|
|
*/
|
|
|
|
|
public function call()
|
|
|
|
|
{
|
|
|
|
|
// Since "before" filters can halt the request cycle, we will return
|
|
|
|
|
// any response from the before filters. Allowing filters to halt the
|
|
|
|
|
// request cycle makes tasks like authorization convenient.
|
2011-10-20 21:44:18 -05:00
|
|
|
//
|
|
|
|
|
// The route is responsible for running the global filters, and any
|
|
|
|
|
// filters defined on the route itself. Since all incoming requests
|
|
|
|
|
// come through a route (either defined or ad-hoc), it makes sense
|
|
|
|
|
// to let the route handle the global filters. If the route uses
|
|
|
|
|
// a controller, the controller will only call its own filters.
|
2011-10-13 21:32:11 -05:00
|
|
|
$before = array_merge(array('before'), $this->filters('before'));
|
|
|
|
|
|
2011-10-22 23:25:07 -05:00
|
|
|
$response = Filter::run($before, array(), true);
|
2011-10-13 21:32:11 -05:00
|
|
|
|
2011-10-22 23:25:07 -05:00
|
|
|
if (is_null($response) and ! is_null($response = $this->response()))
|
2011-10-13 21:32:11 -05:00
|
|
|
{
|
|
|
|
|
if ($response instanceof Delegate)
|
|
|
|
|
{
|
2011-11-08 20:35:24 -06:00
|
|
|
$response = Controller::call($response->destination, $this->parameters);
|
2011-10-13 21:32:11 -05:00
|
|
|
}
|
2011-10-22 23:25:07 -05:00
|
|
|
}
|
2011-10-20 21:44:18 -05:00
|
|
|
|
2011-10-22 23:25:07 -05:00
|
|
|
if ( ! $response instanceof Response)
|
|
|
|
|
{
|
|
|
|
|
$response = new Response($response);
|
|
|
|
|
}
|
2011-10-13 21:32:11 -05:00
|
|
|
|
2011-11-20 22:47:56 -06:00
|
|
|
// Stringify the response. We need to force the response to be
|
|
|
|
|
// stringed before closing the session, since the developer may
|
|
|
|
|
// be using the session within their views, so we cannot age
|
|
|
|
|
// the session data until the view is rendered.
|
|
|
|
|
$response->content = $response->render();
|
|
|
|
|
|
2011-10-22 23:25:07 -05:00
|
|
|
$filters = array_merge($this->filters('after'), array('after'));
|
2011-10-13 21:32:11 -05:00
|
|
|
|
2011-10-22 23:25:07 -05:00
|
|
|
Filter::run($filters, array($response));
|
2011-10-15 14:04:11 -05:00
|
|
|
|
2011-10-22 23:25:07 -05:00
|
|
|
return $response;
|
2011-10-13 21:32:11 -05:00
|
|
|
}
|
|
|
|
|
|
2011-09-06 22:04:52 -05:00
|
|
|
/**
|
2011-09-13 22:12:27 -05:00
|
|
|
* Call the closure defined for the route, or get the route delegator.
|
2011-09-06 22:04:52 -05:00
|
|
|
*
|
2011-10-13 21:32:11 -05:00
|
|
|
* Note that this method differs from the "call" method in that it does
|
|
|
|
|
* not resolve the controller or prepare the response. Delegating to
|
|
|
|
|
* controller's is handled by the "call" method.
|
|
|
|
|
*
|
2011-09-06 22:04:52 -05:00
|
|
|
* @return mixed
|
|
|
|
|
*/
|
2011-10-13 21:32:11 -05:00
|
|
|
protected function response()
|
2011-09-06 22:04:52 -05:00
|
|
|
{
|
2011-11-21 22:22:41 -06:00
|
|
|
// If the route callback is an instance of a Closure, we can call the
|
|
|
|
|
// route function directly. There are no before or after filters to
|
|
|
|
|
// parse out of the route.
|
2011-09-13 21:47:25 -05:00
|
|
|
if ($this->callback instanceof Closure)
|
|
|
|
|
{
|
|
|
|
|
return call_user_func_array($this->callback, $this->parameters);
|
|
|
|
|
}
|
2011-10-26 21:21:31 -05:00
|
|
|
// If the route is an array, we will return the first value with a
|
|
|
|
|
// key of "uses", or the first instance of a Closure. If the value
|
|
|
|
|
// is a string, the route is delegating the responsibility for
|
2011-10-13 21:32:11 -05:00
|
|
|
// for handling the request to a controller.
|
2011-09-13 21:47:25 -05:00
|
|
|
elseif (is_array($this->callback))
|
|
|
|
|
{
|
2011-09-20 21:28:19 -05:00
|
|
|
$callback = Arr::first($this->callback, function($key, $value)
|
|
|
|
|
{
|
2011-10-26 21:21:31 -05:00
|
|
|
return $key == 'uses' or $value instanceof Closure;
|
2011-09-20 21:28:19 -05:00
|
|
|
});
|
2011-09-19 21:33:25 -05:00
|
|
|
|
2011-10-13 21:32:11 -05:00
|
|
|
if ($callback instanceof Closure)
|
|
|
|
|
{
|
|
|
|
|
return call_user_func_array($callback, $this->parameters);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
return new Delegate($callback);
|
|
|
|
|
}
|
2011-09-13 21:47:25 -05:00
|
|
|
}
|
|
|
|
|
elseif (is_string($this->callback))
|
|
|
|
|
{
|
2011-09-19 21:33:25 -05:00
|
|
|
return new Delegate($this->callback);
|
2011-09-13 21:47:25 -05:00
|
|
|
}
|
2011-08-25 22:53:05 -05:00
|
|
|
}
|
2011-06-08 23:45:08 -05:00
|
|
|
|
2011-08-25 22:53:05 -05:00
|
|
|
/**
|
2011-09-09 20:55:24 -05:00
|
|
|
* Get an array of filter names defined for the route.
|
2011-08-25 22:53:05 -05:00
|
|
|
*
|
2011-09-06 22:04:52 -05:00
|
|
|
* @param string $name
|
2011-08-25 22:53:05 -05:00
|
|
|
* @return array
|
|
|
|
|
*/
|
2011-09-06 22:04:52 -05:00
|
|
|
public function filters($name)
|
2011-08-25 22:53:05 -05:00
|
|
|
{
|
2011-09-20 21:28:19 -05:00
|
|
|
if (is_array($this->callback) and isset($this->callback[$name]))
|
|
|
|
|
{
|
2011-11-02 23:02:23 -05:00
|
|
|
$filters = $this->callback[$name];
|
|
|
|
|
|
|
|
|
|
return (is_string($filters)) ? explode('|', $filters) : (array) $filters;
|
2011-09-20 21:28:19 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return array();
|
2011-06-08 23:45:08 -05:00
|
|
|
}
|
|
|
|
|
|
2011-08-05 09:18:40 -05:00
|
|
|
/**
|
2011-09-09 20:55:24 -05:00
|
|
|
* Determine if the route has a given name.
|
2011-08-05 09:18:40 -05:00
|
|
|
*
|
2011-08-25 22:53:05 -05:00
|
|
|
* @param string $name
|
2011-09-06 22:04:52 -05:00
|
|
|
* @return bool
|
|
|
|
|
*/
|
|
|
|
|
public function is($name)
|
|
|
|
|
{
|
2011-10-13 21:32:11 -05:00
|
|
|
return is_array($this->callback) and Arr::get($this->callback, 'name') === $name;
|
2011-09-06 22:04:52 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Determine if the route handles a given URI.
|
|
|
|
|
*
|
|
|
|
|
* @param string $uri
|
|
|
|
|
* @return bool
|
|
|
|
|
*/
|
|
|
|
|
public function handles($uri)
|
|
|
|
|
{
|
|
|
|
|
return in_array($uri, $this->uris);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Magic Method to handle dynamic method calls to determine the name of the route.
|
|
|
|
|
*/
|
|
|
|
|
public function __call($method, $parameters)
|
|
|
|
|
{
|
2011-11-14 21:18:18 -06:00
|
|
|
if (strpos($method, 'is_') === 0)
|
|
|
|
|
{
|
|
|
|
|
return $this->is(substr($method, 3));
|
|
|
|
|
}
|
2011-10-16 21:35:11 -05:00
|
|
|
|
2011-11-15 12:35:04 +00:00
|
|
|
throw new \BadMethodCallException("Call to undefined method [$method] on Route class.");
|
2011-08-05 09:18:40 -05:00
|
|
|
}
|
|
|
|
|
|
2011-11-23 08:49:09 -06:00
|
|
|
}
|