diff --git a/README.md b/README.md index 7d26c3e..b3ae5a6 100644 --- a/README.md +++ b/README.md @@ -2,14 +2,16 @@ [![Build Status](https://travis-ci.org/ozee31/cakephp-cors.svg?branch=master)](https://travis-ci.org/ozee31/cakephp-cors) -A CakePHP (3.3+) plugin for activate cors domain in your application with [Middleware](http://book.cakephp.org/3.0/en/controllers/middleware.html). +A CakePHP (4+) plugin for activate cors domain in your application with [Middleware](http://book.cakephp.org/3.0/en/controllers/middleware.html). [Learn more about CORS](https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS) +**For cake 3.3+ use branch [cake-3](https://github.com/ozee31/cakephp-cors/tree/cake-3)** + ## Requirements -- PHP version 5.6 or higher -- CakePhp 3.3 or higher +- PHP version 7.2 or higher +- CakePhp 4.0 or higher ## Installation @@ -26,8 +28,12 @@ composer require ozee31/cakephp-cors Loading the Plugin ```PHP - // In config/bootstrap.php - Plugin::load('Cors', ['bootstrap' => true, 'routes' => false]); +// In src/Application.php +public function bootstrap(): void +{ + // code ... + $this->addPlugin('Cors'); +} ``` By default the plugin authorize cors for all origins, all methods and all headers and caches all for one day. diff --git a/composer.json b/composer.json index 262d929..96754c3 100644 --- a/composer.json +++ b/composer.json @@ -3,11 +3,14 @@ "description": "A CakePHP (3.3.x) plugin for activate cors domain in your application", "type": "cakephp-plugin", "require": { - "php": ">=5.6", - "cakephp/cakephp": ">=3.3.2 <4.0.0" + "php": ">=7.2.0", + "cakephp/cakephp": "^4.0", + "psr/http-server-handler": "^1.0", + "psr/http-server-middleware": "^1.0" }, "require-dev": { - "phpunit/phpunit": "5.*" + "phpunit/phpunit": "~8.5.0", + "cakephp/cakephp-codesniffer": "^4.0" }, "autoload": { "psr-4": { diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 312dfd8..b31c703 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -3,7 +3,6 @@ colors="true" processIsolation="false" stopOnFailure="false" - syntaxCheck="false" bootstrap="./tests/bootstrap.php" > @@ -31,13 +30,8 @@ - - ./vendor/ - ./vendor/ - - ./tests/ - ./tests/ - + + src/ + - diff --git a/src/Error/AppExceptionRenderer.php b/src/Error/AppExceptionRenderer.php index ad3b810..a6d60f7 100644 --- a/src/Error/AppExceptionRenderer.php +++ b/src/Error/AppExceptionRenderer.php @@ -2,11 +2,7 @@ namespace Cors\Error; use Cake\Core\Configure; -use Cake\Event\Event; -use Cake\Network\Request; -use Cake\Network\Response; -use Cake\Routing\Router; -use Exception; +use Cake\Controller\Controller; use Cors\Routing\Middleware\CorsMiddleware; function get_dynamic_parent() { @@ -16,19 +12,18 @@ class_alias(get_dynamic_parent(), 'Cors\Error\BaseExceptionRenderer'); class AppExceptionRenderer extends BaseExceptionRenderer { - /** * Returns the current controller. * * @return \Cake\Controller\Controller */ - protected function _getController() + protected function _getController(): Controller { $controller = parent::_getController(); $cors = new CorsMiddleware(); - $controller->response = $cors( - $controller->request, $controller->response, - function($request, $response){ return $response; } + $controller->response = $cors->addHeaders( + $controller->getRequest(), + $controller->getResponse() ); return $controller; } diff --git a/src/Plugin.php b/src/Plugin.php new file mode 100644 index 0000000..f75380f --- /dev/null +++ b/src/Plugin.php @@ -0,0 +1,8 @@ +handle($request); + + $response = $this->addHeaders($request, $response); + + return $response; + } + + public function addHeaders(ServerRequestInterface $request, ResponseInterface $response): ResponseInterface + { if ($request->getHeader('Origin')) { $response = $response ->withHeader('Access-Control-Allow-Origin', $this->_allowOrigin($request)) ->withHeader('Access-Control-Allow-Credentials', $this->_allowCredentials()) - ->withHeader('Access-Control-Max-Age', $this->_maxAge()) - ->withHeader('Access-Control-Expose-Headers', $this->_exposeHeaders()) - ; + ->withHeader('Access-Control-Max-Age', $this->_maxAge()); if (strtoupper($request->getMethod()) === 'OPTIONS') { $response = $response + ->withHeader('Access-Control-Expose-Headers', $this->_exposeHeaders()) ->withHeader('Access-Control-Allow-Headers', $this->_allowHeaders($request)) - ->withHeader('Access-Control-Allow-Methods', $this->_allowMethods()) - ; - return $response; + ->withHeader('Access-Control-Allow-Methods', $this->_allowMethods()); } + } - return $next($request, $response); + return $response; } + /** - * PHPCS docblock fix needed! + * @param \Psr\Http\Message\ServerRequestInterface $request + * @return array|string */ - private function _allowOrigin($request) { + private function _allowOrigin(ServerRequestInterface $request) + { $allowOrigin = Configure::read('Cors.AllowOrigin'); $origin = $request->getHeader('Origin'); @@ -59,36 +73,41 @@ private function _allowOrigin($request) { } /** - * PHPCS docblock fix needed! + * @return String */ - private function _allowCredentials() { + private function _allowCredentials(): String + { return (Configure::read('Cors.AllowCredentials')) ? 'true' : 'false'; } /** - * PHPCS docblock fix needed! + * @return String */ - private function _allowMethods() { + private function _allowMethods(): String + { return implode(', ', (array) Configure::read('Cors.AllowMethods')); } /** - * PHPCS docblock fix needed! + * @param \Psr\Http\Message\ServerRequestInterface $request + * @return String */ - private function _allowHeaders($request) { + private function _allowHeaders(ServerRequestInterface $request): String + { $allowHeaders = Configure::read('Cors.AllowHeaders'); if ($allowHeaders === true) { - return $request->getHeader('Access-Control-Request-Headers'); + return $request->getHeaderLine('Access-Control-Request-Headers'); } return implode(', ', (array) $allowHeaders); } /** - * PHPCS docblock fix needed! + * @return String */ - private function _exposeHeaders() { + private function _exposeHeaders(): String + { $exposeHeaders = Configure::read('Cors.ExposeHeaders'); if (is_string($exposeHeaders) || is_array($exposeHeaders)) { @@ -99,9 +118,10 @@ private function _exposeHeaders() { } /** - * PHPCS docblock fix needed! + * @return String */ - private function _maxAge() { + private function _maxAge(): String + { $maxAge = (string) Configure::read('Cors.MaxAge'); return ($maxAge) ?: '0'; diff --git a/tests/TestCase/Controller/ErrorControllerTest.php b/tests/TestCase/Controller/ErrorControllerTest.php index 2c9b495..5489b9f 100644 --- a/tests/TestCase/Controller/ErrorControllerTest.php +++ b/tests/TestCase/Controller/ErrorControllerTest.php @@ -1,10 +1,7 @@ server = [ @@ -33,12 +36,9 @@ private function _setServer(Array $server) private function _sendRequest() { $request = ServerRequestFactory::fromGlobals($this->server); - $response = new Response(); + $handler = new RequestHandlerStub(); $middleware = new CorsMiddleware(); - $next = function ($request, $response) { - return $response; - }; - $response = $middleware($request, $response, $next); + $response = $middleware->process($request, $handler); return $response; } @@ -85,7 +85,7 @@ public function testDefaultValuesIfIsAOptionsRequest() $response = $this->_sendRequest(); $headers = $response->getHeaders(); - $this->assertEquals([], $headers['Access-Control-Allow-Headers']); + $this->assertEquals('', current($headers['Access-Control-Allow-Headers'])); $this->assertEquals('GET, POST, PUT, PATCH, DELETE', current($headers['Access-Control-Allow-Methods'])); $this->assertEquals('', current($headers['Access-Control-Expose-Headers'])); } @@ -224,3 +224,20 @@ public function testMaxAgeFalse() $this->assertEquals(0, $responseMaxAge); } } + +class RequestHandlerStub implements RequestHandlerInterface +{ + public $callable; + + public function __construct(?callable $callable = null) + { + $this->callable = $callable ?: function ($request) { + return new Response(); + }; + } + + public function handle(ServerRequestInterface $request): ResponseInterface + { + return ($this->callable)($request); + } +} diff --git a/tests/bootstrap.php b/tests/bootstrap.php index 5b0f489..90bb771 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -23,4 +23,4 @@ chdir($root); require $root . '/vendor/cakephp/cakephp/tests/bootstrap.php'; -Plugin::load('Cors', ['bootstrap' => true, 'path' => dirname(dirname(__FILE__)) . DS]); +Plugin::getCollection()->add(new \Cors\Plugin(['bootstrap' => true, 'path' => dirname(dirname(__FILE__)) . DS]));