updated routing to fix several issues.

This commit is contained in:
Taylor Otwell
2012-02-12 14:48:36 -06:00
parent 31cf44c374
commit 3a92facc76
31 changed files with 960 additions and 772 deletions

View File

@@ -3,6 +3,7 @@
use Laravel\IoC;
use Laravel\Str;
use Laravel\View;
use Laravel\Event;
use Laravel\Bundle;
use Laravel\Request;
use Laravel\Redirect;
@@ -17,6 +18,13 @@ abstract class Controller {
*/
public $layout;
/**
* The bundle the controller belongs to.
*
* @var string
*/
public $bundle;
/**
* Indicates if the controller uses RESTful routing.
*
@@ -38,7 +46,7 @@ abstract class Controller {
* // Call the "show" method on the "user" controller
* $response = Controller::call('user@show');
*
* // Call the "profile" method on the "user/admin" controller and pass parameters
* // Call the "user/admin" controller and pass parameters
* $response = Controller::call('user.admin@profile', array($username));
* </code>
*
@@ -48,47 +56,52 @@ abstract class Controller {
*/
public static function call($destination, $parameters = array())
{
static::references($destination, $parameters);
list($bundle, $destination) = Bundle::parse($destination);
// We will always start the bundle, just in case the developer is pointing
// a route to another bundle. This allows us to lazy load the bundle and
// improve performance since the bundle is not loaded on every request.
// improve speed since the bundle is not loaded on every request.
Bundle::start($bundle);
list($controller, $method) = explode('@', $destination);
list($method, $parameters) = static::backreference($method, $parameters);
$controller = static::resolve($bundle, $controller);
// If the controller could not be resolved, we're out of options and
// will return the 404 error response. If we found the controller,
// we can execute the requested method on the instance.
if (is_null($controller)) return Response::error('404');
if (is_null($controller))
{
return Event::first('404');
}
return $controller->execute($method, $parameters);
}
/**
* Replace all back-references on the given method.
* Replace all back-references on the given destination.
*
* @param string $method
* @param string $destination
* @param array $parameters
* @return array
*/
protected static function backreference($method, $parameters)
protected static function references(&$destination, &$parameters)
{
// Controller delegates may use back-references to the action parameters,
// which allows the developer to setup more flexible routes to various
// controllers with much less code than usual.
// controllers with much less code than would be usual.
foreach ($parameters as $key => $value)
{
$method = str_replace('(:'.($key + 1).')', $value, $method, $count);
$search = '(:'.($key + 1).')';
$destination = str_replace($search, $value, $destination, $count);
if ($count > 0) unset($parameters[$key]);
}
return array(str_replace('(:1)', 'index', $method), $parameters);
return array($destination, $parameters);
}
/**
@@ -100,18 +113,23 @@ abstract class Controller {
*/
public static function resolve($bundle, $controller)
{
if ( ! static::load($bundle, $controller)) return;
$identifier = Bundle::identifier($bundle, $controller);
// If the controller is registered in the IoC container, we will resolve
// it out of the container. Using constructor injection on controllers
// via the container allows more flexible and testable applications.
$resolver = 'controller: '.Bundle::identifier($bundle, $controller);
// via the container allows more flexible applications.
$resolver = 'controller: '.$identifier;
if (IoC::registered($resolver))
{
return IoC::resolve($resolver);
}
// If we couldn't resolve the controller out of the IoC container we'll
// format the controller name into its proper class name and load it
// by convention out of the bundle's controller directory.
if ( ! static::load($bundle, $controller)) return;
$controller = static::format($bundle, $controller);
$controller = new $controller;
@@ -169,11 +187,12 @@ abstract class Controller {
*/
public function execute($method, $parameters = array())
{
$filters = $this->filters('before', $method);
// Again, as was the case with route closures, if the controller "before"
// filters return a response, it will be considered the response to the
// request and the controller method will not be used to handle the
// request to the application.
$response = Filter::run($this->filters('before', $method), array(), true);
// request and the controller method will not be used .
$response = Filter::run($filters, array(), true);
if (is_null($response))
{
@@ -186,7 +205,7 @@ abstract class Controller {
// The "after" function on the controller is simply a convenient hook
// so the developer can work on the response before it's returned to
// the browser. This is useful for setting partials on the layout.
// the browser. This is useful for templating, etc.
$this->after($response);
Filter::run($this->filters('after', $method), array($response));
@@ -321,7 +340,7 @@ abstract class Controller {
* Dynamically resolve items from the application IoC container.
*
* <code>
* // Retrieve an object registered in the container as "mailer"
* // Retrieve an object registered in the container
* $mailer = $this->mailer;
*
* // Equivalent call using the IoC container instance
@@ -330,9 +349,10 @@ abstract class Controller {
*/
public function __get($key)
{
if (IoC::registered($key)) return IoC::resolve($key);
throw new \Exception("Accessing undefined property [$key] on controller.");
if (IoC::registered($key))
{
return IoC::resolve($key);
}
}
}