dotxxh0998 2014-02-17 14:15
浏览 52
已采纳

ZF1:数据库中的路由

I'm building a simple CMS module for my ZendFramework application.

Currently I have all my routes in a .ini file, would it be possible to make it db-driven. Or if it's possible to build a fallback method to a DB-check if the route doesn't exists in the .ini file.

UPDATE - SOLUTION

Hope this will help somebody - Please note that I have custom My_Db_table and My_Db_Row, which I haven't posted here. So ->fetchAllActive() probably needs change to ->fetchAll(); and the getters on the row object may/may-not work, can't remember if they are custom - you'll figure it out ;-)

But Router basically check against DB if none of the other routes apply, i.e. from a .ini file. I haven't checked if this works with all the route types, but it works with the default route type. I use DB routes to point urls down to a pageController with additional params like pageId stored as a JSON string in the route_defaults cell. But you can basically use this for all kind of routes.

In bootstrap

function _initApplication ()
{
    // Something taken out for simplicity

    $this->bootstrap('frontcontroller');
    $front = $this->getResource('frontcontroller');

    $router = new My_Controller_Router_Rewrite();
    $front->setRouter($router);

    // Something taken out for simplicity        
}

My/Controller/Router/Rewrite.php

<?php

class My_Controller_Router_Rewrite extends Zend_Controller_Router_Rewrite
{


    /**
     * Retrieve a named route
     *
     * @param string $name Name of the route
     * @throws Zend_Controller_Router_Exception
     * @return Zend_Controller_Router_Route_Interface Route object
     */
    public function getRoute($name)
    {
        if (!isset($this->_routes[$name])) {
            /* BEGIN - DB routes */
            $routes = new Routes();
            $route = $routes->getNamedRoute($name);
            if($route instanceof Zend_Controller_Router_Route_Abstract) {
                $this->addRoute($name, $route); 
            }
            /* END - DB routes */
            if (!isset($this->_routes[$name])) {
                require_once 'Zend/Controller/Router/Exception.php';
                throw new Zend_Controller_Router_Exception("Route $name is not defined");
            }
        }

        return $this->_routes[$name];
    }


    /**
     * Find a matching route to the current PATH_INFO and inject
     * returning values to the Request object.
     *
     * @throws Zend_Controller_Router_Exception
     * @return Zend_Controller_Request_Abstract Request object
     */
    public function route(Zend_Controller_Request_Abstract $request)
    {
        if (!$request instanceof Zend_Controller_Request_Http) {
            require_once 'Zend/Controller/Router/Exception.php';
            throw new Zend_Controller_Router_Exception('Zend_Controller_Router_Rewrite requires a Zend_Controller_Request_Http-based request object');
        }

        if ($this->_useDefaultRoutes) {
            $this->addDefaultRoutes();
        }

        // Find the matching route
        $routeMatched = false;

        foreach (array_reverse($this->_routes, true) as $name => $route) {
            // TODO: Should be an interface method. Hack for 1.0 BC
            if (method_exists($route, 'isAbstract') && $route->isAbstract()) {
                continue;
            }

            // TODO: Should be an interface method. Hack for 1.0 BC
            if (!method_exists($route, 'getVersion') || $route->getVersion() == 1) {
                $match = $request->getPathInfo();
            } else {
                $match = $request;
            }

            if ($params = $route->match($match)) {
                $this->_setRequestParams($request, $params);
                $this->_currentRoute = $name;
                $routeMatched        = true;
                break;
            }
        }

        /* BEGIN - DB routes */
        $front = Zend_Controller_Front::getInstance();

        if (!$routeMatched || ($routeMatched && !Zend_Controller_Front::getInstance()->getDispatcher()->isDispatchable($request))) {
            $routes = new Routes();
            $dbRoutes = $routes->getRouterRoutes();

            foreach ($dbRoutes as $name => $route) {
                // TODO: Should be an interface method. Hack for 1.0 BC
                if (method_exists($route, 'isAbstract') && $route->isAbstract()) {
                    continue;
                }

                // TODO: Should be an interface method. Hack for 1.0 BC
                if (!method_exists($route, 'getVersion') || $route->getVersion() == 1) {
                    $match = $request->getPathInfo();
                } else {
                    $match = $request;
                }

                if ($params = $route->match($match)) {
                    $this->_setRequestParams($request, $params);
                    $this->_currentRoute = $name;
                    $routeMatched        = true;
                    break;
                }
            }
        }
        /* END - DB routes */

        if(!$routeMatched) {
            require_once 'Zend/Controller/Router/Exception.php';
            throw new Zend_Controller_Router_Exception('No route matched the request', 404);
        }

        if($this->_useCurrentParamsAsGlobal) {
            $params = $request->getParams();
            foreach($params as $param => $value) {
                $this->setGlobalParam($param, $value);
            }
        }

        return $request;

    }

}

Routes Db_Table model

<?php

class Routes extends My_Db_Table
{
    protected $_name = 'routes';
    protected $_rowClass = 'Route';

