merged skunkworks into develop.
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
<?php namespace Laravel\Routing;
|
||||
|
||||
use Closure;
|
||||
use Laravel\Arr;
|
||||
use Laravel\Bundle;
|
||||
use Laravel\Response;
|
||||
|
||||
class Route {
|
||||
@@ -14,18 +14,25 @@ class Route {
|
||||
public $key;
|
||||
|
||||
/**
|
||||
* The URIs the route responds to.
|
||||
* The URI the route responds to.
|
||||
*
|
||||
* @var array
|
||||
* @var string
|
||||
*/
|
||||
public $uris;
|
||||
|
||||
/**
|
||||
* The route callback or array.
|
||||
* The bundle in which the route was registered.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $bundle;
|
||||
|
||||
/**
|
||||
* The action that is assigned to the route.
|
||||
*
|
||||
* @var mixed
|
||||
*/
|
||||
public $callback;
|
||||
public $action;
|
||||
|
||||
/**
|
||||
* The parameters that will passed to the route callback.
|
||||
@@ -38,62 +45,43 @@ class Route {
|
||||
* Create a new Route instance.
|
||||
*
|
||||
* @param string $key
|
||||
* @param mixed $callback
|
||||
* @param array $action
|
||||
* @param array $parameters
|
||||
* @return void
|
||||
*/
|
||||
public function __construct($key, $callback, $parameters = array())
|
||||
public function __construct($key, $action, $parameters = array())
|
||||
{
|
||||
$this->key = $key;
|
||||
$this->callback = $callback;
|
||||
$this->action = $action;
|
||||
$this->parameters = $parameters;
|
||||
|
||||
// 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
|
||||
// will be returned since that is used for the root route.
|
||||
if (strpos($key, ', ') === false)
|
||||
{
|
||||
$this->uris = array($this->extract($this->key));
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->uris = array_map(array($this, 'extract'), explode(', ', $key));
|
||||
}
|
||||
// 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 will be returned.
|
||||
$uris = array_get($action, 'handles', array());
|
||||
|
||||
if ( ! $this->callable($callback))
|
||||
{
|
||||
throw new \InvalidArgumentException('Invalid route defined for URI ['.$this->key.']');
|
||||
}
|
||||
}
|
||||
$this->uris = array_map(array($this, 'extract'), $uris);
|
||||
|
||||
/**
|
||||
* 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);
|
||||
// Determine the bundle in which the route was registered. We will know
|
||||
// the bundle by the first segment of the route's URI. We need to know
|
||||
// the bundle so we know if we need to run a bundle's global filters
|
||||
// when executing the route.
|
||||
$this->bundle = Bundle::resolve(head(explode('/', $this->uris[0])));
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* If the request is to the application root, a slash is returned.
|
||||
*
|
||||
* @param string $segment
|
||||
* @return string
|
||||
*/
|
||||
protected function extract($segment)
|
||||
protected static function extract($segment)
|
||||
{
|
||||
$segment = substr($segment, strpos($segment, ' ') + 1);
|
||||
$uri = substr($segment, strpos($segment, ' ') + 1);
|
||||
|
||||
return ($segment !== '/') ? trim($segment, '/') : $segment;
|
||||
return ($uri !== '/') ? trim($uri, '/') : $uri;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -103,116 +91,119 @@ class Route {
|
||||
*/
|
||||
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.
|
||||
//
|
||||
// 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.
|
||||
$before = array_merge(array('before'), $this->filters('before'));
|
||||
// to let the route handle the global filters.
|
||||
$response = Filter::run($this->filters('before'), array(), true);
|
||||
|
||||
$response = Filter::run($before, array(), true);
|
||||
|
||||
if (is_null($response) and ! is_null($response = $this->response()))
|
||||
if (is_null($response))
|
||||
{
|
||||
if ($response instanceof Delegate)
|
||||
{
|
||||
$response = Controller::call($response->destination, $this->parameters);
|
||||
}
|
||||
$response = $this->response();
|
||||
}
|
||||
|
||||
if ( ! $response instanceof Response)
|
||||
{
|
||||
$response = new Response($response);
|
||||
}
|
||||
$response = Response::prepare($response);
|
||||
|
||||
// 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();
|
||||
|
||||
$filters = array_merge($this->filters('after'), array('after'));
|
||||
|
||||
Filter::run($filters, array($response));
|
||||
Filter::run($this->filters('after'), array($response));
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Call the closure defined for the route, or get the route delegator.
|
||||
* Execute the route action and return the response.
|
||||
*
|
||||
* 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.
|
||||
* Unlike the "call" method, none of the attached filters will be run.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
protected function response()
|
||||
public function response()
|
||||
{
|
||||
// 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.
|
||||
if ($this->callback instanceof Closure)
|
||||
// If the action is a string, it is simply pointing the route to a
|
||||
// controller action, and we can just call the action and return
|
||||
// its response. This is the most basic form of route, and is
|
||||
// the simplest to handle.
|
||||
if ( ! is_null($delegate = $this->delegate()))
|
||||
{
|
||||
return call_user_func_array($this->callback, $this->parameters);
|
||||
return Controller::call($delegate, $this->parameters);
|
||||
}
|
||||
// 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
|
||||
// for handling the request to a controller.
|
||||
elseif (is_array($this->callback))
|
||||
{
|
||||
$callback = Arr::first($this->callback, function($key, $value)
|
||||
{
|
||||
return $key == 'uses' or $value instanceof Closure;
|
||||
});
|
||||
|
||||
if ($callback instanceof Closure)
|
||||
{
|
||||
return call_user_func_array($callback, $this->parameters);
|
||||
}
|
||||
else
|
||||
{
|
||||
return new Delegate($callback);
|
||||
}
|
||||
}
|
||||
elseif (is_string($this->callback))
|
||||
// If the route does not have a delegate, it should either be a
|
||||
// Closure instance or have a Closure in its action array, so
|
||||
// we will attempt to get the Closure and call it.
|
||||
elseif ( ! is_null($handler = $this->handler()))
|
||||
{
|
||||
return new Delegate($this->callback);
|
||||
return call_user_func_array($handler, $this->parameters);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an array of filter names defined for the route.
|
||||
* Get the filters that are attached to the route for a given event.
|
||||
*
|
||||
* @param string $name
|
||||
* If the route belongs to a bundle, the bundle's global filters are returned too.
|
||||
*
|
||||
* @param string $filter
|
||||
* @return array
|
||||
*/
|
||||
public function filters($name)
|
||||
protected function filters($event)
|
||||
{
|
||||
if (is_array($this->callback) and isset($this->callback[$name]))
|
||||
{
|
||||
$filters = $this->callback[$name];
|
||||
// Add the global filters to the array. We will also attempt to add
|
||||
// the bundle's global filter as well. However, we'll need to keep
|
||||
// the array unique since the default bundle's global filter will
|
||||
// be the same as the application's global filter.
|
||||
$filters = array_unique(array($event, Bundle::prefix($this->bundle).$event));
|
||||
|
||||
return (is_string($filters)) ? explode('|', $filters) : (array) $filters;
|
||||
// Next wee will check to see if there are any filters attached
|
||||
// for the given event. If there are, we'll merge them in with
|
||||
// the global filters for the application event.
|
||||
if (isset($this->action[$event]))
|
||||
{
|
||||
$filters = array_merge($filters, Filter::parse($this->action[$event]));
|
||||
}
|
||||
|
||||
return array();
|
||||
return array(new Filter_Collection($filters));
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* If no anonymous function is assigned, null will be returned by the method.
|
||||
*
|
||||
* @return Closure
|
||||
*/
|
||||
protected function handler()
|
||||
{
|
||||
return array_first($this->action, function($key, $value)
|
||||
{
|
||||
return $value instanceof Closure;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the route has a given name.
|
||||
*
|
||||
* <code>
|
||||
* // Determine if the route is the "login" route
|
||||
* $login = Request::route()->is('login');
|
||||
* </code>
|
||||
*
|
||||
* @param string $name
|
||||
* @return bool
|
||||
*/
|
||||
public function is($name)
|
||||
{
|
||||
return is_array($this->callback) and Arr::get($this->callback, 'name') === $name;
|
||||
return is_array($this->action) and array_get($this->action, 'name') === $name;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -223,20 +214,12 @@ class Route {
|
||||
*/
|
||||
public function handles($uri)
|
||||
{
|
||||
return in_array($uri, $this->uris);
|
||||
}
|
||||
$pattern = '#'.str_replace('*', '(.*)', $uri).'#';
|
||||
|
||||
/**
|
||||
* Magic Method to handle dynamic method calls to determine the name of the route.
|
||||
*/
|
||||
public function __call($method, $parameters)
|
||||
{
|
||||
if (strpos($method, 'is_') === 0)
|
||||
return ! is_null(array_first($this->uris, function($key, $uri) use ($pattern)
|
||||
{
|
||||
return $this->is(substr($method, 3));
|
||||
}
|
||||
|
||||
throw new \BadMethodCallException("Call to undefined method [$method] on Route class.");
|
||||
return preg_match($pattern, $uri);
|
||||
}));
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user