第二章 – Magento請求分發與控制器

深入理解Magento

作者:Alan Storm 
翻譯:Hailong Zhang


第二章 – Magento請求分發與控制器

Model-View-Controller (MVC) ,模型-視圖-控制器,源於Smalltalk編程語言和Xerox Parc。現在有很多系統是基於MVC架構的,不同的系統MVC的實現也略有不同,但都體現了MVC的精髓,分離數據,業務邏輯和顯示邏輯。最常見的 PHP MVC框架是這樣的


  1. URL請求被一個PHP文件攔截,通常稱爲前端控制器(Front Controller)
  2. 這個PHP文件分析這個URL,獲得一個執行控制器(Action Controller)的名字和一個執行方法(Action Method)的名字,這個過程通常稱爲路由(Routing)
  3. 實例化#2獲得的執行控制器
  4. 調用執行控制器的執行方法
  5. 執行方法中處理業務邏輯,比如獲取數據
  6. 執行控制器負責把數據傳遞給顯示邏輯
  7. 顯示邏輯生成HTML

 

這個架構相對於傳統的“每個php都是一個頁面”來講已經是一個巨大的飛躍,但還是有人抱怨【譯者注:CodeIgniter 就是這樣一個MVC框架】

  • 前端控制器仍然以全局的方式運行
  • 基於配置的慣例導致了系統不夠模塊化
    • URL Routing不夠靈活
    • 控制器往往和視圖綁定
    • 更改默認設置往往導致大量的重構

 

Magento創造了一個更抽象的MVC來解決上述問題。


  1. URL請求被一個PHP攔截
  2. 這個PHP文件實例化一個Magento對象
  3. Magento對象實例化前端控制器
  4. 前端控制器實例化全局配置中指定的路由對象,可以是多個
  5. 路由對象會逐個與請求URL匹配
  6. 如果發現匹配,那麼可以獲得一個執行控制器和一個執行方法的名字
  7. 實例化#6獲得的執行控制器,並調用相應的執行方法
  8. 執行方法中處理業務邏輯,模型數據
  9. 控制器實例化佈局對象(Layout)
  10. 佈局對象根據請求的參數,系統配置創建一個塊對象(Block)列表,並實例化
  11. 佈局對象會調用塊對象的output方法生成HTML。這是一個遞歸的過程,因爲塊對象可以嵌套塊對象
  12. 每一個塊對象都和一個模板文件(Template File)對應。塊對象包含了顯示邏輯,模板文件包含了HTML和PHP輸出代碼
  13. 塊對象直接從模型那裏獲得數據,換句話說,在Magento的MVC架構中,控制器並不直接把數據傳給視圖

 

這裏很複雜,我們以後會詳細解釋每一個部分。我們先關注“前端控制器->路由對象->執行控制器”部分。

 

Hello World示例

我們講了太多理論,現在讓我們來實踐一下,通過實踐來加深理解。下面是我們將要做的事情

  1. 創建一個Hello World模塊
  2. 爲這個模塊配置路由
  3. 爲這個模塊創建執行控制器


創建Hello World模塊

首先,我們要創建一個模塊的目錄結構,這個我們以前已經做過了,就不再熬述

app/code/local/Alanstormdotcom/Helloworld/Block

app/code/local/Alanstormdotcom/Helloworld/controllers

app/code/local/Alanstormdotcom/Helloworld/etc

app/code/local/Alanstormdotcom/Helloworld/Helper

app/code/local/Alanstormdotcom/Helloworld/Model

app/code/local/Alanstormdotcom/Helloworld/sql


下面是config.xml的內容 PATH: app/code/local/Alanstormdotcom/Helloworld/etc/config.xml

Xml代碼  收藏代碼
  1. <config>     
  2.     <modules>  
  3.         <Alanstormdotcom_Helloworld>  
  4.             <version>0.1.0</version>  
  5.         </Alanstormdotcom_Helloworld>  
  6.     </modules>  
  7. </config>  
 

然後我們要創建一個系統配置文件來激活這個模塊PATH: app/etc/modules/Alanstormdotcom_Helloworld.xml

Xml代碼  收藏代碼
  1. <config>  
  2.     <modules>  
  3.         <Alanstormdotcom_Helloworld>  
  4.             <active>true</active>  
  5.             <codePool>local</codePool>  
  6.         </Alanstormdotcom_Helloworld>  
  7.     </modules>  
  8. </config>  
 

