プログラムでイベントオブザーバーの登録を解除する


7

プログラムでイベントオブザーバーの登録を解除できるかどうか誰かが知っていますか?newsletter_subscribe_save_after顧客モデルのカスタム属性を更新するオブザーバーがありますが、顧客レコードが保存customer_save_afterされるMage_All.xmlと、定義されたイベントからトリガーされ、ニュースレターのサブスクリプションステータスが再保存され、無限ループが発生し、PHP再帰エラーが発生します100回入れ子に。

理想的にはcustomer_save_after、オブザーバーが起動したときにのみイベントの登録を解除したいと思います。


この質問は必要ありませんが、気に入っています。+1。
pspahn、2015年

回答:


10

イベントにマークを付けてdispatched、2回目に実行しても、すでにディスパッチされている場合は何もしないでください。たとえば、あなたのメソッドがと呼ばれているとしましょう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.
}

レジストリキーの名前は重要ではありません。どちらの場合も必ず同じ名前を使用してください。


夢のように働いた。小さなことの1つは、これは$ thisではなく$ thisになるはずです(6文字未満なので、stackexchangeでは変更できません)
Richard Cleverley

それを私が直した。すみません
マリウス

私は、オブザーバーインスタンスにローカルな変数(そのシングルトンを想定)またはメソッド自体にローカルな静的変数を使用するか、レジストリを使用します。
davidalger 2013

@davidalger理由を少し説明してもらえますか?それは最も便利な縫い目なのでレジストリを使用しました。静的変数を使用する利点はありますか?
マリウス

@Mariusレジストリの使用は、基本的にグローバル変数を使用する必要がない場合に使用します。オブザーバーインスタンスに含まれたままにしておく方がきれいです。したがって、ほとんどが意味論的であり、ソリューションは適切に機能します。:)
davidalger 2013

7

次のように、プログラムでその場でイベントオブザーバーの登録を解除できます。

$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()
        }
    }
}

フラグを使用するか、ディスパッチ済みとして登録することは、面倒が最も少ないようですが、物理的にフラグを無効にする方法を見るのは興味深いです。
Richard Cleverley 2013

1
レジストリを使用することは、グローバル変数を使用することとほとんど同じです。オブザーバーインスタンスの状態を管理する方が良いと思います。
ビナイ

あなたはおそらく正しいです。その方法でオブザーバーにすべてを自己保持することは、おそらくそれを行うためのより良い方法です。
Richard Cleverley 2013

1

以下は、既存のオブザーバーを切り替える概念実証ヘルパーメソッドです。イベントをデフォルトで無効にする場合は、<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。同じトリックを使用して、以前に未定義のオブザーバーを挿入することもできます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.