class HttpKernel

Same name in this branch

This HttpKernel is used to manage scope changes of the DI container.

@author Fabien Potencier <fabien@symfony.com> @author Johannes M. Schmitt <schmittjoh@gmail.com>

Hierarchy

Expanded class hierarchy of HttpKernel

1 file declares its use of HttpKernel
HttpKernelTest.php in drupal/core/tests/Drupal/Tests/Core/HttpKernelTest.php
Contains \Drupal\Tests\Core\HttpKernelTest.
1 string reference to 'HttpKernel'
core.services.yml in drupal/core/core.services.yml
drupal/core/core.services.yml
1 service uses HttpKernel

File

drupal/core/lib/Drupal/Core/HttpKernel.php, line 31
Definition of Drupal\Core\HttpKernel.

Namespace

Drupal\Core
View source
class HttpKernel extends BaseHttpKernel {
  protected $container;
  private $esiSupport;
  public function __construct(EventDispatcherInterface $dispatcher, ContainerInterface $container, ControllerResolverInterface $controllerResolver) {
    parent::__construct($dispatcher, $controllerResolver);
    $this->container = $container;
  }
  public function handle(Request $request, $type = HttpKernelInterface::MASTER_REQUEST, $catch = true) {
    $request->headers
      ->set('X-Php-Ob-Level', ob_get_level());
    $this->container
      ->enterScope('request');
    $this->container
      ->set('request', $request, 'request');
    try {
      $response = parent::handle($request, $type, $catch);
    } catch (\Exception $e) {
      $this->container
        ->leaveScope('request');
      throw $e;
    }
    $this->container
      ->leaveScope('request');
    return $response;
  }

  /**
   * Forwards the request to another controller.
   *
   * @param string|NULL $controller
   *   The controller name (a string like BlogBundle:Post:index).
   * @param array $attributes
   *   An array of request attributes.
   * @param array $query
   *   An array of request query parameters.
   *
   * @return Response
   *   A Response instance
   */
  public function forward($controller, array $attributes = array(), array $query = array()) {
    $subrequest = $this
      ->setupSubrequest($controller, $attributes, $query);
    return $this
      ->handle($subrequest, HttpKernelInterface::SUB_REQUEST);
  }

  /**
   * Renders a Controller and returns the Response content.
   *
   * Note that this method generates an esi:include tag only when both the standalone
   * option is set to true and the request has ESI capability (@see Symfony\Component\HttpKernel\HttpCache\ESI).
   *
   * Available options:
   *
   *  * attributes: An array of request attributes (only when the first argument is a controller)
   *  * query: An array of request query parameters (only when the first argument is a controller)
   *  * ignore_errors: true to return an empty string in case of an error
   *  * 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)
   *  * standalone: whether to generate an esi:include tag or not when ESI is supported
   *  * comment: a comment to add when returning an esi:include tag
   *
   * @param string $controller A controller name to execute (a string like BlogBundle:Post:index), or a relative URI
   * @param array  $options    An array of options
   *
   * @return string The Response content
   */
  public function render($controller, array $options = array()) {
    $options = array_merge(array(
      'attributes' => array(),
      'query' => array(),
      'ignore_errors' => !$this->container
        ->getParameter('kernel.debug'),
      'alt' => array(),
      'standalone' => false,
      'comment' => '',
    ), $options);
    if (!is_array($options['alt'])) {
      $options['alt'] = array(
        $options['alt'],
      );
    }
    if (null === $this->esiSupport) {
      $this->esiSupport = $this->container
        ->has('esi') && $this->container
        ->get('esi')
        ->hasSurrogateEsiCapability($this->container
        ->get('request'));
    }
    if ($this->esiSupport && (true === $options['standalone'] || 'esi' === $options['standalone'])) {
      $uri = $this
        ->generateInternalUri($controller, $options['attributes'], $options['query']);
      $alt = '';
      if ($options['alt']) {
        $alt = $this
          ->generateInternalUri($options['alt'][0], isset($options['alt'][1]) ? $options['alt'][1] : array(), isset($options['alt'][2]) ? $options['alt'][2] : array());
      }
      return $this->container
        ->get('esi')
        ->renderIncludeTag($uri, $alt, $options['ignore_errors'], $options['comment']);
    }
    if ('js' === $options['standalone']) {
      $uri = $this
        ->generateInternalUri($controller, $options['attributes'], $options['query'], false);
      $defaultContent = null;
      if ($template = $this->container
        ->getParameter('templating.hinclude.default_template')) {
        $defaultContent = $this->container
          ->get('templating')
          ->render($template);
      }
      return $this
        ->renderHIncludeTag($uri, $defaultContent);
    }
    $request = $this->container
      ->get('request');

    // controller or URI?
    if (0 === strpos($controller, '/')) {
      $subRequest = Request::create($request
        ->getUriForPath($controller), 'get', array(), $request->cookies
        ->all(), array(), $request->server
        ->all());
      if ($session = $request
        ->getSession()) {
        $subRequest
          ->setSession($session);
      }
    }
    else {
      $options['attributes']['_controller'] = $controller;
      if (!isset($options['attributes']['_format'])) {
        $options['attributes']['_format'] = $request
          ->getRequestFormat();
      }
      $options['attributes'][RouteObjectInterface::ROUTE_OBJECT] = '_internal';
      $subRequest = $request
        ->duplicate($options['query'], null, $options['attributes']);
      $subRequest
        ->setMethod('GET');
    }
    $level = ob_get_level();
    try {
      $response = $this
        ->handle($subRequest, HttpKernelInterface::SUB_REQUEST, false);
      if (!$response
        ->isSuccessful()) {
        throw new \RuntimeException(sprintf('Error when rendering "%s" (Status code is %s).', $request
          ->getUri(), $response
          ->getStatusCode()));
      }
      if (!$response instanceof StreamedResponse) {
        return $response
          ->getContent();
      }
      $response
        ->sendContent();
    } catch (\Exception $e) {
      if ($options['alt']) {
        $alt = $options['alt'];
        unset($options['alt']);
        $options['attributes'] = isset($alt[1]) ? $alt[1] : array();
        $options['query'] = isset($alt[2]) ? $alt[2] : array();
        return $this
          ->render($alt[0], $options);
      }
      if (!$options['ignore_errors']) {
        throw $e;
      }

      // let's clean up the output buffers that were created by the sub-request
      while (ob_get_level() > $level) {
        ob_get_clean();
      }
    }
  }

