Set Yii2 catchAll route depending on database resu

2020-07-27 03:00发布

问题:

<?php

namespace app\modules\site\controllers;

use Yii;
use yii\filters\AccessControl;
use yii\web\Controller;
use app\models\SiteSettings;

class CommonController extends Controller {

public function init() {
    Yii::$app->language = 'bg-BG';
    Yii::$app->formatter->locale = 'bg-BG';
    Yii::$app->params['siteSettings'] = SiteSettings::find()->one();

    if (Yii::$app->params['siteSettings']->in_maintenance == 1) {
        Yii:$app->catchAll = ['index/maintenance', 'message' => Yii::$app->params['siteSettings']->maintenance_message];
    }
}

}

I tried to set the catchAll route from within the CommonController init method, but it throws me an error:

Creating default object from empty value

Is it possible to set the catchAll route on condition provided from the database?

回答1:

You need to setup catchAll property just before request is handled. Init method is executed after resloving controller, so it won't have any effect. You need to use application onBeforeRequest event to setup up catchAll route.

In config file set following:

$config = [
    'id' => '...',
     ......

    'on beforeRequest' => function () {
        Yii::$app->params['siteSettings'] = SiteSettings::find()->one();            
        if (Yii::$app->params['siteSettings']->in_maintenance == 1) {
            Yii::$app->catchAll = [
              'index/maintenance', 
              'message' => Yii::$app->params['siteSettings']->maintenance_message
            ];
        }
    },
    ....
    'comonents' = [
        ....
    ]
];

You can add little improvement to this by caching SiteSettings::find()->one(); to avoid opening connection to database for every request.

Update: I am not sure if catchAll can be used for specific module, but you can handle onBeforeAction event and redirect to custom route.

'on beforeAction' => function ($event) {

    $actionId = $event->action->id;
    $controllerId = $event->action->controller->id;
    $moduleId = $event->action->controller->module->id;

    //TODO: Check module here
    if (!(($controllerId == "site") && ($actionId == "offline")))
    {
        return Yii::$app->response->redirect(['site/offline']);
    }
},


回答2:

Here is my solution for maintenance mode only for specified yii2 module(s):

  • you have to create an ordinary action which will be used as a maintenance mode action for any controller of the module which maintenance mode you need for
  • you need to create simple view layout and a file with view page markup for maintenance action
  • you need to add some code to beforeAction method of your target yii2 module

So your maintenance action can looks like this:

public function actionMaintenance()
{
    // Usually for maintenance mode websites use different simplified layout
    // than for normal pages (without any menus and other stuff)
    $this->layout = 'maintenance_layout';
    return $this->render('maintenance_page');
}

and your beforeAction method can looks like this:

// You can use beforeAction handler inside any yii2 module
public function beforeAction($action)
{
    // default handling of parent before action
    if(!parent::beforeAction($action)) {
        return false;
    }

    // Retrieving of maintenance setting from DB 
    // (of course, you can use smth. other)
    $onMaintenance = Settings::find()->where([
        'name' => 'maintainance_mode'
    ])->asArray()->one();

    // It the module have to be in maintenance mode according to our settings
    if($onMaintenance['value'] === 'on') {
        // and currently requested action is not our maintenance action
        // this is used to avoid infinite call loop 
        if($action->id != 'maintenance')
            // we redirect users to maintenance page
            \Yii::$app->response->redirect(['/frontend/site/maintenance']);
        else
            // and we allow an action to be executed if it is our maintenance action
            return true;
    }

        return true;
}

I think you can use this for several yii2 modules.



标签: php routes yii2