October CMS 后端实现了模型-视图-控制器 (MVC) 模式。本文介绍了如何开发后端控制器以及如何配置控制器行为。
每个控制器都由一个 PHP 脚本表示,该脚本位于插件目录的 /控制器 子目录中。控制器视图是 .php 文件,它们驻留在控制器视图目录中。控制器视图目录名称与以小写形式编写的控制器类名匹配。视图目录还可以包含控制器配置文件。控制器目录结构示例:
├── plugins
| └── acme
| └── blog
| ├── controllers
| | ├── users ← 视图目录
| | | ├── config_form.yaml ← 配置文件
| | | ├── _partial.php ← 局部文件
| | | └── index.php ← 视图文件
| | └── Users.php ← 控制器类
| └── Plugin.php
:::tip
如需查看使用后端控制器的实际示例,请查阅Beyond Behaviors 教程系列。
:::
create:controller 命令会生成控制器、配置文件和视图文件。第一个参数指定作者和插件名称。第二个参数指定控制器类名称。
php artisan create:controller Acme.Blog Posts控制器类必须继承 Backend\Classes\Controller 类。与任何其他插件类一样,控制器应属于 插件命名空间。在插件中使用的控制器最基本的表示形式如下所示。
namespace Acme\Blog\Controllers;
class Posts extends \Backend\Classes\Controller
{
public function index() // ← Action method
{
}
}通常每个控制器都实现处理一种类型数据的功能 - 例如博客文章或分类。下面描述的所有后端行为都假定遵循此约定。
后端控制器基类定义了若干属性允许配置页面外观和管理页面安全:
| Property | Description |
|---|---|
| $fatalError | allows to store a fatal exception generated in an action method in order to display it in the view. |
| $user | contains a reference to the the backend user object. |
| $suppressView | allows to prevent the view display. Can be updated in the action method or in the controller constructor. |
| $params | an array of the routed parameters. |
| $action | a name of the action method being executed in the current request. |
| $publicActions | defines an array of actions available without the backend user authentication. Can be overridden in the class definition. |
| $requiredPermissions | permissions required to view this page. Can be set in the class definition or in the controller constructor. See users & permissions for details. |
| $pageTitle | sets the page title. Can be set in the action method. |
| $bodyClass | body class property used for customizing the layout. Can be set in the controller constructor or action method. |
| $guarded | controller specific methods which cannot be called as actions. Can be extended in the controller constructor. |
| $layout | specify a custom layout for the controller views. |
控制器可以在原生的 __construct 方法中执行初始化逻辑。
构造函数内部的逻辑不受保护,不应处理任何敏感逻辑。
public function __construct()
{
parent::__construct();
}beforeDisplay 方法在权限检查之后调用,大多数逻辑都应放在此处。这包括初始化小部件和其他共享组件。
public function beforeDisplay()
{
// Initialize widgets, handle file uploads, etc.
}公共控制器方法,称为操作,与视图文件耦合,这些视图文件代表与该操作对应的页面。后端视图文件使用 PHP 语法。以下是index.php视图文件的示例内容,对应于index操作方法。
<h1>Hello World</h1>本页面的 URL 由作者名、插件名、控制器名和操作名组成。
admin/[author name]/[plugin name]/[controller name]/[action name]例如,本文开头使用的类定义可通过以下 URL 访问。
https://example.tld/admin/acme/blog/users/index如果 插件已注册 并在 pluginDetails 方法中带有一个 提示,则会提供一个更短的 URL 结构,这对于在 URL 中隐藏作者名称很有用。
admin/[plugin hint]/[controller name]/[action name]使用控制器 $vars 属性将任何数据直接传递给您的视图:
$this->vars['myVariable'] = 'value';通过 $vars 属性传递的变量现在可以直接在你的视图中访问:
<p>The variable value is <?= $myVariable ?></p>插件可以在 插件注册文件 中注册后台导航菜单和子菜单。导航上下文决定了当前后台页面哪个后台菜单和子菜单处于活动状态。您可以使用 BackendMenu 类设置导航上下文:
BackendMenu::setContext('Acme.Blog', 'blog', 'categories');第一个参数指定作者和插件名称。第二个参数设置菜单代码。可选的第三个参数指定子菜单代码。通常,您在控制器构造函数中调用 BackendMenu::setContext。
namespace Acme\Blog\Controllers;
class Categories extends \Backend\Classes\Controller {
public function __construct()
{
parent::__construct();
BackendMenu::setContext('Acme.Blog', 'blog', 'categories');
}你可以使用控制器类的 $pageTitle 属性设置后端页面的标题(请注意,表单和列表行为可以为您完成此操作):
$this->pageTitle = 'Blog Categories';您可以在后端控制器中覆盖响应,作为修改 HTTP 请求响应的一种机制。例如,您可能希望为控制器中的某些操作指定 HTTP 标头,或者在用户不符合特定条件时重定向他们。
覆盖响应尤其在扩展其他控制器时很有用。然而你可能会发现在本地调用这些方法很有用。
\Author\Plugin\Controllers\SomeController::extend(function($controller) {
$controller->setResponseHeader('Test-Header', 'Test');
});如果您想检查路由的动作或参数,您可以在控制器的 getAction 和 getParams 方法中找到这些。
Author\Plugin\Controllers\SomeController::extend(function($controller) {
if ($controller->getAction() === 'index') {
// Only do it for the index action
}
if ($controller->getParams()[0] ?? null) {
// Only if first parameter exists
}
});为了给你的响应添加一个头,你可以调用 setResponseHeader 方法。
$this->setResponseHeader('Test-Header', 'Test');要更改响应的状态码,请使用 setStatusCode 方法。
$this->setStatusCode(404);要覆盖整个响应,请调用 setResponse 方法,这将强制响应,无论页面生命周期中发生什么。
$this->setResponse('Page Not Found');您也可以将一个 Response 对象传递给此方法。
$this->setResponse(Response::make(...));查看 视图与响应文章 以获取更多关于构建响应的信息。