Customizing Magento using Event-Observer Method

Last modified by naitsirch on Mon, September 6, 2010 10:57

Edit this page|Old Revisions  

TABLE OF CONTENTS

Customizing Magento using Event-Observer Method

NOTICE:

Make sure the compiler is turned OFF

Overview

Terminology

Customization - Event Vs Overriding

Example Usage

Step 1

Step 2

Step 3

Step 4

Step 5

Step 6

Step 7

Events

Other Notes

Fix for Step 4

NOTICE:

 

Make sure the compiler is turned OFF

Since version 1.3+, Magento has a compiler mechanism. If that compiler is active, Magento will try to find the files in the folder includes/src.

 

There are 2 ways to check if the compiler is off:

 

1. Backoffice → Tools → Compilation → In the top right corner there are 2 buttons, make sure the first one is labeled ‘Disabled’. If it’s enabled click it.

 

2. Open file includes/config.php, and comment out both lines ( eg: put a # character in front of the php-codelines )

 

Once your plugin is tested and finished, you can turn the compiler back on if you wish so.

 

Overview

 

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. Referred to as the Event-Observer methodology, Magento has been programmed to raise events in crucial areas of the flow and handling these events for customizations would keep upgradation a 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.

 

Terminology

 

Event 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 to i. Save the order details ii. Send e-mail confirmation to customer Events may be seeded before or after each of these flow points to introduce custom logic.

 

Observer Observer is the handler of an event. This listens to any event it is attached to and accordingly handles the event.

 

Customization - Event Vs Overriding

 

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.

 

Example Usage

 

This example tries to use the Event-Observer methodology 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.

 

Step 1

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

 

Step 2

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.

 

Step 3

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>

Step 4

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>catalog/price_observer</class>

            <method>apply_discount_percent</method>

          </xyz_catalog_price_observer>

        </observers>

      </catalog_product_get_final_price>     

    </events>

  </global>

</config>

Step 5

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.

 

<?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;

    }

}

Step 6

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.

 

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).

 

Step 7

Navigate 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 method Mage_CatalogSearch_Block_Result→_getProductCollection()

 

$_productCollection= $_productCollection->addAttributeToSelect('percent_discount');

Events

 

The events list is continually expanding in the Magento core (over 223 in v1.3.2.4 compare to 140 in v1.2.0.2) and extensions can easily add more. 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 app/code/core folder and type

 

grep -r "dispatchEvent" . > ../events.txt

This will create a file app/code/events.txt containing all the events located in the core.

 

For a nice shell script check out this blog post on http://www.edmondscommerce.co.uk/blog/magento/magento-events-cheat-sheet-grep-works-for-any-version/

 

At time of editing the wiki, the script is as follows:

 

#!/bin/bash

 

# Find all Magento Events, include file names, line numbers and the preceding 6 lines of code

 

#Please define these two

 

ABSOLUTE_PATH_TO_MAGENTO_ROOT=/home/joseph/Projects/Magento/

 

ABSOLUTE_PATH_TO_OUTPUT_FILE_INC_FILE_NAME= /home/joseph/magentoEvents.txt

 

#here is the command

 

find $ABSOLUTE_PATH_TO_MAGENTO_ROOT -name “*.php” | xargs -L10 grep -n -B 6 “dispatchEvent” .> $ABSOLUTE_PATH_TO_OUTPUT_FILE_INC_FILE_NAME

 

# save this file as magentoevents.sh

 

# then do command: chmod +x magentoevents.sh

 

# then to run, do command: ./magentoevents.sh

 

Below is a list of events from earlier releases.

 

Event List:

 

Magento v 1.1.6 Event list :

 

http://www.magentocommerce.com/wiki/_media/magento_events_1.1.6.xls

 

Magento v 1.2.0.2 Event list :

 

http://www.magentocommerce.com/wiki/_media/magento_events_v1.2.0.2.xls

 

Other Notes

 

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, change EVENT_TO_HOOK and ‘Company’ and ‘company’ and ‘module’, pay attention to casing, bleh

 

<events>

  <EVENT_TO_HOOK>

    <observers>

      <module>

        <type>singleton</type>

        <class>company_module_model_observer</class>

        <method>methodToCall</method>

      </module>

    </observers>

  </EVENT_TO_HOOK>     

</events>

Fix for Step 4

 

I’ve just found only one error:

 

change:

 

<class>catalog/price_observer</class>

with:

 

<class>Xyz_Catalog_Model_Price_Observer</class>

it will work fine!