You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Drupal 11:编程创建带自定义字段的词汇表,字段不显示于UI

问题分析与解决方案

核心问题

你遇到的问题是:通过entity_insert钩子自动创建词汇表和实体引用字段后,字段无法在分类术语的添加/编辑表单中显示,但手动创建同类型字段却能正常显示。

代码中的问题点及修复

1. 字段存储的provider配置错误

你的字段存储定义中'provider' => 'field_create'是无效的,provider必须是你的模块名称(比如mymodule)。Drupal需要通过provider识别字段的归属模块,错误的provider会导致字段无法被表单系统正确加载。

2. 不恰当的全量缓存刷新

在entity_insert钩子中调用drupal_flush_all_caches()会干扰实体保存的正常流程——此时刚创建的词汇表和字段可能还未完全写入数据库,缓存刷新会导致后续操作无法正确读取实体信息。

3. 表单显示组件配置缺失(可选优化)

虽然不是必须,但明确添加widget的settings配置可以避免潜在的配置缺失问题,确保字段组件被正确初始化。


修复后的完整代码

function mymodule_entity_insert(\Drupal\Core\Entity\EntityInterface $entity) {
  // 创建顶部菜单词汇表(仅针对section类型节点)
  if ($entity->bundle() == "section") {
    /***
     * Top menu vocabulary
     */
    $vocabulary_id = $entity->id() . '_top_menu';
    $vocabulary_name = t('@entity_name Top Menu', ['@entity_name' => $entity->label()]);

    // 创建并保存词汇表
    $vocabulary = Vocabulary::create([
      'vid' => $vocabulary_id,
      'name' => $vocabulary_name,
    ])->save();

    // 定义字段信息
    $field_name = 'field_parent_entity_reference';
    $entity_type = 'taxonomy_term';
    $bundle = $vocabulary_id;

    // 检查字段存储是否存在,不存在则创建
    if (!$field_storage = FieldStorageConfig::loadByName($entity_type, $field_name)) {
      $field_storage = FieldStorageConfig::create([
        'field_name' => $field_name,
        'entity_type' => $entity_type,
        'type' => 'entity_reference',
        'settings' => [
          'target_type' => 'node',
        ],
        'cardinality' => 1,
        'provider' => 'mymodule', // 替换为你的模块名称
      ]);
      $field_storage->save();
    }

    // 检查字段实例是否存在,不存在则创建
    if (!FieldConfig::loadByName($entity_type, $bundle, $field_name)) {
      FieldConfig::create([
        'field_name' => $field_name,
        'entity_type' => $entity_type,
        'field_storage' => $field_storage,
        'bundle' => $bundle,
        'label' => t('Content to show'),
        'settings' => [
          'handler' => 'default',
          'handler_settings' => [
            'target_bundles' => [
              'announcement' => 'announcement',
              'section' => 'section',
              'page' => 'page',
              'event' => 'event',
              'article' => 'article',
            ],
          ],
        ],
      ])->save();
    }

    // 加载或创建表单显示配置
    $form_display = EntityFormDisplay::load('taxonomy_term.' . $bundle . '.default');
    if (!$form_display) {
      $form_display = EntityFormDisplay::create([
        'targetEntityType' => 'taxonomy_term',
        'bundle' => $bundle,
        'mode' => 'default',
      ]);
    }

    // 配置字段的表单组件(添加完整的widget设置)
    $form_display->setComponent($field_name, [
      'type' => 'entity_reference_autocomplete',
      'weight' => 50,
      'settings' => [
        'match_operator' => 'CONTAINS',
        'size' => 60,
        'placeholder' => '',
      ],
    ])->save();

    // 加载或创建视图显示配置
    $view_display = EntityViewDisplay::load('taxonomy_term.' . $bundle . '.default');
    if (!$view_display) {
      $view_display = EntityViewDisplay::create([
        'targetEntityType' => 'taxonomy_term',
        'bundle' => $bundle,
        'mode' => 'default',
      ]);
    }

    // 配置字段的视图组件
    $view_display->setComponent($field_name, [
      'label' => 'above',
      'type' => 'entity_reference_label',
      'weight' => 50,
    ])->save();

    // 仅重置相关实体类型的缓存,而非全量刷新
    \Drupal::entityTypeManager()->getStorage('taxonomy_vocabulary')->resetCache();
    \Drupal::entityTypeManager()->getStorage('field_config')->resetCache();
    \Drupal::entityTypeManager()->getStorage('entity_form_display')->resetCache();

    // 日志调试(可选)
    \Drupal::logger('mymodule')->info('Form display updated for field: @field', ['@field' => $field_name]);
    $vocab_load = Vocabulary::load($vocabulary_id);
    $field_load = FieldConfig::loadByName('taxonomy_term', $bundle, $field_name);
    \Drupal::logger('mymodule')->info('Vocabulary: @vocab, Field: @field', [
      '@vocab' => $vocab_load ? $vocab_load->id() : 'Not Found',
      '@field' => $field_load ? $field_load->id() : 'Not Found',
    ]);

    // 测试创建术语(可选)
    $term = \Drupal\taxonomy\Entity\Term::create([
      'vid' => $vocabulary_id,
      'name' => 'Test Term',
    ]);
    $term->save();
    $loaded_term = \Drupal\taxonomy\Entity\Term::load($term->id());
    \Drupal::logger('mymodule')->info('Field Value: @value', [
      '@value' => $loaded_term->get($field_name)->value ?? 'Empty',
    ]);
  }
}

额外说明

  • 替换代码中的mymodule为你实际的模块名称,确保provider配置正确。
  • 使用针对性的缓存重置替代全量缓存刷新,既保证缓存更新,又不破坏当前实体操作流程。
  • 若修复后仍有问题,可以检查:
    • 字段的权限设置是否允许当前用户编辑该字段
    • 词汇表的bundle是否被正确注册到taxonomy_term实体类型中(可通过drush entity:list taxonomy_term查看)

内容的提问来源于stack exchange,提问作者Zathrus Writer

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 17:22:09