<?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 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);
}
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) {
$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;
}
}
}
}
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];
$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];
}
}