Book Image

Getting Started with Magento Extension Development

By : Branko Ajzele
Book Image

Getting Started with Magento Extension Development

By: Branko Ajzele

Overview of this book

Modules, are a group of php and xml files meant to extend the system with new functionality, or override core system behavior. Most of the base Magento system is built using the module system, so you can see why they are an important feature for this rich open-source e-commerce solutions. This book explores key module development techniques and teaches you to modify, understand and structure your modules making it easy for you to get a strong foundation for clean and unobtrusive Magento module development. Getting Started with Magento Extension Development is a practical, hands-on guide to building Magento modules from scratch. This book provides an in depth introduction and helps you discover features such as; blocks, controllers, models, configuration files, and other crucial elements which contribute to the Magento architecture. This book introduces the you to real-world modules and helps provide a strong foundation which you need to become a professional Magento module developer. The book further explores best practices and tips and tricks offering you the ultimate go to guide. Getting Started with Magento Extension Development focuses on three areas. First you are guided through the entire Magento structure, where each important directory or file is explored in detail. Then the essence of the module structure and development is explained through the detailed coverage of models, blocks, controllers, configuration, and other files that manifest a single module. Finally, a detailed set of instructions is given for building four real-world modules, including a payment and shipping module.
Table of Contents (13 chapters)
Getting Started with Magento Extension Development
Credits
About the Author
About the Reviewers
www.PacktPub.com
Preface
Index

The event/observer pattern


Next, we will move on to an event/observer pattern implemented by Magento. Events and observers are extremely important in Magento because they enable you to easily hook onto various parts of Magento and add your own pieces of code to it. In certain situations they are slightly underestimated by extension developers, either due to their knowledge of the platform, or due to the lack of grand vision or forced quick and dirty implementations.

Events and observers are the key to writing unobtrusive code in cases where you need to change or add to the default Magento behavior. For example, if you need to send all your newly created orders to an external fulfillment system, most of the time you simply need to observe a proper event and implement your business logic within an observer.

There are several types of events getting fired in Magento depending on how you differentiate them. For example, we could divide them into static and dynamic events.

Static events are all those events defined through code with full event names such as Mage::dispatchEvent('admin_session_user_login_failed', array('user_name' => $username, 'exception' => $e));, Mage::dispatchEvent('cms_page_prepare_save', array('page' => $model, 'request' => $this->getRequest()));, Mage::dispatchEvent('catalog_product_get_final_price', array('product' => $product, 'qty' => $qty));, Mage::dispatchEvent('catalog_product_flat_prepare_columns', array('columns' => $columnsObject));, and Mage::dispatchEvent('catalog_prepare_price_select', $eventArgs);.

Dynamic events are all those events defined through code dynamically at runtime such as Mage::dispatchEvent($this->_eventPrefix.'_load_before', $params);, Mage::dispatchEvent($this->_eventPrefix.'_load_after', $this->_getEventData());, Mage::dispatchEvent($this->_eventPrefix.'_save_before', $this->_getEventData());, Mage::dispatchEvent($this->_eventPrefix.'_save_after', $this->_getEventData());, and Mage::dispatchEvent('controller_action_layout_render_before_'.$this->getFullActionName());.

Both types of events are absolutely the same; they function the same, and the preceding differentiation is simply a matter of terminology. We are calling the other ones dynamic because their full name is not known until the runtime.

For example, each time you wish to intercept certain parameters passed to a controller action, you could simply create an event observer that would observe the controller_action_predispatch_* event, which is triggered within the Mage_Core_Controller_Varien_Action class file as follows: Mage::dispatchEvent('controller_action_predispatch_' . $this->getFullActionName(), array('controller_action' => $this));.

Now, let us see how exactly do we define the event observer and place some of our code to be executed upon certain events. First, we need to create an entry within our extensions config.xml file.

Let's say we want to introspect all the parameters passed to the controller action during the customer registration process. When a customer fills in the required registration fields and clicks on Submit, the form posts the data to the http://{{shop.domain}}/index.php/customer/account/createpost/ URL.

