34

I would like to check if my user have filled certain fields in his profile before he can access any action of any controller. For example

if(empty(field1) && empty(field2))
{
   header("Location:/site/error")
}

In yii1 I could do it in protected\components\Controller.php in init() function But in yii2 I'm not sure where to put my code. I cannot modify core files, but not sure what to do in backend of my advanced application to make it work.

I know I can user beforeAction() but I have too many controllers to do that and to keep track of every controller

Misko Mali
  • 587
  • 1
  • 6
  • 17

5 Answers5

54

In case you need to execute a code before every controller and action, you can do like below:

1 - Add a component into your components directory, for example(MyGlobalClass):

namespace app\components;
class MyGlobalClass extends \yii\base\Component{
    public function init() {
        echo "Hi";
        parent::init();
    }
}

2 - Add MyGlobalClass component into your components array in config file:

'components' => [
    'MyGlobalClass'=>[
        'class'=>'app\components\MyGlobalClass'
     ],
     //other components

3 - Add MyGlobalClass into bootstarp array in config file:

'bootstrap' => ['log','MyGlobalClass'],

Now, you can see Hi before every action.

Please note that, if you do not need to use Events and Behaviors you can use \yii\base\Object instead of \yii\base\Component

Ali MasudianPour
  • 13,704
  • 3
  • 57
  • 61
  • @MiskoMali Do you use modules? – Ali MasudianPour Nov 27 '14 at 23:49
  • Another thing, do you need to interact with forms? or you need to just execute some code before every controller's action? in case of forms, if you use a model, you can use `beforeValidate()` – Ali MasudianPour Nov 27 '14 at 23:50
  • 1
    @MiskoMali Well, if you use module, you can write your code in `init()` method which will be executed before each controller of that module – Ali MasudianPour Nov 27 '14 at 23:51
  • I just need to execute some code before every action, not related to any forms or database. I'm using modules in vendor folder, not in backend folder. In backend folder I'm using only Controller and Models – Misko Mali Nov 27 '14 at 23:54
  • I will have to try this myself :), I have no idea how it would work as I do not see a tie between your MyGlobalClass and a controller. Should you not make MyGlobalClass be used instead of \yii\base\Component ? – Mihai P. Nov 28 '14 at 00:35
  • 1
    @MihaiP. No dear, This is just a class (component, object, event or behavior) which will be initiated in application bootstrap. As soon as application runs, this class's `init()` method will be called. – Ali MasudianPour Nov 28 '14 at 00:45
  • You are right, I did not think about it that way :). – Mihai P. Nov 28 '14 at 00:48
  • To be honest what he wants to accomplish is rather crazy, he will not be able to login because he will not have access to any controller / action. – Mihai P. Nov 28 '14 at 00:57
  • i have tried this, i am making a restful application and i need all responses to return as json format (for now for some reason all responses are in xml), i just execute a command to change the response format, but it doesn't work – Oscar Reyes Nov 11 '15 at 02:19
  • Also works if your class extends BaseObject. I have this working in backend of Advanced template, to ensure date_default_timezone_set runs for all actions in all controllers. In the frontend, .htaccess causes everything to go through actionIndex, so it was easier there. – Rich Harding Apr 19 '18 at 14:03
28

Just add in config file into $config array:

    'on beforeAction' => function ($event) {
           echo "Hello";
    },
Ruslan Novikov
  • 856
  • 12
  • 18
24

Create a new controller

namespace backend\components;
class Controller extends \yii\web\Controller {
    public function beforeAction($event)
    {
        ..............
        return parent::beforeAction($event);
    }
}

All your controllers should now extend backend\components\Controller and not \yii\web\Controller. with this, you should modify every controller. I would go for this solution.

I believe you might also replace 1 class with another (so no change to any controller necessary), something like

\Yii::$classMap = array_merge(\Yii::$classMap,[
                '\yii\web\Controller'=>'backend\components\Controller',
            ]);

See more details here: http://www.yiiframework.com/doc-2.0/guide-tutorial-yii-integration.html and I took the code from here: https://github.com/mithun12000/adminUI/blob/master/src/AdminUiBootstrap.php

you can put this in your index.php file. However, make sure you document this change very well as somebody that will come and try to debug your code will be totally confused by this.

SenG
  • 643
  • 1
  • 6
  • 14
Mihai P.
  • 9,324
  • 3
  • 33
  • 47
3

Just i think this code on config file can help you:

'on beforeAction' => function ($event) {
      // To log all request information
},
'components' => [
    'response' => [
        'on beforeSend' => function($event) {
            // To log all response information
        },
    ],
];
Sajjad Dehghani
  • 592
  • 5
  • 15
0

Or, https://github.com/yiisoft/yii2/blob/master/docs/guide/security-authorization.md use RBAC, to restrict access to controllers actions one at a time based on rules. Why would you want to restrict access to controller actions based on user fields is beyond me. You will not be able to access anything (including the login form) if you put a restriction there.

Mihai P.
  • 9,324
  • 3
  • 33
  • 47