Symfony2 DI服务容器优先级/流

标签 symfony dependency-injection request

的故事

让我们以https://nike.awesomedomainname.com/这个要求为例。我需要可以获取nike的服务。

我目前拥有的

我有一项从@request_stack获取路由器 key 的服务。让我们使用公司作为路由器 key 。

我的主要路线如下:

<import host="{company}.domain.{_tld}" prefix="/" schemes="https" resource="@ExampleBundle/Resources/config/routing.xml">
    <default key="_tld">%app_tld%</default>
    <requirement key="_tld">com|dev</requirement>
    <requirement key="company">[a-z0-9]+</requirement>
</import>

因此,我编写了此服务来获取 key 并搜索公司。
...

use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RequestStack;

class CompanyContextRequest {

    protected $request;
    protected $companyRepository;

    public function __construct(RequestStack $requestStack, CompanyRepository $companyRepository) {
        $this->request = $requestStack->getMasterRequest();
        $this->companyRepository = $companyRepository;
    }

    public function getCompany()
    {
        if (null !== $this->request)
        {
            $company = $this->request->attributes->get('company');
            if (null !== $company)
            {
                return $this->companyRepository->findOneBy([
                    'key' => $company
                ]);
            }
        }
    }

    ....

}

以及服务xml定义;
<service id="app.company_context_request" class="AppBundle\Request\CompanyContextRequest">
    <argument type="service" id="request_stack"/>
    <argument type="service" id="orm_entity.company_repository"/>
</service>
<service id="app.current_company" class="AppBundle\Entity\Company">
    <factory service="app.company_context_request" method="getCompany"/>
</service>

现在我的问题是,在某些情况下,服务app.current_company不会返回Company对象,而是会给出null

例如,我有一个自定义的UserProvider,它具有CompanyContextRequest作为依赖项来检查用户是否属于公司,但我不能这样做,因为它返回了null

但是它在 Controller 和大多数其他DI地方都可以完美工作。

有什么建议么?诸如事件订阅者之类的服务是否具有优先级?

我尝试过的内容

我已经将范围app.company_context_request设置为request,并试图从容器中获取它。结果错误。
根据Symfony文档,这应该可行。

我运行的是Symfony v2.7.3的最新稳定版本

编辑:我的目标是随时提供一项服务,该服务可以告诉我当前基于子域的公司。

编辑2 :This example几乎是我所需要的,除了在此示例中,他们使用用户公司,而我需要子域中的company(key)。

最佳答案

您的服务app.company_context_request本质上是合成的问题-无法编译,因为此刻没有请求数据。

How to Inject Instances into the Container

为什么在某些地方可以使用?

它适用于在范围内调用服务的情况:在将合成服务Request插入“服务容器”并激活了范围request之后。 request范围设置和RequestStack填充发生在\Symfony\Component\HttpKernel\DependencyInjection\ContainerAwareHttpKernel::handle方法及其父方法中。
UserProvider不起作用,因为其初始化发生在request范围之外:在Request服务激活之前或应用离开范围之后。

如何预防?

  • RequestStack服务保存到service属性,而不是在构造函数中而是在getCompany方法中获取当前请求-调用构造函数Request时可能是未定义的;
    public function __construct(RequestStack $requestStack, CompanyRepository $companyRepository) 
    {
        // You cannot use request at this point cause at initialization of the service there could be no request yet
        $this->requestStack = $requestStack;
        $this->companyRepository = $companyRepository;
    }
    ...
    public function getCompany()
    {
        $request = $this->requestStack->getMasterRequest();
        if (null !== $request)
    ...
    
  • 添加到服务定义范围request中,并通过container在另一个服务中获取它:当任何服务试图使一个服务超出范围时,它将自动生成异常;否则,它会自动生成异常。您应该注意一些约束:How to Work with Scopes这种方法用于FOS捆绑包中,例如FOSOauthServer

  • 如果您将像1中那样更改代码,则可以保留服务定义不变
    <service id="app.company_context_request" class="AppBundle\Request\CompanyContextRequest">
        <argument type="service" id="request_stack"/>
        <argument type="service" id="orm_entity.company_repository"/>
    </service>
    

    但是current_company应该具有scope。如果在初始化request时未定义Request,则current_company引发异常。或者,如果您想在设置时立即获取scope=prototype,而在current_company不存在时获取null(超出范围,cli调用),则可以使用Request(每次调用都会返回新实例)。
    <service id="app.current_company" class="AppBundle\Entity\Company" scope="request">
        <factory service="app.company_context_request" method="getCompany"/>
    </service>
    

    UPD
    它根本与服务优先级无关。它与容器编译机制有关。某个服务的编译发生在该服务的首次调用上:显式调用或相关服务的编译。

    使用UserProvider路由,当RequestRequestStack中还没有Container对象时,便会编译服务(因此调用__construct)。

    关于Symfony2 DI服务容器优先级/流,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31660224/

    相关文章:

    php - 调用未定义的方法 Symfony\Component\DomCrawler\Crawler::rewind()

    java - 如何解决 'NoSuchBeanDefinitionException: No qualifying bean of type'错误?

    c# - StructureMap 解决跨项目的依赖关系

    AJAX 请求下一页/上一页的帮助

    php - 履带式+喷口 : Accessing to form

    php - 保存实体形式错误 - symfony2

    ios发送带有POST参数的POST请求

    php - 如何在执行函数之前等待 Swift 中的变量? ( swift )

    php - 修改 Sonata Media Bundle 时预览列消失

    c# - 了解为什么我们使用控制反转容器进行单元测试