你可以通过定义一个字段定义文件并将其注册到你的插件注册文件中来创建自己的内容字段。
内容字段定义类位于插件的contentfields目录中。内部目录名与小写形式的部件类名匹配。内容字段可以提供资产和分部视图。示例目录结构如下所示。
├── contentfields
| ├── mycontentfield
| | ├── assets
| | └── partials
| | └── _column_content.php ← 分部文件
| └── MyContentField.php ← 字段类
create:contentfield 命令生成一个内容字段类。第一个参数指定作者和插件名称。第二个参数指定内容字段类名称。
php artisan create:contentfield Acme.Blog MyContentField内容字段类必须扩展 Backend\Classes\FormWidgetBase 类。
注册的内容字段可以在 Tailor 表单字段 和蓝图中使用。 该类定义了字段应如何与系统的其余部分交互。 例如,plugins/acme/blog/contentfields/MyContentField.php 具有以下内容。
namespace Acme\Blog\ContentFields;
use Tailor\Classes\ContentFieldBase;
use October\Contracts\Element\FormElement;
use October\Contracts\Element\ListElement;
use October\Contracts\Element\FilterElement;
class MyContentField extends ContentFieldBase
{
public function defineConfig(array $config) {}
public function defineFormField(FormElement $form, $context = null) {}
public function defineListColumn(ListElement $list, $context = null) {}
public function defineFilterScope(FilterElement $filter, $context = null) {}
public function extendModelObject($model) {}
public function extendDatabaseTable($table) {}
}插件应通过重写 registerContentFields 方法在 插件注册文件 中注册内容字段. 该方法返回一个数组,其中包含以 widget 类作为键,以 widget 短代码作为值. 示例:
public function registerContentFields()
{
return [
\Acme\Blog\ContentFields\MyContentField::class => 'mycontentfield'
];
}该短代码用于在蓝图模板中引用字段时使用,它应该是一个唯一值,以避免与其他表单字段冲突。
假设我们要包含一个名为 secondaryTitle 的字段配置项,它首先在类上定义为一个属性,然后使用 defineConfig 覆盖方法进行填充。
class MyContentField extends ContentFieldBase
{
public $secondaryTitle;
public function defineConfig(array $config)
{
if (isset($config['secondaryTitle'])) {
$this->secondaryTitle = $config['secondaryTitle'];
}
}
}这便变得可用:
my_field:
type: mycontentfield
secondaryTitle: Custom value goes here内容字段可以定义它在后端面板中如何作为表单字段、列表列和筛选范围显示。在每种情况下,生成的对象都是一个流畅的配置对象,它支持方法链或通过 useConfig 方法传入的数组。参见定义内容字段文章了解更多信息。
defineFormField 方法定义了一个内容字段在表单中应如何显示。每个字段都由 addFormField 方法初始化,该方法接收字段名称和要向用户显示的标签。
public function defineFormField(FormElement $form, $context = null)
{
$form->addFormField($this->fieldName, $this->label)->useConfig($this->config);
}defineListColumn 方法定义了内容字段在列表中应如何显示。每个列都由 defineListColumn 方法定义,该方法接收字段名以及要向用户显示的标签。
public function defineListColumn(ListElement $list, $context = null)
{
$list->defineColumn($this->fieldName, $this->label)->displayAs('switch');
}defineFilterScope 方法定义了一个内容字段应如何在筛选器中显示。每个作用域都由 defineScope 方法发起,该方法接受字段名称和标签以展示给用户。
public function defineFilterScope(FilterElement $filter, $context = null)
{
$filter->defineScope($this->fieldName, $this->label)->displayAs('switch');
}extendModelObject 方法允许内容字段扩展记录模型,例如 Tailor\Models\EntryRecord 模型类。一个例子可能是使用 addJsonable 方法使该字段可 JSON 化。
public function extendModelObject($model)
{
$model->addJsonable($this->fieldName);
}另一种方法可能是指定一个 belongsTo 关系。
public function extendModelObject($model)
{
$model->belongsTo[$this->fieldName] = MyOtherModel::class;
}extendDatabaseTable 用于指定此字段所需的数据库列。它使用 标准迁移结构 的简化版本。
public function extendDatabaseTable($table)
{
$table->mediumText($this->fieldName)->nullable();
}下面是一个为 October Test 插件创建内容字段的完整示例。它添加了一个 mycontentfield 类型,该类型可用于所有蓝图,如下面的示例所示。
fields:
mycontentfield:
label: Custom Content Field
type: mycontentfield
firstColor: red
secondColor: blue该字段在文件 plugins/october/test/Plugin.php 内通过 registerContentFields 方法注册。
public function registerContentFields()
{
return [
\October\Test\ContentFields\MyContentField::class => 'mycontentfield'
];
}字段类在文件 plugins/october/test/contentfields/MyContentField.php 中作为一个 PHP 类创建。它将自身注册为 局部字段类型,为求简洁,不包含列表列或筛选范围。addJsonable 方法调用确保字段名是 可 JSON 属性,这样它就可以作为数组存储。数据库列存储为 mediumText 数据库 schema 类型,并带有 nullable 修饰符,允许空值。
namespace October\Test\ContentFields;
use Tailor\Classes\ContentFieldBase;
use October\Contracts\Element\FormElement;
class MyContentField extends ContentFieldBase
{
public function defineFormField(FormElement $form, $context = null)
{
$form->addFormField($this->fieldName, $this->label)
->useConfig($this->config)
->displayAs('partial')
->path('$/october/test/contentfields/mycontentfield/partials/_field.php');
}
public function extendModelObject($model)
{
$model->addJsonable($this->fieldName);
}
public function extendDatabaseTable($table)
{
$table->mediumText($this->fieldName)->nullable();
}
}文件 **plugins/october/test/contentfields/mycontentfield/partials/_field.php** 包含用于渲染表单字段的部分内容。这些值被检索并保存为一个数组 [first_value => 'foo', second_value => 'bar']。
<div class="row">
<div class="col">
<input
type="text"
name="<?= $field->getName() ?>[first_value]"
value="<?= e($field->value['first_value'] ?? '') ?>"
class="form-control"
style="color:<?= $field->firstColor ?: 'red' ?>"
/>
</div>
<div class="col">
<input
type="text"
name="<?= $field->getName() ?>[second_value]"
value="<?= e($field->value['second_value'] ?? '') ?>"
class="form-control"
style="color:<?= $field->secondColor ?: 'blue' ?>"
/>
</div>
</div>一个常见的问题是关于表单微件和内容字段之间的区别,以及哪种在何种情况下更好? 表单微件 是由 Backend\Widgets\Form 微件专属使用的表单字段,以及原生的 表单字段类型 (文本、数字、下拉列表、局部、等等)
内容字段是专供 Tailor 使用的表单字段的超集,并更进一步,还包括该字段如何:
如果一个表单部件在定义时没有内容字段,它仍然可以在 Tailor 中默认使用,并将解析为 Tailor\ContentFields\FallbackField 内容字段类型,该类型是基础的,并将在数据库中注册为 TEXT 列类型。
对于健壮的解决方案,最好同时定义表单部件和内容字段。这使得该字段可以用于插件和Tailor 蓝图中的内容。下面链接到一个可在任何地方使用的货币字段示例。
你可能会注意到在内容字段中 YAML 定义是在 PHP 中定义的。YAML 语法到 PHP 语法相当简单,其中 PHP 方法名就是 YAML 属性名且值作为第一个参数传递——默认值为 true。唯一的主要区别是 type 属性由 displayAs 方法定义。
任何方法名都可以被调用,并链式地作用于 PHP 对象。请参见下表,了解一些 YAML 到 PHP 的转换示例。
| YAML | PHP |
|---|---|
autoFocus: true | ->autoFocus() |
label: my field | ->label('my field') |
type: partial | ->displayAs('partial') |
您也可以将所有所需的 YAML 配置作为数组传递,使用
->useConfig([...])。