根据数据库结果设置 Yii2 catchAll 路由
Set Yii2 catchAll route depending on database result
<?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];
}
}
}
我试图从 CommonController init 方法中设置 catchAll 路由,但它抛出一个错误:
Creating default object from empty value
是否可以根据数据库提供的条件设置 catchAll 路由?
您需要在处理请求之前设置 catchAll 属性。 Init 方法是在resloving controller 之后执行的,所以不会有任何影响。您需要使用应用程序 onBeforeRequest 事件来设置 catchAll 路由。
在配置文件中设置如下:
$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' = [
....
]
];
您可以通过缓存 SiteSettings::find()->one(); 对此做一些改进。以避免为每个请求打开与数据库的连接。
更新:
我不确定 catchAll 是否可以用于特定模块,但您可以处理 onBeforeAction 事件并重定向到自定义路由。
'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']);
}
},
这是我的维护模式解决方案,仅适用于指定的 yii2 模块:
- 您必须创建一个普通操作,该操作将用作您需要维护模式的模块的任何控制器的维护模式操作
- 您需要为维护操作创建简单的视图布局和带有视图页面标记的文件
- 您需要在目标 yii2 的 beforeAction 方法中添加一些代码
模块
因此您的维护操作可以如下所示:
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');
}
您的 beforeAction
方法可以如下所示:
// 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;
}
我认为你可以将它用于多个 yii2 模块。
<?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];
}
}
}
我试图从 CommonController init 方法中设置 catchAll 路由,但它抛出一个错误:
Creating default object from empty value
是否可以根据数据库提供的条件设置 catchAll 路由?
您需要在处理请求之前设置 catchAll 属性。 Init 方法是在resloving controller 之后执行的,所以不会有任何影响。您需要使用应用程序 onBeforeRequest 事件来设置 catchAll 路由。
在配置文件中设置如下:
$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' = [
....
]
];
您可以通过缓存 SiteSettings::find()->one(); 对此做一些改进。以避免为每个请求打开与数据库的连接。
更新: 我不确定 catchAll 是否可以用于特定模块,但您可以处理 onBeforeAction 事件并重定向到自定义路由。
'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']);
}
},
这是我的维护模式解决方案,仅适用于指定的 yii2 模块:
- 您必须创建一个普通操作,该操作将用作您需要维护模式的模块的任何控制器的维护模式操作
- 您需要为维护操作创建简单的视图布局和带有视图页面标记的文件
- 您需要在目标 yii2 的 beforeAction 方法中添加一些代码 模块
因此您的维护操作可以如下所示:
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');
}
您的 beforeAction
方法可以如下所示:
// 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;
}
我认为你可以将它用于多个 yii2 模块。