From 6e0887352de2d51eb5c8853b4ca74f791b3b7df8 Mon Sep 17 00:00:00 2001 From: Marco Spengler Date: Tue, 28 Dec 2021 15:19:00 +0100 Subject: [PATCH 1/5] Add native return types for classes implementing ArrayAccess, Countable, IteratorAggregate, JsonSerializable --- src/json/JsonReference.php | 1 + src/spec/Paths.php | 11 ++++++----- src/spec/Responses.php | 11 ++++++----- 3 files changed, 13 insertions(+), 10 deletions(-) diff --git a/src/json/JsonReference.php b/src/json/JsonReference.php index fe27ced1..cfac559e 100644 --- a/src/json/JsonReference.php +++ b/src/json/JsonReference.php @@ -126,6 +126,7 @@ public function getReference(): string * @return mixed data which can be serialized by json_encode, * which is a value of any type other than a resource. */ + #[\ReturnTypeWillChange] public function jsonSerialize() { return (object)['$ref' => $this->getReference()]; diff --git a/src/spec/Paths.php b/src/spec/Paths.php index a2da8a10..6bb86255 100644 --- a/src/spec/Paths.php +++ b/src/spec/Paths.php @@ -183,7 +183,7 @@ public function getErrors(): array * @return boolean true on success or false on failure. * The return value will be casted to boolean if non-boolean was returned. */ - public function offsetExists($offset) + public function offsetExists($offset): bool { return $this->hasPath($offset); } @@ -194,6 +194,7 @@ public function offsetExists($offset) * @param mixed $offset The offset to retrieve. * @return PathItem Can return all value types. */ + #[\ReturnTypeWillChange] public function offsetGet($offset) { return $this->getPath($offset); @@ -205,7 +206,7 @@ public function offsetGet($offset) * @param mixed $offset The offset to assign the value to. * @param mixed $value The value to set. */ - public function offsetSet($offset, $value) + public function offsetSet($offset, $value): void { $this->addPath($offset, $value); } @@ -215,7 +216,7 @@ public function offsetSet($offset, $value) * @link http://php.net/manual/en/arrayaccess.offsetunset.php * @param mixed $offset The offset to unset. */ - public function offsetUnset($offset) + public function offsetUnset($offset): void { $this->removePath($offset); } @@ -226,7 +227,7 @@ public function offsetUnset($offset) * @return int The custom count as an integer. * The return value is cast to an integer. */ - public function count() + public function count(): int { return count($this->_paths); } @@ -236,7 +237,7 @@ public function count() * @link http://php.net/manual/en/iteratoraggregate.getiterator.php * @return Traversable An instance of an object implementing Iterator or Traversable */ - public function getIterator() + public function getIterator(): Traversable { return new ArrayIterator($this->_paths); } diff --git a/src/spec/Responses.php b/src/spec/Responses.php index 52476031..3e40f784 100644 --- a/src/spec/Responses.php +++ b/src/spec/Responses.php @@ -173,7 +173,7 @@ public function getErrors(): array * @return boolean true on success or false on failure. * The return value will be casted to boolean if non-boolean was returned. */ - public function offsetExists($offset) + public function offsetExists($offset): bool { return $this->hasResponse($offset); } @@ -184,6 +184,7 @@ public function offsetExists($offset) * @param mixed $offset The offset to retrieve. * @return mixed Can return all value types. */ + #[\ReturnTypeWillChange] public function offsetGet($offset) { return $this->getResponse($offset); @@ -195,7 +196,7 @@ public function offsetGet($offset) * @param mixed $offset The offset to assign the value to. * @param mixed $value The value to set. */ - public function offsetSet($offset, $value) + public function offsetSet($offset, $value): void { $this->addResponse($offset, $value); } @@ -205,7 +206,7 @@ public function offsetSet($offset, $value) * @link http://php.net/manual/en/arrayaccess.offsetunset.php * @param mixed $offset The offset to unset. */ - public function offsetUnset($offset) + public function offsetUnset($offset): void { $this->removeResponse($offset); } @@ -216,7 +217,7 @@ public function offsetUnset($offset) * @return int The custom count as an integer. * The return value is cast to an integer. */ - public function count() + public function count(): int { return count($this->_responses); } @@ -226,7 +227,7 @@ public function count() * @link http://php.net/manual/en/iteratoraggregate.getiterator.php * @return Traversable An instance of an object implementing Iterator or Traversable */ - public function getIterator() + public function getIterator(): Traversable { return new ArrayIterator($this->_responses); } From 46fe6fe2c2d5cf33b05d1a0a121df1aeed675d56 Mon Sep 17 00:00:00 2001 From: Marco Spengler Date: Tue, 28 Dec 2021 16:54:15 +0100 Subject: [PATCH 2/5] Update phpstan for PHP 8.1 type compatibility --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 941ca3e9..b7e14fae 100644 --- a/composer.json +++ b/composer.json @@ -31,7 +31,7 @@ "mermade/openapi3-examples": "1.0.0", "apis-guru/openapi-directory": "1.0.0", "nexmo/api-specification": "1.0.0", - "phpstan/phpstan": "^0.12.0" + "phpstan/phpstan": "^1.2" }, "autoload": { "psr-4": { From 6b03cc0e447e68bd87bb66fd6d463c6378d7591a Mon Sep 17 00:00:00 2001 From: Marco Spengler Date: Tue, 28 Dec 2021 16:55:06 +0100 Subject: [PATCH 3/5] Update Reader type annotations and return type to pass phpstan analyze --- src/Reader.php | 44 ++++++++++++++++++++++++-------------------- 1 file changed, 24 insertions(+), 20 deletions(-) diff --git a/src/Reader.php b/src/Reader.php index 99ee5c36..3378f188 100644 --- a/src/Reader.php +++ b/src/Reader.php @@ -23,45 +23,48 @@ class Reader { /** * Populate OpenAPI spec object from JSON data. - * @phpstan-template T of SpecObjectInterface - * @phpstan-param class-string $baseType - * @phpstan-return T + * @phpstan-template BT1 of SpecObjectInterface + * @phpstan-template BT2 of DocumentContextInterface + * @phpstan-param class-string $baseType + * @phpstan-return BT1|BT2 * @param string $json the JSON string to decode. * @param string $baseType the base Type to instantiate. This must be an instance of [[SpecObjectInterface]]. * The default is [[OpenApi]] which is the base type of a OpenAPI specification file. * You may choose a different type if you instantiate objects from sub sections of a specification. - * @return SpecObjectInterface|OpenApi the OpenApi object instance. + * @return SpecObjectInterface|DocumentContextInterface|OpenApi the OpenApi object instance. * The type of the returned object depends on the `$baseType` argument. * @throws TypeErrorException in case invalid spec data is supplied. */ - public static function readFromJson(string $json, string $baseType = OpenApi::class): SpecObjectInterface + public static function readFromJson(string $json, string $baseType = OpenApi::class) { return new $baseType(json_decode($json, true)); } /** * Populate OpenAPI spec object from YAML data. - * @phpstan-template T of SpecObjectInterface - * @phpstan-param class-string $baseType - * @phpstan-return T + * @phpstan-template BT1 of SpecObjectInterface + * @phpstan-template BT2 of DocumentContextInterface + * @phpstan-param class-string $baseType + * @phpstan-return BT1|BT2 * @param string $yaml the YAML string to decode. * @param string $baseType the base Type to instantiate. This must be an instance of [[SpecObjectInterface]]. * The default is [[OpenApi]] which is the base type of a OpenAPI specification file. * You may choose a different type if you instantiate objects from sub sections of a specification. - * @return SpecObjectInterface|OpenApi the OpenApi object instance. + * @return SpecObjectInterface|DocumentContextInterface|OpenApi the OpenApi object instance. * The type of the returned object depends on the `$baseType` argument. * @throws TypeErrorException in case invalid spec data is supplied. */ - public static function readFromYaml(string $yaml, string $baseType = OpenApi::class): SpecObjectInterface + public static function readFromYaml(string $yaml, string $baseType = OpenApi::class) { return new $baseType(Yaml::parse($yaml)); } /** * Populate OpenAPI spec object from a JSON file. - * @phpstan-template T of SpecObjectInterface - * @phpstan-param class-string $baseType - * @phpstan-return T + * @phpstan-template BT1 of SpecObjectInterface + * @phpstan-template BT2 of DocumentContextInterface + * @phpstan-param class-string $baseType + * @phpstan-return BT1|BT2 * @param string $fileName the file name of the file to be read. * If `$resolveReferences` is true (the default), this should be an absolute URL, a `file://` URI or * an absolute path to allow resolving relative path references. @@ -74,14 +77,14 @@ public static function readFromYaml(string $yaml, string $baseType = OpenApi::cl * Since version 1.5.0 this can be a string indicating the reference resolving mode: * - `inline` only resolve references to external files. * - `all` resolve all references except recursive references. - * @return SpecObjectInterface|OpenApi the OpenApi object instance. + * @return SpecObjectInterface|DocumentContextInterface|OpenApi the OpenApi object instance. * The type of the returned object depends on the `$baseType` argument. * @throws TypeErrorException in case invalid spec data is supplied. * @throws UnresolvableReferenceException in case references could not be resolved. * @throws IOException when the file is not readable. * @throws InvalidJsonPointerSyntaxException in case an invalid JSON pointer string is passed to the spec references. */ - public static function readFromJsonFile(string $fileName, string $baseType = OpenApi::class, $resolveReferences = true): SpecObjectInterface + public static function readFromJsonFile(string $fileName, string $baseType = OpenApi::class, $resolveReferences = true) { $fileContent = file_get_contents($fileName); if ($fileContent === false) { @@ -106,9 +109,10 @@ public static function readFromJsonFile(string $fileName, string $baseType = Ope /** * Populate OpenAPI spec object from YAML file. - * @phpstan-template T of SpecObjectInterface - * @phpstan-param class-string $baseType - * @phpstan-return T + * @phpstan-template BT1 of SpecObjectInterface + * @phpstan-template BT2 of DocumentContextInterface + * @phpstan-param class-string $baseType + * @phpstan-return BT1|BT2 * @param string $fileName the file name of the file to be read. * If `$resolveReferences` is true (the default), this should be an absolute URL, a `file://` URI or * an absolute path to allow resolving relative path references. @@ -121,13 +125,13 @@ public static function readFromJsonFile(string $fileName, string $baseType = Ope * Since version 1.5.0 this can be a string indicating the reference resolving mode: * - `inline` only resolve references to external files. * - `all` resolve all references except recursive references. - * @return SpecObjectInterface|OpenApi the OpenApi object instance. + * @return SpecObjectInterface|DocumentContextInterface|OpenApi the OpenApi object instance. * The type of the returned object depends on the `$baseType` argument. * @throws TypeErrorException in case invalid spec data is supplied. * @throws UnresolvableReferenceException in case references could not be resolved. * @throws IOException when the file is not readable. */ - public static function readFromYamlFile(string $fileName, string $baseType = OpenApi::class, $resolveReferences = true): SpecObjectInterface + public static function readFromYamlFile(string $fileName, string $baseType = OpenApi::class, $resolveReferences = true) { $fileContent = file_get_contents($fileName); if ($fileContent === false) { From ea6f466325af8be6c61d0ab86c3709ab342ae3ba Mon Sep 17 00:00:00 2001 From: Marco Spengler Date: Tue, 28 Dec 2021 16:55:55 +0100 Subject: [PATCH 4/5] Add php 8.1 to GitHub workflow --- .github/workflows/php.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/php.yml b/.github/workflows/php.yml index ccd13c23..d1e2d7d1 100644 --- a/.github/workflows/php.yml +++ b/.github/workflows/php.yml @@ -14,7 +14,7 @@ jobs: matrix: # os: [ubuntu-latest, macos-latest, windows-latest] os: [ubuntu-latest] - php: ['7.1', '7.2', '7.3', '7.4', '8.0'] + php: ['7.1', '7.2', '7.3', '7.4', '8.0', '8.1'] # max 4.4.16, see https://github.com/symfony/symfony/issues/39521 # max 5.1.8, see https://github.com/symfony/symfony/issues/39521 yaml: ['5.2.9', '5.1.11', '4.4.24', '^3.4'] @@ -70,13 +70,13 @@ jobs: if: matrix.os != 'windows-latest' run: | make install - composer require symfony/yaml:"${YAML}" --prefer-dist --no-interaction --ansi + composer require symfony/yaml:"${{ matrix.yaml }}" --prefer-dist --no-interaction --ansi - name: Install dependencies (Windows) if: matrix.os == 'windows-latest' run: | composer install --prefer-dist --no-interaction --no-progress --ansi - composer require symfony/yaml:5.1.8 --prefer-dist --no-interaction --ansi + composer require symfony/yaml:${{ matrix.yaml }} --prefer-dist --no-interaction --ansi - name: Validate test data if: matrix.os == 'ubuntu-latest' From db931b8ed3ed7409e15aa20a21f0abe8f274c21b Mon Sep 17 00:00:00 2001 From: Marco Spengler Date: Tue, 28 Dec 2021 16:56:54 +0100 Subject: [PATCH 5/5] Assure compatible dependencies are installed during workflow execution --- .github/workflows/php.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/php.yml b/.github/workflows/php.yml index d1e2d7d1..867ba703 100644 --- a/.github/workflows/php.yml +++ b/.github/workflows/php.yml @@ -70,13 +70,13 @@ jobs: if: matrix.os != 'windows-latest' run: | make install - composer require symfony/yaml:"${{ matrix.yaml }}" --prefer-dist --no-interaction --ansi + composer require symfony/yaml:"${{ matrix.yaml }}" --with-all-dependencies --prefer-dist --no-interaction --ansi - name: Install dependencies (Windows) if: matrix.os == 'windows-latest' run: | composer install --prefer-dist --no-interaction --no-progress --ansi - composer require symfony/yaml:${{ matrix.yaml }} --prefer-dist --no-interaction --ansi + composer require symfony/yaml:${{ matrix.yaml }} --with-all-dependencies --prefer-dist --no-interaction --ansi - name: Validate test data if: matrix.os == 'ubuntu-latest'