Events Yii2:仅在场景中触发的ActiveRecord事件

Events Yii2:仅在场景中触发的ActiveRecord事件,events,activerecord,yii2,scenarios,Events,Activerecord,Yii2,Scenarios,有没有人需要绑定ActiveRecord事件处理程序,使其仅在特定场景中触发 在理想情况下,ActiveRecordon()方法还将接受$scenarios参数,并仅在事件发生时ActiveRecord正在使用该场景时触发处理程序。但既然不是这样,我正在寻找一种干净、可靠的方法来实现这种功能 编辑:这需要处理任何事件,包括由Yii框架触发的内置事件(例如插入后的事件)。这是我第一次评论的改进 class ScenarioEvent extends \yii\base\Event { pr

有没有人需要绑定ActiveRecord事件处理程序,使其仅在特定场景中触发

在理想情况下,ActiveRecord
on()
方法还将接受$scenarios参数,并仅在事件发生时ActiveRecord正在使用该场景时触发处理程序。但既然不是这样,我正在寻找一种干净、可靠的方法来实现这种功能


编辑:这需要处理任何事件,包括由Yii框架触发的内置事件(例如插入后的事件)。

这是我第一次评论的改进

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;
                }
            }
        }
    }
}

我认为您可以扩展
\yii\base\Event
并在Scenario()上添加自己的方法
。它将与()上的
相同
,但会在场景中获得一个附加参数。您可以像在ActiveRecord中使用方法
scenarios()
一样使用它。您还需要重写
trigger()
方法,并在父调用之前添加场景检查。遗憾的是,这可能只适用于手动触发的事件(我不需要)。它不适用于任何自动触发的内置事件(例如
\yii\db\AfterSaveEvent
中的
\yii\db\ActiveRecord
),这正是我实际需要的。