123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329 |
- <?php namespace Laravel\Routing;
- use Closure;
- use Laravel\Bundle;
- use Laravel\Request;
- class Filter {
- /**
- * The route filters for the application.
- *
- * @var array
- */
- public static $filters = array();
- /**
- * The route filters that are based on pattern.
- *
- * @var array
- */
- public static $patterns = array();
- /**
- * All of the registered filter aliases.
- *
- * @var array
- */
- public static $aliases = array();
- /**
- * Register a filter for the application.
- *
- * <code>
- * // Register a closure as a filter
- * Filter::register('before', function() {});
- *
- * // Register a class callback as a filter
- * Filter::register('before', array('Class', 'method'));
- * </code>
- *
- * @param string $name
- * @param mixed $callback
- * @return void
- */
- public static function register($name, $callback)
- {
- if (isset(static::$aliases[$name])) $name = static::$aliases[$name];
- // If the filter starts with "pattern: ", the filter is being setup to match on
- // all requests that match a given pattern. This is nice for defining filters
- // that handle all URIs beginning with "admin" for example.
- if (starts_with($name, 'pattern: '))
- {
- foreach (explode(', ', substr($name, 9)) as $pattern)
- {
- static::$patterns[$pattern] = $callback;
- }
- }
- else
- {
- static::$filters[$name] = $callback;
- }
- }
- /**
- * Alias a filter so it can be used by another name.
- *
- * This is convenient for shortening filters that are registered by bundles.
- *
- * @param string $filter
- * @param string $alias
- * @return void
- */
- public static function alias($filter, $alias)
- {
- static::$aliases[$alias] = $filter;
- }
- /**
- * Parse a filter definition into an array of filters.
- *
- * @param string|array $filters
- * @return array
- */
- public static function parse($filters)
- {
- return (is_string($filters)) ? explode('|', $filters) : (array) $filters;
- }
- /**
- * Call a filter or set of filters.
- *
- * @param array $collections
- * @param array $pass
- * @param bool $override
- * @return mixed
- */
- public static function run($collections, $pass = array(), $override = false)
- {
- foreach ($collections as $collection)
- {
- foreach ($collection->filters as $filter)
- {
- list($filter, $parameters) = $collection->get($filter);
- // We will also go ahead and start the bundle for the developer. This allows
- // the developer to specify bundle filters on routes without starting the
- // bundle manually, and performance is improved by lazy-loading.
- Bundle::start(Bundle::name($filter));
- if ( ! isset(static::$filters[$filter])) continue;
- $callback = static::$filters[$filter];
- // Parameters may be passed into filters by specifying the list of parameters
- // as an array, or by registering a Closure which will return the array of
- // parameters. If parameters are present, we will merge them with the
- // parameters that were given to the method.
- $response = call_user_func_array($callback, array_merge($pass, $parameters));
- // "Before" filters may override the request cycle. For example, an auth
- // filter may redirect a user to a login view if they are not logged in.
- // Because of this, we will return the first filter response if
- // overriding is enabled for the filter collections
- if ( ! is_null($response) and $override)
- {
- return $response;
- }
- }
- }
- }
- }
- class Filter_Collection {
- /**
- * The filters contained by the collection.
- *
- * @var string|array
- */
- public $filters = array();
- /**
- * The parameters specified for the filter.
- *
- * @var mixed
- */
- public $parameters;
- /**
- * The included controller methods.
- *
- * @var array
- */
- public $only = array();
- /**
- * The excluded controller methods.
- *
- * @var array
- */
- public $except = array();
- /**
- * The HTTP methods for which the filter applies.
- *
- * @var array
- */
- public $methods = array();
- /**
- * Create a new filter collection instance.
- *
- * @param string|array $filters
- * @param mixed $parameters
- * @return void
- */
- public function __construct($filters, $parameters = null)
- {
- $this->parameters = $parameters;
- $this->filters = Filter::parse($filters);
- }
- /**
- * Parse the filter string, returning the filter name and parameters.
- *
- * @param string $filter
- * @return array
- */
- public function get($filter)
- {
- // If the parameters were specified by passing an array into the collection,
- // then we will simply return those parameters. Combining passed parameters
- // with parameters specified directly in the filter attachment is not
- // currently supported by the framework.
- if ( ! is_null($this->parameters))
- {
- return array($filter, $this->parameters());
- }
- // If no parameters were specified when the collection was created, we will
- // check the filter string itself to see if the parameters were injected
- // into the string as raw values, such as "role:admin".
- if (($colon = strpos(Bundle::element($filter), ':')) !== false)
- {
- $parameters = explode(',', substr(Bundle::element($filter), $colon + 1));
- // If the filter belongs to a bundle, we need to re-calculate the position
- // of the parameter colon, since we originally calculated it without the
- // bundle identifier because the identifier uses colons as well.
- if (($bundle = Bundle::name($filter)) !== DEFAULT_BUNDLE)
- {
- $colon = strlen($bundle.'::') + $colon;
- }
- return array(substr($filter, 0, $colon), $parameters);
- }
- // If no parameters were specified when the collection was created or
- // in the filter string, we will just return the filter name as is
- // and give back an empty array of parameters.
- return array($filter, array());
- }
- /**
- * Evaluate the collection's parameters and return a parameters array.
- *
- * @return array
- */
- protected function parameters()
- {
- if ($this->parameters instanceof Closure)
- {
- $this->parameters = call_user_func($this->parameters);
- }
- return $this->parameters;
- }
- /**
- * 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;
- }
- $request = strtolower(Request::method());
- if (count($this->methods) > 0 and ! in_array($request, $this->methods))
- {
- return false;
- }
- return true;
- }
- /**
- * Set the excluded controller methods.
- *
- * <code>
- * // 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'));
- * </code>
- *
- * @param array $methods
- * @return Filter_Collection
- */
- public function except($methods)
- {
- $this->except = (array) $methods;
- return $this;
- }
- /**
- * Set the included controller methods.
- *
- * <code>
- * // 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'));
- * </code>
- *
- * @param array $methods
- * @return Filter_Collection
- */
- public function only($methods)
- {
- $this->only = (array) $methods;
- return $this;
- }
- /**
- * Set the HTTP methods for which the filter applies.
- *
- * <code>
- * // Specify that a filter only applies on POST requests
- * $this->filter('before', 'csrf')->on('post');
- *
- * // Specify that a filter applies for multiple HTTP request methods
- * $this->filter('before', 'csrf')->on(array('post', 'put'));
- * </code>
- *
- * @param array $methods
- * @return Filter_Collection
- */
- public function on($methods)
- {
- $this->methods = array_map('strtolower', (array) $methods);
- return $this;
- }
- }
|