Php Symfony-更改控制器的实例化和执行方式
注意:从2.8版开始,Symfony为服务配置提供了Php Symfony-更改控制器的实例化和执行方式,php,symfony,Php,Symfony,注意:从2.8版开始,Symfony为服务配置提供了autowire:true,从3.3版开始,Symfony提供了alias(而不是autowire\u类型)来将具体对象别名到接口,以便将依赖项自动注入到“控制器即服务”中。还有一个包允许控制器“动作”方法的自动接线,尽管我已经离开了这个包,并且更多地关注ADR模式的变化(基本上,这是一个带有接口方法的单个“action”类,而不是在单个类中推送一堆actions方法,最终导致架构噩梦)。这就是我多年来一直在寻找的,现在不再需要“钩住”一个像样
autowire:true
,从3.3版开始,Symfony提供了alias
(而不是autowire\u类型
)来将具体对象别名到接口,以便将依赖项自动注入到“控制器即服务”中。还有一个包允许控制器“动作”方法的自动接线,尽管我已经离开了这个包,并且更多地关注ADR模式的变化(基本上,这是一个带有接口方法的单个“action”类,而不是在单个类中推送一堆actions方法,最终导致架构噩梦)。这就是我多年来一直在寻找的,现在不再需要“钩住”一个像样的递归依赖注入程序(auryn)由于框架现在处理的是四年前应该有的东西,我将把这个答案留在这里,以防有人想跟踪我所做的步骤,看看内核是如何工作的,以及这个级别上的一些可用选项
注意:尽管这个问题主要针对Symfony 3,但它也应该与Symfony 2的用户相关,因为内核逻辑似乎没有太大变化 我想更改控制器在Symfony中的实例化方式。它们的实例化逻辑当前位于,更具体地说,。我想用我自己的执行该特定行的注入器替换
call\u user\u func\u array($controller,$arguments)
到目前为止,我尝试了以下几种选择:
- 用我自己的方法扩展
,然后由symfony调用HttpKernel::handle
- 创建和注册新的控制器冲突解决程序
routes.yml
获取路由,并找出作为可调用的控制器调用的类和方法可呼叫
- 在
内核上添加事件侦听器。请求
- 收听事件
call\u user\u func\u array()
我已经记录了我的想法,但我已经出局了。我如何才能实现以下目标
- 更改控制器的实例化和执行方式,特别是
call\u user\u func\u array()
- 如果我的控制器实例化不起作用,请返回默认控制器实例化
- 允许其他一切按预期工作,如分析器加载
- 能够将其与其他用户的扩展捆绑在一起
我为什么要这样做
控制器可以针对不同的情况使用许多不同的方法,每个方法都应该能够针对其各自需要的内容键入提示,而不是让构造函数获取所有内容,其中一些内容甚至可能无法使用,具体取决于正在执行的控制器方法这是一个“对象边缘情况”,但它们就是这样
我想用我自己的递归自动连接注入器来替换控制器的创建方式,以及它们的执行方式,再次使用通过我的注入器的递归自省,因为默认的Symfony软件包似乎没有此功能。即使使用最新的“autowire”Symfony 2.8+中的服务选项。为什么不从自定义ControllerResolverInterface
返回您自己的可调用项,以您想要的方式实例化控制器并调用它
它基本上是一个装饰师
您可以使用自己的instanceController()
方法实现来扩展Symfony\Component\HttpKernel\Controller\ControllerResolver
,也可以从头开始实现ControllerResolverInterface
UPD:
当Symfony调用用户函数数组($controller,$arguments);
调用handleRaw()
时,$controller
变量是您从自定义的ControllerResolver
返回的。这意味着您可以从解析程序返回任何可调用的内容(可以是[$this,“callController”]
f.e.)在这个callable中,您可以使用Auryn创建一个新的控制器
,并调用它
UPD2:
如果你还在为此挣扎,我将添加一个例子,因为你可能会错过我在这里的意思
use Symfony\Bundle\FrameworkBundle\Controller\ControllerResolver;
class AutowiringControllerResolver extends ControllerResolver
{
// ... constructor stuff; assume $injector is a part of this class
protected function createController($controller)
{
$controller = parent::createController($controller);
return function (...$arguments) use ($controller) {
// you can do with resolved $arguments whatever you want
// or you can override getArguments() method and return
// empty array to discard getArguments() functionality completely
return $this->injector->execute($controller);
};
}
protected function instantiateController($classname)
{
return $this->injector->make($classname);
}
}
控制器解析器实际上做两件事。第一件是获取控制器。第二件是获取给定操作的参数列表<
controller_resolver:
class: AppBundle\ControllerResolver
arguments: []
kernel.request:
class: MyCustomRequestListener
tags:
- { name: kernel.event_listener, event: kernel.request, method: onKernelRequest, priority: 33 /** Important, we'll get to why in a minute **/ }
use Symfony\Bundle\FrameworkBundle\Controller\ControllerResolver;
class AutowiringControllerResolver extends ControllerResolver
{
// ... constructor stuff; assume $injector is a part of this class
protected function createController($controller)
{
$controller = parent::createController($controller);
return function (...$arguments) use ($controller) {
// you can do with resolved $arguments whatever you want
// or you can override getArguments() method and return
// empty array to discard getArguments() functionality completely
return $this->injector->execute($controller);
};
}
protected function instantiateController($classname)
{
return $this->injector->make($classname);
}
}
$arguments = $this->resolver->getArguments($request, $controller);
$response = call_user_func_array($controller, $arguments);