src/Router.php
53e0de50
 <?php
 
 namespace elanpl\L3;
 
 class Router{
 
     //protected static $_instance; // object instance (for fluent api)
     protected static $routes; // The defined routes collection
     protected static $parsedParameters; // Parameters parsed from Request Path
     protected static $depth; // Number of nested nodes in Request Path
     protected static $routeNameIndex; // An array with elements that reference to the routes ordered by a route names
     public static $RouteInfo; // The RouteInfo objcet if the route was matched
 
     public function __construct()
     {
         //if(!isset(self::$_instance)) self::$_instance = new self;
         if(!isset(self::$routes)) self::$routes = array(); 
         if(!isset(self::$routeNameIndex)) self::$routeNameIndex= array();
     }
 
     public static function add($Method, $Path, $Result, $Name = ''){
         self::$routes[] = new RouteInfo($Method, $Path, $Result, $Name);
         if(isset($Name)&&$Name!='') self::$routeNameIndex[$Name] = &self::$routes[count(self::$routes)-1];
         return new self;
     }
 
     public static function get($Path, $Result, $Name = ''){
         return self::add('GET', $Path, $Result, $Name);
     }
 
     public static function post($Path, $Result, $Name = ''){
         return self::add('POST', $Path, $Result, $Name);
     }
 
     public static function put($Path, $Result, $Name = ''){
         return self::add('PUT', $Path, $Result, $Name);
     }
 
     public static function patch($Path, $Result, $Name = ''){
         return self::add('PATCH', $Path, $Result, $Name);
     }
 
     public static function delete($Path, $Result, $Name = ''){
         return self::add('DELETE', $Path, $Result, $Name);
     }
 
     public static function any($Path, $Result, $Name = ''){
         return self::add('ANY', $Path, $Result, $Name);
     }
 
     public static function AddBeforeAction($event_handler){
         self::$routes[count(self::$routes)-1]->AddBeforeAction($event_handler);
         return new self;
     }
 
     public static function AddAfterAction($event_handler){
         self::$routes[count(self::$routes)-1]->AddAfterAction($event_handler);
         return new self;
     }
 
     public static function AddAfterResult($event_handler){
         self::$routes[count(self::$routes)-1]->AddAfterAction($event_handler);
         return new self;
     }
 
     public static function match($Request){
 
         $auri = explode('/', trim($Request->Path, "/ \t\n\r\0\x0B"));
         $curi = count($auri);
 			
         foreach (self::$routes as $routeInfo) {
             
             $route = $routeInfo->Path;
             $method = $routeInfo->Method;
             if($method=='ANY' || strpos($Request->Method,$method)!==false){
                 $aroute = explode('/', trim($route, "/ \t\n\r\0\x0B"));
                 //print_r($aroute);
                 if($curi==count($aroute)){ //compare path element count
                     //optimistic assumption :)
                     $matchResult = true;
                     for($i = 0; $i<$curi; $i++){
                         $pathPartName = trim($aroute[$i],'{}');
                         if($aroute[$i]==$pathPartName){
                             if($auri[$i]!=$pathPartName){
                                 //echo "diffrence found";
                                 $matchResult = false;
                                 break;
                             }
                         }
                         else{ // {...} found -> catch $uri variable
                             $value = $auri[$i];
                             $valueKey = explode(':', $pathPartName);
                             //validation
                             if(isset($valueKey[1]) && $valueKey[1]=='int'){
                                 $value = intval($value);
                             }
                             //value store...
                             self::$parsedParameters[$valueKey[0]] = $value;
                         }
                     }
                     if($matchResult){ // match found
                         self::$depth = $curi;
                         self::$RouteInfo = $routeInfo;
                         return $routeInfo->Result;
                     }
                 }
             }
         }
         return false;
     }
 
     public static function link($name, $parameters){
         $route = self::$routeNameIndex[$name];
         $fields = array_keys($parameters);
         $values = array_values($parameters);
         array_walk($fields, function (&$item, $key){
             $item = "/\{".$item."\}/";
         });
         return preg_replace($fields, $values, $route->Path);
     }
 
     public function __get($name)
     {
         if($name=="routes") return self::$routes;
         if($name=="parsedParameters") return self::$parsedParameters;
         if($name=="depth") return self::$depth;
         if($name=="RouteInfo") return self::$RouteInfo;
     }
 
     public function __call($name, $arguments)
     {
         if($name == 'GetParameter'){
             return self::$parsedParameters[$arguments[0]];
         }
         // Note: value of $name is case sensitive.
         $allowed_methods = ['add', 'post', 'any', 'get', 'match', 'AddBeforeAction', 'AddAfterAction', 'AddAfterResult'];
 
         if(in_array($name, $allowed_methods)){
             $the_method = new \ReflectionMethod($this, $name);
             $the_method->invokeArgs(NULL,$arguments);
         }
         else{
             throw new \Exception("Call undefined or inaccesible method ".get_class($this)."::$name");
         }
         
     }
 
 }