Getting a controller action before the behavior code runs in Yii2

I am trying to execute some code inside the Yii2 controller, since I need some code from the model to access the behaviors section, so that I can pass the model as a parameter and not run repeated requests; however, I also need to find out what is called action , but I was not very lucky.

I tried using beforeAction , but it seems to run AFTER the behaviours code runs, so that doesn't help me.

Then I tried to use init , but it seems that action not available through $this->action->id at this point.

Code example:

 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 is simply a reference to a member variable inside an AccessRule class AccessRule .

Anyway, can I do this?

+6
source share
1 answer

Well, if I get you right, you are looking for something like this:

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

Since behaviors() is just a method, you can declare any variables and add any logic you want, the only convention you have to follow is that the return type must be an array.

If you use your behavior, you can use the events() method, where you can bind your behavior methods to specific events. For instance.

 class MyBehavior extends Behavior { public function events() { return [ \yii\web\User::EVENT_AFTER_LOGIN => 'myAfterLoginEvent', ]; } public function myAfterLoginEvent($event) { //dealing with event } } 

In this example, myAfterLoginEvent will be executed after the user successfully logs into the application. $event variable will be passed by the framework and depending on the type of event it will contain different data. Read about the event object

UPDATE:

As I now see, my answer was more general regarding events and behavior. And now that you have added the code, I can suggest you to redefine the beforeAction($action) behavior method with the following code:

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

Also look at the AccessControl method of the beforeAction method , it calls the allows method for each rule, passing it the current action as a parameter. Therefore, if you have a class that extends AccessRule, you can either override the method ($ action, $ user, $ request) or matchCustom($action) to set the appropriate model script. Hope this helps.

Another alternative:

override runAction($id, $params = []) controller runAction($id, $params = []) . Here $ id - actionID is exactly what you need. Check the identifier, install the appropriate model script and call parent::runAction($id, $params);

+9
source

Source: https://habr.com/ru/post/990027/


All Articles