Browse Source

5.x Remove RequestHandlerComponent

Remove RequestHandlerComponent and the related stub classes. I also had
to update the default error controller to do content-type negotiation
for json. I didn't include Xml but could add it if folks feel strongly
that we should have that out of the box.
Mark Story 4 years ago
parent
commit
76f05ea22e

+ 0 - 5
psalm-baseline.xml

@@ -28,11 +28,6 @@
       <code>$callback</code>
     </MissingParamType>
   </file>
-  <file src="src/Controller/Component/RequestHandlerComponent.php">
-    <DeprecatedMethod occurrences="1">
-      <code>prefers</code>
-    </DeprecatedMethod>
-  </file>
   <file src="src/Controller/ControllerFactory.php">
     <ArgumentTypeCoercion occurrences="3">
       <code>$request</code>

+ 0 - 516
src/Controller/Component/RequestHandlerComponent.php

@@ -1,516 +0,0 @@
-<?php
-declare(strict_types=1);
-
-/**
- * CakePHP(tm) : Rapid Development Framework (https://cakephp.org)
- * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
- *
- * Licensed under The MIT License
- * For full copyright and license information, please see the LICENSE.txt
- * Redistributions of files must retain the above copyright notice.
- *
- * @copyright     Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
- * @link          https://cakephp.org CakePHP(tm) Project
- * @since         0.10.4
- * @license       https://opensource.org/licenses/mit-license.php MIT License
- */
-namespace Cake\Controller\Component;
-
-use Cake\Controller\Component;
-use Cake\Controller\ComponentRegistry;
-use Cake\Controller\Controller;
-use Cake\Core\App;
-use Cake\Core\Configure;
-use Cake\Event\EventInterface;
-use Cake\Http\ContentTypeNegotiation;
-use Cake\Http\Exception\NotFoundException;
-use Cake\Http\Response;
-use Cake\Http\ServerRequest;
-use Cake\Routing\Router;
-use Cake\Utility\Inflector;
-
-/**
- * Request object handling for alternative HTTP requests.
- *
- * This Component checks for requests for different content types like JSON, XML,
- * XMLHttpRequest(AJAX) and configures the response object and view builder accordingly.
- *
- * It can also check for HTTP caching headers like `Last-Modified`, `If-Modified-Since`
- * etc. and return a response accordingly.
- *
- * @link https://book.cakephp.org/4/en/controllers/components/request-handling.html
- * @deprecated 4.4.0 See the 4.4 migration guide for how to upgrade.
- *   https://book.cakephp.org/4/en/appendices/4-4-migration-guide.html#requesthandlercomponent
- */
-class RequestHandlerComponent extends Component
-{
-    /**
-     * Contains the file extension parsed out by the Router
-     *
-     * @var string|null
-     * @see \Cake\Routing\Router::extensions()
-     */
-    protected ?string $ext = null;
-
-    /**
-     * The template type to use when rendering the given content type.
-     *
-     * @var string|null
-     */
-    protected ?string $_renderType = null;
-
-    /**
-     * Default config
-     *
-     * These are merged with user-provided config when the component is used.
-     *
-     * - `checkHttpCache` - Whether to check for HTTP cache. Default `true`.
-     * - `viewClassMap` - Mapping between type and view classes. If undefined
-     *   JSON, XML, and AJAX will be mapped. Defining any types will omit the defaults.
-     *
-     * @var array<string, mixed>
-     */
-    protected array $_defaultConfig = [
-        'checkHttpCache' => true,
-        'viewClassMap' => [],
-    ];
-
-    /**
-     * Constructor. Parses the accepted content types accepted by the client using HTTP_ACCEPT
-     *
-     * @param \Cake\Controller\ComponentRegistry $registry ComponentRegistry object.
-     * @param array<string, mixed> $config Array of config.
-     */
-    public function __construct(ComponentRegistry $registry, array $config = [])
-    {
-        $config += [
-            'viewClassMap' => [
-                'json' => 'Json',
-                'xml' => 'Xml',
-                'ajax' => 'Ajax',
-            ],
-        ];
-        parent::__construct($registry, $config);
-    }
-
-    /**
-     * Events supported by this component.
-     *
-     * @return array<string, mixed>
-     */
-    public function implementedEvents(): array
-    {
-        return [
-            'Controller.startup' => 'startup',
-            'Controller.beforeRender' => 'beforeRender',
-        ];
-    }
-
-    /**
-     * Set the extension based on the `Accept` header or URL extension.
-     *
-     * Compares the accepted types and configured extensions.
-     * If there is one common type, that is assigned as the ext/content type for the response.
-     * The type with the highest weight will be set. If the highest weight has more
-     * than one type matching the extensions, the order in which extensions are specified
-     * determines which type will be set.
-     *
-     * If html is one of the preferred types, no content type will be set, this
-     * is to avoid issues with browsers that prefer HTML and several other content types.
-     *
-     * @param \Cake\Http\ServerRequest $request The request instance.
-     * @param \Cake\Http\Response $response The response instance.
-     * @return void
-     */
-    protected function _setExtension(ServerRequest $request, Response $response): void
-    {
-        $content = new ContentTypeNegotiation();
-        $accept = $content->parseAccept($request);
-
-        if (empty($accept) || current($accept)[0] === 'text/html') {
-            return;
-        }
-
-        /** @var array $accepts */
-        $accepts = $response->mapType($accept);
-        $preferredTypes = current($accepts);
-        if (array_intersect($preferredTypes, ['html', 'xhtml'])) {
-            return;
-        }
-
-        $extensions = array_unique(
-            array_merge(Router::extensions(), array_keys($this->getConfig('viewClassMap')))
-        );
-        foreach ($accepts as $types) {
-            $ext = array_intersect($extensions, $types);
-            if ($ext) {
-                $this->ext = current($ext);
-                break;
-            }
-        }
-    }
-
-    /**
-     * The startup method of the RequestHandler enables several automatic behaviors
-     * related to the detection of certain properties of the HTTP request, including:
-     *
-     * If the XML data is POSTed, the data is parsed into an XML object, which is assigned
-     * to the $data property of the controller, which can then be saved to a model object.
-     *
-     * @param \Cake\Event\EventInterface $event The startup event that was fired.
-     * @return void
-     */
-    public function startup(EventInterface $event): void
-    {
-        $controller = $this->getController();
-        $request = $controller->getRequest();
-        $response = $controller->getResponse();
-
-        $this->ext = $request->getParam('_ext');
-        if (!$this->ext || in_array($this->ext, ['html', 'htm'], true)) {
-            $this->_setExtension($request, $response);
-        }
-
-        $isAjax = $request->is('ajax');
-        $controller->setRequest($request->withAttribute('isAjax', $isAjax));
-
-        if (!$this->ext && $isAjax) {
-            $this->ext = 'ajax';
-        }
-    }
-
-    /**
-     * Checks if the response can be considered different according to the request
-     * headers, and the caching response headers. If it was not modified, then the
-     * render process is skipped. And the client will get a blank response with a
-     * "304 Not Modified" header.
-     *
-     * - If Router::extensions() is enabled, the layout and template type are
-     *   switched based on the parsed extension or `Accept` header. For example,
-     *   if `controller/action.xml` is requested, the view path becomes
-     *   `templates/Controller/xml/action.php`. Also, if `controller/action` is
-     *   requested with `Accept: application/xml` in the headers the view
-     *   path will become `templates/Controller/xml/action.php`. Layout and template
-     *   types will only switch to mime-types recognized by \Cake\Http\Response.
-     *   If you need to declare additional mime-types, you can do so using
-     *   {@link \Cake\Http\Response::setTypeMap()} in your controller's beforeFilter() method.
-     * - If a helper with the same name as the extension exists, it is added to
-     *   the controller.
-     * - If the extension is of a type that RequestHandler understands, it will
-     *   set that Content-type in the response header.
-     *
-     * @param \Cake\Event\EventInterface $event The Controller.beforeRender event.
-     * @return void
-     * @throws \Cake\Http\Exception\NotFoundException If invoked extension is not configured.
-     */
-    public function beforeRender(EventInterface $event): void
-    {
-        $controller = $this->getController();
-        $response = $controller->getResponse();
-
-        if ($this->ext && !in_array($this->ext, ['html', 'htm'], true)) {
-            if (!$response->getMimeType($this->ext)) {
-                throw new NotFoundException('Invoked extension not recognized/configured: ' . $this->ext);
-            }
-
-            $this->renderAs($controller, $this->ext);
-            $response = $controller->getResponse();
-        } else {
-            $response = $response->withCharset(Configure::read('App.encoding'));
-        }
-
-        $request = $controller->getRequest();
-        if ($this->_config['checkHttpCache'] && $response->isNotModified($request)) {
-            $response = $response->withNotModified();
-            $event->stopPropagation();
-        }
-
-        $controller->setResponse($response);
-    }
-
-    /**
-     * Determines which content types the client accepts. Acceptance is based on
-     * the file extension parsed by the Router (if present), and by the HTTP_ACCEPT
-     * header. Unlike {@link \Cake\Http\ServerRequest::accepts()} this method deals entirely with mapped content types.
-     *
-     * Usage:
-     *
-     * ```
-     * $this->RequestHandler->accepts(['xml', 'html', 'json']);
-     * ```
-     *
-     * Returns true if the client accepts any of the supplied types.
-     *
-     * ```
-     * $this->RequestHandler->accepts('xml');
-     * ```
-     *
-     * Returns true if the client accepts XML.
-     *
-     * @param array<string>|string|null $type Can be null (or no parameter), a string type name, or an
-     *   array of types
-     * @return array|string|bool|null If null or no parameter is passed, returns an array of content
-     *   types the client accepts. If a string is passed, returns true
-     *   if the client accepts it. If an array is passed, returns true
-     *   if the client accepts one or more elements in the array.
-     * @deprecated 4.4.0 Use ContentTypeNegotiation::prefersChoice() or Controller::getViewClasses() instead.
-     */
-    public function accepts(array|string|null $type = null): mixed
-    {
-        $controller = $this->getController();
-        /** @var array $accepted */
-        $accepted = $controller->getRequest()->accepts();
-
-        if (!$type) {
-            return $controller->getResponse()->mapType($accepted);
-        }
-
-        if (is_array($type)) {
-            foreach ($type as $t) {
-                $t = $this->mapAlias($t);
-                if (in_array($t, $accepted, true)) {
-                    return true;
-                }
-            }
-
-            return false;
-        }
-
-        return in_array($this->mapAlias($type), $accepted, true);
-    }
-
-    /**
-     * Determines the content type of the data the client has sent (i.e. in a POST request)
-     *
-     * @param array<string>|string|null $type Can be null (or no parameter), a string type name, or an array of types
-     * @return mixed If a single type is supplied a boolean will be returned. If no type is provided
-     *   The mapped value of CONTENT_TYPE will be returned. If an array is supplied the first type
-     *   in the request content type will be returned.
-     */
-    public function requestedWith(array|string|null $type = null): mixed
-    {
-        $controller = $this->getController();
-        $request = $controller->getRequest();
-
-        if (
-            !$request->is('post') &&
-            !$request->is('put') &&
-            !$request->is('patch') &&
-            !$request->is('delete')
-        ) {
-            return null;
-        }
-        if (is_array($type)) {
-            foreach ($type as $t) {
-                if ($this->requestedWith($t)) {
-                    return $t;
-                }
-            }
-
-            return false;
-        }
-
-        [$contentType] = explode(';', $request->contentType() ?? '');
-        if ($type === null) {
-            return $controller->getResponse()->mapType($contentType);
-        }
-
-        return $type === $controller->getResponse()->mapType($contentType);
-    }
-
-    /**
-     * Determines which content-types the client prefers. If no parameters are given,
-     * the single content-type that the client most likely prefers is returned. If $type is
-     * an array, the first item in the array that the client accepts is returned.
-     * Preference is determined primarily by the file extension parsed by the Router
-     * if provided, and secondarily by the list of content-types provided in
-     * HTTP_ACCEPT.
-     *
-     * @param array<string>|string|null $type An optional array of 'friendly' content-type names, i.e.
-     *   'html', 'xml', 'js', etc.
-     * @return string|bool|null If $type is null or not provided, the first content-type in the
-     *    list, based on preference, is returned. If a single type is provided
-     *    a boolean will be returned if that type is preferred.
-     *    If an array of types are provided then the first preferred type is returned.
-     *    If no type is provided the first preferred type is returned.
-     * @deprecated 4.4.0 Use Controller::getViewClasses() instead.
-     */
-    public function prefers(array|string|null $type = null): string|bool|null
-    {
-        $controller = $this->getController();
-        $request = $controller->getRequest();
-        $content = new ContentTypeNegotiation();
-
-        $acceptRaw = $content->parseAccept($request);
-        if (empty($acceptRaw)) {
-            return $type ? $type === $this->ext : $this->ext;
-        }
-
-        /** @var array $accepts */
-        $accepts = $controller->getResponse()->mapType(array_shift($acceptRaw));
-        if (!$type) {
-            if (empty($this->ext) && !empty($accepts)) {
-                return $accepts[0];
-            }
-
-            return $this->ext;
-        }
-
-        $types = (array)$type;
-        if (count($types) === 1) {
-            if ($this->ext) {
-                return in_array($this->ext, $types, true);
-            }
-
-            return in_array($types[0], $accepts, true);
-        }
-
-        $intersect = array_values(array_intersect($accepts, $types));
-        if (!$intersect) {
-            return false;
-        }
-
-        return $intersect[0];
-    }
-
-    /**
-     * Sets either the view class if one exists or the layout and template path of the view.
-     * The names of these are derived from the $type input parameter.
-     *
-     * ### Usage:
-     *
-     * Render the response as an 'ajax' response.
-     *
-     * ```
-     * $this->RequestHandler->renderAs($this, 'ajax');
-     * ```
-     *
-     * Render the response as an XML file and force the result as a file download.
-     *
-     * ```
-     * $this->RequestHandler->renderAs($this, 'xml', ['attachment' => 'myfile.xml'];
-     * ```
-     *
-     * @param \Cake\Controller\Controller $controller A reference to a controller object
-     * @param string $type Type of response to send (e.g: 'ajax')
-     * @param array<string, mixed> $options Array of options to use
-     * @return void
-     * @see \Cake\Controller\Component\RequestHandlerComponent::respondAs()
-     */
-    public function renderAs(Controller $controller, string $type, array $options = []): void
-    {
-        $defaults = ['charset' => 'UTF-8'];
-        $viewClassMap = $this->getConfig('viewClassMap');
-
-        if (Configure::read('App.encoding') !== null) {
-            $defaults['charset'] = Configure::read('App.encoding');
-        }
-        $options += $defaults;
-
-        $builder = $controller->viewBuilder();
-        if (array_key_exists($type, $viewClassMap)) {
-            $view = $viewClassMap[$type];
-        } else {
-            $view = Inflector::classify($type);
-        }
-
-        $viewClass = null;
-        if ($builder->getClassName() === null) {
-            $viewClass = App::className($view, 'View', 'View');
-        }
-
-        if ($viewClass) {
-            $builder->setClassName($viewClass);
-        } else {
-            if (!$this->_renderType) {
-                $builder->setTemplatePath((string)$builder->getTemplatePath() . DIRECTORY_SEPARATOR . $type);
-            } else {
-                $builder->setTemplatePath(preg_replace(
-                    "/([\/\\\\]{$this->_renderType})$/",
-                    DIRECTORY_SEPARATOR . $type,
-                    (string)$builder->getTemplatePath()
-                ));
-            }
-
-            $this->_renderType = $type;
-            $builder->setLayoutPath($type);
-        }
-
-        if ($controller->getResponse()->getMimeType($type)) {
-            $this->respondAs($type, $options);
-        }
-    }
-
-    /**
-     * Sets the response header based on type map index name. This wraps several methods
-     * available on {@link \Cake\Http\Response}. It also allows you to use Content-Type aliases.
-     *
-     * @param string $type Friendly type name, i.e. 'html' or 'xml', or a full content-type,
-     *    like 'application/x-shockwave'.
-     * @param array<string, mixed> $options If $type is a friendly type name that is associated with
-     *    more than one type of content, $index is used to select which content-type to use.
-     * @return bool Returns false if the friendly type name given in $type does
-     *    not exist in the type map, or if the Content-type header has
-     *    already been set by this method.
-     */
-    public function respondAs(string $type, array $options = []): bool
-    {
-        $defaults = ['index' => null, 'charset' => null, 'attachment' => false];
-        $options += $defaults;
-
-        $cType = $type;
-        $controller = $this->getController();
-        $response = $controller->getResponse();
-
-        if (!str_contains($type, '/')) {
-            $cType = $response->getMimeType($type);
-        }
-        if (is_array($cType)) {
-            $cType = $cType[$options['index']] ?? $cType;
-            $cType = $this->prefers($cType) ?: $cType[0];
-        }
-
-        if (!$cType) {
-            return false;
-        }
-
-        /** @psalm-suppress PossiblyInvalidArgument */
-        $response = $response->withType($cType);
-
-        if (!empty($options['charset'])) {
-            $response = $response->withCharset($options['charset']);
-        }
-        if (!empty($options['attachment'])) {
-            $response = $response->withDownload($options['attachment']);
-        }
-        $controller->setResponse($response);
-
-        return true;
-    }
-
-    /**
-     * Maps a content type alias back to its mime-type(s)
-     *
-     * @param array<string>|string $alias String alias to convert back into a content type. Or an array of aliases to map.
-     * @return array|string|null Null on an undefined alias. String value of the mapped alias type. If an
-     *   alias maps to more than one content type, the first one will be returned. If an array is provided
-     *   for $alias, an array of mapped types will be returned.
-     */
-    public function mapAlias(array|string $alias): array|string|null
-    {
-        if (is_array($alias)) {
-            return array_map([$this, 'mapAlias'], $alias);
-        }
-
-        $type = $this->getController()->getResponse()->getMimeType($alias);
-        if (!$type) {
-            return null;
-        }
-
-        if (is_array($type)) {
-            return $type[0];
-        }
-
-        return $type;
-    }
-}

