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

如何在Shopware中扩展搜索结果以包含外部API查询的实体

解决方案:Shopware搜索结果添加外部产品

一、修复搜索结果计数与排序问题

你之前只往ProductSearchResult的items里添加外部产品,但没同步更新total属性——这个属性是独立维护的,不会自动根据items数量计算,所以才会出现计数和实际条目不符的情况。同时要确保外部产品始终排在内部结果之后,具体实现步骤如下:

事件订阅者代码实现

创建事件订阅类,在ProductSearchResultEvent中合并内部、外部结果并更新计数:

<?php

namespace YourPlugin\Subscriber;

use Shopware\Core\Content\Product\Events\ProductSearchResultEvent;
use Shopware\Core\Content\Product\ProductEntity;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;

class ExternalProductSearchSubscriber implements EventSubscriberInterface
{
    public static function getSubscribedEvents(): array
    {
        return [
            ProductSearchResultEvent::class => 'onProductSearchResult',
        ];
    }

    public function onProductSearchResult(ProductSearchResultEvent $event): void
    {
        $searchResult = $event->getResult();
        $internalItems = $searchResult->getItems();
        $internalTotal = $searchResult->getTotal();

        // 调用外部API获取匹配的产品
        $externalProducts = $this->fetchExternalProducts($event->getSearchTerm());
        // 将外部产品转换为Shopware兼容的ProductEntity(保证前端渲染字段一致)
        $externalItems = $this->mapToProductEntities($externalProducts);

        // 合并结果:内部在前,外部在后
        $mergedItems = array_merge($internalItems, $externalItems);
        $newTotal = $internalTotal + count($externalItems);

        // 更新搜索结果的条目和计数
        $searchResult->setItems($mergedItems);
        $searchResult->setTotal($newTotal);
    }

    private function fetchExternalProducts(string $searchTerm): array
    {
        // 替换为实际外部API调用逻辑
        return [
            ['id' => 'ext-1001', 'name' => '外部产品A', 'price' => 89.99, 'thumbnail' => 'https://example.com/ext-a.jpg'],
            ['id' => 'ext-1002', 'name' => '外部产品B', 'price' => 129.99, 'thumbnail' => 'https://example.com/ext-b.jpg'],
        ];
    }

    private function mapToProductEntities(array $externalProducts): array
    {
        $entities = [];
        // 用固定货币ID(示例为欧元,根据你的Shopware配置调整)
        $defaultCurrencyId = 'b7d2554b0ce847cd82f3ac9bd1c0dfca';

        foreach ($externalProducts as $product) {
            $entity = new ProductEntity();
            $entity->setId($product['id']); // 用自定义前缀(如ext-)避免和内部产品ID冲突
            $entity->setName($product['name']);
            $entity->setPrice([
                [
                    'gross' => $product['price'],
                    'net' => $product['price'] * 0.8,
                    'currencyId' => $defaultCurrencyId
                ]
            ]);
            $entity->setCover([
                'media' => ['url' => $product['thumbnail']]
            ]);
            // 补充其他前端渲染需要的字段(如description、stock等)
            $entities[] = $entity;
        }
        return $entities;
    }
}

二、外部产品详情页处理

因为外部产品未存入Shopware数据库,默认的产品详情路由无法识别,需要通过自定义路由+控制器来实现:

1. 添加自定义路由

在插件的src/Resources/config/routes.xml中定义外部产品详情路由:

<?xml version="1.0" encoding="UTF-8" ?>
<routes xmlns="http://symfony.com/schema/routing"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://symfony.com/schema/routing https://symfony.com/schema/routing/routing-1.0.xsd">

    <route id="frontend.external_product.detail" path="/external-product/{externalId}">
        <default key="_controller">YourPlugin\Controller\ExternalProductController::detail</default>
    </route>
</routes>

2. 实现详情页控制器

创建控制器获取外部产品详情并渲染页面:

<?php

namespace YourPlugin\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;

class ExternalProductController extends AbstractController
{
    #[Route('/external-product/{externalId}', name: 'frontend.external_product.detail', methods: ['GET'])]
    public function detail(string $externalId): Response
    {
        // 调用外部API获取产品详情
        $product = $this->fetchExternalProductDetail($externalId);

        // 复用Shopware默认产品详情模板,或自定义模板
        return $this->render('@YourPlugin/storefront/page/product/detail.html.twig', [
            'product' => $product,
            'isExternal' => true
        ]);
    }

    private function fetchExternalProductDetail(string $externalId): array
    {
        // 替换为实际外部API详情查询逻辑
        return [
            'id' => $externalId,
            'name' => '外部产品A',
            'description' => '这是来自外部API的产品详细描述',
            'price' => 89.99,
            'images' => ['https://example.com/ext-a-detail.jpg'],
            'specs' => ['材质' => '合金', '尺寸' => '30x20cm']
        ];
    }
}

3. 修改前端链接指向

在Shopware的产品卡片模板(如storefront/component/product/card/box-standard.html.twig)中,判断产品ID前缀,将外部产品的链接指向自定义路由:

{% set productUrl = product.id starts with 'ext-' 
    ? path('frontend.external_product.detail', {externalId: product.id}) 
    : seoUrl('frontend.detail.page', {productId: product.id})
%}

<a href="{{ productUrl }}" class="product-box-link" title="{{ product.name }}">
    <!-- 原有卡片内容 -->
</a>

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 06:43:09