  /**
   * Generates an internal URI for a given controller.
   *
   * This method uses the "_internal" route, which should be available.
   *
   * @param string  $controller A controller name to execute (a string like BlogBundle:Post:index), or a relative URI
   * @param array   $attributes An array of request attributes
   * @param array   $query      An array of request query parameters
   * @param boolean $secure
   *
   * @return string An internal URI
   */
  public function generateInternalUri($controller, array $attributes = array(), array $query = array(), $secure = true) {
    if (0 === strpos($controller, '/')) {
      return $controller;
    }
    $path = http_build_query($attributes, '', '&');
    $uri = $this->container
      ->get('router')
      ->generate($secure ? '_internal' : '_internal_public', array(
      'controller' => $controller,
      'path' => $path ?: 'none',
      '_format' => $this->container
        ->get('request')
        ->getRequestFormat(),
    ));
    if ($queryString = http_build_query($query, '', '&')) {
      $uri .= '?' . $queryString;
    }
    return $uri;
  }

  /**
   * Renders an HInclude tag.
   *
   * @param string $uri A URI
   * @param string $defaultContent Default content
   */
  public function renderHIncludeTag($uri, $defaultContent = null) {
    return sprintf('<hx:include src="%s">%s</hx:include>', $uri, $defaultContent);
  }
  public function hasEsiSupport() {
    return $this->esiSupport;
  }

  /**
   * Creates a request object for a subrequest.
   *
   * @param string $controller
   *   The controller name (a string like BlogBundle:Post:index)
   * @param array $attributes
   *   An array of request attributes.
   * @param array $query
   *   An array of request query parameters.
   *
   * @return \Symfony\Component\HttpFoundation\Request
   *   Returns the new request.
   */
  public function setupSubrequest($controller, array $attributes, array $query) {

    // Don't override the controller if it's NULL.
    if (isset($controller)) {
      $attributes['_controller'] = $controller;
    }
    else {
      unset($attributes['_controller']);
    }
    return $this->container
      ->get('request')
      ->duplicate($query, NULL, $attributes);
  }

}

Members

Namesort descending Modifiers Type Description Overrides
HttpKernel::$container protected property
HttpKernel::$dispatcher protected property
HttpKernel::$esiSupport private property
HttpKernel::$resolver protected property
HttpKernel::filterResponse private function Filters a response object.
HttpKernel::forward public function Forwards the request to another controller.
HttpKernel::generateInternalUri public function Generates an internal URI for a given controller.
HttpKernel::handle public function @api Overrides HttpKernel::handle
HttpKernel::handleException private function Handles an exception by trying to convert it to a Response.
HttpKernel::handleRaw private function Handles a request to convert it to a response.
HttpKernel::hasEsiSupport public function
HttpKernel::render public function Renders a Controller and returns the Response content.
HttpKernel::renderHIncludeTag public function Renders an HInclude tag.
HttpKernel::setupSubrequest public function Creates a request object for a subrequest.
HttpKernel::terminate public function @api Overrides TerminableInterface::terminate
HttpKernel::varToString private function
HttpKernel::__construct public function Constructor Overrides HttpKernel::__construct
HttpKernelInterface::MASTER_REQUEST constant
HttpKernelInterface::SUB_REQUEST constant