Warning: Redis::connect(): connect() failed: Connection refused in /var/www/admclub.com/wp-content/object-cache.php on line 418
重写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成功记录了我们的信息,打开页面http://www.wemvc.dev /checkout/cart/,显示的是购物车页面,一切正常,但如果你访问http://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框架.

我们再看下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,是他们对待工作的热情和责任感促使我写这些教程。

出自:精東·博客

admclub.com注:感谢原作者的精彩讲解.

发表评论?

0 条评论。

发表评论


注意 - 你可以用以下 HTML tags and attributes:
<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>