HttpKernel类是Symfony2的核心类,负责处理客户端的请求。它的主要目标是将Request对象“转换”成Response对象。

每个Symfony2的Kernel都实现HttpKernelInterface接口:

  1. function handle(Request $request, $type = self::MASTER_REQUEST, $catch = true) 

控制器

要将Request转换成Response,Kernel依赖“控制器”。控制器可以是任一有效的PHP调用。

Kernel代表控制器选择应该执行哪个ControllerResolverInterface实现:

  1. public function getController(Request $request); 
  2.  
  3. public function getArguments(Request $request, $controller); 

getController()方法返回与给定Request相关的控制器(一个PHP调用)。缺省实现 (ControllerResolver) 查找请求参数_controller,该参数代表控制器名称(一个"class::method"字符串,如Bundle\BlogBundle\PostController:indexAction)。 

该缺省实现使用RequestListener去定义_controller请求属性(参见 kernel-core_request)。

getArguments()方法返回一个发送给控制器调用的参数数组。缺省实现基于Request属性自动解析方法参数。

从Request属性匹配控制器方法参数

对于每个访问参数,Symfony2尝试从Request的同名属性中取值。如果没有定义则需要参数的缺省值:

  1. // Symfony2 will look for an 'id' attribute (mandatory) 
  2. // and an 'admin' one (optional) 
  3. public function showAction($id, $admin = true) 
  4.     // ... 

处理请求

handle()方法接受一个Request并总是返回一个Response。为转换Request,handle()依赖Resolver和一个Event通知的步骤(每个Event的详细信息参见下一章节):

  1. 在做其它任何事之前,发送core.request事件通知。如果监听器返回Response,则直接跳到步骤8;
  2. 调用Resolver以确定执行Controller;
  3. core.response事件监听器现在可以按它们希望的方式(改变它、封装它...)调用Controller;
  4. Kernel检查Controller实际是一个有效的PHP调用;
  5. 调用Resolver以确定发送给Controller的参数;

如果在处理过程中抛出一个异常,那么发送core.exception事件通知,监听器将得到一个改变去将异常转换成Response。如果正常工作,那么发送core.response事件通知;否则将再次抛出异常。

如果你不想异常被捕获(如内嵌的请求),那么发送false给handle()方法的第3个参数,禁用core.exception事件。

内部请求

有时,在处理请求(“主”请求)时,可以处理子请求。你可以将请求类型发送到handle()方法(它是第2个参数):

  • HttpKernelInterface::MASTER_REQUEST;
  • HttpKernelInterface::SUB_REQUEST.

事件和监听器可以根据发送的类型处理(一些进程只能在主请求中发生)。

事件

每个通过Kernel抛出的事件都是KernelEvent的子类。这就是说每个事件都可以访问到相同的基本信息:

  • getRequestType() - 返回请求类型 (HttpKernelInterface::MASTER_REQUEST或 HttpKernelInterface::SUB_REQUEST);
  • getKernel() - 返回处理请求的Kernel;
  • getRequest() - 返回当前正在处理的Request。

getRequestType()

getRequestType()方法可以让监听器知道请求类型。例如,如果监听器只能被主请求激活,那么在你监听器方法的开始添加以下代码:

  1. use Symfony\Component\HttpKernel\HttpKernelInterface; 
  2.  
  3. if (HttpKernelInterface::MASTER_REQUEST !== $event->getRequestType()) { 
  4.     // return immediately 
  5.     return; 

如果你对Symfony2事件调度不熟的话,请先查看调度章节。

core.request事件

事件类:GetResponseEvent

该事件的目标是立即返回一个Response对象或设置变量,以便可以在事件后调用Controller。任何监听器都可以通过在事件的setResponse()方法返回一个Response对象。在这种情况下,其它所有监听器都不会被调用。

该事件被FrameworkBundle通过RequestListener来填充_controller请求属性。RequestListener使用RouterInterface对象来匹配Request,并确定Controller名(保存在_controller请求属性中)

core.controller事件

事件类:FilterControllerEvent

该事件没有被FrameworkBundle使用,但可以作为修改应该执行控制器的切入点:

  1. use Symfony\Component\HttpKernel\Event\FilterControllerEvent; 
  2.  
  3. public function onCoreController(FilterControllerEvent $event) 
  4.     $controller = $event->getController(); 
  5.     // ... 
  6.  
  7.     // the controller can be changed to any PHP callable 
  8.     $event->setController($controller); 

core.view事件

事件类:GetResponseForControllerResultEvent

该事件没有被FrameworkBundle使用,但它可以用来实现一个视图子系统。该事件仅当Controller没有返回Response对象时被调用。该事件的目的是让其它的返回值转换成Response。

通过Controller返回的值可以由getControllerResult方法访问:

  1. use Symfony\Component\HttpKernel\Event\GetResponseForControllerResultEvent; 
  2. use Symfony\Component\HttpFoundation\Response; 
  3.  
  4. public function onCoreView(GetResponseForControllerResultEvent $event) 
  5.     $val = $event->getReturnValue(); 
  6.     $response = new Response(); 
  7.     // some how customize the Response from the return value 
  8.  
  9.     $event->setResponse($response); 

core.response事件

事件类:lterResponseEvent

该事件目标是在其被创建后让其它系统去修改或替代Response对象:

  1. public function onCoreResponse(FilterResponseEvent $event) 
  2.     $response = $event->getResponse(); 
  3.     // .. modify the response object 

FrameworkBundle注册几个监听器:

core.exception事件

事件类:GetResponseForExceptionEvent

FrameworkBundle注册一个将Request转发给指定Controller(exception_listener.controller参数的值必须在class::method注释中)的ExceptionListener

该事件的监听器可以创建和设置一个Response对象,或者什么也不做:

  1. use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent; 
  2. use Symfony\Component\HttpFoundation\Response; 
  3.  
  4. public function onCoreException(GetResponseForExceptionEvent $event) 
  5.     $exception = $event->getException(); 
  6.     $response = new Response(); 
  7.     // setup the Response object based on the caught exception 
  8.     $event->setResponse($response); 
  9.  
  10.     // you can alternatively set a new Exception 
  11.     // $exception = new \Exception('Some special exception'); 
  12.     // $event->setException($exception); 
  13. }