+ 6 - 4
src/Controller/ErrorController.php

@@ -17,6 +17,7 @@ declare(strict_types=1);
 namespace Cake\Controller;
 
 use Cake\Event\EventInterface;
+use Cake\View\JsonView;
 
 /**
  * Error Handling Controller
@@ -26,13 +27,14 @@ use Cake\Event\EventInterface;
 class ErrorController extends Controller
 {
     /**
-     * Initialization hook method.
+     * Get alternate view classes that can be used in
+     * content-type negotiation.
      *
-     * @return void
+     * @return string[]
      */
-    public function initialize(): void
+    public function viewClasses(): array
     {
-        $this->loadComponent('RequestHandler');
+        return [JsonView::class];
     }
 
     /**

+ 0 - 13
src/Error/ExceptionRenderer.php

@@ -174,25 +174,12 @@ class ExceptionRenderer implements ExceptionRendererInterface
             $controller = new $class($request);
             $controller->startupProcess();
         } catch (Throwable) {
-            $errorOccured = true;
         }
 
         if (!isset($controller)) {
             return new Controller($request);
         }
 
-        // Retry RequestHandler, as another aspect of startupProcess()
-        // could have failed. Ignore any exceptions out of startup, as
-        // there could be userland input data parsers.
-        if ($errorOccured && isset($controller->RequestHandler)) {
-            try {
-                $event = new Event('Controller.startup', $controller);
-                /** @psalm-suppress PossiblyUndefinedMethod */
-                $controller->RequestHandler->startup($event);
-            } catch (Throwable) {
-            }
-        }
-
         return $controller;
     }
 

