Magento事件机制 - Magento Event/Observer 【magento二次开发】

来源:互联网 发布:oracle 数据库别名 编辑:程序博客网 时间:2024/06/05 14:48
为了扩展Magento的功能,我们可以重写Magento的代码,但因为代码只能被重写一次,所以当多个模块需要重写同一部分的代码时,就会引起冲突,好在Magento提供了另一种扩展功能的方法:事件机制,原理是在需要扩展的地方触发事件,各模块捕捉到事件后,如果有该事件的响应,便执行对应的代码,这样便实现了在多个模块中扩展程序的功能。


我们首先看一下Magento系统中预定义了哪些事件:Magento Events , 这个表格有三列,第一列是事件的名称,比如"customer_login",我们大概知道,这是用户登录时触发的事件;第二列是事件的作用域,只要有global/frontend/adminhtml这三种,分别是全局/前台/后台作用域,我们可以指定在哪些作用域响应该事件;最后一列是相应该事件的模块,比如"customer_login"事件在Catalog,Checkout,Log,Reports,Wishlist这几个模块中都有相应。ba


如果需要找到触发事件的地方,可以在《Magento Event/Observer Hooks Cheat Sheet》这个网页中搜索,比如通过查找,我们可以知道"customer_login"这个事件是在 app/code/core/Mage/Customer/Model/Session.php 这个文件中触发的,我们打开这个文件,会发现这样的代码:
class Mage_Customer_Model_Session extends Mage_Core_Model_Session_Abstract
{
    // ...


    public function setCustomerAsLoggedIn($customer)
    {
        $this->setCustomer($customer);
        Mage::dispatchEvent('customer_login', array('customer'=>$customer));
        return $this;
    }
}
我们可以发现"customer_login"事件是在Mage_Customer_Model_Session类的setCustomerAsLoggedIn()函数中通过Mage::dispatchEvent()触发的,同时把customer变量作为参数传递给相应事件的对象。


我们再来分析模块是怎样相应事件的,仍以"customer_login"这个事件为例,我们看到Log模块响应了该事件,打开/app/code/core/Mage/Log/etc/config.xml文件,会看到这样的部分代码:
<config>
    <frontend>
        <events>
            <customer_login>
                <observers>
                    <log>
                        <class>log/visitor</class>
                        <method>bindCustomerLogin</method>
                    </log>
                </observers>
            </customer_login>
        </events>
    </frontend>
<config>
可以看到在Log模块中是在前台相应"customer_login"事件的,捕捉到这个事件时将执行"log/visitor"类的"bindCustomerLogin"方法,我们打开/app/code/core/Mage/Log/Model/Visitor.php文件,将发现这样的代码:
class Mage_Log_Model_Visitor extends Mage_Core_Model_Abstract
{
    // ...


    public function bindCustomerLogin($observer)
    {
        if (!$this->getCustomerId() && $customer = $observer->getEvent()->getCustomer()) {
            $this->setDoCustomerLogin(true);
            $this->setCustomerId($customer->getId());
        }
        return $this;
    }
}
在触发事件时我们使用 Mage::dispatchEvent('customer_login', array('customer'=>$customer)); 的第二个参数传递变量,在bindCustomerLogin($observer)函数中使用$observer参数获取该变量$customer = $observer->getEvent()->getCustomer(),之后进行相应的扩展。


这里也有一个例子:《Customize Magento using Event/Observer》 
Referred to as the Event-Observer methodology, Magento has been programmed to raise events in crucial areas of the flow Using these events for customizations can keep upgrading a much more simple task that does not require fiddling around with Magento’s core source code. An example would be the event ‘catalog_product_save_after’ which will be raised by Magento immediately after a product is saved.Event An Event is something that occurs in a certain place during a particular sequence flow. Say once a customer completes an order, the flow sequence would be toSeems like this tutorial doesn’t work anymore for recent versions (1.6.2 for me), because of magento prices indexing. Price is not calculated on the fly on frontend anymore, and indexing does not call the event “catalog_product_get_final_price”. To be confirmed.




System → Tools → Compilation → In the top right corner there are 2 buttons, make sure the first one is labeled ‘Disabled’.Apart from the powerful OOP way of customizing Magento, which is overriding methods by subclassing Magento’s core Blocks and Models, there is another way to plug in customizations in key flow areas of your Magento eCommerce shop.


1. Save the order details 2. Send e-mail confirmation to customer


Events may be emitted before or after each of these flow points to introduce custom logic.


Observer An Observer is an event handler. It listens to any event it is attached to and accordingly reacts to the event.Simply put, think about overriding existing core logic if you need to completely change or if you need to extend core logic and your new logic is going to be reused elsewhere. Use events if you are fine with existing logic provided by Magento and need to add to the core logic.This example tries to use the Event-Observer technique to introduce a percentage discount for each product. Currently Magento supports special price functionality without a % discount. So we would use this opportunity to customize magento to introduce %discount at a product level.


Before starting, the aim is to ensure that the percentage discount is considered for a simple product when a product is displayed. The event is raised in the class Mage_Catalog_Model_Product_Type_Price→getFinalPrice() (Magento 1.3.0 file: app/code/core/Mage/Catalog/Model/Product/Type/Price.php). The event is raised by the line Mage::dispatchEvent(’catalog_product_get_final_price’,array(’product’⇒$product));


