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

Drupal:如何在_node_update钩子中调用自定义CustomizedSerializer?

问题分析

你遇到的核心问题是:CustomizedSerializer是Views的样式插件,而非Drupal核心序列化系统的独立服务,所以直接调用\Drupal::service('serializer')只会触发核心序列化逻辑,不会用到你自定义的插件。

这个插件设计用于处理Views查询结果的输出渲染,原本的JSON API端点应该是基于Views构建的,所以访问时会触发插件的render方法;而你的钩子代码直接调用核心序列化服务,自然走不通同一路径。

解决方案

推荐优先采用逻辑抽离的方式,保证Views和钩子代码复用同一套序列化逻辑,避免重复维护;如果临时需要快速复用插件,也可以尝试实例化插件的方式(不推荐长期使用)。

方案一:抽离核心序列化逻辑(推荐)

把CustomizedSerializer里的序列化逻辑单独封装成一个独立服务,让Views插件和钩子代码都调用这个服务,确保输出一致。

1. 定义自定义服务

在modules/custom/my_module/my_module.services.yml中添加服务配置:

services:
  my_module.product_serializer:
    class: Drupal\my_module\Serializer\ProductSerializer
    arguments: ['@serializer', '@logger.factory']

2. 创建序列化服务类

新建modules/custom/my_module/src/Serializer/ProductSerializer.php:

<?php

namespace Drupal\my_module\Serializer;

use Drupal\Core\Logger\LoggerChannelFactoryInterface;
use Drupal\Core\Serializer\Serializer;
use Drupal\node\NodeInterface;

class ProductSerializer {
  protected $serializer;
  protected $logger;

  public function __construct(Serializer $serializer, LoggerChannelFactoryInterface $loggerFactory) {
    $this->serializer = $serializer;
    $this->logger = $loggerFactory->get('php');
  }

  /**
   * 序列化产品节点数组为JSON
   */
  public function serializeProducts(array $nodes): string {
    $this->logger->notice('ProductSerializer::serializeProducts');
    
    // 这里复制原CustomizedSerializer::render里的逻辑,处理节点数据
    $processedData = [];
    foreach ($nodes as $node) {
      if ($node instanceof NodeInterface && $node->bundle() === 'product') {
        $processedData[] = [
          'id' => $node->id(),
          'title' => $node->getTitle(),
          'created' => $node->getCreatedTime(),
          // 其他需要的字段处理逻辑,和原插件保持一致
        ];
      }
    }

    return $this->serializer->serialize($processedData, 'json');
  }
}

3. 修改Views插件调用新服务

更新modules/custom/my_module/src/Plugin/views/style/CustomizedSerializer.php:

<?php

namespace Drupal\my_module\Plugin\views\style;

use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Drupal\Core\Serializer\Serializer;
use Drupal\my_module\Serializer\ProductSerializer;
use Drupal\views\Plugin\views\style\Serializer;
use Symfony\Component\DependencyInjection\ContainerInterface;

class CustomizedSerializer extends Serializer implements ContainerFactoryPluginInterface {
  protected $productSerializer;

  public function __construct(
    array $configuration,
    $plugin_id,
    $plugin_definition,
    Serializer $serializer,
    ProductSerializer $productSerializer
  ) {
    parent::__construct($configuration, $plugin_id, $plugin_definition, $serializer);
    $this->productSerializer = $productSerializer;
  }

  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
    return new static(
      $configuration,
      $plugin_id,
      $plugin_definition,
      $container->get('serializer'),
      $container->get('my_module.product_serializer')
    );
  }

  public function render($unserialized) {
    // 从Views结果中提取节点对象
    $nodes = [];
    foreach ($unserialized as $row) {
      if (isset($row->_entity) && $row->_entity instanceof NodeInterface) {
        $nodes[] = $row->_entity;
      }
    }

    return $this->productSerializer->serializeProducts($nodes);
  }
}

4. 在钩子中调用新服务

修改modules/custom/my_module/my_module.module:

<?php

function my_module_node_update($node) {
  if ($node->getType() == 'product') {
    $nids = \Drupal::entityQuery('node')
      ->condition('type', 'product')
      ->execute();
    $nodes = \Drupal\node\Entity\Node::loadMultiple($nids);
    
    // 调用自定义序列化服务
    $serializer = \Drupal::service('my_module.product_serializer');
    $result = $serializer->serializeProducts($nodes);
    
    // 使用Drupal文件系统API更安全
    $filePath = \Drupal::service('file_system')->realpath('public://products.json');
    file_put_contents($filePath, $result);
  }
}

方案二:直接实例化Views插件(临时方案)

如果不想重构代码,可以尝试直接实例化CustomizedSerializer,但需要模拟Views的运行环境(可能存在隐藏依赖,不推荐长期使用):

<?php

function my_module_node_update($node) {
  if ($node->getType() == 'product') {
    $nids = \Drupal::entityQuery('node')
      ->condition('type', 'product')
      ->execute();
    $nodes = \Drupal\node\Entity\Node::loadMultiple($nids);
    
    // 模拟Views行数据结构(插件render方法接收的是Views结果格式)
    $unserialized = [];
    foreach ($nodes as $node) {
      $unserialized[] = (object) ['_entity' => $node];
    }

    // 实例化Views样式插件
    $pluginManager = \Drupal::service('plugin.manager.views.style');
    $serializerPlugin = $pluginManager->createInstance('customized_serializer', []);
    
    // 调用插件的render方法
    $result = $serializerPlugin->render($unserialized);
    
    $filePath = \Drupal::service('file_system')->realpath('public://products.json');
    file_put_contents($filePath, $result);
  }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.25 23:47:45