I have been wondering about this for a while. What if Magento has written a core Observer class and performs a functionality that you do not want it to execute, or you want to rewrite it? Is there a way to say, don’t use this method in an Observer, just use mine. If I setup a method for my own Observer won’t it just do the core functionality first and then whatever I have implement?
For example, Magento wants to save some data to the database in an Observer method, but I don’t want it to save that data at all, I want it to save some other data that I have added columns or attributes to the database for.
Standard caveat about class overrides being the last resort for implementing your own functionality
It’s probably possible to fiddle with the loading of the Magento global config to strip out a core Magento Observer, but there’s no supported way for doing it.
However, consider how the Core observers are configured.
<adminhtml> <events> <cms_wysiwyg_config_prepare> <observers> <widget_observer> <class>widget/observer</class> <method>prepareWidgetsPluginConfig</method> </widget_observer> </observers> </cms_wysiwyg_config_prepare> </events> </adminhtml>
Observers are Magento Model classes. If a Model’s been configured with the URI/path based syntax
as opposed to a full PHP class name
you can create an override for the Observer Model class (just as you can for any other Model). If a PHP class name’s been used, you’re out of luck. (You could place a local file in local/Mage/Widget/Model/Observer.php if you’re willing to take on the responsibility of maintenance, but I don’t recommend it)
So, to override the above observer, you would
Create a custom module that include an override for the class Mage_Widget_Model_Observer.
In your override class, either redeclare
prepareWidgetsPluginConfigto do what you want OR override the specific method. This could include a empty method to completely remove the functionality.
A better method of doing this is to simply re-declare the observer’s definition in a config.xml file.
For example, I needed to disable the enterprise_persistent_cart observer which was declared on event controller_action_layout_generate_blocks_after by module Enterprise_Persistent.
The declaration in Enterprise_Persistent’s config.xml file is such
<frontend> <events> <controller_action_layout_generate_blocks_after> <observers> <enterprise_persistent_cart> <class>enterprise_persistent/observer</class> <method>removeCartLink</method> </enterprise_persistent_cart> </observers> </controller_action_layout_generate_blocks_after>
So I created a module, and in my module’s config.xml, I did the following:
<frontend> <events> <controller_action_layout_generate_blocks_after> <observers> <enterprise_persistent_cart> <type>disabled</type> </enterprise_persistent_cart> </observers> </controller_action_layout_generate_blocks_after>
I also made my module depend on the Enterprise_Persistent module. This is necessary to make sure my module’s config.xml is processed AFTER the Enterprise_Persistent module’s config.xml. I did this by doing the following in my module’s app/etc/modules My_Module.xml module declaration file
<config> <modules> <Atlex_AddCartLinkToHeader> <active>true</active> <codePool>local</codePool> <depends> <Enterprise_Persistent/> </depends> </Atlex_AddCartLinkToHeader> </modules> </config>
For each event, there can only be one observer action declared for a given observer name. Therefore, as long as my module’s config.xml is processed after the Enterprise_Persistent module’s config.xml file, my observer declaration for enterprise_persistent_cart will be the observer action which is excuted.
The <type> disabled </type> node will disable the observer from firing. If you wanted to override the observer to execute your own method, then you would simply replace the <type> node with your observer’s <class> and <method> nodes.
This allows you to override/disable observers without overriding core classes. It’s more extendable for future developers.
I wanted to add a comment to @Alan’s answer because I think he’s nailed it, but my comment got too long and not enough formatting! Here goes:
Nice one @Alan, a clever way to fix what appears to be a hole while still respecting the architecture. A couple of thoughts:
if a custom module binds to the same event, the custom Observer would be called later in the Chain of Responsiblity than the core and hence could possibly override the core Observer? This depends on what the core Observer is doing, e.g. setting a redirect value. In the example the OP provided, this will work. When binding to a Model_save_before event, the core Observer will get called, but your Observer can still modify the contents of the model save data before it is written to the database. You can change or unset the values that are affected by the core Observer.
to override the core Observer’s model, inserting a
<models><widget><rewrite>in the config.xml would be the right approach
this might be one of the few cases where calling
parent::is not required when overriding(!)
EDIT – more info added in step 1 to answer specifics of OP’s question
Thanks Jonathan, I override Observer with basic model overiding syntax
<config> <global> <models> <sales> <rewrite> <observer>PPI_Sales_Model_Observer</observer> </rewrite> </sales> </models> </global> </config>
It worked well.