diff --git a/core/lib/Drupal/Core/CoreBundle.php b/core/lib/Drupal/Core/CoreBundle.php index 91a7d0144b5..7ae47c69bec 100644 --- a/core/lib/Drupal/Core/CoreBundle.php +++ b/core/lib/Drupal/Core/CoreBundle.php @@ -230,15 +230,10 @@ class CoreBundle extends Bundle { $container->register('mime_type_matcher', 'Drupal\Core\Routing\MimeTypeMatcher') ->addTag('route_filter'); - $container->register('paramconverter_manager', 'Drupal\Core\ParamConverter\ParamConverterManager') - ->addTag('route_enhancer'); $container->register('paramconverter.entity', 'Drupal\Core\ParamConverter\EntityConverter') ->addArgument(new Reference('plugin.manager.entity')) ->addTag('paramconverter'); - $container->register('router_processor_subscriber', 'Drupal\Core\EventSubscriber\RouteProcessorSubscriber') - ->addArgument(new Reference('content_negotiation')) - ->addTag('event_subscriber'); $container->register('router_listener', 'Symfony\Component\HttpKernel\EventListener\RouterListener') ->addArgument(new Reference('router')) ->addTag('event_subscriber'); @@ -322,7 +317,6 @@ class CoreBundle extends Bundle { $container->addCompilerPass(new RegisterAccessChecksPass()); // Add a compiler pass for upcasting of entity route parameters. $container->addCompilerPass(new RegisterParamConvertersPass()); - $container->addCompilerPass(new RegisterRouteEnhancersPass()); // Add a compiler pass for registering services needing destruction. $container->addCompilerPass(new RegisterServicesForDestructionPass()); } @@ -380,6 +374,23 @@ class CoreBundle extends Bundle { ->addMethodCall('setContext', array(new Reference('router.request_context'))) ->addMethodCall('add', array(new Reference('router.dynamic'))) ->addMethodCall('add', array(new Reference('legacy_router'))); + + // Add a route enhancer to upcast parameters to objects if possible. + $container->register('paramconverter_manager', 'Drupal\Core\ParamConverter\ParamConverterManager') + ->addTag('route_enhancer', array('priority' => 50)); + + // Add core route enhancers to dynamically derive the _controller + $container->register('route_enhancer.ajax', 'Drupal\Core\Routing\Enhancer\AjaxEnhancer') + ->addArgument(new Reference('content_negotiation')) + ->addTag('route_enhancer', array('priority' => 20)); + $container->register('route_enhancer.form', 'Drupal\Core\Routing\Enhancer\FormEnhancer') + ->addArgument(new Reference('content_negotiation')) + ->addTag('route_enhancer', array('priority' => 10)); + $container->register('route_enhancer.page', 'Drupal\Core\Routing\Enhancer\PageEnhancer') + ->addArgument(new Reference('content_negotiation')) + ->addTag('route_enhancer', array('priority' => 0)); + + $container->addCompilerPass(new RegisterRouteEnhancersPass()); } /** diff --git a/core/lib/Drupal/Core/EventSubscriber/RouteProcessorSubscriber.php b/core/lib/Drupal/Core/EventSubscriber/RouteProcessorSubscriber.php deleted file mode 100644 index 7b1e34a53dd..00000000000 --- a/core/lib/Drupal/Core/EventSubscriber/RouteProcessorSubscriber.php +++ /dev/null @@ -1,72 +0,0 @@ -negotiation = $negotiation; - } - - /** - * Sets a default controller for a route if one was not specified. - * - * @param Symfony\Component\HttpKernel\Event\GetResponseEvent $event - * Event that is created to create a response for a request. - */ - public function onRequestSetController(GetResponseEvent $event) { - $request = $event->getRequest(); - - // @todo This should all get converted into one or more RouteEnhancers. - if (!$request->attributes->has('_content') && $this->negotiation->getContentType($request) == 'drupal_ajax') { - $request->attributes->set('_content', $request->attributes->get('_controller')); - $request->attributes->set('_controller', '\Drupal\Core\AjaxController::content'); - } - elseif (!$request->attributes->has('_controller') && $this->negotiation->getContentType($request) === 'html') { - if ($request->attributes->has('_form')) { - $request->attributes->set('_controller', '\Drupal\Core\HtmlFormController::content'); - } - elseif ($request->attributes->has('_content')) { - $request->attributes->set('_controller', '\Drupal\Core\HtmlPageController::content'); - } - else { - throw new \InvalidArgumentException('No valid subcontroller key was found'); - } - } - } - - /** - * Registers the methods in this class that should be listeners. - * - * @return array - * An array of event listener definitions. - */ - static function getSubscribedEvents() { - // The RouterListener has priority 32, and we need to run after that. - $events[KernelEvents::REQUEST][] = array('onRequestSetController', 30); - - return $events; - } - -} diff --git a/core/lib/Drupal/Core/Routing/Enhancer/AjaxEnhancer.php b/core/lib/Drupal/Core/Routing/Enhancer/AjaxEnhancer.php new file mode 100644 index 00000000000..1fd99eaf3b8 --- /dev/null +++ b/core/lib/Drupal/Core/Routing/Enhancer/AjaxEnhancer.php @@ -0,0 +1,52 @@ +negotiation = $negotiation; + } + + /** + * Implements \Symfony\Cmf\Component\Routing\Enhancer\RouteEnhancerInterface::enhance() + */ + public function enhance(array $defaults, Request $request) { + // Old-style routes work differently, since they are their own controller. + if ($request->attributes->get('_legacy') == TRUE) { + if (empty($defaults['_content']) && $this->negotiation->getContentType($request) == 'drupal_ajax') { + $defaults['_content'] = $defaults['_controller']; + $defaults['_controller'] = '\Drupal\Core\AjaxController::content'; + } + } + else { + if (empty($defaults['_controller']) && !empty($defaults['_content']) && $this->negotiation->getContentType($request) === 'drupal_ajax') { + $defaults['_controller'] = '\Drupal\Core\AjaxController::content'; + } + } + return $defaults; + } + +} diff --git a/core/lib/Drupal/Core/Routing/Enhancer/FormEnhancer.php b/core/lib/Drupal/Core/Routing/Enhancer/FormEnhancer.php new file mode 100644 index 00000000000..2210d0352ad --- /dev/null +++ b/core/lib/Drupal/Core/Routing/Enhancer/FormEnhancer.php @@ -0,0 +1,43 @@ +negotiation = $negotiation; + } + + /** + * Implements \Symfony\Cmf\Component\Routing\Enhancer\RouteEnhancerInterface::enhance() + */ + public function enhance(array $defaults, Request $request) { + if (empty($defaults['_controller']) && !empty($defaults['_form']) && $this->negotiation->getContentType($request) === 'html') { + $defaults['_controller'] = '\Drupal\Core\HtmlFormController::content'; + } + return $defaults; + } + +} diff --git a/core/lib/Drupal/Core/Routing/Enhancer/PageEnhancer.php b/core/lib/Drupal/Core/Routing/Enhancer/PageEnhancer.php new file mode 100644 index 00000000000..3d73e9ea60a --- /dev/null +++ b/core/lib/Drupal/Core/Routing/Enhancer/PageEnhancer.php @@ -0,0 +1,43 @@ +negotiation = $negotiation; + } + + /** + * Implements \Symfony\Cmf\Component\Routing\Enhancer\RouteEnhancerInterface::enhance() + */ + public function enhance(array $defaults, Request $request) { + if (empty($defaults['_controller']) && !empty($defaults['_content']) && $this->negotiation->getContentType($request) === 'html') { + $defaults['_controller'] = '\Drupal\Core\HtmlPageController::content'; + } + return $defaults; + } + +} diff --git a/core/modules/system/lib/Drupal/system/Tests/Routing/RouterTest.php b/core/modules/system/lib/Drupal/system/Tests/Routing/RouterTest.php index 8a3f45f0d7e..352e89f9232 100644 --- a/core/modules/system/lib/Drupal/system/Tests/Routing/RouterTest.php +++ b/core/modules/system/lib/Drupal/system/Tests/Routing/RouterTest.php @@ -106,4 +106,35 @@ class RouterTest extends WebTestBase { $this->assertResponse(200); $this->assertRaw('test5', 'The correct string was returned because the route was successful.'); } + + /** + * Checks that a request with text/html response gets rendered as a page. + */ + public function testControllerResolutionPage() { + $this->drupalGet('/router_test/test10'); + + $this->assertRaw('abcde', 'Correct body was found.'); + + // Confirm that the page wrapping is being added, so we're not getting a + // raw body returned. + $this->assertRaw('', 'Page markup was found.'); + + // In some instances, the subrequest handling may get confused and render + // a page inception style. This test verifies that is not happening. + $this->assertNoPattern('#.*#s', 'There was no double-page effect from a misrendered subrequest.'); + } + + /** + * Checks that an ajax request gets rendered as an Ajax response, by mime. + */ + public function testControllerResolutionAjax() { + // This will fail with a JSON parse error if the request is not routed to + // The correct controller. + $this->drupalGetAJAX('/router_test/test10', array(), array('Accept: application/vnd.drupal-ajax')); + + $this->assertEqual($this->drupalGetHeader('Content-Type'), 'application/json', 'Correct mime content type was returned'); + + $this->assertRaw('abcde', 'Correct body was found.'); + } + } diff --git a/core/modules/system/tests/modules/router_test/lib/Drupal/router_test/TestContent.php b/core/modules/system/tests/modules/router_test/lib/Drupal/router_test/TestContent.php new file mode 100644 index 00000000000..11fc1b0d5da --- /dev/null +++ b/core/modules/system/tests/modules/router_test/lib/Drupal/router_test/TestContent.php @@ -0,0 +1,19 @@ +