magento開發 -- 深入理解Magento第二章
第二章 - Magento請求分發與控製器
Model-View-Controller (MVC) ,模型-視圖-控製器,源於Smalltalk編程語言和Xerox Parc。現在有很多係統是基於MVC架構的,不同的係統MVC的實現也略有不同,但都體現了MVC的精髓,分離數據,業務邏輯和顯示邏輯。最常見的PHP MVC框架是這樣的

- URL請求被一個PHP文件攔截,通常稱為前端控製器(Front Controller)
- 這個PHP文件分析這個URL,獲得一個執行控製器(Action Controller)的名字和一個執行方法(Action Method)的名字,這個過程通常稱為路由(Routing)
- 實例化#2獲得的執行控製器
- 調用執行控製器的執行方法
- 執行方法中處理業務邏輯,比如獲取數據
- 執行控製器負責把數據傳遞給顯示邏輯
- 顯示邏輯生成HTML
這個架構相對於傳統的“每個php都是一個頁麵”來講已經是一個巨大的飛躍,但還是有人抱怨【譯者注: CodeIgniter就是這樣一個MVC框架】
- 前端控製器仍然以全局的方式運行
- 基於配置的慣例導致了係統不夠模塊化
- URL Routing不夠靈活
- 控製器往往和視圖綁定
- 更改默認設置往往導致大量的重構
Magento創造了一個更抽象的MVC來解決上述問題。

