自定义路由URL参数

时间:2015-04-16 09:38:42

标签: php routes router

我正在尝试编写自己的路由器,因为我开始了我的MVC之旅。我有它的基础知识,但是当涉及到其他URL参数时,我遇到了一些麻烦。根据我迄今为止编写代码的方式,我不知道如何处理这个问题。

这是我的代码:

公共/ index.php的

<?php

include '../config.php';
include '../routes.php';
include '../app/controllers/RouteController.php';

$rc = new RouteController($config, $routes);

?>

的config.php

<?php

$config['app_url'] = 'http://localhost/mymvc'; // no ending slashes

?>

routes.php文件

<?php

$routes = array();
$routes[] = array('url' => '', 'controller' => 'HomeController');
$routes[] = array('url' => 'leads', 'controller' => 'LeadController');
$routes[] = array('url' => 'leads/page/[0-9]', 'controller' => 'LeadController', 'method' => 'update', 'params' => 'page=$1');
$routes[] = array('url' => 'leads/create', 'controller' => 'LeadController', 'method' => 'create');
$routes[] = array('url' => 'leads/update/[0-9]', 'controller' => 'LeadController', 'method' => 'update', 'params' => 'id=$1');

?>

应用\控制器\ RouteController.php

<?php

class RouteController {

    private $config;
    private $routes;
    private $url;
    private $controller = null;
    private $method = null;
    private $params = array();

    public function __construct ($config, $routes) {
        $this->config = $config;
        $this->routes = $routes;
        $this->setUrl();
        $route_exists = false;

        // check if route has been declared for security
        foreach ($this->routes as $route) {
            if ($route['url'] == $this->url) {
                $this->controller = $route['controller'];
                $this->method = isset($route['method']) ? $route['method'] : null;
                $this->params = isset($route['params']) ? $route['params'] : array();
                $route_exists = true;
            }
        }

        // send them to app index if route does not exist
        if ($route_exists) {
            $this->route();
        }
        else {
            header('Location: '.$this->config['app_url']);
            die('route does not exist');
        }       
    }

    private function setUrl () {
        $url = trim($_GET['url'], '/');
        $url = filter_var($url, FILTER_SANITIZE_URL);
        $this->url = $url;
    }

    private function route () {
        // include '../controllers/'.$this->controller;
        // do stuff with the controller, method, params
    }

}

?>

现在,如果你查看routes.php文件,你可以从我的代码中看到它对以下路由没有问题:

<?php

$routes = array();
$routes[] = array('url' => '', 'controller' => 'HomeController');
$routes[] = array('url' => 'leads', 'controller' => 'LeadController');
$routes[] = array('url' => 'leads/create', 'controller' => 'LeadController', 'method' => 'create');

?>

我需要弄清楚的是如何在路线中处理其他参数。这些是我试图找到解决方案的有问题的路线:

$routes[] = array('url' => 'leads/page/[0-9]', 'controller' => 'LeadController', 'method' => 'update', 'params' => 'page=$1');
$routes[] = array('url' => 'leads/update/[0-9]', 'controller' => 'LeadController', 'method' => 'update', 'params' => 'id=$1');

非常感谢任何帮助。谢谢:))

1 个答案:

答案 0 :(得分:2)

将尝试演示我的例子。 Bootstrap班级:

    $uri = Router::make_uri();

    if ($params = Router::match_uri($uri))
    {
        $controller = ucwords($params['controller']).'_Controller';
        $method = $params['method'];

        unset($params['controller'], $params['method']);

        if (class_exists($controller))
        {
            if (method_exists($controller, $method))
            {
                call_user_func_array(array(new $controller, $method), $params);
            }
            else
            {
                Error::throw_error('Bootstrap : No method found '.$method);
            }
        }
        else
        {
            Error::throw_error('Bootstrap : No controller found '.$controller);
        }
    }
    else
    {
        Error::throw_error('Bootstrap : No route found '.$uri);
    }

Router班级:

public static function make_uri()
{
    if(!empty($_SERVER['PATH_INFO']))
    {
        self::$uri = $_SERVER['PATH_INFO'];
    }
    elseif (!empty($_SERVER['REQUEST_URI']))
    {
        self::$uri = $_SERVER['REQUEST_URI'];

        //removing index
        if (strpos(self::$uri, 'index.php') !== FALSE)
        {
            self::$uri = str_replace(self::$uri, 'index.php', '');
        }
    }

    return parse_url(trim(self::$uri, '/'), PHP_URL_PATH);
}

public static function match_uri($uri)
{
    require(APP_DIR.DIR_SEP.'system'.DIR_SEP.'config'.DIR_SEP.'Routes.php');

    if (empty($routes))
    {
        Error::throw_error('Routes must not be empty');
    }

    self::$routes = $routes;

    $params = array();

    foreach ($routes as $route)
    {
        //we keep our route uri in the [0] position
        $route_uri = array_shift($route);

        $regex_uri = self::make_regex_uri($route_uri);

        if (!preg_match($regex_uri, $uri, $match))
        {
            continue;
        }
        else
        {               
            foreach ($match as $key => $value)
            {
                if (is_int($key))
                {
                    //removing preg_match digit keys
                    continue;
                }

                $params[$key] = $value;
            }

            //if no values are set, load default ones
            foreach ($route as $key => $value)
            {
                if (!isset($params[$key]))
                {
                    $params[$key] = $value;
                }
            }

            break;
        }
    }

    return $params;
}

private static function make_regex_uri($uri)
{
    $reg_escape = '[.\\+*?[^\\]${}=!|]';
    $expression = preg_replace('#'.$reg_escape.'#', '\\\\$0', $uri);

    if (strpos($expression, '(') !== FALSE)
    {
        $expression = str_replace(array('(', ')'), array('(?:', ')?'), $expression);
    }

    $reg_segment = '[^/.,;?\n]++';
    $expression = str_replace(array('<', '>'), array('(?P<', '>'.$reg_segment.')'), $expression);

    return '#^'.$expression.'$#uD';
}

$routes

$routes['password'] = array(
'password(/<hash>)',
'controller' => 'account',
'method' => 'password',
'hash' => ''
);

评论:

  1. Bootstrap类接收请求并调用返回当前Router::make_uri的静态URL
  2. $uri与预设的$routes数组匹配。如果任何路由的正则表达式与当前URL匹配,则传递的值和默认值(如果未设置传递值)将添加到$params,这将在成功的正则表达式匹配时返回。
  3. $params现在具有匹配路线中定义的所有参数 - ControllerMethod和额外的参数,例如$hash
  4. 进行相应的调用(如果存在类和方法)

    Class Account_Controller
    {
        public function password($hash)
        {
            echo $hash;
        }
     }