Drupal 11:通过hook添加自定义双列字段报错求解决方案
问题:自定义双列字段通过hook_entity_base_field_info添加到用户实体时触发QueryException错误
我开发了一个包含c1、c2双列的自定义字段模块,手动将其附加到用户实体并通过Drupal常规配置界面保存设置时可正常使用。但在demo2c.module中通过demo2c_entity_base_field_info()钩子添加该字段到user实体时,触发如下错误:
Drupal\Core\Entity\Query\QueryException: 'my_2c' not found in Drupal\Core\Entity\Query\Sql\Tables->ensureEntityTable() (line 373 of core/lib/Drupal/Core/Entity/Query/Sql/Tables.php).
模块完整代码
demo2c.info.yml
name: Demo With Two Column Field Type type: module description: Fails with hook_entity_base_field_info(). core_version_requirement: ^11.0 package: Demo
src/Plugin/Field/FieldType/Demo2CType.php
<?php namespace Drupal\demo2c\Plugin\Field\FieldType ; use Drupal\Core\Field\FieldItemBase ; use Drupal\Core\Field\FieldStorageDefinitionInterface ; use Drupal\Core\TypedData\DataDefinition ; /** * A field type with two integer columns. * * @FieldType( * id = "demo2c_field_type", * label = @Translation( "Demo Two Column Field Type" ), * module = "demo2c", * description = @Translation( "Fails when added with hook_entity_base_field_info()." ), * default_widget = "demo2c_field_widget", * default_formatter = "demo2c_field_formatter" * ) */ class Demo2CType extends FieldItemBase { /** * {@inheritdoc} */ public static function schema( FieldStorageDefinitionInterface $field_definition ) { return [ 'columns' => [ 'c1' => [ 'type' => 'int', 'size' => 'normal', 'not null' => FALSE ], 'c2' => [ 'type' => 'int', 'size' => 'normal', 'not null' => FALSE ] ] ] ; } /** * {@inheritdoc} */ public function isEmpty() { return $this->get( 'c1' )->getValue() === NULL && $this->get( 'c2' )->getValue() === NULL ; } /** * {@inheritdoc} */ public static function propertyDefinitions( FieldStorageDefinitionInterface $field_definition ) { $prop[ 'c1' ] = DataDefinition::create( 'integer' )->setLabel( t( 'Column One' ) ) ; $prop[ 'c2' ] = DataDefinition::create( 'integer' )->setLabel( t( 'Column Two' ) ) ; return $prop ; } }
src/Plugin/Field/FieldWidget/Demo2CWidget.php
<?php namespace Drupal\demo2c\Plugin\Field\FieldWidget ; use Drupal\Core\Field\FieldItemListInterface ; use Drupal\Core\Field\WidgetBase ; use Drupal\Core\Form\FormStateInterface ; /** * A field widget with two integer columns. * * @FieldWidget( * id = "demo2c_field_widget", * label = @Translation( "Demo Two Column Field Widget" ), * module = "demo2c", * field_types = { "demo2c_field_type" } * ) */ class Demo2CWidget extends WidgetBase { /** * {@inheritdoc} */ public function formElement( FieldItemListInterface $items, $delta, array $element, array &$form, FormStateInterface $form_state ) { $element += [ '#type' => 'fieldset' ] ; $element[ 'c1' ] = [ '#type' => 'number', '#default_value' => $items->get( $delta )->get( 'c1' )->getValue() ?? 0, '#title' => $this->t( "Column One" ) ] ; $element[ 'c2' ] = [ '#type' => 'number', '#default_value' => $items->get( $delta )->get( 'c2' )->getValue() ?? 0, '#title' => $this->t( "Column Two" ) ] ; return $element ; } }
src/Plugin/Field/FieldFormatter/Demo2CFormatter.php
<?php namespace Drupal\demo2c\Plugin\Field\FieldFormatter ; use Drupal\Core\Field\FormatterBase ; use Drupal\Core\Field\FieldItemListInterface ; /** * A field formatter with two integer columns. * * @FieldFormatter( * id = "demo2c_field_formatter", * module = "demo2c", * label = @Translation( "Demo Two Column Field Formatter" ), * field_types = { "demo2c_field_type" } * ) */ class Demo2CFormatter extends FormatterBase { /** * {@inheritdoc} */ public function viewElements( FieldItemListInterface $items, $langcade ) { $elements = [] ; foreach( $items as $delta => $item ) { $c1 = $item->get( 'c1' )->getValue() ; $c2 = $item->get( 'c2' )->getValue() ; $elements[ $delta ] = [ '#markup' => "Column one: $c1, column two: $c2." ] ; } return $elements ; } }
触发错误的demo2c.module代码
<?php use Drupal\Core\Entity\EntityTypeInterface; use Drupal\Core\Field\BaseFieldDefinition; function demo2c_entity_base_field_info( EntityTypeInterface $entity_type ) { if ( $entity_type->id() === 'user' ) { $fields[ 'my_2c' ] = BaseFieldDefinition::create( 'demo2c_field_type' ) ->setLabel( t( 'My Demo Two Column Field' ) ) ->setDescription( t( "Doesn't work." ) ) ->addConstraint( 'UniqueField' ) ->setDisplayOptions( 'form', [ 'weight' => -1 ] ) ; return $fields ; } }
解决方案
需要修改以下内容来解决问题:
1. 修复hook_entity_base_field_info的返回逻辑
当前钩子仅在匹配user实体时返回字段数组,其他实体类型无返回值,会干扰Drupal的字段收集流程。必须始终返回数组(即使为空):
修改后的demo2c.module代码:
<?php use Drupal\Core\Entity\EntityTypeInterface; use Drupal\Core\Field\BaseFieldDefinition; function demo2c_entity_base_field_info(EntityTypeInterface $entity_type) { $fields = []; if ($entity_type->id() === 'user') { $fields['my_2c'] = BaseFieldDefinition::create('demo2c_field_type') ->setLabel(t('My Demo Two Column Field')) ->setDescription(t("Now works.")) ->addConstraint('UniqueField') ->setDisplayOptions('form', ['weight' => -1]) // 补充显示配置,确保字段在表单和视图中可配置 ->setDisplayConfigurable('form', TRUE) ->setDisplayConfigurable('view', TRUE); } return $fields; }
2. 完善自定义字段类型的属性定义初始化
在Demo2CType.php的propertyDefinitions方法中,需要先初始化空数组,避免潜在的未定义变量问题:
修改后的代码片段:
public static function propertyDefinitions(FieldStorageDefinitionInterface $field_definition) { $prop = []; // 初始化空数组 $prop['c1'] = DataDefinition::create('integer')->setLabel(t('Column One')); $prop['c2'] = DataDefinition::create('integer')->setLabel(t('Column Two')); return $prop; }
3. 执行数据库更新
修改代码后,运行Drupal数据库更新命令,确保新的基础字段结构被添加到用户表:
drush updatedb
或者通过后台的“模块更新”页面执行更新操作。
原因说明
- 钩子函数必须始终返回数组,否则会导致Drupal处理其他实体时丢失字段定义,引发查询错误。
- 补充显示配置选项确保字段在表单和视图中能被正确初始化和处理。
- 数据库更新会触发Drupal重新生成实体表结构,确保新字段的数据库列被正确创建。
内容的提问来源于stack exchange,提问作者The Real Kwizats Haderach
相关产品推荐
相关产品推荐

