Symfony - 在接口中获取容器

Symfony - Get a container inside an Interface

我正在使用 symfony 并且需要知道如何将容器注入 EventSubscriberInterface?

我的目标是使用“mail_template_type.repository”。它在控制器中工作正常,但 EventSubscriberInterface 似乎没有容器,或者至少 dumpe($event) 没有显示它。

         /**
         * @var EntityRepositoryInterface $mailTypeRepository
         * @var EntityRepositoryInterface $mailRepository
         */
        $mailTypeRepository = getContainer()->get('mail_template_type.repository');
        $mailRepository = getContainer()->get('mail_template.repository');

完整代码如下:

<?php
namespace RegistrationExtension\Subscriber;

use Shopware\Core\Framework\DataAbstractionLayer\Event\EntityLoadedEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Shopware\Core\Checkout\Customer\CustomerEvents;
use Shopware\Core\Checkout\Customer\CustomerEntity;
use Shopware\Core\System\SalesChannel\SalesChannelContext;
use Shopware\Storefront\Controller\StorefrontController;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\EqualsFilter;
use Shopware\Core\Framework\DataAbstractionLayer\EntityRepositoryInterface;
use Shopware\Core\Checkout\Customer\Event\CustomerRegisterEvent;
use Shopware\Storefront\Page\Account\Login\AccountLoginPageLoadedEvent;
use Symfony\Component\DependencyInjection\ContainerAwareInterface;
use Psr\Container\ContainerInterface;

use RegisterExtension\Struct\RegisterStruct;


class RegisterExtensionSubscriber implements EventSubscriberInterface{
    /**
     * @param ContainerInterface|NULL $container
     */
    public function setContainer(ContainerInterface $container = NULL){
        $this->container = $container;
        return $this;
    }

    /**
     * @return ContainerInterface
     */
    protected function getContainer(){
        return $this->container;
    }
    public static function getSubscribedEvents(): array{
        return [
            AccountLoginPageLoadedEvent::class => 'onCustomRegister'
        ];
    }
    public function onCustomRegister(AccountLoginPageLoadedEvent $event){
        //dump($this->getContainer('mail_template_type.repository'));
        //$event->getPage()->addExtension('custom_struct', new RegisterStruct());
         /**
         * @var EntityRepositoryInterface $mailTypeRepository
         * @var EntityRepositoryInterface $mailRepository
         */
        $mailTypeRepository = getContainer()->get('mail_template_type.repository');
        $mailRepository = getContainer()->get('mail_template.repository');
        
        $mailEntity = $mailTypeRepository->search(
            (new Criteria())->addFilter(new EqualsFilter('mail_template_type.technicalName', "customer_register")),
            $event->getContext()
        );

        $mailTypeId = $mailEntity->getEntities()->first()->getId();


        $mailEntity = $mailRepository->search(
            (new Criteria())->addFilter(new EqualsFilter('mail_template.mailTemplateTypeId', $mailTypeId)),
            $event->getContext()
        );
        
        //$mailEntity->getEntities()->setContentHtml("test");
        $mail = $mailEntity->getEntities();
    }
}
<?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="RegistrationExtension\Storefront\Controller\RegistrationExtensionController" public="true"> </service>
        <service id="RegistrationExtension\Subscriber\RegisterExtensionSubscriber">
            <tag name="kernel.event_subscriber"/>
        </service>
    </services>
</container>

如我的评论所述,您应该利用依赖注入来仅添加您需要的服务,而不是整个容器。

请务必在进行以下更改后清除并预热您的 Symfony 缓存。

自动装配服务

在 Symfony 3.4+ 中,您可以使用 autowire,它会自动将已知的 FQCN 服务注入 __construct,例如使用记录器服务。

vendor/symfony/monolog-bundle/Resources/config/monolog.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="monolog.logger" parent="monolog.logger_prototype" public="false">
            <argument index="0">app</argument>
            <call method="useMicrosecondTimestamps">
                <argument>%monolog.use_microseconds%</argument>
            </call>
        </service>
        <service id="logger" alias="monolog.logger" />

        <service id="Psr\Log\LoggerInterface" alias="logger" public="false" />

        <!-- ... -->

        </service>
    </services>
</container>

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>
        <!-- attempts to inject and tag services automatically -->
        <defaults autowire="true" autoconfigure="true" public="false"/>

        <service id="RegistrationExtension\Storefront\Controller\RegistrationExtensionController" public="true"> </service>
        <service id="RegistrationExtension\Subscriber\RegisterExtensionSubscriber">
            <tag name="kernel.event_subscriber"/>
        </service>
    </services>
</container>

src/RegistrationExtension/Subscriber/RegisterExtensionSubscriber.php

use Psr\Log\LoggerInterface;

class RegisterExtensionSubscriber implements EventSubscriberInterface 
{
    private $logger;

    public function __construct(LoggerInterface $logger) 
    {
         $this->logger = $logger;
    }
}

依赖注入

如果服务无法使用 autowire 注入,因为它使用字符串服务名称而不是 FQCN,您可以在配置中手动声明该服务。

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="RegistrationExtension\Storefront\Controller\RegistrationExtensionController" public="true"> </service>
        <service id="RegistrationExtension\Subscriber\RegisterExtensionSubscriber">
            <argument type="service" id="mail_template_type.repository" />
            <argument type="service" id="mail_template.repository" />
            <tag name="kernel.event_subscriber"/>
        </service>
    </services>
</container>

src/RegistrationExtension/Subscriber/RegisterExtensionSubscriber.php


use Shopware\Core\Framework\DataAbstractionLayer\EntityRepositoryInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
//...

class RegisterExtensionSubscriber implements EventSubscriberInterface 
{

    /**
     * @var EntityRepositoryInterface
     */
    private $mailTypeRepository;

    /**
     * @var EntityRepositoryInterface
     */
    private $mailRepository;

    public function __construct(
        EntityRepositoryInterface $mailTypeRepository,
        EntityRepositoryInterface $mailRepository
    ) {
         $this->mailTypeRepository = $mailTypeRepository;
         $this->mailRepository = $mailRepository;
    }

    public function onCustomRegister(AccountLoginPageLoadedEvent $event)
    {        
        $mailEntity = $this->mailTypeRepository->search(
            (new Criteria())->addFilter(new EqualsFilter('mail_template_type.technicalName', "customer_register")),
            $event->getContext()
        );

        if ($mailType = $mailEntity->getEntities()->first()) {
            $mailEntity = $this->mailRepository->search(
                (new Criteria())->addFilter(new EqualsFilter('mail_template.mailTemplateTypeId', $mailType->getId())),
                $event->getContext()
            );
        
            $mail = $mailEntity->getEntities();
            //...
        }
    }
}