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 求给定范围的全体素数p的(p-2)的连乘积
  • ¥15 VFP如何使用阿里TTS实现文字转语音?
  • ¥100 需要跳转番茄畅听app的adb命令
  • ¥50 寻找一位有逆向游戏盾sdk 应用程序经验的技术
  • ¥15 请问有用MZmine处理 “Waters SYNAPT G2-Si QTOF质谱仪在MSE模式下采集的非靶向数据” 的分析教程吗
  • ¥50 opencv4nodejs 如何安装
  • ¥15 adb push异常 adb: error: 1409-byte write failed: Invalid argument
  • ¥15 nginx反向代理获取ip,java获取真实ip
  • ¥15 eda:门禁系统设计
  • ¥50 如何使用js去调用vscode-js-debugger的方法去调试网页