diff --git a/core/core.services.yml b/core/core.services.yml index 5399bc7..9b691a3 100644 --- a/core/core.services.yml +++ b/core/core.services.yml @@ -182,6 +182,7 @@ services: factory_class: Symfony\Component\HttpFoundation\Request factory_method: createFromGlobals #synthetic: true + synchronized: true event_dispatcher: class: Symfony\Component\EventDispatcher\ContainerAwareEventDispatcher arguments: ['@service_container'] @@ -328,17 +329,17 @@ services: arguments: ['@content_negotiation'] tags: - { name: route_enhancer, priority: 30 } - route_enhancer.ajax: - class: Drupal\Core\Routing\Enhancer\AjaxEnhancer + route_enhancer.entity: + class: Drupal\Core\Entity\Enhancer\EntityRouteEnhancer arguments: ['@content_negotiation'] tags: - { name: route_enhancer, priority: 20 } - - { name: legacy_route_enhancer, priority: 20 } - route_enhancer.entity: - class: Drupal\Core\Entity\Enhancer\EntityRouteEnhancer + route_enhancer.ajax: + class: Drupal\Core\Routing\Enhancer\AjaxEnhancer arguments: ['@content_negotiation'] tags: - { name: route_enhancer, priority: 15 } + - { name: legacy_route_enhancer, priority: 20 } route_enhancer.form: class: Drupal\Core\Routing\Enhancer\FormEnhancer arguments: ['@content_negotiation'] @@ -350,10 +351,13 @@ services: - { name: event_subscriber } controller.page: class: Drupal\Core\Controller\HtmlPageController - arguments: ['@http_kernel', '@controller_resolver'] + arguments: ['@controller_resolver'] controller.dialog: class: Drupal\Core\Controller\DialogController - arguments: ['@http_kernel'] + arguments: ['@controller_resolver'] + controller.ajax: + class: Drupal\Core\Controller\AjaxController + arguments: ['@controller_resolver'] router_listener: class: Symfony\Component\HttpKernel\EventListener\RouterListener tags: @@ -424,13 +428,11 @@ services: tags: - { name: event_subscriber } arguments: ['@language_manager'] - scope: request redirect_response_subscriber: class: Drupal\Core\EventSubscriber\RedirectResponseSubscriber arguments: ['@url_generator'] tags: - { name: event_subscriber } - scope: request request_close_subscriber: class: Drupal\Core\EventSubscriber\RequestCloseSubscriber tags: diff --git a/core/lib/Drupal/Core/Controller/AjaxController.php b/core/lib/Drupal/Core/Controller/AjaxController.php index 7b2cece..fd40496 100644 --- a/core/lib/Drupal/Core/Controller/AjaxController.php +++ b/core/lib/Drupal/Core/Controller/AjaxController.php @@ -10,13 +10,30 @@ use Drupal\Core\Ajax\AjaxResponse; use Drupal\Core\Ajax\InsertCommand; use Drupal\Core\Ajax\PrependCommand; -use Symfony\Component\DependencyInjection\ContainerAware; use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\Response; /** * Default controller for ajax requests. */ -class AjaxController extends ContainerAware { +class AjaxController { + + /** + * The controller resolver. + * + * @var \Drupal\Core\Controller\ControllerResolverInterface + */ + protected $controllerResolver; + + /** + * Constructs a HtmlPageController instance. + * + * @param \Drupal\Core\Controller\ControllerResolverInterface $controller_resolver + * The controller resolver. + */ + public function __construct(ControllerResolverInterface $controller_resolver) { + $this->controllerResolver = $controller_resolver; + } /** * Controller method for AJAX content. @@ -30,50 +47,34 @@ class AjaxController extends ContainerAware { * A response object. */ public function content(Request $request, $_content) { - - // @todo When we have a Generator, we can replace the forward() call with - // a render() call, which would handle ESI and hInclude as well. That will - // require an _internal route. For examples, see: - // https://github.com/symfony/symfony/blob/master/src/Symfony/Bundle/FrameworkBundle/Resources/config/routing/internal.xml - // https://github.com/symfony/symfony/blob/master/src/Symfony/Bundle/FrameworkBundle/Controller/InternalController.php - $attributes = clone $request->attributes; - $controller = $_content; - - // We need to clean up the derived information and such so that the - // subrequest can be processed properly without leaking data through. - $attributes->remove('_system_path'); - $attributes->remove('_content'); - $attributes->remove('_legacy'); - - // Remove the accept header so the subrequest does not end up back in this - // controller. - $request->headers->remove('accept'); - // Remove the header in order to let the subrequest not think that it's an - // ajax request, see \Drupal\Core\ContentNegotiation. - $request->headers->remove('x-requested-with'); - - $response = $this->container->get('http_kernel')->forward($controller, $attributes->all(), $request->query->all()); - // For successful (HTTP status 200) responses. - if ($response->isOk()) { - // If there is already an AjaxResponse, then return it without - // manipulation. - if (!($response instanceof AjaxResponse)) { + $callable = $this->controllerResolver->createController($_content); + $arguments = $this->controllerResolver->getArguments($request, $callable); + $response = call_user_func_array($callable, $arguments); + if ($response instanceof Response) { + if ($response instanceof AjaxResponse || !$response->isOk()) { + return $response; + } + else { // Pull the content out of the response. $content = $response->getContent(); - // A page callback could return a render array or a string. - $html = is_string($content) ? $content : drupal_render($content); - $response = new AjaxResponse(); - // The selector for the insert command is NULL as the new content will - // replace the element making the ajax call. The default 'replaceWith' - // behavior can be changed with #ajax['method']. - $response->addCommand(new InsertCommand(NULL, $html)); - $status_messages = array('#theme' => 'status_messages'); - $output = drupal_render($status_messages); - if (!empty($output)) { - $response->addCommand(new PrependCommand(NULL, $output)); - } } } + else { + $content = $response; + } + + // A page callback could return a render array or a string. + $html = is_string($content) ? $content : drupal_render($content); + $response = new AjaxResponse(); + // The selector for the insert command is NULL as the new content will + // replace the element making the ajax call. The default 'replaceWith' + // behavior can be changed with #ajax['method']. + $response->addCommand(new InsertCommand(NULL, $html)); + $status_messages = array('#theme' => 'status_messages'); + $output = drupal_render($status_messages); + if (!empty($output)) { + $response->addCommand(new PrependCommand(NULL, $output)); + } return $response; } } diff --git a/core/lib/Drupal/Core/Controller/ControllerResolver.php b/core/lib/Drupal/Core/Controller/ControllerResolver.php index f363d65..dd9300b 100644 --- a/core/lib/Drupal/Core/Controller/ControllerResolver.php +++ b/core/lib/Drupal/Core/Controller/ControllerResolver.php @@ -100,21 +100,9 @@ public function getController(Request $request) { } /** - * Returns a callable for the given controller. - * - * @param string $controller - * A Controller string. - * - * @return mixed - * A PHP callable. - * - * @throws \LogicException - * If the controller cannot be parsed - * - * @throws \InvalidArgumentException - * If the controller class does not exist + * {@inheritdoc} */ - protected function createController($controller) { + public function createController($controller) { // Controller in the service:method notation. $count = substr_count($controller, ':'); if ($count == 1) { diff --git a/core/lib/Drupal/Core/Controller/ControllerResolverInterface.php b/core/lib/Drupal/Core/Controller/ControllerResolverInterface.php index b0179fe..0eec574 100644 --- a/core/lib/Drupal/Core/Controller/ControllerResolverInterface.php +++ b/core/lib/Drupal/Core/Controller/ControllerResolverInterface.php @@ -34,4 +34,21 @@ */ public function getControllerFromDefinition($controller); + /** + * Returns a callable for the given controller. + * + * @param string $controller + * A Controller string. + * + * @return mixed + * A PHP callable. + * + * @throws \LogicException + * If the controller cannot be parsed + * + * @throws \InvalidArgumentException + * If the controller class does not exist + */ + public function createController($controller); + } diff --git a/core/lib/Drupal/Core/Controller/DialogController.php b/core/lib/Drupal/Core/Controller/DialogController.php index cde2876..c8478f8 100644 --- a/core/lib/Drupal/Core/Controller/DialogController.php +++ b/core/lib/Drupal/Core/Controller/DialogController.php @@ -19,51 +19,20 @@ class DialogController { /** - * The HttpKernel object to use for subrequests. + * The controller resolver. * - * @var \Symfony\Component\HttpKernel\HttpKernelInterface + * @var \Drupal\Core\Controller\ControllerResolverInterface */ - protected $httpKernel; + protected $controllerResolver; /** * Constructs a new DialogController. * - * @param \Symfony\Component\HttpKernel\HttpKernelInterface $kernel - * The kernel. + * @param \Drupal\Core\Controller\ControllerResolverInterface $controller_resolver + * The controller resolver. */ - public function __construct(HttpKernelInterface $kernel) { - $this->httpKernel = $kernel; - } - - /** - * Forwards request to a subrequest. - * - * @param \Symfony\Component\HttpFoundation\RequestRequest $request - * The request object. - * - * @return \Symfony\Component\HttpFoundation\Response - * A response object. - */ - protected function forward(Request $request) { - // @todo When we have a Generator, we can replace the forward() call with - // a render() call, which would handle ESI and hInclude as well. That will - // require an _internal route. For examples, see: - // https://github.com/symfony/symfony/blob/master/src/Symfony/Bundle/FrameworkBundle/Resources/config/routing/internal.xml - // https://github.com/symfony/symfony/blob/master/src/Symfony/Bundle/FrameworkBundle/Controller/InternalController.php - $attributes = clone $request->attributes; - // We need to clean up the derived information and such so that the - // subrequest can be processed properly without leaking data through. - $attributes->remove('_system_path'); - $attributes->set('dialog', TRUE); - - // Remove the accept header so the subrequest does not end up back in this - // controller. - $request->headers->remove('accept'); - // Remove the X-Requested-With header so the subrequest is not mistaken for - // an ajax request. - $request->headers->remove('x-requested-with'); - - return $this->httpKernel->forward(NULL, $attributes->all(), $request->query->all()); + public function __construct(ControllerResolverInterface $controller_resolver) { + $this->controllerResolver = $controller_resolver; } /** @@ -75,8 +44,8 @@ protected function forward(Request $request) { * @return \Drupal\Core\Ajax\AjaxResponse * AjaxResponse to return the content wrapper in a modal dialog. */ - public function modal(Request $request) { - return $this->dialog($request, TRUE); + public function modal(Request $request, $_content) { + return $this->dialog($request, $_content, TRUE); } /** @@ -90,10 +59,12 @@ public function modal(Request $request) { * @return \Drupal\Core\Ajax\AjaxResponse * AjaxResponse to return the content wrapper in a dialog. */ - public function dialog(Request $request, $modal = FALSE) { - $subrequest = $this->forward($request); - if ($subrequest->isOk()) { - $content = $subrequest->getContent(); + public function dialog(Request $request, $_content, $modal = FALSE) { + $callable = $this->controllerResolver->createController($_content); + $arguments = $this->controllerResolver->getArguments($request, $callable); + $controller_response = call_user_func_array($callable, $arguments); + if ($controller_response->isOk()) { + $content = $controller_response->getContent(); // @todo Remove use of drupal_get_title() when // http://drupal.org/node/1871596 is in. $title = drupal_get_title(); @@ -129,6 +100,7 @@ public function dialog(Request $request, $modal = FALSE) { return $response; } // An error occurred in the subrequest, return that. - return $subrequest; + return $controller_response; } + } diff --git a/core/lib/Drupal/Core/Controller/HtmlPageController.php b/core/lib/Drupal/Core/Controller/HtmlPageController.php index d87b3ed..cdb0174 100644 --- a/core/lib/Drupal/Core/Controller/HtmlPageController.php +++ b/core/lib/Drupal/Core/Controller/HtmlPageController.php @@ -7,6 +7,7 @@ namespace Drupal\Core\Controller; +use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\HttpKernelInterface; @@ -17,13 +18,6 @@ class HtmlPageController { /** - * The HttpKernel object to use for subrequests. - * - * @var \Symfony\Component\HttpKernel\HttpKernelInterface - */ - protected $httpKernel; - - /** * The controller resolver. * * @var \Drupal\Core\Controller\ControllerResolverInterface @@ -33,12 +27,10 @@ class HtmlPageController { /** * Constructs a new HtmlPageController. * - * @param \Symfony\Component\HttpKernel\HttpKernelInterface $kernel * @param \Drupal\Core\Controller\ControllerResolverInterface $controller_resolver * The controller resolver. */ - public function __construct(HttpKernelInterface $kernel, ControllerResolverInterface $controller_resolver) { - $this->httpKernel = $kernel; + public function __construct(ControllerResolverInterface $controller_resolver) { $this->controllerResolver = $controller_resolver; } diff --git a/core/lib/Drupal/Core/Entity/Enhancer/EntityRouteEnhancer.php b/core/lib/Drupal/Core/Entity/Enhancer/EntityRouteEnhancer.php index 2cf8d47..bf9023d 100644 --- a/core/lib/Drupal/Core/Entity/Enhancer/EntityRouteEnhancer.php +++ b/core/lib/Drupal/Core/Entity/Enhancer/EntityRouteEnhancer.php @@ -38,7 +38,7 @@ public function __construct(ContentNegotiation $negotiation) { * {@inheritdoc} */ public function enhance(array $defaults, Request $request) { - if (empty($defaults['_controller']) && $this->negotiation->getContentType($request) === 'html') { + if (empty($defaults['_controller']) && in_array($this->negotiation->getContentType($request), array('html', 'drupal_ajax'))) { if (!empty($defaults['_entity_form'])) { $defaults['_controller'] = '\Drupal\Core\Entity\HtmlEntityFormController::content'; } diff --git a/core/lib/Drupal/Core/HttpKernel.php b/core/lib/Drupal/Core/HttpKernel.php index 07c79c7..ec426c7 100644 --- a/core/lib/Drupal/Core/HttpKernel.php +++ b/core/lib/Drupal/Core/HttpKernel.php @@ -2,12 +2,7 @@ /** * @file - * Definition of Drupal\Core\HttpKernel. - * - * @todo This file is copied verbatim, with the exception of the namespace - * change and this commment block, from Symfony full stack's FrameworkBundle. - * Once the FrameworkBundle is available as a Composer package we should switch - * to pulling it via Composer. + * Contains \Drupal\Core\HttpKernel. */ namespace Drupal\Core; @@ -23,249 +18,42 @@ use Symfony\Component\EventDispatcher\EventDispatcherInterface; /** - * This HttpKernel is used to manage scope changes of the DI container. - * - * @author Fabien Potencier - * @author Johannes M. Schmitt + * HttpKernel extension to allow easy in-process subrequests. */ -class HttpKernel extends BaseHttpKernel -{ - protected $container; +class HttpKernel extends BaseHttpKernel { - 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; - } + /** + * Constructs a \Drupal\Core\HttpKernel object. + * + * @param \Symfony\Component\EventDispatcher\EventDispatcherInterface $dispatcher + * The event dispatcher. + * @param \Symfony\Component\DependencyInjection\ContainerInterface $container + * The service container. + * @param \Symfony\Component\HttpKernel\Controller\ControllerResolverInterface $resolver + * The controller resolver. + */ + public function __construct(EventDispatcherInterface $dispatcher, ContainerInterface $container, ControllerResolverInterface $resolver) { + parent::__construct($dispatcher, $resolver); + $this->container = $container; + } - $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(), - )); + public function handle(Request $request, $type = HttpKernelInterface::MASTER_REQUEST, $catch = true) { + $request->headers->set('X-Php-Ob-Level', ob_get_level()); - if ($queryString = http_build_query($query, '', '&')) { - $uri .= '?'.$queryString; - } + $this->container->enterScope('request'); + $this->container->set('request', $request, 'request'); - return $uri; + try { + $response = parent::handle($request, $type, $catch); } - - /** - * Renders an HInclude tag. - * - * @param string $uri A URI - * @param string $defaultContent Default content - */ - public function renderHIncludeTag($uri, $defaultContent = null) - { - return sprintf('%s', $uri, $defaultContent); + catch (\Exception $e) { + $this->container->leaveScope('request'); + throw $e; } - public function hasEsiSupport() - { - return $this->esiSupport; - } + $this->container->leaveScope('request'); - /** - * 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); + return $response; } } diff --git a/core/lib/Drupal/Core/Routing/Enhancer/AjaxEnhancer.php b/core/lib/Drupal/Core/Routing/Enhancer/AjaxEnhancer.php index 47c5179..7c4a1df 100644 --- a/core/lib/Drupal/Core/Routing/Enhancer/AjaxEnhancer.php +++ b/core/lib/Drupal/Core/Routing/Enhancer/AjaxEnhancer.php @@ -39,7 +39,7 @@ public function __construct(ContentNegotiation $negotiation) { public function enhance(array $defaults, Request $request) { if (empty($defaults['_content']) && $this->negotiation->getContentType($request) == 'drupal_ajax') { $defaults['_content'] = isset($defaults['_controller']) ? $defaults['_controller'] : NULL; - $defaults['_controller'] = '\Drupal\Core\Controller\AjaxController::content'; + $defaults['_controller'] = 'controller.ajax:content'; } return $defaults; } diff --git a/core/lib/Drupal/Core/Routing/Enhancer/ContentControllerEnhancer.php b/core/lib/Drupal/Core/Routing/Enhancer/ContentControllerEnhancer.php index e088d44..de2d41f 100644 --- a/core/lib/Drupal/Core/Routing/Enhancer/ContentControllerEnhancer.php +++ b/core/lib/Drupal/Core/Routing/Enhancer/ContentControllerEnhancer.php @@ -58,11 +58,6 @@ public function enhance(array $defaults, Request $request) { $defaults['_controller'] = $this->types[$type]; } } - // When the dialog attribute is TRUE this is a DialogController sub-request. - // Route the sub-request to the _content callable. - if ($request->attributes->get('dialog') && !empty($defaults['_content'])) { - $defaults['_controller'] = $defaults['_content']; - } return $defaults; } } diff --git a/core/tests/Drupal/Tests/Core/HttpKernelTest.php b/core/tests/Drupal/Tests/Core/HttpKernelTest.php deleted file mode 100644 index b51e108..0000000 --- a/core/tests/Drupal/Tests/Core/HttpKernelTest.php +++ /dev/null @@ -1,65 +0,0 @@ - 'HttpKernel (Unit)', - 'description' => 'Tests the HttpKernel.', - 'group' => 'Routing', - ); - } - - /** - * Tests the forward method. - * - * @see \Drupal\Core\HttpKernel::setupSubrequest() - */ - public function testSetupSubrequest() { - $container = new ContainerBuilder(); - - $request = new Request(); - $container->addScope(new Scope('request')); - $container->enterScope('request'); - $container->set('request', $request, 'request'); - - $dispatcher = new EventDispatcher(); - $controller_resolver = new ControllerResolver($container); - - $http_kernel = new HttpKernel($dispatcher, $container, $controller_resolver); - - $test_controller = '\Drupal\Tests\Core\Controller\TestController'; - $random_attribute = $this->randomName(); - $subrequest = $http_kernel->setupSubrequest($test_controller, array('custom_attribute' => $random_attribute), array('custom_query' => $random_attribute)); - $this->assertNotSame($subrequest, $request, 'The subrequest is not the same as the main request.'); - $this->assertEquals($subrequest->attributes->get('custom_attribute'), $random_attribute, 'Attributes are set from the subrequest.'); - $this->assertEquals($subrequest->query->get('custom_query'), $random_attribute, 'Query attributes are set from the subrequest.'); - $this->assertEquals($subrequest->attributes->get('_controller'), $test_controller, 'Controller attribute got set.'); - - $subrequest = $http_kernel->setupSubrequest(NULL, array(), array()); - $this->assertFalse($subrequest->attributes->has('_controller'), 'Ensure that _controller is not copied when no controller was set before.'); - } - -}