Yii2:将行为附加到每个控制器

Yii2: Attach behavior to every controller

我们如何将行为附加到应用程序中的所有 Web 控制器?

我知道这 理论上 可以通过依赖注入实现,所以我假设这样的事情会起作用:

Yii::$container->set('yii\web\Controller', [
    'as myBehavior' => [
        'class'     => 'app\behaviors\MyBehavior',
    ],
]);

但是 DI 需要精确的 class 匹配(附加到父 class 将不起作用)。无法提前知道所有控制器名称,尤其是当大多数控制器名称来自 3rd 方模块时。

还有其他方法吗?

编辑:这样做的目的是动态添加控制器过滤器(这只是一种特殊类型的行为)。因此,在 EVENT_BEFORE_ACTION 事件期间附加行为是不够的,因为它是在请求过滤后很久才触发的。

有趣的问题,我必须说。我找不到简单的解决方案,但我有这个老掉牙的想法。您可以利用 Yii 自动加载器并加载您的 yii\web\Controller 版本而不是原始版本。

为此:

  1. 从供应商处复制原始文件并将其放入您的应用程序

  2. 不要更改原来的命名空间和名称。

  3. 在里面添加你的行为配置(或者只是行为的代码,随便什么)。

  4. 将此行添加到每次应用程序运行时都会调用的位置(如入口点文件或 bootstrap 文件,必须在 after vendor/yiisoft/yii2/Yii.php 文件是 required):

    Yii::$classMap['yii\web\Controller'] = ''; // replace '' with the path to your version
                                               // of yii\web\Controller
    

现在,每次自动加载器尝试加载 yii\web\Controller 时,它都会加载您的版本,因此它应该可以像您希望的那样工作。

这样做的明显弊端是升级 Yii 时您必须手动检查原始文件是否未更新以使其保持最新。

模块(和应用程序)的 beforeAction 事件在该事件的控制器版本之前触发。您可以利用它并将行为附加到当前控制器。

例如在您的 web.php 配置中:

return [
    'on beforeAction' => function() {
        Yii::$app->controller->attachBehavior(
            'myBehavior',
            \app\behaviors\MyBehavior::class
        );
    },
    // ... other configurations
];

当然缺点是从一开始就没有附加行为

注意:如果您的目标是将过滤器附加到每个控制器,您可以简单地将它附加到应用程序本身而不是控制器。

子控制器行为取决于 AccesControler 行为

   class WorkerimgController extends OfficeController{
    public function behaviors()
    {
      return ArrayHelper::merge(parent::behaviors(), [
      ]);
    }
}