1

我正在爲我的ZendFramework應用程序構建一個簡單的CMS模塊。ZF1:數據庫中的路由

目前我的所有路線都放在.ini文件中,是否可以使其成爲數據庫驅動。或者,如果可以爲DB創建回退方法,請檢查.ini文件中是否存在路由。

更新 - 解

希望這會幫助別人 - 請注意,我有自定義My_Db_table和My_Db_Row,我還沒有張貼在這裏。所以 - > fetchAllActive()可能需要更改爲 - > fetchAll();並且行對象上的getters可能/可能不工作,不記得它們是否是自定義的 - 你會發現它;-)

但是,如果沒有其他路由適用,路由器基本上會檢查數據庫,即從.ini文件。我沒有檢查過它是否適用於所有的路由類型,但是它與默認的路由類型一起工作。我使用數據庫路由將url指向一個pageControl的pageControl控件,其它參數如pageId作爲JSON字符串存儲在route_defaults單元格中。但你基本上可以用它來處理所有類型的路線。

在自舉

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   
} 

我/控制器/路由器/ 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; 

    } 

} 

路線Db_Table模型

<?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(); 
     } 
    } 
} 

路線 - 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模式

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 ; 
+0

也許這篇文章可以幫助你:http://richard.parnaby-king.co.uk/2013/04/zend-framework-routing-solutions/ – Flixer

回答

0

有,我能想到的三種方法。

首先是我在ZF1中成功使用的。 Here's the code爲路由本身。這個想法很簡單:設置一個「別名」路由(在我的情況下,簡單地使用「.html」後綴來區分它與其他URL)。如果找到了路由,則可以從DB獲取別名,然後將目標控制器+操作的請求轉發到DB中定義的內容(like here)。我的代碼不漂亮,但它的工作原理。

第二:寫你自己的路由器。您可以擴展路由器類,並簡單地在其中添加自己的路由解析規則:從數據庫中獲取數據,如果別名在數據庫中,則返回true(並設置參數)。

第三:刪除別名表並將所有內容存儲在.ini文件(或者您可能使用的任何緩存)中。這與你已經實現的沒有什麼不同,你需要做的就是自動化別名刮取。

+0

我最終擴展了Zend_Controler_Router_Rewrite - 並且在route()函數中如果請求在加載的routes.ini的可調度路由中不匹配,則對數據庫執行檢查。只需要進行其他更改就可以在引導程序中告訴應用程序,使用我的自定義My_Controller_Router_Rewrite類:-) – Phliplip

+0

我相信這是「正確」的方式:) – mingos

+0

我在OP中添加了我的解決方案 – Phliplip