From cd310efd2553077d31ae6b3bc88f08272ca6b1c8 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Mon, 7 Nov 2011 21:46:55 -0600 Subject: [PATCH] revised method of declaring filters on controllers. --- laravel/routing/controller.php | 58 ++++++++++----- laravel/routing/filter.php | 127 ++++++++++++++++++++++++++++++++- 2 files changed, 166 insertions(+), 19 deletions(-) diff --git a/laravel/routing/controller.php b/laravel/routing/controller.php index 5b8222eb..563d56c4 100644 --- a/laravel/routing/controller.php +++ b/laravel/routing/controller.php @@ -7,18 +7,11 @@ abstract class Controller { /** - * The "before" filters defined for the controller. + * The filters assigned to the controller. * * @var array */ - public $before = array(); - - /** - * The "after" filters defined for the controller. - * - * @var array - */ - public $after = array(); + protected $filters = array(); /** * Handle the delegation of a route to a controller method. @@ -115,13 +108,11 @@ public function execute($method, $parameters = array()) // "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'), array(), true); + $response = Filter::run($this->filters('before', $method), array(), true); if (is_null($response)) { - $verb = strtolower(Request::method()); - - $response = call_user_func_array(array($this, "{$verb}_{$method}"), $parameters); + $response = call_user_func_array(array($this, "action_{$method}"), $parameters); } // The after filter and the framework expects all responses to @@ -129,7 +120,7 @@ public function execute($method, $parameters = array()) // return an instsance of Response, we will make on now. if ( ! $response instanceof Response) $response = new Response($response); - Filter::run($this->filters('after'), array($response)); + Filter::run($this->filters('after', $method), array($response)); return $response; } @@ -145,15 +136,50 @@ protected static function hidden($method) return $method == 'before' or $method == 'after' or strncmp($method, '_', 1) == 0; } + /** + * Set filters on the controller's methods. + * + * Generally, this method will be used in the controller's constructor. + * + * + * // Set an "auth" before filter on the controller + * $this->filter('before', 'auth'); + * + * // Set several filters on an explicit group of methods + * $this->filter('before', 'auth|csrf')->only(array('user', 'profile')); + * + * + * @param string $name + * @param string|array $filters + * @return Filter_Collection + */ + public function filter($name, $filters) + { + $this->filters[] = new Filter_Collection($name, $filters); + + return $this->filters[count($this->filters) - 1]; + } + /** * Get an array of filter names defined for the destination. * * @param string $name + * @param string $method * @return array */ - protected function filters($name) + protected function filters($name, $method) { - return (array) $this->$name; + $filters = array(); + + foreach ($this->filters as $filter) + { + if ($filter->name === $name and $filter->applies($method)) + { + $filters = array_merge($filters, $filter->filters); + } + } + + return array_unique($filters); } /** diff --git a/laravel/routing/filter.php b/laravel/routing/filter.php index 4543421d..f4ad41d2 100644 --- a/laravel/routing/filter.php +++ b/laravel/routing/filter.php @@ -30,9 +30,7 @@ public static function register($filters) */ public static function run($filters, $parameters = array(), $override = false) { - if (is_string($filters)) $filters = explode('|', $filters); - - foreach ((array) $filters as $filter) + foreach (static::parse($filters) as $filter) { // Parameters may be passed into routes by specifying the list of // parameters after a colon. If parameters are present, we will @@ -57,4 +55,127 @@ public static function run($filters, $parameters = array(), $override = false) } } + /** + * Parse a string of filters into an array. + * + * @param string|array $filters + * @return array + */ + public static function parse($filters) + { + return (is_string($filters)) ? explode('|', $filters) : (array) $filters; + } + +} + +class Filter_Collection { + + /** + * The event being filtered. + * + * @var string + */ + public $name; + + /** + * The included controller methods. + * + * @var array + */ + public $only = array(); + + /** + * The excluded controller methods. + * + * @var array + */ + public $except = array(); + + /** + * The filters contained by the collection. + * + * @var string|array + */ + public $filters = array(); + + /** + * Create a new filter collection instance. + * + * @param string $name + * @param string|array $filters + */ + public function __construct($name, $filters) + { + $this->name = $name; + $this->filters = Filter::parse($filters); + } + + /** + * Determine if this collection's filters apply to a given method. + * + * @param string $method + * @return bool + */ + public function applies($method) + { + if (count($this->only) > 0 and ! in_array($method, $this->only)) + { + return false; + } + + if (count($this->except) > 0 and in_array($method, $this->except)) + { + return false; + } + + return true; + } + + /** + * Set the excluded controller methods. + * + * When methods are excluded, the collection's filters will be run for each + * controller method except those explicitly specified via this method. + * + * + * // Specify a filter for all methods except "index" + * $this->filter('before', 'auth')->except('index'); + * + * // Specify a filter for all methods except "index" and "home" + * $this->filter('before', 'auth')->except(array('index', 'home')); + * + * + * @param array $methods + * @return Filter_Collection + */ + public function except($methods) + { + $this->except = (array) $methods; + return $this; + } + + /** + * Set the included controller methods. + * + * This method is the inverse of the "except" methods. The methods specified + * via this method are the only controller methods on which the collection's + * filters will be run. + * + * + * // Specify a filter for only the "index" method + * $this->filter('before', 'auth')->only('index'); + * + * // Specify a filter for only the "index" and "home" methods + * $this->filter('before', 'auth')->only(array('index', 'home')); + * + * + * @param array $methods + * @return Filter_Collection + */ + public function only($methods) + { + $this->only = (array) $methods; + return $this; + } + } \ No newline at end of file