最後,讓我們檢查一下模塊是不是已經被激活

  1. 清空Magento緩存
  2. 在管理後臺,進入 System->Configuration->Advanced
  3. 展開“Disable Modules Output”
  4. 確認Alanstormdotcom_Helloworld顯示出來了


配置路由

下面,我們要配置一個路由。路由是用來把一個URL請求轉換成一個執行控制器和方法。和傳統的PHP MVC不同的是,你需要在Magento的全局配置中顯式的定義你的路由。我們繼續上面的例子,在config.xml中,添加如下代碼

Xml代碼  收藏代碼
  1. <config>     
  2.     ...  
  3.     <frontend>  
  4.         <routers>  
  5.             <helloworld>  
  6.                 <use>standard</use>  
  7.                 <args>  
  8.                     <module>Alanstormdotcom_Helloworld</module>  
  9.                     <frontName>helloworld</frontName>  
  10.                 </args>  
  11.             </helloworld>  
  12.         </routers>   
  13.     </frontend>  
  14.     ...  
  15. </config>  
 

在這裏,我們有很多新名詞要解釋。


什麼是<frontend />?

<frontend />標籤指向一個Magento區(Area),比如“frontend”就是指網站的前臺,“admin”是指網站的後臺,“install”是 指Magento的安裝程序。【譯者注:這個有點像磁盤分區,區和區之間是相互獨立的,但是都歸操作系統能夠管理,在這裏歸Magento管理。默認的 Magento安裝沒有“install”這個區,frontend區接管了,全局配置中的以下代碼可以解釋這一點

Xml代碼  收藏代碼
  1. <frontend>  
  2. ...  
  3.   <install>  
  4.     <use>standard</use>  
  5.     <args>  
  6.       <module>Mage_Install</module>  
  7.       <frontName>install</frontName>  
  8.     </args>  
  9.   </install>  
  10. ...  
  11. </frontend>  
 

什麼是<routers />?

Phil Karlton有一句很著名的話“在計算機領域只有兩件事是困難的:緩存和命名”。Magento引入了很多新概念,無疑存在很多命名問題,這裏就是一個 例子。<routers>標籤有時候包含的是路由對象的定義,有時候包含的是路徑的定義。路由對象是進行路由操作的實體,而路徑僅僅是路由對 象的一個參數。【譯者注: 如果你仔細看過那個全局配置xml的話,你會發現有兩處地方出現<routers>,一處是“<web> -> <routers>”,另外一處是“<frontend> -> <routers>”。你再仔細看看會發現兩處<routers>包含的內容不一樣。第一處包含的是路由對象的定義,第二處包含 的是路徑的定義。】


什麼是<module />?

這個標籤的內容應該是一個模塊的全名,Packagename_Modulename,在這裏是“Alanstormdotcom_Helloworld”。Magento用這個名字來定位你的模塊文件。


什麼是<frontName />?

當一個router解析一個URL的時候,它是按照如下規則進行的
http://example.com/frontName/actionControllerName/actionMethod/


所以,當我們在<frontName>標籤裏定義了“helloworld”以後,Magento會把如下的URL請求交給我們的模塊“Alanstormdotcom_Helloworld”來處理
http://example.com/helloworld/*


有些人容易把<frontName>和前端控制器(Front Controller)混淆起來。它們是兩個不同的概念,<frontName>只跟路由相關。【譯者注: 根據我們前面講過的Magento的MVC流程,前端控制器是用來實例化所有路由的,而這裏的“frontName”只是路由過程中的一個參數】


什麼是 <helloworld />?

這個標籤的名字應該是模塊名字的小寫版本。我們的模塊名字是“Helloworld”,所以這裏我們用“helloworld”。你應該也已經注意 到我們定義的“frontName”也是和我們的模塊相匹配的。這是一個不成文的規定,但不是強制要求。事實上,一個模塊可以定義多 個<routers>,也就是可以有多個“frontName”。


爲路由創建執行控制器

還記得Magento的MVC流程嗎?路由會把控制權交給執行控制器。上面我們定義了路由,現在我們來定義我們的執行控制器。首先創建文件
app/code/local/Alanstormdotcom/Helloworld/controllers/IndexController.php


模塊的控制器應該放在模塊的子目錄“controllers”(小寫c)裏面。這是規定,Magento會在這個目錄尋找模塊的控制器文件。我們的第一個控制器包含以下內容

