Отменить регистрацию наблюдателя событий программно
Кто-нибудь знает, можно ли отменить регистрацию наблюдателя событий программно? У меня есть наблюдатель на newsletter_subscribe_save_after
, который обновляет пользовательский атрибут в модели клиента, но когда запись клиента сохраняется, она запускает событие customer_save_after
, определенное в Mage_All.xml
, которое затем повторно сохраняет статус подписки на новостную рассылку, что приводит к бесконечному циклу, который затем запускает ошибку рекурсии PHP из-за вложенности 100 раз.
В идеале я хотел бы отменить регистрацию события customer_save_after
только когда мой наблюдатель стреляет.
3 answers
Вы можете попытаться пометить свое событие как dispatched
и при второй попытке запустить его просто ничего не делайте, если оно уже отправлено. Например, предположим, что ваш метод называется 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.
}
Имя раздела реестра не имеет значения, просто убедитесь, что вы используете одно и то же имя в обоих случаях.
Вы можете отменить регистрацию события наблюдатель на лету программно следующим образом:
$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');
}
Вы не можете отменить регистрацию самого события. Чтобы полностью деактивировать событие, вам придется зациклиться на всех дочерних элементах $branch . '/events/customer_save_after/observers'
и деактивировать каждый из них.
Если это всего лишь один конкретный метод наблюдателя, который вы не хотите запускать снова, вы можете установить его тип singleton
, а затем просто использовать логическое свойство в качестве флага, чтобы проверить, был ли он уже вызван один раз следующим образом:
class Your_Module_Model_Observer
{
private $_processFlag = false;
public function customerSaveAfter($data)
{
if (! $this->_processFlag) {
$this->_processFlag = true;
// do your thing with $customer->save()
}
}
}
Вот вспомогательный метод доказательства концепции, который переключает существующего наблюдателя. если вы хотите, чтобы событие было отключено по умолчанию, добавьте <type>disabled</type>
в список вашего наблюдателя config.xml определение.
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);
}
}
Функция использует отражение для доступа к защищенному в противном случае свойству $_events
Mage_Mage_Core_Model_App
. Тот же трюк может быть использован для введения ранее неопределенных наблюдателей.