Within Magento 1 you can use observers to listen to events triggered elsewhere, and thus extend Magento in a clean way. On twitter, @tim_bezhashvyly mentioned that observer methods should be named a certain way. So let's see where this brings us.
The basics
Within a Magento module you can define an observer in the XML file config.xml
, by adding the following structure to it:
<config>
<global>
<events>
<catalog_product_save_before>
<observers>
<example_fix_product_alias>
<class>example/observer</class>
<method>fixProductAlias</method>
</example_fix_product_alias>
</observers>
</catalog_product_save_before>
</events>
</global>
</config>
We'll assume our module is called Yireo_Example
. This XML code defines that our module listens to an event catalog_product_save_before
(triggered right before the product is saved to the database) and that whenever this event is triggered, our observer example/observer
is called upon with a method fixProductAlias
. Assuming the alias example/observer
translates into a class name Yireo_Example_Model_Observer
, the observer class could look like the following:
class Yireo_Example_Model_Observer
{
public function fixProductAlias($observer)
{
$product = $observer->getEvent()->getProduct();
// @todo: Fix the product alias
return $this;
}
}
This setup assumes some standards and some free naming. For instance, it is rather a standard to name your observer simply Observer
. Only when you have many events to listen to, it might be a good idea to split up events across multiple observers, and for instance name the class after the group of events (for instance ProductObserver
).
The string example_fix_product_alias
identifies our observer uniquely within Magento (so, you might say it is the observer identifier - I usually name this after the method itself but with my module name prefixed to it. The method fixProductAlias
already tells us a bit on what the purpose of the observer actually is - to fix the product alias.
My standard so far
I've been defining my methods and names a bit differently. Instead of naming the observer method and observer identifier after its purpose, I've named them after the event. A common Yireo module would like the following (same goal as above, different naming):
<config>
<global>
<events>
<catalog_product_save_before>
<observers>
<example_catalog_product_save_before>
<class>example/observer</class>
<method>catalogProductSaveBefore</method>
</example_catalog_product_save_before>
</observers>
</catalog_product_save_before>
</events>
</global>
</config>
And the PHP code:
class Yireo_Example_Model_Observer
{
public function catalogProductSaveBefore($observer)
{
$product = $observer->getEvent()->getProduct();
// @todo: Fix the product alias
return $this;
}
}
This would actually defy the principles of clean coding, because the method name catalogProductSaveBefore
does not describe the goal of the method. Instead of renaming the method, I've most of the time refactored this to add a new method that states the actual purpose:
class Yireo_Example_Model_Observer
{
public function catalogProductSaveBefore($observer)
{
$product = $observer->getEvent()->getProduct();
$this->fixProductAlias($product);
return $this;
}
protected function fixProductAlias($product)
{
// @todo: Fix the product alias
}
}
To me, this was the best solution: It complies the Single Responsibility Principle, because the sole purpose of the method catalogProductSaveBefore
is not intercept the event, while the second method fixProductAlias
does the fixing part.
The discussion on naming your observer methods
The reason for this blog is that @tim_bezhashvyly pointed out observer methods should be named after their purpose, not their event. One of the reasons he mentioned for this was that a Magento developer should scan your XML code and see directly for what purpose you have defined an observer. With the first code sample, the method name fixProductAlias
already gives a clue here. With my code samples, you have to jump to the PHP code to find out - so it requires an extra step.
Personally I always jump to the PHP code to find out about the nature, but as Magento 2 its Interface Driven Design gains ground, it makes more and more sense to have observer methods named after their purpose. Moreover, I reminded myself of the n98-magerun
command to get a listing of observers:
magerun dev:module:observer:list
It does not include any of the PHP implementation. It simply lists all of the XML names and PHP method names. Not naming XML names and observer methods after their purpose will leave magerun
users in the dark. Tim has convinced me.
Documenting your observer methods
Still, my workflow will be that I quickly open up observer classes in PhpStorm to see what their purpose is. The same annoyance that Tim had with observer methods named after their event, I now have with observer methods named after their purpose:
class Yireo_Example_Model_Observer
{
public function fixProductAlias($observer)
{
$product = $observer->getEvent()->getProduct();
// @todo: Fix the product alias
return $this;
}
}
If the event catalog_product_save_before
was used this code would be completely different from when the event catalog_product_save_after
was used. The method name now states everything about its purpose, but nothing about its circumstances. Of course, you could jump from the PHP class to the XML code, but this completely screws the point of Tim and me.
To fix this problem, I would suggest a simple change: Add the proper PHP comments. Below I add a method description which I use most of the time, but just easily a new tag @observer
could be invented for this:
class Yireo_Example_Model_Observer
{
/**
* Event "catalog_product_save_before"
*
* @observer catalog_product_save_before
*/
public function fixProductAlias($observer)
{
$product = $observer->getEvent()->getProduct();
// @todo: Fix the product alias
return $this;
}
}
Multiple events
But what if your observer listens to the same event for different reasons? The logical followup would be to define multiple observer hooks:
<config>
<global>
<events>
<catalog_product_save_before>
<observers>
<example_fix_product_alias>
<class>example/observer</class>
<method>fixProductAlias</method>
</example_fix_product_alias>
<example_log_old_product>
<class>example/observer</class>
<method>logOldProduct</method>
</example_log_old_product>
</observers>
</catalog_product_save_before>
</events>
</global>
</config>
This will give a slight overhead in Magento, compared to adding a single observer method, which then splits up into 2 task methods. But taken into account that Magento has 1000s of observers I would say that this has no point. And for sure the XML code is readable and declarative all the time.
About the author
Jisse Reitsma is the founder of Yireo, extension developer, developer trainer and 3x Magento Master. His passion is for technology and open source. And he loves talking as well.