Php代碼  收藏代碼
  1. class Alanstormdotcom_Helloworld_IndexController extends Mage_Core_Controller_Front_Action {         
  2.     public function indexAction() {  
  3.         echo 'Hello World!';  
  4.     }  
  5. }  
 

清空Magento緩存,請求如下URL
http://exmaple.com/helloworld/index/index


如果你看到一個空白頁面上面寫着“Hello World”,那麼恭喜你,你已經成功創建了你的第一個Magento控制器!


如何命名執行控制器?

還記得config.xml的<module>標籤嗎?

Xml代碼  收藏代碼
  1. <module>Alanstormdotcom_Helloworld</module>  
 

執行控制的名字的構成如下

  1. 以<moudule>標籤的內容開始 (Alanstormdotcom_Helloworld)
  2. 緊接一個下劃線 (Alanstormdotcom_Helloworld_)
  3. 加上我們給控制器取的名字“Index”(Alanstormdotcom_Helloworld_Index)
  4. 最後加上關鍵詞“Controller” (Alanstormdotcom_Helloworld_IndexController)

我們自己定義的屬於frontend區的執行控制器都應該繼承Mage_Core_Controller_Front_Action。


URL裏面的index/index是什麼意思?

正如前文所述,Magento默認的路由的規則如下
http://example.com/frontName/actionControllerName/actionMethod/


所以在我們請求的URL
http://exmaple.com/helloworld/index/index


其中“helloworld”是“frontName”,第一個“index”是執行控制器(Action Controller)的名字,第二個“index”是執行方法的名字。對比我們寫的執行控制器代碼,我們不難發現執行方法的定義是執行方法名字加上 “Action”關鍵字

Php代碼  收藏代碼
  1. public function indexAction(){...}  
 

Magento根據命名規則找到執行控制器文件並實例化,然後再根據命名規則調用指定的執行方法。如果URL沒有給出執行控制器名字或者執行方法,Magento會用默認的“index”來替代,所以下面三個URL是等價的

http://exmaple.com/helloworld/index/index

http://exmaple.com/helloworld/index/

http://exmaple.com/helloworld/


我們再來看一個例子。如果URL如下
http://exmaple.com/checkout/cart/add


Magento的執行步驟如下

  1. 查詢全局配置,找到frontName “checkout”對應的模塊,Mage_Checkout
  2. 找到執行控制器 “Mage_Checkout_CartController”
  3. 調用執行控制器的“addAction”方法


進一步理解執行控制器

下面我們來爲我們的執行控制器添加一個執行方法。添加如下代碼到IndexController.php

Php代碼  收藏代碼
  1. public function goodbyeAction() {  
  2.     echo 'Goodbye World!';  
  3. }   
 

請求URL
http://example.com/helloworld/index/goodbye


這次你應該看到“Goodbye World!”。因爲我們繼承了“Mage_Core_Controller_Front_Action”,我們可以使用一些父類已經定義好的方法和變 量。比如父類會把URL後面跟的參數轉換成key/value的數組。添加如下代碼到我們的執行控制器

Php代碼  收藏代碼
  1. public function paramsAction() {  
  2.     echo '<dl>';             
  3.     foreach($this->getRequest()->getParams() as $key=>$value) {  
  4.         echo '<dt><strong>Param: </strong>'.$key.'</dt>';  
  5.         echo '<dl><strong>Value: </strong>'.$value.'</dl>';  
  6.     }  
  7.     echo '</dl>';  
  8. }  
 

請求如下URL
http://example.com/helloworld/index/params?foo=bar&baz=eof

或者

http://example.com/helloworld/index/params /foo/bar/baz/eof


你應該看到如下輸出
Param: foo
  Value: bar
Param: baz
  Value: eof


最後,讓我們再寫一個執行控制器,用來處理以下URL
http://example.com/helloworld/messages/goodbye


這裏的執行控制器名字是“messages”,所以我們要創建如下文件
app/code/local/Alanstormdotcom/Helloworld/controllers/MessagesController.php


執行控制器的類名應該是
Alanstormdotcom_Helloworld_MessagesController


添加執行方法

Php代碼  收藏代碼
  1. public function goodbyeAction()          
  2. {  
  3.     echo 'Another Goodbye';  
  4. }  
 

好了,Magento的MVC架構大概就是這樣了。它比傳統的PHP MVC要複雜一點,但是Magento的這個高度靈活的MVC架構能讓你創造出幾乎所有你能想到的URL結構。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章