- URL請求被一個PHP攔截
- 這個PHP文件實例化一個Magento對象
- Magento對象實例化前端控製器
- 前端控製器實例化全局配置中指定的路由對象,可以是多個
- 路由對象會逐個與請求URL匹配
- 如果發現匹配,那麼可以獲得一個執行控製器和一個執行方法的名字
- 實例化#6獲得的執行控製器,並調用相應的執行方法
- 執行方法中處理業務邏輯,模型數據
- 控製器實例化布局對象(Layout)
- 布局對象根據請求的參數,係統配置創建一個塊對象(Block)列表,並實例化
- 布局對象會調用塊對象的output方法生成HTML。這是一個遞歸的過程,因為塊對象可以嵌套塊對象
- 每一個塊對象都和一個模板文件(Template File)對應。塊對象包含了顯示邏輯,模板文件包含了HTML和PHP輸出代碼
- 塊對象直接從模型那裏獲得數據,換句話說,在Magento的MVC架構中,控製器並不直接把數據傳給視圖
這裏很複雜,我們以後會詳細解釋每一個部分。我們先關注“前端控製器->路由對象->執行控製器”部分。
Hello World示例
我們講了太多理論,現在讓我們來實踐一下,通過實踐來加深理解。下麵是我們將要做的事情
- 創建一個Hello World模塊
- 為這個模塊配置路由
- 為這個模塊創建執行控製器
創建Hello World模塊
首先,我們要創建一個模塊的目錄結構,這個我們以前已經做過了,就不再熬述
app/code/local/Alanstormdotcom/Helloworld/Block
下麵是config.xml的內容
- 清空Magento緩存
- 在管理後台,進入 System->Configuration->Advanced
- 展開“Disable Modules Output”
- 確認Alanstormdotcom_Helloworld顯示出來了
配置路由
下麵,我們要配置一個路由。路由是用來把一個URL請求轉換成一個執行控製器和方法。和傳統的PHP MVC不同的是,你需要在Magento的全局配置中顯式的定義你的路由。我們繼續上麵的例子,在config.xml中,添加如下代碼
<config> ... <frontend> <routers> <helloworld> <use>standard</use> <args> <module>Alanstormdotcom_Helloworld</module> <frontName>helloworld</frontName> </args> </helloworld> </routers> </frontend> ... </config>
在這裏,我們有很多新名詞要解釋。
什麼是<frontend />?
<frontend />標簽指向一個Magento區(Area),比如“frontend”就是指網站的前台,“admin”是指網站的後台,“install”是指Magento的安裝程序。【譯者注:這個有點像磁盤分區,區和區之間是相互獨立的,但是都歸操作係統能夠管理,在這裏歸Magento管理。默認的Magento安裝沒有“install”這個區,frontend區接管了,全局配置中的以下代碼可以解釋這一點
<frontend> ... <install> <use>standard</use> <args> <module>Mage_Install</module> <frontName>install</frontName> </args> </install> ... </frontend>
什麼是<routers />?
Phil Karlton有一句很著名的話“在計算機領域隻有兩件事是困難的:緩存和命名”。Magento引入了很多新概念,無疑存在很多命名問題,這裏就是一個例子。<routers>標簽有時候包含的是路由對象的定義,有時候包含的是路徑的定義。路由對象是進行路由操作的實體,而路徑僅僅是路由對象的一個參數。【譯者注: 如果你仔細看過那個全局配置xml的話,你會發現有兩處地方出現<routers>,一處是“<web> -> <routers>”,另外一處是“<frontend> -> <routers>”。你再仔細看看會發現兩處<routers>包含的內容不一樣。第一處包含的是路由對象的定義,第二處包含的是路徑的定義。】
什麼是<module />?
這個標簽的內容應該是一個模塊的全名,Packagename_Modulename,在這裏是“Alanstormdotcom_Helloworld”。Magento用這個名字來定位你的模塊文件。什麼是<frontName />?
當一個router解析一個URL的時候,它是按照如下規則進行的https://example.com/frontName/actionControllerName/actionMethod/
所以,當我們在<frontName>標簽裏定義了“helloworld”以後,Magento會把如下的URL請求交給我們的模塊“Alanstormdotcom_Helloworld”來處理
https://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會在這個目錄尋找模塊的控製器文件。我們的第一個控製器包含以下內容
class Alanstormdotcom_Helloworld_IndexController extends Mage_Core_Controller_Front_Action { public function indexAction() { echo 'Hello World!'; } }
清空Magento緩存,請求如下URL
https://exmaple.com/helloworld/index/index
如果你看到一個空白頁麵上麵寫著“Hello World”,那麼恭喜你,你已經成功創建了你的第一個Magento控製器!
如何命名執行控製器?
還記得config.xml的<module>標簽嗎?<module>Alanstormdotcom_Helloworld</module>
執行控製的名字的構成如下
- 以<moudule>標簽的內容開始 (Alanstormdotcom_Helloworld)
- 緊接一個下劃線 (Alanstormdotcom_Helloworld_)
- 加上我們給控製器取的名字“Index”(Alanstormdotcom_Helloworld_Index)
- 最後加上關鍵詞“Controller” (Alanstormdotcom_Helloworld_IndexController)
URL裏麵的index/index是什麼意思?
正如前文所述,Magento默認的路由的規則如下https://example.com/frontName/actionControllerName/actionMethod/
所以在我們請求的URL
https://exmaple.com/helloworld/index/index
其中“helloworld”是“frontName”,第一個“index”是執行控製器(Action Controller)的名字,第二個“index”是執行方法的名字。對比我們寫的執行控製器代碼,我們不難發現執行方法的定義是執行方法名字加上“Action”關鍵字
public function indexAction(){...}
Magento根據命名規則找到執行控製器文件並實例化,然後再根據命名規則調用指定的執行方法。如果URL沒有給出執行控製器名字或者執行方法,Magento會用默認的“index”來替代,所以下麵三個URL是等價的
https://exmaple.com/helloworld/index/index
https://exmaple.com/helloworld/index/
https://exmaple.com/helloworld/
我們再來看一個例子。如果URL如下
https://exmaple.com/checkout/cart/add
Magento的執行步驟如下
- 查詢全局配置,找到frontName “checkout”對應的模塊,Mage_Checkout
- 找到執行控製器 “Mage_Checkout_CartController”
- 調用執行控製器的“addAction”方法
進一步理解執行控製器
下麵我們來為我們的執行控製器添加一個執行方法。添加如下代碼到IndexController.php
public function goodbyeAction() { echo 'Goodbye World!'; }
請求URL
https://example.com/helloworld/index/goodbye
這次你應該看到“Goodbye World!”。因為我們繼承了“Mage_Core_Controller_Front_Action”,我們可以使用一些父類已經定義好的方法和變量。比如父類會把URL後麵跟的參數轉換成key/value的數組。添加如下代碼到我們的執行控製器
public function paramsAction() { echo '<dl>'; foreach($this->getRequest()->getParams() as $key=>$value) { echo '<dt><strong>Param: </strong>'.$key.'</dt>'; echo '<dl><strong>Value: </strong>'.$value.'</dl>'; } echo '</dl>'; }
https://example.com/helloworld/index/params?foo=bar&baz=eof
你應該看到如下輸出
https://example.com/helloworld/messages/goodbye
這裏的執行控製器名字是“messages”,所以我們要創建如下文件
app/code/local/Alanstormdotcom/Helloworld/controllers/MessagesController.php
執行控製器的類名應該是
Alanstormdotcom_Helloworld_MessagesController
最後更新:2017-04-02 05:21:04
上一篇:
如果做好需求調研工作
下一篇:
wince C#調試出現:0x80070070: 磁盤空間不足
智能手機病毒解析
Struts2中的ActionContext.getContext().getParameters()
Tomcat啟動報錯:java.lang.IllegalArgumentException: Can't convert argument:null
飛天技術匯 - 阿裏雲技術大牛為您揭秘雙11幕後的技術保障
室內設計響應式網站模板下載建站
iOS開發那些事-響應內存警告
開發手機直播App:如何在真旺雲配置七牛直播計費【上篇】
web profiler 環境搭建
Java NIO係列教程(五) 通道之間的數據傳輸
【信息圖表】從擁抱到開源,阿裏開源貢獻一覽