关于 drupal-backend
drupal-backend 是面向 Drupal 8 至 11+ 后端开发的技能,提供自定义模块、Drupal API、钩子、插件、服务、路由、表单和数据库操作的模式与示例。
主要功能
- 01自定义模块脚手架与结构
- 02钩子、控制器与路由
- 03表单与实体操作
- 04插件、服务与依赖注入
- 05数据库查询与架构定义
- 06开发与故障排查指南
适用场景
- 01构建 Drupal 自定义模块
- 02添加路由、表单或插件
- 03实现实体或数据库操作
- 04排查模块与 API 问题
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ omedia/ drupal-skill --skill drupal-backend安装后在 Claude Code 中输入/drupal-backend确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
assets/module-template/MODULENAME.info.ymlMODULENAME.moduleMODULENAME.routing.ymlREADME.mdassets/module-template/src/Controller/ExampleController.phpreferences/hooks.mdmodule_structure.md详细介绍
Drupal 后端开发
概述
提供专家级 Drupal 后端开发能力。为 Drupal 8、9、10 和 11+ 的自定义模块开发、PHP 编程、API 使用、钩子、插件、服务和数据库操作提供全面指导。
何时使用此技能
在以下情况下使用此技能:
- 自定义模块开发:创建新的 Drupal 模块
- 钩子:实现 Drupal 钩子以更改系统行为
- 控制器和路由:构建自定义页面和路由
- 表单:创建配置表单或自定义表单
- 实体:处理内容实体或配置实体
- 插件:构建区块、字段类型、格式化程序或其他插件
- 服务:创建可复用的业务逻辑服务
- 数据库操作:自定义查询和架构定义
- API:Entity API、Form API、Database API、Plugin API
核心能力
1. 自定义模块开发
创建完整且符合规范的 Drupal 模块:
快速入门工作流:
- 使用
assets/module-template/中的模块模板 - 将
MODULENAME替换为机器名(小写,使用下划线) - 将
MODULELABEL替换为易读的名称 - 使用 Drupal API 实现功能
- 启用模块并测试:
ddev drush en mymodule -y
模块结构:
.info.yml- 模块元数据和依赖项.module- 钩子实现.routing.yml- 路由定义.services.yml- 服务定义.permissions.yml- 自定义权限src/- PHP 类(PSR-4 自动加载)config/- 配置文件
参考文档:
references/module_structure.md- 完整的模块模式references/hooks.md- 钩子实现
2. 钩子系统
实现钩子以更改 Drupal 行为:
常用钩子:
hook_entity_presave()- 保存前修改实体hook_entity_insert/update/delete()- 响应实体更改hook_form_alter()- 修改任意表单hook_node_access()- 控制节点访问hook_cron()- 执行定期任务hook_install/uninstall()- 模块安装任务
钩子模式:
function MODULENAME_hook_name($param1, &$param2) {
// Implementation
}
最佳实践:
- 仅在
.module文件中实现钩子 - 使用恰当的类型提示
- 使用 PHPDoc 注释块编写文档
- 处理前检查实体类型
- 留意性能影响
3. 控制器和路由
创建自定义页面和端点:
路由定义(.routing.yml):
mymodule.example:
path: '/example/{param}'
defaults:
_controller: '\Drupal\mymodule\Controller\ExampleController::content'
_title: 'Example Page'
requirements:
_permission: 'access content'
param: \d+
控制器模式:
namespace Drupal\mymodule\Controller;
use Drupal\Core\Controller\ControllerBase;
class ExampleController extends ControllerBase {
public function content() {
return ['#markup' => $this->t('Hello!')];
}
}
使用依赖注入:
public function __construct(EntityTypeManagerInterface $entity_type_manager) {
$this->entityTypeManager = $entity_type_manager;
}
public static function create(ContainerInterface $container) {
return new static($container->get('entity_type.manager'));
}
4. Forms API
构建配置表单和自定义表单:
配置表单:
class SettingsForm extends ConfigFormBase {
protected function getEditableConfigNames() {
return ['mymodule.settings'];
}
public function buildForm(array $form, FormStateInterface $form_state) {
$config = $this->config('mymodule.settings');
$form['api_key'] = [
'#type' => 'textfield',
'#title' => $this->t('API Key'),
'#default_value' => $config->get('api_key'),
];
return parent::buildForm($form, $form_state);
}
public function submitForm(array &$form, FormStateInterface $form_state) {
$this->config('mymodule.settings')
->set('api_key', $form_state->getValue('api_key'))
->save();
parent::submitForm($form, $form_state);
}
}
表单验证:
public function validateForm(array &$form, FormStateInterface $form_state) {
if (strlen($form_state->getValue('field')) < 5) {
$form_state->setErrorByName('field', $this->t('Too short.'));
}
}
5. Entity API
处理内容实体和配置实体:
加载实体:
// Load single entity
$node = \Drupal::entityTypeManager()->getStorage('node')->load($nid);
// Load multiple entities
$nodes = \Drupal::entityTypeManager()->getStorage('node')->loadMultiple([1, 2, 3]);
// Load by properties
$nodes = \Drupal::entityTypeManager()->getStorage('node')->loadByProperties([
'type' => 'article',
'status' => 1,
]);
创建/保存实体:
$node = \Drupal::entityTypeManager()->getStorage('node')->create([
'type' => 'article',
'title' => 'My Article',
'body' => ['value' => 'Content', 'format' => 'basic_html'],
]);
$node->save();
实体查询:
$query = \Drupal::entityQuery('node')
->condition('type', 'article')
->condition('status', 1)
->accessCheck(TRUE)
->sort('created', 'DESC')
->range(0, 10);
$nids = $query->execute();
6. 插件系统
创建自定义插件(区块、字段等):
区块插件:
/**
* @Block(
* id = "mymodule_custom_block",
* admin_label = @Translation("Custom Block"),
* )
*/
class CustomBlock extends BlockBase {
public function build() {
return ['#markup' => 'Block content'];
}
public function blockForm($form, FormStateInterface $form_state) {
$form['setting'] = [
'#type' => 'textfield',
'#title' => $this->t('Setting'),
'#default_value' => $this->configuration['setting'] ?? '',
];
return $form;
}
public function blockSubmit($form, FormStateInterface $form_state) {
$this->configuration['setting'] = $form_state->getValue('setting');
}
}
7. 服务和依赖注入
创建可复用的服务:
服务定义(.services.yml):
services:
mymodule.custom_service:
class: Drupal\mymodule\Service\CustomService
arguments: ['@entity_type.manager', '@current_user']
服务类:
namespace Drupal\mymodule\Service;
class CustomService {
protected $entityTypeManager;
protected $currentUser;
public function __construct(EntityTypeManagerInterface $entity_type_manager, AccountProxyInterface $current_user) {
$this->entityTypeManager = $entity_type_manager;
$this->currentUser = $current_user;
}
public function doSomething() {
// Business logic
}
}
8. 数据库操作
执行自定义查询:
使用 Database API:
$database = \Drupal::database();
// Select query
$query = $database->select('node_field_data', 'n')
->fields('n', ['nid', 'title'])
->condition('type', 'article')
->condition('status', 1)
->range(0, 10);
$results = $query->execute()->fetchAll();
// Insert
$database->insert('mymodule_table')
->fields(['name' => 'Example', 'value' => 123])
->execute();
// Update
$database->update('mymodule_table')
->fields(['value' => 456])
->condition('name', 'Example')
->execute();
架构定义(.install 文件):
function mymodule_schema() {
$schema['mymodule_table'] = [
'fields' => [
'id' => ['type' => 'serial', 'not null' => TRUE],
'name' => ['type' => 'varchar', 'length' => 255, 'not null' => TRUE],
'value' => ['type' => 'int', 'not null' => TRUE, 'default' => 0],
],
'primary key' => ['id'],
'indexes' => ['name' => ['name']],
];
return $schema;
}
开发工作流
创建自定义模块
-
搭建模块框架:
cp -r assets/module-template/ /path/to/drupal/modules/custom/mymodule/ cd /path/to/drupal/modules/custom/mymodule/ mv MODULENAME.info.yml mymodule.info.yml mv MODULENAME.module mymodule.module mv MODULENAME.routing.yml mymodule.routing.yml -
更新模块文件:
- 将
MODULENAME替换为机器名 - 将
MODULELABEL替换为易读的名称 - 更新
.info.yml中的依赖项 - 自定义控制器、路由和逻辑
- 将
-
启用并测试:
ddev drush en mymodule -y ddev drush cr -
迭代开发:
- 实现功能
- 清除缓存:
ddev drush cr - 进行全面测试
- 检查日志:
ddev drush watchdog:tail
标准开发工作流
- 规划:确定所需的 API/钩子
- 编码:使用 Drupal API 实现
- 测试:启用模块、清除缓存并测试功能
- 调试:检查日志,必要时使用 Xdebug
- 优化:进行优化、添加测试并提升代码质量
最佳实践
模块开发
- PSR-4 自动加载:遵循命名空间约定
- 依赖注入:在类中使用 DI
- 钩子:仅在
.module文件中实现 - 类型提示:使用正确的 PHP 类型声明
- 文档:添加 PHPDoc 注释块
- 测试:编写自动化测试
代码质量
- Drupal 编码标准:遵循 PHPCS 规则
- 安全性:验证输入、清理输出、检查权限
- 性能:尽可能使用缓存并优化查询
- 无障碍性:确保表单和页面可访问
- 国际化:对所有字符串使用
$this->t()
API 使用
- 实体 API:优先使用实体操作,而非直接查询数据库
- 配置:使用 Config API 管理设置
- 状态 API:用于临时或不可导出的数据
- 缓存 API:为开销较大的操作实现缓存
- 队列 API:用于长时间运行的任务
常见模式
事件订阅器
class MyModuleSubscriber implements EventSubscriberInterface {
public static function getSubscribedEvents() {
return [KernelEvents::REQUEST => ['onRequest', 0]];
}
public function onRequest(RequestEvent $event) {
// Handle event
}
}
自定义权限
# mymodule.permissions.yml
administer mymodule:
title: 'Administer My Module'
restrict access: true
自定义访问检查
class CustomAccessCheck implements AccessInterface {
public function access(AccountInterface $account) {
return AccessResult::allowedIf($account->hasPermission('access content'));
}
}
故障排除
模块未显示
- 检查
.info.yml语法 - 验证
core_version_requirement - 清除缓存:
ddev drush cr
钩子无法正常工作
- 确认钩子名称正确
- 添加钩子后清除缓存
- 如果钩子顺序很重要,请检查模块权重
找不到类
- 验证 PSR-4 命名空间与目录匹配
- 清除缓存以重建类注册表
- 使用
composer dump-autoload检查自动加载
数据库错误
- 检查架构定义语法
- 架构变更后运行
ddev drush updb - 验证查询中的表名和列名
资源
参考文档
-
references/hooks.md- 常见钩子及示例- 实体钩子
- 表单钩子
- 节点钩子
- 安装钩子
- 令牌钩子
-
references/module_structure.md- 模块模式- 控制器和路由
- 表单(配置和自定义)
- 插件(区块、字段等)
- 服务和 DI
- 事件订阅器
资源模板
assets/module-template/- 模块脚手架.info.yml元数据.module钩子文件.routing.yml路由- 示例控制器
版本兼容性
Drupal 8 与 9、10、11
- 核心 API:各版本之间基本一致
- PHP 要求:8.x(7.0+)、9.x(7.3+)、10.x(8.1+)、11.x(8.3+)
- 弃用项:升级时请查看变更记录
- Symfony:不同 Drupal 版本使用不同的 Symfony 版本
另请参阅
- drupal-frontend - 主题开发、Twig 模板
- drupal-tooling - DDEV 和 Drush 开发工具
- Drupal API - 官方 API 文档
评论
支持 Markdown