区块 API
概览
在 Drupal 8 中,区块实际上由两个独立的 API 结构组成,以便创建与之前版本 Drupal 所支持的类似的用户界面。这两个 API 分别是 Block Plugin API(可复用的独立 API)和 Block Entity API(Drupal 8 特有的区块放置与可见性控制机制)。
使用 Block Plugin API 创建区块
要在模块代码中定义区块,需要学习和理解 插件 API,特别是 基于注解的插件发现机制,这是 Drupal 8 用来找到定义区块的代码的方法。
创建一个由模块定义的自定义区块包含以下步骤:
- 使用注解创建一个区块插件
- 扩展 Drupal\Core\Block\BlockBase 类
- 实现 Drupal\Core\Block\BlockPluginInterface 接口中的必要方法
让你的区块对 Drupal 和用户可见
Drupal 使用 PSR-4 标准来发现类。假设模块名为 fax,那么自定义区块的代码应该放在 fax/src/Plugin/Block/ 目录下。目录中的每个文件必须与其包含的类同名。例如,如果我们要定义 FaxBlock 类,它应位于 fax/src/Plugin/Block/FaxBlock.php 文件中,并包含如下内容:
namespace Drupal\fax\Plugin\Block;
use Drupal\Core\Block\BlockBase;
/**
* 提供一个 'Fax' 区块.
*
* @Block(
* id = "fax_block",
* admin_label = @Translation("Fax block"),
* )
*/
class FaxBlock extends BlockBase {
// 在这里重写 BlockPluginInterface 方法.
}
注解中的 id 属性定义了区块的唯一机器可读 ID,而 admin_label 则定义了区块在后台界面中显示的可读名称。可用的注解属性可以在 \Drupal\Core\Block\Annotation\Block 中找到。
最常用的两个方法需要重写:
BlockPluginInterface::build()—— 返回一个渲染数组,定义区块要显示的内容。BlockBase::access()—— 控制区块的可见性,需返回一个 AccessResult 对象。
为区块添加自定义配置参数
你可以通过重写 BlockPluginInterface::blockForm() 和 BlockPluginInterface::blockSubmit() 方法,并结合使用 BlockBase::setConfigurationValue() 和 BlockBase::getConfiguration() 来为区块的配置表单添加自定义参数。
例如,在 blockForm() 方法中添加一个文本字段,并在 blockSubmit() 中保存用户输入:
use Drupal\Core\Block\BlockBase;
use Drupal\Core\Block\BlockPluginInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Access\AccessResult;
/**
* 提供一个 'Fax' 区块.
*
* @Block(
* id = "fax_block",
* admin_label = @Translation("Fax block"),
* )
*/
class FaxBlock extends BlockBase implements BlockPluginInterface {
public function build() {
$config = $this->getConfiguration();
$fax_number = isset($config['fax_number']) ? $config['fax_number'] : '';
return [
'#markup' => $this->t('The fax number is @number!', ['@number' => $fax_number]),
];
}
public function blockForm($form, FormStateInterface $form_state) {
$form = parent::blockForm($form, $form_state);
$config = $this->getConfiguration();
$form['fax_number'] = [
'#type' => 'textfield',
'#title' => t('Fax number'),
'#default_value' => isset($config['fax_number']) ? $config['fax_number'] : '',
];
return $form;
}
public function blockSubmit($form, FormStateInterface $form_state) {
$this->setConfigurationValue('fax_number', $form_state->getValue('fax_number'));
}
public function blockValidate($form, FormStateInterface $form_state) {
$fax_number = $form_state->getValue('fax_number');
if (!is_numeric($fax_number)) {
$form_state->setErrorByName('fax_number', t('Needs to be an integer'));
}
}
}
你可以在 build() 方法中通过 getConfiguration() 获取配置数据并展示给用户。access() 方法中也可以添加更复杂的逻辑来决定区块是否显示。
访问条件示例方法:
public function access(AccountInterface $account, $return_as_object = FALSE) {
return \Drupal\Core\Access\AccessResult::allowedIf($account->isAuthenticated());
}
使用缓存标签的示例:
public function getCacheTags() {
return \Drupal\Core\Cache\Cache::mergeTags(parent::getCacheTags(), ['node_list']);
}
设置区块的缓存最大时长:
public function getCacheMaxAge() {
// 禁用该区块缓存
return 0;
}