2015-08-18 00:00:26 +00:00
< ? php
/*
* This file is part of the Symfony package .
*
* ( c ) Fabien Potencier < fabien @ symfony . com >
*
* For the full copyright and license information , please view the LICENSE
* file that was distributed with this source code .
*/
namespace Symfony\Component\HttpKernel ;
2018-11-23 12:29:20 +00:00
use Symfony\Component\EventDispatcher\EventDispatcherInterface ;
use Symfony\Component\HttpFoundation\Exception\RequestExceptionInterface ;
use Symfony\Component\HttpFoundation\Request ;
use Symfony\Component\HttpFoundation\RequestStack ;
use Symfony\Component\HttpFoundation\Response ;
use Symfony\Component\HttpKernel\Controller\ArgumentResolver ;
use Symfony\Component\HttpKernel\Controller\ArgumentResolverInterface ;
2015-08-18 00:00:26 +00:00
use Symfony\Component\HttpKernel\Controller\ControllerResolverInterface ;
2018-11-23 12:29:20 +00:00
use Symfony\Component\HttpKernel\Event\FilterControllerArgumentsEvent ;
2015-08-18 00:00:26 +00:00
use Symfony\Component\HttpKernel\Event\FilterControllerEvent ;
use Symfony\Component\HttpKernel\Event\FilterResponseEvent ;
use Symfony\Component\HttpKernel\Event\FinishRequestEvent ;
use Symfony\Component\HttpKernel\Event\GetResponseEvent ;
use Symfony\Component\HttpKernel\Event\GetResponseForControllerResultEvent ;
use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent ;
use Symfony\Component\HttpKernel\Event\PostResponseEvent ;
2018-11-23 12:29:20 +00:00
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException ;
use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface ;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException ;
2015-08-18 00:00:26 +00:00
/**
* HttpKernel notifies events to convert a Request object to a Response one .
*
* @ author Fabien Potencier < fabien @ symfony . com >
*/
class HttpKernel implements HttpKernelInterface , TerminableInterface
{
protected $dispatcher ;
protected $resolver ;
protected $requestStack ;
2018-11-23 12:29:20 +00:00
private $argumentResolver ;
2015-08-18 00:00:26 +00:00
2018-11-23 12:29:20 +00:00
public function __construct ( EventDispatcherInterface $dispatcher , ControllerResolverInterface $resolver , RequestStack $requestStack = null , ArgumentResolverInterface $argumentResolver = null )
2015-08-18 00:00:26 +00:00
{
$this -> dispatcher = $dispatcher ;
$this -> resolver = $resolver ;
$this -> requestStack = $requestStack ? : new RequestStack ();
2018-11-23 12:29:20 +00:00
$this -> argumentResolver = $argumentResolver ;
if ( null === $this -> argumentResolver ) {
@ trigger_error ( sprintf ( 'As of 3.1 an %s is used to resolve arguments. In 4.0 the $argumentResolver becomes the %s if no other is provided instead of using the $resolver argument.' , ArgumentResolverInterface :: class , ArgumentResolver :: class ), E_USER_DEPRECATED );
// fallback in case of deprecations
$this -> argumentResolver = $resolver ;
}
2015-08-18 00:00:26 +00:00
}
/**
* { @ inheritdoc }
*/
public function handle ( Request $request , $type = HttpKernelInterface :: MASTER_REQUEST , $catch = true )
{
$request -> headers -> set ( 'X-Php-Ob-Level' , ob_get_level ());
try {
return $this -> handleRaw ( $request , $type );
} catch ( \Exception $e ) {
2018-11-23 12:29:20 +00:00
if ( $e instanceof RequestExceptionInterface ) {
$e = new BadRequestHttpException ( $e -> getMessage (), $e );
2017-02-03 00:28:38 +00:00
}
2015-08-18 00:00:26 +00:00
if ( false === $catch ) {
$this -> finishRequest ( $request , $type );
throw $e ;
}
return $this -> handleException ( $e , $request , $type );
}
}
/**
* { @ inheritdoc }
*/
public function terminate ( Request $request , Response $response )
{
$this -> dispatcher -> dispatch ( KernelEvents :: TERMINATE , new PostResponseEvent ( $this , $request , $response ));
}
/**
* @ internal
*/
2018-11-23 12:29:20 +00:00
public function terminateWithException ( \Exception $exception , Request $request = null )
2015-08-18 00:00:26 +00:00
{
2018-11-23 12:29:20 +00:00
if ( ! $request = $request ? : $this -> requestStack -> getMasterRequest ()) {
throw $exception ;
2015-08-18 00:00:26 +00:00
}
$response = $this -> handleException ( $exception , $request , self :: MASTER_REQUEST );
$response -> sendHeaders ();
$response -> sendContent ();
$this -> terminate ( $request , $response );
}
/**
* Handles a request to convert it to a response .
*
* Exceptions are not caught .
*
* @ param Request $request A Request instance
* @ param int $type The type of the request ( one of HttpKernelInterface :: MASTER_REQUEST or HttpKernelInterface :: SUB_REQUEST )
*
* @ return Response A Response instance
*
* @ throws \LogicException If one of the listener does not behave as expected
* @ throws NotFoundHttpException When controller cannot be found
*/
private function handleRaw ( Request $request , $type = self :: MASTER_REQUEST )
{
$this -> requestStack -> push ( $request );
// request
$event = new GetResponseEvent ( $this , $request , $type );
$this -> dispatcher -> dispatch ( KernelEvents :: REQUEST , $event );
if ( $event -> hasResponse ()) {
return $this -> filterResponse ( $event -> getResponse (), $request , $type );
}
// load controller
if ( false === $controller = $this -> resolver -> getController ( $request )) {
throw new NotFoundHttpException ( sprintf ( 'Unable to find the controller for path "%s". The route is wrongly configured.' , $request -> getPathInfo ()));
}
$event = new FilterControllerEvent ( $this , $controller , $request , $type );
$this -> dispatcher -> dispatch ( KernelEvents :: CONTROLLER , $event );
$controller = $event -> getController ();
// controller arguments
2018-11-23 12:29:20 +00:00
$arguments = $this -> argumentResolver -> getArguments ( $request , $controller );
$event = new FilterControllerArgumentsEvent ( $this , $controller , $arguments , $request , $type );
$this -> dispatcher -> dispatch ( KernelEvents :: CONTROLLER_ARGUMENTS , $event );
$controller = $event -> getController ();
$arguments = $event -> getArguments ();
2015-08-18 00:00:26 +00:00
// call controller
2018-11-23 12:29:20 +00:00
$response = \call_user_func_array ( $controller , $arguments );
2015-08-18 00:00:26 +00:00
// view
if ( ! $response instanceof Response ) {
$event = new GetResponseForControllerResultEvent ( $this , $request , $type , $response );
$this -> dispatcher -> dispatch ( KernelEvents :: VIEW , $event );
if ( $event -> hasResponse ()) {
$response = $event -> getResponse ();
}
if ( ! $response instanceof Response ) {
$msg = sprintf ( 'The controller must return a response (%s given).' , $this -> varToString ( $response ));
// the user may have forgotten to return something
if ( null === $response ) {
$msg .= ' Did you forget to add a return statement somewhere in your controller?' ;
}
throw new \LogicException ( $msg );
}
}
return $this -> filterResponse ( $response , $request , $type );
}
/**
* Filters a response object .
*
* @ param Response $response A Response instance
* @ param Request $request An error message in case the response is not a Response object
* @ param int $type The type of the request ( one of HttpKernelInterface :: MASTER_REQUEST or HttpKernelInterface :: SUB_REQUEST )
*
* @ return Response The filtered Response instance
*
* @ throws \RuntimeException if the passed object is not a Response instance
*/
private function filterResponse ( Response $response , Request $request , $type )
{
$event = new FilterResponseEvent ( $this , $request , $type , $response );
$this -> dispatcher -> dispatch ( KernelEvents :: RESPONSE , $event );
$this -> finishRequest ( $request , $type );
return $event -> getResponse ();
}
/**
* Publishes the finish request event , then pop the request from the stack .
*
* Note that the order of the operations is important here , otherwise
* operations such as { @ link RequestStack :: getParentRequest ()} can lead to
* weird results .
*
* @ param Request $request
* @ param int $type
*/
private function finishRequest ( Request $request , $type )
{
$this -> dispatcher -> dispatch ( KernelEvents :: FINISH_REQUEST , new FinishRequestEvent ( $this , $request , $type ));
$this -> requestStack -> pop ();
}
/**
* Handles an exception by trying to convert it to a Response .
*
* @ param \Exception $e An \Exception instance
* @ param Request $request A Request instance
* @ param int $type The type of the request
*
* @ return Response A Response instance
*
* @ throws \Exception
*/
private function handleException ( \Exception $e , $request , $type )
{
$event = new GetResponseForExceptionEvent ( $this , $request , $type , $e );
$this -> dispatcher -> dispatch ( KernelEvents :: EXCEPTION , $event );
// a listener might have replaced the exception
$e = $event -> getException ();
if ( ! $event -> hasResponse ()) {
$this -> finishRequest ( $request , $type );
throw $e ;
}
$response = $event -> getResponse ();
// the developer asked for a specific status code
if ( $response -> headers -> has ( 'X-Status-Code' )) {
2018-11-23 12:29:20 +00:00
@ trigger_error ( sprintf ( 'Using the X-Status-Code header is deprecated since Symfony 3.3 and will be removed in 4.0. Use %s::allowCustomResponseCode() instead.' , GetResponseForExceptionEvent :: class ), E_USER_DEPRECATED );
2015-08-18 00:00:26 +00:00
$response -> setStatusCode ( $response -> headers -> get ( 'X-Status-Code' ));
$response -> headers -> remove ( 'X-Status-Code' );
2018-11-23 12:29:20 +00:00
} elseif ( ! $event -> isAllowingCustomResponseCode () && ! $response -> isClientError () && ! $response -> isServerError () && ! $response -> isRedirect ()) {
2015-08-18 00:00:26 +00:00
// ensure that we actually have an error response
if ( $e instanceof HttpExceptionInterface ) {
// keep the HTTP status code and headers
$response -> setStatusCode ( $e -> getStatusCode ());
$response -> headers -> add ( $e -> getHeaders ());
} else {
$response -> setStatusCode ( 500 );
}
}
try {
return $this -> filterResponse ( $response , $request , $type );
} catch ( \Exception $e ) {
return $response ;
}
}
private function varToString ( $var )
{
2018-11-23 12:29:20 +00:00
if ( \is_object ( $var )) {
return sprintf ( 'Object(%s)' , \get_class ( $var ));
2015-08-18 00:00:26 +00:00
}
2018-11-23 12:29:20 +00:00
if ( \is_array ( $var )) {
2015-08-18 00:00:26 +00:00
$a = array ();
foreach ( $var as $k => $v ) {
$a [] = sprintf ( '%s => %s' , $k , $this -> varToString ( $v ));
}
return sprintf ( 'Array(%s)' , implode ( ', ' , $a ));
}
2018-11-23 12:29:20 +00:00
if ( \is_resource ( $var )) {
2015-08-18 00:00:26 +00:00
return sprintf ( 'Resource(%s)' , get_resource_type ( $var ));
}
if ( null === $var ) {
return 'null' ;
}
if ( false === $var ) {
return 'false' ;
}
if ( true === $var ) {
return 'true' ;
}
return ( string ) $var ;
}
}