The event that we are about to handle is catalog_product_get_final_price which is going to help us add logic to consider the percentage discount.


Add this new attribute to your attributeset. If your product’s attributeset is ‘default‘, add the new ‘percent_discount’ attribute to this attributeset under “prices” attribute group.Create a new attribute ‘percent_discount‘.


Attrib Identifier –percent_discount , Scope – Store View , Catalog I/p – Text , Unique Value – No , Values Required – NoInput , Validation –Decimal , Apply to Configurable/All Product Types - Yes


Use in quick search – No , Advanced Search – No , Comparable – No , Visibile on Frontend – Yes , Attribute Label – % Discount


Register a new custom local module under name ‘Xyz’. For this create file ‘Xyz.xml’ under directory ‘app/etc/modules/’. File contents are -


<?xml version="1.0"?>
<config>
  <modules>
    <Xyz_Catalog>
      <codePool>local</codePool>
      <active>true</active>
    </Xyz_Catalog>
  </modules>
</config>
grep -rin -B2 -A2 "Mage::dispatchEvent" app/* > events.txtNavigate to the product details page on the front end and observe that the new discount has taken effect. To be noted here is that, on all other screens where discounted price is required. An example here is the search results screen, where you would need to add this new attribute to the select query search attributes in methodMage_CatalogSearch_Block_Result→_getProductCollection()NOTE: To get Magento to load the changed local code configuration, one needs to (temporary) disable caching of code configuration. In admin panel, go to System > Cache management and uncheck the Configuration option.Creating the Observer. Create the directory structure - app/code/local/Xyz/Catalog/Model/Price/. Place the php code below in a file by name ‘Observer.php’ in the directory just created.Register the event with its Observer. Create file ‘config.xml’ under directory ‘app/code/local/Xyz/Catalog/etc/’ with contents as -


<?xml version="1.0"?>
<config>
  <global>
    <models>
        <xyzcatalog>
             <class>Xyz_Catalog_Model</class>
        </xyzcatalog>
    </models>
    <events>
      <catalog_product_get_final_price>
        <observers>
          <xyz_catalog_price_observer>
            <type>singleton</type>
            <class>Xyz_Catalog_Model_Price_Observer</class>
            <method>apply_discount_percent</method>
          </xyz_catalog_price_observer>
        </observers>
      </catalog_product_get_final_price>     
    </events>
  </global>
</config>
<?php
class Xyz_Catalog_Model_Price_Observer
{
    public function __construct()
    {
    }
    /**
     * Applies the special price percentage discount
     * @param   Varien_Event_Observer $observer
     * @return  Xyz_Catalog_Model_Price_Observer
     */
    public function apply_discount_percent($observer)
    {
      $event = $observer->getEvent();
      $product = $event->getProduct();   
      // process percentage discounts only for simple products     
      if ($product->getSuperProduct() && $product->getSuperProduct()->isConfigurable()) {
      } else {
        $percentDiscount = $product->getPercentDiscount();
 
        if (is_numeric($percentDiscount)) {
          $today = floor(time()/86400)*86400;
          $from = floor(strtotime($product->getSpecialFromDate())/86400)*86400;
          $to = floor(strtotime($product->getSpecialToDate())/86400)*86400;
 
          if ($product->getSpecialFromDate() && $today < $from) {
          } elseif ($product->getSpecialToDate() && $today > $to) {
          } else {
            $price = $product->getPrice();
            $finalPriceNow = $product->getData('final_price');
 
            $specialPrice = $price - $price * $percentDiscount / 100;
 
            // if special price is negative - negate the discount - this may be a mistake in data
            if ($specialPrice < 0)
              $specialPrice = $finalPriceNow;
                 
            if ($specialPrice < $finalPriceNow)
              $product->setFinalPrice($specialPrice); // set the product final price
          }
        }   
      }         
      return $this;
    }
}
Set the discount on the product. Navigate to the catalog product on the admin login and edit a product. Set the percentage discount for this product (under prices subtab).


$_productCollection= $_productCollection->addAttributeToSelect('percent_discount');The events list is continually expanding in the Magento core and with extensions you can easily add even more events. In v1.4 there are nearly 300 events compared to 223 in v1.3 and 140 in v1.2. On a Unix like system you can easily determine the available events in your particular build by grepping through the Local, Core and Community folders of your install eg change to the Magento root folder and type
This will create a file events.txt containing all the events located in the app folder.


If you prefere a shell script check out the blog post


(From an unknown Wiki user) I found that step 4 was wrong, here is how I got it to work:


Created: local/Company/Module/Model/Observer.php as class Company_Module_Model_Observer


Then I played around with the XML and watched the file it was trying to include (which with the above instructions was looking for classes called Mage_Company). Then I used this XML exactly, changed EVENT_TO_HOOK and ‘Company’ and ‘company’ and ‘module’. Pay attention to case. (Note from the editor: the case of “company_module_model_observer” seems to be wrong. Won’t problably work on case-sensitive file systems).


<events>
  <EVENT_TO_HOOK>
    <observers>
      <module>
        <type>singleton</type>
        <class>company_module_model_observer</class>
        <method>methodToCall</method>
      </module>
    </observers>
  </EVENT_TO_HOOK>     
</events>
0 0
原创粉丝点击