+ 2 - 2
src/Routing/Router.php

@@ -711,8 +711,8 @@ class Router
      * Instructs the router to parse out file extensions
      * from the URL. For example, http://example.com/posts.rss would yield a file
      * extension of "rss". The file extension itself is made available in the
-     * controller as `$this->request->getParam('_ext')`, and is used by the RequestHandler
-     * component to automatically switch to alternate layouts and templates, and
+     * controller as `$this->request->getParam('_ext')`, and is used by content
+     * type negotiation to automatically switch to alternate layouts and templates, and
      * load helpers corresponding to the given content, i.e. RssHelper. Switching
      * layouts and helpers requires that the chosen extension has a defined mime type
      * in `Cake\Http\Response`.

+ 0 - 878
tests/TestCase/Controller/Component/RequestHandlerComponentTest.php

@@ -1,878 +0,0 @@
-<?php
-declare(strict_types=1);
-
-/**
- * CakePHP(tm) : Rapid Development Framework (https://cakephp.org)
- * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
- *
- * Licensed under The MIT License
- * For full copyright and license information, please see the LICENSE.txt
- * Redistributions of files must retain the above copyright notice
- *
- * @copyright     Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
- * @link          https://cakephp.org CakePHP(tm) Project
- * @since         1.2.0
- * @license       https://opensource.org/licenses/mit-license.php MIT License
- */
-namespace Cake\Test\TestCase\Controller\Component;
-
-use Cake\Controller\Component\RequestHandlerComponent;
-use Cake\Controller\ComponentRegistry;
-use Cake\Controller\Controller;
-use Cake\Event\Event;
-use Cake\Event\EventInterface;
-use Cake\Http\Exception\NotFoundException;
-use Cake\Http\Response;
-use Cake\Http\ServerRequest;
-use Cake\Routing\Router;
-use Cake\TestSuite\TestCase;
-use Cake\View\AjaxView;
-use Cake\View\JsonView;
-use Cake\View\XmlView;
-use TestApp\Controller\Component\RequestHandlerExtComponent;
-use TestApp\Controller\RequestHandlerTestController;
-use TestApp\View\AppView;
-
-/**
- * RequestHandlerComponentTest class
- */
-class RequestHandlerComponentTest extends TestCase
-{
-    /**
-     * @var \TestApp\Controller\RequestHandlerTestController
-     */
-    protected $Controller;
-
-    /**
-     * @var \TestApp\Controller\Component\RequestHandlerExtComponent
-     */
-    protected $RequestHandler;
-
-    /**
-     * @var \Cake\Http\ServerRequest
-     */
-    protected $request;
-
-    /**
-     * Backup of $_SERVER
-     *
-     * @var array
-     */
-    protected $server = [];
-
-    /**
-     * @var \Cake\Routing\RouteBuilder
-     */
-    protected $builder;
-
-    /**
-     * setUp method
-     */
-    public function setUp(): void
-    {
-        parent::setUp();
-        $this->server = $_SERVER;
-        static::setAppNamespace();
-        $this->_init();
-    }
-
-    /**
-     * init method
-     */
-    protected function _init(): void
-    {
-        $request = new ServerRequest(['url' => 'controller_posts/index']);
-        $response = new Response();
-        $this->Controller = new RequestHandlerTestController($request, $response);
-        $this->RequestHandler = $this->Controller->components()->load(RequestHandlerExtComponent::class);
-        $this->request = $request;
-
-        $this->builder = Router::createRouteBuilder('/');
-        $this->builder->setExtensions('json');
-        $this->builder->fallbacks('InflectedRoute');
-    }
-
-    /**
-     * tearDown method
-     */
-    public function tearDown(): void
-    {
-        parent::tearDown();
-        Router::reload();
-        $_SERVER = $this->server;
-        unset($this->RequestHandler, $this->Controller);
-    }
-
-    /**
-     * Test that the constructor sets the config.
-     */
-    public function testConstructorConfig(): void
-    {
-        $config = [
-            'viewClassMap' => ['json' => 'MyPlugin.MyJson'],
-        ];
-        /** @var \Cake\Controller\Controller|\PHPUnit\Framework\MockObject\MockObject $controller */
-        $controller = $this->getMockBuilder(Controller::class)
-            ->onlyMethods(['redirect'])
-            ->getMock();
-        $collection = new ComponentRegistry($controller);
-        $requestHandler = new RequestHandlerComponent($collection, $config);
-        $this->assertEquals(['json' => 'MyPlugin.MyJson'], $requestHandler->getConfig('viewClassMap'));
-    }
-
-    /**
-     * testInitializeCallback method
-     */
-    public function testInitializeCallback(): void
-    {
-        $this->assertNull($this->RequestHandler->getExt());
-        $this->Controller->setRequest($this->Controller->getRequest()->withParam('_ext', 'rss'));
-        $this->RequestHandler->startup(new Event('Controller.startup', $this->Controller));
-        $this->assertSame('rss', $this->RequestHandler->getExt());
-    }
-
-    /**
-     * test that a mapped Accept-type header will set $this->ext correctly.
-     */
-    public function testInitializeContentTypeSettingExt(): void
-    {
-        Router::reload();
-        $this->Controller->setRequest($this->request->withHeader('Accept', 'application/json'));
-
-        $this->RequestHandler->setExt(null);
-        $this->RequestHandler->startup(new Event('Controller.startup', $this->Controller));
-        $this->assertSame('json', $this->RequestHandler->getExt());
-    }
-
-    /**
-     * Test that RequestHandler sets $this->ext when jQuery sends its wonky-ish headers.
-     */
-    public function testInitializeContentTypeWithjQueryAccept(): void
-    {
-        Router::reload();
-        $this->Controller->setRequest($this->request
-            ->withHeader('Accept', 'application/json, application/javascript, */*; q=0.01')
-            ->withHeader('X-Requested-With', 'XMLHttpRequest'));
-        $this->RequestHandler->setExt(null);
-        Router::extensions('json', false);
-
-        $this->RequestHandler->startup(new Event('Controller.startup', $this->Controller));
-        $this->assertSame('json', $this->RequestHandler->getExt());
-    }
-
-    /**
-     * Test that RequestHandler does not set extension to csv for text/plain mimetype
-     */
-    public function testInitializeContentTypeWithjQueryTextPlainAccept(): void
-    {
-        Router::reload();
-        $this->Controller->setRequest($this->request->withHeader('Accept', 'text/plain, */*; q=0.01'));
-
-        $this->RequestHandler->startup(new Event('Controller.startup', $this->Controller));
-        $this->assertNull($this->RequestHandler->ext);
-    }
-
-    /**
-     * Test that RequestHandler sets $this->ext when jQuery sends its wonky-ish headers
-     * and the application is configured to handle multiple extensions
-     */
-    public function testInitializeContentTypeWithjQueryAcceptAndMultiplesExtensions(): void
-    {
-        Router::reload();
-        $this->Controller->setRequest($this->request->withHeader('Accept', 'application/json, application/javascript, */*; q=0.01'));
-        $this->RequestHandler->setExt(null);
-        Router::extensions(['rss', 'json'], false);
-
-        $this->RequestHandler->startup(new Event('Controller.startup', $this->Controller));
-        $this->assertSame('json', $this->RequestHandler->getExt());
-    }
-
-    /**
-     * Test that RequestHandler does not set $this->ext when multiple accepts are sent.
-     */
-    public function testInitializeNoContentTypeWithSingleAccept(): void
-    {
-        Router::reload();
-        $_SERVER['HTTP_ACCEPT'] = 'application/json, text/html, */*; q=0.01';
-        $this->assertNull($this->RequestHandler->getExt());
-
-        $this->RequestHandler->startup(new Event('Controller.startup', $this->Controller));
-        $this->assertNull($this->RequestHandler->getExt());
-    }
-
-    /**
-     * Test that ext is set to the first listed extension with multiple accepted
-     * content types.
-     * Having multiple types accepted with same weight, means the client lets the
-     * server choose the returned content type.
-     */
-    public function testInitializeNoContentTypeWithMultipleAcceptedTypes(): void
-    {
-        $this->Controller->setRequest($this->request->withHeader(
-            'Accept',
-            'application/json, application/javascript, application/xml, */*; q=0.01'
-        ));
-        $this->RequestHandler->setExt(null);
-        Router::extensions(['xml', 'json'], false);
-
-        $this->RequestHandler->startup(new Event('Controller.startup', $this->Controller));
-        $this->assertSame('xml', $this->RequestHandler->getExt());
-
-        $this->RequestHandler->setExt(null);
-        Router::extensions(['json', 'xml'], false);
-
-        $this->RequestHandler->startup(new Event('Controller.startup', $this->Controller));
-        $this->assertSame('json', $this->RequestHandler->getExt());
-    }
-
-    /**
-     * Test that ext is set to type with highest weight
-     */
-    public function testInitializeContentTypeWithMultipleAcceptedTypes(): void
-    {
-        Router::reload();
-        $this->Controller->setRequest($this->request->withHeader(
-            'Accept',
-            'text/csv;q=1.0, application/json;q=0.8, application/xml;q=0.7'
-        ));
-        $this->RequestHandler->setExt(null);
-
-        $this->RequestHandler->startup(new Event('Controller.startup', $this->Controller));
-        $this->assertSame('json', $this->RequestHandler->getExt());
-    }
-
-    /**
-     * Test that ext is not set with confusing android accepts headers.
-     */
-    public function testInitializeAmbiguousAndroidAccepts(): void
-    {
-        Router::reload();
-        $this->request = $this->request->withEnv(
-            'HTTP_ACCEPT',
-            'application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5'
-        );
-        $this->RequestHandler->setExt(null);
-
-        $this->RequestHandler->startup(new Event('Controller.startup', $this->Controller));
-        $this->assertNull($this->RequestHandler->getExt());
-    }
-
-    /**
-     * Test that the headers sent by firefox are not treated as XML requests.
-     */
-    public function testInititalizeFirefoxHeaderNotXml(): void
-    {
-        $_SERVER['HTTP_ACCEPT'] = 'text/html,application/xhtml+xml,application/xml;image/png,image/jpeg,image/*;q=0.9,*/*;q=0.8';
-        Router::extensions(['xml', 'json'], false);
-
-        $this->RequestHandler->startup(new Event('Controller.startup', $this->Controller));
-        $this->assertNull($this->RequestHandler->getExt());
-    }
-
-    /**
-     * Test that a type mismatch doesn't incorrectly set the ext
-     */
-    public function testInitializeContentTypeAndExtensionMismatch(): void
-    {
-        $this->assertNull($this->RequestHandler->getExt());
-        $extensions = Router::extensions();
-        Router::extensions('xml', false);
-
-        $request = new ServerRequest([
-            'environment' => ['HTTP_ACCEPT' => 'text/plain'],
-        ]);
-        $this->Controller->setRequest($request);
-
-        $this->RequestHandler->startup(new Event('Controller.startup', $this->Controller));
-        $this->assertNull($this->RequestHandler->getExt());
-
-        Router::extensions($extensions, false);
-    }
-
-    /**
-     * Test that startup() throws deprecation warning if input data is available and request data is not populated.
-     */
-    public function testInitializeInputNoWarningEmptyJsonObject(): void
-    {
-        $request = new ServerRequest([
-            'input' => json_encode([]),
-        ]);
-        $this->Controller->setRequest($request->withMethod('POST'));
-        $this->RequestHandler->startup(new Event('Controller.startup', $this->Controller));
-        $this->assertSame([], $request->getParsedBody());
-    }
-
-    /**
-     * testViewClassMap
-     */
-    public function testViewClassMap(): void
-    {
-        $this->RequestHandler->setConfig(['viewClassMap' => ['json' => 'CustomJson']]);
-        $result = $this->RequestHandler->getConfig('viewClassMap');
-        $expected = [
-            'json' => 'CustomJson',
-            'xml' => 'Xml',
-            'ajax' => 'Ajax',
-        ];
-        $this->assertEquals($expected, $result);
-        $this->RequestHandler->setConfig(['viewClassMap' => ['xls' => 'Excel.Excel']]);
-        $result = $this->RequestHandler->getConfig('viewClassMap');
-        $expected = [
-            'json' => 'CustomJson',
-            'xml' => 'Xml',
-            'ajax' => 'Ajax',
-            'xls' => 'Excel.Excel',
-        ];
-        $this->assertEquals($expected, $result);
-
-        $this->RequestHandler->renderAs($this->Controller, 'json');
-        $this->assertSame('TestApp\View\CustomJsonView', $this->Controller->viewBuilder()->getClassName());
-    }
-
-    /**
-     * Verify that isAjax is set on the request params for AJAX requests
-     *
-     * @triggers Controller.startup $this->Controller
-     */
-    public function testIsAjaxParams(): void
-    {
-        $this->Controller->setRequest($this->request->withHeader('X-Requested-With', 'XMLHttpRequest'));
-        $event = new Event('Controller.startup', $this->Controller);
-        $this->Controller->beforeFilter($event);
-        $this->RequestHandler->startup($event);
-        $this->assertTrue($this->Controller->getRequest()->getAttribute('isAjax'));
-    }
-
-    /**
-     * testAutoAjaxLayout method
-     *
-     * @triggers Controller.startup $this->Controller
-     */
-    public function testAutoAjaxLayout(): void
-    {
-        $event = new Event('Controller.startup', $this->Controller);
-        $this->Controller->setRequest($this->request->withHeader('X-Requested-With', 'XMLHttpRequest'));
-        $this->RequestHandler->startup($event);
-        $event = new Event('Controller.beforeRender', $this->Controller);
-        $this->RequestHandler->beforeRender($event);
-
-        $view = $this->Controller->createView();
-        $this->assertInstanceOf(AjaxView::class, $view);
-        $this->assertSame('ajax', $view->getLayout());
-        $this->assertSame((new Response(['type' => 'ajax']))->getType(), $view->getResponse()->getType());
-
-        $this->_init();
-        $this->Controller->setRequest($this->Controller->getRequest()->withParam('_ext', 'js'));
-        $this->RequestHandler->startup($event);
-        $this->assertNotEquals(AjaxView::class, $this->Controller->viewBuilder()->getClassName());
-    }
-
-    /**
-     * @return array
-     */
-    public function defaultExtensionsProvider(): array
-    {
-        return [['html'], ['htm']];
-    }
-
-    /**
-     * Tests that the default extensions are using the default view.
-     *
-     * @param string $extension Extension to test.
-     * @dataProvider defaultExtensionsProvider
-     */
-    public function testDefaultExtensions($extension): void
-    {
-        Router::extensions([$extension], false);
-
-        $this->Controller->setRequest($this->request->withParam('_ext', $extension));
-        $this->RequestHandler->startup(new Event('Controller.startup', $this->Controller));
-        $this->RequestHandler->beforeRender(new Event('Controller.beforeRender', $this->Controller));
-
-        $this->assertSame($extension, $this->RequestHandler->getExt());
-        $this->assertSame('text/html', $this->Controller->getResponse()->getType());
-
-        $view = $this->Controller->createView();
-        $this->assertInstanceOf(AppView::class, $view);
-        $this->assertEmpty($view->getLayoutPath());
-        $this->assertEmpty($view->getSubDir());
-    }
-
-    /**
-     * Tests that the default extensions can be overwritten by the accept header.
-     *
-     * @param string $extension Extension to test.
-     * @dataProvider defaultExtensionsProvider
-     */
-    public function testDefaultExtensionsOverwrittenByAcceptHeader($extension): void
-    {
-        Router::extensions([$extension], false);
-
-        $request = $this->request->withHeader(
-            'Accept',
-            'application/xml'
-        );
-        $this->Controller->setRequest($request->withParam('_ext', $extension));
-        $this->RequestHandler->startup(new Event('Controller.startup', $this->Controller));
-        $this->RequestHandler->beforeRender(new Event('Controller.beforeRender', $this->Controller));
-
-        $this->assertSame('xml', $this->RequestHandler->getExt());
-        $this->assertSame('application/xml', $this->Controller->getResponse()->getType());
-
-        $view = $this->Controller->createView();
-        $this->assertInstanceOf(XmlView::class, $view);
-        $this->assertSame('xml', $view->getLayoutPath());
-        $this->assertSame('xml', $view->getSubDir());
-    }
-
-    /**
-     * test custom JsonView class is loaded and correct.
-     *
-     * @triggers Controller.startup $this->Controller
-     */
-    public function testJsonViewLoaded(): void
-    {
-        Router::extensions(['json', 'xml', 'ajax'], false);
-        $this->Controller->setRequest($this->Controller->getRequest()->withParam('_ext', 'json'));
-        $event = new Event('Controller.startup', $this->Controller);
-        $this->RequestHandler->startup($event);
-        $event = new Event('Controller.beforeRender', $this->Controller);
-        $this->RequestHandler->beforeRender($event);
-        $view = $this->Controller->createView();
-        $this->assertInstanceOf(JsonView::class, $view);
-        $this->assertSame('json', $view->getLayoutPath());
-        $this->assertSame('json', $view->getSubDir());
-    }
-
-    /**
-     * test custom XmlView class is loaded and correct.
-     *
-     * @triggers Controller.startup $this->Controller
-     */
-    public function testXmlViewLoaded(): void
-    {
-        Router::extensions(['json', 'xml', 'ajax'], false);
-        $this->Controller->setRequest($this->Controller->getRequest()->withParam('_ext', 'xml'));
-        $event = new Event('Controller.startup', $this->Controller);
-        $this->RequestHandler->startup($event);
-        $event = new Event('Controller.beforeRender', $this->Controller);
-        $this->RequestHandler->beforeRender($event);
-        $view = $this->Controller->createView();
-        $this->assertInstanceOf(XmlView::class, $view);
-        $this->assertSame('xml', $view->getLayoutPath());
-        $this->assertSame('xml', $view->getSubDir());
-    }
-
-    /**
-     * test custom AjaxView class is loaded and correct.
-     *
-     * @triggers Controller.startup $this->Controller
-     */
-    public function testAjaxViewLoaded(): void
-    {
-        Router::extensions(['json', 'xml', 'ajax'], false);
-        $this->Controller->setRequest($this->Controller->getRequest()->withParam('_ext', 'ajax'));
-        $event = new Event('Controller.startup', $this->Controller);
-        $this->RequestHandler->startup($event);
-        $event = new Event('Controller.beforeRender', $this->Controller);
-        $this->RequestHandler->beforeRender($event);
-        $view = $this->Controller->createView();
-        $this->assertInstanceOf(AjaxView::class, $view);
-        $this->assertSame('ajax', $view->getLayout());
-    }
-
-    /**
-     * test configured extension but no view class set.
-     *
-     * @triggers Controller.beforeRender $this->Controller
-     */
-    public function testNoViewClassExtension(): void
-    {
-        Router::extensions(['json', 'xml', 'ajax', 'csv'], false);
-        $this->Controller->setRequest($this->Controller->getRequest()->withParam('_ext', 'csv'));
-        $event = new Event('Controller.startup', $this->Controller);
-        $this->RequestHandler->startup($event);
-        $this->Controller->getEventManager()->on('Controller.beforeRender', function () {
-            return $this->Controller->getResponse();
-        });
-        $this->Controller->render();
-        $this->assertSame('RequestHandlerTest' . DS . 'csv', $this->Controller->viewBuilder()->getTemplatePath());
-        $this->assertSame('csv', $this->Controller->viewBuilder()->getLayoutPath());
-    }
-
-    /**
-     * Tests that configured extensions that have no configured mimetype do not silently fallback to HTML.
-     */
-    public function testUnrecognizedExtensionFailure(): void
-    {
-        $this->expectException(NotFoundException::class);
-        $this->expectExceptionMessage('Invoked extension not recognized/configured: foo');
-
-        Router::extensions(['json', 'foo'], false);
-        $this->Controller->setRequest($this->Controller->getRequest()->withParam('_ext', 'foo'));
-        $event = new Event('Controller.startup', $this->Controller);
-        $this->RequestHandler->startup($event);
-        $this->Controller->getEventManager()->on('Controller.beforeRender', function () {
-            return $this->Controller->getResponse();
-        });
-        $this->Controller->render();
-        $this->assertSame('RequestHandlerTest' . DS . 'csv', $this->Controller->viewBuilder()->getTemplatePath());
-    }
-
-    /**
-     * testRenderAs method
-     */
-    public function testRenderAs(): void
-    {
-        $this->RequestHandler->renderAs($this->Controller, 'rss');
-
-        $this->Controller->viewBuilder()->setTemplatePath('request_handler_test\\rss');
-        $this->RequestHandler->renderAs($this->Controller, 'js');
-        $this->assertSame('request_handler_test' . DS . 'js', $this->Controller->viewBuilder()->getTemplatePath());
-    }
-
-    /**
-     * test that attachment headers work with renderAs
-     */
-    public function testRenderAsWithAttachment(): void
-    {
-        $this->Controller->setRequest($this->request->withHeader('Accept', 'application/xml;q=1.0'));
-
-        $this->RequestHandler->renderAs($this->Controller, 'xml', ['attachment' => 'myfile.xml']);
-        $this->assertSame(XmlView::class, $this->Controller->viewBuilder()->getClassName());
-        $this->assertSame('application/xml', $this->Controller->getResponse()->getType());
-        $this->assertSame('UTF-8', $this->Controller->getResponse()->getCharset());
-        $this->assertStringContainsString('myfile.xml', $this->Controller->getResponse()->getHeaderLine('Content-Disposition'));
-    }
-
-    /**
-     * test that respondAs works as expected.
-     */
-    public function testRespondAs(): void
-    {
-        $result = $this->RequestHandler->respondAs('json');
-        $this->assertTrue($result);
-        $this->assertSame('application/json', $this->Controller->getResponse()->getType());
-
-        $result = $this->RequestHandler->respondAs('text/xml');
-        $this->assertTrue($result);
-        $this->assertSame('text/xml', $this->Controller->getResponse()->getType());
-    }
-
-    /**
-     * test that attachment headers work with respondAs
-     */
-    public function testRespondAsWithAttachment(): void
-    {
-        $result = $this->RequestHandler->respondAs('xml', ['attachment' => 'myfile.xml']);
-        $this->assertTrue($result);
-        $response = $this->Controller->getResponse();
-        $this->assertStringContainsString('myfile.xml', $response->getHeaderLine('Content-Disposition'));
-        $this->assertStringContainsString('application/xml', $response->getType());
-    }
-
-    /**
-     * test that calling renderAs() more than once continues to work.
-     *
-     * @link #6466
-     */
-    public function testRenderAsCalledTwice(): void
-    {
-        $this->Controller->getEventManager()->on('Controller.beforeRender', function (EventInterface $e) {
-            return $e->getSubject()->getResponse();
-        });
-        $this->Controller->render();
-
-        $this->RequestHandler->renderAs($this->Controller, 'print');
-        $this->assertSame('RequestHandlerTest' . DS . 'print', $this->Controller->viewBuilder()->getTemplatePath());
-        $this->assertSame('print', $this->Controller->viewBuilder()->getLayoutPath());
-
-        $this->RequestHandler->renderAs($this->Controller, 'js');
-        $this->assertSame('RequestHandlerTest' . DS . 'js', $this->Controller->viewBuilder()->getTemplatePath());
-        $this->assertSame('js', $this->Controller->viewBuilder()->getLayoutPath());
-    }
-
-    /**
-     * testRequestContentTypes method
-     */
-    public function testRequestContentTypes(): void
-    {
-        $this->Controller->setRequest($this->request->withEnv('REQUEST_METHOD', 'GET'));
-        $this->assertNull($this->RequestHandler->requestedWith());
-
-        $this->Controller->setRequest($this->request->withEnv('REQUEST_METHOD', 'POST')
-            ->withEnv('CONTENT_TYPE', 'application/json'));
-        $this->assertSame('json', $this->RequestHandler->requestedWith());
-
-        $result = $this->RequestHandler->requestedWith(['json', 'xml']);
-        $this->assertSame('json', $result);
-
-        $result = $this->RequestHandler->requestedWith(['rss', 'atom']);
-        $this->assertFalse($result);
-
-        $this->Controller->setRequest($this->request
-            ->withEnv('REQUEST_METHOD', 'PATCH')
-            ->withEnv('CONTENT_TYPE', 'application/json'));
-        $this->assertSame('json', $this->RequestHandler->requestedWith());
-
-        $this->Controller->setRequest($this->request
-            ->withEnv('REQUEST_METHOD', 'DELETE')
-            ->withEnv('CONTENT_TYPE', 'application/json'));
-        $this->assertSame('json', $this->RequestHandler->requestedWith());
-
-        $this->Controller->setRequest($this->request
-            ->withEnv('REQUEST_METHOD', 'POST')
-            ->withEnv('CONTENT_TYPE', 'application/json'));
-        $result = $this->RequestHandler->requestedWith(['json', 'xml']);
-        $this->assertSame('json', $result);
-
-        $result = $this->RequestHandler->requestedWith(['rss', 'atom']);
-        $this->assertFalse($result);
-
-        $this->Controller->setRequest($this->request->withHeader(
-            'Accept',
-            'text/xml,application/xml,application/xhtml+xml,text/html,text/plain,image/png,*/*'
-        ));
-        $this->assertTrue($this->RequestHandler->prefers('xml'));
-        $this->assertFalse($this->RequestHandler->prefers('atom'));
-        $this->assertFalse($this->RequestHandler->prefers('rss'));
-
-        $this->Controller->setRequest($this->request->withHeader(
-            'Accept',
-            'application/atom+xml,text/xml,application/xml,application/xhtml+xml,text/html,text/plain,image/png,*/*'
-        ));
-        $this->assertTrue($this->RequestHandler->prefers('atom'));
-        $this->assertFalse($this->RequestHandler->prefers('rss'));
-
-        $this->Controller->setRequest($this->request->withHeader(
-            'Accept',
-            'application/rss+xml,text/xml,application/xml,application/xhtml+xml,text/html,text/plain,image/png,*/*'
-        ));
-        $this->assertFalse($this->RequestHandler->prefers('atom'));
-        $this->assertTrue($this->RequestHandler->prefers('rss'));
-    }
-
-    /**
-     * test that map alias converts aliases to content types.
-     */
-    public function testMapAlias(): void
-    {
-        $result = $this->RequestHandler->mapAlias('xml');
-        $this->assertSame('application/xml', $result);
-
-        $result = $this->RequestHandler->mapAlias('text/html');
-        $this->assertNull($result);
-
-        $result = $this->RequestHandler->mapAlias('wap');
-        $this->assertSame('text/vnd.wap.wml', $result);
-
-        $result = $this->RequestHandler->mapAlias(['xml', 'js', 'json']);
-        $expected = ['application/xml', 'application/javascript', 'application/json'];
-        $this->assertEquals($expected, $result);
-    }
-
-    /**
-     * test accepts() on the component
-     */
-    public function testAccepts(): void
-    {
-        $this->Controller->setRequest($this->request->withHeader(
-            'Accept',
-            'text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5'
-        ));
-        $this->assertTrue($this->RequestHandler->accepts(['js', 'xml', 'html']));
-        $this->assertFalse($this->RequestHandler->accepts(['gif', 'jpeg', 'foo']));
-
-        $this->Controller->setRequest($this->request->withHeader('Accept', '*/*;q=0.5'));
-        $this->assertFalse($this->RequestHandler->accepts('rss'));
-    }
-
-    /**
-     * test accepts and prefers methods.
-     */
-    public function testPrefers(): void
-    {
-        $this->Controller->setRequest($this->request->withHeader(
-            'Accept',
-            'text/xml,application/xml,application/xhtml+xml,text/html,text/plain,image/png,*/*'
-        ));
-        $this->assertNotEquals('rss', $this->RequestHandler->prefers());
-
-        $this->RequestHandler->setExt('rss');
-        $this->assertSame('rss', $this->RequestHandler->prefers());
-        $this->assertFalse($this->RequestHandler->prefers('xml'));
-        $this->assertSame('xml', $this->RequestHandler->prefers(['js', 'xml', 'xhtml']));
-        $this->assertFalse($this->RequestHandler->prefers(['red', 'blue']));
-        $this->assertSame('xhtml', $this->RequestHandler->prefers(['js', 'json', 'xhtml']));
-        $this->assertTrue($this->RequestHandler->prefers(['rss']), 'Should return true if input matches ext.');
-        $this->assertFalse($this->RequestHandler->prefers(['html']), 'No match with ext, return false.');
-
-        $this->_init();
-        $this->Controller->setRequest($this->request->withHeader(
-            'Accept',
-            'text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5'
-        ));
-        $this->assertSame('xml', $this->RequestHandler->prefers());
-
-        $this->Controller->setRequest($this->request->withHeader('Accept', '*/*;q=0.5'));
-        $this->assertSame('html', $this->RequestHandler->prefers());
-        $this->assertFalse($this->RequestHandler->prefers('rss'));
-
-        $this->Controller->setRequest($this->request->withEnv('HTTP_ACCEPT', ''));
-        $this->RequestHandler->setExt('json');
-        $this->assertFalse($this->RequestHandler->prefers('xml'));
-    }
-
-    /**
-     * Test checkNotModified method
-     *
-     * @triggers Controller.beforeRender $this->Controller
-     */
-    public function testCheckNotModifiedByEtagStar(): void
-    {
-        $response = new Response();
-        $response = $response->withEtag('something')
-            ->withHeader('Content-Type', 'text/plain')
-            ->withStringBody('keeper');
-        $this->Controller->setResponse($response);
-        $this->Controller->setRequest($this->request->withHeader('If-None-Match', '*'));
-
-        $event = new Event('Controller.beforeRender', $this->Controller);
-        $requestHandler = new RequestHandlerComponent($this->Controller->components());
-        $requestHandler->beforeRender($event);
-        $this->assertTrue($event->isStopped());
-        $this->assertSame(304, $this->Controller->getResponse()->getStatusCode());
-        $this->assertSame('', (string)$this->Controller->getResponse()->getBody());
-        $this->assertFalse($this->Controller->getResponse()->hasHeader('Content-Type'), 'header should not be removed.');
-    }
-
-    /**
-     * Test checkNotModified method
-     *
-     * @triggers Controller.beforeRender
-     */
-    public function testCheckNotModifiedByEtagExact(): void
-    {
-        $response = new Response();
-        $response = $response->withEtag('something', true)
-            ->withHeader('Content-Type', 'text/plain')
-            ->withStringBody('keeper');
-        $this->Controller->setResponse($response);
-
-        $this->Controller->setRequest($this->request->withHeader('If-None-Match', 'W/"something", "other"'));
-        $event = new Event('Controller.beforeRender', $this->Controller);
-
-        $requestHandler = new RequestHandlerComponent($this->Controller->components());
-        $requestHandler->beforeRender($event);
-        $this->assertTrue($event->isStopped());
-        $this->assertSame(304, $this->Controller->getResponse()->getStatusCode());
-        $this->assertSame('', (string)$this->Controller->getResponse()->getBody());
-        $this->assertFalse($this->Controller->getResponse()->hasHeader('Content-Type'));
-    }
-
-    /**
-     * Test checkNotModified method
-     *
-     * @triggers Controller.beforeRender $this->Controller
-     */
-    public function testCheckNotModifiedByEtagAndTime(): void
-    {
-        $this->Controller->setRequest($this->request
-            ->withHeader('If-None-Match', 'W/"something", "other"')
-            ->withHeader('If-Modified-Since', '2012-01-01 00:00:00'));
-
-        $response = new Response();
-        $response = $response->withEtag('something', true)
-            ->withHeader('Content-type', 'text/plain')
-            ->withStringBody('should be removed')
-            ->withModified('2012-01-01 00:00:00');
-        $this->Controller->setResponse($response);
-
-        $event = new Event('Controller.beforeRender', $this->Controller);
-        $requestHandler = new RequestHandlerComponent($this->Controller->components());
-        $requestHandler->beforeRender($event);
-        $this->assertTrue($event->isStopped());
-
-        $this->assertSame(304, $this->Controller->getResponse()->getStatusCode());
-        $this->assertSame('', (string)$this->Controller->getResponse()->getBody());
-        $this->assertFalse($this->Controller->getResponse()->hasHeader('Content-type'));
-    }
-
-    /**
-     * Test checkNotModified method
-     *
-     * @triggers Controller.beforeRender $this->Controller
-     */
-    public function testCheckNotModifiedNoInfo(): void
-    {
-        $response = new Response();
-        $this->Controller->setResponse($response);
-
-        $event = new Event('Controller.beforeRender', $this->Controller);
-        $requestHandler = new RequestHandlerComponent($this->Controller->components());
-        $requestHandler->beforeRender($event);
-        $this->assertSame(200, $response->getStatusCode());
-    }
-
-    /**
-     * Test default options in construction
-     */
-    public function testConstructDefaultOptions(): void
-    {
-        $requestHandler = new RequestHandlerComponent($this->Controller->components());
-        $viewClass = $requestHandler->getConfig('viewClassMap');
-        $expected = [
-            'json' => 'Json',
-            'xml' => 'Xml',
-            'ajax' => 'Ajax',
-        ];
-        $this->assertEquals($expected, $viewClass);
-    }
-
-    /**
-     * Test options in constructor replace defaults
-     */
-    public function testConstructReplaceOptions(): void
-    {
-        $requestHandler = new RequestHandlerComponent(
-            $this->Controller->components(),
-            [
-                'viewClassMap' => ['json' => 'Json'],
-                'inputTypeMap' => ['json' => ['json_decode', true]],
-            ]
-        );
-        $viewClass = $requestHandler->getConfig('viewClassMap');
-        $expected = [
-            'json' => 'Json',
-        ];
-        $this->assertEquals($expected, $viewClass);
-
-        $inputs = $requestHandler->getConfig('inputTypeMap');
-        $this->assertArrayHasKey('json', $inputs);
-        $this->assertCount(1, $inputs);
-    }
-
-    /**
-     * test beforeRender() doesn't override response type set in controller action
-     */
-    public function testBeforeRender(): void
-    {
-        $this->Controller->set_response_type();
-        $event = new Event('Controller.beforeRender', $this->Controller);
-        $this->RequestHandler->beforeRender($event);
-        $this->assertSame('text/plain', $this->Controller->getResponse()->getType());
-    }
-
-    /**
-     * tests beforeRender automatically uses renderAs when a supported extension is found
-     */
-    public function testBeforeRenderAutoRenderAs(): void
-    {
-        $this->Controller->setRequest($this->request->withParam('_ext', 'csv'));
-        $this->RequestHandler->startup(new Event('Controller.startup', $this->Controller));
-
-        $event = new Event('Controller.beforeRender', $this->Controller);
-        $this->RequestHandler->beforeRender($event);
-        $this->assertSame('text/csv', $this->Controller->getResponse()->getType());
-    }
-}

