向JSON:API响应中添加计算字段 - Goran Nikolovski

作者:API传播员 · 2025-11-22 · 阅读时间:3分钟
本文详细介绍了如何在JSON:API响应中添加计算字段,包括使用hookentitybasefieldinfo_alter钩子和创建MyComputedField类,以及针对特定包和多值字段的实现方法。计算字段不存储在数据库中,但可缓存提升性能,并避免使用includes功能带来的JSON响应复杂性。

向 JSON:API 响应中添加计算字段

在开发过程中,我们常常需要向 JSON:API 响应中添加额外的字段。本文将介绍如何通过计算字段实现这一目标。计算字段与常规字段不同,它们并不存储在数据库中,但如果启用了缓存模块,这些字段会被缓存,从而提高性能。


添加计算字段的基本步骤

要向响应中添加计算字段,首先需要在 *.module 文件中实现 hook_entity_base_field_info_alter() 钩子。以下是示例代码:

使用 DrupalCoreEntityEntityTypeInterface;
使用 DrupalCoreFieldBaseFieldDefinition;
使用 DrupalMODULE_NAMEPluginFieldMyComputedField;

/**
 * 实现 hook_entity_base_field_info_alter()。
 */
函数 MODULE_NAME_entity_base_field_info_alter(&$fields, EntityTypeInterface $entity_type) {
  if ($entity_type->id() == 'node') {
    $fields['my_computed_field'] = BaseFieldDefinition::create('string')
      ->setLabel(t('My Computed Field'))
      ->setName('my_computed_field')
      ->setDescription(t('Description of my computed field.'))
      ->setComputed(TRUE)
      ->setClass(MyComputedField::class);
  }
}

上述代码会为所有节点添加一个名为 my_computed_field 的计算字段。


创建计算字段类

接下来,我们需要创建 MyComputedField 类。以下是实现代码:

getEntity()->get('field_product')->entity;

    if ($product_node instanceof NodeInterface && !$product_node->get('field_image')->isEmpty()) {
      $image_url = file_create_url($product_node->get('field_image')->entity->getFileUri());
    }

    $this->list[0] = $this->createItem(0, $image_url);
  }
}

通过清除缓存后,您将在节点资源的 JSON:API 输出中看到新字段。


针对特定包添加计算字段

如果需要将计算字段添加到一个或多个特定的内容包中,可以使用 hook_entity_bundle_field_info_alter() 钩子。例如:

函数 MODULE_NAME_entity_bundle_field_info_alter(&$fields, EntityTypeInterface $entity_type, $bundle) {
  // 针对特定内容包的逻辑。
}

创建多值计算字段

如果需要创建多值字段,请确保在 BaseFieldDefinition 中将基数设置为无限:

->setCardinality(FieldStorageConfigInterface::CARDINALITY_UNLIMITED)

此外,别忘了在 use 部分添加以下接口:

使用 DrupalfieldFieldStorageConfigInterface;

图片 URL 示例

计算字段在某些场景下非常有用,例如存储引用节点中图像的 URL。通过这种方式,可以避免使用 includes 功能带来的 JSON 响应复杂性。

假设有一个内容类型通过 field_product 字段引用了另一个名为 Product 的内容类型,而 Product 内容类型中包含一个图像字段。以下是实现代码:

getEntity()->get('field_product')->entity;

    if ($product_node instanceof NodeInterface && !$product_node->get('field_image')->isEmpty()) {
      $image_url = file_create_url($product_node->get('field_image')->entity->getFileUri());
    }

    $this->list[0] = $this->createItem(0, $image_url);
  }
}

注意事项

需要注意的是,您无法在计算字段上添加过滤器。这是因为 JSON:API 模块的过滤功能直接基于核心实体查询 API,而核心并不支持对计算字段进行过滤。因此,JSON:API 也不支持该操作。


通过本文的介绍,您应该能够在 JSON:API 响应中成功添加计算字段。无论是为所有节点添加字段,还是为特定内容包添加字段,这种方法都能满足您的需求。

原文链接: https://gorannikolovski.com/blog/add-computed-field-jsonapi-response