Orion PHP  0.11.12
The PHP5.3 framework
route.php
Go to the documentation of this file.
00001 <?php
00002 namespace Orion\Core;
00003 
00004 /**
00005  * \Orion\Core\Route
00006  * 
00007  * Orion Route class
00008  *
00009  * Handles routing rules and URI parsing.
00010  *
00011  * @author Thibaut Despoulain
00012  * @license BSD 4-clauses
00013  * @version 0.11.12
00014  */
00015 class Route
00016 {
00017     /**
00018      * The 1024 error is passed as argument to the error method when no matching rule is found.
00019      */
00020     const E_NORULE = 1024;
00021 
00022     /**
00023      * Default method to be called if no rule match is found or if module is called without a route.
00024      * /!\ This method name must be given WITHOUT the security prefix, like you would declare it inside of a route rule.
00025      * By default, 'index' is used.
00026      * @var string
00027      */
00028     private $defaultMethod = 'index';
00029 
00030     /**
00031      * Method called when no rule matches the URI.
00032      * @var string 
00033      */
00034     private $errorMethod = 'error';
00035 
00036     /**
00037      * Array of routing rules.
00038      * The form is array($methodname => regex)
00039      * @var array
00040      */
00041     private $rules = array();
00042 
00043 
00044     /**
00045      * Decode current request URI into a usable RouteMethod.<br />
00046      * It's then possible to retreive the method to call and the arguments via the following getters:<br />
00047      * RouteMethod->getMethod();<br />
00048      * RouteMethod->getArgs();<br />
00049      * RouteMethod->getURI();<br />
00050      *
00051      * @return RouteMethod
00052      * @see RouteMethod
00053      */
00054     public function decode()
00055     {
00056         $uri = Context::getModuleURI();
00057 
00058         $matches = array();
00059         
00060         if($uri == '' || $uri == '/')
00061             return new RouteMethod($this->defaultMethod, null, $uri);
00062 
00063         foreach($this->rules as $regex => $method)
00064         {
00065             if(preg_match(Tools::translateRegex($regex).'six', $uri, $matches))
00066             {
00067                 array_shift($matches);
00068                 return new RouteMethod($method, $matches, $uri);
00069             }
00070         }
00071 
00072         return new RouteMethod($this->errorMethod, array(self::E_NORULE), $uri);
00073         
00074     }
00075         
00076     /**
00077     * Decode current request URI into a usable OrionRouteMethod using an automated parser.<br />
00078     * It's then possible to retreive the method to call and the arguments via the following getters:<br />
00079     * OrionRouteMethod->getMethod();<br />
00080     * OrionRouteMethod->getArgs();<br />
00081     * OrionRouteMethod->getURI();<br />
00082     *
00083     * @return OrionRouteMethod
00084     * @see OrionRouteMethod
00085     */
00086     public function decodeAuto()
00087     {
00088         $uri = Context::$MODULE_URI;
00089         $matches = array();
00090 
00091         if($uri == '' || $uri == '/')
00092             return new RouteMethod($this->defaultMethod, null, $uri);
00093 
00094 
00095         if(preg_match('/^([a-zA-Z0-9_-]+)\/(.*)$/i', $uri, $matches))
00096         {
00097             array_shift($matches);
00098             $method = array_shift($matches);
00099             $args = array_shift($matches);
00100 
00101             if(\Orion::config()->defined('ROUTE_AUTO_ARGSEP'))
00102                 $cargs = explode(\Orion::config()->get('ROUTE_AUTO_ARGSEP'), $args);
00103             else
00104                 $cargs = array($args);
00105 
00106             return new RouteMethod($method, $cargs, $uri);
00107         }
00108         elseif(preg_match('/^([a-zA-Z0-9_-]+)$/i', $uri, $matches))
00109         {
00110             array_shift($matches);
00111             $method = array_shift($matches);
00112             return new RouteMethod($method, null, $uri);
00113         }
00114 
00115         return new RouteMethod($this->errorMethod, array(self::E_NORULE), $uri);
00116     }
00117 
00118     /**
00119      * Adds a new routing rule to parse URIs.
00120      * Rules are identified by their regex, thus, it's impossible to have the same regex for two different functions.<br />
00121      * <b>'index' method rule (blank regex) is implicit and thus doesn't needs to be added, but you can still define a 'index.html' rule mapped to the _index function.</b> Note that while the rule is implicit, the function itself as to be manualy overriden in the module.
00122      * @param string $regex
00123      *          Must be either a PCRE regex or a custom Easy-regex<br />
00124      *          Example : 'article-?-@-*.html' is the Easy-regex equivalent to '#article\-([a-zA-Z0-9_-]+)\-(\d+)-(.*?)\.html$#')
00125      *          If the method has a dynamic number of arguments or facultative arguments, you have to add a rule for each possible URI.
00126      * @param string $method the method name to be called (without any security character, see OrionModule callback for more)
00127          */
00128     public function addRule($regex, $method)
00129     {
00130         $this->rules[$regex] = $method;
00131     }
00132 
00133     /**
00134      * Set the default method to be called with empty or '/' URI.
00135      * @param string $method
00136      */
00137     public function setDefaultMethod($method)
00138     {
00139         $this->defaultMethod = $method;
00140     }
00141 
00142     /**
00143      * Set the error method to be called if no rule match is found or if module is called without a route.
00144      * @param string $method
00145      */
00146     public function setErrorMethod($method)
00147     {
00148         $this->errorMethod = $method;
00149     }
00150 
00151     /**
00152      * Get defined rules
00153      * @return array Rules
00154      */
00155     public function getRules()
00156     {
00157         return $this->rules;
00158     }
00159 
00160 }
00161 /**
00162  * OrionRoute subclass Method.
00163  * Handles OrionRoute decode response.
00164  *
00165  * @author Thibaut Despoulain
00166  */
00167 class RouteMethod
00168 {
00169         /**
00170          * Decoded method name (without any security escaping character like the default '_')
00171          * @var string
00172          */
00173         private $name;
00174 
00175         /**
00176          * Decoded method args, to use with call_user_func_array($function, $param_array)
00177          * @var array<mixed>
00178          */
00179         private $args;
00180 
00181         /**
00182          * The decoded URI
00183          * @var string
00184          */
00185         private $uri;
00186 
00187         /**
00188          * Builds an OrionRouteMethod response used to call rule-linked methods
00189          * @param string $_method
00190          * @param array<mixed> $_args
00191          * @param string $_uri
00192          */
00193         public function  __construct($_name, $_args, $_uri)
00194         {
00195                 $this->name = $_name;
00196                 $this->args = $_args;
00197                 $this->uri = $_uri;
00198         }
00199 
00200         /**
00201          * Get the decoded method name (without any security escaping character like the default '_')
00202          * @return string
00203          */
00204         public function getName()
00205         {
00206                 return $this->name;
00207         }
00208 
00209         /**
00210          * Get the decoded method args, to use with call_user_func_array($function, $param_array)
00211          * @return array<mixed>
00212          */
00213         public function getArgs()
00214         {
00215                 return $this->args;
00216         }
00217 
00218         /**
00219          * Get the decoded URI
00220          * @return string
00221          */
00222         public function getURI()
00223         {
00224                 return $this->uri;
00225         }
00226 }
00227 
00228 ?>