+ 19 - 19
tests/TestCase/Controller/ComponentRegistryTest.php

@@ -17,7 +17,7 @@ declare(strict_types=1);
 namespace Cake\Test\TestCase\Controller;
 
 use Cake\Controller\Component\FlashComponent;
-use Cake\Controller\Component\RequestHandlerComponent;
+use Cake\Controller\Component\FormProtectionComponent;
 use Cake\Controller\ComponentRegistry;
 use Cake\Controller\Controller;
 use Cake\Controller\Exception\MissingComponentException;
@@ -162,10 +162,10 @@ class ComponentRegistryTest extends TestCase
     public function testReset(): void
     {
         $eventManager = $this->Components->getController()->getEventManager();
-        $instance = $this->Components->load('RequestHandler');
+        $instance = $this->Components->load('FormProtection');
         $this->assertSame(
             $instance,
-            $this->Components->RequestHandler,
+            $this->Components->FormProtection,
             'Instance in registry should be the same as previously loaded'
         );
         $this->assertCount(1, $eventManager->listeners('Controller.startup'));
@@ -173,7 +173,7 @@ class ComponentRegistryTest extends TestCase
         $this->assertSame($this->Components, $this->Components->reset());
         $this->assertCount(0, $eventManager->listeners('Controller.startup'));
 
-        $this->assertNotSame($instance, $this->Components->load('RequestHandler'));
+        $this->assertNotSame($instance, $this->Components->load('FormProtection'));
     }
 
     /**
@@ -183,11 +183,11 @@ class ComponentRegistryTest extends TestCase
     {
         $eventManager = $this->Components->getController()->getEventManager();
 
-        $this->Components->load('RequestHandler');
-        $result = $this->Components->unload('RequestHandler');
+        $this->Components->load('FormProtection');
+        $result = $this->Components->unload('FormProtection');
 
         $this->assertSame($this->Components, $result);
-        $this->assertFalse(isset($this->Components->RequestHandler), 'Should be gone');
+        $this->assertFalse(isset($this->Components->FormProtection), 'Should be gone');
         $this->assertCount(0, $eventManager->listeners('Controller.startup'));
     }
 
@@ -198,10 +198,10 @@ class ComponentRegistryTest extends TestCase
     {
         $eventManager = $this->Components->getController()->getEventManager();
 
-        $this->Components->load('RequestHandler');
-        unset($this->Components->RequestHandler);
+        $this->Components->load('FormProtection');
+        unset($this->Components->FormProtection);
 
-        $this->assertFalse(isset($this->Components->RequestHandler), 'Should be gone');
+        $this->assertFalse(isset($this->Components->FormProtection), 'Should be gone');
         $this->assertCount(0, $eventManager->listeners('Controller.startup'));
     }
 
@@ -223,11 +223,11 @@ class ComponentRegistryTest extends TestCase
         $eventManager = $this->Components->getController()->getEventManager();
         $this->assertCount(0, $eventManager->listeners('Controller.startup'));
 
-        $requestHandler = new RequestHandlerComponent($this->Components);
-        $result = $this->Components->set('RequestHandler', $requestHandler);
+        $formProtection = new FormProtectionComponent($this->Components);
+        $result = $this->Components->set('FormProtection', $formProtection);
 
-        $this->assertSame($this->Components, $result);
-        $this->assertTrue(isset($this->Components->RequestHandler), 'Should be present');
+        $this->assertEquals($this->Components, $result);
+        $this->assertTrue(isset($this->Components->FormProtection), 'Should be present');
         $this->assertCount(1, $eventManager->listeners('Controller.startup'));
     }
 
@@ -239,10 +239,10 @@ class ComponentRegistryTest extends TestCase
         $eventManager = $this->Components->getController()->getEventManager();
         $this->assertCount(0, $eventManager->listeners('Controller.startup'));
 
-        $requestHandler = new RequestHandlerComponent($this->Components);
-        $this->Components->RequestHandler = $requestHandler;
+        $formProtection = new FormProtectionComponent($this->Components);
+        $this->Components->FormProtection = $formProtection;
 
-        $this->assertTrue(isset($this->Components->RequestHandler), 'Should be present');
+        $this->assertTrue(isset($this->Components->FormProtection), 'Should be present');
         $this->assertCount(1, $eventManager->listeners('Controller.startup'));
     }
 
@@ -251,7 +251,7 @@ class ComponentRegistryTest extends TestCase
      */
     public function testCountable(): void
     {
-        $this->Components->load('RequestHandler');
+        $this->Components->load('FormProtection');
         $this->assertInstanceOf(Countable::class, $this->Components);
         $count = count($this->Components);
         $this->assertSame(1, $count);
@@ -262,7 +262,7 @@ class ComponentRegistryTest extends TestCase
      */
     public function testTraversable(): void
     {
-        $this->Components->load('RequestHandler');
+        $this->Components->load('FormProtection');
         $this->assertInstanceOf(Traversable::class, $this->Components);
 
         $result = null;

+ 0 - 19
tests/test_app/TestApp/Controller/Component/RequestHandlerExtComponent.php

@@ -1,19 +0,0 @@
-<?php
-declare(strict_types=1);
-
-namespace TestApp\Controller\Component;
-
-use Cake\Controller\Component\RequestHandlerComponent;
-
-class RequestHandlerExtComponent extends RequestHandlerComponent
-{
-    public function getExt(): ?string
-    {
-        return $this->ext;
-    }
-
-    public function setExt(?string $ext)
-    {
-        $this->ext = $ext;
-    }
-}

+ 7 - 1
tests/test_app/TestApp/Controller/PostsController.php

@@ -18,6 +18,7 @@ namespace TestApp\Controller;
 
 use Cake\Event\EventInterface;
 use Cake\Http\Cookie\Cookie;
+use Cake\View\JsonView;
 use OutOfBoundsException;
 
 /**
@@ -31,7 +32,6 @@ class PostsController extends AppController
     public function initialize(): void
     {
         $this->loadComponent('Flash');
-        $this->loadComponent('RequestHandler');
         $this->loadComponent('FormProtection');
 
         $this->middleware(function ($request, $handler) {
@@ -64,6 +64,12 @@ class PostsController extends AppController
         }
     }
 
+    public function viewClasses(): array
+    {
+        return [JsonView::class];
+    }
+
+
     /**
      * Index method.
      *

+ 0 - 73
tests/test_app/TestApp/Controller/RequestHandlerTestController.php

@@ -1,73 +0,0 @@
-<?php
-declare(strict_types=1);
-
-/**
- * CakePHP(tm) : Rapid Development Framework (https://cakephp.org)
- *
- * CakePHP(tm) : Rapid Development Framework (https://cakephp.org)
- * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
- *
- * Licensed under The MIT License
- * For full copyright and license information, please see the LICENSE.txt
- * Redistributions of files must retain the above copyright notice.
- *
- * @copyright     Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
- * @link          https://cakephp.org CakePHP(tm) Project
- * @since         3.0.0
- * @license       https://opensource.org/licenses/mit-license.php MIT License
- */
-namespace TestApp\Controller;
-
-use Cake\Controller\Controller;
-
-/**
- * RequestHandlerTestController class
- */
-class RequestHandlerTestController extends Controller
-{
-    /**
-     * test method for AJAX redirection
-     *
-     * @return void
-     */
-    public function destination()
-    {
-        $this->viewBuilder()->setTemplatePath('Posts');
-        $this->render('index');
-    }
-
-    /**
-     * test method for AJAX redirection + parameter parsing
-     *
-     * @param string|null $one
-     * @param string|null $two
-     * @return void
-     */
-    public function param_method($one = null, $two = null)
-    {
-        echo "one: $one two: $two";
-        $this->autoRender = false;
-    }
-
-    /**
-     * test method for testing layout rendering when isAjax()
-     *
-     * @return void
-     */
-    public function ajax2_layout()
-    {
-        $this->viewBuilder()->setLayout('ajax2');
-        $this->destination();
-    }
-
-    /**
-     * test method for testing that response type set in action doesn't get
-     * overridden by RequestHandlerComponent::beforeRender()
-     *
-     * @return void
-     */
-    public function set_response_type()
-    {
-        $this->response = $this->response->withType('txt');
-    }
-}