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 @@ use Laravel\Response;
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 @@ abstract class 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'), 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 @@ abstract class Controller {
// 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 @@ abstract class Controller {
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 @@ class Filter {
*/
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 @@ class Filter {
}
}
+ /**
+ * 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