从Drupal7转Drupal8:如何正确覆写节点删除操作?
正确覆写Drupal 8节点删除操作的实现方式
嘿,从Drupal7转到D8确实得适应不少架构变化,尤其是表单这块——ConfirmFormBase是官方推荐的正确路子,你选的方向没错!下面给你一步步拆解扎实的实现方式:
1. 完整实现自定义删除确认表单(ConfirmFormBase)
你已经创建了src/Form/DeleteXXXConfirm.php,下面是带关键注释的可运行代码示例:
namespace Drupal\XXX\Form; use Drupal\Core\Form\ConfirmFormBase; use Drupal\Core\Form\FormStateInterface; use Drupal\Core\Url; use Drupal\node\Entity\Node; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; /** * 自定义节点删除确认表单. */ class DeleteXXXConfirm extends ConfirmFormBase { /** * 要删除的节点对象. * * @var \Drupal\node\Entity\Node */ protected $node; /** * {@inheritdoc} */ public function getFormId() { // 表单唯一ID,需与模块名对应 return 'xxx_node_delete_confirm'; } /** * {@inheritdoc} */ public function getQuestion() { // 确认表单标题,用节点标题动态替换 return $this->t('Are you sure you want to delete the node %title?', ['%title' => $this->node->getTitle()]); } /** * {@inheritdoc} */ public function getCancelUrl() { // 取消操作后的跳转URL,这里跳回节点详情页 return Url::fromRoute('entity.node.canonical', ['node' => $this->node->id()]); } /** * {@inheritdoc} */ public function getConfirmText() { // 自定义确认按钮文字,默认是"Delete" return $this->t('Delete Node'); } /** * {@inheritdoc} */ public function buildForm(array $form, FormStateInterface $form_state, $node = NULL) { // 加载目标节点,不存在则抛出404 $this->node = Node::load($node); if (!$this->node) { throw new NotFoundHttpException(); } // 调用父类方法生成基础确认表单结构 return parent::buildForm($form, $form_state); } /** * {@inheritdoc} */ public function submitForm(array &$form, FormStateInterface $form_state) { // 自定义删除逻辑,可按需调整 // 1. 执行默认节点删除操作(如需保留原生行为) $this->node->delete(); // 2. 添加自定义操作:比如记录日志、触发关联事件 $this->messenger()->addStatus($this->t('Node %title has been deleted.', ['%title' => $this->node->getTitle()])); // 3. 设置提交后的跳转目标,这里跳回内容列表页 $form_state->setRedirect('system.admin_content'); } }
2. 替换默认节点删除表单路由
要让Drupal使用你的自定义表单,需要通过hook_route_alter替换原生路由,在模块的.module文件中添加:
/** * Implements hook_route_alter(). */ function xxx_route_alter(&$routes) { // 替换默认的节点删除确认路由 if (isset($routes['entity.node.delete_form'])) { $routes['entity.node.delete_form']->setDefault('_form', '\Drupal\XXX\Form\DeleteXXXConfirm'); } }
3. 配合hook_node_delete做后续处理(可选)
你提到Drupal8仍支持hook_node_delete,这个钩子在节点删除后触发,适合做关联数据清理、日志记录等操作,在.module文件中添加:
/** * Implements hook_node_delete(). */ function xxx_node_delete($node) { // 节点删除后的自定义逻辑示例 \Drupal::logger('xxx')->notice('Node @nid (@title) has been deleted.', [ '@nid' => $node->id(), '@title' => $node->getTitle(), ]); }
关键注意事项
- 模块名统一:把代码中的
XXX替换成你的实际模块名,包括命名空间、钩子前缀 - 权限控制:自定义表单会继承原生节点删除权限,如需特殊权限,可在
buildForm中添加权限检查并抛出AccessDeniedException - 缓存清理:修改代码后必须执行缓存清理(
drush cr或后台手动清理),否则路由和表单不会生效
内容的提问来源于stack exchange,提问作者user82521
相关产品推荐
相关产品推荐

