2013-05-13 44 views
1

我正在使用Zend Framework 1.12.3開發API。我使用Zend_Rest_Route,但我想有層次網址:Zend Rest Route - 如何創建分層的URL?

我正在考慮使用這種方法,因爲我不得不將一些主題分配給某些教授,我相信這個模式能夠很好地解決它。

但是,我很難實現層次結構URL。我已經嘗試過:

  1. Zend_Controller_Router_Route中與鏈,在配置.ini文件,但由於兩個控制器和動作都在訪問http://api.example.com/professors/:professorId/subjects它總是指向同一動作時(指定,即,無論調用方法是什麼 - POST,PUT,GET,DELETE - 它總是指向config .ini文件中指定的動作)。例如,如果我在配置文件中指定了getAction,那麼無論使用什麼方法,使用鏈將始終調用getAction。目前,在進行POST調用時,它實際上會調用postAction()(同樣發生在PUT,GET,DELETE,PATCH,HEAD和OPTIONS)。我的控制器文件看起來像這樣:

    class V1_ProfessorsController extends REST_Controller 
    { 
         public function optionsAction() 
         { 
           // code goes here 
         } 
    
         public function headAction() 
         { 
           // code goes here 
         } 
    
         public function indexAction() 
         { 
           // code goes here - list of resources 
         } 
    
         public function getAction() 
         { 
           // code goes here 
         } 
    
         public function postAction() 
         { 
           // code goes here 
         } 
    
         public function putAction() 
         { 
           // code goes here 
         } 
    
         public function patchAction() 
         { 
           // code goes here 
         } 
    
         public function deleteAction() 
         { 
           // code goes here 
         } 
    
    } 
    
  2. 子類化Zend_Rest_Route並重寫匹配()函數指出here。問題是,雖然這在調用http://api.example.com/professors/:professorId/subjects時起作用,但它仍使用調用http://api.example.com/professors時使用的相同ProfessorsController。我不確定這一點,但我相信最好有自己的控制器(例如ProfessorsSubjectsController)。

另外,我有一個問題。等級路線應該如何工作?對不同的資源/子資源有不同的控制器會更好嗎?例如,有http://api.example.com/professors/:professorId的ProfessorsController和http://api.example.com/professors/:professorId/subjects/:subjectId的ProfessorsSubjectsController?

+2

在尋找答案的任何進展?用相同的問題解決問題。 – Gabriel 2013-06-05 06:20:53

+0

@Gabriel不幸的是,還沒有。我正在開發API的其他部分,並且我認爲我會最後離開分層URL。 如果我找到解決方案,我會在這裏發佈。如果你這樣做,我會很感激。 – Daniel 2013-06-05 09:39:23

+0

會做。我檢查是否有可能有解決方案使用鏈接路線。 – Gabriel 2013-06-05 12:05:58

回答

3

我找到了一個解決方案,稍微修改了一下。這是一個自定義的路線類,它可以做我認爲我們都希望它做的事。

<?php 

require_once "modules.inc"; 

