vendor/symfony/src/Symfony/Bundle/FrameworkBundle/HttpKernel.php
changeset 0 7f95f8617b0b
equal deleted inserted replaced
-1:000000000000 0:7f95f8617b0b
       
     1 <?php
       
     2 
       
     3 /*
       
     4  * This file is part of the Symfony framework.
       
     5  *
       
     6  * (c) Fabien Potencier <fabien@symfony.com>
       
     7  *
       
     8  * This source file is subject to the MIT license that is bundled
       
     9  * with this source code in the file LICENSE.
       
    10  */
       
    11 
       
    12 namespace Symfony\Bundle\FrameworkBundle;
       
    13 
       
    14 use Symfony\Component\HttpFoundation\Request;
       
    15 use Symfony\Component\HttpKernel\HttpKernelInterface;
       
    16 use Symfony\Component\HttpKernel\Controller\ControllerResolverInterface;
       
    17 use Symfony\Component\DependencyInjection\ContainerInterface;
       
    18 use Symfony\Component\HttpKernel\HttpKernel as BaseHttpKernel;
       
    19 use Symfony\Component\EventDispatcher\EventDispatcherInterface;
       
    20 
       
    21 /**
       
    22  * This HttpKernel is used to manage scope changes of the DI container.
       
    23  *
       
    24  * @author Johannes M. Schmitt <schmittjoh@gmail.com>
       
    25  */
       
    26 class HttpKernel extends BaseHttpKernel
       
    27 {
       
    28     private $container;
       
    29     private $esiSupport;
       
    30 
       
    31     public function __construct(EventDispatcherInterface $dispatcher, ContainerInterface $container, ControllerResolverInterface $controllerResolver)
       
    32     {
       
    33         parent::__construct($dispatcher, $controllerResolver);
       
    34 
       
    35         $this->container = $container;
       
    36     }
       
    37 
       
    38     public function handle(Request $request, $type = HttpKernelInterface::MASTER_REQUEST, $catch = true)
       
    39     {
       
    40         $this->container->enterScope('request');
       
    41         $this->container->set('request', $request, 'request');
       
    42 
       
    43         try {
       
    44             $response = parent::handle($request, $type, $catch);
       
    45         } catch (\Exception $e) {
       
    46             $this->container->leaveScope('request');
       
    47 
       
    48             throw $e;
       
    49         }
       
    50 
       
    51         $this->container->leaveScope('request');
       
    52 
       
    53         return $response;
       
    54     }
       
    55 
       
    56     /**
       
    57      * Forwards the request to another controller.
       
    58      *
       
    59      * @param  string  $controller The controller name (a string like BlogBundle:Post:index)
       
    60      * @param  array   $attributes An array of request attributes
       
    61      * @param  array   $query      An array of request query parameters
       
    62      *
       
    63      * @return Response A Response instance
       
    64      */
       
    65     public function forward($controller, array $attributes = array(), array $query = array())
       
    66     {
       
    67         $attributes['_controller'] = $controller;
       
    68         $subRequest = $this->container->get('request')->duplicate($query, null, $attributes);
       
    69 
       
    70         return $this->handle($subRequest, HttpKernelInterface::SUB_REQUEST);
       
    71     }
       
    72 
       
    73     /**
       
    74      * Renders a Controller and returns the Response content.
       
    75      *
       
    76      * Note that this method generates an esi:include tag only when both the standalone
       
    77      * option is set to true and the request has ESI capability (@see Symfony\Component\HttpKernel\HttpCache\ESI).
       
    78      *
       
    79      * Available options:
       
    80      *
       
    81      *  * attributes: An array of request attributes (only when the first argument is a controller)
       
    82      *  * query: An array of request query parameters (only when the first argument is a controller)
       
    83      *  * ignore_errors: true to return an empty string in case of an error
       
    84      *  * alt: an alternative controller to execute in case of an error (can be a controller, a URI, or an array with the controller, the attributes, and the query arguments)
       
    85      *  * standalone: whether to generate an esi:include tag or not when ESI is supported
       
    86      *  * comment: a comment to add when returning an esi:include tag
       
    87      *
       
    88      * @param string $controller A controller name to execute (a string like BlogBundle:Post:index), or a relative URI
       
    89      * @param array  $options    An array of options
       
    90      *
       
    91      * @return string The Response content
       
    92      */
       
    93     public function render($controller, array $options = array())
       
    94     {
       
    95         $options = array_merge(array(
       
    96             'attributes'    => array(),
       
    97             'query'         => array(),
       
    98             'ignore_errors' => !$this->container->getParameter('kernel.debug'),
       
    99             'alt'           => array(),
       
   100             'standalone'    => false,
       
   101             'comment'       => '',
       
   102         ), $options);
       
   103 
       
   104         if (!is_array($options['alt'])) {
       
   105             $options['alt'] = array($options['alt']);
       
   106         }
       
   107 
       
   108         if (null === $this->esiSupport) {
       
   109             $this->esiSupport = $this->container->has('esi') && $this->container->get('esi')->hasSurrogateEsiCapability($this->container->get('request'));
       
   110         }
       
   111 
       
   112         if ($this->esiSupport && $options['standalone']) {
       
   113             $uri = $this->generateInternalUri($controller, $options['attributes'], $options['query']);
       
   114 
       
   115             $alt = '';
       
   116             if ($options['alt']) {
       
   117                 $alt = $this->generateInternalUri($options['alt'][0], isset($options['alt'][1]) ? $options['alt'][1] : array(), isset($options['alt'][2]) ? $options['alt'][2] : array());
       
   118             }
       
   119 
       
   120             return $this->container->get('esi')->renderIncludeTag($uri, $alt, $options['ignore_errors'], $options['comment']);
       
   121         }
       
   122 
       
   123         $request = $this->container->get('request');
       
   124 
       
   125         // controller or URI?
       
   126         if (0 === strpos($controller, '/')) {
       
   127             $subRequest = Request::create($controller, 'get', array(), $request->cookies->all(), array(), $request->server->all());
       
   128             $subRequest->setSession($request->getSession());
       
   129         } else {
       
   130             $options['attributes']['_controller'] = $controller;
       
   131             $options['attributes']['_format'] = $request->getRequestFormat();
       
   132             $options['attributes']['_route'] = '_internal';
       
   133             $subRequest = $request->duplicate($options['query'], null, $options['attributes']);
       
   134         }
       
   135 
       
   136         try {
       
   137             $response = $this->handle($subRequest, HttpKernelInterface::SUB_REQUEST, false);
       
   138 
       
   139             if (!$response->isSuccessful()) {
       
   140                 throw new \RuntimeException(sprintf('Error when rendering "%s" (Status code is %s).', $request->getUri(), $response->getStatusCode()));
       
   141             }
       
   142 
       
   143             return $response->getContent();
       
   144         } catch (\Exception $e) {
       
   145             if ($options['alt']) {
       
   146                 $alt = $options['alt'];
       
   147                 unset($options['alt']);
       
   148                 $options['attributes'] = isset($alt[1]) ? $alt[1] : array();
       
   149                 $options['query'] = isset($alt[2]) ? $alt[2] : array();
       
   150 
       
   151                 return $this->render($alt[0], $options);
       
   152             }
       
   153 
       
   154             if (!$options['ignore_errors']) {
       
   155                 throw $e;
       
   156             }
       
   157         }
       
   158     }
       
   159 
       
   160     /**
       
   161      * Generates an internal URI for a given controller.
       
   162      *
       
   163      * This method uses the "_internal" route, which should be available.
       
   164      *
       
   165      * @param string $controller A controller name to execute (a string like BlogBundle:Post:index), or a relative URI
       
   166      * @param array  $attributes An array of request attributes
       
   167      * @param array  $query      An array of request query parameters
       
   168      *
       
   169      * @return string An internal URI
       
   170      */
       
   171     public function generateInternalUri($controller, array $attributes = array(), array $query = array())
       
   172     {
       
   173         if (0 === strpos($controller, '/')) {
       
   174             return $controller;
       
   175         }
       
   176 
       
   177         $path = http_build_query($attributes);
       
   178         $uri = $this->container->get('router')->generate('_internal', array(
       
   179             'controller' => $controller,
       
   180             'path'       => $path ?: 'none',
       
   181             '_format'    => $this->container->get('request')->getRequestFormat(),
       
   182         ));
       
   183 
       
   184         if ($queryString = http_build_query($query)) {
       
   185             $uri .= '?'.$queryString;
       
   186         }
       
   187 
       
   188         return $uri;
       
   189     }
       
   190 }