控制器和 AJAX
Introduction
Winter CMS 后端实现了 MVC 模式。控制器管理后端页面并实现各种功能,如表单和列表。本文介绍如何开发后端控制器以及如何配置控制器行为。
每个控制器都包含一个 PHP 文件,该文件位于/controllers 插件目录的子目录。控制器视图是.htm
驻留在控制器视图目录中的文件。控制器视图目录名称与小写的控制器类名称匹配。视图目录还可以包含控制器配置文件。控制器目录结构的示例:
📂 plugins
┗ 📂 acme
┗ 📂 blog
┣ 📂 controllers
┃ ┣ 📂 users <=== Controller view directory
┃ ┃ ┣ 📜 _partial.htm <=== Controller partial file
┃ ┃ ┣ 📜 config_form.yaml <=== Controller config file
┃ ┃ ┗ 📜 index.htm <=== Controller view file
┃ ┗ 📜 Users.php <=== Controller class
┗ 📜 Plugin.php
类定义
控制器类必须扩展\Backend\Classes\Controller
班级。与任何其他插件类一样,控制器应该属于插件命名空间.在插件中使用的控制器的最基本表示如下所示:
namespace Acme\Blog\Controllers;
class Posts extends \Backend\Classes\Controller {
public function index() // <=== Action method
{
}
}
通常每个控制器都实现处理单一类型数据的功能——比如博客文章或类别。下面描述的所有后端行为都采用此约定。
控制器属性
后端控制器基类定义了一些允许配置页面外观和管理页面安全性的属性:
Property | Description |
---|---|
$fatalError |
允许存储在操作方法中生成的致命异常,以便在视图中显示它。 |
$user |
包含对后端用户对象的引用。 |
$suppressView |
允许阻止视图显示。可以在操作方法或控制器构造函数中更新。 |
$params |
路由参数的数组。 |
$action |
当前请求中正在执行的操作方法的名称。 |
$publicActions |
定义了一组无需后端用户身份验证即可使用的操作。可以在类定义中被覆盖。 |
$requiredPermissions |
查看此页面所需的权限。可以在类定义或控制器构造函数中设置。看用户和权限 了解详情。 |
$pageTitle |
设置页面标题。可以在动作方法中设置。 |
$bodyClass |
用于自定义布局的 body 类属性。可以在控制器构造函数或操作方法中设置。 |
$guarded |
不能作为动作调用的控制器特定方法。可以在控制器构造函数中扩展。 |
$layout |
为控制器视图指定自定义布局(请参阅layouts 以下)。 |
动作、视图和路由
公共控制器方法,称为actions 耦合到查看文件 表示对应于操作的页面。后端视图文件使用 PHP 语法。的例子index.htm 查看文件内容,对应index 动作方法:
<h1>Hello World</h1>
该页面的 URL 由作者姓名、插件名称、控制器名称和操作名称组成。
backend/[author name]/[plugin name]/[controller name]/[action name]
上面的 Controller 结果如下:
https://example.com/backend/acme/blog/users/index
将数据传递给视图
使用控制器的$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';
使用 AJAX 处理程序
后端 AJAX 框架使用相同的AJAX 库 作为前端页面。该库会自动加载到后端页面上。
后端 AJAX 处理程序
后端 AJAX 处理程序可以在控制器类中定义或widgets.在控制器类中,AJAX 处理程序被定义为名称以“on”字符串开头的公共方法:onCreateTemplate,onGetTemplateList, ETC。
后端 AJAX 处理程序可以返回数据数组、抛出异常或重定向到另一个页面(请参阅AJAX 事件处理程序).您可以使用$this->vars
设置变量和控制器的makePartial
方法来呈现部分并将其内容作为响应数据的一部分返回。
public function onOpenTemplate()
{
if (Request::input('someVar') != 'someValue') {
throw new ApplicationException('Invalid value');
}
$this->vars['foo'] = 'bar';
return [
'partialContents' => $this->makePartial('some-partial')
];
}
触发 AJAX 请求
可以使用数据属性 API 或 JavaScript API 触发 AJAX 请求。请参阅前端 AJAX 库 了解详情。以下示例显示如何使用后端按钮触发请求。
<button
type="button"
data-request="onDoSomething"
class="btn btn-default">
Do something
</button>
NOTE:您可以使用前缀专门针对小部件的 AJAX 处理程序
widget::onName
.见小部件 AJAX 处理程序文章 更多细节。
控制器中间件
您可以在后端控制器中定义中间件,为您提供一种方便的机制来更改 HTTP 请求的响应。例如,您可能希望在控制器中为某些操作指定 HTTP 标头,或者在用户不符合某些条件时重定向用户。
控制器中间件在 Winter CMS 处理请求之后,但在将响应发送到浏览器之前执行。
要为您的控制器定义中间件,您可以在__construct()
通过调用后端控制器的方法middleware()
方法。
public function __construct()
{
parent::__construct();
$this->middleware(function ($request, $response) {
// Middleware functionality
});
}
这middleware()
方法需要一个带有两个参数的回调,$request
提供请求信息 和$response
提供响应对象.回调应该返回$response
反对您的修改。
例如,添加一个Test-Header
标题到您的回复,您可以执行以下操作:
public function __construct()
{
parent::__construct();
$this->middleware(function ($request, $response) {
$response->headers->set('Test-Header', 'Test');
return $response;
});
}
您还可以通过使用控制哪些操作将使用您的中间件only()
和except()
修饰符。例如,限制中间件只运行在index
操作,您可以执行以下操作:
public function __construct()
{
parent::__construct();
$this->middleware(function ($request, $response) {
// Middleware functionality
})->only('index');
}
或者,在除了index
行动:
public function __construct()
{
parent::__construct();
$this->middleware(function ($request, $response) {
// Middleware functionality
})->except('index');
}