的故事
让我们以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
路由,当Request
和RequestStack
中还没有Container
对象时,便会编译服务(因此调用__construct)。
关于Symfony2 DI服务容器优先级/流,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31660224/