閱讀293 返回首頁    go 技術社區[雲棲]


深入理解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

  上一篇:go magento 1.4 -- 推薦插件 -- 產品頁計算運費插件(Estimate Shipping on the Product Page)
  下一篇:go Could not find main class javacc