The question:
Does anyone know if it’s possible to unregister an event observer programatically? I have an observer on newsletter_subscribe_save_after
that updates a custom attribute in the customer model but when the customer record is saved it triggers off the customer_save_after
event defined in Mage_All.xml
which then re-saves the newsletter subscription status resulting in an infinite loop that then triggers the PHP recursion error due to nesting 100 times.
Ideally I’d like to unregister the customer_save_after
event only when my observer fires.
The Solutions:
Below are the methods you can try. The first solution is probably the best. Try others if the first one doesn’t work. Senior developers aren’t just copying/pasting – they read the methods carefully & apply them wisely to each case.
Method 1
You can try to mark your event as dispatched
and on the second attempt of running it just do nothing if it’s already dispatched. For example let’s say your method is called updateCustomer()
.
public function updateCustomer($observer){
if (Mage::registry('my_event_was_dispatched') == 1){//do nothing if the event was dispatched
return $this;
}
//your code here
Mage::register('my_event_was_dispatched', 1);//mark the event as dispatched.
}
The registry key name is not important, just make sure you use the same one in both cases.
Method 2
You can unregister an event observer on the fly programmatically as follows:
$area = Mage::app()->getStore()->isAdmin() ? 'adminhtml' : 'frontend';
foreach (array($area, 'global') as $branch) {
$path = $branch . '/events/customer_save_after/observers/your_module/type';
Mage::app()->getConfig()->setNode($path, 'disabled');
}
You can not unregister an event itself. To completely deactivate an event, you would have to loop over all children of $branch . '/events/customer_save_after/observers'
and deactivate each one.
If it’s just a single specific observer method you don’t want to run again, you can set it’s type to be singleton
and then just use a boolean property as a flag to check if it already was called once as follows:
class Your_Module_Model_Observer
{
private $_processFlag = false;
public function customerSaveAfter($data)
{
if (! $this->_processFlag) {
$this->_processFlag = true;
// do your thing with $customer->save()
}
}
}
Method 3
here’s a proof-of-concept helper method that toggles an existing observer. if you want to have the event disabled as default, add <type>disabled</type>
to your observer’s config.xml definition.
public function toggleObserver($area, $event, $name, $enable)
{
$app = Mage::app();
// reflection on the property Mage_Core_Model_App::_events
$class = new ReflectionClass(get_class($app));
$property = $class->getProperty('_events');
$property->setAccessible(true);
// get the events
$events = $property->getValue($app);
// make sure the event config is loaded
if (!isset($events[$area][$event]))
{
// load observers from config
/** @see Mage_Core_Model_App::dispatchEvent() */
$config = $app->getConfig()->getEventConfig($area, $event);
if (!$config)
{
// event is not configured
return;
}
// create observers array
$observers = array();
foreach ($config->observers->children() as $name => $values)
{
$observers[$name] = array(
'type' => (string) $values->type,
'model' => $values->class ? (string) $values->class : $values->getClassName(),
'method'=> (string) $values->method,
'args' => (array) $values->args,
);
}
$events[$area][$event]['observers'] = $observers;
}
if ($events[$area][$event] && isset($events[$area][$event]['observers'][$name]))
{
// enable/disable the observer by changing its type
$events[$area][$event]['observers'][$name]['type'] = $enable ? '' : 'disabled';
// update the object
$property->setValue($app, $events);
}
}
the function makes use of reflection to access the otherwise protected $_events
property of Mage_Mage_Core_Model_App
. the same trick could be used to inject previously undefined observers.
All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0