If you look at the previously mentioned the controller_action_predispatch_* event, the expression $this->getFullActionName() would return the customer_account_createpost string. You can find that out easily by placing the var_dump($this->getFullActionName()); exit; expression right there under the Mage::dispatchEvent('controller_action_predispatch_... expression. Please note that we are using var_dump here just for the simplicity of demonstration. So now that we know this, we can safely conclude that the full event name we need to observe in this case is controller_action_predispatch_customer_account_createpost.

Now we know that the event name is a requirement upon which we create a proper config.xml entry for defining our event observer as shown in the following code:

<?xml version="1.0"?>
<config>
   <!-- … other elements ... -->
   <frontend>
      <events>
         <controller_action_predispatch_customer_account_createpost>
            <observers>
              <foggyline_happyhour_intercept>
                 <class>foggyline_happyhour/observerobserver</class>
                 <method>intercept</method>
                 </foggyline_happyhour_intercept>
              </observers>
         </controller_action_predispatch_customer_account_createpost>
      </events>
   </frontend>
   <!-- … other elements ... -->
</config>

Within the observer's element comes the definition of our observer, which we call foggyline_happyhour_intercept in this case. Each observer needs two properties-defined classes, which in this case points to the foggyline_happyhour class group and Observer class file thus, the string foggyline_happyhour/observer; the other one is the method within the Observer class file.

Next, we create the actual Observer class file app/code/community/Foggyline/HappyHour/Model/Observer.php with the following content:

<?php

class Foggyline_HappyHour_Model_Observer
{
   public function intercept($observer = null)
   {
      $event = $observer->getEvent();
      $controllerAction = $event->getControllerAction();
      $params = $controllerAction->getRequest()->getParams();
      
      Mage::log($params);
   }
}

A quick look at Foggyline_HappyHour_Model_Observer reveals one important thing: unlike Model, Block, and Controller classes, the Observer classes do not need to extend anything.

If you now go to your browser and try to create a new customer account, you will get your var/log/system.log file filled with the HTTP POST parameters provided by the customer during the registration process. You might need to refresh/re-open system.log in your editor in order to pick up the changes, in case you don't see the log entries.

Sometimes, the right event might not be there; so you might need to look for the second best. For example, if we did not have the controller_action_predispatch_customer_account_createpost event dispatched, the next best event would probably be the following one: Mage::dispatchEvent('controller_action_predispatch', array('controller_action' => $this));.

However, the event controller_action_predispatch is pretty generic, which means it will get triggered for every controller action predispatch. In this case, you would have to do a little if/else logic within your event observer code. Just as we have controller fired events, we also have model-fired events. If you open a class file like Mage_Catalog_Model_Product, you can see property definitions like protected $_eventPrefix = 'catalog_product'; and protected $_eventObject = 'product';.

Now, if you trace the code a little bit down to the Mage_Core_Model_Abstract class file, you will see that the properties $_eventPrefix and $_eventObject are used for dynamic events such as (along with the static events for the same action) Mage::dispatchEvent($this->_eventPrefix.'_load_before', $params);, Mage::dispatchEvent($this->_eventPrefix.'_load_after', $this->_getEventData());, Mage::dispatchEvent($this->_eventPrefix.'_save_commit_after', $this->_getEventData());, Mage::dispatchEvent($this->_eventPrefix.'_save_before', $this->_getEventData());, Mage::dispatchEvent($this->_eventPrefix.'_save_after', $this->_getEventData());, Mage::dispatchEvent($this->_eventPrefix.'_delete_before', $this->_getEventData());, Mage::dispatchEvent($this->_eventPrefix.'_delete_after', $this->_getEventData());, Mage::dispatchEvent($this->_eventPrefix.'_delete_commit_after', $this->_getEventData());, and Mage::dispatchEvent($this->_eventPrefix.'_clear', $this->_getEventData());.

Knowing this is extremely important, as it enables you to create all sorts of event observers for specific models and their actions, for example customer, order, and invoice entity create/update/delete actions. This is why defining the $_eventPrefix and $_eventObject properties on your custom model classes is something you should adopt as a sign of good coding practice. Doing so enables other third-party developers to easily hook onto your extension code via the observer in a clean and unobtrusive way.