March 6, 2016

Naming Magento observer methods

Yireo Blog Post

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.

Posted on March 6, 2016

About the author

Author Jisse Reitsma

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.

Sponsor Yireo

Looking for a training in-house?

Let's get to it!

We don't write too commercial stuff, we focus on the technology (which we love) and we regularly come up with innovative solutions. Via our newsletter, you can keep yourself up to date on all of this coolness. Subscribing only takes seconds.

Do not miss out on what we say

This will be the most interesting spam you have ever read

We don't write too commercial stuff, we focus on the technology (which we love) and we regularly come up with innovative solutions. Via our newsletter, you can keep yourself up to date on all of this coolness. Subscribing only takes seconds.