9.8. 在 Drupal 中使用表单。通过代码添加配置表单。
在本教程中,我们将处理 Drupal Form API,并为模块创建一个设置表单。我们已经创建了用于显示页面和块的模块,现在让我们创建一个配置表单,用于存储连接到某个条件服务的数据。假设我们需要在站点上存储 API 密钥和 API 客户端 ID,例如用于 Google Maps API。
代码示例可以在 GitHub 上查看:
https://github.com/levmyshkin/drupalbook8
我们可以将这些数据存储在 settings.php 中,并将这些设置添加到 git 中。但这样做不安全,存储对服务的访问权限最好存在数据库中。
现在让我们为表单添加另一个路由:
modules/custom/drupalbook/drupalbook.routing.yml
drupalbook.settings:
path: '/admin/structure/drupalbook/settings'
defaults:
_form: '\Drupal\drupalbook\Form\DrupalbookSettingsForm'
_title: 'DrupalBook Settings form'
requirements:
_permission: 'administer site configuration'
与之前的路由不同,在 defaults 中我们指定的是 _form,而不是 _controller。原因是我们将为表单创建一个表单类,而不是控制器类。现在让我们为表单类创建一个文件:
modules/custom/drupalbook/src/Form/DrupalbookSettingsForm.php
你需要在 src 文件夹中为表单创建一个单独的 Form 文件夹。这允许你将模块代码分离到不同的文件夹中,并且可以根据文件夹名称轻松找到所需的代码。
添加以下表单代码,我们将分析每个代码块以及它的工作原理:
<?php
namespace Drupal\drupalbook\Form;
use Drupal\Core\Form\ConfigFormBase;
use Drupal\Core\Form\FormStateInterface;
/**
* Configure example settings for this site.
*/
class DrupalbookSettingsForm extends ConfigFormBase {
/**
* {@inheritdoc}
*/
public function getFormId() {
return 'drupalbook_admin_settings';
}
/**
* {@inheritdoc}
*/
protected function getEditableConfigNames() {
return [
'drupalbook.settings',
];
}
/**
* {@inheritdoc}
*/
public function buildForm(array $form, FormStateInterface $form_state) {
$config = $this->config('drupalbook.settings');
$form['drupalbook_api_key'] = array(
'#type' => 'textfield',
'#title' => $this->t('API Key'),
'#default_value' => $config->get('drupalbook_api_key'),
);
$form['drupalbook_api_client_id'] = array(
'#type' => 'textfield',
'#title' => $this->t('API Client ID'),
'#default_value' => $config->get('drupalbook_api_client_id'),
);
return parent::buildForm($form, $form_state);
}
/**
* {@inheritdoc}
*/
public function submitForm(array &$form, FormStateInterface $form_state) {
// Retrieve the configuration
$this->configFactory->getEditable('drupalbook.settings')
// Set the submitted configuration setting
->set('drupalbook_api_key', $form_state->getValue('drupalbook_api_key'))
// You can set multiple configurations at once by making
// multiple calls to set()
->set('drupalbook_api_client_id', $form_state->getValue('drupalbook_api_client_id'))
->save();
parent::submitForm($form, $form_state);
}
}
我们已经了解了命名空间(namespace)和使用(use)操作符,以及 Drupal 如何自动连接仅需要的类:
\drupalbook\Form;
use Drupal\Core\Form\ConfigFormBase;
use Drupal\Core\Form\FormStateInterface;
为了创建配置表单,你需要继承 ConfigFormBase 类,ConfigFormBase 表示你将把数据从表单保存到配置中。
extends ConfigFormBase {
接下来,指定表单 ID,它必须对每个表单都是唯一的。如果你将表单 ID 以模块名称开头,确保你的 ID 是唯一的:
function getFormId() {
return 'drupalbook_admin_settings';
}
指定我们将存储数据的配置组:
function getEditableConfigNames() {
return [
'drupalbook.settings',
];
}
现在,让我们来看一下我们如何创建表单字段。你可以通过阅读文档来评估 Form API 的功能,以及你可以显示哪些字段:
https://api.drupal.org/api/drupal/elements/8.5.x
我们目前仅使用了 textfield 字段:
但是你经常需要处理下拉列表:
复选框和单选按钮:
尝试将你的字段添加到表单中,而不限于文本字段。
function buildForm(array $form, FormStateInterface $form_state) {
$config = $this->config('drupalbook.settings');
我们在 $form 中构建表单数组,然后从中生成 HTML。变量 $form_state 存储表单提交的所有数据,这里包括所有字段的值、表单 ID、用于防止自动提交的 CSRF token。$form_state 还允许你在多步表单的各个步骤之间传递数据,我们将在接下来的课程中使用这个功能。每次表单通过 AJAX 提交时,表单都会被重新构建,而 $form_state 使你能够构建提交按钮点击前的表单副本。如果表单因为错误没有提交,例如某个字段未填,所有字段的值都会保存到 $form_state 中。
在这里,我们还从配置中加载数据。如果你已经在 drupalbook.settings 中保存了一些数据,那么 $config 就不再是空的,这将允许你通过 #default_value 为每个文本字段设置当前值,并使用 get() 方法从配置中获取数据。
['drupalbook_api_key'] = array(
'#type' => 'textfield',
'#title' => $this->t('API Key'),
'#default_value' => $config->get('drupalbook_api_key'),
);
$form['drupalbook_api_client_id'] = array(
'#type' => 'textfield',
'#title' => $this->t('API Client ID'),
'#default_value' => $config->get('drupalbook_api_client_id'),
);
在方法结束时,我们返回 $form 和 $form_state,以便表单能够被构建。
::buildForm($form, $form_state);
接下来是 submitForm() 方法,它会在表单提交且没有发生错误时触发。如果你确实有一个必填字段未填写,并且 Drupal 抛出一个错误,那么 submitForm 将不会执行。如果你想检查提交的数据值,那么你需要使用 validateForm(),即使表单中有错误,validate 也会生效,使用 validate 你可以取消表单的提交,并且如果数据不符合你的要求,可以引发错误。我们将在接下来的表单教程中覆盖验证功能。
在 submitForm() 方法中,我们遍历所有字段,收集它们的值并更新 drupalbook.settings 配置:
function submitForm(array &$form, FormStateInterface $form_state) {
// Retrieve the configuration
$this->configFactory->getEditable('drupalbook.settings')
// Set the submitted configuration setting
->set('drupalbook_api_key', $form_state->getValue('drupalbook_api_key'))
// You can set multiple configurations at once by making
// multiple calls to set()
->set('drupalbook_api_client_id', $form_state->getValue('drupalbook_api_client_id'))
->save();
parent::submitForm($form, $form_state);
}
我们还调用了父方法 submitForm,它会显示表单提交成功的消息。你可以注释掉这行并写自己的消息:
//parent::submitForm($form, $form_state);
drupal_set_message($this->t('My Cool Form have been saved!'));
记得清理缓存以应用你的路由。现在你可以尝试你的表单了。当你需要加载 API 密钥时,可以使用以下代码:
$config = \Drupal::config('example.settings');
$api_key =$config->get('drupalbook_api_key');
$api_client_id = $config->get('drupalbook_api_client_id');
这段代码将在任何模块或预处理函数中工作,因为 Drupal 中有一个统一的配置系统。
这就是本节关于表单的内容,接下来的课程我们将分析如何制作多步表单。
代码示例可以在 GitHub 上查看:
https://github.com/levmyshkin/drupalbook8