diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 2e8e92e9..956f8e70 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -14,7 +14,7 @@ jobs: - name: Setup PHP uses: shivammathur/setup-php@v2 with: - php-version: 7.4 + php-version: 8.2 ini-values: assert.exception=1, phar.readonly=0, zend.assertions=1 extensions: curl, json, phar, mbstring, gzip, bzip2, openssl tools: pecl, phing diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 36f91c15..a0bc812f 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -18,10 +18,10 @@ jobs: key: cache-v1 # can be any string, change to clear the extension cache. strategy: matrix: - php-versions: ['7.4', '8.0', '8.1'] + php-versions: ['8.0', '8.1', '8.2'] experimental: [ false ] include: - - php-versions: 8.2 + - php-versions: 8.3 experimental: true steps: - name: Checkout @@ -97,7 +97,7 @@ jobs: key: cache-v1 # can be any string, change to clear the extension cache. strategy: matrix: - php-versions: ['8.1'] + php-versions: ['8.2'] steps: - name: Checkout uses: actions/checkout@v2 diff --git a/composer.json b/composer.json index 52fb6704..7afc3bd7 100644 --- a/composer.json +++ b/composer.json @@ -18,11 +18,11 @@ } ], "require": { - "php": "^7.4||^8.0", + "php": "^8.1", "ql/uri-template": "~1.0", "vanilla/garden-cli": "~3.0", "michelf/php-markdown": "~2.0", - "lukasoppermann/http-status": "~3.1", + "lukasoppermann/http-status": "~3.2", "ext-json": "*", "ext-curl": "*", "twig/twig": "^3.0", @@ -35,7 +35,9 @@ "theseer/autoload": "~1.0", "phing/phing": "~2.0", "phpstan/phpstan": "^1.2.0", - "phpstan/phpstan-phpunit": "^1.0.0" + "phpstan/phpstan-phpunit": "^1.0.0", + "phpstan/phpstan-deprecation-rules": "^1.1", + "phpstan/phpstan-strict-rules": "^1.4" }, "autoload": { "psr-4": { "PHPDraft\\": "src/PHPDraft" } diff --git a/composer.lock b/composer.lock index c16896b8..cfe6a00e 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": "f4a0e264b7c00f9f71212ce356a9960b", + "content-hash": "dafb3f80edd1257d5d264b021f080c7a", "packages": [ { "name": "lukasoppermann/http-status", @@ -723,30 +723,30 @@ "packages-dev": [ { "name": "doctrine/instantiator", - "version": "1.4.1", + "version": "1.5.0", "source": { "type": "git", "url": "https://github.com/doctrine/instantiator.git", - "reference": "10dcfce151b967d20fde1b34ae6640712c3891bc" + "reference": "0a0fa9780f5d4e507415a065172d26a98d02047b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/instantiator/zipball/10dcfce151b967d20fde1b34ae6640712c3891bc", - "reference": "10dcfce151b967d20fde1b34ae6640712c3891bc", + "url": "https://api.github.com/repos/doctrine/instantiator/zipball/0a0fa9780f5d4e507415a065172d26a98d02047b", + "reference": "0a0fa9780f5d4e507415a065172d26a98d02047b", "shasum": "" }, "require": { "php": "^7.1 || ^8.0" }, "require-dev": { - "doctrine/coding-standard": "^9", + "doctrine/coding-standard": "^9 || ^11", "ext-pdo": "*", "ext-phar": "*", "phpbench/phpbench": "^0.16 || ^1", "phpstan/phpstan": "^1.4", "phpstan/phpstan-phpunit": "^1", "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5", - "vimeo/psalm": "^4.22" + "vimeo/psalm": "^4.30 || ^5.4" }, "type": "library", "autoload": { @@ -773,7 +773,7 @@ ], "support": { "issues": "https://github.com/doctrine/instantiator/issues", - "source": "https://github.com/doctrine/instantiator/tree/1.4.1" + "source": "https://github.com/doctrine/instantiator/tree/1.5.0" }, "funding": [ { @@ -789,30 +789,30 @@ "type": "tidelift" } ], - "time": "2022-03-03T08:28:38+00:00" + "time": "2022-12-30T00:15:36+00:00" }, { "name": "lunr/halo", "version": "dev-master", "source": { "type": "git", - "url": "https://github.com/M2mobi/lunr.halo.git", - "reference": "394d28f496f3b223c7dcbc3e4c83ed897b30dd04" + "url": "https://github.com/lunr-php/lunr.halo.git", + "reference": "324e4c80ac8f53e8d6474fe59984f59c77e94b5b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/M2mobi/lunr.halo/zipball/394d28f496f3b223c7dcbc3e4c83ed897b30dd04", - "reference": "394d28f496f3b223c7dcbc3e4c83ed897b30dd04", + "url": "https://api.github.com/repos/lunr-php/lunr.halo/zipball/324e4c80ac8f53e8d6474fe59984f59c77e94b5b", + "reference": "324e4c80ac8f53e8d6474fe59984f59c77e94b5b", "shasum": "" }, "require": { "ext-uopz": ">=6.1", - "php": "~7.4||~8.0", + "php": ">=7.4", "psr/log": "~1.1" }, "require-dev": { - "ext-xdebug": ">=2.6", - "phpunit/phpunit": "~9.0" + "ext-xdebug": ">=3.0", + "phpunit/phpunit": ">=8.5" }, "default-branch": true, "type": "library", @@ -833,10 +833,10 @@ "unit tests" ], "support": { - "issues": "https://github.com/M2mobi/lunr.halo/issues", - "source": "https://github.com/M2mobi/lunr.halo/tree/master" + "issues": "https://github.com/lunr-php/lunr.halo/issues", + "source": "https://github.com/lunr-php/lunr.halo/tree/0.7.0" }, - "time": "2021-11-11T15:43:07+00:00" + "time": "2022-12-25T12:49:25+00:00" }, { "name": "myclabs/deep-copy", @@ -1235,6 +1235,54 @@ ], "time": "2023-01-08T21:26:18+00:00" }, + { + "name": "phpstan/phpstan-deprecation-rules", + "version": "1.1.1", + "source": { + "type": "git", + "url": "https://github.com/phpstan/phpstan-deprecation-rules.git", + "reference": "2c6792eda026d9c474c14aa018aed312686714db" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpstan/phpstan-deprecation-rules/zipball/2c6792eda026d9c474c14aa018aed312686714db", + "reference": "2c6792eda026d9c474c14aa018aed312686714db", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0", + "phpstan/phpstan": "^1.9.3" + }, + "require-dev": { + "php-parallel-lint/php-parallel-lint": "^1.2", + "phpstan/phpstan-php-parser": "^1.1", + "phpstan/phpstan-phpunit": "^1.0", + "phpunit/phpunit": "^9.5" + }, + "type": "phpstan-extension", + "extra": { + "phpstan": { + "includes": [ + "rules.neon" + ] + } + }, + "autoload": { + "psr-4": { + "PHPStan\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "PHPStan rules for detecting usage of deprecated classes, methods, properties, constants and traits.", + "support": { + "issues": "https://github.com/phpstan/phpstan-deprecation-rules/issues", + "source": "https://github.com/phpstan/phpstan-deprecation-rules/tree/1.1.1" + }, + "time": "2022-12-13T14:26:20+00:00" + }, { "name": "phpstan/phpstan-phpunit", "version": "1.3.3", @@ -1287,18 +1335,66 @@ }, "time": "2022-12-21T15:25:00+00:00" }, + { + "name": "phpstan/phpstan-strict-rules", + "version": "1.4.4", + "source": { + "type": "git", + "url": "https://github.com/phpstan/phpstan-strict-rules.git", + "reference": "23e5f377ee6395a1a04842d3d6ed4bd25e7b44a6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpstan/phpstan-strict-rules/zipball/23e5f377ee6395a1a04842d3d6ed4bd25e7b44a6", + "reference": "23e5f377ee6395a1a04842d3d6ed4bd25e7b44a6", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0", + "phpstan/phpstan": "^1.8.6" + }, + "require-dev": { + "nikic/php-parser": "^4.13.0", + "php-parallel-lint/php-parallel-lint": "^1.2", + "phpstan/phpstan-phpunit": "^1.0", + "phpunit/phpunit": "^9.5" + }, + "type": "phpstan-extension", + "extra": { + "phpstan": { + "includes": [ + "rules.neon" + ] + } + }, + "autoload": { + "psr-4": { + "PHPStan\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Extra strict and opinionated rules for PHPStan", + "support": { + "issues": "https://github.com/phpstan/phpstan-strict-rules/issues", + "source": "https://github.com/phpstan/phpstan-strict-rules/tree/1.4.4" + }, + "time": "2022-09-21T11:38:17+00:00" + }, { "name": "phpunit/php-code-coverage", - "version": "9.2.19", + "version": "9.2.23", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "c77b56b63e3d2031bd8997fcec43c1925ae46559" + "reference": "9f1f0f9a2fbb680b26d1cf9b61b6eac43a6e4e9c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/c77b56b63e3d2031bd8997fcec43c1925ae46559", - "reference": "c77b56b63e3d2031bd8997fcec43c1925ae46559", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/9f1f0f9a2fbb680b26d1cf9b61b6eac43a6e4e9c", + "reference": "9f1f0f9a2fbb680b26d1cf9b61b6eac43a6e4e9c", "shasum": "" }, "require": { @@ -1354,7 +1450,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", - "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.19" + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.23" }, "funding": [ { @@ -1362,7 +1458,7 @@ "type": "github" } ], - "time": "2022-11-18T07:47:47+00:00" + "time": "2022-12-28T12:41:10+00:00" }, { "name": "phpunit/php-file-iterator", @@ -2823,21 +2919,23 @@ }, { "name": "zetacomponents/base", - "version": "1.9.3", + "version": "1.9.4", "source": { "type": "git", "url": "https://github.com/zetacomponents/Base.git", - "reference": "2f432f4117a5aa2164d4fb1784f84db91dbdd3b8" + "reference": "b6ae5f6177f6e51c5fc3514800e1c3fb076ec4be" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/zetacomponents/Base/zipball/2f432f4117a5aa2164d4fb1784f84db91dbdd3b8", - "reference": "2f432f4117a5aa2164d4fb1784f84db91dbdd3b8", + "url": "https://api.github.com/repos/zetacomponents/Base/zipball/b6ae5f6177f6e51c5fc3514800e1c3fb076ec4be", + "reference": "b6ae5f6177f6e51c5fc3514800e1c3fb076ec4be", "shasum": "" }, "require-dev": { - "phpunit/phpunit": "~8.0", - "zetacomponents/unit-test": "*" + "phpunit/php-invoker": "^2.0|^3.1", + "phpunit/phpunit": "~9.0", + "zetacomponents/coding-standard": "dev-main", + "zetacomponents/unit-test": "~1.2.3" }, "type": "library", "autoload": { @@ -2885,9 +2983,9 @@ "homepage": "https://github.com/zetacomponents", "support": { "issues": "https://github.com/zetacomponents/Base/issues", - "source": "https://github.com/zetacomponents/Base/tree/1.9.3" + "source": "https://github.com/zetacomponents/Base/tree/1.9.4" }, - "time": "2021-07-25T15:46:08+00:00" + "time": "2022-11-30T16:16:25+00:00" }, { "name": "zetacomponents/console-tools", @@ -2969,7 +3067,7 @@ "prefer-stable": false, "prefer-lowest": false, "platform": { - "php": "^7.4||^8.0", + "php": "^8.1", "ext-json": "*", "ext-curl": "*" }, diff --git a/phpdraft b/phpdraft index 8a3cda38..5567d03c 100755 --- a/phpdraft +++ b/phpdraft @@ -92,7 +92,7 @@ try $html = ParserFactory::getJson()->init($data); $name = 'PHPD_SORT_' . strtoupper($args->getOpt('sort', '')); - $html->sorting = Sorting::${$name} ?? -1; + $html->sorting = Sorting::${$name} ?? Sorting::PHPD_SORT_NONE; $color1 = getenv('COLOR_PRIMARY') === FALSE ? NULL : getenv('COLOR_PRIMARY'); $color2 = getenv('COLOR_SECONDARY') === FALSE ? NULL : getenv('COLOR_SECONDARY'); diff --git a/phpstan.neon.dist b/phpstan.neon.dist index 57c7ab4e..25aef39a 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -1,5 +1,5 @@ parameters: - phpVersion: 70400 + phpVersion: 80100 bootstrapFiles: - tests/test.bootstrap.inc.php excludePaths: @@ -7,7 +7,4 @@ parameters: - src/PHPDraft/Parse/Tests/BaseParserTest.php - src/PHPDraft/Parse/Tests/DrafterTest.php - src/PHPDraft/Parse/Tests/DrafterAPITest.php - - src/PHPDraft/**/Tests/* - ignoreErrors: - - '#Access to an undefined property object::\$[a-zA-Z0-9\\_]+#' - - '#Access to an undefined property PHPDraft\\Model\\HierarchyElement::\$[a-zA-Z0-9_]+#' \ No newline at end of file + - src/PHPDraft/**/Tests/* \ No newline at end of file diff --git a/src/PHPDraft/In/ApibFileParser.php b/src/PHPDraft/In/ApibFileParser.php index 86684336..95ba7b08 100644 --- a/src/PHPDraft/In/ApibFileParser.php +++ b/src/PHPDraft/In/ApibFileParser.php @@ -11,11 +11,12 @@ namespace PHPDraft\In; use PHPDraft\Parse\ExecutionException; +use Stringable; /** * Class ApibFileParser. */ -class ApibFileParser +class ApibFileParser implements Stringable { /** * Complete API Blueprint. @@ -31,21 +32,13 @@ class ApibFileParser */ protected string $location; - /** - * Filename to parse. - * - * @var string - */ - private string $filename; - /** * FileParser constructor. * * @param string $filename File to parse */ - public function __construct(string $filename = 'index.apib') + public function __construct(private string $filename = 'index.apib') { - $this->filename = $filename; $this->location = pathinfo($this->filename, PATHINFO_DIRNAME) . '/'; set_include_path(get_include_path() . ':' . $this->location); @@ -56,7 +49,7 @@ public function __construct(string $filename = 'index.apib') * * @throws ExecutionException * - * @return $this self reference. + * @return self self reference. */ public function parse(): self { diff --git a/src/PHPDraft/In/Tests/ApibFileParserTest.php b/src/PHPDraft/In/Tests/ApibFileParserTest.php index 37f92cb6..90e23e47 100644 --- a/src/PHPDraft/In/Tests/ApibFileParserTest.php +++ b/src/PHPDraft/In/Tests/ApibFileParserTest.php @@ -63,9 +63,7 @@ public function testFilenameSetupWrong(): void $this->expectExceptionMessageMatches('/API File not found: .*\/drafter\/non_existing_including_apib/'); $this->expectExceptionCode(1); - $property = $this->reflection->getProperty('filename'); - $property->setAccessible(true); - $property->setValue($this->class, TEST_STATICS . '/drafter/non_existing_including_apib'); + $this->set_reflection_property_value('filename', TEST_STATICS . '/drafter/non_existing_including_apib'); $this->class->parse(); } diff --git a/src/PHPDraft/Model/Category.php b/src/PHPDraft/Model/Category.php index 7355798b..78059ba6 100644 --- a/src/PHPDraft/Model/Category.php +++ b/src/PHPDraft/Model/Category.php @@ -12,6 +12,7 @@ namespace PHPDraft\Model; +use PHPDraft\Model\Elements\BasicStructureElement; use PHPDraft\Model\Elements\ObjectStructureElement; /** @@ -22,7 +23,7 @@ class Category extends HierarchyElement /** * API Structure element. * - * @var ObjectStructureElement[] + * @var BasicStructureElement[] */ public array $structures = []; @@ -49,7 +50,7 @@ public function parse(object $object): self $struct->deps = $deps; $struct->parse($item->content, $deps); - if (isset($item->content->content) && is_array($item->content->content) && isset($item->content->content[0]->meta->id)) { + if (isset($item->content) && isset($item->content->content) && is_array($item->content->content) && isset($item->content->content[0]->meta->id)) { $this->structures[$item->content->content[0]->meta->id] = $struct; } elseif (isset($item->content->meta->id->content)) { $this->structures[$item->content->meta->id->content] = $struct; diff --git a/src/PHPDraft/Model/Elements/ArrayStructureElement.php b/src/PHPDraft/Model/Elements/ArrayStructureElement.php index b50eb37b..69bac8a7 100644 --- a/src/PHPDraft/Model/Elements/ArrayStructureElement.php +++ b/src/PHPDraft/Model/Elements/ArrayStructureElement.php @@ -27,7 +27,7 @@ class ArrayStructureElement extends BasicStructureElement * * @return self Self reference */ - public function parse(?object $object, array &$dependencies): StructureElement + public function parse(?object $object, array &$dependencies): self { $this->element = $object->element ?? 'array'; diff --git a/src/PHPDraft/Model/Elements/BasicStructureElement.php b/src/PHPDraft/Model/Elements/BasicStructureElement.php index fd02f2e6..2e254ffb 100644 --- a/src/PHPDraft/Model/Elements/BasicStructureElement.php +++ b/src/PHPDraft/Model/Elements/BasicStructureElement.php @@ -8,7 +8,9 @@ namespace PHPDraft\Model\Elements; -abstract class BasicStructureElement implements StructureElement +use Stringable; + +abstract class BasicStructureElement implements StructureElement, Stringable { /** * Object key. @@ -39,7 +41,7 @@ abstract class BasicStructureElement implements StructureElement * * @var mixed */ - public $value = null; + public mixed $value = null; /** * Object status (required|optional). * @@ -71,16 +73,9 @@ abstract class BasicStructureElement implements StructureElement * @param object|null $object An object to parse * @param string[] $dependencies Dependencies of this object * - * @return StructureElement self reference - */ - abstract public function parse(?object $object, array &$dependencies): StructureElement; - - /** - * Print a string representation. - * - * @return string + * @return self self reference */ - abstract public function __toString(): string; + abstract public function parse(?object $object, array &$dependencies): self; /** * Get a new instance of a class. @@ -167,21 +162,21 @@ protected function get_element_as_html(string $element): string * * @return string */ - public function string_value(bool $flat = false) + public function string_value(bool $flat = false): string { if (is_array($this->value)) { $value_key = rand(0, count($this->value)); if (is_subclass_of($this->value[$value_key], StructureElement::class) && $flat === false) { - return $this->value[$value_key]->string_value($flat); + return $this->value[$value_key]->string_value(); } - return $this->value[$value_key]; + return $this->value[$value_key] ?? ''; } if (is_subclass_of($this->value, BasicStructureElement::class) && $flat === true) { return is_array($this->value->value) ? array_keys($this->value->value)[0] : $this->value->value; } - return $this->value; + return $this->value ?? ''; } /** @@ -193,19 +188,10 @@ public function string_value(bool $flat = false) */ public function get_class(string $element): BasicStructureElement { - switch ($element) { - default: - case 'object': - $struct = $this->new_instance(); - break; - case 'array': - $struct = new ArrayStructureElement(); - break; - case 'enum': - $struct = new EnumStructureElement(); - break; - } - - return $struct; + return match ($element) { + 'array' => new ArrayStructureElement(), + 'enum' => new EnumStructureElement(), + default => $this->new_instance(), + }; } } diff --git a/src/PHPDraft/Model/Elements/ElementStructureElement.php b/src/PHPDraft/Model/Elements/ElementStructureElement.php index 7dce2e26..b6a579c0 100644 --- a/src/PHPDraft/Model/Elements/ElementStructureElement.php +++ b/src/PHPDraft/Model/Elements/ElementStructureElement.php @@ -2,7 +2,9 @@ namespace PHPDraft\Model\Elements; -class ElementStructureElement implements StructureElement +use Stringable; + +class ElementStructureElement implements StructureElement, Stringable { /** * Object JSON type. @@ -23,7 +25,7 @@ class ElementStructureElement implements StructureElement * * @var mixed */ - public $value = null; + public mixed $value = null; /** * Parse a JSON object to a structure. @@ -62,7 +64,7 @@ public function __toString(): string * * @return string */ - public function string_value(bool $flat = false) + public function string_value(bool $flat = false): string { if ($flat === true) { return $this->value; diff --git a/src/PHPDraft/Model/Elements/EnumStructureElement.php b/src/PHPDraft/Model/Elements/EnumStructureElement.php index f0621c28..6fc083dc 100644 --- a/src/PHPDraft/Model/Elements/EnumStructureElement.php +++ b/src/PHPDraft/Model/Elements/EnumStructureElement.php @@ -22,9 +22,9 @@ class EnumStructureElement extends BasicStructureElement * @param object|null $object APIB Item to parse * @param string[] $dependencies List of dependencies build * - * @return $this + * @return self self reference */ - public function parse(?object $object, array &$dependencies): StructureElement + public function parse(?object $object, array &$dependencies): self { $this->element = $object->element; diff --git a/src/PHPDraft/Model/Elements/ObjectStructureElement.php b/src/PHPDraft/Model/Elements/ObjectStructureElement.php index cbf062b8..28c700d1 100644 --- a/src/PHPDraft/Model/Elements/ObjectStructureElement.php +++ b/src/PHPDraft/Model/Elements/ObjectStructureElement.php @@ -19,21 +19,6 @@ */ class ObjectStructureElement extends BasicStructureElement { - /** - * Object representation before parsing - * @var object|null - * @phpstan-ignore-next-line - */ - private ?object $object; - - /** - * Unset object function. - * @internal Only for tests - */ - public function __clearForTest(): void - { - $this->object = null; - } /** * Parse a JSON object to a data structure. @@ -43,9 +28,8 @@ public function __clearForTest(): void * * @return ObjectStructureElement self reference */ - public function parse(?object $object, array &$dependencies): StructureElement + public function parse(?object $object, array &$dependencies): self { - $this->object = $object; if (is_null($object) || !isset($object->element) || !(isset($object->content) || isset($object->meta) )) { return $this; } diff --git a/src/PHPDraft/Model/Elements/RequestBodyElement.php b/src/PHPDraft/Model/Elements/RequestBodyElement.php index f287aa6a..54c4dc8a 100644 --- a/src/PHPDraft/Model/Elements/RequestBodyElement.php +++ b/src/PHPDraft/Model/Elements/RequestBodyElement.php @@ -30,36 +30,29 @@ public function print_request(?string $type = 'application/x-www-form-urlencoded $return = ''; $list = []; foreach ($this->value as $object) { - if (get_class($object) === self::class) { - $list[] = $object->print_request($type); + if (get_class($object) !== self::class) { + continue; } + $list[] = $object->print_request($type); } - switch ($type) { - case 'application/x-www-form-urlencoded': - $return .= join('&', $list); - break; - default: - $return .= join(PHP_EOL, $list); - break; - } + $return .= match ($type) + { + 'application/x-www-form-urlencoded' => join('&', $list), + default => join(PHP_EOL, $list), + }; $return .= ''; return $return; } - $value = (empty($this->value)) ? '?' : $this->value; - - switch ($type) { - case 'application/x-www-form-urlencoded': - return "{$this->key->value}=$value"; - default: - $object = []; - $object[$this->key->value] = $value; + $value = $this->value ?? '?'; - return json_encode($object); - } + return match ($type) { + 'application/x-www-form-urlencoded' => "{$this->key->value}=$value", + default => json_encode([$this->key->value => $value]), + }; } /** diff --git a/src/PHPDraft/Model/Elements/StructureElement.php b/src/PHPDraft/Model/Elements/StructureElement.php index 156b40ce..88e1112c 100644 --- a/src/PHPDraft/Model/Elements/StructureElement.php +++ b/src/PHPDraft/Model/Elements/StructureElement.php @@ -31,13 +31,6 @@ interface StructureElement */ public function parse(?object $object, array &$dependencies): self; - /** - * Print a string representation. - * - * @return string - */ - public function __toString(): string; - /** * Get a string representation of the value. @@ -46,5 +39,5 @@ public function __toString(): string; * * @return string */ - public function string_value(bool $flat = false); + public function string_value(bool $flat = false): string; } diff --git a/src/PHPDraft/Model/HTTPRequest.php b/src/PHPDraft/Model/HTTPRequest.php index da01f485..5d487f2b 100644 --- a/src/PHPDraft/Model/HTTPRequest.php +++ b/src/PHPDraft/Model/HTTPRequest.php @@ -15,8 +15,9 @@ use PHPDraft\Model\Elements\RequestBodyElement; use PHPDraft\Model\Elements\StructureElement; use QL\UriTemplate\Exception; +use Stringable; -class HTTPRequest implements Comparable +class HTTPRequest implements Comparable, Stringable { /** * HTTP Headers. @@ -95,14 +96,14 @@ public function __construct(Transition &$parent) * * @param object $object JSON object * - * @return $this self-reference + * @return self self-reference */ public function parse(object $object): self { $this->method = $object->attributes->method->content ?? $object->attributes->method; $this->title = $object->meta->title->content ?? $object->meta->title ?? null; - if (isset($object->content) && $object->content !== null) { + if (isset($object->content)) { foreach ($object->content as $value) { if ($value->element === 'dataStructure') { $this->parse_structure($value); diff --git a/src/PHPDraft/Model/HTTPResponse.php b/src/PHPDraft/Model/HTTPResponse.php index 669d48f8..f9a070bc 100644 --- a/src/PHPDraft/Model/HTTPResponse.php +++ b/src/PHPDraft/Model/HTTPResponse.php @@ -13,8 +13,9 @@ namespace PHPDraft\Model; use PHPDraft\Model\Elements\ObjectStructureElement; +use Stringable; -class HTTPResponse implements Comparable +class HTTPResponse implements Comparable, Stringable { /** * HTTP Status code. @@ -76,7 +77,7 @@ public function __construct(Transition $parent) * * @param object $object JSON object * - * @return $this self-reference + * @return self self-reference */ public function parse(object $object): self { @@ -131,7 +132,7 @@ protected function parse_content(object $value): void return; } - if ($value->element === 'asset') { + if ($value->element === 'asset' && property_exists($value, 'content')) { if (isset($value->attributes->contentType->content)) { $this->content[$value->attributes->contentType->content] = $value->content; } elseif (isset($value->attributes->contentType)) { diff --git a/src/PHPDraft/Model/HierarchyElement.php b/src/PHPDraft/Model/HierarchyElement.php index 8be8b166..fa32e3eb 100644 --- a/src/PHPDraft/Model/HierarchyElement.php +++ b/src/PHPDraft/Model/HierarchyElement.php @@ -38,28 +38,21 @@ abstract class HierarchyElement */ public array $children = []; - /** - * Parent Element. - * - * @var HierarchyElement|null - */ - protected ?HierarchyElement $parent = null; - /** * Parse a JSON object to an element. * * @param object $object an object to parse * - * @return void + * @return self */ - public function parse(object $object) + public function parse(object $object): self { if (isset($object->meta) && isset($object->meta->title)) { $this->title = $object->meta->title->content ?? $object->meta->title; } if (!isset($object->content) || !is_array($object->content)) { - return; + return $this; } foreach ($object->content as $key => $item) { @@ -72,6 +65,7 @@ public function parse(object $object) if (!empty($object->content)) { $object->content = array_slice($object->content, 0); } + return $this; } /** @@ -82,7 +76,7 @@ public function parse(object $object) public function get_href(): string { $separator = '-'; - $prep = ($this->parent !== null) ? $this->parent->get_href() . $separator : ''; + $prep = isset($this->parent) ? $this->parent->get_href() . $separator : ''; return $prep . str_replace(' ', '-', strtolower($this->title)); } diff --git a/src/PHPDraft/Model/Resource.php b/src/PHPDraft/Model/Resource.php index b5aaade6..f8d8de41 100644 --- a/src/PHPDraft/Model/Resource.php +++ b/src/PHPDraft/Model/Resource.php @@ -35,9 +35,9 @@ class Resource extends HierarchyElement * * @param Category $parent A reference to the parent object */ - public function __construct(Category &$parent) + public function __construct(protected Category $parent) { - $this->parent = $parent; + $this->parent = &$parent; } /** @@ -45,7 +45,7 @@ public function __construct(Category &$parent) * * @param object $object JSON object * - * @return $this self-reference + * @return self self-reference */ public function parse(object $object): self { diff --git a/src/PHPDraft/Model/Transition.php b/src/PHPDraft/Model/Transition.php index 82f78ed9..e1b0c86e 100644 --- a/src/PHPDraft/Model/Transition.php +++ b/src/PHPDraft/Model/Transition.php @@ -15,6 +15,7 @@ use PHPDraft\Model\Elements\BasicStructureElement; use PHPDraft\Model\Elements\ObjectStructureElement; use PHPDraft\Model\Elements\StructureElement; +use QL\UriTemplate\Exception as UrlException; use QL\UriTemplate\UriTemplate; class Transition extends HierarchyElement @@ -73,9 +74,9 @@ class Transition extends HierarchyElement * * @param Resource $parent A reference to the parent object */ - public function __construct(Resource &$parent) + public function __construct(protected Resource $parent) { - $this->parent = $parent; + $this->parent = &$parent; } /** @@ -83,7 +84,7 @@ public function __construct(Resource &$parent) * * @param object $object JSON object * - * @return $this self-reference + * @return self self-reference */ public function parse(object $object): self { @@ -100,7 +101,7 @@ public function parse(object $object): self } } - if (isset($object->attributes->data)) { + if (isset($object->attributes->data) && property_exists($object, 'element')) { $deps = []; $struct = (new ObjectStructureElement())->get_class($object->element); $this->data_variables = $struct->parse($object->attributes->data->content, $deps); @@ -152,14 +153,14 @@ public function parse(object $object): self * @param string $base_url the URL to which the URL variables apply * @param bool $clean Get the URL without HTML * - * @throws \QL\UriTemplate\Exception - * * @return string HTML representation of the transition URL + *@throws UrlException + * */ public function build_url(string $base_url = '', bool $clean = false): string { $url = $this->overlap_urls($this->parent->href ?? '', $this->href); - if ($url === false) { + if ($url === NULL) { $url = $this->parent->href . $this->href; } $tpl = new UriTemplate($url); @@ -197,21 +198,22 @@ public function build_url(string $base_url = '', bool $clean = false): string * @param string $str1 First part * @param string $str2 Second part * - * @return bool|string + * @return null|string * * @see http://stackoverflow.com/questions/2945446/built-in-function-to-combine-overlapping-string-sequences-in-php */ - private function overlap_urls(string $str1, string $str2) + private function overlap_urls(string $str1, string $str2): ?string { - if ($overlap = $this->find_overlap($str1, $str2)) { - $overlap = $overlap[count($overlap) - 1]; - $str1 = substr($str1, 0, -strlen($overlap)); - $str2 = substr($str2, strlen($overlap)); - - return $str1 . $overlap . $str2; + $overlap = $this->find_overlap($str1, $str2); + if ($overlap === NULL) { + return NULL; } - return false; + $overlap = $overlap[count($overlap) - 1]; + $str1 = substr($str1, 0, -strlen($overlap)); + $str2 = substr($str2, strlen($overlap)); + + return $str1 . $overlap . $str2; } /** @@ -220,9 +222,9 @@ private function overlap_urls(string $str1, string $str2) * @param string $str1 First part * @param string $str2 Second part * - * @return array|bool + * @return array|null */ - private function find_overlap(string $str1, string $str2) + private function find_overlap(string $str1, string $str2): ?array { $return = []; $sl1 = strlen($str1); @@ -241,7 +243,7 @@ private function find_overlap(string $str1, string $str2) return $return; } - return false; + return NULL; } /** @@ -261,11 +263,11 @@ public function get_method(int $request = 0): string * * @param string $base_url base URL of the server * @param array $additional additional arguments to pass - * @param int $key number of the request to generate for + * @param int $key number of the request to generate for * * @return string A cURL CLI command * - * @throws \QL\UriTemplate\Exception If URL parts are invalid + * @throws UrlException If URL parts are invalid */ public function get_curl_command(string $base_url, array $additional = [], int $key = 0): string { diff --git a/src/PHPDraft/Out/BaseTemplateRenderer.php b/src/PHPDraft/Out/BaseTemplateRenderer.php index 5524d6b0..deaa957f 100644 --- a/src/PHPDraft/Out/BaseTemplateRenderer.php +++ b/src/PHPDraft/Out/BaseTemplateRenderer.php @@ -13,6 +13,7 @@ namespace PHPDraft\Out; use Lukasoppermann\Httpstatus\Httpstatus; +use PHPDraft\Model\Elements\BasicStructureElement; use PHPDraft\Model\Elements\ObjectStructureElement; abstract class BaseTemplateRenderer @@ -20,9 +21,9 @@ abstract class BaseTemplateRenderer /** * Type of sorting to do on objects. * - * @var int + * @var Sorting */ - public int $sorting; + public Sorting $sorting; /** * CSS Files to load. * @@ -62,7 +63,7 @@ abstract class BaseTemplateRenderer /** * Structures used in all data. * - * @var ObjectStructureElement[] + * @var BasicStructureElement[] */ protected array $base_structures = []; } diff --git a/src/PHPDraft/Out/Sorting.php b/src/PHPDraft/Out/Sorting.php index 7da422f1..b17ea345 100644 --- a/src/PHPDraft/Out/Sorting.php +++ b/src/PHPDraft/Out/Sorting.php @@ -15,44 +15,36 @@ /** * Sorting constants. */ -class Sorting +enum Sorting { /** * Sets sorting to all parts. - * - * @var int */ - public const PHPD_SORT_ALL = 3; + case PHPD_SORT_ALL; /** * Sets sorting to all webservices. - * - * @var int */ - public const PHPD_SORT_WEBSERVICES = 2; + case PHPD_SORT_WEBSERVICES; /** * Sets sorting to all data structures. - * - * @var int */ - public const PHPD_SORT_STRUCTURES = 1; + case PHPD_SORT_STRUCTURES; /** * Sets sorting to no data structures. - * - * @var int */ - public const PHPD_SORT_NONE = -1; + case PHPD_SORT_NONE; /** * Check if structures should be sorted. * - * @param int $sort The sorting level. + * @param Sorting $sort The sorting level. * * @return bool */ - public static function sortStructures(int $sort): bool + public static function sortStructures(Sorting $sort): bool { return $sort === self::PHPD_SORT_ALL || $sort === self::PHPD_SORT_STRUCTURES; } @@ -60,11 +52,11 @@ public static function sortStructures(int $sort): bool /** * Check if services should be sorted. * - * @param int $sort The sorting level. + * @param Sorting $sort The sorting level. * * @return bool */ - public static function sortServices(int $sort): bool + public static function sortServices(Sorting $sort): bool { return $sort === self::PHPD_SORT_ALL || $sort === self::PHPD_SORT_WEBSERVICES; } diff --git a/src/PHPDraft/Out/TemplateRenderer.php b/src/PHPDraft/Out/TemplateRenderer.php index e30ec1ed..18b4d838 100644 --- a/src/PHPDraft/Out/TemplateRenderer.php +++ b/src/PHPDraft/Out/TemplateRenderer.php @@ -20,6 +20,9 @@ use PHPDraft\Model\Elements\ObjectStructureElement; use PHPDraft\Parse\ExecutionException; use Twig\Environment; +use Twig\Error\LoaderError; +use Twig\Error\RuntimeError; +use Twig\Error\SyntaxError; use Twig\Extra\Markdown\DefaultMarkdown; use Twig\Extra\Markdown\MarkdownExtension; use Twig\Extra\Markdown\MarkdownRuntime; @@ -55,9 +58,9 @@ public function __construct(string $template, ?string $image) * * @throws ExecutionException When template is not found * - * @throws \Twig\Error\LoaderError - * @throws \Twig\Error\RuntimeError - * @throws \Twig\Error\SyntaxError + * @throws LoaderError + * @throws RuntimeError + * @throws SyntaxError */ public function get(object $object): string { @@ -185,39 +188,20 @@ public function find_include_file(string $template, string $extension = 'twig', public static function get_method_icon(string $method): string { $class = ['fas', strtoupper($method)]; - switch (strtolower($method)) { - case 'post': - $class[] = 'fa-plus-square'; - break; - case 'put': - $class[] = 'fa-pen-square'; - break; - case 'get': - $class[] = 'fa-arrow-circle-down'; - break; - case 'delete': - $class[] = 'fa-minus-square'; - break; - case 'head': - $class[] = 'fa-info'; - break; - case 'connect': - $class[] = 'fa-ethernet'; - break; - case 'options': - $class[] = 'fa-sliders-h'; - break; - case 'trace': - $class[] = 'fa-route'; - break; - case 'patch': - $class[] = 'fa-band-aid'; - break; - default: - break; - } - - return join(' ', $class); + $class[] = match (strtolower($method)) { + 'post' => 'fa-plus-square', + 'put' => 'fa-pen-square', + 'get' => 'fa-arrow-circle-down', + 'delete' => 'fa-minus-square', + 'head' => 'fa-info', + 'connect' => 'fa-ethernet', + 'options' => 'fa-sliders-h', + 'trace' => 'fa-route', + 'patch' => 'fa-band-aid', + default => NULL, + }; + + return trim(join(' ', $class)); } /** diff --git a/src/PHPDraft/Out/Tests/SortingTest.php b/src/PHPDraft/Out/Tests/SortingTest.php index 66b55b3c..7ca8aa0a 100644 --- a/src/PHPDraft/Out/Tests/SortingTest.php +++ b/src/PHPDraft/Out/Tests/SortingTest.php @@ -28,11 +28,10 @@ class SortingTest extends LunrBaseTest */ public function testSortsServicesIfNeeded(): void { - $this->assertTrue(Sorting::sortServices(3)); - $this->assertTrue(Sorting::sortServices(2)); - $this->assertFalse(Sorting::sortServices(-1)); - $this->assertFalse(Sorting::sortServices(1)); - $this->assertFalse(Sorting::sortServices(0)); + $this->assertTrue(Sorting::sortServices(Sorting::PHPD_SORT_ALL)); + $this->assertTrue(Sorting::sortServices(Sorting::PHPD_SORT_WEBSERVICES)); + $this->assertFalse(Sorting::sortServices(Sorting::PHPD_SORT_NONE)); + $this->assertFalse(Sorting::sortServices(Sorting::PHPD_SORT_STRUCTURES)); } /** @@ -42,10 +41,9 @@ public function testSortsServicesIfNeeded(): void */ public function testSortsStructureIfNeeded(): void { - $this->assertTrue(Sorting::sortStructures(3)); - $this->assertTrue(Sorting::sortStructures(1)); - $this->assertFalse(Sorting::sortStructures(-1)); - $this->assertFalse(Sorting::sortStructures(2)); - $this->assertFalse(Sorting::sortStructures(0)); + $this->assertTrue(Sorting::sortStructures(Sorting::PHPD_SORT_ALL)); + $this->assertTrue(Sorting::sortStructures(Sorting::PHPD_SORT_STRUCTURES)); + $this->assertFalse(Sorting::sortStructures(Sorting::PHPD_SORT_NONE)); + $this->assertFalse(Sorting::sortStructures(Sorting::PHPD_SORT_WEBSERVICES)); } } diff --git a/src/PHPDraft/Out/Tests/TemplateRendererTest.php b/src/PHPDraft/Out/Tests/TemplateRendererTest.php index 2f811e47..3f830b48 100644 --- a/src/PHPDraft/Out/Tests/TemplateRendererTest.php +++ b/src/PHPDraft/Out/Tests/TemplateRendererTest.php @@ -10,6 +10,7 @@ namespace PHPDraft\Out\Tests; use Lunr\Halo\LunrBaseTest; +use PHPDraft\Out\Sorting; use PHPDraft\Out\TemplateRenderer; /** @@ -221,7 +222,7 @@ public function testGetTemplate(): void */ public function testGetTemplateSorting(): void { - $this->set_reflection_property_value('sorting', 3); + $this->set_reflection_property_value('sorting', Sorting::PHPD_SORT_ALL); $json = '{"content": [{"content": "hello"}]}'; $this->assertStringEqualsFile(TEST_STATICS . '/empty_html_template', $this->class->get(json_decode($json))); @@ -233,7 +234,7 @@ public function testGetTemplateSorting(): void */ public function testGetTemplateMetaData(): void { - $this->set_reflection_property_value('sorting', 3); + $this->set_reflection_property_value('sorting', Sorting::PHPD_SORT_ALL); $json = <<<'TAG' {"content": [{"content": [], "attributes": { "metadata": {"content": [ @@ -252,7 +253,7 @@ public function testGetTemplateMetaData(): void */ public function testGetTemplateCategories(): void { - $this->set_reflection_property_value('sorting', 3); + $this->set_reflection_property_value('sorting', Sorting::PHPD_SORT_ALL); $json = <<<'TAG' {"content": [ {"content": [{"element": "copy", "content": "__desc__"}, {"element": "category", "content": []}], diff --git a/src/PHPDraft/Out/Version.php b/src/PHPDraft/Out/Version.php index 23ccedf1..5a431817 100644 --- a/src/PHPDraft/Out/Version.php +++ b/src/PHPDraft/Out/Version.php @@ -45,7 +45,7 @@ public static function release_id(): string */ public function series(): string { - if (strpos(self::release_id(), '-')) { + if (str_contains(self::release_id(), '-')) { $version = explode('-', self::release_id())[0]; } else { $version = self::release_id(); @@ -61,7 +61,7 @@ public function series(): string */ public function getReleaseChannel(): string { - if (strpos(self::release_id(), '-') !== false) { + if (str_contains(self::release_id(), '-')) { return '-nightly'; } diff --git a/src/PHPDraft/Parse/BaseHtmlGenerator.php b/src/PHPDraft/Parse/BaseHtmlGenerator.php index afd23494..5fd4254d 100644 --- a/src/PHPDraft/Parse/BaseHtmlGenerator.php +++ b/src/PHPDraft/Parse/BaseHtmlGenerator.php @@ -13,16 +13,18 @@ namespace PHPDraft\Parse; use PHPDraft\Out\BaseTemplateRenderer; +use PHPDraft\Out\Sorting; use stdClass; +use Stringable; -abstract class BaseHtmlGenerator +abstract class BaseHtmlGenerator implements Stringable { /** * Type of sorting to do. * - * @var int + * @var Sorting */ - public int $sorting; + public Sorting $sorting; /** * JSON representation of an API Blueprint. @@ -65,12 +67,4 @@ public function init(object $json): self * @throws ExecutionException As a runtime exception */ abstract public function build_html(string $template = 'default', ?string $image = null, ?string $css = null, ?string $js = null): void; - - - /** - * Get the HTML representation of the object. - * - * @return string - */ - abstract public function __toString(); } diff --git a/src/PHPDraft/Parse/Drafter.php b/src/PHPDraft/Parse/Drafter.php index b6fe2696..499288ce 100644 --- a/src/PHPDraft/Parse/Drafter.php +++ b/src/PHPDraft/Parse/Drafter.php @@ -28,13 +28,13 @@ class Drafter extends BaseParser * * @param ApibFileParser $apib API Blueprint text * - * @return \PHPDraft\Parse\BaseParser + * @return BaseParser */ public function init(ApibFileParser $apib): BaseParser { parent::init($apib); $loc = self::location(); - if ($loc === false) { + if ($loc === NULL) { throw new \UnexpectedValueException("Could not find drafter location!"); } $this->drafter = $loc; @@ -45,14 +45,18 @@ public function init(ApibFileParser $apib): BaseParser /** * Return drafter location if found. * - * @return false|string + * @return null|string */ - public static function location() + public static function location(): ?string { $returnVal = shell_exec('which drafter 2> /dev/null'); + if ($returnVal === NULL || $returnVal === FALSE) { + return NULL; + } + $returnVal = preg_replace('/^\s+|\n|\r|\s+$/m', '', $returnVal); - return empty($returnVal) ? false : $returnVal; + return empty($returnVal) ? NULL : $returnVal; } /** diff --git a/src/PHPDraft/Parse/DrafterAPI.php b/src/PHPDraft/Parse/DrafterAPI.php index 2871de7a..4717f44f 100644 --- a/src/PHPDraft/Parse/DrafterAPI.php +++ b/src/PHPDraft/Parse/DrafterAPI.php @@ -12,6 +12,7 @@ namespace PHPDraft\Parse; +use CurlHandle; use PHPDraft\In\ApibFileParser; class DrafterAPI extends BaseParser @@ -21,7 +22,7 @@ class DrafterAPI extends BaseParser * * @param ApibFileParser $apib API Blueprint text * - * @return \PHPDraft\Parse\BaseParser + * @return BaseParser */ public function init(ApibFileParser $apib): BaseParser { @@ -41,7 +42,7 @@ protected function parse(): void $response = curl_exec($ch); - if (curl_errno($ch) !== 0) { + if (curl_errno($ch) !== 0 || $response === FALSE) { throw new ResourceException('Drafter webservice failed to parse input', 1); } @@ -53,9 +54,9 @@ protected function parse(): void * * @param string $message API blueprint to parse * - * @return false|resource + * @return CurlHandle */ - public static function curl_init_drafter(string $message) + public static function curl_init_drafter(string $message): CurlHandle { $ch = curl_init(); diff --git a/src/PHPDraft/Parse/HtmlGenerator.php b/src/PHPDraft/Parse/HtmlGenerator.php index bb93b01f..70eb679b 100644 --- a/src/PHPDraft/Parse/HtmlGenerator.php +++ b/src/PHPDraft/Parse/HtmlGenerator.php @@ -12,7 +12,6 @@ namespace PHPDraft\Parse; -use PHPDraft\Out\BaseTemplateRenderer; use PHPDraft\Out\TemplateRenderer; /** @@ -54,7 +53,7 @@ public function build_html(string $template = 'default', ?string $image = null, * * @return string */ - public function __toString() + public function __toString(): string { return $this->html; } diff --git a/src/PHPDraft/Parse/Tests/HtmlGeneratorTest.php b/src/PHPDraft/Parse/Tests/HtmlGeneratorTest.php index 1925ddf7..dd056110 100644 --- a/src/PHPDraft/Parse/Tests/HtmlGeneratorTest.php +++ b/src/PHPDraft/Parse/Tests/HtmlGeneratorTest.php @@ -10,6 +10,7 @@ namespace PHPDraft\Parse\Tests; use Lunr\Halo\LunrBaseTest; +use PHPDraft\Out\Sorting; use PHPDraft\Parse\HtmlGenerator; use ReflectionClass; @@ -37,7 +38,7 @@ public function setUp(): void $this->reflection = new ReflectionClass('PHPDraft\Parse\HtmlGenerator'); $this->class->init($data); - $this->class->sorting = -1; + $this->class->sorting = Sorting::PHPD_SORT_NONE; } /**