Magento - Rewrite機制一窺

看一個url例子 
http://localhost/magento/index.php/customer/account/login 
這裏假定http://localhost/magento/ 是magento安裝目錄。那麼Magento將自動轉而執行customer模塊下名字AccountController的loginAction方法。這個是ZendFramework的默認重寫規則。 

另一個產品詳細頁的例子 
http://localhost/magento/index.php/catalog/product/view/id/1/category/3 

Magento將尋址catalog模塊的ProductController的viewAction方法,傳入參數id和category. 

爲了搜索引擎更加友好化,咱們可能但願用用下面的url一樣訪問到該產品 
http://localhost/magento/index.php/basketball/tayshaun-prince-signed-auto-baketball-with-coa-gold.html 

Magento重寫了ZendFramework的機制完成這個功能,它的實現思路是:當發送請求的時候,Magento首先判斷 basketball/tayshaun-prince-signed-auto-baketball-with-coa-gold.html是否在數據庫core_url_rewrite表中是否有該route path和實際target path映射記錄,沒有的話,就使用Zend Framework的重寫規則尋址相應的php執行代碼。 


爲了窺視它的Rewrite機制, 還着實費了很多力氣,可是也只是懂些皮毛。下面說說我分析這個機制的過程: 

仍然以訪問 php

Html代碼   收藏代碼
  1. http://localhost/magento/index.php/basketball/tayshaun-prince-signed-auto-baketball-with-coa-gold.html  


爲例 

1. 從magento安裝目錄下的index.php開始,末尾的Mage::run();很顯然是程序的入口。 
2. 打開app/Magento.php查看run()函數嘗試在不一樣的位置輸出self::_$app屬性(是一個類),看看有沒有url關鍵字basketball,結果發現多處子對象有字符串屬性包含它: 


html

Java代碼   收藏代碼
  1. Mage_Core_Controller_Request_Http  
  2.  ->_originalPathInfo = "/basketball/tayshaun-prince-signed-auto-baketball-with-coa-gold.html"  
  3.  ->_requestString = "/basketball/tayshaun-prince-signed-auto-baketball-with-coa-gold.html"  
  4.  ->_requestUri = "/magento/index.php/basketball/tayshaun-prince-signed-auto-baketball-with-coa-gold.html"  
  5.  ->_pathInfo = "catalog/product/view/id/1/category/3"  



那麼爲了完成映射,程序必須有一處讀取其中一個屬性(原始url串),而後進行解析和轉換。這是着實有點迷惑了,四個屬性,到底哪個纔是關鍵的呢? 

3.打開Mage_Core_Controller_Request_Http類文件,先從_originalPathInfo入手(由於名字帶了一個original),找到getOriginalPathInfo(), 該方法調用了setPathInfo(), 這麼說這個方法應該是設置_pathInfo的函數了,結果這個發現該方法先調用getRequestUrl方法初始化屬性 
_requestUri,這個是url源頭,而後運算出以下屬性: 
_originalPathInfo 
_requestString 
_pathInfo 

4. 接着全目錄搜索調用getOriginalPathInfo的類方法,找到類Mage_Core_Controller_Varien_Router_Standard。打開調用方法爲match,瀏覽了下整個函數內容,發現了以下代碼 程序員

Java代碼   收藏代碼
  1.    
  2. $request->setModuleName($module);  
  3.  $request->setControllerName($controller);  
  4.  $request->setActionName($action);  



由此能夠猜想出,對於該例子,這裏應該有以下的映射: 數據庫

Java代碼   收藏代碼
  1. $module = 'catalog';  
  2. $controller = 'ProductController';  
  3. $action = 'viewAction';  



因此下面的就是要找出$moudle變量是如何計算出來的 

5. 找到上面初始化$module的位置 
  $module = $request->getModuleName(); 
必定是$request的屬性被某處初始化,才使得 $request->getModuleName()返回module名字。 
因而代碼定位到前面的 
  $p = explode('/', trim($request->getPathInfo(), '/')); 

6. $request是Mage_Core_Controller_Request_Http類的實例,打開它的getPathInfo方法。 
......哈哈 

線索中斷,其實這種分析方法是不推薦的,徹底沒有程序員邏輯:) 

線索II. 
1. 從Mage::run()方法開始,程序員能夠敏感地意識到下面代碼的關鍵性 app

Java代碼   收藏代碼
  1. Mage::run() {  
  2.   ...  
  3.   self::app()->getFrontController()->dispatch();  
  4.   ...  
  5. }  



2.打開Mage_Core_Controller_Varien_Front的 dispatch方法 函數

Java代碼   收藏代碼
  1. class Mage_Core_Controller_Varien_Front{  
  2.  function dispatch() {  
  3.    ....  
  4.    Mage::getModel('core/url_rewrite')->rewrite();  
  5.    ....  
  6.    while (!$request->isDispatched() && $i++<100) {  
  7.      foreach ($this->_routers as $router) {  
  8.         if ($router->match($this->getRequest())) {  
  9.           break;  
  10.         }  
  11.       }  
  12.    }  
  13.   
  14. }  



3. Mage::getModel('core/url_rewrite')能夠定位到Mage_Core_Model_Url_Rewrite類文件 工具

Java代碼   收藏代碼
  1. class Mage_Core_Model_Url_Rewrite {  
  2.  public function rewrite() {  
  3.         $this->loadByRequestPath($requestCases);     
  4.         ......  
  5.         if (!$this->getId()) {  
  6.             // debug code  
  7.             var_dump($requestCases);  
  8.             exit();  
  9.   
  10.             return false;  
  11.         }  
  12.         ....  
  13.         $request->setPathInfo($this->getTargetPath());  
  14.         return true;  
  15.  }  
  16. }  



若是 $this->loadByRequestPath($requestCases);從數據庫中core_url_rewrite表查找是否有對應的target_path,若是找不到return false(用默認的rewrite機制),這裏應該是能夠找到targe path的,即 
catalog/product/view/id/1/category/3 

4. 繼續回到dispatch()方法,代碼 if ($router->match($this->getRequest()))中 
$router 是Mage_Core_Controller_Varien_Router_Standard的實例,方法match以下: this

Java代碼   收藏代碼
  1. public function match(Zend_Controller_Request_Http $request) {  
  2.    ....  
  3.     // set values only after all the checks are done  
  4.    $request->setModuleName($module);  
  5.   
  6.    $request->setControllerName($controller);  
  7.    $request->setActionName($action);  
  8. }  


上面代碼顯而易見,到此代碼分析結束。 

結論:這次分析是推論+推測(瞎蒙,瞎蒙就是全文搜索匹配字符串肯定調用和被調用關係),沒有使用任何單步調式工具。 

那麼分析Rewrite機制對於擴展Magento的意義何在呢? 好比,若是你想爲產品增長品牌分類,那麼你可能須要定義以下的符合SEO的URL 
http://localhost/magento/index.php/ibm/ 
使之映射到 
http://localhost/magento/index.php/catalog/brand/id/2 

此時,你就要定義重寫機制使兩個URL的映射關係保存到數據庫表中。 搜索引擎

相關文章
相關標籤/搜索