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

D9中如何在Hook函数内用实体引用字段值设置另一实体引用字段

问题

创建PL类型节点时,通过hook函数自动创建Commerce Product,现有两个实体引用字段:

  • Name of Project(对应字段field_name_of_project):引用内容类型
  • Type of Use(对应字段field_type_of_use):引用分类术语

目前标题字段能正常设置,但这两个实体引用字段的值无法正确赋值,以下是我的代码:

<?php

/**
 * @file
 * file for the PL Product Creation module, which creates a product and product variations when a Pl node is created.
 *
 */ 

use Drupal\node\Entity\Node;
use Drupal\node\NodeInterface;
use Drupal\commerce_product\Entity\ProductVariation;
use Drupal\commerce_product\Entity\Product;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\StringTranslation\StringTranslationTrait;

/**
 * Implementation of hook_entity_insert().
 */
function pl_product_creation_entity_insert(Drupal\Core\Entity\EntityInterface $entity) {
    if ($entity->getEntityTypeId() == 'node' && $entity->bundle() == 'pl_node') {
        // Get the pl node properties
        $name_of_project = $entity->field_name_of_project->entity->getTitle();
        $type_of_use = $entity->field_type_of_use->entity->getName();
  
  
        // Load the product
        $pl_product_title = 'Products at ' . $name_of_project;

        // Load the product storage.
        $entity_type_manager = \Drupal::service('entity_type.manager');
        $product_storage = $entity_type_manager->getStorage('commerce_product');

        // Load the product by title.
        $pl_product = $product_storage->loadByProperties(['title' => $pl_product_title]);
  
        // Check if the Pl product exists
        if (!empty($pl_product)) {
            // Load the Pl product
            $pl_product = reset($pl_product);
        }
        else {
            // Create a new Pl product
            $pl_product = Product::create([
                'type' => 'pl',
            ]);

            // Set the title field.
            $pl_product->setTitle($pl_product_title);

            // Set the values of the custom fields.
            $pl_product->set('field_name_of_project', $name_of_project);
            $pl_product->set('field_type_of_use', $type_of_use);

            // Save the product entity.
            $pl_product->save();
        }

    }
}
问题分析与解决

实体引用字段不能直接赋值实体的标题或名称,必须传入实体ID或者实体对象,你的代码错误地使用了标题/名称字符串,这是核心问题。

错误点拆解

  1. $name_of_project = $entity->field_name_of_project->entity->getTitle();
    • 获取的是被引用内容类型节点的标题,但实体引用字段需要的是该节点的ID,不是标题文本。
  2. $type_of_use = $entity->field_type_of_use->entity->getName();
    • 同理,分类术语的实体引用字段需要的是术语的ID,不是术语名称。
  3. 赋值时直接传入字符串:$pl_product->set('field_name_of_project', $name_of_project);
    • 实体引用字段不接受纯字符串,Drupal无法识别这个字符串对应的实体,导致赋值失败。

修正后的代码

<?php

/**
 * @file
 * file for the PL Product Creation module, which creates a product and product variations when a Pl node is created.
 *
 */ 

use Drupal\node\Entity\Node;
use Drupal\node\NodeInterface;
use Drupal\commerce_product\Entity\ProductVariation;
use Drupal\commerce_product\Entity\Product;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\StringTranslation\StringTranslationTrait;

/**
 * Implementation of hook_entity_insert().
 */
function pl_product_creation_entity_insert(Drupal\Core\Entity\EntityInterface $entity) {
    if ($entity->getEntityTypeId() == 'node' && $entity->bundle() == 'pl_node') {
        // 获取被引用实体的ID(而非标题/名称)
        $project_node = $entity->field_name_of_project->entity;
        $use_term = $entity->field_type_of_use->entity;

        // 先检查引用是否存在,避免空指针错误
        if (!$project_node || !$use_term) {
            return;
        }

        $project_id = $project_node->id();
        $use_term_id = $use_term->id();
        $pl_product_title = 'Products at ' . $project_node->getTitle();

        // 加载产品存储
        $entity_type_manager = \Drupal::service('entity_type.manager');
        $product_storage = $entity_type_manager->getStorage('commerce_product');

        // 按标题查找产品
        $pl_product = $product_storage->loadByProperties(['title' => $pl_product_title]);
  
        // 检查产品是否存在
        if (!empty($pl_product)) {
            $pl_product = reset($pl_product);
        }
        else {
            // 创建新产品
            $pl_product = Product::create([
                'type' => 'pl',
            ]);

            $pl_product->setTitle($pl_product_title);

            // 使用实体ID赋值实体引用字段
            $pl_product->set('field_name_of_project', $project_id);
            $pl_product->set('field_type_of_use', $use_term_id);

            $pl_product->save();
        }

    }
}

额外优化说明

  • 增加了引用实体的空值检查:如果原PL节点的两个引用字段未填写,直接返回,避免后续代码抛出空指针异常。
  • 也可以直接传入实体对象赋值,比如$pl_product->set('field_name_of_project', $project_node);,效果和传ID一致,两种方式都可行。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.01 11:05:15