2016-04-07 2 views
0

Нужно ли кому-либо когда-либо связывать обработчик событий ActiveRecord таким образом, чтобы он запускался только в определенных сценариях?Yii2: события ActiveRecord, которые запускаются только по сценарию

В идеальном мире метод ActiveRecord on() также принимает параметр $ scenarios и запускает обработчик только в том случае, если ActiveRecord использует этот сценарий в момент возникновения события. Но так как это не так, я ищу чистый и надежный способ реализовать этот тип функциональности.

Редактировать: Это должно работать с любым событием, включая встроенные события, инициируемые структурой Yii (например, ActiveRecord::EVENT_AFTER_INSERT).

+1

Я думаю, вы можете расширить '\ yii \ base \ Event' и добавить свой собственный метод' onScenario() '. Он будет таким же, как 'on()', но получает еще один аргумент со сценариями. Вы можете использовать его как метод 'scenarios()' в ActiveRecord. Также вам нужно переопределить метод 'trigger()' и добавить проверку сценария перед вызовом родителя. – SiZE

ответ

0

Это улучшение моего первого комментария.

class ScenarioEvent extends \yii\base\Event 
{ 
    private static $_events = []; 

    public static function onScenario($scenario, $class, $name, $handler, $data = null) 
    { 
     // You may use foreach if you wil use many scenarios for event 
     if (!isset(self::$_scenarios)) { 
      self::$_scenarios[$scenario] = []; 
     } 
     self::$_scenarios[$scenario][$name][] = $class; 
     return static::on($class, $name, $handler, $data); 
    } 

    public static function trigger($class, $name, $event = null) 
    { 
     if (
      // If event is null assumed that it has no sender with scenario 
      $event === null 
      || empty(self::$_scenarios[$event->sender->scenario][$name]) 
     ) { 
      parent::trigger($class, $name, $event); 
     } else { 
      $classes = array_merge(
       [$class], 
       class_parents($class, true), 
       class_implements($class, true) 
      ); 

      foreach ($classes as $class) { 
       if (in_array($class, self::$_scenarios[$event->sender->scenario][$name])) { 
        parent::trigger($class, $name, $event); 
        break; 
       } 
      } 
     } 
    } 
} 
+0

К сожалению, это может работать только с событиями, инициируемыми вручную (мне это не нужно). Он не работает с любыми встроенными событиями с автоматическим запуском (например, '\ yii \ db \ AfterSaveEvent' в' \ yii \ db \ ActiveRecord'), что мне действительно нужно. – mae