Drupal 8:如何在节点保存前获取旧节点并修改值?
解决Drupal 8节点编辑时在保存前获取旧数据并修改的问题
你遇到的问题我太熟悉了——Drupal节点表单的默认提交回调会先完成节点保存操作,而你把自定义回调追加到#submit数组末尾,时机确实太晚了,自然拿不到原始的旧数据。下面给你两个靠谱的解决办法,都能在节点保存前拿到旧数据并修改:
方案一:使用hook_entity_presave(推荐,通用型)
这个钩子会在任何实体(包括节点)保存之前触发,不管是通过表单提交还是API操作,适用性更广。你可以在这里加载数据库里的原始节点数据,对比后修改当前实体的值,系统会自动处理后续的保存流程。
/** * Implements hook_entity_presave(). */ function custom_module_entity_presave(Drupal\Core\Entity\EntityInterface $entity) { // 仅处理节点类型,且是更新操作(排除新建节点) if ($entity->getEntityTypeId() === 'node' && !$entity->isNew()) { // 加载数据库里的原始旧节点数据(未被当前表单修改的版本) $old_node = Drupal::entityTypeManager()->getStorage('node')->loadUnchanged($entity->id()); // 示例:对比旧标题,修改新标题 if ($old_node->getTitle() === '旧标题') { $entity->setTitle('修改后的新标题'); } // 示例:把旧内容追加到新内容后面 $old_body = $old_node->get('body')->value; $new_body = $entity->get('body')->value; $entity->set('body', $new_body . '<br><strong>原内容:</strong>' . $old_body); // 无需手动调用$entity->save(),钩子执行后系统会自动完成保存 } }
方案二:调整表单提交回调的执行顺序(表单专属)
如果你只需要在用户通过编辑表单提交时处理,可以调整#submit数组的顺序,让你的自定义回调在默认的节点保存回调之前执行:
function custom_module_form_node_form_alter(&$form, FormStateInterface $form_state) { $editing_entity = $form_state->getFormObject()->getEntity(); if (!$editing_entity->isNew()) { // 找到默认的节点表单提交回调的位置 $default_submit_key = array_search('node_form_submit', $form['actions']['submit']['#submit']); if ($default_submit_key !== FALSE) { // 先移除默认回调,再重新添加顺序:自定义回调在前,默认回调在后 unset($form['actions']['submit']['#submit'][$default_submit_key]); $form['actions']['submit']['#submit'][] = 'custom_module_node_form_submit'; $form['actions']['submit']['#submit'][] = 'node_form_submit'; } } } function custom_module_node_form_submit($form, FormStateInterface $form_state) { $editing_entity = $form_state->getFormObject()->getEntity(); // 加载原始旧节点数据 $old_node = Drupal::entityTypeManager()->getStorage('node')->loadUnchanged($editing_entity->id()); // 在这里根据旧数据修改当前实体的值,示例: $old_field_value = $old_node->get('field_custom')->value; $editing_entity->set('field_custom', $old_field_value . '-追加内容'); // 不要手动调用save(),后面的node_form_submit会处理保存 }
关键注意点
- 一定要用
loadUnchanged()而不是普通的load(),前者会直接从数据库读取未修改的原始数据,后者可能拿到的是已经被表单修改过的缓存实体。 - 不要在回调里手动调用
$entity->save(),否则会导致节点被保存两次,可能引发不必要的问题。
内容的提问来源于stack exchange,提问作者O Connor
相关产品推荐
相关产品推荐

