深入理解Magento-第九章-修改、擴展、重寫Magento代碼
作為一個開發者的你,肯定要修改Magento代碼去適應你的業務需求,但是在很多時候我們不希望修改Magento的核心代碼,這裏有很多原因, 例如將來還希望升級Magento、還想使用更多的Magento代碼。如果你正在尋找修改Magento代碼的最佳方式,那麼此篇文章將會是一個不錯的 教程。
適合對象:高級開發者
適合目標:開發者希望自定義修改Magento
當前版本:Magento versions: 1.4.0.1
作者:精東
最後修改時間:2010年5月30日
版本:V 0.3.0
重寫Magento模塊(Module)
第一步,你需要創建屬於你自己代碼的命名空間,例如Wemvc,App等,為了方便與大家分享代碼,我將空間命名為App。
app/ code/ core/ community/ local/ App/
假如你現在打算修改Mage/Catalog/Block/Breadcrumbs.php這個文件,你可以在你的命名空間,App裏添加一個新的模塊 “Catalog”。接下來創建塊(Block)目錄,並複製Breadcrumbs.php到你的新目錄中。這裏還需要你創建一個config.xml 配置文件。
app/ code/ core/ community/ local/ App/ Catalog/ Block/ Breadcrumbs.php etc/ config.xml
修改Breadcrumbs.php的類名為App_Catalog_Block_Breadcrumbs,並繼承原類名Mage_Catalog_Block_Breadcrumbs。
現在,你需要激活你的新模塊,這樣magento才能夠知道你的新模塊。
創建文件app/etc/modules/App_All.xml,添加如下代碼。
< ?xml version="1.0"?> <config> <modules> <App_Catalog> <active>true</active> <codePool>local</codePool> </App_Catalog> </modules> </config>
下麵我們需要一個特殊的標簽來複寫掉Breadcrumbs,下麵我們通過模塊的配置文件來實現。
重寫Magento區塊(Blocks)
編輯文件“app/code/local/App/Catalog/etc/config.xml”
<?xml version="1.0" encoding="UTF-8"?> <config> <modules> <App_Catalog> <version>0.1.0</version> </App_Catalog> </modules> <global> <blocks> <catalog> <rewrite> <breadcrumbs>App_Catalog_Block_Breadcrumbs</breadcrumbs> </rewrite> </catalog> </blocks> </global> </config>
我們需要添加一個“blocks” 標簽,或者在已經存在的“blocks”標簽中添加內容。然後在模塊名後麵添加rewrite標簽,在這個例子中模塊名是“catalog”。然後我們看 “breadcrumbs”標簽,這個標簽幫助magento找到我們我們想修改的塊。在我們的列子中,breadcrumbs是Magento核心代碼 中的類名: app/code/core/Mage/Catalog/Block/Breadcrumbs.php。如果你有更多的目錄層級,可以用下滑線來分隔。例 如:
<blocks> <catalog> <rewrite> <category_view>App_Catalog_Block_Category_View</category_view> </rewrite> </catalog> </blocks>
在這個例子中,我們重寫了app/code/core/Mage/Catalog/Block/Category/View.php。
在breadcrumbs標簽中的值是你的類名,這樣Magento就可以獲取你的類,因為類名與你的目錄名一致。用過zend
framework的人都知道,自動加載auto
loader這個東西,它會跟你類名中的下滑線去你的目錄中需要對應的類文件。記住一點,下滑線代表下一級別的文件夾,如果你的類名與你的文件目錄名不一
致,那麼Magento根本不會理睬你。
舉例來說:
App_Catalog_Block_Breadcrumbs → /app/code/local/App/Catalog/Block/Breadcrumbs.php App_Catalog_Block_Category_View → /app/code/local/App/Catalog/Block/Category/View.php
重寫Magento控製器(Controller)-正則表達式匹配式
重寫Magento控製器我們我們以重寫購物車為例。
1、首先在App下創建新的模塊,依次創建如下文件:
/app/code/local/App/Shopping /app/code/local/App/Shopping/etc /app/code/local/App/Shopping/etc/config.xml /app/code/local/App/Shopping/controllers /app/code/local/App/Shopping/controllers/CartController.php
2、編輯/app/code/local/App/Shopping/etc/config.xml文件,加入如下代碼:
<?xml version="1.0"?> <config> <modules> <App_Shopping> <version>0.1.0</version> </App_Shopping> </modules> <global> <!-- This rewrite rule could be added to the database instead --> <rewrite> <!-- This is an identifier for your rewrite that should be unique --> <!-- THIS IS THE CLASSNAME IN YOUR OWN CONTROLLER --> <App_Shopping_cart> <from><!--[CDATA[#^/checkout/cart/#]]--></from> <!-- - Shopping module matches the router frontname below - checkout_cart matches the path to your controller Considering the router below, "/shopping/cart/" will be "translated" to "/App/Shopping/controllers/CartController.php" (?) --> <to>/shopping/cart/</to> </App_Shopping_cart> </rewrite> </global> <!-- If you want to overload an admin-controller this tag should be <admin> instead, or <adminhtml> if youre overloading such stuff (?) --> <frontend> <routers> <App_Shopping> <!-- should be set to "admin" when overloading admin stuff (?) --> <use>standard</use> <args> <module>App_Shopping</module> <!-- This is used when "catching" the rewrite above --> <frontName>shopping</frontName> </args> </App_Shopping> </routers> </frontend> </config>
3、改寫你自己的控製器
/app/code/local/App/Shopping/controllers/CartController.php
請將下麵的代碼添加到你的控製器中,我們唯一修改的地方是在index動作中添加一個error_log();
< ?php # 控製器不會自動加載,所以我們需要包含文件,這裏與區塊(Block)不一樣 require_once 'Mage/Checkout/controllers/CartController.php'; class App_Shopping_CartController extends Mage_Checkout_CartController { #覆寫indexAction方法 public function indexAction() { # Just to make sure error_log('耶~成功重寫購物車!'); parent::indexAction(); } }
在這段代碼中,首先是類名,跟前麵講到的區塊(Block)一樣,我們自己的類名是App_Shopping_CartController繼承原先Mage_Checkout_CartController.在indexAction中我們記錄了一段信息。
4、修改App_All.xml,激活我們新的Shopping模塊
<?xml version="1.0"?> <config> <modules> <App_Catalog> <active>true</active> <codePool>local</codePool> </App_Catalog> <App_Shopping> <active>true</active> <codePool>local</codePool> </App_Shopping> </modules> </config>
到這裏,清除緩存後,你已經可以看到error_log成功記錄了我們的信息,打開頁麵https://www.wemvc.dev /checkout/cart/,顯示的是購物車頁麵,一切正常,但如果你訪問https://www.wemvc.dev/shopping/cart /,你會發現是首頁。。。。我們期望的購物車視圖還沒有出現,如何解決呢?讓我們接下來往下看。
5、修改視圖文件app/design/frontend/[myinterface]/[mytheme]/layout/checkout.xml
在layout標簽中,添加下麵內容:
<app_shopping_cart_index> <update handle="checkout_cart_index"/> </app_shopping_cart_index>
注意,這裏的大小寫敏感。
到這裏基本大功告成,但是,我建議你學習下正則表達式,因為剛剛的代碼中,有這麼一段:
<from>< ![CDATA[#^/checkout/cart/#]]></from>
這裏是使用正則表達式進行匹配的。
還有一點,經過嚐試,這裏是可以支持同模塊名覆蓋的,例如Magento代碼中商品詳情頁是Mage_Catalog_ProductController::viewAction(),如果我們想重寫這個Controller,我們可以這樣做:
a.簡曆新的目錄/app/code/local/App/Catalog/controllers/ProductController.php
代碼如下:
require_once 'Mage/Catalog/controllers/ProductController.php'; /** * Product controller * * @category Mage * @package Mage_Catalog */ class App_Catalog_ProductController extends Mage_Catalog_ProductController { /** * View product action */ public function viewAction() { echo '覆蓋過的....'; parent::viewAction(); } }
b.編輯/app/code/local/App/Catalog/etc/config.xml,代碼如下:
<?xml version="1.0" encoding="UTF-8"?> <config> <modules> <App_Catalog> <version>0.1.0</version> </App_Catalog> </modules> <global> <!-- This rewrite rule could be added to the database instead --> <rewrite> <!-- This is an identifier for your rewrite that should be unique --> <!-- THIS IS THE CLASSNAME IN YOUR OWN CONTROLLER --> <App_Shopping_cart> <from><!--[CDATA[#^/catalog/product/#]]--></from> <!-- - Shopping module matches the router frontname below - checkout_cart matches the path to your controller Considering the router below, "/shopping/cart/" will be "translated" to "/App/Shopping/controllers/CartController.php" (?) --> <to>/catalog/product/</to> </App_Shopping_cart> </rewrite> <blocks> <catalog> <rewrite> <breadcrumbs>App_Catalog_Block_Breadcrumbs</breadcrumbs> </rewrite> </catalog> </blocks> </global> <frontend> <routers> <catalog> <use>standard</use> <args> <module>App_Catalog</module> <frontName>catalog</frontName> </args> </catalog> </routers> </frontend> </config>
清空緩存,刷新你的商品詳情頁,看是不是變了,嗬嗬。但是這個方法有個弊病,你需要把這個模塊的所有Controller都複寫掉,不然你會遇到比較大的麻煩。說到這,我再介紹一種重寫方法.
仔細看配置文件的寫法:
<?xml version="1.0"?> <config> <modules> <App_Mycms> <version>0.1.0</version> </App_Mycms> </modules> <frontend> <routers> <mycms> <use>standard</use> <args> <module>App_Mycms</module> <frontName>mycms</frontName> </args> </mycms> </routers> </frontend> <global> <routers> <cms> <rewrite> <index> <to>App_Mycms/index</to> <override_actions>true</override_actions> <actions> <noroute><to>App_Mycms/index/noroute</to></noroute> </actions> </index> </rewrite> </cms> </routers> </global> </config>
重寫Magento模型和動作助手(Model&Helper)
我們在改寫Magento的過程中,為了實現自己的業務邏輯,難免要改它的業務模型,這裏先介紹一個最簡單的辦法。前麵我們有將到,Magento是使用的Zend Framework框架:
在breadcrumbs標簽中的值是你的類名,這樣Magento就可以獲取你的類,因為類名與你的目錄名一致。用過zend framework的人都知道,自動加載auto loader這個東西,它會跟你類名中的下滑線去你的目錄中需要對應的類文件。記住一點,下滑線代表下一級別的文件夾,如果你的類名與你的文件目錄名不一 致,那麼Magento根本不會理睬你。
舉例來說:
App_Catalog_Block_Breadcrumbs → /app/code/local/App/Catalog/Block/Breadcrumbs.php App_Catalog_Block_Category_View → /app/code/local/App/Catalog/Block/Category/View.php
我們再看下Magento的啟動器,Mage類中的一段代碼:
if (defined('COMPILER_INCLUDE_PATH')) { $app_path = COMPILER_INCLUDE_PATH; set_include_path($app_path . PS . Mage::registry('original_include_path')); include_once "Mage_Core_functions.php"; include_once "Varien_Autoload.php"; } else { /** * Set include path */ $paths[] = BP . DS . 'app' . DS . 'code' . DS . 'local'; $paths[] = BP . DS . 'app' . DS . 'code' . DS . 'community'; $paths[] = BP . DS . 'app' . DS . 'code' . DS . 'core'; $paths[] = BP . DS . 'lib'; $app_path = implode(PS, $paths); set_include_path($app_path . PS . Mage::registry('original_include_path'));
Magento 在原有的包含路徑上重新添加了它自己的幾個包含路徑(include path),分別是local,community,core代碼池目錄,然後是varien庫目錄,這樣的順序確定了PHP查詢PHP類的順序,分別是 local,community,core,因為magento 並沒有顯式加載任何的庫,而是利用了php的__autoload特性。
如果你在local代碼池(目錄)下麵創建一個Mage名字空間(目錄),那麼你幾乎可以重寫 magento的任意一個類了。比如,我們要重寫Mage_Catalog_Model_Category這個類,那麼你可以創建下列的文件目錄結構:
app/code/local/Mage/Catalog/Model/Category.php
這樣你可以直接將原來的文件複製過來,然後你可以做任意修改了,而不用擔心版本更新的問題。在這裏我不得不告訴你,這樣重寫類的方法不是最佳方案,因為你每次都要複製一個類出來,這樣的方式跟直接修改Magento代碼大區別。你可以嚐試用模塊下的配置文件配置你自己的類,繼承你想重寫的模型或者助手,然後調用自己的類。現在我們以用戶模型為例深入講解。
a.首先創建自己的模塊文件夾
app/code/local/App/Customer app/code/local/App/Customer/etc/config.xml app/code/local/App/Customer/Model app/code/local/App/Customer/Model/Customer.php
b.修改app/etc/modules/App_All.xml
<App_Customer> <active>true</active> <codePool>local</codePool> </App_Customer>
c.修改自己的模塊配置文件app/code/local/App/Customer/etc/config.xml
<?xml version="1.0" encoding="UTF-8"?> <config> <modules> <App_Customer> <version>0.1.0</version> </App_Customer> </modules> <global> <models> <customer> <rewrite> <customer>App_Customer_Model_Customer</customer> </rewrite> </customer> </models> </global> </config>
d.現在寫你新的Model,在文件app/code/local/App/Customer/Model/Customer.php中新建類App_Customer_Model_Cutomer
class App_Customer_Model_Customer extends Mage_Customer_Model_Customer { // 重寫已存在的方法 public function validate() { // Define new validate rules. From now magento call this validate method instead of existing method //return $errors; return true; } // 你還可以創建新的方法 public function newMethod() { // function logic } }
e.我們再重寫一個類,以加深理解。接下來我們重寫Customer Address Model。 跟重寫Customer Model一樣,我們先編輯模塊的配置文件app/code/local/App/Customer/etc/config.xml。
<?xml version="1.0" encoding="UTF-8"?> <config> <modules> <App_Customer> <version>0.1.0</version> </App_Customer> </modules> <global> <models> <customer> <rewrite> <customer>App_Customer_Model_Customer</customer> <address>App_Customer_Model_Address</address> </rewrite> </customer> </models> </global> </config>
上麵看出來了麼,rewrite標簽內的customer和address其實就是你要覆寫的magento model。
接下來創建model class App_Customer_Model_Address,並寫你要覆蓋和新增的方法
class App_Customer_Model_Address extends Mage_Customer_Model_Address { // 重寫已存在的方法 public function validate() { // Define new validate rules. From now magento call this validate method instead of existing method //return $errors; return true; } // 你還可以創建新的方法 public function newMethod() { // function logic } }
f.我再講下如何覆蓋Magento的模型資源,這裏以複寫Address Entity Model class為例,我們先來修改模塊的配置文件app/code/local/App/Customer/etc/config.xml。
<?xml version="1.0" encoding="UTF-8"?> <config> <modules> <App_Customer> <version>0.1.0</version> </App_Customer> </modules> <global> <models> <customer> <rewrite> <customer>App_Customer_Model_Customer</customer> <address>App_Customer_Model_Address</address> </rewrite> </customer> <customer_entity> <rewrite> <address>App_Customer_Model_Entity_Address</address> </rewrite> </customer_entity> </models> </global> </config>
接下來創建類文件。
class App_Customer_Model_Entity_Address extends Mage_Customer_Model_Entity_Address { protected function _afterSave(Varien_Object $address) { // Write your code } }
總結
在本章中我們學習了如何重寫模塊、重寫控製器、重寫區塊,以及如何重寫模型和助手,基本重寫Magento代碼對你來說已經不是難事了。文章至此, 要恭喜你,你已經掌握了大部分修改Magento的技能。下麵的文章我們會進行更深入的研究。最後感謝所有Sasacake Team Member,是他們對待工作的熱情和責任感促使我寫這些教程。
出自:精東·博客
最後更新:2017-04-02 06:51:19