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

Shopware 6(Symfony)中抽象类与依赖注入实现方案问询

基于Shopware 6的抽象类+依赖注入重构方案

针对你的需求,我们可以通过抽象类封装通用逻辑+依赖注入注入具体仓库的方式来重构,下面是适合刚接触OOP的一步步实现方案:

1. 编写抽象基础服务类

先把所有实体通用的方法(比如获取ID、增改实体)抽到抽象类里,这个类作为所有实体服务的“模板”,只定义通用逻辑,不处理具体业务。

<?php

namespace YourPlugin\Service;

use Shopware\Core\Framework\Context;
use Shopware\Core\Framework\DataAbstractionLayer\EntityRepository;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
use Shopware\Core\Framework\DataAbstractionLayer\Search\IdSearchResult;

abstract class AbstractEntityService
{
    // 子类需要注入具体的实体仓库
    protected EntityRepository $repository;

    // 构造函数接收仓库实例,所有子类都会继承这个构造逻辑
    public function __construct(EntityRepository $repository)
    {
        $this->repository = $repository;
    }

    /**
     * 根据过滤条件获取实体ID列表
     */
    public function getEntityIds(array $filters, Context $context): array
    {
        $criteria = new Criteria();
        foreach ($filters as $filter) {
            $criteria->addFilter($filter);
        }

        /** @var IdSearchResult $result */
        $result = $this->repository->searchIds($criteria, $context);

        return $result->getIds();
    }

    /**
     * 通用的实体增改方法(upsert:存在则更新,不存在则创建)
     */
    public function upsertEntity(array $data, Context $context): void
    {
        $this->repository->upsert($data, $context);
    }

    /**
     * 根据ID获取单个实体
     */
    public function getEntityById(string $id, Context $context): ?object
    {
        $criteria = new Criteria([$id]);
        $result = $this->repository->search($criteria, $context);

        return $result->first();
    }
}

2. 创建子类适配具体实体仓库

针对商品、分类等不同实体,创建对应的子类继承抽象类,只需要实现该实体专属的业务逻辑,通用方法直接继承即可。

商品服务子类

<?php

namespace YourPlugin\Service;

use Shopware\Core\Framework\Context;

class ProductService extends AbstractEntityService
{
    // 商品专属业务:更新库存
    public function updateStock(string $productId, int $stock, Context $context): void
    {
        // 直接调用抽象类的upsert方法,不用重复写仓库操作
        $this->upsertEntity([
            [
                'id' => $productId,
                'stock' => $stock
            ]
        ], $context);
    }
}

分类服务子类

<?php

namespace YourPlugin\Service;

use Shopware\Core\Framework\Context;

class CategoryService extends AbstractEntityService
{
    // 分类专属业务:更新分类排序
    public function updateCategoryPosition(string $categoryId, int $position, Context $context): void
    {
        $this->upsertEntity([
            [
                'id' => $categoryId,
                'position' => $position
            ]
        ], $context);
    }
}

3. 配置依赖注入(services.xml)

Shopware 6基于Symfony,所以需要在插件的src/Resources/config/services.xml里配置服务,告诉容器如何注入具体的实体仓库:

<?xml version="1.0" ?>

<container xmlns="http://symfony.com/schema/dic/services"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">

    <services>
        <!-- 抽象服务:标记为abstract,不会被实例化,仅作为子类的父模板 -->
        <service id="YourPlugin\Service\AbstractEntityService" abstract="true">
            <argument type="service" id="Shopware\Core\Framework\DataAbstractionLayer\EntityRepository"/>
        </service>

        <!-- 商品服务:继承抽象服务,替换参数为Shopware内置的商品仓库 -->
        <service id="YourPlugin\Service\ProductService" parent="YourPlugin\Service\AbstractEntityService">
            <argument type="service" id="product.repository"/>
        </service>

        <!-- 分类服务:继承抽象服务,替换参数为Shopware内置的分类仓库 -->
        <service id="YourPlugin\Service\CategoryService" parent="YourPlugin\Service\AbstractEntityService">
            <argument type="service" id="category.repository"/>
        </service>
    </services>
</container>

注:Shopware内置的实体仓库ID格式为{实体名}.repository,比如商品是product.repository,分类是category.repository,直接使用即可。

4. 在业务代码中使用

比如在控制器里注入子类服务,直接调用通用或专属方法:

<?php

namespace YourPlugin\Controller;

use YourPlugin\Service\ProductService;
use YourPlugin\Service\CategoryService;
use Shopware\Core\Framework\Context;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\EqualsFilter;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;

#[Route(defaults: ['_routeScope' => ['api']])]
class EntityController extends AbstractController
{
    // 构造函数注入子类服务
    public function __construct(
        private readonly ProductService $productService,
        private readonly CategoryService $categoryService
    ) {}

    #[Route(path: '/api/v{version}/your-plugin/active-product-ids', methods: ['GET'])]
    public function getActiveProductIds(Context $context): Response
    {
        // 调用抽象类的通用方法获取启用状态的商品ID
        $filters = [new EqualsFilter('active', true)];
        $productIds = $this->productService->getEntityIds($filters, $context);

        return $this->json(['active_product_ids' => $productIds]);
    }

    #[Route(path: '/api/v{version}/your-plugin/update-category-position', methods: ['POST'])]
    public function updateCategoryPosition(string $categoryId, int $position, Context $context): Response
    {
        // 调用分类服务的专属方法
        $this->categoryService->updateCategoryPosition($categoryId, $position, $context);

        return $this->json(['success' => true]);
    }
}

核心逻辑说明

  • 抽象类的价值:把重复的通用逻辑封装起来,子类只需要关注自身专属业务,避免代码冗余;抽象类不能直接实例化,必须被继承。
  • 依赖注入的作用:把实体仓库的实例化交给Symfony容器,代码解耦,后续替换仓库(比如测试用Mock仓库)时不需要修改业务代码。
  • Shopware的仓库注入:直接使用官方内置的仓库ID即可,不需要自己实例化仓库类。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 19:50:26