    public static $primaryColumn = 'route_id';
    public static $statusColumn = 'route_status';
    public static $nameColumn = 'route_name';
    public static $typeColumn = 'route_type';
    public static $urlColumn = 'route_url';
    public static $moduleColumn = 'route_module';
    public static $controllerColumnn = 'route_controller';
    public static $actionColumnn = 'route_action';
    public static $defaultsColumnn = 'route_defaults';
    public static $reqsColumnn = 'route_reqs';
    public static $createdColumnn = 'route_created';

    public function getRouterRoutes() {
        $routes = array();
        $rowset = $this->fetchAllActive();
        foreach($rowset as $row) {
            $routes[$row->getName()] = $row->getRouteObject();
        }
        return $routes;     
    }

    public function getNamedRoute($name) {
        $select = $this->select()
                        ->where(self::$statusColumn . ' = ?', 1)
                        ->where(self::$nameColumn . ' = ?', $name);
        $rowset = $this->fetchAll($select);
        foreach($rowset as $row) {
            return $row->getRouteObject();
        }
    }
}

Route - Db_Table_row

<?php

class Route extends My_Db_Table_Row_Observable
{

    public function getType() {
        if(empty($this->{Routes::$typeColumn})) {
            return "Zend_Controller_Router_Route";
        } else {
            return $this->{Routes::$typeColumn};
        }
    }

    public function getDefaults() {
        $defaults = $this->{Routes::$defaultsColumnn};
        if($defaults) {
            $defaults = Zend_Json::decode($defaults);
        } else {
            $defaults = array();
        }

        $defaults['module'] = $this->getModule();
        $defaults['controller'] = $this->getController();
        $defaults['action'] = $this->getAction();

        return $defaults;
    }

    public function getReqs() {
        $reqs = $this->{Routes::$reqsColumnn};
        if($reqs) {
            $reqs = Zend_Json::decode($reqs);
        } else {
            $reqs = array();
        }
        return $reqs;
    }

    public function getModule() {
        if(empty($this->{Routes::$moduleColumn})) {
            return "default";
        } else {
            return $this->{Routes::$moduleColumn};
        }
    }
    public function getController() {
        if(empty($this->{Routes::$controllerColumnn})) {
            return "default";
        } else {
            return $this->{Routes::$controllerColumnn};
        }
    }
    public function getAction() {
        if(empty($this->{Routes::$actionColumnn})) {
            return "default";
        } else {
            return $this->{Routes::$actionColumnn};
        }
    }
    public function getRouteObject() {
        $class = $this->getType();
        $defaults = $this->getDefaults();
        $reqs = $this->getReqs();
        $route = new $class($this->getUrl(), $defaults, $reqs);
        return $route;
    }
}

SQL schema for routes table

CREATE TABLE IF NOT EXISTS `routes` (
  `route_id` smallint(1) unsigned NOT NULL AUTO_INCREMENT,
  `route_status` tinyint(1) unsigned NOT NULL,
  `route_name` varchar(16) NOT NULL,
  `route_type` varchar(255) NOT NULL,
  `route_url` varchar(255) NOT NULL,
  `route_module` varchar(32) NOT NULL,
  `route_controller` varchar(32) NOT NULL,
  `route_action` varchar(32) NOT NULL,
  `route_defaults` varchar(255) NOT NULL,
  `route_reqs` varchar(255) NOT NULL,
  `route_created` datetime NOT NULL,
  PRIMARY KEY (`route_id`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 ;
  • 写回答

1条回答 默认 最新

  • dtcu5885 2014-02-17 14:30
    关注

    There are three approaches that I can think of.

    First is what I've successfully used in ZF1. Here's the code for the routing itself. The idea is simple: set an "alias" routing (which, in my case, simply used the ".html" suffix to differentiate it from other URLs). If the routing is found, you can get the alias from the DB and then forward the request from the target controller+action to what's defined in the DB (like here). My code isn't pretty, but it works.

    Second: write your own router. You can extend the router class and simply add yout own route resolving rules there: get data from the DB, return true (and set params) if the alias is in the database.

    Third: scrape the aliases table and store everything in an .ini file (or whatever cache you might be using). This is not much different from what you've implemented already and all you'd need to do would be to automate the alias scraping.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 关于#windows#的问题:怎么用WIN 11系统的电脑 克隆WIN NT3.51-4.0系统的硬盘
  • ¥15 matlab有关常微分方程的问题求解决
  • ¥15 perl MISA分析p3_in脚本出错
  • ¥15 k8s部署jupyterlab,jupyterlab保存不了文件
  • ¥15 ubuntu虚拟机打包apk错误
  • ¥199 rust编程架构设计的方案 有偿
  • ¥15 回答4f系统的像差计算
  • ¥15 java如何提取出pdf里的文字?
  • ¥100 求三轴之间相互配合画圆以及直线的算法
  • ¥100 c语言,请帮蒟蒻写一个题的范例作参考