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

如何在Shopware的自定义非继承类中访问数据库层(无需container->get()或DI服务)

在Shopware自定义类中无需手动获取容器即可访问数据库的解决方案

首先,Shopware的最佳实践绝对不推荐手动调用container->get()或者直接获取容器实例——这会破坏依赖注入的设计原则,让代码难以测试和维护。你的DiscountCollector已经通过构造函数注入了PercentagePriceCalculator,我们只需要沿用这个模式,注入你需要的数据库访问类即可。

方法1:注入Shopware专用Repository(推荐)

Shopware为每个实体都提供了专用的Repository类,这些类封装了Doctrine的数据库操作,并且适配Shopware的上下文系统(比如多语言、多店铺)。

步骤1:修改类的构造函数,注入目标Repository

比如如果你需要操作产品数据,就注入ProductRepository:

<?php declare(strict_types=1);
namespace Author\\PriceDiscountPlugin\\Handlers;

use Shopware\\Core\\Checkout\\Cart\\Cart;
use Shopware\\Core\\Checkout\\Cart\\CartBehavior;
use Shopware\\Core\\Checkout\\Cart\\CartProcessorInterface;
use Shopware\\Core\\Checkout\\Cart\\LineItem\\CartDataCollection;
use Shopware\\Core\\Checkout\\Cart\\LineItem\\LineItem;
use Shopware\\Core\\Checkout\\Cart\\LineItem\\LineItemCollection;
use Shopware\\Core\\Checkout\\Cart\\Price\\PercentagePriceCalculator;
use Shopware\\Core\\Checkout\\Cart\\Price\\Struct\\PercentagePriceDefinition;
use Shopware\\Core\\Checkout\\Cart\\Rule\\LineItemRule;
use Shopware\\Core\\System\\SalesChannel\\SalesChannelContext;
// 引入需要的Repository和查询条件类
use Shopware\\Core\\Content\\Product\\ProductRepository;
use Shopware\\Core\\Framework\\DataAbstractionLayer\\Search\\Criteria;

class DiscountCollector implements CartProcessorInterface
{
    /**
     * @var PercentagePriceCalculator
     */
    private $calculator;
    
    /**
     * @var ProductRepository
     */
    private $productRepository;

    // 修改构造函数,注入ProductRepository
    public function __construct(PercentagePriceCalculator $calculator, ProductRepository $productRepository)
    {
        $this->calculator = $calculator;
        $this->productRepository = $productRepository;
    }

    public function process(CartDataCollection $data, Cart $original, Cart $toCalculate, SalesChannelContext $context, CartBehavior $behavior): void
    {
        // 示例:查询某个产品
        $productId = '...'; // 替换成你的目标产品ID
        $criteria = new Criteria([$productId]);
        // 必须传入context的内部Context对象,适配多语言/多店铺数据
        $product = $this->productRepository->search($criteria, $context->getContext())->first();
        
        // 接下来就可以使用$product的属性,比如$product->getPrice()、$product->getName()
        // 你的数据库操作逻辑...
    }
}

步骤2:在插件中注册服务

Shopware的DI容器只会自动注入已注册的服务,所以你需要在插件的配置文件中声明这个类的服务:

如果使用XML配置(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>
        <service id="Author\PriceDiscountPlugin\Handlers\DiscountCollector">
            <argument type="service" id="Shopware\Core\Checkout\Cart\Price\PercentagePriceCalculator"/>
            <argument type="service" id="Shopware\Core\Content\Product\ProductRepository"/>
        </service>
    </services>
</container>

如果使用PHP配置(src/Resources/config/services.php):

use Author\PriceDiscountPlugin\Handlers\DiscountCollector;
use Shopware\Core\Checkout\Cart\Price\PercentagePriceCalculator;
use Shopware\Core\Content\Product\ProductRepository;
use Symfony\Component\DependencyInjection\ContainerConfigurator;

return static function (ContainerConfigurator $containerConfigurator): void {
    $services = $containerConfigurator->services();

    $services->set(DiscountCollector::class)
        ->arg('$calculator', service(PercentagePriceCalculator::class))
        ->arg('$productRepository', service(ProductRepository::class));
};

方法2:注入通用EntityManagerInterface

如果你需要执行更灵活的Doctrine原生操作(比如自定义DQL),可以注入EntityManagerInterface:

步骤1:修改构造函数注入EntityManager

// 引入Doctrine的EntityManager接口
use Doctrine\ORM\EntityManagerInterface;
use Shopware\Core\Content\Product\ProductEntity;

class DiscountCollector implements CartProcessorInterface
{
    /**
     * @var PercentagePriceCalculator
     */
    private $calculator;
    
    /**
     * @var EntityManagerInterface
     */
    private $entityManager;

    public function __construct(PercentagePriceCalculator $calculator, EntityManagerInterface $entityManager)
    {
        $this->calculator = $calculator;
        $this->entityManager = $entityManager;
    }

    public function process(CartDataCollection $data, Cart $original, Cart $toCalculate, SalesChannelContext $context, CartBehavior $behavior): void
    {
        // 示例:通过Doctrine Repository查询
        $productRepository = $this->entityManager->getRepository(ProductEntity::class);
        $product = $productRepository->findOneBy(['id' => $productId], null, $context->getContext());
        
        // 或者执行自定义DQL查询
        $query = $this->entityManager->createQuery(
            'SELECT p FROM Shopware\Core\Content\Product\ProductEntity p WHERE p.id = :productId'
        )->setParameter('productId', $productId);
        
        $product = $query->getOneOrNullResult();
    }
}

步骤2:注册服务时注入EntityManager

XML配置中替换第二个参数:

<argument type="service" id="Doctrine\ORM\EntityManagerInterface"/>

PHP配置中:

->arg('$entityManager', service(EntityManagerInterface::class))

关键注意事项

  • 永远不要手动获取容器:依赖注入是Shopware和Symfony的核心设计,手动调用container->get()会让代码耦合度极高,难以测试和扩展。
  • 必须传递Context对象:Shopware的SalesChannelContext包含当前的店铺、语言、用户等上下文信息,传递给Repository的search方法才能确保获取到正确的数据(比如多语言的产品名称)。
  • 优先使用Shopware专用Repository:专用Repository已经适配了Shopware的数据结构和业务逻辑,比直接使用Doctrine的EntityManager更符合Shopware的开发规范。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.29 10:02:32