Я пытаюсь выполнить некоторый код внутри контроллера Yii2
как мне нужен какой-то код из модели, чтобы быть доступным в разделе behaviors
чтобы я мог передать модель в качестве параметра и не запускать повторяющиеся запросы; однако мне также нужно выяснить, какое action
вызывается, но мне не очень повезло.
Я пробовал использовать beforeAction
но кажется, что это запускается ПОСЛЕ выполнения кода behaviours
, так что это не помогает мне.
Затем я попытался использовать init
, но, похоже, action
не доступно через $this->action->id
в этой точке.
Пример кода:
class MyController extends Controller { public $defaultAction = 'view'; public function init() { // $this->action not available in here } public function beforeAction() { // This is of no use as this runs *after* the 'behaviors' method } public function behaviors() { return [ 'access' => [ 'class' => NewAccessControl::className(), 'only' => ['view','example1','example2'], 'rules' => [ [ 'allow' => false, 'authManager' => [ 'model' => $this->model, 'other_param' => $foo, 'other_param' => $bar, ], 'actions' => ['view'], ], // everything else is denied ], ], ]; } public function viewAction() { // This is how it is currently instantiated, but we want to instantiate *before* the behavior code is run so we don't need to instantiate it twice // but to be able to do that we need to know the action so we can pass in the correct scenario $model = new exampleModel(['scenario' => 'view']); } }
authManager
– это просто ссылка на member variable
внутри расширения класса AccessRule
.
В любом случае я могу это сделать?
Хорошо, если я получу вас правильно, вы ищете что-то вроде этого:
public function behaviors() { $model = MyModel::find()->someQuery(); $action = Yii::$app->controller->action->id; return [ 'someBehavior' => [ 'class' => 'behavior/namespace/class', 'callback' => function() use ($model, $action) { //some logic here } ] ]; }
Поскольку behaviors()
– это всего лишь метод, вы можете объявлять любые переменные и добавлять любую логику, которая вам нужна, единственное соглашение, которое вы должны следовать, – это то, что возвращаемый тип должен быть массивом .
Если вы используете свое обычное поведение, вы можете использовать метод events()
где вы можете привязать методы вашего поведения к определенным событиям. Например
class MyBehavior extends Behavior { public function events() { return [ \yii\web\User::EVENT_AFTER_LOGIN => 'myAfterLoginEvent', ]; } public function myAfterLoginEvent($event) { //dealing with event } }
В этом примере myAfterLoginEvent
будет выполнен после успешного входа пользователя в приложение. переменная $event
будет передана каркасом и в зависимости от типа события будет содержать разные данные. Читайте о объекте события
ОБНОВИТЬ:
Как я теперь вижу, мой ответ был более общим по поводу событий и поведения. И теперь, когда вы добавили код, я могу предложить вам переопределить beforeAction($action)
поведения beforeAction($action)
с помощью следующего кода:
public function beforeAction($action) { $actionID = $action->id; /* @var $rule AccessRule */ foreach ($this->rules as &$rule) { $model = &$rule->authManager['model']; //now set model scenario maybe like this $model->scenario = $actionID; } //now call parent implementation parent::beforeAction($action); }
Также взгляните на реализацию beforeAction
метода beforeAction
, который он вызывает для каждого правила, allows
метод с передачей текущего действия ему в качестве параметра. Поэтому, если у вас есть класс, который расширяет AccessRule , вы можете либо переопределить метод ($ action, $ user, $ request), либо метод matchCustom($action)
для установки соответствующего модельного сценария. Надеюсь, это поможет.
Еще одна альтернатива:
переопределить runAction($id, $params = [])
контроллера runAction($id, $params = [])
. Здесь $ id – actionID – именно то, что вам нужно. Проверьте идентификатор, установите соответствующий сценарий модели и вызовите parent::runAction($id, $params);