<?php namespace elanpl\L3; define('_L3_ROUTE_404_NAME', '_L3_404'); class Router{ protected $routes; // The defined routes collection protected $routeNameIndex; // An array with elements that reference to the routes ordered by a route names public $parsedParameters; // Parameters parsed from Request Path public $depth; // Number of nested nodes in Request Path public $routeInfo; // The RouteInfo object if the route was matched public function __construct($routing) { $this->routes = array(); $this->routeNameIndex = array(); //Set the routing from configuration object $routing->set($this); } public function add($method, $path, $result, $name = ''){ $this->routes[] = new RouteInfo($method, $path, $result, $name); if(isset($name)&&$name!='') $this->routeNameIndex[$name] = &$this->routes[count($this->routes)-1]; return $this; } public function add_preg($method, $path, $result, $name = ''){ $this->routes[] = new RouteInfo($method, $path, $result, $name, RouteInfo::REGEX); if(isset($name)&&$name!='') $this->routeNameIndex[$name] = &$this->routes[count($this->routes)-1]; return $this; } public function add404($result){ return $this->add('404', '', $result, _L3_ROUTE_404_NAME); } public function get($path, $result, $name = ''){ return $this->add('GET', $path, $result, $name); } public function post($path, $result, $name = ''){ return $this->add('POST', $path, $result, $name); } public function put($path, $result, $name = ''){ return $this->add('PUT', $path, $result, $name); } public function patch($path, $result, $name = ''){ return $this->add('PATCH', $path, $result, $name); } public function delete($path, $result, $name = ''){ return $this->add('DELETE', $path, $result, $name); } public function any($path, $result, $name = ''){ return $this->add('ANY', $path, $result, $name); } // Regular expression based routes public function get_preg($path, $result, $name = ''){ return $this->add_preg('GET', $path, $result, $name); } public function post_preg($path, $result, $name = ''){ return $this->add_preg('POST', $path, $result, $name); } public function put_preg($path, $result, $name = ''){ return $this->add_preg('PUT', $path, $result, $name); } public function patch_preg($path, $result, $name = ''){ return $this->add_preg('PATCH', $path, $result, $name); } public function delete_preg($path, $result, $name = ''){ return $this->add_preg('DELETE', $path, $result, $name); } public function any_preg($path, $result, $name = ''){ return $this->add_preg('ANY', $path, $result, $name); } public function addBeforeAction($event_handler){ $this->routes[count($this->routes)-1]->addBeforeAction($event_handler); return $this; } public function addAfterAction($event_handler){ $this->routes[count($this->routes)-1]->addAfterAction($event_handler); return $this; } public function addAfterResult($event_handler){ $this->routes[count($this->routes)-1]->addAfterAction($event_handler); return $this; } public function match($request){ $auri = explode('/', trim($request->path, "/ \t\n\r\0\x0B")); $curi = count($auri); foreach ($this->routes as $routeInfo) { if($routeInfo->type == RouteInfo::L3){ $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... $this->parsedParameters[$valueKey[0]] = $value; } } if($matchResult){ // match found $this->depth = $curi; $this->routeInfo = $routeInfo; return $routeInfo->result; } } } } if($routeInfo->type == RouteInfo::REGEX){ $route_pattern = $routeInfo->path; $method = $routeInfo->method; if($method=='ANY' || strpos($request->method, $method)!==false){ if(\preg_match($route_pattern, $request->path, $match)){ $this->parsedParameters = $match; $this->depth = $curi; $this->routeInfo = $routeInfo; return $routeInfo->result; } } } } return false; } public function getRouteInfo($name){ if(isset($this->routeNameIndex[$name])) return $this->routeNameIndex[$name]; else return false; } public function calculateRequestDepth($request){ return count(explode('/',trim($request->path, "/ \t\n\r\0\x0B"))); } public function setMatch404($request){ if($routeInfo404 = $this->getRouteInfo(_L3_ROUTE_404_NAME)){ $this->depth = $this->calculateRequestDepth($request); $this->routeInfo = $routeInfo404; return $routeInfo404->result; } else{ return false; } } public function is_Match404(){ return isset($this->routeInfo) && ($this->routeInfo->name === _L3_ROUTE_404_NAME); } public function link($name, $parameters){ $route = $this->routeNameIndex[$name]; if($route->type == RouteInfo::REGEX){ throw new \Exception("Method Router::link not applicable to REGEX routes."); } $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 getParameter($name){ return $this->parsedParameters[$name]; } }