class Rest_Controller_Route extends Zend_Controller_Router_Route 
{ 

/** 
* @var Zend_Controller_Front 
*/ 
protected $_front; 

protected $_actionKey  = 'action'; 

/** 
* Prepares the route for mapping by splitting (exploding) it 
* to a corresponding atomic parts. These parts are assigned 
* a position which is later used for matching and preparing values. 
* 
* @param Zend_Controller_Front $front Front Controller object 
* @param string $route Map used to match with later submitted URL path 
* @param array $defaults Defaults for map variables with keys as variable names 
* @param array $reqs Regular expression requirements for variables (keys as variable names) 
* @param Zend_Translate $translator Translator to use for this instance 
*/ 
public function __construct(Zend_Controller_Front $front, $route, $defaults = array(), $reqs = array(), Zend_Translate $translator = null, $locale = null) 
{ 
    $this->_front  = $front; 
    $this->_dispatcher = $front->getDispatcher(); 

    parent::__construct($route, $defaults, $reqs, $translator, $locale); 
} 



/** 
* Matches a user submitted path with parts defined by a map. Assigns and 
* returns an array of variables on a successful match. 
* 
* @param string $path Path used to match against this routing map 
* @return array|false An array of assigned values or a false on a mismatch 
*/ 
public function match($path, $partial = false) 
{ 

    $return = parent::match($path, $partial); 

    // add the RESTful action mapping 
    if ($return) { 
     $request = $this->_front->getRequest(); 
     $path = $request->getPathInfo(); 
     $params = $request->getParams(); 

     $path = trim($path, '/'); 

     if ($path != '') { 
      $path = explode('/', $path); 
     } 

     $lastParam = array_pop($path); 

     // Determine Action 
     $requestMethod = strtolower($request->getMethod()); 
     if ($requestMethod == 'head') { 
      if (is_numeric($lastParam)) { 
       $return[$this->_actionKey] = 'head'; 
       $return["id"] = $lastParam; 
      } 
     } else if ($requestMethod != 'get') { 
      if ($request->getParam('_method')) { 
       $return[$this->_actionKey] = strtolower($request->getParam('_method')); 
      } elseif ($request->getHeader('X-HTTP-Method-Override')) { 
       $return[$this->_actionKey] = strtolower($request->getHeader('X-HTTP-Method-Override')); 
      } else { 
       $return[$this->_actionKey] = $requestMethod; 
      } 

      // Map PUT, DELETE and POST to actual create/update/delete actions 
      // based on parameter count (posting to resource or collection) 
      switch($return[$this->_actionKey]){ 
       case 'post': 
        $return[$this->_actionKey] = 'post'; 
        break; 
       case 'put': 
        $return[$this->_actionKey] = 'put'; 
        $return["id"] = $lastParam; 
        break; 
       case 'delete': 
        $return[$this->_actionKey] = 'delete'; 
        $return["id"] = $lastParam; 
        break; 
      } 
     } else { 
      // if the last argument in the path is a numeric value, consider this request a GET of an item 
      if (is_numeric($lastParam)) { 
       $return[$this->_actionKey] = 'get'; 
       $return["id"] = $lastParam; 
      } else { 
       if (isset($data[0]) && is_numeric($data[0])) { 
        $return[$this->_actionKey] = 'get'; 
        $return["id"] = $lastParam; 
       } else { 
        $return[$this->_actionKey] = 'index'; 
       } 
      } 
     } 
    } 

    return $return; 

} 

} 

要使用此,建立在你的引導或index.php文件,兩個例子,所有的路線是這樣的:

$route = new Rest_Controller_Route($front, 'customers/*', array('controller' => 'customers')); 
$router->addRoute('customers', $route); 

$route = new Rest_Controller_Route($front, 'customers/:customer_id/documents/*', array('controller' => 'customers-documents')); 
$router->addRoute('customersdocuments', $route); 

這可以作爲一個魅力對我來說。你認爲這不是我的最終解決方案,所以可能有我沒有發現的龍所以要注意。 :)

+0

非常感謝您的解決方案。它似乎在工作,但我認爲我需要在我的Zend環境中更改一些設置。我一直在使用Zend_Rest_Route application.ini 但爲了您的解決方案的工作,我需要停止使用這個Zend_Rest_Route,因此它試圖找到索引/ get/put/post/patch/delete .phtml視圖文件夾中的文件。 – Daniel 2013-07-02 09:09:36

+0

此外,似乎我無法在正文中發送參數(例如curl -v -X http://api.example.com/customers -d foo = bar)。 – Daniel 2013-07-02 09:25:04

+0

這很奇怪,因爲我在做它..我不熟悉捲曲,我使用Firefox插件來做到這一點。這是一個獲得手術,你做什麼或什麼? – Gabriel 2013-07-02 11:54:03