Drupal 8模块开发
第二章 区块,配置和表单
2.1 :区块与配置
我们已经了解了构建模块的几个必要条件,接下来看下 Drupal 8 中最常用的组件:区块和表单。
Drupal 8 中的块 API 变了,现在块既是插件(plugins)也是实体(entities)。 Drupal 8 中的块由两部分 API 组成:
块插件 API :一个独立可重用的 API
? 块实体 API :处理块的位置和可见性控制
?
这意味着现在块是可字段化的实体和正在使用新的插件系统(change record here)。
也意味着我们可以创建新的绑定,追加字段,使用不同方式查看它们。
现在一个区块可以同时显示在多个区域(regions)内,这在 Drupal 8 之前是不可以的。
实质上现在是可以创建同一个块的多个实例了。
你也可以通过 UI 把一个块同时放在不同的区域,不会发生冲突。
本课我们将使用 Examples 项目的 block_example 模块。
本课…
创建 examples/block_example 模块 介绍 Drupal 8 中的注解
探讨如何使用 Drupal GUI 添加区块 学习 Form API
探讨如何使用 Form API
研究如何创建带有表单的区块和页面
11
Drupal 8模块开发
Drupal 8 区块
不必使用 4 个钩子定义区块了(Drupal 7 中你必须这样做),插件系统支持以下内容:
一个区块一个文件
如果你想创建新区块,可以直接拷贝、修改之前区块文件,即得到新区块。 以往修改区块需要处理位于不同位置的四个函数,且这些函数可能在两个文件里。 现在区块内容只在一个文件内。 所有逻辑都在那个文件
你不需要去任何 info 文件声明你的类路径,因为它会被自动加载。 区块很好地被封装在一个独立文件内
创建一个简单的区块
Example 项目有个 block_example 模块,在 src/Plugin/Block 文件夹内有 3 个例子,分别展示 3 种不同区块。
我们看下最简单的那个:创建一个没有任何内容的空块。
首先在 examples 文件夹内创建新模块 block_example(创建模块方法请参考上一课)。 之后在 block_example 目录下创建 src/Plugin/Block 目录。
最后在 Block 目录创建 ExampleEmptyBlock.php 文件,放置以下代码。 下载文件
namespace Drupal\\block_example\\Plugin\\Block; use Drupal\\Core\\Block\\BlockBase; /**
* Provides a 'Example: empty block' block. *
* @Block(
* id = \
* admin_label = @Translation(\ * ) */
class ExampleEmptyBlock extends BlockBase {
/**
* {@inheritdoc} */
public function build() { return [
'#type' => 'markup', '#markup' => '', ]; }
12
Drupal 8模块开发
}
类和注解
所有类开始的时候必须定义名字空间,之后我们扩展BlockBase 创建类 ExampleEmptyBlock 。
在这个类里我们可以使用 Drupal 8 引入的注解。
通常 PHP 注解是一段自包含的注释文本,它允许类文件注册信息和元数据的自动发现。
上面第 1 组注解是告诉 Drupal 我们要创建一个 id 为 example_empty 和管理 label 为 “Example: empty block”的区块(@Block)。并且这个管理 label 在使用之前要经过翻译系统处理。
在覆写类函数时可以使用 {@inheritdoc} 注解,它告诉系统这里使用父类的注解。 注意:
只有书写了正确的注解后 Drupal 才能监测到这个块。 我们实现了一个 build() 方法,这是一个最重要、常用的方法,它会返回一个可渲染数组(用于块输出)。
确保 block_example 模块被激活,清空缓存。
在块配置页(/admin/structure/block)的任意区域内点击“放置区块”按钮,弹出的对话框内你会看到这个新区块。
2.2 :创建表单
Drupal 8 表单
现在我们已经能够创建从区块布局画面可重复使用的区块,是时候学习怎样利用 API 添加一个配置表单了。
这个新的配置表单允许你使用用户界面设置显示在区块内的一个文本字符串。
以下面的方式处理额外的配置表单元素:
使用blockForm()方法向接收的 $form 数组添加元素。 使用blockSubmit()方法保存从表单接收的数据。
使用defaultConfiguration()方法定义默认的配置值。
为表单创建个区块
首先,我们创建一个包含这个表单的区块:
创建文
block_example/src/Plugin/Block/ExampleConfigurableTextBlock.php 粘贴以下代码 下载文件
13
件
Drupal 8模块开发
* @file
* Contains \\Drupal\\block_example\\Plugin\\Block\\ExampleConfigurableTextBlock. */
namespace Drupal\\block_example\\Plugin\\Block;
use Drupal\\Core\\Block\\Annotation\\Block; use Drupal\\Core\\Block\\BlockBase;
use Drupal\\Core\\Annotation\\Translation; use Drupal\\Core\\Form\\FormStateInterface; /**
* Provides a 'Example: configurable text string' block. *
* Drupal\\block\\BlockBase gives us a very useful set of basic functionality for * this configurable block. We can just fill in a few of the blanks with * defaultConfiguration(), blockForm(), blockSubmit(), and build(). *
* @Block(
* id = \
* admin_label = @Translation(\ * category = @Translation(\ * ) */
class ExampleConfigurableTextBlock extends BlockBase {
/**
* {@inheritdoc} */
public function defaultConfiguration() { return [
'block_example_string' => $this->t('A default value. This block was created at %time', ['%time' =>date('c')]), ]; }
/**
* {@inheritdoc} */
public function blockForm($form, FormStateInterface $form_state) { $form['block_example_string_text'] = [ '#type' => 'textfield',
'#title' => $this->t('Block contents'), '#size' => 60,
14
Drupal 8模块开发
'#description' => $this->t('This text will appear in the example block.'), '#default_value' => $this->configuration['block_example_string'], ];
return $form; }
/**
* {@inheritdoc} */
public function blockSubmit($form, FormStateInterface $form_state) { $this->configuration['block_example_string']
= $form_state->getValue('block_example_string_text'); }
/**
* {@inheritdoc} */
public function build() { return [
'#type' => 'markup',
'#markup' => $this->configuration['block_example_string'], ]; } }
清空缓存,查看区块。
理解新特征和函数
避免全局函数
Drupal 8 内每片代码都尽可能的自包含。意味着大多数函数不再暴露在全局范围内而是被封装在类里。
因此不推荐像 Drupal 7 那样直接使用 l()或t()这样的函数。
现在通过叫依赖注入(dependency injection)的系统向类提供功能,这个在后面的课程会讨论。 扩展基类
大多数组件(例如区块、控制器)都会使用扩展基类这种模式。
基类封装了很多像 t() 这样的通用机能,所以尽可能的去继承基类。我们创建块的时候继承了BlockBase 这个基类,它就定义了类似 Drupal 7 的 t() 方法。 Traits
Traits 本质上就是我们 Drupal 7 使用的 include,它提供能够被包含在任何类中的额外方法。
通过在 BlockBase 中包含StringTranslationTrait,我们可以使用它的任何方法,就如同这些方法在BlockBase 中一样。
$this->t() 定义在 StringTranslationTrait 内。BlockBase 继承
15