Как мы прикрепляем поведение ко всем веб-контроллерам в приложении?

Я понимаю, что это теоретически возможно с внедрением зависимостей, поэтому я предположил, что что-то вроде этого будет работать:

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

Однако для DI требуется точное соответствие класса (присоединение к родительскому классу не сработает). Невозможно заранее узнать все имена контроллеров, особенно если большинство из них поступают от сторонних модулей.

Есть ли другой способ добиться этого?

РЕДАКТИРОВАТЬ: цель этого - динамически добавлять фильтры контроллера (которые представляют собой просто особый тип поведения). Поэтому прикрепление поведения во время EVENT_BEFORE_ACTION < / a> недостаточно, потому что оно запускается спустя долгое время после фильтрации запроса.

1
mae 11 Ноя 2020 в 15:36

2 ответа

Лучший ответ

Событие модуля (и приложения) beforeAction запускается до версии этого события для контроллера. Вы можете воспользоваться этим и использовать его для привязки поведения к текущему контроллеру.

Например, в вашей конфигурации web.php:

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

Конечно, недостатком является то, что поведение не привязано с самого начала.

ПРИМЕЧАНИЕ . Если ваша цель - прикрепить фильтр к каждому контроллеру, вы можете просто прикрепить его к самому приложению, а не к контроллерам.

1
Michal Hynčica 12 Ноя 2020 в 12:45

Надо сказать, интересная проблема. Я не мог найти для этого простого решения, но у меня есть эта хакерская идея. Вы можете воспользоваться автозагрузчиком Yii и загрузить свою версию yii\web\Controller вместо исходной.

Для этого:

  1. Скопируйте исходный файл от поставщика и поместите его в свое приложение.

  2. Не меняйте исходное пространство имен и имя.

  3. Добавьте свою конфигурацию поведения (или просто код поведения, что угодно) внутрь.

  4. Добавьте эту строку ниже в место, которое будет вызываться каждый раз при запуске приложения (например, файл точки входа или файл начальной загрузки, он должен вызываться после 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, чтобы сделать его актуальным.

0
Bizley 12 Ноя 2020 в 10:02