]> git.andy128k.dev Git - ipf.git/commitdiff
router expressions
authorAndrey Kutejko <andy128k@gmail.com>
Thu, 4 Jul 2013 19:23:41 +0000 (22:23 +0300)
committerAndrey Kutejko <andy128k@gmail.com>
Thu, 4 Jul 2013 19:23:41 +0000 (22:23 +0300)
ipf/http/url.php
ipf/project.php
ipf/router.php
ipf/template/tag/url.php

index ea8502608333d6e81c71c4da1bcf701d03709678..5f6c843df9b5bf7350e3fdf800aa8d97094344e5 100644 (file)
@@ -33,65 +33,10 @@ class IPF_HTTP_URL
         return '/';
     }
 
-    public static function urlForView($view, $params=array(), $by_name=false,
-                                      $get_params=array(), $encoded=true)
+    public static function urlForView($view, $params=array(), $get_params=array(), $encoded=true)
     {
-        $action = self::reverse($view, $params, $by_name);
+        $action = IPF_Project::getInstance()->router->reverse($view, $params);
         return self::generate($action, $get_params, $encoded);
     }
-
-    public static function reverse($view, $params=array(), $by_name=false)
-    {
-        $regex = null;
-        
-        foreach (IPF::get('urls') as $url) {
-            $prefix = $url['prefix'];
-            foreach ($url['urls'] as $suburl){
-                if ($suburl['func']==$view){
-                    $regex = $prefix.$suburl['regex'];
-                    break;
-                }
-            }
-            if ($regex!==null)
-                break;
-        }
-        if ($regex === null) {
-            throw new IPF_Exception('Error, the view: '.$view.' has not been found.');
-        }
-        $url = self::buildReverseUrl($regex, $params);
-        return IPF::get('app_base').$url;
-    }
-
-    public static function buildReverseUrl($url_regex, $params=array())
-    {
-        $url_regex = str_replace('\\.', '.', $url_regex);
-        $url_regex = str_replace('\\-', '-', $url_regex);
-        $url = $url_regex;
-        $groups = '#\(([^)]+)\)#';
-        $matches = array();
-        preg_match_all($groups, $url_regex, $matches);
-        reset($params);
-        if (count($matches[0]) && count($matches[0]) == count($params)) {
-            // Test the params against the pattern
-            foreach ($matches[0] as $pattern) {
-                $in = current($params);
-                if (0 === preg_match('#'.$pattern.'#', $in)) {
-                    throw new IPF_Exception('Error, param: '.$in.' is not matching the pattern: '.$pattern);
-                }
-                next($params);
-            }
-            $func = create_function('$matches', 
-                                    'static $p = '.var_export($params, true).'; '.
-                                    '$a = current($p); '.
-                                    'next($p); '.
-                                    'return $a;');
-            $url = preg_replace_callback($groups, $func, $url_regex);
-        }
-        $url = substr(substr($url, 2), 0, -2);
-        if (substr($url, -1) !== '$') {
-            return $url;
-        }
-        return substr($url, 0, -1);
-    }
 }
 
index 7c575eafef5123438ede9c584e49171e5ff33ba8..aebcf8bfec84d50aa004238d70e05a2bad04c25a 100644 (file)
@@ -3,6 +3,7 @@
 final class IPF_Project
 {
     private $apps = array();
+    public $router = null;
     public $sqlProfiler = null;
 
     static private $instance = NULL;
index b790630b112cdff2d3c15a4be5326e135455660e..6af909e4563c8afc95e28aaa5e24cc363f9e3771 100644 (file)
@@ -2,6 +2,28 @@
 
 class IPF_Router
 {
+    private $routes = array();
+
+    public function __construct()
+    {
+        foreach (IPF::get('urls') as $url) {
+            $prefix = $url['prefix'];
+            foreach ($url['urls'] as $suburl) {
+                if (isset($suburl['regex']))
+                    $matcher = new IPF_Router_RegexMatch($prefix . $suburl['regex']);
+                elseif (isset($suburl['expr']))
+                    $matcher = RouteExpression::compile($prefix . $suburl['expr']);
+                else
+                    throw new IPF_Exception('Unsupported route type');
+
+                $this->routes[] = array(
+                    $matcher,
+                    $suburl['func'],
+                );
+            }
+        }
+    }
+
     public static function response500($e)
     {
         error_log($e);
@@ -11,7 +33,7 @@ class IPF_Router
             return new IPF_HTTP_Response_ServerError($e);
     }
 
-    public static function dispatch($query='')
+    public function dispatch($query='')
     {
         try{
             $query = preg_replace('#^(/)+#', '/', '/'.$query);
@@ -33,7 +55,7 @@ class IPF_Router
                 }
             }
             if ($skip === false) {   
-                $response = IPF_Router::match($req);
+                $response = $this->match($req);
                 if (!empty($req->response_vary_on)) {
                     $response->headers['Vary'] = $req->response_vary_on;
                 }
@@ -48,50 +70,110 @@ class IPF_Router
             }
             return array($req, $response);
         } catch (IPF_Exception $e) {
-            $response = IPF_Router::response500($e);
+            $response = self::response500($e);
             $response->render();
         }
    }
 
