Browse Source

Use _ext routing parameter for view selection if available.

This allows routes to force content types based on extensions. This
preserves behavior with RequestHandler and is generally what should
happen.
Mark Story 4 years ago
parent
commit
353a4a94bd
2 changed files with 30 additions and 5 deletions
  1. 16 5
      src/Controller/Controller.php
  2. 14 0
      tests/TestCase/Controller/ControllerTest.php

+ 16 - 5
src/Controller/Controller.php

@@ -797,14 +797,14 @@ class Controller implements EventListenerInterface, EventDispatcherInterface
      */
     protected function chooseViewClass(): ?string
     {
-        if ($this->viewBuilder()->getClassName() !== null) {
-            return null;
-        }
-
         $possibleViewClasses = $this->getViewClasses();
         if (empty($possibleViewClasses)) {
             return null;
         }
+        if ($this->viewBuilder()->getClassName() !== null) {
+            return null;
+        }
+
         $typeMap = [];
         foreach ($possibleViewClasses as $class) {
             $viewContentType = $class::getContentType();
@@ -812,9 +812,20 @@ class Controller implements EventListenerInterface, EventDispatcherInterface
                 $typeMap[$viewContentType] = $class;
             }
         }
+        $request = $this->getRequest();
+
+        // Prefer the _ext route parameter if it is defined.
+        $ext = $request->getParam('_ext');
+        if ($ext) {
+            $extType = $this->response->getMimeType($ext);
+            if (isset($typeMap[$extType])) {
+                return $typeMap[$extType];
+            }
+        }
 
+        // Use accept header based negotiation.
         $contentType = new ContentTypeNegotiation();
-        $preferredType = $contentType->preferredType($this->getRequest(), array_keys($typeMap));
+        $preferredType = $contentType->preferredType($request, array_keys($typeMap));
         if (!$preferredType) {
             return null;
         }

+ 14 - 0
tests/TestCase/Controller/ControllerTest.php

@@ -350,6 +350,20 @@ class ControllerTest extends TestCase
         $this->assertStringContainsString('hello world', $response->getBody() . '');
     }
 
+    public function testRenderViewClassesUsesExt()
+    {
+        $request = new ServerRequest([
+            'url' => '/',
+            'environment' => [],
+            'params' => ['plugin' => null, 'controller' => 'ContentTypes', 'action' => 'all', '_ext' => 'json'],
+        ]);
+        $controller = new ContentTypesController($request, new Response());
+        $controller->all();
+        $response = $controller->render();
+        $this->assertSame('application/json', $response->getHeaderLine('Content-Type'));
+        $this->assertNotEmpty(json_decode($response->getBody() . ''), 'Body should be json');
+    }
+
     /**
      * test view rendering changing response
      */