Sne*_*nek 9 dependency-injection request symfony
故事
我们以此请求https://nike.awesomedomainname.com/
为例.我需要一个可以获取的服务nike
.
我现在有什么
我有一个从服务器获取路由器密钥的服务@request_stack
.让我们使用公司作为路由器密钥.
我的主要路线如下;
<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>
Run Code Online (Sandbox Code Playgroud)
所以我写了这个服务来获取密钥并搜索公司;
...
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
]);
}
}
}
....
}
Run Code Online (Sandbox Code Playgroud)
和服务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>
Run Code Online (Sandbox Code Playgroud)
现在我的问题是,在某些情况下,服务app.current_company
不会返回一个Company
对象,而是null
给出了一个.
比如我有一个自定义的UserProvider
具有CompanyContextRequest
作为依赖检查,如果用户属于公司,但我不能这样做,因为它返回null
.
但它在控制器和大多数其他DI位置都能很好地工作.
有什么建议?是否有像活动订阅者这样的服务的优先级?
我试过的
我已将范围设置app.company_context_request
为request
并尝试从容器中获取它.结果不对.根据Symfony文档,这应该工作.
我运行最新的稳定版Symfony v2.7.3
编辑:我的目标是随时提供服务,告诉我当前的公司是基于子域的.
编辑2:这个例子几乎是我需要的,除了在这个例子中他们使用用户公司,我需要来自子域的公司(密钥).
app.company_context_request
您的服务本质上是合成的问题- 您无法编译,因为此时没有请求数据。
为什么它在某些地方有效?
它适用于调用范围内的服务的情况:将合成服务Request
插入服务容器并request
激活范围后。request
范围设置和RequestStack
填充发生在\Symfony\Component\HttpKernel\DependencyInjection\ContainerAwareHttpKernel::handle
方法及其父方法中。
UserProvider
不起作用,因为它的初始化发生在request
范围之外:在Request
服务激活之前或应用程序离开范围之后。
如何预防呢?
将服务保存RequestStack
到服务属性并不在构造函数中而是在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)
...
Run Code Online (Sandbox Code Playgroud)添加到服务定义范围request
并通过另一个服务内部获取它container
:当任何服务尝试使该服务超出范围时,它将自动生成异常;您应该注意一些限制:如何使用范围这种方式用于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>
Run Code Online (Sandbox Code Playgroud)
但current_company
应该有scope
。如果在初始化时未定义,request
则抛出异常。或者,如果您想在它被设置的时刻以及在不存在的时刻(超出范围,cli 调用),您可以使用(它将在每次调用时返回新实例)。Request
current_company
scope=prototype
current_company
null
Request
<service id="app.current_company" class="AppBundle\Entity\Company" scope="request">
<factory service="app.company_context_request" method="getCompany"/>
</service>
Run Code Online (Sandbox Code Playgroud)
UPD 与服务优先级完全无关。这和容器编译机制有关。特定服务的编译发生在首次调用该服务时:显式调用或依赖服务的编译时。
通过UserProvider
路由编译您的服务(因此调用 __construct )发生在Request
对象尚未RequestStack
在Container
.
归档时间: |
|
查看次数: |
790 次 |
最近记录: |