rpicms

A CMS for the Raspberry Pi
git clone git://archive.git.mtrnord.blog/RpicmsTeam/rpicms.git
Log | Files | Refs | README | LICENSE

Route.php (12791B)


      1 <?php
      2 /**
      3  * Slim - a micro PHP 5 framework
      4  *
      5  * @author      Josh Lockhart <info@slimframework.com>
      6  * @copyright   2011 Josh Lockhart
      7  * @link        http://www.slimframework.com
      8  * @license     http://www.slimframework.com/license
      9  * @version     2.4.2
     10  * @package     Slim
     11  *
     12  * MIT LICENSE
     13  *
     14  * Permission is hereby granted, free of charge, to any person obtaining
     15  * a copy of this software and associated documentation files (the
     16  * "Software"), to deal in the Software without restriction, including
     17  * without limitation the rights to use, copy, modify, merge, publish,
     18  * distribute, sublicense, and/or sell copies of the Software, and to
     19  * permit persons to whom the Software is furnished to do so, subject to
     20  * the following conditions:
     21  *
     22  * The above copyright notice and this permission notice shall be
     23  * included in all copies or substantial portions of the Software.
     24  *
     25  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
     26  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
     27  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
     28  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
     29  * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
     30  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
     31  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
     32  */
     33 namespace Slim;
     34 
     35 /**
     36  * Route
     37  * @package Slim
     38  * @author  Josh Lockhart, Thomas Bley
     39  * @since   1.0.0
     40  */
     41 class Route
     42 {
     43     /**
     44      * @var string The route pattern (e.g. "/books/:id")
     45      */
     46     protected $pattern;
     47 
     48     /**
     49      * @var mixed The route callable
     50      */
     51     protected $callable;
     52 
     53     /**
     54      * @var array Conditions for this route's URL parameters
     55      */
     56     protected $conditions = array();
     57 
     58     /**
     59      * @var array Default conditions applied to all route instances
     60      */
     61     protected static $defaultConditions = array();
     62 
     63     /**
     64      * @var string The name of this route (optional)
     65      */
     66     protected $name;
     67 
     68     /**
     69      * @var array Key-value array of URL parameters
     70      */
     71     protected $params = array();
     72 
     73     /**
     74      * @var array value array of URL parameter names
     75      */
     76     protected $paramNames = array();
     77 
     78     /**
     79      * @var array key array of URL parameter names with + at the end
     80      */
     81     protected $paramNamesPath = array();
     82 
     83     /**
     84      * @var array HTTP methods supported by this Route
     85      */
     86     protected $methods = array();
     87 
     88     /**
     89      * @var array[Callable] Middleware to be run before only this route instance
     90      */
     91     protected $middleware = array();
     92 
     93     /**
     94      * @var bool Whether or not this route should be matched in a case-sensitive manner
     95      */
     96     protected $caseSensitive;
     97 
     98     /**
     99      * Constructor
    100      * @param string $pattern The URL pattern (e.g. "/books/:id")
    101      * @param mixed $callable Anything that returns TRUE for is_callable()
    102      * @param bool $caseSensitive Whether or not this route should be matched in a case-sensitive manner
    103      */
    104     public function __construct($pattern, $callable, $caseSensitive = true)
    105     {
    106         $this->setPattern($pattern);
    107         $this->setCallable($callable);
    108         $this->setConditions(self::getDefaultConditions());
    109         $this->caseSensitive = $caseSensitive;
    110     }
    111 
    112     /**
    113      * Set default route conditions for all instances
    114      * @param  array $defaultConditions
    115      */
    116     public static function setDefaultConditions(array $defaultConditions)
    117     {
    118         self::$defaultConditions = $defaultConditions;
    119     }
    120 
    121     /**
    122      * Get default route conditions for all instances
    123      * @return array
    124      */
    125     public static function getDefaultConditions()
    126     {
    127         return self::$defaultConditions;
    128     }
    129 
    130     /**
    131      * Get route pattern
    132      * @return string
    133      */
    134     public function getPattern()
    135     {
    136         return $this->pattern;
    137     }
    138 
    139     /**
    140      * Set route pattern
    141      * @param  string $pattern
    142      */
    143     public function setPattern($pattern)
    144     {
    145         $this->pattern = $pattern;
    146     }
    147 
    148     /**
    149      * Get route callable
    150      * @return mixed
    151      */
    152     public function getCallable()
    153     {
    154         return $this->callable;
    155     }
    156 
    157     /**
    158      * Set route callable
    159      * @param  mixed $callable
    160      * @throws \InvalidArgumentException If argument is not callable
    161      */
    162     public function setCallable($callable)
    163     {
    164         $matches = array();
    165         if (is_string($callable) && preg_match('!^([^\:]+)\:([a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)$!', $callable, $matches)) {
    166             $class = $matches[1];
    167             $method = $matches[2];
    168             $callable = function() use ($class, $method) {
    169                 static $obj = null;
    170                 if ($obj === null) {
    171                     $obj = new $class;
    172                 }
    173                 return call_user_func_array(array($obj, $method), func_get_args());
    174             };
    175         }
    176 
    177         if (!is_callable($callable)) {
    178             throw new \InvalidArgumentException('Route callable must be callable');
    179         }
    180 
    181         $this->callable = $callable;
    182     }
    183 
    184     /**
    185      * Get route conditions
    186      * @return array
    187      */
    188     public function getConditions()
    189     {
    190         return $this->conditions;
    191     }
    192 
    193     /**
    194      * Set route conditions
    195      * @param  array $conditions
    196      */
    197     public function setConditions(array $conditions)
    198     {
    199         $this->conditions = $conditions;
    200     }
    201 
    202     /**
    203      * Get route name
    204      * @return string|null
    205      */
    206     public function getName()
    207     {
    208         return $this->name;
    209     }
    210 
    211     /**
    212      * Set route name
    213      * @param  string $name
    214      */
    215     public function setName($name)
    216     {
    217         $this->name = (string)$name;
    218     }
    219 
    220     /**
    221      * Get route parameters
    222      * @return array
    223      */
    224     public function getParams()
    225     {
    226         return $this->params;
    227     }
    228 
    229     /**
    230      * Set route parameters
    231      * @param  array $params
    232      */
    233     public function setParams($params)
    234     {
    235         $this->params = $params;
    236     }
    237 
    238     /**
    239      * Get route parameter value
    240      * @param  string $index Name of URL parameter
    241      * @return string
    242      * @throws \InvalidArgumentException If route parameter does not exist at index
    243      */
    244     public function getParam($index)
    245     {
    246         if (!isset($this->params[$index])) {
    247             throw new \InvalidArgumentException('Route parameter does not exist at specified index');
    248         }
    249 
    250         return $this->params[$index];
    251     }
    252 
    253     /**
    254      * Set route parameter value
    255      * @param  string $index Name of URL parameter
    256      * @param  mixed $value The new parameter value
    257      * @throws \InvalidArgumentException If route parameter does not exist at index
    258      */
    259     public function setParam($index, $value)
    260     {
    261         if (!isset($this->params[$index])) {
    262             throw new \InvalidArgumentException('Route parameter does not exist at specified index');
    263         }
    264         $this->params[$index] = $value;
    265     }
    266 
    267     /**
    268      * Add supported HTTP method(s)
    269      */
    270     public function setHttpMethods()
    271     {
    272         $args = func_get_args();
    273         $this->methods = $args;
    274     }
    275 
    276     /**
    277      * Get supported HTTP methods
    278      * @return array
    279      */
    280     public function getHttpMethods()
    281     {
    282         return $this->methods;
    283     }
    284 
    285     /**
    286      * Append supported HTTP methods
    287      */
    288     public function appendHttpMethods()
    289     {
    290         $args = func_get_args();
    291         if(count($args) && is_array($args[0])){
    292             $args = $args[0];
    293         }
    294         $this->methods = array_merge($this->methods, $args);
    295     }
    296 
    297     /**
    298      * Append supported HTTP methods (alias for Route::appendHttpMethods)
    299      * @return \Slim\Route
    300      */
    301     public function via()
    302     {
    303         $args = func_get_args();
    304         if(count($args) && is_array($args[0])){
    305             $args = $args[0];
    306         }
    307         $this->methods = array_merge($this->methods, $args);
    308 
    309         return $this;
    310     }
    311 
    312     /**
    313      * Detect support for an HTTP method
    314      * @param  string $method
    315      * @return bool
    316      */
    317     public function supportsHttpMethod($method)
    318     {
    319         return in_array($method, $this->methods);
    320     }
    321 
    322     /**
    323      * Get middleware
    324      * @return array[Callable]
    325      */
    326     public function getMiddleware()
    327     {
    328         return $this->middleware;
    329     }
    330 
    331     /**
    332      * Set middleware
    333      *
    334      * This method allows middleware to be assigned to a specific Route.
    335      * If the method argument `is_callable` (including callable arrays!),
    336      * we directly append the argument to `$this->middleware`. Else, we
    337      * assume the argument is an array of callables and merge the array
    338      * with `$this->middleware`.  Each middleware is checked for is_callable()
    339      * and an InvalidArgumentException is thrown immediately if it isn't.
    340      *
    341      * @param  Callable|array[Callable]
    342      * @return \Slim\Route
    343      * @throws \InvalidArgumentException If argument is not callable or not an array of callables.
    344      */
    345     public function setMiddleware($middleware)
    346     {
    347         if (is_callable($middleware)) {
    348             $this->middleware[] = $middleware;
    349         } elseif (is_array($middleware)) {
    350             foreach ($middleware as $callable) {
    351                 if (!is_callable($callable)) {
    352                     throw new \InvalidArgumentException('All Route middleware must be callable');
    353                 }
    354             }
    355             $this->middleware = array_merge($this->middleware, $middleware);
    356         } else {
    357             throw new \InvalidArgumentException('Route middleware must be callable or an array of callables');
    358         }
    359 
    360         return $this;
    361     }
    362 
    363     /**
    364      * Matches URI?
    365      *
    366      * Parse this route's pattern, and then compare it to an HTTP resource URI
    367      * This method was modeled after the techniques demonstrated by Dan Sosedoff at:
    368      *
    369      * http://blog.sosedoff.com/2009/09/20/rails-like-php-url-router/
    370      *
    371      * @param  string $resourceUri A Request URI
    372      * @return bool
    373      */
    374     public function matches($resourceUri)
    375     {
    376         //Convert URL params into regex patterns, construct a regex for this route, init params
    377         $patternAsRegex = preg_replace_callback(
    378             '#:([\w]+)\+?#',
    379             array($this, 'matchesCallback'),
    380             str_replace(')', ')?', (string)$this->pattern)
    381         );
    382         if (substr($this->pattern, -1) === '/') {
    383             $patternAsRegex .= '?';
    384         }
    385 
    386         $regex = '#^' . $patternAsRegex . '$#';
    387 
    388         if ($this->caseSensitive === false) {
    389             $regex .= 'i';
    390         }
    391 
    392         //Cache URL params' names and values if this route matches the current HTTP request
    393         if (!preg_match($regex, $resourceUri, $paramValues)) {
    394             return false;
    395         }
    396         foreach ($this->paramNames as $name) {
    397             if (isset($paramValues[$name])) {
    398                 if (isset($this->paramNamesPath[$name])) {
    399                     $this->params[$name] = explode('/', urldecode($paramValues[$name]));
    400                 } else {
    401                     $this->params[$name] = urldecode($paramValues[$name]);
    402                 }
    403             }
    404         }
    405 
    406         return true;
    407     }
    408 
    409     /**
    410      * Convert a URL parameter (e.g. ":id", ":id+") into a regular expression
    411      * @param  array $m URL parameters
    412      * @return string       Regular expression for URL parameter
    413      */
    414     protected function matchesCallback($m)
    415     {
    416         $this->paramNames[] = $m[1];
    417         if (isset($this->conditions[$m[1]])) {
    418             return '(?P<' . $m[1] . '>' . $this->conditions[$m[1]] . ')';
    419         }
    420         if (substr($m[0], -1) === '+') {
    421             $this->paramNamesPath[$m[1]] = 1;
    422 
    423             return '(?P<' . $m[1] . '>.+)';
    424         }
    425 
    426         return '(?P<' . $m[1] . '>[^/]+)';
    427     }
    428 
    429     /**
    430      * Set route name
    431      * @param  string $name The name of the route
    432      * @return \Slim\Route
    433      */
    434     public function name($name)
    435     {
    436         $this->setName($name);
    437 
    438         return $this;
    439     }
    440 
    441     /**
    442      * Merge route conditions
    443      * @param  array $conditions Key-value array of URL parameter conditions
    444      * @return \Slim\Route
    445      */
    446     public function conditions(array $conditions)
    447     {
    448         $this->conditions = array_merge($this->conditions, $conditions);
    449 
    450         return $this;
    451     }
    452 
    453     /**
    454      * Dispatch route
    455      *
    456      * This method invokes the route object's callable. If middleware is
    457      * registered for the route, each callable middleware is invoked in
    458      * the order specified.
    459      *
    460      * @return bool
    461      */
    462     public function dispatch()
    463     {
    464         foreach ($this->middleware as $mw) {
    465             call_user_func_array($mw, array($this));
    466         }
    467 
    468         $return = call_user_func_array($this->getCallable(), array_values($this->getParams()));
    469         return ($return === false) ? false : true;
    470     }
    471 }