From 0d914a0e3888ad1b4706142cf865f120c36cf4b0 Mon Sep 17 00:00:00 2001 From: Greg Bowler Date: Tue, 15 Feb 2022 18:46:58 +0000 Subject: [PATCH 01/13] Depend on PHPUnit for development In order to run the unit tests, PHPUnit is a hard dev dependency, so I've included it in this commit, and now I can run the unit tests as part of this PR. --- composer.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/composer.json b/composer.json index a60bc88..5725d1a 100644 --- a/composer.json +++ b/composer.json @@ -25,6 +25,7 @@ } }, "require-dev": { - "symfony/phpunit-bridge": "^5.0" + "symfony/phpunit-bridge": "^5.0", + "phpunit/phpunit": "^9.5" } } From d8a356afde0139553ecc735ec5d865383e7f81ca Mon Sep 17 00:00:00 2001 From: Greg Bowler Date: Tue, 15 Feb 2022 18:59:28 +0000 Subject: [PATCH 02/13] Depend on PHPStan for development This is for #89 - to ensure correct type hints are provided to developers who use IDEs. --- composer.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 5725d1a..56d3863 100644 --- a/composer.json +++ b/composer.json @@ -26,6 +26,7 @@ }, "require-dev": { "symfony/phpunit-bridge": "^5.0", - "phpunit/phpunit": "^9.5" + "phpunit/phpunit": "^9.5", + "phpstan/phpstan": "^1.4" } } From e3d8b4c1dbd70484d325df5e8b4ba201c20cb612 Mon Sep 17 00:00:00 2001 From: Greg Bowler Date: Tue, 15 Feb 2022 19:33:27 +0000 Subject: [PATCH 03/13] Fix object model of AcceptHeader interface Fixes #89 - IDEs and PHPStan are happy with this implementation --- src/Negotiation/AbstractNegotiator.php | 2 +- src/Negotiation/Accept.php | 2 +- src/Negotiation/AcceptCharset.php | 2 +- src/Negotiation/AcceptEncoding.php | 2 +- src/Negotiation/AcceptLanguage.php | 2 +- src/Negotiation/BaseAccept.php | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Negotiation/AbstractNegotiator.php b/src/Negotiation/AbstractNegotiator.php index 79c7c9b..e4917dc 100644 --- a/src/Negotiation/AbstractNegotiator.php +++ b/src/Negotiation/AbstractNegotiator.php @@ -11,7 +11,7 @@ abstract class AbstractNegotiator * @param string $header A string containing an `Accept|Accept-*` header. * @param array $priorities A set of server priorities. * - * @return AcceptHeader|null best matching type + * @return BaseAccept|null best matching type */ public function getBest($header, array $priorities, $strict = false) { diff --git a/src/Negotiation/Accept.php b/src/Negotiation/Accept.php index 281ae27..27c1c88 100644 --- a/src/Negotiation/Accept.php +++ b/src/Negotiation/Accept.php @@ -4,7 +4,7 @@ use Negotiation\Exception\InvalidMediaType; -final class Accept extends BaseAccept implements AcceptHeader +final class Accept extends BaseAccept { private $basePart; diff --git a/src/Negotiation/AcceptCharset.php b/src/Negotiation/AcceptCharset.php index 7ce3490..1bd4e92 100644 --- a/src/Negotiation/AcceptCharset.php +++ b/src/Negotiation/AcceptCharset.php @@ -2,6 +2,6 @@ namespace Negotiation; -final class AcceptCharset extends BaseAccept implements AcceptHeader +final class AcceptCharset extends BaseAccept { } diff --git a/src/Negotiation/AcceptEncoding.php b/src/Negotiation/AcceptEncoding.php index 8165a7f..9ba89c7 100644 --- a/src/Negotiation/AcceptEncoding.php +++ b/src/Negotiation/AcceptEncoding.php @@ -2,6 +2,6 @@ namespace Negotiation; -final class AcceptEncoding extends BaseAccept implements AcceptHeader +final class AcceptEncoding extends BaseAccept { } diff --git a/src/Negotiation/AcceptLanguage.php b/src/Negotiation/AcceptLanguage.php index ad1c032..d18df1b 100644 --- a/src/Negotiation/AcceptLanguage.php +++ b/src/Negotiation/AcceptLanguage.php @@ -4,7 +4,7 @@ use Negotiation\Exception\InvalidLanguage; -final class AcceptLanguage extends BaseAccept implements AcceptHeader +final class AcceptLanguage extends BaseAccept { private $language; private $script; diff --git a/src/Negotiation/BaseAccept.php b/src/Negotiation/BaseAccept.php index a4663d2..465c27c 100644 --- a/src/Negotiation/BaseAccept.php +++ b/src/Negotiation/BaseAccept.php @@ -2,7 +2,7 @@ namespace Negotiation; -abstract class BaseAccept +abstract class BaseAccept implements AcceptHeader { /** * @var float From c641a913456f92be579e5e3fc667e490b578213f Mon Sep 17 00:00:00 2001 From: Greg Bowler Date: Tue, 15 Feb 2022 19:36:18 +0000 Subject: [PATCH 04/13] Correct return type --- src/Negotiation/AbstractNegotiator.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Negotiation/AbstractNegotiator.php b/src/Negotiation/AbstractNegotiator.php index e4917dc..5248e7a 100644 --- a/src/Negotiation/AbstractNegotiator.php +++ b/src/Negotiation/AbstractNegotiator.php @@ -130,7 +130,7 @@ protected function match(AcceptHeader $header, AcceptHeader $priority, $index) /** * @param string $header A string that contains an `Accept*` header. * - * @return AcceptHeader[] + * @return string[] */ private function parseHeader($header) { From 56a14078c4b13b58a70bc6470fbb88900f8e7703 Mon Sep 17 00:00:00 2001 From: Greg Bowler Date: Tue, 15 Feb 2022 19:37:55 +0000 Subject: [PATCH 05/13] Correct nonexistent Priority class to AcceptHeader --- src/Negotiation/AbstractNegotiator.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Negotiation/AbstractNegotiator.php b/src/Negotiation/AbstractNegotiator.php index 5248e7a..3749c27 100644 --- a/src/Negotiation/AbstractNegotiator.php +++ b/src/Negotiation/AbstractNegotiator.php @@ -145,7 +145,7 @@ private function parseHeader($header) /** * @param AcceptHeader[] $headerParts - * @param Priority[] $priorities Configured priorities + * @param AcceptHeader[] $priorities Configured priorities * * @return AcceptMatch[] Headers matched */ From 90bc8cb30016a9eeb464e3b2e6face1a444e8b3f Mon Sep 17 00:00:00 2001 From: Greg Bowler Date: Tue, 15 Feb 2022 19:39:27 +0000 Subject: [PATCH 06/13] Improve typehint - allow looser type to be returned --- src/Negotiation/AbstractNegotiator.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Negotiation/AbstractNegotiator.php b/src/Negotiation/AbstractNegotiator.php index 3749c27..2a81409 100644 --- a/src/Negotiation/AbstractNegotiator.php +++ b/src/Negotiation/AbstractNegotiator.php @@ -100,7 +100,7 @@ public function getOrderedElements($header) /** * @param string $header accept header part or server priority * - * @return AcceptHeader Parsed header object + * @return BaseAccept Parsed header object */ abstract protected function acceptFactory($header); From ba44a7a0547a48139fdede12928e868cdec75554 Mon Sep 17 00:00:00 2001 From: Greg Bowler Date: Tue, 15 Feb 2022 19:40:35 +0000 Subject: [PATCH 07/13] Improve typehint - more accurate types as parameters --- src/Negotiation/AbstractNegotiator.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Negotiation/AbstractNegotiator.php b/src/Negotiation/AbstractNegotiator.php index 2a81409..cdbe748 100644 --- a/src/Negotiation/AbstractNegotiator.php +++ b/src/Negotiation/AbstractNegotiator.php @@ -105,13 +105,13 @@ public function getOrderedElements($header) abstract protected function acceptFactory($header); /** - * @param AcceptHeader $header - * @param AcceptHeader $priority + * @param BaseAccept $header + * @param BaseAccept $priority * @param integer $index * * @return AcceptMatch|null Headers matched */ - protected function match(AcceptHeader $header, AcceptHeader $priority, $index) + protected function match(BaseAccept $header, BaseAccept $priority, $index) { $ac = $header->getType(); $pc = $priority->getType(); From d13b8ca4c38d88cd2fb966ccc8cfc4598eaf7571 Mon Sep 17 00:00:00 2001 From: Greg Bowler Date: Tue, 15 Feb 2022 19:41:03 +0000 Subject: [PATCH 08/13] Improve typehint - more accurate generics as parameters --- src/Negotiation/AbstractNegotiator.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Negotiation/AbstractNegotiator.php b/src/Negotiation/AbstractNegotiator.php index cdbe748..3355e92 100644 --- a/src/Negotiation/AbstractNegotiator.php +++ b/src/Negotiation/AbstractNegotiator.php @@ -144,8 +144,8 @@ private function parseHeader($header) } /** - * @param AcceptHeader[] $headerParts - * @param AcceptHeader[] $priorities Configured priorities + * @param BaseAccept[] $headerParts + * @param BaseAccept[] $priorities Configured priorities * * @return AcceptMatch[] Headers matched */ From fc3ca90333da2f78a54233d9bebbcfeaef32eda7 Mon Sep 17 00:00:00 2001 From: Greg Bowler Date: Tue, 15 Feb 2022 19:45:21 +0000 Subject: [PATCH 09/13] Expose script property - was only ever written --- src/Negotiation/AcceptLanguage.php | 8 ++++++++ tests/Negotiation/Tests/AcceptLanguageTest.php | 6 ++++++ 2 files changed, 14 insertions(+) diff --git a/src/Negotiation/AcceptLanguage.php b/src/Negotiation/AcceptLanguage.php index d18df1b..69d765d 100644 --- a/src/Negotiation/AcceptLanguage.php +++ b/src/Negotiation/AcceptLanguage.php @@ -46,4 +46,12 @@ public function getBasePart() { return $this->language; } + + /** + * @return null|string + */ + public function getScript() + { + return $this->script; + } } diff --git a/tests/Negotiation/Tests/AcceptLanguageTest.php b/tests/Negotiation/Tests/AcceptLanguageTest.php index bc8ab24..ccd674e 100644 --- a/tests/Negotiation/Tests/AcceptLanguageTest.php +++ b/tests/Negotiation/Tests/AcceptLanguageTest.php @@ -42,6 +42,12 @@ public function testGetValue($header, $expected) } + public function testGetScript() + { + $accept = new AcceptLanguage("zh-Hans-CN;q=0.3"); + $this->assertSame("hans", $accept->getScript()); + } + public static function dataProviderForGetValue() { return array( From df2623ff970c666af5fc5cd8dfe8185366333058 Mon Sep 17 00:00:00 2001 From: Greg Bowler Date: Tue, 15 Feb 2022 19:46:24 +0000 Subject: [PATCH 10/13] Properly typehint associative array --- src/Negotiation/BaseAccept.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Negotiation/BaseAccept.php b/src/Negotiation/BaseAccept.php index 465c27c..8435000 100644 --- a/src/Negotiation/BaseAccept.php +++ b/src/Negotiation/BaseAccept.php @@ -140,14 +140,13 @@ private function parseParameters($acceptPart) } /** - * @param string $parameters + * @param array $parameters * * @return string */ private function buildParametersString($parameters) { $parts = []; - ksort($parameters); foreach ($parameters as $key => $val) { $parts[] = sprintf('%s=%s', $key, $val); From a00546f78ebb349d2b8e2987c809279071e9f58a Mon Sep 17 00:00:00 2001 From: Greg Bowler Date: Tue, 15 Feb 2022 19:47:57 +0000 Subject: [PATCH 11/13] Typehint nullable string --- src/Negotiation/AcceptLanguage.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Negotiation/AcceptLanguage.php b/src/Negotiation/AcceptLanguage.php index 69d765d..fed5991 100644 --- a/src/Negotiation/AcceptLanguage.php +++ b/src/Negotiation/AcceptLanguage.php @@ -32,7 +32,7 @@ public function __construct($value) } /** - * @return string + * @return null|string */ public function getSubPart() { From b453ccd3d864b753d941961021dff0a4844f99f1 Mon Sep 17 00:00:00 2001 From: Greg Bowler Date: Tue, 15 Feb 2022 19:48:13 +0000 Subject: [PATCH 12/13] Match typehints of parent method --- src/Negotiation/LanguageNegotiator.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Negotiation/LanguageNegotiator.php b/src/Negotiation/LanguageNegotiator.php index ba33616..9e79c01 100644 --- a/src/Negotiation/LanguageNegotiator.php +++ b/src/Negotiation/LanguageNegotiator.php @@ -15,7 +15,7 @@ protected function acceptFactory($accept) /** * {@inheritdoc} */ - protected function match(AcceptHeader $acceptLanguage, AcceptHeader $priority, $index) + protected function match(BaseAccept $acceptLanguage, BaseAccept $priority, $index) { if (!$acceptLanguage instanceof AcceptLanguage || !$priority instanceof AcceptLanguage) { return null; From 91a9d73772500cca95dfd946a9955eb45ba97f02 Mon Sep 17 00:00:00 2001 From: Greg Bowler Date: Tue, 15 Feb 2022 21:56:45 +0000 Subject: [PATCH 13/13] Run PHPStan as Github Action (#2) * Depend on PHPUnit for development In order to run the unit tests, PHPUnit is a hard dev dependency, so I've included it in this commit, and now I can run the unit tests as part of this PR. * Depend on PHPStan for development This is for #89 - to ensure correct type hints are provided to developers who use IDEs. * Fix object model of AcceptHeader interface Fixes #89 - IDEs and PHPStan are happy with this implementation * Correct return type * Correct nonexistent Priority class to AcceptHeader * Improve typehint - allow looser type to be returned * Improve typehint - more accurate types as parameters * Improve typehint - more accurate generics as parameters * Expose script property - was only ever written * Properly typehint associative array * Typehint nullable string * Match typehints of parent method * Add PHPStan to CI * Configure PHPUnit versions for different PHP runtimes * Use real phpunit --- .github/workflows/ci.yaml | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index d3fee8c..867b906 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -31,4 +31,30 @@ jobs: uses: "ramsey/composer-install@v1" - name: "Run PHPUnit" - run: "vendor/bin/simple-phpunit --coverage-text" + run: "vendor/bin/phpunit --coverage-text" + + phpstan: + runs-on: "ubuntu-20.04" + + strategy: + fail-fast: false + matrix: + php-version: + - "7.4" + - "8.0" + - "8.1" + + steps: + - uses: actions/checkout@v2 + + - name: "Install PHP ${{ matrix.php-version }}" + uses: "shivammathur/setup-php@v2" + with: + php-version: "${{ matrix.php-version }}" + coverage: "pcov" + + - name: "Install dependencies with Composer" + uses: "ramsey/composer-install@v1" + + - name: "Run PHPStan" + run: "vendor/bin/phpstan analyse src --level 5"