-    public static function match($req)
+    public function match($req)
     {
-        foreach (IPF::get('urls') as $url) {
-            $prefix = $url['prefix'];
-            foreach ($url['urls'] as $suburl){
-                $regex = $prefix.$suburl['regex'];
-                $match = array();
-                if (preg_match($regex, $req->query, $match)) {
-                    try{
-                        IPF::loadFunction($suburl['func']);
-                        $r = $suburl['func']($req, $match);
-                        if (!is_a($r,'IPF_HTTP_Response')){
-                            return IPF_Router::response500(new IPF_Exception('function '.$suburl['func'].'() must return IPF_HTTP_Response instance'));
-                        }
-                        return $r;
-                    } catch (IPF_HTTP_Error404 $e) {
-                        return new IPF_HTTP_Response_NotFound($req);
-                    } catch (IPF_Exception $e) {
-                        return IPF_Router::response500($e);
-                    }
+        $func = null;
+        foreach ($this->routes as $route) {
+            $match = array();
+            if ($route[0]->match($req->query, $match)) {
+                $func = $route[1];
+                break;
+            }
+        }
+
+        if ($func) {
+            try {
+                IPF::loadFunction($func);
+                $r = $func($req, $match);
+                if (!is_a($r, 'IPF_HTTP_Response')) {
+                    return self::response500(new IPF_Exception('function '.$func.'() must return IPF_HTTP_Response instance'));
                 }
+                return $r;
+            } catch (IPF_HTTP_Error404 $e) {
+                return new IPF_HTTP_Response_NotFound($req);
+            } catch (IPF_Exception $e) {
+                return self::response500($e);
             }
         }
+
         return new IPF_HTTP_Response_NotFound($req);
     }
 
-    public static function describe()
+    public function describe()
     {
-        $routes = array();
-        foreach (IPF::get('urls') as $url) {
-            $prefix = $url['prefix'];
-            foreach ($url['urls'] as $suburl) {
-                $routes[] = array(
-                    $prefix . $suburl['regex'],
-                    $suburl['func'],
-                );
+        $result = array();
+        foreach ($this->routes as $route) {
+            $result[] = array(
+                (string)$route[0],
+                $route[1],
+            );
+        }
+        return $result;
+    }
+
+    public function reverse($view, $params=array())
+    { 
+        foreach ($this->routes as $route)
+            if ($route[1] == $view)
+                return IPF::get('app_base') . $route[0]->reverse($params);
+        throw new IPF_Exception('Error, the view: '.$view.' has not been found.');
+    }
+}
+
+class IPF_Router_RegexMatch
+{
+    private $regex;
+
+    public function __construct($regex)
+    {
+        $this->regex = $regex;
+    }
+
+    public function __toString()
+    {
+        return $this->regex;
+    }
+
+    public function match($query, &$matches)
+    {
+        return preg_match($this->regex, $query, $matches);
+    }
+
+    public function reverse($params)
+    {
+        $url_regex = str_replace('\\.', '.', $this->regex);
+        $url_regex = str_replace('\\-', '-', $url_regex);
+        $url = $url_regex;
+        $groups = '#\(([^)]+)\)#';
+        $matches = array();
+        preg_match_all($groups, $url_regex, $matches);
+        reset($params);
+        if (count($matches[0]) && count($matches[0]) == count($params)) {
+            // Test the params against the pattern
+            foreach ($matches[0] as $pattern) {
+                $in = current($params);
+                if (0 === preg_match('#'.$pattern.'#', $in)) {
+                    throw new IPF_Exception('Error, param: '.$in.' is not matching the pattern: '.$pattern);
+                }
+                next($params);
             }
+            $func = create_function('$matches', 
+                                    'static $p = '.var_export($params, true).'; '.
+                                    '$a = current($p); '.
+                                    'next($p); '.
+                                    'return $a;');
+            $url = preg_replace_callback($groups, $func, $url_regex);
+        }
+        $url = substr(substr($url, 2), 0, -2);
+        if (substr($url, -1) !== '$') {
+            return $url;
         }
-        return $routes;
+        return substr($url, 0, -1);
     }
 }
 
index 2a3bb558f0d29ef194ebef6f95da1d4be866b72f..ec3509e492fecde056769df3cd8ee3825d256b5c 100644 (file)
@@ -2,9 +2,9 @@
 
 class IPF_Template_Tag_Url extends IPF_Template_Tag
 {
-    function start($view, $params=array(), $by_name=false, $get_params=array())
+    function start($view, $params=array(), $get_params=array())
     {
-        echo IPF_HTTP_URL::urlForView($view, $params, $by_name, $get_params);
+        echo IPF_HTTP_URL::urlForView($view, $params, $get_params);
     }
 }