FormHelper 承担了大部分表单创建的工作。FormHelper 侧重于快速创建表单,以简化验证、重新填充和布局。FormHelper 也很灵活,它可以通过约定为你做几乎所有事情,或者你可以使用特定的方法只获取你需要的部分。
$context
- 定义表单的上下文。可以是 ORM 实体、ORM 结果集、Form
实例、元数据数组或 null
(创建无模型表单)。
$options
- 选项和/或 HTML 属性的数组。
为了使用 FormHelper,你需要使用的方法是 create()
。此方法输出一个开头的表单标签。
所有参数都是可选的。如果 create()
被调用时没有提供参数,它假设你正在构建一个提交到当前控制器,通过当前 URL 的表单。表单提交的默认方法是 POST。如果你要在 UsersController::add()
的视图中调用 create()
,你会在渲染的视图中看到类似以下输出
<form method="post" action="/users/add">
$context
参数用作表单的“上下文”。有几个内置的表单上下文,你也可以添加自己的上下文,我们将在后面的部分中介绍。内置的提供者映射到 $context
的以下值
一个 Entity
实例或迭代器将映射到 EntityContext;这个上下文类允许 FormHelper 使用来自内置 ORM 的结果。
包含 'schema'
键的数组将映射到 ArrayContext,它允许你创建简单的 数据结构来构建表单。
null
将映射到 NullContext;这个上下文类只是满足 FormHelper 所需的接口。这个上下文在你想要构建一个不需要 ORM 持久化的简短表单时很有用。
一旦使用上下文创建了一个表单,你创建的所有控件都将使用活动上下文。在 ORM 支持的表单的情况下,FormHelper 可以访问关联数据、验证错误和架构元数据。你可以使用 end()
方法关闭活动上下文,或者再次调用 create()
。
要为实体创建表单,请执行以下操作
// If you are on /articles/add
// $article should be an empty Article entity.
echo $this->Form->create($article);
输出
<form method="post" action="/articles/add">
这将把表单数据 POST 到 ArticlesController 的 add()
操作。但是,你也可以使用相同的逻辑来创建编辑表单。FormHelper 使用 Entity
对象自动检测是否创建添加或编辑表单。如果提供的实体不是“新的”,则表单将被创建为编辑表单。
例如,如果我们浏览到 **http://example.org/articles/edit/5**,我们可以执行以下操作
// src/Controller/ArticlesController.php:
public function edit($id = null)
{
if (empty($id)) {
throw new NotFoundException;
}
$article = $this->Articles->get($id);
// Save logic goes here
$this->set('article', $article);
}
// View/Articles/edit.php:
// Since $article->isNew() is false, we will get an edit form
<?= $this->Form->create($article) ?>
输出
<form method="post" action="/articles/edit/5">
<input type="hidden" name="_method" value="PUT">
注意
由于这是一个编辑表单,因此生成了一个隐藏的 input
字段来覆盖默认的 HTTP 方法。
在某些情况下,实体的 ID 会自动附加到表单的 action
URL 的末尾。如果你想避免将 ID 添加到 URL,你可以向 $options['url']
传递一个字符串,例如 '/my-account'
或 \Cake\Routing\Router::url(['controller' => 'Users', 'action' => 'myAccount'])
。
$options
数组是大多数表单配置发生的地方。这个特殊的数组可以包含许多不同的键值对,它们会影响表单标签的生成方式。有效值
'type'
- 允许你选择要创建的表单类型。如果没有提供类型,它将根据表单上下文自动检测。有效值
'get'
- 将表单方法设置为 HTTP GET。
'file'
- 将表单方法设置为 POST,并将 'enctype'
设置为“multipart/form-data”。
'post'
- 将方法设置为 POST。
'put', 'delete', 'patch'
- 当提交表单时,将分别使用 PUT、DELETE 或 PATCH 覆盖 HTTP 方法。
'method'
- 有效值与上述相同。允许你显式覆盖表单的方法。
'url'
- 指定表单将提交到的 URL。可以是字符串或 URL 数组。
'encoding'
- 设置表单的 accept-charset
编码。默认为 Configure::read('App.encoding')
。
'enctype'
- 允许你显式设置表单编码。
'templates'
- 你想要为这个表单使用的模板。提供的任何模板都将合并到已加载的模板之上。可以是 /config
中的某个文件名(不含扩展名),也可以是 要使用的模板数组。
'context'
- 表单上下文类的额外选项。(例如,EntityContext
接受一个 'table'
选项,它允许你设置表单应该基于的特定 Table 类。)
'idPrefix'
- 为生成的 ID 属性添加的前缀。
'templateVars'
- 允许您为 formStart
模板提供模板变量。
autoSetCustomValidity
- 设置为 true
以在控件的 HTML5 有效性消息中使用自定义的必需和非空验证消息。默认值为 true
。
提示
除了上述选项外,您还可以使用 $options
参数提供任何您想要传递给创建的 form
元素的有效 HTML 属性。
FormHelper 的值源定义了其渲染的元素(例如输入标签)从何处获取其值。
支持的源是 context
、data
和 query
。您可以通过设置 valueSources
选项或使用 setValuesSource()
来使用一个或多个源。由 FormHelper
生成的任何小部件将从源中收集其值,按照您设置的顺序。
默认情况下,FormHelper
从 data
或 context
获取其值,即它将从 $request->getData()
中获取数据,或者如果不存在,则从活动上下文的 data 中获取数据,在 EntityContext
的情况下,这些数据是实体的数据。
但是,如果您正在构建一个需要从查询字符串中读取数据的表单,您可以更改 FormHelper
读取输入数据的位置
// Use query string instead of request data:
echo $this->Form->create($article, [
'type' => 'get',
'valueSources' => ['query', 'context'],
]);
// Same effect:
echo $this->Form
->setValueSources(['query', 'context'])
->create($articles, ['type' => 'get']);
当输入数据需要由实体处理,即编组转换、表查询结果或实体计算,并在一次或多次表单提交后(其中保留请求数据)显示时,您需要将 context
放在首位
// Prioritize context over request data:
echo $this->Form->create($article,
'valueSources' => ['context', 'data'],
]);
当调用 end()
时,值源将重置为默认值 ['data', 'context']
。
使用 type
选项,您可以更改表单将使用的 HTTP 方法
echo $this->Form->create($article, ['type' => 'get']);
输出
<form method="get" action="/articles/edit/5">
为 type
指定一个 'file'
值,将表单提交方法更改为 'post',并在表单标签中包含一个 enctype
为 “multipart/form-data”。如果表单中有任何文件元素,则应使用此方法。缺少正确的 enctype
属性会导致文件上传无法正常工作。
例如
echo $this->Form->create($article, ['type' => 'file']);
输出
<form enctype="multipart/form-data" method="post" action="/articles/add">
当使用 'put'
、'patch'
或 'delete'
作为 'type'
值时,您的表单在功能上将等效于 'post' 表单,但在提交时,HTTP 请求方法将被覆盖为 'PUT'、'PATCH' 或 'DELETE'。这允许 CakePHP 在 Web 浏览器中模拟正确的 REST 支持。
使用 'url'
选项,您可以将表单指向当前控制器中的特定操作或应用程序中的另一个控制器。
例如,如果您想将表单指向当前控制器的 publish()
操作,您需要提供一个 $options
数组,如下所示
echo $this->Form->create($article, ['url' => ['action' => 'publish']]);
输出
<form method="post" action="/articles/publish">
如果所需的表单操作不在当前控制器中,您可以为表单操作指定一个完整的 URL。提供的 URL 可以是相对于您的 CakePHP 应用程序的
echo $this->Form->create(null, [
'url' => [
'controller' => 'Articles',
'action' => 'publish',
],
]);
输出
<form method="post" action="/articles/publish">
或者,您可以指向一个外部域
echo $this->Form->create(null, [
'url' => 'https://www.google.com/search',
'type' => 'get',
]);
输出
<form method="get" action="https://www.google.com/search">
如果您不想将 URL 作为表单操作输出,请使用 'url' => false
。
模型通常会包含多个验证器集合,您可以让 FormHelper 根据控制器操作将要应用的特定验证器来标记字段是否必需。例如,您的 Users 表包含仅在注册帐户时才适用的特定验证规则
echo $this->Form->create($user, [
'context' => ['validator' => 'register'],
]);
上面的代码将使用在 register
验证器中定义的验证规则,这些规则由 UsersTable::validationRegister()
为 $user
和所有相关关联定义,来对 $user
进行验证。如果您正在为关联实体创建表单,您可以使用数组为每个关联定义验证规则
echo $this->Form->create($user, [
'context' => [
'validator' => [
'Users' => 'register',
'Comments' => 'default',
],
],
]);
上面的代码将对用户使用 register
,对用户的评论使用 default
。FormHelper 使用验证器来生成 HTML5 必需属性、相关的 ARIA 属性,并使用 浏览器验证器 API 设置错误消息。如果您想禁用 HTML5 验证消息,请使用
$this->Form->setConfig('autoSetCustomValidity', false);
这不会禁用 required
/aria-required
属性。
虽然内置的上下文类旨在涵盖您会遇到的基本情况,但如果您使用的是其他 ORM,您可能需要构建一个新的上下文类。在这种情况下,您需要实现 Cake\View\Form\ContextInterface。实现此接口后,您可以将新的上下文连接到 FormHelper。通常最好在 View.beforeRender
事件侦听器或应用程序视图类中执行此操作
$this->Form->addContextProvider('myprovider', function ($request, $data) {
if ($data['entity'] instanceof MyOrmClass) {
return new MyProvider($data);
}
});
上下文工厂函数是您可以添加逻辑的地方,用于检查表单选项以确定正确的实体类型。如果找到匹配的输入数据,您可以返回一个对象。如果没有匹配项,则返回 null。
$fieldName
- 表单中的字段名称,格式为 'Modelname.fieldname'
。
$options
- 一个可选数组,可以包含 控件特定选项、其他方法的选项(control()
在内部使用这些选项来生成各种 HTML 元素)以及任何有效的 HTML 属性。
control()
方法允许您生成完整的表单控件。这些控件将包含一个包装的 div
、label
、控件小部件以及必要的验证错误。通过使用表单上下文中的元数据,此方法将为每个字段选择适当的控件类型。在内部,control()
使用 FormHelper 的其他方法。
提示
请注意,虽然由 control()
方法生成的字段在此页面上被通用地称为“输入”,但从技术上讲,control()
方法不仅可以生成所有 HTML input
类型元素,还可以生成其他 HTML 表单元素,例如 select
、button
、textarea
。
默认情况下,control()
方法将使用以下小部件模板
'inputContainer' => '<div class="input {{type}}{{required}}">{{content}}</div>'
'input' => '<input type="{{type}}" name="{{name}}"{{attrs}}>'
'requiredClass' => 'required'
在出现验证错误的情况下,它还会使用
'inputContainerError' => '<div class="input {{type}}{{required}} error">{{content}}{{error}}</div>'
创建的控件类型(当我们不提供任何其他选项来指定生成的元素类型时)是通过模型自省推断的,并且取决于列数据类型
生成的表单字段
text
checkbox
number
number
number
textarea
password
tel
date
datetime-local
datetime-local
time
month
带有年份的 select
file
$options
参数允许您在需要时选择特定的控件类型
echo $this->Form->control('published', ['type' => 'checkbox']);
提示
需要注意的是,通过 control()
表单方法生成特定的元素,通常也会生成包装的 div
。通过其中一个特定的表单方法生成相同类型的元素(例如 $this->Form->checkbox('published');
)在大多数情况下不会生成包装的 div
。您可以根据自己的需要使用其中一个或另一个。
如果模型字段的验证规则指示该字段是必需的并且不允许为空,则包装的 div
将追加一个 required
类名。您可以使用 'required'
选项禁用自动 required
标记
echo $this->Form->control('title', ['required' => false]);
要跳过对整个表单的浏览器验证触发,您可以为使用Cake\View\Helper\FormHelper::submit()
生成的输入按钮设置选项'formnovalidate' => true
,或者在Cake\View\Helper\FormHelper::create()
的选项中设置'novalidate' => true
。
例如,假设您的 Users 模型包含以下字段:username(varchar)、password(varchar)、approved(datetime)和 quote(text)。您可以使用 FormHelper 的 control()
方法为所有这些表单字段创建相应的控件。
echo $this->Form->create($user);
// The following generates a Text input
echo $this->Form->control('username');
// The following generates a Password input
echo $this->Form->control('password');
// Assuming 'approved' is a datetime or timestamp field the following
//generates an input of type "datetime-local"
echo $this->Form->control('approved');
// The following generates a Textarea element
echo $this->Form->control('quote');
echo $this->Form->button('Add');
echo $this->Form->end();
一个更全面的示例,展示了日期字段的一些选项。
echo $this->Form->control('birth_date', [
'label' => 'Date of birth',
'min' => date('Y') - 70,
'max' => date('Y') - 18,
]);
除了特定于控件的选项之外,您还可以指定所选(或由 CakePHP 推断)控件类型接受的任何选项,以及任何 HTML 属性(例如 onfocus
)。
如果您想在使用 belongsTo(或 hasOne)关系时创建一个 select
表单字段,您可以将以下内容添加到您的 UsersController(假设您的 User belongsTo Group)。
$this->set('groups', $this->Users->Groups->find('list')->all());
然后,将以下内容添加到您的视图模板中。
echo $this->Form->control('group_id', ['options' => $groups]);
要为 belongsToMany Groups 关联创建一个 select
框,您可以将以下内容添加到您的 UsersController 中。
$this->set('groups', $this->Users->Groups->find('list')->all());
然后,将以下内容添加到您的视图模板中。
echo $this->Form->control('groups._ids', ['options' => $groups]);
如果您的模型名称包含两个或更多个单词(例如“UserGroups”),当使用 set()
传递数据时,您应该以复数形式和小驼峰式格式命名您的数据,如下所示。
$this->set('userGroups', $this->UserGroups->find('list')->all());
注意
您不应该使用 FormHelper::control()
生成提交按钮。请改用Cake\View\Helper\FormHelper::submit()
。
创建控件小部件时,您应该根据表单实体中匹配的属性来命名您的字段。例如,如果您为一个 $article
实体创建了一个表单,您将创建以属性命名的字段。例如 title
、body
和 published
。
您可以通过将 association.fieldname
作为第一个参数传递来创建关联模型或任意模型的控件。
echo $this->Form->control('association.fieldname');
您的字段名称中的任何点都会转换为嵌套的请求数据。例如,如果您创建了一个名为 0.comments.body
的字段,您将获得一个看起来像 0[comments][body]
的名称属性。此约定与您在 ORM 中使用的约定相匹配。各种关联类型的详细信息可以在创建关联数据的输入部分找到。
创建与日期时间相关的控件时,FormHelper 将追加一个字段后缀。您可能会注意到名为 year
、month
、day
、hour
、minute
或 meridian
的其他字段被添加。当实体被封送时,这些字段将被自动转换为 DateTime
对象。
FormHelper::control()
通过其 $options
参数支持大量选项。除了它自己的选项之外,control()
接受为推断/选择的生成控件类型(例如,对于 checkbox
或 textarea
)的选项,以及 HTML 属性。本小节将介绍特定于 FormHelper::control()
的选项。
$options['type']
- 指定要生成的控件类型的字符串。除了在创建表单控件中找到的字段类型之外,您还可以创建 'file'
、'password'
和 HTML5 支持的任何其他类型。通过指定 'type'
,您将强制生成控件的类型,从而覆盖模型自省。默认为 null
。
例如
echo $this->Form->control('field', ['type' => 'file']);
echo $this->Form->control('email', ['type' => 'email']);
输出
<div class="input file">
<label for="field">Field</label>
<input type="file" name="field" value="" id="field">
</div>
<div class="input email">
<label for="email">Email</label>
<input type="email" name="email" value="" id="email">
</div>
$options['label']
- 可以是字符串标题或标签选项的数组。您可以将此键设置为要在通常伴随着 input
HTML 元素的标签中显示的字符串。默认为 null
。
例如
echo $this->Form->control('name', [
'label' => 'The User Alias'
]);
输出
<div class="input">
<label for="name">The User Alias</label>
<input name="name" type="text" value="" id="name">
</div>
或者,将此键设置为 false
以禁用 label
元素的生成。
例如
echo $this->Form->control('name', ['label' => false]);
输出
<div class="input">
<input name="name" type="text" value="" id="name">
</div>
如果标签被禁用,并且提供了 placeholder
属性,生成的输入将设置 aria-label
。
将 label
选项设置为数组以提供 label
元素的额外选项。如果您这样做,您可以使用数组中的 'text'
键来自定义标签文本。
例如
echo $this->Form->control('name', [
'label' => [
'class' => 'thingy',
'text' => 'The User Alias'
]
]);
输出
<div class="input">
<label for="name" class="thingy">The User Alias</label>
<input name="name" type="text" value="" id="name">
</div>
$options['options']
- 您可以在此处提供一个数组,其中包含要为诸如 radio
或 select
之类的控件生成的元素,这些控件需要一个包含项目数组的参数(有关更多详细信息,请参见创建单选按钮和创建选择器)。默认为 null
。
$options['error']
- 使用此键可以覆盖默认的模型错误消息,并且可以使用它来设置 i18n 消息,例如。要禁用错误消息输出和字段类,请将 'error'
键设置为 false
。默认为 null
。
例如
echo $this->Form->control('name', ['error' => false]);
要覆盖模型错误消息,请使用一个数组,其键与原始验证错误消息匹配。
例如
$this->Form->control('name', [
'error' => ['Not long enough' => __('This is not long enough')]
]);
如上所示,您可以为模型中的每个验证规则设置错误消息。此外,您可以为表单提供 i18n 消息。
要仅对错误消息禁用 HTML 实体编码,可以使用 'escape'
子键。
$this->Form->control('name', [
'error' => ['escape' => false],
]);
$options['nestedInput']
- 与复选框和单选按钮一起使用。控制输入元素是在 label
元素内部还是外部生成。当 control()
生成复选框或单选按钮时,您可以将其设置为 false
以强制在 label
元素之外生成 HTML input
元素。
另一方面,您可以将其设置为 true
以强制在标签内生成任何控件类型的输入元素。如果您更改了单选按钮的设置,那么您还需要修改默认的radioWrapper 模板。根据生成的控件类型,它默认为 true
或 false
。
$options['templates']
- 您想要为此输入使用的模板。任何指定的模板都将在已加载的模板之上进行合并。此选项可以是 /config
中包含您想要加载的模板的文件名(不含扩展名),也可以是模板数组。
$options['labelOptions']
- 将其设置为 false
以禁用嵌套小部件周围的标签,或将其设置为要提供给 label
标签的属性数组。
$options['readonly']
- 将字段设置为表单中的 readonly
。
例如
echo $this->Form->control('name', ['readonly' => true]);
除了通用 control()
方法之外,FormHelper
还具有用于生成多种不同类型控件的特定方法。这些方法可以用来生成控件小部件本身,并与其他方法(如 Cake\View\Helper\FormHelper::label()
和 Cake\View\Helper\FormHelper::error()
)结合使用,以生成完全自定义的表单布局。
许多不同的控件元素方法支持一组通用的选项,这些选项根据使用的方法,必须在 $options
还是在 $attributes
数组参数中提供。所有这些选项也受 control()
方法支持。为了减少重复,所有控件方法共享的通用选项如下所示。
'id'
- 将此键设置为强制控件的 DOM id 的值。这将覆盖可能设置的 'idPrefix'
。
'default'
- 用于为控件字段设置默认值。如果传递给表单的数据不包含该字段的值(或根本没有传递数据),则使用该值。如果没有提供默认值,将使用该列的默认值。
使用示例。
echo $this->Form->text('ingredient', ['default' => 'Sugar']);
使用 select
字段的示例(“Medium”尺寸将被选中为默认值)。
$sizes = ['s' => 'Small', 'm' => 'Medium', 'l' => 'Large'];
echo $this->Form->select('size', $sizes, ['default' => 'm']);
注意
您不能使用 default
来选中复选框 - 相反,您可以在控制器中的 $this->request->getData()
中设置值,或者将控制选项 'checked'
设置为 true
。
注意使用 false
来分配默认值。一个 false
值用于禁用/排除控制字段的选项,因此 'default' => false
不会设置任何值。 相反,使用 'default' => 0
。
'value'
- 用于为控制字段设置特定值。这将覆盖从上下文注入的任何值,例如 Form、Entity 或 request->getData()
等。
注意
如果您想将字段设置为不渲染从上下文或 valuesSource 获取的值,您需要将 'value'
设置为 ''
(而不是将其设置为 null
)。
除了以上选项之外,您可以混合任何您希望使用的 HTML 属性。任何非特殊选项名称将被视为 HTML 属性,并应用于生成的 HTML 控制元素。
FormHelper 中可用的其他方法用于创建特定的表单元素。这些方法中的许多也使用一个特殊的 $options
或 $attributes
参数。但是,在这种情况下,此参数主要用于指定 HTML 标签属性(例如表单中元素的值或 DOM id)。
$name
- 表单中的字段名称,格式为 'Modelname.fieldname'
。
$options
- 一个可选数组,包括任何 特定控制的通用选项 以及任何有效的 HTML 属性。
创建一个简单的 input
HTML 元素,类型为 text
。
例如
echo $this->Form->text('username', ['class' => 'users']);
将输出
<input name="username" type="text" class="users">
$fieldName
- 表单中的字段名称,格式为 'Modelname.fieldname'
。
$options
- 一个可选数组,包括任何 特定控制的通用选项 以及任何有效的 HTML 属性。
创建一个简单的 input
元素,类型为 password
。
例如
echo $this->Form->password('password');
将输出
<input name="password" value="" type="password">
$fieldName
- 表单中的字段名称,格式为 'Modelname.fieldname'
。
$options
- 一个可选数组,包括任何 特定控制的通用选项、特定文本区域选项(见下文)以及任何有效的 HTML 属性。
创建一个文本区域控制字段。使用的默认小部件模板是
'textarea' => '<textarea name="{{name}}"{{attrs}}>{{value}}</textarea>'
例如
echo $this->Form->textarea('notes');
将输出
<textarea name="notes"></textarea>
如果表单正在被编辑(即数组 $this->request->getData()
包含之前为 User
实体保存的信息),则与 notes
字段对应的值将自动添加到生成的 HTML 中。
示例
<textarea name="notes" id="notes">
This text is to be edited.
</textarea>
文本区域选项
除了 特定控制的通用选项 之外,textarea()
还支持一些特定的选项
'escape'
- 确定是否应该转义文本区域的内容。默认值为 true
。
例如
echo $this->Form->textarea('notes', ['escape' => false]);
// OR....
echo $this->Form->control('notes', ['type' => 'textarea', 'escape' => false]);
'rows', 'cols'
- 您可以使用这两个键来设置指定 textarea
字段的行数和列数的 HTML 属性。
例如
echo $this->Form->textarea('comment', ['rows' => '5', 'cols' => '5']);
输出
<textarea name="comment" cols="5" rows="5">
</textarea>
这些控件有一些共性,以及一些选项,因此,为了便于参考,它们都在本小节中进行了分组。
您可以在下面找到 select()
、checkbox()
和 radio()
共享的选项(仅对其中一种方法特定的选项在每种方法的各自部分中描述)。
'value'
- 设置或选择受影响元素的值
对于复选框,它将分配给 input
元素的 HTML 'value'
属性设置为您提供的任何值。
对于单选按钮或选择选择器,它定义了在渲染表单时将选择哪个元素(在这种情况下,'value'
必须分配一个有效的现有元素值)。也可以与任何选择类型控件结合使用,例如 date()
、time()
、dateTime()
echo $this->Form->time('close_time', [
'value' => '13:30:00',
]);
注意
'value'
键用于 date()
和 dateTime()
控制的也可能具有 UNIX 时间戳或 DateTime 对象的值。
对于 select
控制,您将 'multiple'
属性设置为 true
,您可以提供一个数组,其中包含您要默认选择的值
// HTML <option> elements with values 1 and 3 will be rendered preselected
echo $this->Form->select(
'rooms',
[1, 2, 3, 4, 5],
[
'multiple' => true,
'value' => [1, 3]
]
);
'empty'
- 应用于 radio()
和 select()
。默认值为 false
。
当传递给 radio()
并设置为 true
时,它将创建一个额外的输入元素作为第一个单选按钮,其值为 ''
,标签标题等于字符串 'empty'
。如果您想控制标签标题,请将此选项设置为字符串。
当传递给 select
方法时,这将在下拉列表中创建一个空的 HTML option
元素,其值为 ''
。如果您想有一个带有显示文本的空值,而不是一个简单的空 option
,请将字符串传递给 'empty'
echo $this->Form->select(
'field',
[1, 2, 3, 4, 5],
['empty' => '(choose one)']
);
输出
<select name="field">
<option value="">(choose one)</option>
<option value="0">1</option>
<option value="1">2</option>
<option value="2">3</option>
<option value="3">4</option>
<option value="4">5</option>
</select>
'hiddenField'
- 对于复选框和单选按钮,默认情况下,还会创建一个隐藏的 input
元素,以及主元素,因此即使没有指定值,$this->request->getData()
中的键也将存在。对于复选框,其值默认为 0
,对于单选按钮,其值默认为 ''
。
默认输出示例
<input type="hidden" name="published" value="0">
<input type="checkbox" name="published" value="1">
可以通过将 'hiddenField'
设置为 false
来禁用它
echo $this->Form->checkbox('published', ['hiddenField' => false]);
它输出
<input type="checkbox" name="published" value="1">
如果您想在表单上创建多个控制块,这些块都分组在一起,您应该在除第一个控制之外的所有控制上将此参数设置为 false
。如果隐藏输入在页面上出现多次,则只保存最后一组 inputs
的值。
在此示例中,只有第三种颜色会被传递,而主要颜色会被覆盖
<h2>Primary Colors</h2>
<input type="hidden" name="color" value="0">
<label for="color-red">
<input type="checkbox" name="color[]" value="5" id="color-red">
Red
</label>
<label for="color-blue">
<input type="checkbox" name="color[]" value="5" id="color-blue">
Blue
</label>
<label for="color-yellow">
<input type="checkbox" name="color[]" value="5" id="color-yellow">
Yellow
</label>
<h2>Tertiary Colors</h2>
<input type="hidden" name="color" value="0">
<label for="color-green">
<input type="checkbox" name="color[]" value="5" id="color-green">
Green
</label>
<label for="color-purple">
<input type="checkbox" name="color[]" value="5" id="color-purple">
Purple
</label>
<label for="color-orange">
<input type="checkbox" name="color[]" value="5" id="color-orange">
Orange
</label>
在第二个控制组上禁用 'hiddenField'
将阻止这种行为。
您可以将隐藏字段设置为除 0 之外的值,例如 'N'
echo $this->Form->checkbox('published', [
'value' => 'Y',
'hiddenField' => 'N',
]);
可以使用 Collection 类来构建选项数组。如果您已经有一个实体集合并且想要从中构建一个选择元素,这种方法是理想的。
您可以使用 combine
方法来构建一个基本的选项数组。
$options = $examples->combine('id', 'name');
还可以通过扩展数组添加额外的属性。以下示例将使用 map
集合方法在选项元素上创建数据属性。
$options = $examples->map(function ($value, $key) {
return [
'value' => $value->id,
'text' => $value->name,
'data-created' => $value->created
];
});
$fieldName
- 表单中的字段名称,格式为 'Modelname.fieldname'
。
$options
- 一个可选的数组,包含任何 特定控件的通用选项 或 Select、Checkbox 和 Radio 控件的选项、复选框特定选项(见下文),以及任何有效的 HTML 属性。
创建一个 checkbox
表单元素。使用的窗口小部件模板为
'checkbox' => '<input type="checkbox" name="{{name}}" value="{{value}}"{{attrs}}>'
复选框选项
'checked'
- 布尔值,指示是否选中此复选框。默认为 false
。
'disabled'
- 创建一个禁用的复选框输入。
此方法还生成一个关联的隐藏表单 input
元素,以强制提交指定字段的数据。
例如
echo $this->Form->checkbox('done');
将输出
<input type="hidden" name="done" value="0">
<input type="checkbox" name="done" value="1">
可以使用 $options
数组指定复选框的值。
例如
echo $this->Form->checkbox('done', ['value' => 555]);
将输出
<input type="hidden" name="done" value="0">
<input type="checkbox" name="done" value="555">
如果不想让 FormHelper 创建隐藏输入,请使用 'hiddenField'
。
例如
echo $this->Form->checkbox('done', ['hiddenField' => false]);
将输出
<input type="checkbox" name="done" value="1">
$fieldName
- 表单中的字段名 'fieldname'
或 'related_entity.fieldname'
。这将提供 select
元素的 name
属性。
$options
- 一个可选的数组,包含选择器项目的列表。如果此数组不存在,该方法将仅生成一个空的 select
HTML 元素,其中不包含任何 option
元素。
$attributes
- 一个可选的数组,包含任何 特定控件的通用选项 或 Select、Checkbox 和 Radio 控件的选项 或选择器特定属性(见下文),以及任何有效的 HTML 属性。
创建一个 select
元素,使用 $options
数组中的项目进行填充。如果提供了 $attributes['value']
,则在渲染选择器时,将显示具有指定值(s) 的 HTML option
元素(s) 作为选中状态。
默认情况下,select
使用以下窗口小部件模板
'select' => '<select name="{{name}}"{{attrs}}>{{content}}</select>'
'option' => '<option value="{{value}}"{{attrs}}>{{text}}</option>'
也可以使用
'optgroup' => '<optgroup label="{{label}}"{{attrs}}>{{content}}</optgroup>'
'selectMultiple' => '<select name="{{name}}[]" multiple="multiple"{{attrs}}>{{content}}</select>'
选择器属性
'multiple'
- 如果设置为 true
,则允许在选择器中进行多选。如果设置为 'checkbox'
,则将创建多个复选框。默认为 null
。
'escape'
- 布尔值。如果为 true
,则选择器内的 option
元素的内容将进行 HTML 实体编码。默认为 true
。
'val'
- 允许在选择器中预选一个值。
'disabled'
- 控制 disabled
属性。如果设置为 true
,则禁用整个选择器。如果设置为数组,则将仅禁用数组中提供值的那些特定 option
元素。
$options
参数允许手动指定 select
控件的 option
元素的内容。
例如
echo $this->Form->select('field', [1, 2, 3, 4, 5]);
输出
<select name="field">
<option value="0">1</option>
<option value="1">2</option>
<option value="2">3</option>
<option value="3">4</option>
<option value="4">5</option>
</select>
$options
的数组也可以作为键值对提供。
例如
echo $this->Form->select('field', [
'Value 1' => 'Label 1',
'Value 2' => 'Label 2',
'Value 3' => 'Label 3'
]);
输出
<select name="field">
<option value="Value 1">Label 1</option>
<option value="Value 2">Label 2</option>
<option value="Value 3">Label 3</option>
</select>
如果要生成一个带有选项组的 select
,只需以分层格式(嵌套数组)传递数据即可。这在多个复选框和单选按钮上也有效,但它不会使用 optgroup
,而是将元素包装在 fieldset
元素中。
例如
$options = [
'Group 1' => [
'Value 1' => 'Label 1',
'Value 2' => 'Label 2',
],
'Group 2' => [
'Value 3' => 'Label 3',
],
];
echo $this->Form->select('field', $options);
输出
<select name="field">
<optgroup label="Group 1">
<option value="Value 1">Label 1</option>
<option value="Value 2">Label 2</option>
</optgroup>
<optgroup label="Group 2">
<option value="Value 3">Label 3</option>
</optgroup>
</select>
要在 option
标签中生成 HTML 属性
$options = [
['text' => 'Description 1', 'value' => 'value 1', 'attr_name' => 'attr_value 1'],
['text' => 'Description 2', 'value' => 'value 2', 'attr_name' => 'attr_value 2'],
['text' => 'Description 3', 'value' => 'value 3', 'other_attr_name' => 'other_attr_value'],
];
echo $this->Form->select('field', $options);
输出
<select name="field">
<option value="value 1" attr_name="attr_value 1">Description 1</option>
<option value="value 2" attr_name="attr_value 2">Description 2</option>
<option value="value 3" other_attr_name="other_attr_value">Description 3</option>
</select>
通过属性控制选择器
通过在 $attributes
参数中使用特定选项,可以控制 select()
方法的某些行为。
'empty'
- 将 $attributes
参数中的 'empty'
键设置为 true
(默认值为 false
)以在下拉列表的顶部添加一个空白选项,其值为“”。
例如
$options = ['M' => 'Male', 'F' => 'Female'];
echo $this->Form->select('gender', $options, ['empty' => true]);
将输出
<select name="gender">
<option value=""></option>
<option value="M">Male</option>
<option value="F">Female</option>
</select>
'escape'
- select()
方法允许使用名为 'escape'
的属性,该属性接受一个布尔值,并确定是否对 select
的 option
元素的内容进行 HTML 实体编码。
例如
// This will prevent HTML-encoding the contents of each option element
$options = ['M' => 'Male', 'F' => 'Female'];
echo $this->Form->select('gender', $options, ['escape' => false]);
'multiple'
- 如果设置为 true
,则选择器将允许多选。
例如
echo $this->Form->select('field', $options, ['multiple' => true]);
或者,将 'multiple'
设置为 'checkbox'
以输出一组相关复选框
$options = [
'Value 1' => 'Label 1',
'Value 2' => 'Label 2'
];
echo $this->Form->select('field', $options, [
'multiple' => 'checkbox'
]);
输出
<input name="field" value="" type="hidden">
<div class="checkbox">
<label for="field-1">
<input name="field[]" value="Value 1" id="field-1" type="checkbox">
Label 1
</label>
</div>
<div class="checkbox">
<label for="field-2">
<input name="field[]" value="Value 2" id="field-2" type="checkbox">
Label 2
</label>
</div>
'disabled'
- 此选项可以用于禁用所有或部分 select
的 option
项。要禁用所有项目,请将 'disabled'
设置为 true
。要仅禁用某些项目,请将 'disabled'
分配给包含要禁用的项目的键的数组。
例如
$options = [
'M' => 'Masculine',
'F' => 'Feminine',
'N' => 'Neuter'
];
echo $this->Form->select('gender', $options, [
'disabled' => ['M', 'N']
]);
将输出
<select name="gender">
<option value="M" disabled="disabled">Masculine</option>
<option value="F">Feminine</option>
<option value="N" disabled="disabled">Neuter</option>
</select>
此选项在 'multiple'
设置为 'checkbox'
时也有效。
$options = [
'Value 1' => 'Label 1',
'Value 2' => 'Label 2'
];
echo $this->Form->select('field', $options, [
'multiple' => 'checkbox',
'disabled' => ['Value 1']
]);
输出
<input name="field" value="" type="hidden">
<div class="checkbox">
<label for="field-1">
<input name="field[]" disabled="disabled" value="Value 1" type="checkbox">
Label 1
</label>
</div>
<div class="checkbox">
<label for="field-2">
<input name="field[]" value="Value 2" id="field-2" type="checkbox">
Label 2
</label>
</div>
$fieldName
- 表单中的字段名称,格式为 'Modelname.fieldname'
。
$options
- 一个可选数组,包括任何 特定控制的通用选项 以及任何有效的 HTML 属性。
在表单中创建一个文件上传字段。默认使用的窗口模板是
'file' => '<input type="file" name="{{name}}"{{attrs}}>'
要向表单添加文件上传字段,首先必须确保表单的 enctype 设置为 'multipart/form-data'
。
因此,从以下 create()
方法开始
echo $this->Form->create($document, ['enctype' => 'multipart/form-data']);
// OR
echo $this->Form->create($document, ['type' => 'file']);
接下来,将类似于以下两行中的任何一行添加到表单的视图模板文件
echo $this->Form->control('submittedfile', [
'type' => 'file'
]);
// OR
echo $this->Form->file('submittedfile');
注意
由于 HTML 本身的限制,不可能将默认值放入类型为“file”的输入字段中。每次显示表单时,里面的值都将为空。
为了防止 submittedfile
被覆盖为空白,请将其从 $_accessible
中删除。或者,您可以使用 beforeMarshal
取消设置索引。
public function beforeMarshal(\Cake\Event\EventInterface $event, \ArrayObject $data, \ArrayObject $options)
{
if ($data['submittedfile'] === '') {
unset($data['submittedfile']);
}
}
提交后,可以通过请求上的 UploadedFileInterface
对象访问文件字段。要将上传的文件移动到永久位置,可以使用
$fileobject = $this->request->getData('submittedfile');
$destination = UPLOAD_DIRECTORY . $fileobject->getClientFilename();
// Existing files with the same name will be replaced.
$fileobject->moveTo($destination);
注意
使用 $this->Form->file()
时,请记住通过在 $this->Form->create()
中将 'type'
选项设置为 'file'
来设置表单编码类型。
$fieldName
- 表单中的字段名称,格式为 'Modelname.fieldname'
。
$text
- 可选。提供标签标题文本的字符串。
$options
- 可选。包含任何 特定控件的通用选项以及任何有效 HTML 属性的数组。
创建一个 label
元素。参数 $fieldName
用于生成元素的 HTML for
属性;如果 $text
未定义,则 $fieldName
也将用于对标签的 text
属性进行词形变换。
例如
echo $this->Form->label('name');
echo $this->Form->label('name', 'Your username');
输出
<label for="name">Name</label>
<label for="name">Your username</label>
使用第三个参数 $options
,您可以设置 id 或类。
echo $this->Form->label('name', null, ['id' => 'user-label']);
echo $this->Form->label('name', 'Your username', ['class' => 'highlight']);
输出
<label for="name" id="user-label">Name</label>
<label for="name" class="highlight">Your username</label>
FormHelper 公开了几个方法,这些方法允许我们轻松地检查字段错误,并在必要时显示自定义错误消息。
$fieldName
- 表单中的字段名称,格式为 'Modelname.fieldname'
。
$text
- 可选。提供错误消息的字符串或数组。如果为数组,则它应该是键名称 => 消息的哈希。默认为 null
。
$options
- 可选数组,只能包含一个布尔值,其键为 'escape'
,它将定义是否对错误消息的内容进行 HTML 转义。默认为 true
。
显示给定字段的验证错误消息(由 $text
指定),如果发生了验证错误。如果没有提供 $text
,则将使用该字段的默认验证错误消息。
使用以下模板窗口
'error' => '<div class="error-message">{{content}}</div>'
'errorList' => '<ul>{{content}}</ul>'
'errorItem' => '<li>{{text}}</li>'
'errorList'
和 'errorItem'
模板用于格式化每个字段的多个错误消息。
示例
// If in TicketsTable you have a 'notEmpty' validation rule:
public function validationDefault(Validator $validator): Validator
{
$validator
->requirePresence('ticket', 'create')
->notEmpty('ticket');
}
// And inside templates/Tickets/add.php you have:
echo $this->Form->text('ticket');
if ($this->Form->isFieldError('ticket')) {
echo $this->Form->error('ticket', 'Completely custom error message!');
}
如果您在不为“Ticket”字段提供值的情况下单击表单的“Submit”按钮,则您的表单将输出
<input name="ticket" class="form-error" required="required" value="" type="text">
<div class="error-message">Completely custom error message!</div>
注意
使用 Cake\View\Helper\FormHelper::control()
时,错误默认情况下会呈现,因此您无需使用 isFieldError()
或手动调用 error()
。
提示
如果您使用某个模型字段通过 control()
生成多个表单字段,并且您希望为每个字段显示相同的验证错误消息,那么您最好在相应的 验证器规则 中定义自定义错误消息。
$fieldName
- 表单中的字段名称,格式为 'Modelname.fieldname'
。
如果提供的 $fieldName
具有活动验证错误,则返回 true
,否则返回 false
。
示例
if ($this->Form->isFieldError('gender')) {
echo $this->Form->error('gender');
}
如果 autoSetCustomValidity
FormHelper 选项设置为 true
,则该字段的 required 和 notBlank 验证规则的错误消息将用于替代默认的浏览器 HTML5 required 消息。启用该选项将向您的字段添加 onvalid
和 oninvalid
事件属性,例如
<input type="text" name="field" required onvalid="this.setCustomValidity('')" oninvalid="this.setCustomValidity('Custom notBlank message')">
如果您想使用自定义 JavaScript 手动设置这些事件,可以将 autoSetCustomValidity
选项设置为 false
,并使用特殊的 customValidityMessage
模板变量。当字段是必填字段时,会添加此模板变量
// example template
[
'input' => '<input type="{{type}}" name="{{name}}" data-error-message="{{customValidityMessage}}" {{attrs}}/>',
]
// would create an input like this
<input type="text" name="field" required data-error-message="Custom notBlank message" />
然后,您可以使用 JavaScript 按照您的意愿设置 onvalid
和 oninvalid
事件。
$secureAttributes
- 可选。允许您提供安全的属性,这些属性将作为 HTML 属性传递到为 FormProtectionComponent 生成的隐藏输入元素中。
end()
方法关闭并完成表单。通常,end()
只会输出一个关闭的表单标签,但是使用 end()
是一个好习惯,因为它使 FormHelper 能够插入 Cake\Controller\Component\FormProtectionComponent
所需的隐藏表单元素
<?= $this->Form->create(); ?>
<!-- Form elements go here -->
<?= $this->Form->end(); ?>
如果您需要向生成的隐藏输入添加其他属性,可以使用 $secureAttributes
参数。
例如
echo $this->Form->end(['data-type' => 'hidden']);
将输出
<div style="display:none;">
<input type="hidden" name="_Token[fields]" data-type="hidden"
value="2981c38990f3f6ba935e6561dc77277966fabd6d%3AAddresses.id">
<input type="hidden" name="_Token[unlocked]" data-type="hidden"
value="address%7Cfirst_name">
</div>
注意
如果您在应用程序中使用 Cake\Controller\Component\SecurityComponent
,您应该始终使用 end()
结束您的表单。
与 CakePHP 中的许多助手一样,FormHelper 使用字符串模板来格式化它创建的 HTML。虽然默认模板旨在成为一组合理的默认值,但您可能需要自定义模板以适应您的应用程序。
要更改加载助手时的模板,您可以在控制器中包含助手时设置 'templates'
选项
// In a View class
$this->loadHelper('Form', [
'templates' => 'app_form',
]);
这将加载在 config/app_form.php 中找到的标签。此文件应包含一个模板数组,按名称索引
// in config/app_form.php
return [
'inputContainer' => '<div class="form-control">{{content}}</div>',
];
您定义的任何模板都将替换助手中包含的默认模板。未替换的模板将继续使用默认值。
您也可以使用 setTemplates()
方法在运行时更改模板
$myTemplates = [
'inputContainer' => '<div class="form-control">{{content}}</div>',
];
$this->Form->setTemplates($myTemplates);
警告
包含百分号 (%
) 的模板字符串需要特别注意;您应该在该字符前面加上另一个百分号,使其看起来像 %%
。原因是模板在内部被编译以与 sprintf()
一起使用。示例:'<div style="width:{{size}}%%">{{content}}</div>'
可以在 FormHelper API 文档 中找到默认模板列表、它们的默认格式以及它们期望的变量。
除了这些模板之外,control()
方法还将尝试为每个控件容器使用不同的模板。例如,在创建日期时间控件时,如果存在 datetimeContainer
,则将使用它。如果该容器不存在,则将使用 inputContainer
模板。
例如
// Add custom radio wrapping HTML
$this->Form->setTemplates([
'radioContainer' => '<div class="form-radio">{{content}}</div>'
]);
// Create a radio set with our custom wrapping div.
echo $this->Form->control('email_notifications', [
'options' => ['y', 'n'],
'type' => 'radio'
]);
与控制容器类似,control()
方法还将尝试为每个表单组使用不同的模板。表单组是标签和控件的组合。例如,在创建单选按钮控件时,如果存在 radioFormGroup
,则将使用它。如果该模板不存在,默认情况下,每组 label
& input
将使用默认的 formGroup
模板呈现。
例如
// Add custom radio form group
$this->Form->setTemplates([
'radioFormGroup' => '<div class="radio">{{label}}{{input}}</div>'
]);
您可以在自定义模板中添加其他模板占位符,并在生成控件时填充这些占位符。
例如
// Add a template with the help placeholder.
$this->Form->setTemplates([
'inputContainer' => '<div class="input {{type}}{{required}}">
{{content}} <span class="help">{{help}}</span></div>'
]);
// Generate an input and populate the help variable
echo $this->Form->control('password', [
'templateVars' => ['help' => 'At least 8 characters long.'],
]);
输出
<div class="input password">
<label for="password">
Password
</label>
<input name="password" id="password" type="password">
<span class="help">At least 8 characters long.</span>
</div>
默认情况下,CakePHP 将通过 control()
创建的复选框和通过 control()
和 radio()
创建的单选按钮嵌套在标签元素中。这有助于更轻松地集成流行的 CSS 框架。如果您需要将复选框/单选按钮输入放置在标签之外,您可以通过修改模板来实现
$this->Form->setTemplates([
'nestingLabel' => '{{hidden}}{{input}}<label{{attrs}}>{{text}}</label>',
'formGroup' => '{{input}}{{label}}',
]);
这将使单选按钮和复选框在它们的标签之外呈现。
$fields
- 要生成的字段数组。允许为每个指定的字段设置自定义类型、标签和其他选项。
$options
- 可选。一个选项数组。有效的键是
'fieldset'
- 将其设置为 false
以禁用字段集。如果为空,则字段集将被启用。也可以是将作为 HTML 属性应用于 fieldset
标签的参数数组。
legend
- 用于自定义 legend
文本的字符串。将其设置为 false
以禁用为生成的输入集生成的图例。
生成针对给定上下文的一组控件,并将其包装在 fieldset
中。您可以通过将它们包含在内来指定生成的字段
echo $this->Form->controls([
'name',
'email'
]);
您可以使用一个选项来自定义图例文本
echo $this->Form->controls($fields, ['legend' => 'Update news post']);
您可以通过在 $fields
参数中定义其他选项来自定义生成的控件
echo $this->Form->controls([
'name' => ['label' => 'custom label'],
]);
在自定义 $fields
时,您可以使用 $options
参数来控制生成的图例/字段集。
例如
echo $this->Form->controls(
[
'name' => ['label' => 'custom label'],
],
[
'legend' => 'Update your post',
]
);
如果你禁用 fieldset
,legend
不会被打印。
$fields
- 可选。要生成的字段的自定义数组。允许设置自定义类型、标签和其他选项。
$options
- 可选。一个选项数组。有效的键是
'fieldset'
- 将其设置为 false
以禁用 fieldset。如果为空,则 fieldset 将被启用。也可以是应用为 fieldset
标签的 HTML 属性的数组参数。
legend
- 用于自定义 legend
文本的字符串。将其设置为 false
以禁用为生成的控件集创建的 legend。
此方法与 controls()
密切相关,但是 $fields
参数默认为当前顶级实体中的所有字段。要从生成的控件中排除特定字段,请在 $fields
参数中将其设置为 false
echo $this->Form->allControls(['password' => false]);
为关联数据创建表单非常简单,并且与实体数据中的路径密切相关。假设以下表关系
Authors HasOne Profiles
Authors HasMany Articles
Articles HasMany Comments
Articles BelongsTo Authors
Articles BelongsToMany Tags
如果我们要编辑包含关联数据的文章,我们可以创建以下控件
$this->Form->create($article);
// Article controls.
echo $this->Form->control('title');
// Author controls (belongsTo)
echo $this->Form->control('author.id');
echo $this->Form->control('author.first_name');
echo $this->Form->control('author.last_name');
// Author profile (belongsTo + hasOne)
echo $this->Form->control('author.profile.id');
echo $this->Form->control('author.profile.username');
// Tags controls (belongsToMany)
// as separate inputs
echo $this->Form->control('tags.0.id');
echo $this->Form->control('tags.0.name');
echo $this->Form->control('tags.1.id');
echo $this->Form->control('tags.1.name');
// Inputs for the joint table (articles_tags)
echo $this->Form->control('tags.0._joinData.starred');
echo $this->Form->control('tags.1._joinData.starred');
// Comments controls (hasMany)
echo $this->Form->control('comments.0.id');
echo $this->Form->control('comments.0.comment');
echo $this->Form->control('comments.1.id');
echo $this->Form->control('comments.1.comment');
然后,可以使用控制器中的以下代码将上述控件编组到完成的实体图中
$article = $this->Articles->patchEntity($article, $this->request->getData(), [
'associated' => [
'Authors',
'Authors.Profiles',
'Tags',
'Comments',
],
]);
以上示例显示了多对多关联的扩展示例,其中每个实体和联接数据记录都有单独的输入。您还可以为多对多关联创建多个选择输入
// Multiple select element for belongsToMany
// Does not support _joinData
echo $this->Form->control('tags._ids', [
'type' => 'select',
'multiple' => true,
'options' => $tags, // $tags is the output of $this->Articles->Tags->find('list')->all() in the controller
]);
您可以在 CakePHP 中添加自定义控件小部件,并像使用其他任何控件类型一样使用它们。所有核心控件类型都作为小部件实现,这意味着您可以用自己的实现覆盖任何核心小部件。
小部件类有一个非常简单的必需接口。它们必须实现 Cake\View\Widget\WidgetInterface
。此接口要求实现 render(array $data)
和 secureFields(array $data)
方法。 render()
方法期望一个用于构建小部件的数据数组,并期望返回小部件的 HTML 字符串。 secureFields()
方法也期望一个数据数组,并期望返回包含此小部件要保护的字段列表的数组。如果 CakePHP 正在构建您的小部件,您可以期望获取一个 Cake\View\StringTemplate
实例作为第一个参数,然后是您定义的任何依赖项。如果我们想构建一个自动完成小部件,我们可以执行以下操作
namespace App\View\Widget;
use Cake\View\Form\ContextInterface;
use Cake\View\StringTemplate;
use Cake\View\Widget\WidgetInterface;
class AutocompleteWidget implements WidgetInterface
{
/**
* StringTemplate instance.
*
* @var \Cake\View\StringTemplate
*/
protected $_templates;
/**
* Constructor.
*
* @param \Cake\View\StringTemplate $templates Templates list.
*/
public function __construct(StringTemplate $templates)
{
$this->_templates = $templates;
}
/**
* Methods that render the widget.
*
* @param array $data The data to build an input with.
* @param \Cake\View\Form\ContextInterface $context The current form context.
*
* @return string
*/
public function render(array $data, ContextInterface $context): string
{
$data += [
'name' => '',
];
return $this->_templates->format('autocomplete', [
'name' => $data['name'],
'attrs' => $this->_templates->formatAttributes($data, ['name'])
]);
}
public function secureFields(array $data): array
{
return [$data['name']];
}
}
显然,这是一个非常简单的示例,但它演示了如何构建自定义小部件。此小部件将呈现“自动完成”字符串模板,例如
$this->Form->setTemplates([
'autocomplete' => '<input type="autocomplete" name="{{name}}" {{attrs}} />'
]);
有关字符串模板的更多信息,请参阅 自定义 FormHelper 使用的模板。
您可以在加载 FormHelper 时或使用 addWidget()
方法加载自定义小部件。加载 FormHelper 时,小部件被定义为设置
// In View class
$this->loadHelper('Form', [
'widgets' => [
'autocomplete' => ['Autocomplete'],
],
]);
如果您的窗口小部件需要其他窗口小部件,您可以通过声明它们让 FormHelper 填充这些依赖项
$this->loadHelper('Form', [
'widgets' => [
'autocomplete' => [
'App\View\Widget\AutocompleteWidget',
'text',
'label',
],
],
]);
在上面的示例中,autocomplete
小部件将依赖于 text
和 label
小部件。如果您的窗口小部件需要访问视图,您应该使用 _view
“窗口小部件”。创建 autocomplete
小部件时,将传递与 text
和 label
名称相关的窗口小部件对象。要使用 addWidget()
方法添加窗口小部件,操作如下
// Using a classname.
$this->Form->addWidget(
'autocomplete',
['Autocomplete', 'text', 'label']
);
// Using an instance - requires you to resolve dependencies.
$autocomplete = new AutocompleteWidget(
$this->Form->getTemplater(),
$this->Form->getWidgetLocator()->get('text'),
$this->Form->getWidgetLocator()->get('label'),
);
$this->Form->addWidget('autocomplete', $autocomplete);
添加/替换后,可以使用控件“类型”使用窗口小部件
echo $this->Form->control('search', ['type' => 'autocomplete']);
这将创建具有 label
和包装 div
的自定义窗口小部件,就像 controls()
一样。或者,您可以使用魔术方法仅创建控件窗口小部件
echo $this->Form->autocomplete('search', $options);
Cake\Controller\Component\SecurityComponent
提供了一些功能,使您的表单更安全。只需在控制器中包含 SecurityComponent
,您将自动从表单篡改防御功能中获益。
如前所述,使用 SecurityComponent 时,您应该始终使用 Cake\View\Helper\FormHelper::end()
关闭表单。这将确保生成特殊 _Token
输入。
$name
- 可选。字段的点分隔名称。
解锁字段,使其免受 SecurityComponent
字段哈希的影响。这也允许字段被 JavaScript 操作。 $name
参数应该是字段的实体属性名称
$this->Form->unlockField('id');
$fields
- 可选。包含用于生成哈希的字段列表的数组。如果未提供,则将使用 $this->fields
。
$secureAttributes
- 可选。要传递到为 SecurityComponent 生成的隐藏输入元素中的 HTML 属性数组。
生成一个基于表单中使用的字段的隐藏 input
字段,或者在不使用安全表单时生成一个空字符串。如果设置了 $secureAttributes
,这些 HTML 属性将合并到为 SecurityComponent 生成的隐藏输入标签中。这对于设置像 'form'
这样的 HTML5 属性特别有用。