diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 966393e..c2746b9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -49,4 +49,25 @@ jobs: vendor/bin/phpunit --coverage-clover=coverage.xml else vendor/bin/phpunit - fi \ No newline at end of file + fi + + cs: + name: Coding Standard + runs-on: ubuntu-22.04 + + steps: + - uses: actions/checkout@v4 + + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: '8.2' + extensions: mbstring, intl + coverage: none + tools: cs2pr + + - name: Composer install + uses: ramsey/composer-install@v2 + + - name: Run phpcs + run: vendor/bin/phpcs --report=checkstyle src/ tests/ | cs2pr \ No newline at end of file diff --git a/composer.json b/composer.json index 977b352..ab477b7 100644 --- a/composer.json +++ b/composer.json @@ -10,6 +10,7 @@ "psr/http-server-middleware": "^1.0" }, "require-dev": { + "cakephp/cakephp-codesniffer": "@stable", "phpunit/phpunit": "^10.1" }, "autoload": { @@ -19,11 +20,18 @@ }, "autoload-dev": { "psr-4": { - "Cors\\Test\\": "tests", - "Cake\\Test\\": "./vendor/cakephp/cakephp/tests" + "TestApp\\": "tests/test_app/src", + "Rrd108\\Cors\\Tests\\": "tests" } }, "scripts": { - "test": "phpunit" + "test": "phpunit", + "cs-check": "phpcs --colors -p ./src ./tests", + "cs-fix": "phpcbf --colors -p ./src ./tests" + }, + "config": { + "allow-plugins": { + "dealerdirect/phpcodesniffer-composer-installer": true + } } } diff --git a/composer.lock b/composer.lock index c3b1cc1..02eb754 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "bcfcb875c9001311a189513a14e6274d", + "content-hash": "eeedffb121d417a01228263374a8f988", "packages": [ { "name": "cakephp/cakephp", @@ -918,6 +918,137 @@ } ], "packages-dev": [ + { + "name": "cakephp/cakephp-codesniffer", + "version": "5.1.1", + "source": { + "type": "git", + "url": "https://github.com/cakephp/cakephp-codesniffer.git", + "reference": "3227936e698774025a16fb808c28f92688672306" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/cakephp/cakephp-codesniffer/zipball/3227936e698774025a16fb808c28f92688672306", + "reference": "3227936e698774025a16fb808c28f92688672306", + "shasum": "" + }, + "require": { + "php": ">=8.1.0", + "phpstan/phpdoc-parser": "^1.4.5", + "slevomat/coding-standard": "^8.4", + "squizlabs/php_codesniffer": "^3.7.1" + }, + "require-dev": { + "phpunit/phpunit": "^7.1" + }, + "type": "phpcodesniffer-standard", + "autoload": { + "psr-4": { + "CakePHP\\": "CakePHP/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "CakePHP Community", + "homepage": "https://github.com/cakephp/cakephp-codesniffer/graphs/contributors" + } + ], + "description": "CakePHP CodeSniffer Standards", + "homepage": "https://cakephp.org", + "keywords": [ + "codesniffer", + "framework" + ], + "support": { + "forum": "https://stackoverflow.com/tags/cakephp", + "irc": "irc://irc.freenode.org/cakephp", + "issues": "https://github.com/cakephp/cakephp-codesniffer/issues", + "source": "https://github.com/cakephp/cakephp-codesniffer" + }, + "time": "2023-04-09T13:00:25+00:00" + }, + { + "name": "dealerdirect/phpcodesniffer-composer-installer", + "version": "v1.0.0", + "source": { + "type": "git", + "url": "https://github.com/PHPCSStandards/composer-installer.git", + "reference": "4be43904336affa5c2f70744a348312336afd0da" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/PHPCSStandards/composer-installer/zipball/4be43904336affa5c2f70744a348312336afd0da", + "reference": "4be43904336affa5c2f70744a348312336afd0da", + "shasum": "" + }, + "require": { + "composer-plugin-api": "^1.0 || ^2.0", + "php": ">=5.4", + "squizlabs/php_codesniffer": "^2.0 || ^3.1.0 || ^4.0" + }, + "require-dev": { + "composer/composer": "*", + "ext-json": "*", + "ext-zip": "*", + "php-parallel-lint/php-parallel-lint": "^1.3.1", + "phpcompatibility/php-compatibility": "^9.0", + "yoast/phpunit-polyfills": "^1.0" + }, + "type": "composer-plugin", + "extra": { + "class": "PHPCSStandards\\Composer\\Plugin\\Installers\\PHPCodeSniffer\\Plugin" + }, + "autoload": { + "psr-4": { + "PHPCSStandards\\Composer\\Plugin\\Installers\\PHPCodeSniffer\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Franck Nijhof", + "email": "franck.nijhof@dealerdirect.com", + "homepage": "http://www.frenck.nl", + "role": "Developer / IT Manager" + }, + { + "name": "Contributors", + "homepage": "https://github.com/PHPCSStandards/composer-installer/graphs/contributors" + } + ], + "description": "PHP_CodeSniffer Standards Composer Installer Plugin", + "homepage": "http://www.dealerdirect.com", + "keywords": [ + "PHPCodeSniffer", + "PHP_CodeSniffer", + "code quality", + "codesniffer", + "composer", + "installer", + "phpcbf", + "phpcs", + "plugin", + "qa", + "quality", + "standard", + "standards", + "style guide", + "stylecheck", + "tests" + ], + "support": { + "issues": "https://github.com/PHPCSStandards/composer-installer/issues", + "source": "https://github.com/PHPCSStandards/composer-installer" + }, + "time": "2023-01-05T11:28:13+00:00" + }, { "name": "myclabs/deep-copy", "version": "1.11.1", @@ -1146,6 +1277,53 @@ }, "time": "2022-02-21T01:04:05+00:00" }, + { + "name": "phpstan/phpdoc-parser", + "version": "1.25.0", + "source": { + "type": "git", + "url": "https://github.com/phpstan/phpdoc-parser.git", + "reference": "bd84b629c8de41aa2ae82c067c955e06f1b00240" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/bd84b629c8de41aa2ae82c067c955e06f1b00240", + "reference": "bd84b629c8de41aa2ae82c067c955e06f1b00240", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "require-dev": { + "doctrine/annotations": "^2.0", + "nikic/php-parser": "^4.15", + "php-parallel-lint/php-parallel-lint": "^1.2", + "phpstan/extension-installer": "^1.0", + "phpstan/phpstan": "^1.5", + "phpstan/phpstan-phpunit": "^1.1", + "phpstan/phpstan-strict-rules": "^1.0", + "phpunit/phpunit": "^9.5", + "symfony/process": "^5.2" + }, + "type": "library", + "autoload": { + "psr-4": { + "PHPStan\\PhpDocParser\\": [ + "src/" + ] + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "PHPDoc parser with support for nullable, intersection and generic types", + "support": { + "issues": "https://github.com/phpstan/phpdoc-parser/issues", + "source": "https://github.com/phpstan/phpdoc-parser/tree/1.25.0" + }, + "time": "2024-01-04T17:06:16+00:00" + }, { "name": "phpunit/php-code-coverage", "version": "10.1.11", @@ -2483,6 +2661,151 @@ ], "time": "2023-02-07T11:34:05+00:00" }, + { + "name": "slevomat/coding-standard", + "version": "8.14.1", + "source": { + "type": "git", + "url": "https://github.com/slevomat/coding-standard.git", + "reference": "fea1fd6f137cc84f9cba0ae30d549615dbc6a926" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/slevomat/coding-standard/zipball/fea1fd6f137cc84f9cba0ae30d549615dbc6a926", + "reference": "fea1fd6f137cc84f9cba0ae30d549615dbc6a926", + "shasum": "" + }, + "require": { + "dealerdirect/phpcodesniffer-composer-installer": "^0.6.2 || ^0.7 || ^1.0", + "php": "^7.2 || ^8.0", + "phpstan/phpdoc-parser": "^1.23.1", + "squizlabs/php_codesniffer": "^3.7.1" + }, + "require-dev": { + "phing/phing": "2.17.4", + "php-parallel-lint/php-parallel-lint": "1.3.2", + "phpstan/phpstan": "1.10.37", + "phpstan/phpstan-deprecation-rules": "1.1.4", + "phpstan/phpstan-phpunit": "1.3.14", + "phpstan/phpstan-strict-rules": "1.5.1", + "phpunit/phpunit": "8.5.21|9.6.8|10.3.5" + }, + "type": "phpcodesniffer-standard", + "extra": { + "branch-alias": { + "dev-master": "8.x-dev" + } + }, + "autoload": { + "psr-4": { + "SlevomatCodingStandard\\": "SlevomatCodingStandard/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Slevomat Coding Standard for PHP_CodeSniffer complements Consistence Coding Standard by providing sniffs with additional checks.", + "keywords": [ + "dev", + "phpcs" + ], + "support": { + "issues": "https://github.com/slevomat/coding-standard/issues", + "source": "https://github.com/slevomat/coding-standard/tree/8.14.1" + }, + "funding": [ + { + "url": "https://github.com/kukulich", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/slevomat/coding-standard", + "type": "tidelift" + } + ], + "time": "2023-10-08T07:28:08+00:00" + }, + { + "name": "squizlabs/php_codesniffer", + "version": "3.8.1", + "source": { + "type": "git", + "url": "https://github.com/PHPCSStandards/PHP_CodeSniffer.git", + "reference": "14f5fff1e64118595db5408e946f3a22c75807f7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/PHPCSStandards/PHP_CodeSniffer/zipball/14f5fff1e64118595db5408e946f3a22c75807f7", + "reference": "14f5fff1e64118595db5408e946f3a22c75807f7", + "shasum": "" + }, + "require": { + "ext-simplexml": "*", + "ext-tokenizer": "*", + "ext-xmlwriter": "*", + "php": ">=5.4.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0 || ^8.0 || ^9.3.4" + }, + "bin": [ + "bin/phpcbf", + "bin/phpcs" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.x-dev" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Greg Sherwood", + "role": "Former lead" + }, + { + "name": "Juliette Reinders Folmer", + "role": "Current lead" + }, + { + "name": "Contributors", + "homepage": "https://github.com/PHPCSStandards/PHP_CodeSniffer/graphs/contributors" + } + ], + "description": "PHP_CodeSniffer tokenizes PHP, JavaScript and CSS files and detects violations of a defined set of coding standards.", + "homepage": "https://github.com/PHPCSStandards/PHP_CodeSniffer", + "keywords": [ + "phpcs", + "standards", + "static analysis" + ], + "support": { + "issues": "https://github.com/PHPCSStandards/PHP_CodeSniffer/issues", + "security": "https://github.com/PHPCSStandards/PHP_CodeSniffer/security/policy", + "source": "https://github.com/PHPCSStandards/PHP_CodeSniffer", + "wiki": "https://github.com/PHPCSStandards/PHP_CodeSniffer/wiki" + }, + "funding": [ + { + "url": "https://github.com/PHPCSStandards", + "type": "github" + }, + { + "url": "https://github.com/jrfnl", + "type": "github" + }, + { + "url": "https://opencollective.com/php_codesniffer", + "type": "open_collective" + } + ], + "time": "2024-01-11T20:47:48+00:00" + }, { "name": "theseer/tokenizer", "version": "1.2.2", @@ -2536,7 +2859,9 @@ ], "aliases": [], "minimum-stability": "stable", - "stability-flags": [], + "stability-flags": { + "cakephp/cakephp-codesniffer": 0 + }, "prefer-stable": false, "prefer-lowest": false, "platform": [], diff --git a/phpcs.xml b/phpcs.xml new file mode 100644 index 0000000..39c70e9 --- /dev/null +++ b/phpcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/src/CorsPlugin.php b/src/CorsPlugin.php index 9e1b2ca..afdd337 100644 --- a/src/CorsPlugin.php +++ b/src/CorsPlugin.php @@ -1,47 +1,24 @@ insertBefore( 'Cake\Routing\Middleware\RoutingMiddleware', new CorsMiddleware($this) ); - - return $middleware; - } - - public function console(CommandCollection $commands): CommandCollection - { - // Add console commands here. - $commands = parent::console($commands); - - return $commands; - } - - public function bootstrap(PluginApplicationInterface $app): void - { - // Add constants, load configuration defaults. - // By default will load `config/bootstrap.php` in the plugin. - parent::bootstrap($app); - } - - public function routes($routes): void - { - // Add routes. - // By default will load `config/routes.php` in the plugin. - parent::routes($routes); } } diff --git a/src/Routing/Middleware/CorsMiddleware.php b/src/Routing/Middleware/CorsMiddleware.php index 383986a..c84371a 100644 --- a/src/Routing/Middleware/CorsMiddleware.php +++ b/src/Routing/Middleware/CorsMiddleware.php @@ -1,32 +1,34 @@ getMethod()) === 'OPTIONS') { - if (!array_intersect($request->getHeader("Access-Control-Request-Method"), Configure::read('Cors.AllowMethods'))) { - $response = new Response([ + $allowedMethods = Configure::read('Cors.AllowMethods'); + if (!array_intersect($request->getHeader('Access-Control-Request-Method'), $allowedMethods)) { + $response = new Response([ 'status' => 403, - 'body' => 'Method Forbidden' + 'body' => 'Method Forbidden', ]); } else { - $response = new Response([ - 'status' => 200 + $response = new Response([ + 'status' => 200, ]); } } else { @@ -38,6 +40,11 @@ public function process(ServerRequestInterface $request, RequestHandlerInterface return $response; } + /** + * @param \Psr\Http\Message\ServerRequestInterface $request + * @param \Psr\Http\Message\ResponseInterface $response + * @return \Psr\Http\Message\ResponseInterface + */ public function addHeaders(ServerRequestInterface $request, ResponseInterface $response): ResponseInterface { if ($request->getHeader('Origin')) { @@ -57,12 +64,11 @@ public function addHeaders(ServerRequestInterface $request, ResponseInterface $r return $response; } - /** * @param \Psr\Http\Message\ServerRequestInterface $request * @return array|string */ - private function _allowOrigin(ServerRequestInterface $request) + private function _allowOrigin(ServerRequestInterface $request): array|string { $allowOrigin = Configure::read('Cors.AllowOrigin'); $origin = $request->getHeader('Origin'); @@ -72,7 +78,7 @@ private function _allowOrigin(ServerRequestInterface $request) } if (is_array($allowOrigin)) { - $origin = (array) $origin; + $origin = (array)$origin; foreach ($origin as $o) { if (in_array($o, $allowOrigin)) { @@ -89,24 +95,24 @@ private function _allowOrigin(ServerRequestInterface $request) /** * @return String */ - private function _allowCredentials(): String + private function _allowCredentials(): string { - return (Configure::read('Cors.AllowCredentials')) ? 'true' : 'false'; + return Configure::read('Cors.AllowCredentials') ? 'true' : 'false'; } /** * @return String */ - private function _allowMethods(): String + private function _allowMethods(): string { - return implode(', ', (array) Configure::read('Cors.AllowMethods')); + return implode(', ', (array)Configure::read('Cors.AllowMethods')); } /** * @param \Psr\Http\Message\ServerRequestInterface $request * @return String */ - private function _allowHeaders(ServerRequestInterface $request): String + private function _allowHeaders(ServerRequestInterface $request): string { $allowHeaders = Configure::read('Cors.AllowHeaders'); @@ -114,18 +120,18 @@ private function _allowHeaders(ServerRequestInterface $request): String return $request->getHeaderLine('Access-Control-Request-Headers'); } - return implode(', ', (array) $allowHeaders); + return implode(', ', (array)$allowHeaders); } /** * @return String */ - private function _exposeHeaders(): String + private function _exposeHeaders(): string { $exposeHeaders = Configure::read('Cors.ExposeHeaders'); if (is_string($exposeHeaders) || is_array($exposeHeaders)) { - return implode(', ', (array) $exposeHeaders); + return implode(', ', (array)$exposeHeaders); } return ''; @@ -134,10 +140,10 @@ private function _exposeHeaders(): String /** * @return String */ - private function _maxAge(): String + private function _maxAge(): string { - $maxAge = (string) Configure::read('Cors.MaxAge'); + $maxAge = (string)Configure::read('Cors.MaxAge'); - return ($maxAge) ?: '0'; + return $maxAge ?: '0'; } } diff --git a/tests/TestCase/Middleware/CorsMiddlewareTest.php b/tests/TestCase/Middleware/CorsMiddlewareTest.php index c2f7fa3..9364a14 100644 --- a/tests/TestCase/Middleware/CorsMiddlewareTest.php +++ b/tests/TestCase/Middleware/CorsMiddlewareTest.php @@ -1,25 +1,25 @@ server = [ @@ -37,9 +37,25 @@ private function _setServer(array $server) private function _sendRequest() { $request = ServerRequestFactory::fromGlobals($this->server); - $handler = new RequestHandlerStub(); + $handler = new class 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); + } + }; $middleware = new CorsMiddleware(); $response = $middleware->process($request, $handler); + return $response; } @@ -95,6 +111,7 @@ private function _sendRequestForOriginTest($originUrl, $allowUrl) { Configure::write('Cors.AllowOrigin', $allowUrl); $this->_setServer(['HTTP_ORIGIN' => $originUrl]); + return $this->_sendRequest()->getHeaderLine('Access-Control-Allow-Origin'); } @@ -225,20 +242,3 @@ 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 569a1fc..bd991e3 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -1,5 +1,4 @@ [] + 'Rrd108/Cors' => [], ]; diff --git a/tests/test_app/src/Application.php b/tests/test_app/src/Application.php index 64be3a3..6a34262 100644 --- a/tests/test_app/src/Application.php +++ b/tests/test_app/src/Application.php @@ -1,18 +1,15 @@ add(new RoutingMiddleware($this))