diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md new file mode 100644 index 00000000..c7d0eb78 --- /dev/null +++ b/.github/copilot-instructions.md @@ -0,0 +1,32 @@ +# Everywhere within this repository: +* **Always** use `null|` in favor of `?` for nullable types (e.g. `?string` instead of `string|null`). +* **Always** use variadic parameters instead of `array` for lists of items (e.g. `string ...$items` instead + of `array $items`). +* **Always** use `self` instead of the class name in method signatures (e.g. + `public function setFoo(string $foo): self` instead of `public function setFoo(string $foo): MyClass`). +* **Always** always match casing of class properties when defining parameters and methods (e.g. + `public function setFooBar(string $FooBar)` if the class property is `$FooBar`). +* **Always** define a phpdoc for `array` types that specifies the item type (e.g. + `/** @param string[] $items */` for `array $items`). +* **Never** edit files using sed, awk, or other shell utilities. +* **Always** limit yourself to POSIX shell syntax when executing shell scripts. +* **Always** run phpstan with 512MB of memory when analyzing generated code + (e.g. `phpstan analyze -c phpstan.neon --memory-limit=512M src/`). +* **Always** specify `: void` for methods that do not return a value (e.g. `public function setFoo(string $foo): void`). + * This includes unit test methods (e.g. `public function testFoo(): void`). +* **Always** use `declare(strict_types=1);` at the top of all PHP files. + * Do not do this in PHPUnit test class files, as PHPUnit does not support strict types. +* **Always** ensure that constructor parameters for enum fields also accept the enum value type + (e.g. `public function __construct(string $foo, string|MyEnum $bar)`). + * Write tests for both cases. +* **Never** leave imports unused in generated code. +* **Always** used named parameters wherever possible. +* **Never** bother with docblocks unless they are necessary to specify types that cannot be expressed in code + (e.g. `/** @param string[] $items */` for `array $items`). + +# When generting code for concrete implementations of AbstractType: +* **Always** ensure that class fields have an associated getter and setter method. +* **Always** ensure the constructor has parameters for all class fields, and that the constructor parameters are + assigned to the class fields. +* **Always** write unit tests that use both the constructor and the setter methods to set class fields, + and that use the getter methods and fields directly to verify that the fields were set correctly. \ No newline at end of file diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index 8ed1b16e..44dbb4f6 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -1,5 +1,21 @@ name: "Tests" +permissions: + actions: none + attestations: none + checks: none + contents: read + deployments: none + id-token: none + issues: none + models: none + discussions: none + packages: none + pages: none + pull-requests: none + security-events: none + statuses: none + on: pull_request: branches: @@ -22,7 +38,7 @@ on: env: CONSUL_HTTP_ADDR: "127.0.0.1:8500" - CONSUL_VERSION: '1.20.5' + CONSUL_VERSION: '1.22.2' jobs: tests: @@ -34,6 +50,7 @@ jobs: - '8.2' - '8.3' - '8.4' + - '8.5' name: Tests - PHP ${{ matrix.php-version }} steps: @@ -48,8 +65,9 @@ jobs: case "${{ matrix.php-version }}" in 8.1) _phpunit_version='10.5' ;; 8.2) _phpunit_version='11.1' ;; - 8.3) _phpunit_version='11.1' ;; - 8.4) _phpunit_version='11.1' ;; + 8.3) _phpunit_version='12.0' ;; + 8.4) _phpunit_version='12.0' ;; + 8.5) _phpunit_version='12.0' ;; *) echo "Unsupported PHP version: ${{ matrix.php-version }}" && exit 1 ;; esac echo "phpunit-version=${_phpunit_version}" >> $GITHUB_OUTPUT @@ -59,6 +77,7 @@ jobs: php-version: ${{ matrix.php-version }} extensions: json ini-values: precision=14,serialize_precision=-1 + ini-file: 'development' - name: 'Install jq' uses: dcarbone/install-jq-action@v3 diff --git a/README.md b/README.md index 41bc3880..e815ef66 100644 --- a/README.md +++ b/README.md @@ -14,11 +14,27 @@ This library is loosely based upon the [official GO client](https://github.com/h | 0.6.x | 0.7-0.8 | | v1.x | 0.9-current | | v2.x | 0.9-current | +| v3.x | 0.9-current | | dev-main | current | Newer versions of the api lib will probably work in a limited capacity with older versions of Consul, but no guarantee is made and backwards compatibility issues will not be addressed. +### V3 Breaking Changes + +There are a couple breaking changes between v2 and v3: + +1. The `FakeMap` class has been removed. +2. The `FakeSlice` class has been removed. +3. The `ReadableDuration` class has been removed. +4. All models now have parameterized constructors. + * For the life of V3 I will continue to support construction from associative arrays, but the parameterized + constructors are the preferred method of construction. + * Construction via associative array will be removed entirely in V4 (whenever I get around to that). +5. All of that `Transcoding` nonsense has been removed. +6. The root `Config` class may no longer be constructed with a map. You must use constructor parameters. +7. All "map" fields are now defined as `\stdClass` objects. + ## Composer This lib is designed to be used with [Composer](https://getcomposer.org) @@ -28,7 +44,7 @@ Require Entry: ```json { "require": { - "dcarbone/php-consul-api": "^v2.0" + "dcarbone/php-consul-api": "^v3.0" } } ``` @@ -53,22 +69,28 @@ $config = \DCarbone\PHPConsulAPI\Config::newDefaultConfig(); You may alternatively define values yourself: ```php -$config = new \DCarbone\PHPConsulAPI\Config([ - 'HttpClient' => $client, // [required] Client conforming to GuzzleHttp\ClientInterface - 'Address' => 'address of server', // [required] - - 'Scheme' => 'http or https', // [optional] defaults to "http" - 'Datacenter' => 'name of datacenter', // [optional] - 'HttpAuth' => 'user:pass', // [optional] - 'WaitTime' => '0s', // [optional] amount of time to wait on certain blockable endpoints. go time duration string format. - 'Token' => 'auth token', // [optional] default auth token to use - 'TokenFile' => 'file with auth token', // [optional] file containing auth token string - 'InsecureSkipVerify' => false, // [optional] if set to true, ignores all SSL validation - 'CAFile' => '', // [optional] path to ca cert file, see http://docs.guzzlephp.org/en/latest/request-options.html#verify - 'CertFile' => '', // [optional] path to client public key. if set, requires KeyFile also be set - 'KeyFile' => '', // [optional] path to client private key. if set, requires CertFile also be set - 'JSONEncodeOpts'=> 0, // [optional] php json encode opt value to use when serializing requests -]); +$config = new \DCarbone\PHPConsulAPI\Config( + // required fields + HttpClient: $client, // [required] Client conforming to GuzzleHttp\ClientInterface + Address: 'address of server', // [required] + + // optional fields + Scheme: 'http or https', // [optional] defaults to "http" + Datacenter: 'name of datacenter', // [optional] + HttpAuth: 'user:pass', // [optional] + WaitTime: '0s', // [optional] amount of time to wait on certain blockable endpoints. go time duration string format. + Token: 'auth token', // [optional] default auth token to use + TokenFile: 'file with auth token', // [optional] file containing auth token string + InsecureSkipVerify: false, // [optional] if set to true, ignores all SSL validation + CAFile: '', // [optional] path to ca cert file, see http://docs.guzzlephp.org/en/latest/request-options.html#verify + CertFile: '', // [optional] path to client public key. if set, requires KeyFile also be set + KeyFile: '', // [optional] path to client private key. if set, requires CertFile also be set + + // php specific options + JSONEncodeOpts: JSON_UNESCAPED_SLASHES, + JSONDecodeMaxDepth: 512, + JSONDecodeOpts: 0, +); ``` #### Configuration Note: @@ -83,11 +105,11 @@ prior to constructing a PHPConsulAPI Config object. As an example: ```php -$proxyClient = new \GuzzleHttp\Client(['proxy' => 'whatever proxy you want']]); -$config = new \DCarbone\PHPConsulAPI\Config([ - 'HttpClient' => $proxyClient, - 'Address' => 'address of server', -]); +$proxyClient = new \GuzzleHttp\Client(['proxy' => 'whatever proxy you want']); +$config = new \DCarbone\PHPConsulAPI\Config( + HttpClient: $proxyClient, + Address: 'address of server', +); ``` When constructing your client, if you are using the `GuzzleHttp\Client` object directly or derivative thereof, you may diff --git a/composer.json b/composer.json index abff10c1..ba45d280 100644 --- a/composer.json +++ b/composer.json @@ -25,19 +25,18 @@ }, "autoload": { "files": [ - "src/Coordinate/funcs.php", - "src/funcs.php" + "src/PHPLib/funcs.php" ], "psr-4": { "DCarbone\\PHPConsulAPI\\": "src/" } }, "require-dev": { - "phpunit/phpunit": "^10.5 || ^11.0" + "phpunit/phpunit": "^10.5 || ^11.0 || ^13.0", + "phpstan/phpstan": "~2.1.11" }, "autoload-dev": { "files": [ - "src/Coordinate/funcs.php", "tests/funcs.php" ], "psr-4": { diff --git a/composer.lock b/composer.lock index c2e968d1..dbea1932 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": "01cc136766bba4c1a8f16d214945f536", + "content-hash": "86e172995bb9ccdc446f6a028d8ea25a", "packages": [ { "name": "dcarbone/gohttp", @@ -638,16 +638,16 @@ }, { "name": "symfony/deprecation-contracts", - "version": "v3.5.1", + "version": "v3.6.0", "source": { "type": "git", "url": "https://github.com/symfony/deprecation-contracts.git", - "reference": "74c71c939a79f7d5bf3c1ce9f5ea37ba0114c6f6" + "reference": "63afe740e99a13ba87ec199bb07bbdee937a5b62" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/74c71c939a79f7d5bf3c1ce9f5ea37ba0114c6f6", - "reference": "74c71c939a79f7d5bf3c1ce9f5ea37ba0114c6f6", + "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/63afe740e99a13ba87ec199bb07bbdee937a5b62", + "reference": "63afe740e99a13ba87ec199bb07bbdee937a5b62", "shasum": "" }, "require": { @@ -660,7 +660,7 @@ "name": "symfony/contracts" }, "branch-alias": { - "dev-main": "3.5-dev" + "dev-main": "3.6-dev" } }, "autoload": { @@ -685,7 +685,7 @@ "description": "A generic function and convention to trigger deprecation notices", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/deprecation-contracts/tree/v3.5.1" + "source": "https://github.com/symfony/deprecation-contracts/tree/v3.6.0" }, "funding": [ { @@ -701,22 +701,22 @@ "type": "tidelift" } ], - "time": "2024-09-25T14:20:29+00:00" + "time": "2024-09-25T14:21:43+00:00" } ], "packages-dev": [ { "name": "myclabs/deep-copy", - "version": "1.13.0", + "version": "1.13.1", "source": { "type": "git", "url": "https://github.com/myclabs/DeepCopy.git", - "reference": "024473a478be9df5fdaca2c793f2232fe788e414" + "reference": "1720ddd719e16cf0db4eb1c6eca108031636d46c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/024473a478be9df5fdaca2c793f2232fe788e414", - "reference": "024473a478be9df5fdaca2c793f2232fe788e414", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/1720ddd719e16cf0db4eb1c6eca108031636d46c", + "reference": "1720ddd719e16cf0db4eb1c6eca108031636d46c", "shasum": "" }, "require": { @@ -755,7 +755,7 @@ ], "support": { "issues": "https://github.com/myclabs/DeepCopy/issues", - "source": "https://github.com/myclabs/DeepCopy/tree/1.13.0" + "source": "https://github.com/myclabs/DeepCopy/tree/1.13.1" }, "funding": [ { @@ -763,20 +763,20 @@ "type": "tidelift" } ], - "time": "2025-02-12T12:17:51+00:00" + "time": "2025-04-29T12:36:36+00:00" }, { "name": "nikic/php-parser", - "version": "v5.4.0", + "version": "v5.5.0", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "447a020a1f875a434d62f2a401f53b82a396e494" + "reference": "ae59794362fe85e051a58ad36b289443f57be7a9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/447a020a1f875a434d62f2a401f53b82a396e494", - "reference": "447a020a1f875a434d62f2a401f53b82a396e494", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/ae59794362fe85e051a58ad36b289443f57be7a9", + "reference": "ae59794362fe85e051a58ad36b289443f57be7a9", "shasum": "" }, "require": { @@ -819,9 +819,9 @@ ], "support": { "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v5.4.0" + "source": "https://github.com/nikic/PHP-Parser/tree/v5.5.0" }, - "time": "2024-12-30T11:07:19+00:00" + "time": "2025-05-31T08:24:38+00:00" }, { "name": "phar-io/manifest", @@ -941,37 +941,95 @@ }, "time": "2022-02-21T01:04:05+00:00" }, + { + "name": "phpstan/phpstan", + "version": "2.1.17", + "source": { + "type": "git", + "url": "https://github.com/phpstan/phpstan.git", + "reference": "89b5ef665716fa2a52ecd2633f21007a6a349053" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/89b5ef665716fa2a52ecd2633f21007a6a349053", + "reference": "89b5ef665716fa2a52ecd2633f21007a6a349053", + "shasum": "" + }, + "require": { + "php": "^7.4|^8.0" + }, + "conflict": { + "phpstan/phpstan-shim": "*" + }, + "bin": [ + "phpstan", + "phpstan.phar" + ], + "type": "library", + "autoload": { + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "PHPStan - PHP Static Analysis Tool", + "keywords": [ + "dev", + "static analysis" + ], + "support": { + "docs": "https://phpstan.org/user-guide/getting-started", + "forum": "https://github.com/phpstan/phpstan/discussions", + "issues": "https://github.com/phpstan/phpstan/issues", + "security": "https://github.com/phpstan/phpstan/security/policy", + "source": "https://github.com/phpstan/phpstan-src" + }, + "funding": [ + { + "url": "https://github.com/ondrejmirtes", + "type": "github" + }, + { + "url": "https://github.com/phpstan", + "type": "github" + } + ], + "time": "2025-05-21T20:55:28+00:00" + }, { "name": "phpunit/php-code-coverage", - "version": "11.0.9", + "version": "10.1.16", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "14d63fbcca18457e49c6f8bebaa91a87e8e188d7" + "reference": "7e308268858ed6baedc8704a304727d20bc07c77" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/14d63fbcca18457e49c6f8bebaa91a87e8e188d7", - "reference": "14d63fbcca18457e49c6f8bebaa91a87e8e188d7", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/7e308268858ed6baedc8704a304727d20bc07c77", + "reference": "7e308268858ed6baedc8704a304727d20bc07c77", "shasum": "" }, "require": { "ext-dom": "*", "ext-libxml": "*", "ext-xmlwriter": "*", - "nikic/php-parser": "^5.4.0", - "php": ">=8.2", - "phpunit/php-file-iterator": "^5.1.0", - "phpunit/php-text-template": "^4.0.1", - "sebastian/code-unit-reverse-lookup": "^4.0.1", - "sebastian/complexity": "^4.0.1", - "sebastian/environment": "^7.2.0", - "sebastian/lines-of-code": "^3.0.1", - "sebastian/version": "^5.0.2", + "nikic/php-parser": "^4.19.1 || ^5.1.0", + "php": ">=8.1", + "phpunit/php-file-iterator": "^4.1.0", + "phpunit/php-text-template": "^3.0.1", + "sebastian/code-unit-reverse-lookup": "^3.0.0", + "sebastian/complexity": "^3.2.0", + "sebastian/environment": "^6.1.0", + "sebastian/lines-of-code": "^2.0.2", + "sebastian/version": "^4.0.1", "theseer/tokenizer": "^1.2.3" }, "require-dev": { - "phpunit/phpunit": "^11.5.2" + "phpunit/phpunit": "^10.1" }, "suggest": { "ext-pcov": "PHP extension that provides line coverage", @@ -980,7 +1038,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "11.0.x-dev" + "dev-main": "10.1.x-dev" } }, "autoload": { @@ -1009,7 +1067,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", "security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy", - "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/11.0.9" + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/10.1.16" }, "funding": [ { @@ -1017,32 +1075,32 @@ "type": "github" } ], - "time": "2025-02-25T13:26:39+00:00" + "time": "2024-08-22T04:31:57+00:00" }, { "name": "phpunit/php-file-iterator", - "version": "5.1.0", + "version": "4.1.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-file-iterator.git", - "reference": "118cfaaa8bc5aef3287bf315b6060b1174754af6" + "reference": "a95037b6d9e608ba092da1b23931e537cadc3c3c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/118cfaaa8bc5aef3287bf315b6060b1174754af6", - "reference": "118cfaaa8bc5aef3287bf315b6060b1174754af6", + "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/a95037b6d9e608ba092da1b23931e537cadc3c3c", + "reference": "a95037b6d9e608ba092da1b23931e537cadc3c3c", "shasum": "" }, "require": { - "php": ">=8.2" + "php": ">=8.1" }, "require-dev": { - "phpunit/phpunit": "^11.0" + "phpunit/phpunit": "^10.0" }, "type": "library", "extra": { "branch-alias": { - "dev-main": "5.0-dev" + "dev-main": "4.0-dev" } }, "autoload": { @@ -1070,7 +1128,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/php-file-iterator/issues", "security": "https://github.com/sebastianbergmann/php-file-iterator/security/policy", - "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/5.1.0" + "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/4.1.0" }, "funding": [ { @@ -1078,28 +1136,28 @@ "type": "github" } ], - "time": "2024-08-27T05:02:59+00:00" + "time": "2023-08-31T06:24:48+00:00" }, { "name": "phpunit/php-invoker", - "version": "5.0.1", + "version": "4.0.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-invoker.git", - "reference": "c1ca3814734c07492b3d4c5f794f4b0995333da2" + "reference": "f5e568ba02fa5ba0ddd0f618391d5a9ea50b06d7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-invoker/zipball/c1ca3814734c07492b3d4c5f794f4b0995333da2", - "reference": "c1ca3814734c07492b3d4c5f794f4b0995333da2", + "url": "https://api.github.com/repos/sebastianbergmann/php-invoker/zipball/f5e568ba02fa5ba0ddd0f618391d5a9ea50b06d7", + "reference": "f5e568ba02fa5ba0ddd0f618391d5a9ea50b06d7", "shasum": "" }, "require": { - "php": ">=8.2" + "php": ">=8.1" }, "require-dev": { "ext-pcntl": "*", - "phpunit/phpunit": "^11.0" + "phpunit/phpunit": "^10.0" }, "suggest": { "ext-pcntl": "*" @@ -1107,7 +1165,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "5.0-dev" + "dev-main": "4.0-dev" } }, "autoload": { @@ -1133,8 +1191,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/php-invoker/issues", - "security": "https://github.com/sebastianbergmann/php-invoker/security/policy", - "source": "https://github.com/sebastianbergmann/php-invoker/tree/5.0.1" + "source": "https://github.com/sebastianbergmann/php-invoker/tree/4.0.0" }, "funding": [ { @@ -1142,32 +1199,32 @@ "type": "github" } ], - "time": "2024-07-03T05:07:44+00:00" + "time": "2023-02-03T06:56:09+00:00" }, { "name": "phpunit/php-text-template", - "version": "4.0.1", + "version": "3.0.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-text-template.git", - "reference": "3e0404dc6b300e6bf56415467ebcb3fe4f33e964" + "reference": "0c7b06ff49e3d5072f057eb1fa59258bf287a748" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/3e0404dc6b300e6bf56415467ebcb3fe4f33e964", - "reference": "3e0404dc6b300e6bf56415467ebcb3fe4f33e964", + "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/0c7b06ff49e3d5072f057eb1fa59258bf287a748", + "reference": "0c7b06ff49e3d5072f057eb1fa59258bf287a748", "shasum": "" }, "require": { - "php": ">=8.2" + "php": ">=8.1" }, "require-dev": { - "phpunit/phpunit": "^11.0" + "phpunit/phpunit": "^10.0" }, "type": "library", "extra": { "branch-alias": { - "dev-main": "4.0-dev" + "dev-main": "3.0-dev" } }, "autoload": { @@ -1194,7 +1251,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/php-text-template/issues", "security": "https://github.com/sebastianbergmann/php-text-template/security/policy", - "source": "https://github.com/sebastianbergmann/php-text-template/tree/4.0.1" + "source": "https://github.com/sebastianbergmann/php-text-template/tree/3.0.1" }, "funding": [ { @@ -1202,32 +1259,32 @@ "type": "github" } ], - "time": "2024-07-03T05:08:43+00:00" + "time": "2023-08-31T14:07:24+00:00" }, { "name": "phpunit/php-timer", - "version": "7.0.1", + "version": "6.0.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-timer.git", - "reference": "3b415def83fbcb41f991d9ebf16ae4ad8b7837b3" + "reference": "e2a2d67966e740530f4a3343fe2e030ffdc1161d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/3b415def83fbcb41f991d9ebf16ae4ad8b7837b3", - "reference": "3b415def83fbcb41f991d9ebf16ae4ad8b7837b3", + "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/e2a2d67966e740530f4a3343fe2e030ffdc1161d", + "reference": "e2a2d67966e740530f4a3343fe2e030ffdc1161d", "shasum": "" }, "require": { - "php": ">=8.2" + "php": ">=8.1" }, "require-dev": { - "phpunit/phpunit": "^11.0" + "phpunit/phpunit": "^10.0" }, "type": "library", "extra": { "branch-alias": { - "dev-main": "7.0-dev" + "dev-main": "6.0-dev" } }, "autoload": { @@ -1253,8 +1310,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/php-timer/issues", - "security": "https://github.com/sebastianbergmann/php-timer/security/policy", - "source": "https://github.com/sebastianbergmann/php-timer/tree/7.0.1" + "source": "https://github.com/sebastianbergmann/php-timer/tree/6.0.0" }, "funding": [ { @@ -1262,20 +1318,20 @@ "type": "github" } ], - "time": "2024-07-03T05:09:35+00:00" + "time": "2023-02-03T06:57:52+00:00" }, { "name": "phpunit/phpunit", - "version": "11.5.15", + "version": "10.5.47", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "4b6a4ee654e5e0c5e1f17e2f83c0f4c91dee1f9c" + "reference": "3637b3e50d32ab3a0d1a33b3b6177169ec3d95a3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/4b6a4ee654e5e0c5e1f17e2f83c0f4c91dee1f9c", - "reference": "4b6a4ee654e5e0c5e1f17e2f83c0f4c91dee1f9c", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/3637b3e50d32ab3a0d1a33b3b6177169ec3d95a3", + "reference": "3637b3e50d32ab3a0d1a33b3b6177169ec3d95a3", "shasum": "" }, "require": { @@ -1285,26 +1341,26 @@ "ext-mbstring": "*", "ext-xml": "*", "ext-xmlwriter": "*", - "myclabs/deep-copy": "^1.13.0", + "myclabs/deep-copy": "^1.13.1", "phar-io/manifest": "^2.0.4", "phar-io/version": "^3.2.1", - "php": ">=8.2", - "phpunit/php-code-coverage": "^11.0.9", - "phpunit/php-file-iterator": "^5.1.0", - "phpunit/php-invoker": "^5.0.1", - "phpunit/php-text-template": "^4.0.1", - "phpunit/php-timer": "^7.0.1", - "sebastian/cli-parser": "^3.0.2", - "sebastian/code-unit": "^3.0.3", - "sebastian/comparator": "^6.3.1", - "sebastian/diff": "^6.0.2", - "sebastian/environment": "^7.2.0", - "sebastian/exporter": "^6.3.0", - "sebastian/global-state": "^7.0.2", - "sebastian/object-enumerator": "^6.0.1", - "sebastian/type": "^5.1.2", - "sebastian/version": "^5.0.2", - "staabm/side-effects-detector": "^1.0.5" + "php": ">=8.1", + "phpunit/php-code-coverage": "^10.1.16", + "phpunit/php-file-iterator": "^4.1.0", + "phpunit/php-invoker": "^4.0.0", + "phpunit/php-text-template": "^3.0.1", + "phpunit/php-timer": "^6.0.0", + "sebastian/cli-parser": "^2.0.1", + "sebastian/code-unit": "^2.0.0", + "sebastian/comparator": "^5.0.3", + "sebastian/diff": "^5.1.1", + "sebastian/environment": "^6.1.0", + "sebastian/exporter": "^5.1.2", + "sebastian/global-state": "^6.0.2", + "sebastian/object-enumerator": "^5.0.0", + "sebastian/recursion-context": "^5.0.0", + "sebastian/type": "^4.0.0", + "sebastian/version": "^4.0.1" }, "suggest": { "ext-soap": "To be able to generate mocks based on WSDL files" @@ -1315,7 +1371,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "11.5-dev" + "dev-main": "10.5-dev" } }, "autoload": { @@ -1347,7 +1403,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", "security": "https://github.com/sebastianbergmann/phpunit/security/policy", - "source": "https://github.com/sebastianbergmann/phpunit/tree/11.5.15" + "source": "https://github.com/sebastianbergmann/phpunit/tree/10.5.47" }, "funding": [ { @@ -1358,37 +1414,45 @@ "url": "https://github.com/sebastianbergmann", "type": "github" }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, { "url": "https://tidelift.com/funding/github/packagist/phpunit/phpunit", "type": "tidelift" } ], - "time": "2025-03-23T16:02:11+00:00" + "time": "2025-06-20T11:29:11+00:00" }, { "name": "sebastian/cli-parser", - "version": "3.0.2", + "version": "2.0.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/cli-parser.git", - "reference": "15c5dd40dc4f38794d383bb95465193f5e0ae180" + "reference": "c34583b87e7b7a8055bf6c450c2c77ce32a24084" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/15c5dd40dc4f38794d383bb95465193f5e0ae180", - "reference": "15c5dd40dc4f38794d383bb95465193f5e0ae180", + "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/c34583b87e7b7a8055bf6c450c2c77ce32a24084", + "reference": "c34583b87e7b7a8055bf6c450c2c77ce32a24084", "shasum": "" }, "require": { - "php": ">=8.2" + "php": ">=8.1" }, "require-dev": { - "phpunit/phpunit": "^11.0" + "phpunit/phpunit": "^10.0" }, "type": "library", "extra": { "branch-alias": { - "dev-main": "3.0-dev" + "dev-main": "2.0-dev" } }, "autoload": { @@ -1412,7 +1476,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/cli-parser/issues", "security": "https://github.com/sebastianbergmann/cli-parser/security/policy", - "source": "https://github.com/sebastianbergmann/cli-parser/tree/3.0.2" + "source": "https://github.com/sebastianbergmann/cli-parser/tree/2.0.1" }, "funding": [ { @@ -1420,32 +1484,32 @@ "type": "github" } ], - "time": "2024-07-03T04:41:36+00:00" + "time": "2024-03-02T07:12:49+00:00" }, { "name": "sebastian/code-unit", - "version": "3.0.3", + "version": "2.0.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/code-unit.git", - "reference": "54391c61e4af8078e5b276ab082b6d3c54c9ad64" + "reference": "a81fee9eef0b7a76af11d121767abc44c104e503" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/code-unit/zipball/54391c61e4af8078e5b276ab082b6d3c54c9ad64", - "reference": "54391c61e4af8078e5b276ab082b6d3c54c9ad64", + "url": "https://api.github.com/repos/sebastianbergmann/code-unit/zipball/a81fee9eef0b7a76af11d121767abc44c104e503", + "reference": "a81fee9eef0b7a76af11d121767abc44c104e503", "shasum": "" }, "require": { - "php": ">=8.2" + "php": ">=8.1" }, "require-dev": { - "phpunit/phpunit": "^11.5" + "phpunit/phpunit": "^10.0" }, "type": "library", "extra": { "branch-alias": { - "dev-main": "3.0-dev" + "dev-main": "2.0-dev" } }, "autoload": { @@ -1468,8 +1532,7 @@ "homepage": "https://github.com/sebastianbergmann/code-unit", "support": { "issues": "https://github.com/sebastianbergmann/code-unit/issues", - "security": "https://github.com/sebastianbergmann/code-unit/security/policy", - "source": "https://github.com/sebastianbergmann/code-unit/tree/3.0.3" + "source": "https://github.com/sebastianbergmann/code-unit/tree/2.0.0" }, "funding": [ { @@ -1477,32 +1540,32 @@ "type": "github" } ], - "time": "2025-03-19T07:56:08+00:00" + "time": "2023-02-03T06:58:43+00:00" }, { "name": "sebastian/code-unit-reverse-lookup", - "version": "4.0.1", + "version": "3.0.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git", - "reference": "183a9b2632194febd219bb9246eee421dad8d45e" + "reference": "5e3a687f7d8ae33fb362c5c0743794bbb2420a1d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/183a9b2632194febd219bb9246eee421dad8d45e", - "reference": "183a9b2632194febd219bb9246eee421dad8d45e", + "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/5e3a687f7d8ae33fb362c5c0743794bbb2420a1d", + "reference": "5e3a687f7d8ae33fb362c5c0743794bbb2420a1d", "shasum": "" }, "require": { - "php": ">=8.2" + "php": ">=8.1" }, "require-dev": { - "phpunit/phpunit": "^11.0" + "phpunit/phpunit": "^10.0" }, "type": "library", "extra": { "branch-alias": { - "dev-main": "4.0-dev" + "dev-main": "3.0-dev" } }, "autoload": { @@ -1524,8 +1587,7 @@ "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/", "support": { "issues": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/issues", - "security": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/security/policy", - "source": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/tree/4.0.1" + "source": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/tree/3.0.0" }, "funding": [ { @@ -1533,39 +1595,36 @@ "type": "github" } ], - "time": "2024-07-03T04:45:54+00:00" + "time": "2023-02-03T06:59:15+00:00" }, { "name": "sebastian/comparator", - "version": "6.3.1", + "version": "5.0.3", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/comparator.git", - "reference": "24b8fbc2c8e201bb1308e7b05148d6ab393b6959" + "reference": "a18251eb0b7a2dcd2f7aa3d6078b18545ef0558e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/24b8fbc2c8e201bb1308e7b05148d6ab393b6959", - "reference": "24b8fbc2c8e201bb1308e7b05148d6ab393b6959", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/a18251eb0b7a2dcd2f7aa3d6078b18545ef0558e", + "reference": "a18251eb0b7a2dcd2f7aa3d6078b18545ef0558e", "shasum": "" }, "require": { "ext-dom": "*", "ext-mbstring": "*", - "php": ">=8.2", - "sebastian/diff": "^6.0", - "sebastian/exporter": "^6.0" + "php": ">=8.1", + "sebastian/diff": "^5.0", + "sebastian/exporter": "^5.0" }, "require-dev": { - "phpunit/phpunit": "^11.4" - }, - "suggest": { - "ext-bcmath": "For comparing BcMath\\Number objects" + "phpunit/phpunit": "^10.5" }, "type": "library", "extra": { "branch-alias": { - "dev-main": "6.3-dev" + "dev-main": "5.0-dev" } }, "autoload": { @@ -1605,7 +1664,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/comparator/issues", "security": "https://github.com/sebastianbergmann/comparator/security/policy", - "source": "https://github.com/sebastianbergmann/comparator/tree/6.3.1" + "source": "https://github.com/sebastianbergmann/comparator/tree/5.0.3" }, "funding": [ { @@ -1613,33 +1672,33 @@ "type": "github" } ], - "time": "2025-03-07T06:57:01+00:00" + "time": "2024-10-18T14:56:07+00:00" }, { "name": "sebastian/complexity", - "version": "4.0.1", + "version": "3.2.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/complexity.git", - "reference": "ee41d384ab1906c68852636b6de493846e13e5a0" + "reference": "68ff824baeae169ec9f2137158ee529584553799" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/ee41d384ab1906c68852636b6de493846e13e5a0", - "reference": "ee41d384ab1906c68852636b6de493846e13e5a0", + "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/68ff824baeae169ec9f2137158ee529584553799", + "reference": "68ff824baeae169ec9f2137158ee529584553799", "shasum": "" }, "require": { - "nikic/php-parser": "^5.0", - "php": ">=8.2" + "nikic/php-parser": "^4.18 || ^5.0", + "php": ">=8.1" }, "require-dev": { - "phpunit/phpunit": "^11.0" + "phpunit/phpunit": "^10.0" }, "type": "library", "extra": { "branch-alias": { - "dev-main": "4.0-dev" + "dev-main": "3.2-dev" } }, "autoload": { @@ -1663,7 +1722,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/complexity/issues", "security": "https://github.com/sebastianbergmann/complexity/security/policy", - "source": "https://github.com/sebastianbergmann/complexity/tree/4.0.1" + "source": "https://github.com/sebastianbergmann/complexity/tree/3.2.0" }, "funding": [ { @@ -1671,33 +1730,33 @@ "type": "github" } ], - "time": "2024-07-03T04:49:50+00:00" + "time": "2023-12-21T08:37:17+00:00" }, { "name": "sebastian/diff", - "version": "6.0.2", + "version": "5.1.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/diff.git", - "reference": "b4ccd857127db5d41a5b676f24b51371d76d8544" + "reference": "c41e007b4b62af48218231d6c2275e4c9b975b2e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/b4ccd857127db5d41a5b676f24b51371d76d8544", - "reference": "b4ccd857127db5d41a5b676f24b51371d76d8544", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/c41e007b4b62af48218231d6c2275e4c9b975b2e", + "reference": "c41e007b4b62af48218231d6c2275e4c9b975b2e", "shasum": "" }, "require": { - "php": ">=8.2" + "php": ">=8.1" }, "require-dev": { - "phpunit/phpunit": "^11.0", - "symfony/process": "^4.2 || ^5" + "phpunit/phpunit": "^10.0", + "symfony/process": "^6.4" }, "type": "library", "extra": { "branch-alias": { - "dev-main": "6.0-dev" + "dev-main": "5.1-dev" } }, "autoload": { @@ -1730,7 +1789,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/diff/issues", "security": "https://github.com/sebastianbergmann/diff/security/policy", - "source": "https://github.com/sebastianbergmann/diff/tree/6.0.2" + "source": "https://github.com/sebastianbergmann/diff/tree/5.1.1" }, "funding": [ { @@ -1738,27 +1797,27 @@ "type": "github" } ], - "time": "2024-07-03T04:53:05+00:00" + "time": "2024-03-02T07:15:17+00:00" }, { "name": "sebastian/environment", - "version": "7.2.0", + "version": "6.1.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/environment.git", - "reference": "855f3ae0ab316bbafe1ba4e16e9f3c078d24a0c5" + "reference": "8074dbcd93529b357029f5cc5058fd3e43666984" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/855f3ae0ab316bbafe1ba4e16e9f3c078d24a0c5", - "reference": "855f3ae0ab316bbafe1ba4e16e9f3c078d24a0c5", + "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/8074dbcd93529b357029f5cc5058fd3e43666984", + "reference": "8074dbcd93529b357029f5cc5058fd3e43666984", "shasum": "" }, "require": { - "php": ">=8.2" + "php": ">=8.1" }, "require-dev": { - "phpunit/phpunit": "^11.0" + "phpunit/phpunit": "^10.0" }, "suggest": { "ext-posix": "*" @@ -1766,7 +1825,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "7.2-dev" + "dev-main": "6.1-dev" } }, "autoload": { @@ -1794,7 +1853,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/environment/issues", "security": "https://github.com/sebastianbergmann/environment/security/policy", - "source": "https://github.com/sebastianbergmann/environment/tree/7.2.0" + "source": "https://github.com/sebastianbergmann/environment/tree/6.1.0" }, "funding": [ { @@ -1802,34 +1861,34 @@ "type": "github" } ], - "time": "2024-07-03T04:54:44+00:00" + "time": "2024-03-23T08:47:14+00:00" }, { "name": "sebastian/exporter", - "version": "6.3.0", + "version": "5.1.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/exporter.git", - "reference": "3473f61172093b2da7de1fb5782e1f24cc036dc3" + "reference": "955288482d97c19a372d3f31006ab3f37da47adf" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/3473f61172093b2da7de1fb5782e1f24cc036dc3", - "reference": "3473f61172093b2da7de1fb5782e1f24cc036dc3", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/955288482d97c19a372d3f31006ab3f37da47adf", + "reference": "955288482d97c19a372d3f31006ab3f37da47adf", "shasum": "" }, "require": { "ext-mbstring": "*", - "php": ">=8.2", - "sebastian/recursion-context": "^6.0" + "php": ">=8.1", + "sebastian/recursion-context": "^5.0" }, "require-dev": { - "phpunit/phpunit": "^11.3" + "phpunit/phpunit": "^10.0" }, "type": "library", "extra": { "branch-alias": { - "dev-main": "6.1-dev" + "dev-main": "5.1-dev" } }, "autoload": { @@ -1872,7 +1931,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/exporter/issues", "security": "https://github.com/sebastianbergmann/exporter/security/policy", - "source": "https://github.com/sebastianbergmann/exporter/tree/6.3.0" + "source": "https://github.com/sebastianbergmann/exporter/tree/5.1.2" }, "funding": [ { @@ -1880,35 +1939,35 @@ "type": "github" } ], - "time": "2024-12-05T09:17:50+00:00" + "time": "2024-03-02T07:17:12+00:00" }, { "name": "sebastian/global-state", - "version": "7.0.2", + "version": "6.0.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/global-state.git", - "reference": "3be331570a721f9a4b5917f4209773de17f747d7" + "reference": "987bafff24ecc4c9ac418cab1145b96dd6e9cbd9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/3be331570a721f9a4b5917f4209773de17f747d7", - "reference": "3be331570a721f9a4b5917f4209773de17f747d7", + "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/987bafff24ecc4c9ac418cab1145b96dd6e9cbd9", + "reference": "987bafff24ecc4c9ac418cab1145b96dd6e9cbd9", "shasum": "" }, "require": { - "php": ">=8.2", - "sebastian/object-reflector": "^4.0", - "sebastian/recursion-context": "^6.0" + "php": ">=8.1", + "sebastian/object-reflector": "^3.0", + "sebastian/recursion-context": "^5.0" }, "require-dev": { "ext-dom": "*", - "phpunit/phpunit": "^11.0" + "phpunit/phpunit": "^10.0" }, "type": "library", "extra": { "branch-alias": { - "dev-main": "7.0-dev" + "dev-main": "6.0-dev" } }, "autoload": { @@ -1934,7 +1993,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/global-state/issues", "security": "https://github.com/sebastianbergmann/global-state/security/policy", - "source": "https://github.com/sebastianbergmann/global-state/tree/7.0.2" + "source": "https://github.com/sebastianbergmann/global-state/tree/6.0.2" }, "funding": [ { @@ -1942,33 +2001,33 @@ "type": "github" } ], - "time": "2024-07-03T04:57:36+00:00" + "time": "2024-03-02T07:19:19+00:00" }, { "name": "sebastian/lines-of-code", - "version": "3.0.1", + "version": "2.0.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/lines-of-code.git", - "reference": "d36ad0d782e5756913e42ad87cb2890f4ffe467a" + "reference": "856e7f6a75a84e339195d48c556f23be2ebf75d0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/d36ad0d782e5756913e42ad87cb2890f4ffe467a", - "reference": "d36ad0d782e5756913e42ad87cb2890f4ffe467a", + "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/856e7f6a75a84e339195d48c556f23be2ebf75d0", + "reference": "856e7f6a75a84e339195d48c556f23be2ebf75d0", "shasum": "" }, "require": { - "nikic/php-parser": "^5.0", - "php": ">=8.2" + "nikic/php-parser": "^4.18 || ^5.0", + "php": ">=8.1" }, "require-dev": { - "phpunit/phpunit": "^11.0" + "phpunit/phpunit": "^10.0" }, "type": "library", "extra": { "branch-alias": { - "dev-main": "3.0-dev" + "dev-main": "2.0-dev" } }, "autoload": { @@ -1992,7 +2051,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/lines-of-code/issues", "security": "https://github.com/sebastianbergmann/lines-of-code/security/policy", - "source": "https://github.com/sebastianbergmann/lines-of-code/tree/3.0.1" + "source": "https://github.com/sebastianbergmann/lines-of-code/tree/2.0.2" }, "funding": [ { @@ -2000,34 +2059,34 @@ "type": "github" } ], - "time": "2024-07-03T04:58:38+00:00" + "time": "2023-12-21T08:38:20+00:00" }, { "name": "sebastian/object-enumerator", - "version": "6.0.1", + "version": "5.0.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/object-enumerator.git", - "reference": "f5b498e631a74204185071eb41f33f38d64608aa" + "reference": "202d0e344a580d7f7d04b3fafce6933e59dae906" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/f5b498e631a74204185071eb41f33f38d64608aa", - "reference": "f5b498e631a74204185071eb41f33f38d64608aa", + "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/202d0e344a580d7f7d04b3fafce6933e59dae906", + "reference": "202d0e344a580d7f7d04b3fafce6933e59dae906", "shasum": "" }, "require": { - "php": ">=8.2", - "sebastian/object-reflector": "^4.0", - "sebastian/recursion-context": "^6.0" + "php": ">=8.1", + "sebastian/object-reflector": "^3.0", + "sebastian/recursion-context": "^5.0" }, "require-dev": { - "phpunit/phpunit": "^11.0" + "phpunit/phpunit": "^10.0" }, "type": "library", "extra": { "branch-alias": { - "dev-main": "6.0-dev" + "dev-main": "5.0-dev" } }, "autoload": { @@ -2049,8 +2108,7 @@ "homepage": "https://github.com/sebastianbergmann/object-enumerator/", "support": { "issues": "https://github.com/sebastianbergmann/object-enumerator/issues", - "security": "https://github.com/sebastianbergmann/object-enumerator/security/policy", - "source": "https://github.com/sebastianbergmann/object-enumerator/tree/6.0.1" + "source": "https://github.com/sebastianbergmann/object-enumerator/tree/5.0.0" }, "funding": [ { @@ -2058,32 +2116,32 @@ "type": "github" } ], - "time": "2024-07-03T05:00:13+00:00" + "time": "2023-02-03T07:08:32+00:00" }, { "name": "sebastian/object-reflector", - "version": "4.0.1", + "version": "3.0.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/object-reflector.git", - "reference": "6e1a43b411b2ad34146dee7524cb13a068bb35f9" + "reference": "24ed13d98130f0e7122df55d06c5c4942a577957" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/6e1a43b411b2ad34146dee7524cb13a068bb35f9", - "reference": "6e1a43b411b2ad34146dee7524cb13a068bb35f9", + "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/24ed13d98130f0e7122df55d06c5c4942a577957", + "reference": "24ed13d98130f0e7122df55d06c5c4942a577957", "shasum": "" }, "require": { - "php": ">=8.2" + "php": ">=8.1" }, "require-dev": { - "phpunit/phpunit": "^11.0" + "phpunit/phpunit": "^10.0" }, "type": "library", "extra": { "branch-alias": { - "dev-main": "4.0-dev" + "dev-main": "3.0-dev" } }, "autoload": { @@ -2105,8 +2163,7 @@ "homepage": "https://github.com/sebastianbergmann/object-reflector/", "support": { "issues": "https://github.com/sebastianbergmann/object-reflector/issues", - "security": "https://github.com/sebastianbergmann/object-reflector/security/policy", - "source": "https://github.com/sebastianbergmann/object-reflector/tree/4.0.1" + "source": "https://github.com/sebastianbergmann/object-reflector/tree/3.0.0" }, "funding": [ { @@ -2114,32 +2171,32 @@ "type": "github" } ], - "time": "2024-07-03T05:01:32+00:00" + "time": "2023-02-03T07:06:18+00:00" }, { "name": "sebastian/recursion-context", - "version": "6.0.2", + "version": "5.0.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/recursion-context.git", - "reference": "694d156164372abbd149a4b85ccda2e4670c0e16" + "reference": "05909fb5bc7df4c52992396d0116aed689f93712" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/694d156164372abbd149a4b85ccda2e4670c0e16", - "reference": "694d156164372abbd149a4b85ccda2e4670c0e16", + "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/05909fb5bc7df4c52992396d0116aed689f93712", + "reference": "05909fb5bc7df4c52992396d0116aed689f93712", "shasum": "" }, "require": { - "php": ">=8.2" + "php": ">=8.1" }, "require-dev": { - "phpunit/phpunit": "^11.0" + "phpunit/phpunit": "^10.0" }, "type": "library", "extra": { "branch-alias": { - "dev-main": "6.0-dev" + "dev-main": "5.0-dev" } }, "autoload": { @@ -2169,8 +2226,7 @@ "homepage": "https://github.com/sebastianbergmann/recursion-context", "support": { "issues": "https://github.com/sebastianbergmann/recursion-context/issues", - "security": "https://github.com/sebastianbergmann/recursion-context/security/policy", - "source": "https://github.com/sebastianbergmann/recursion-context/tree/6.0.2" + "source": "https://github.com/sebastianbergmann/recursion-context/tree/5.0.0" }, "funding": [ { @@ -2178,32 +2234,32 @@ "type": "github" } ], - "time": "2024-07-03T05:10:34+00:00" + "time": "2023-02-03T07:05:40+00:00" }, { "name": "sebastian/type", - "version": "5.1.2", + "version": "4.0.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/type.git", - "reference": "a8a7e30534b0eb0c77cd9d07e82de1a114389f5e" + "reference": "462699a16464c3944eefc02ebdd77882bd3925bf" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/a8a7e30534b0eb0c77cd9d07e82de1a114389f5e", - "reference": "a8a7e30534b0eb0c77cd9d07e82de1a114389f5e", + "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/462699a16464c3944eefc02ebdd77882bd3925bf", + "reference": "462699a16464c3944eefc02ebdd77882bd3925bf", "shasum": "" }, "require": { - "php": ">=8.2" + "php": ">=8.1" }, "require-dev": { - "phpunit/phpunit": "^11.3" + "phpunit/phpunit": "^10.0" }, "type": "library", "extra": { "branch-alias": { - "dev-main": "5.1-dev" + "dev-main": "4.0-dev" } }, "autoload": { @@ -2226,8 +2282,7 @@ "homepage": "https://github.com/sebastianbergmann/type", "support": { "issues": "https://github.com/sebastianbergmann/type/issues", - "security": "https://github.com/sebastianbergmann/type/security/policy", - "source": "https://github.com/sebastianbergmann/type/tree/5.1.2" + "source": "https://github.com/sebastianbergmann/type/tree/4.0.0" }, "funding": [ { @@ -2235,29 +2290,29 @@ "type": "github" } ], - "time": "2025-03-18T13:35:50+00:00" + "time": "2023-02-03T07:10:45+00:00" }, { "name": "sebastian/version", - "version": "5.0.2", + "version": "4.0.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/version.git", - "reference": "c687e3387b99f5b03b6caa64c74b63e2936ff874" + "reference": "c51fa83a5d8f43f1402e3f32a005e6262244ef17" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/c687e3387b99f5b03b6caa64c74b63e2936ff874", - "reference": "c687e3387b99f5b03b6caa64c74b63e2936ff874", + "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/c51fa83a5d8f43f1402e3f32a005e6262244ef17", + "reference": "c51fa83a5d8f43f1402e3f32a005e6262244ef17", "shasum": "" }, "require": { - "php": ">=8.2" + "php": ">=8.1" }, "type": "library", "extra": { "branch-alias": { - "dev-main": "5.0-dev" + "dev-main": "4.0-dev" } }, "autoload": { @@ -2280,8 +2335,7 @@ "homepage": "https://github.com/sebastianbergmann/version", "support": { "issues": "https://github.com/sebastianbergmann/version/issues", - "security": "https://github.com/sebastianbergmann/version/security/policy", - "source": "https://github.com/sebastianbergmann/version/tree/5.0.2" + "source": "https://github.com/sebastianbergmann/version/tree/4.0.1" }, "funding": [ { @@ -2289,59 +2343,7 @@ "type": "github" } ], - "time": "2024-10-09T05:16:32+00:00" - }, - { - "name": "staabm/side-effects-detector", - "version": "1.0.5", - "source": { - "type": "git", - "url": "https://github.com/staabm/side-effects-detector.git", - "reference": "d8334211a140ce329c13726d4a715adbddd0a163" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/staabm/side-effects-detector/zipball/d8334211a140ce329c13726d4a715adbddd0a163", - "reference": "d8334211a140ce329c13726d4a715adbddd0a163", - "shasum": "" - }, - "require": { - "ext-tokenizer": "*", - "php": "^7.4 || ^8.0" - }, - "require-dev": { - "phpstan/extension-installer": "^1.4.3", - "phpstan/phpstan": "^1.12.6", - "phpunit/phpunit": "^9.6.21", - "symfony/var-dumper": "^5.4.43", - "tomasvotruba/type-coverage": "1.0.0", - "tomasvotruba/unused-public": "1.0.0" - }, - "type": "library", - "autoload": { - "classmap": [ - "lib/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "A static analysis tool to detect side effects in PHP code", - "keywords": [ - "static analysis" - ], - "support": { - "issues": "https://github.com/staabm/side-effects-detector/issues", - "source": "https://github.com/staabm/side-effects-detector/tree/1.0.5" - }, - "funding": [ - { - "url": "https://github.com/staabm", - "type": "github" - } - ], - "time": "2024-10-20T05:08:20+00:00" + "time": "2023-02-07T11:34:05+00:00" }, { "name": "theseer/tokenizer", diff --git a/phpstan.neon b/phpstan.neon new file mode 100644 index 00000000..50495918 --- /dev/null +++ b/phpstan.neon @@ -0,0 +1,6 @@ +parameters: + level: 6 + paths: + - src + - tests + treatPhpDocTypesAsCertain: false diff --git a/phpunit.xml b/phpunit.xml index 0699e390..d324fb9b 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -8,11 +8,15 @@ > - - + + + + ./tests/Unit + + ./tests/Usage/ConfigUsageTest.php @@ -20,9 +24,9 @@ ./tests/Usage/RequestUsageTest.php - - - + + ./tests/Usage/ACL + ./tests/Usage/Agent diff --git a/src/ACL/ACLAuthMethod.php b/src/ACL/ACLAuthMethod.php index bb7d2d9d..95ba7e33 100644 --- a/src/ACL/ACLAuthMethod.php +++ b/src/ACL/ACLAuthMethod.php @@ -21,67 +21,56 @@ */ use DCarbone\Go\Time; -use DCarbone\PHPConsulAPI\AbstractModel; -use DCarbone\PHPConsulAPI\Transcoding; +use DCarbone\PHPConsulAPI\PHPLib\AbstractType; -class ACLAuthMethod extends AbstractModel +class ACLAuthMethod extends AbstractType { - protected const FIELDS = [ - self::FIELD_DISPLAY_NAME => Transcoding::OMITEMPTY_STRING_FIELD, - self::FIELD_DESCRIPTION => Transcoding::OMITEMPTY_STRING_FIELD, - self::FIELD_MAX_TOKEN_TTL => [ - Transcoding::FIELD_UNMARSHAL_CALLBACK => Transcoding::UNMARSHAL_DURATION, - Transcoding::FIELD_MARSHAL_AS => Transcoding::STRING, - Transcoding::FIELD_OMITEMPTY => true, - ], - self::FIELD_TOKEN_LOCALITY => Transcoding::OMITEMPTY_STRING_FIELD, - self::FIELD_NAMESPACE_RULES => [ - Transcoding::FIELD_TYPE => Transcoding::ARRAY, - Transcoding::FIELD_CLASS => ACLAuthMethodNamespaceRule::class, - Transcoding::FIELD_ARRAY_TYPE => Transcoding::class, - Transcoding::FIELD_OMITEMPTY => true, - ], - self::FIELD_NAMESPACE => Transcoding::OMITEMPTY_STRING_FIELD, - ]; - - private const FIELD_DISPLAY_NAME = 'DisplayName'; - private const FIELD_DESCRIPTION = 'Description'; - private const FIELD_MAX_TOKEN_TTL = 'MaxTokenTTL'; - private const FIELD_TOKEN_LOCALITY = 'TokenLocality'; - private const FIELD_NAMESPACE_RULES = 'NamespaceRules'; - private const FIELD_NAMESPACE = 'Namespace'; - - public string $ID = ''; - public string $Name = ''; - public string $Type = ''; - public string $DisplayName = ''; - public string $Description = ''; + public string $Name; + public string $Type; + public string $DisplayName; + public string $Description; public Time\Duration $MaxTokenTTL; - public string $TokenLocality = ''; - public array $config = []; - public int $CreateIndex = 0; - public int $ModifyIndex = 0; - public array $NamespaceRules = []; - public string $Namespace = ''; - - public function __construct(?array $data = null) - { - parent::__construct($data); - if (!isset($this->MaxTokenTTL)) { - $this->MaxTokenTTL = new Time\Duration(); - } - } - - public function getID(): string - { - return $this->ID; - } - - public function setID(string $ID): ACLAuthMethod - { - $this->ID = $ID; - return $this; - } + public string $TokenLocality; + /** @var array */ + public array $Config; + public int $CreateIndex; + public int $ModifyIndex; + /** @var \DCarbone\PHPConsulAPI\ACL\ACLAuthMethodNamespaceRule[] */ + public array $NamespaceRules; + public string $Namespace; + public string $Partition; + + /** + * @param array $Config + * @param array<\DCarbone\PHPConsulAPI\ACL\ACLAuthMethodNamespaceRule> $NamespaceRules + */ + public function __construct( + string $Name = '', + string $Type = '', + string $DisplayName = '', + string $Description = '', + null|int|float|string|\DateInterval|Time\Duration $MaxTokenTTL = null, + string $TokenLocality = '', + array $Config = [], + int $CreateIndex = 0, + int $ModifyIndex = 0, + array $NamespaceRules = [], + string $Namespace = '', + string $Partition = '', + ) { + $this->Name = $Name; + $this->Type = $Type; + $this->DisplayName = $DisplayName; + $this->Description = $Description; + $this->MaxTokenTTL = Time::Duration($MaxTokenTTL); + $this->TokenLocality = $TokenLocality; + $this->setConfig($Config); + $this->CreateIndex = $CreateIndex; + $this->ModifyIndex = $ModifyIndex; + $this->setNamespaceRules(...$NamespaceRules); + $this->Namespace = $Namespace; + $this->Partition = $Partition; +} public function getName(): string { @@ -132,9 +121,9 @@ public function getMaxTokenTTL(): Time\Duration return $this->MaxTokenTTL; } - public function setMaxTokenTTL(int|string|Time\Duration $MaxTokenTTL): self + public function setMaxTokenTTL(null|int|float|string|\DateInterval|Time\Duration $MaxTokenTTL): self { - $this->MaxTokenTTL = Time::ParseDuration($MaxTokenTTL); + $this->MaxTokenTTL = Time::Duration($MaxTokenTTL); return $this; } @@ -149,14 +138,26 @@ public function setTokenLocality(string $TokenLocality): self return $this; } + /** + * @return array + */ public function getConfig(): array { - return $this->config; + return $this->Config; } - public function setConfig(array $config): self + /** + * @param null|\stdClass|array $Config + * @return $this + */ + public function setConfig(null|\stdClass|array $Config): self { - $this->config = $config; + $this->Config = []; + if (null !== $Config) { + foreach ($Config as $k => $v) { + $this->Config[$k] = $v; + } + } return $this; } @@ -182,14 +183,23 @@ public function setModifyIndex(int $ModifyIndex): self return $this; } + /** + * @return array<\DCarbone\PHPConsulAPI\ACL\ACLAuthMethodNamespaceRule> + */ public function getNamespaceRules(): array { return $this->NamespaceRules; } - public function setNamespaceRules(array $NamespaceRules): self + public function addNamespaceRule(ACLAuthMethodNamespaceRule $rule): self + { + $this->NamespaceRules[] = $rule; + return $this; + } + + public function setNamespaceRules(ACLAuthMethodNamespaceRule ...$rules): self { - $this->NamespaceRules = $NamespaceRules; + $this->NamespaceRules = $rules; return $this; } @@ -203,4 +213,66 @@ public function setNamespace(string $Namespace): self $this->Namespace = $Namespace; return $this; } + + public function getPartition(): string + { + return $this->Partition; + } + + public function setPartition(string $Partition): self + { + $this->Partition = $Partition; + return $this; + } + + public static function jsonUnserialize(\stdClass $decoded): self + { + $n = new self(); + foreach ((array)$decoded as $k => $v) { + if ('MaxTokenTTL' === $k) { + $n->setMaxTokenTTL($v); + } elseif ('NamespaceRules' === $k) { + $n->NamespaceRules = []; + foreach ($v as $vv) { + $n->NamespaceRules[] = ACLAuthMethodNamespaceRule::jsonUnserialize($vv); + } + } elseif ('Config' === $k) { + $n->setConfig($v); + } else { + $n->{$k} = $v; + } + } + return $n; + } + + public function jsonSerialize(): \stdClass + { + $out = $this->_startJsonSerialize(); + $out->Name = $this->Name; + if ('' !== $this->DisplayName) { + $out->DisplayName = $this->DisplayName; + } + if ('' !== $this->Description) { + $out->Description = $this->Description; + } + if (0 !== $this->MaxTokenTTL->Nanoseconds()) { + $out->MaxTokenTTL = (string)$this->MaxTokenTTL; + } + if ('' !== $this->TokenLocality) { + $out->TokenLocality = $this->TokenLocality; + } + $out->Config = $this->Config; + $out->CreateIndex = $this->CreateIndex; + $out->ModifyIndex = $this->ModifyIndex; + if ([] !== $this->NamespaceRules) { + $out->NamespaceRules = $this->NamespaceRules; + } + if ('' !== $this->Namespace) { + $out->Namespace = $this->Namespace; + } + if ('' !== $this->Partition) { + $out->Partition = $this->Partition; + } + return $out; + } } diff --git a/src/ACL/ACLAuthMethodListEntry.php b/src/ACL/ACLAuthMethodListEntry.php index 3a54d9f7..d0cc6670 100644 --- a/src/ACL/ACLAuthMethodListEntry.php +++ b/src/ACL/ACLAuthMethodListEntry.php @@ -21,43 +21,41 @@ */ use DCarbone\Go\Time; -use DCarbone\PHPConsulAPI\AbstractModel; -use DCarbone\PHPConsulAPI\Transcoding; +use DCarbone\PHPConsulAPI\PHPLib\AbstractType; -class ACLAuthMethodListEntry extends AbstractModel +class ACLAuthMethodListEntry extends AbstractType { - protected const FIELDS = [ - self::FIELD_DISPLAY_NAME => Transcoding::OMITEMPTY_STRING_FIELD, - self::FIELD_DESCRIPTION => Transcoding::OMITEMPTY_STRING_FIELD, - self::FIELD_MAX_TOKEN_TTL => [ - Transcoding::FIELD_MARSHAL_AS => Transcoding::STRING, - Transcoding::FIELD_OMITEMPTY => true, - Transcoding::FIELD_UNMARSHAL_CALLBACK => Transcoding::UNMARSHAL_DURATION, - ], - self::FIELD_TOKEN_LOCALITY => Transcoding::OMITEMPTY_STRING_FIELD, - self::FIELD_NAMESPACE => Transcoding::OMITEMPTY_STRING_FIELD, - ]; - - private const FIELD_DISPLAY_NAME = 'DisplayName'; - private const FIELD_DESCRIPTION = 'Description'; - private const FIELD_MAX_TOKEN_TTL = 'MaxTokenTTL'; - private const FIELD_TOKEN_LOCALITY = 'TokenLocality'; - private const FIELD_NAMESPACE = 'Namespace'; - - public string $Name = ''; - public string $Type = ''; - public string $DisplayName = ''; - public string $Description = ''; + public string $Name; + public string $Type; + public string $DisplayName; + public string $Description; public Time\Duration $MaxTokenTTL; - /** - * TokenLocality defines the kind of token that this auth method produces. - * This can be either 'local' or 'global'. If empty 'local' is assumed. - * @var string - */ public string $TokenLocality; - public int $CreateIndex = 0; - public int $ModifyIndex = 0; - public string $Namespace = ''; + public int $CreateIndex; + public int $ModifyIndex; + public string $Namespace; + + public function __construct( + string $Name = '', + string $Type = '', + string $DisplayName = '', + string $Description = '', + null|int|float|string|\DateInterval|Time\Duration $MaxTokenTTL = null, + string $TokenLocality = '', + int $CreateIndex = 0, + int $ModifyIndex = 0, + string $Namespace = '' + ) { + $this->Name = $Name; + $this->Type = $Type; + $this->DisplayName = $DisplayName; + $this->Description = $Description; + $this->setMaxTokenTTL($MaxTokenTTL); + $this->TokenLocality = $TokenLocality; + $this->CreateIndex = $CreateIndex; + $this->ModifyIndex = $ModifyIndex; + $this->Namespace = $Namespace; +} public function getName(): string { @@ -108,30 +106,17 @@ public function getMaxTokenTTL(): Time\Duration return $this->MaxTokenTTL; } - public function setMaxTokenTTL(Time\Duration $MaxTokenTTL): self + public function setMaxTokenTTL(null|int|float|string|\DateInterval|Time\Duration $MaxTokenTTL): self { - $this->MaxTokenTTL = $MaxTokenTTL; + $this->MaxTokenTTL = Time::Duration($MaxTokenTTL); return $this; } - /** - * TokenLocality defines the kind of token that this auth method produces. - * This can be either 'local' or 'global'. If empty 'local' is assumed. - * - * @return string - */ public function getTokenLocality(): string { return $this->TokenLocality; } - /** - * TokenLocality defines the kind of token that this auth method produces. - * This can be either 'local' or 'global'. If empty 'local' is assumed. - * - * @param string $TokenLocality - * @return \DCarbone\PHPConsulAPI\ACL\ACLAuthMethodListEntry - */ public function setTokenLocality(string $TokenLocality): self { $this->TokenLocality = $TokenLocality; @@ -171,13 +156,40 @@ public function setNamespace(string $Namespace): self return $this; } - public function jsonSerialize(): array + public static function jsonUnserialize(\stdClass $decoded): self { - $out = parent::jsonSerialize(); - if (!isset($this->MaxTokenTTL) || 0 === $this->MaxTokenTTL->Nanoseconds()) { - $out[self::FIELD_MAX_TOKEN_TTL] = ''; - } else { - $out[self::FIELD_MAX_TOKEN_TTL] = (string)$this->MaxTokenTTL; + $n = new self(); + foreach ((array)$decoded as $k => $v) { + if ('MaxTokenTTL' === $k) { + $n->setMaxTokenTTL($v); + } else { + $n->{$k} = $v; + } + } + return $n; + } + + public function jsonSerialize(): \stdClass + { + $out = $this->_startJsonSerialize(); + $out->Name = $this->Name; + $out->Type = $this->Type; + if ('' !== $this->DisplayName) { + $out->DisplayName = $this->DisplayName; + } + if ('' !== $this->Description) { + $out->Description = $this->Description; + } + if (0 !== $this->MaxTokenTTL->Nanoseconds()) { + $out->MaxTokenTTL = (string)$this->MaxTokenTTL; + } + if ('' !== $this->TokenLocality) { + $out->TokenLocality = $this->TokenLocality; + } + $out->CreateIndex = $this->CreateIndex; + $out->ModifyIndex = $this->ModifyIndex; + if ('' !== $this->Namespace) { + $out->Namespace = $this->Namespace; } return $out; } diff --git a/src/ACL/ACLAuthMethodListEntryQueryResponse.php b/src/ACL/ACLAuthMethodListEntryQueryResponse.php index 7233b6c2..deb6902b 100644 --- a/src/ACL/ACLAuthMethodListEntryQueryResponse.php +++ b/src/ACL/ACLAuthMethodListEntryQueryResponse.php @@ -20,23 +20,26 @@ limitations under the License. */ -use DCarbone\PHPConsulAPI\AbstractValuedQueryResponse; -use DCarbone\PHPConsulAPI\UnmarshalledResponseInterface; +use DCarbone\PHPConsulAPI\PHPLib\AbstractValuedQueryResponse; +use DCarbone\PHPConsulAPI\PHPLib\UnmarshalledResponseInterface; class ACLAuthMethodListEntryQueryResponse extends AbstractValuedQueryResponse implements UnmarshalledResponseInterface { - public ?array $ACLAuthMethodListEntries = []; + /** @var \DCarbone\PHPConsulAPI\ACL\ACLAuthMethodListEntry[] */ + public array $ACLAuthMethodListEntries = []; - public function getValue(): ?array + /** + * @return \DCarbone\PHPConsulAPI\ACL\ACLAuthMethodListEntry[] + */ + public function getValue(): array { return $this->ACLAuthMethodListEntries; } - public function unmarshalValue(mixed $decodedData): void + public function unmarshalValue(mixed $decoded): void { - $this->ACLAuthMethodListEntries = []; - foreach ($decodedData as $datum) { - $this->ACLAuthMethodListEntries[] = new ACLAuthMethodListEntry($datum); + foreach ($decoded as $datum) { + $this->ACLAuthMethodListEntries[] = ACLAuthMethodListEntry::jsonUnserialize($datum); } } } diff --git a/src/ACL/ACLAuthMethodNamespaceRule.php b/src/ACL/ACLAuthMethodNamespaceRule.php index c6b76694..e5172b98 100644 --- a/src/ACL/ACLAuthMethodNamespaceRule.php +++ b/src/ACL/ACLAuthMethodNamespaceRule.php @@ -20,21 +20,18 @@ limitations under the License. */ -use DCarbone\PHPConsulAPI\AbstractModel; -use DCarbone\PHPConsulAPI\Transcoding; +use DCarbone\PHPConsulAPI\PHPLib\AbstractType; -class ACLAuthMethodNamespaceRule extends AbstractModel +class ACLAuthMethodNamespaceRule extends AbstractType { - protected const FIELDS = [ - self::FIELD_SELECTOR => Transcoding::OMITEMPTY_STRING_FIELD, - self::FIELD_BIND_NAMESPACE => Transcoding::OMITEMPTY_STRING_FIELD, - ]; + public string $Selector; + public string $BindNamespace; - private const FIELD_SELECTOR = 'Selector'; - private const FIELD_BIND_NAMESPACE = 'BindNamespace'; - - public string $Selector = ''; - public string $BindNamespace = ''; + public function __construct(string $Selector = '', string $BindNamespace = '') + { + $this->Selector = $Selector; + $this->BindNamespace = $BindNamespace; + } public function getSelector(): string { @@ -57,4 +54,25 @@ public function setBindNamespace(string $BindNamespace): self $this->BindNamespace = $BindNamespace; return $this; } + + public static function jsonUnserialize(\stdClass $decoded): self + { + $n = new self(); + foreach ((array)$decoded as $k => $v) { + $n->{$k} = $v; + } + return $n; + } + + public function jsonSerialize(): \stdClass + { + $out = $this->_startJsonSerialize(); + if ('' !== $this->Selector) { + $out->Selector = $this->Selector; + } + if ('' !== $this->BindNamespace) { + $out->BindNamespace = $this->BindNamespace; + } + return $out; + } } diff --git a/src/ACL/ACLAuthMethodQueryResponse.php b/src/ACL/ACLAuthMethodQueryResponse.php index a3a26039..265d0716 100644 --- a/src/ACL/ACLAuthMethodQueryResponse.php +++ b/src/ACL/ACLAuthMethodQueryResponse.php @@ -20,20 +20,24 @@ limitations under the License. */ -use DCarbone\PHPConsulAPI\AbstractValuedQueryResponse; -use DCarbone\PHPConsulAPI\UnmarshalledResponseInterface; +use DCarbone\PHPConsulAPI\PHPLib\AbstractValuedQueryResponse; +use DCarbone\PHPConsulAPI\PHPLib\UnmarshalledResponseInterface; class ACLAuthMethodQueryResponse extends AbstractValuedQueryResponse implements UnmarshalledResponseInterface { - public ?ACLAuthMethod $ACLAuthMethod = null; + public null|ACLAuthMethod $ACLAuthMethod = null; - public function getValue(): ?ACLAuthMethod + public function getValue(): null|ACLAuthMethod { return $this->ACLAuthMethod; } - public function unmarshalValue(mixed $decodedData): void + public function unmarshalValue(mixed $decoded): void { - $this->ACLAuthMethod = new ACLAuthMethod((array)$decodedData); + if (null === $decoded) { + $this->ACLAuthMethod = null; + return; + } + $this->ACLAuthMethod = $this->ACLAuthMethod::jsonUnserialize($decoded); } } diff --git a/src/ACL/ACLAuthMethodWriteResponse.php b/src/ACL/ACLAuthMethodWriteResponse.php index 0a609b71..0f9ad031 100644 --- a/src/ACL/ACLAuthMethodWriteResponse.php +++ b/src/ACL/ACLAuthMethodWriteResponse.php @@ -20,20 +20,24 @@ limitations under the License. */ -use DCarbone\PHPConsulAPI\AbstractValuedWriteResponse; -use DCarbone\PHPConsulAPI\UnmarshalledResponseInterface; +use DCarbone\PHPConsulAPI\PHPLib\AbstractValuedWriteResponse; +use DCarbone\PHPConsulAPI\PHPLib\UnmarshalledResponseInterface; class ACLAuthMethodWriteResponse extends AbstractValuedWriteResponse implements UnmarshalledResponseInterface { - public ?ACLAuthMethod $ACLAuthMethod = null; + public null|ACLAuthMethod $ACLAuthMethod = null; - public function getValue(): ?ACLAuthMethod + public function getValue(): null|ACLAuthMethod { return $this->ACLAuthMethod; } - public function unmarshalValue(mixed $decodedData): void + public function unmarshalValue(mixed $decoded): void { - $this->ACLAuthMethod = new ACLAuthMethod((array)$decodedData); + if (null === $decoded) { + $this->ACLAuthMethod = null; + return; + } + $this->ACLAuthMethod = ACLAuthMethod::jsonUnserialize($decoded); } } diff --git a/src/ACL/ACLBindingRule.php b/src/ACL/ACLBindingRule.php index 0a359399..2eb4cc88 100644 --- a/src/ACL/ACLBindingRule.php +++ b/src/ACL/ACLBindingRule.php @@ -20,26 +20,41 @@ limitations under the License. */ -use DCarbone\PHPConsulAPI\AbstractModel; -use DCarbone\PHPConsulAPI\Transcoding; +use DCarbone\PHPConsulAPI\PHPLib\AbstractType; -class ACLBindingRule extends AbstractModel +class ACLBindingRule extends AbstractType { - protected const FIELDS = [ - self::FIELD_NAMESPACE => Transcoding::OMITEMPTY_STRING_FIELD, - ]; - - private const FIELD_NAMESPACE = 'Namespace'; - - public string $ID = ''; - public string $Description = ''; - public string $AuthMethod = ''; - public string $Selector = ''; - public string $BindType = ''; - public string $BindName = ''; - public int $CreateIndex = 0; - public int $ModifyIndex = 0; - public string $Namespace = ''; + public string $ID; + public string $Description; + public string $AuthMethod; + public string $Selector; + public BindingRuleBindType $BindType; + public string $BindName; + public int $CreateIndex; + public int $ModifyIndex; + public string $Namespace; + + public function __construct( + string $ID = '', + string $Description = '', + string $AuthMethod = '', + string $Selector = '', + string|BindingRuleBindType $BindType = BindingRuleBindType::UNDEFINED, + string $BindName = '', + int $CreateIndex = 0, + int $ModifyIndex = 0, + string $Namespace = '' + ) { + $this->ID = $ID; + $this->Description = $Description; + $this->AuthMethod = $AuthMethod; + $this->Selector = $Selector; + $this->BindType = ($BindType instanceof BindingRuleBindType) ? $BindType : BindingRuleBindType::from($BindType); + $this->BindName = $BindName; + $this->CreateIndex = $CreateIndex; + $this->ModifyIndex = $ModifyIndex; + $this->Namespace = $Namespace; +} public function getID(): string { @@ -85,14 +100,14 @@ public function setSelector(string $Selector): self return $this; } - public function getBindType(): string + public function getBindType(): BindingRuleBindType { return $this->BindType; } - public function setBindType(string $BindType): self + public function setBindType(string|BindingRuleBindType $BindType): self { - $this->BindType = $BindType; + $this->BindType = ($BindType instanceof BindingRuleBindType) ? $BindType : BindingRuleBindType::from($BindType); return $this; } @@ -139,4 +154,30 @@ public function setNamespace(string $Namespace): self $this->Namespace = $Namespace; return $this; } + + public static function jsonUnserialize(\stdClass $decoded): self + { + $n = new self(); + foreach ((array)$decoded as $k => $v) { + $n->{$k} = $v; + } + return $n; + } + + public function jsonSerialize(): \stdClass + { + $out = $this->_startJsonSerialize(); + $out->ID = $this->ID; + $out->Description = $this->Description; + $out->AuthMethod = $this->AuthMethod; + $out->Selector = $this->Selector; + $out->BindType = $this->BindType; + $out->BindName = $this->BindName; + $out->CreateIndex = $this->CreateIndex; + $out->ModifyIndex = $this->ModifyIndex; + if ('' !== $this->Namespace) { + $out->Namespace = $this->Namespace; + } + return $out; + } } diff --git a/src/ACL/ACLBindingRuleQueryResponse.php b/src/ACL/ACLBindingRuleQueryResponse.php index ee85a37d..7259cbb6 100644 --- a/src/ACL/ACLBindingRuleQueryResponse.php +++ b/src/ACL/ACLBindingRuleQueryResponse.php @@ -20,20 +20,24 @@ limitations under the License. */ -use DCarbone\PHPConsulAPI\AbstractValuedQueryResponse; -use DCarbone\PHPConsulAPI\UnmarshalledResponseInterface; +use DCarbone\PHPConsulAPI\PHPLib\AbstractValuedQueryResponse; +use DCarbone\PHPConsulAPI\PHPLib\UnmarshalledResponseInterface; class ACLBindingRuleQueryResponse extends AbstractValuedQueryResponse implements UnmarshalledResponseInterface { - public ?ACLBindingRule $ACLBindingRule = null; + public null|ACLBindingRule $ACLBindingRule = null; - public function getValue(): ?ACLBindingRule + public function getValue(): null|ACLBindingRule { return $this->ACLBindingRule; } - public function unmarshalValue(mixed $decodedData): void + public function unmarshalValue(mixed $decoded): void { - $this->ACLBindingRule = new ACLBindingRule((array)$decodedData); + if (null === $decoded) { + $this->ACLBindingRule = null; + return; + } + $this->ACLBindingRule = ACLBindingRule::jsonUnserialize($decoded); } } diff --git a/src/ACL/ACLBindingRuleWriteResponse.php b/src/ACL/ACLBindingRuleWriteResponse.php index c1ba51c1..b636850c 100644 --- a/src/ACL/ACLBindingRuleWriteResponse.php +++ b/src/ACL/ACLBindingRuleWriteResponse.php @@ -20,20 +20,24 @@ limitations under the License. */ -use DCarbone\PHPConsulAPI\AbstractValuedWriteResponse; -use DCarbone\PHPConsulAPI\UnmarshalledResponseInterface; +use DCarbone\PHPConsulAPI\PHPLib\AbstractValuedWriteResponse; +use DCarbone\PHPConsulAPI\PHPLib\UnmarshalledResponseInterface; class ACLBindingRuleWriteResponse extends AbstractValuedWriteResponse implements UnmarshalledResponseInterface { - public ?ACLBindingRule $ACLBindingRule = null; + public null|ACLBindingRule $ACLBindingRule = null; - public function getValue(): ?ACLBindingRule + public function getValue(): null|ACLBindingRule { return $this->ACLBindingRule; } - public function unmarshalValue(mixed $decodedData): void + public function unmarshalValue(mixed $decoded): void { - $this->ACLBindingRule = new ACLBindingRule((array)$decodedData); + if (null === $decoded) { + $this->ACLBindingRule = null; + return; + } + $this->ACLBindingRule = ACLBindingRule::jsonUnserialize($decoded); } } diff --git a/src/ACL/ACLBindingRulesQueryResponse.php b/src/ACL/ACLBindingRulesQueryResponse.php index 59d77a58..f8480204 100644 --- a/src/ACL/ACLBindingRulesQueryResponse.php +++ b/src/ACL/ACLBindingRulesQueryResponse.php @@ -20,23 +20,27 @@ limitations under the License. */ -use DCarbone\PHPConsulAPI\AbstractValuedQueryResponse; -use DCarbone\PHPConsulAPI\UnmarshalledResponseInterface; +use DCarbone\PHPConsulAPI\PHPLib\AbstractValuedQueryResponse; +use DCarbone\PHPConsulAPI\PHPLib\UnmarshalledResponseInterface; class ACLBindingRulesQueryResponse extends AbstractValuedQueryResponse implements UnmarshalledResponseInterface { - public ?array $ACLBindingRules = []; + /** @var \DCarbone\PHPConsulAPI\ACL\ACLBindingRule[] */ + public array $ACLBindingRules = []; - public function getValue(): ?array + /** + * @return \DCarbone\PHPConsulAPI\ACL\ACLBindingRule[] + */ + public function getValue(): array { return $this->ACLBindingRules; } - public function unmarshalValue(mixed $decodedData): void + public function unmarshalValue(mixed $decoded): void { $this->ACLBindingRules = []; - foreach ($decodedData as $datum) { - $this->ACLBindingRules[] = new ACLBindingRule($datum); + foreach ($decoded as $datum) { + $this->ACLBindingRules[] = ACLBindingRule::jsonUnserialize($datum); } } } diff --git a/src/ACL/ACLClient.php b/src/ACL/ACLClient.php index 79e3daa0..781573cb 100644 --- a/src/ACL/ACLClient.php +++ b/src/ACL/ACLClient.php @@ -20,12 +20,12 @@ limitations under the License. */ -use DCarbone\PHPConsulAPI\AbstractClient; -use DCarbone\PHPConsulAPI\Error; +use DCarbone\PHPConsulAPI\PHPLib\AbstractClient; +use DCarbone\PHPConsulAPI\PHPLib\Error; +use DCarbone\PHPConsulAPI\PHPLib\ValuedWriteStringResponse; +use DCarbone\PHPConsulAPI\PHPLib\WriteResponse; use DCarbone\PHPConsulAPI\QueryOptions; -use DCarbone\PHPConsulAPI\ValuedWriteStringResponse; use DCarbone\PHPConsulAPI\WriteOptions; -use DCarbone\PHPConsulAPI\WriteResponse; class ACLClient extends AbstractClient { @@ -34,27 +34,27 @@ public function Bootstrap(): ValuedWriteStringResponse return $this->_executePutValuedStr('v1/acl/bootstrap', null, null); } - public function Create(ACLEntry $acl, ?WriteOptions $opts = null): ValuedWriteStringResponse + public function Create(ACLEntry $acl, null|WriteOptions $opts = null): ValuedWriteStringResponse { return $this->_executePutValuedStr('v1/acl/create', $acl, $opts); } - public function Update(ACLEntry $acl, ?WriteOptions $opts = null): WriteResponse + public function Update(ACLEntry $acl, null|WriteOptions $opts = null): WriteResponse { return $this->_executePut('v1/acl/update', $acl, $opts); } - public function Destroy(string $id, ?WriteOptions $opts = null): WriteResponse + public function Destroy(string $id, null|WriteOptions $opts = null): WriteResponse { return $this->_executePut(sprintf('v1/acl/destroy/%s', $id), null, $opts); } - public function Clone(string $id, ?WriteOptions $opts = null): ValuedWriteStringResponse + public function Clone(string $id, null|WriteOptions $opts = null): ValuedWriteStringResponse { return $this->_executePutValuedStr(sprintf('v1/acl/clone/%s', $id), null, $opts); } - public function Info(string $id, ?QueryOptions $opts = null): ACLEntriesResponse + public function Info(string $id, null|QueryOptions $opts = null): ACLEntriesResponse { $resp = $this->_requireOK($this->_doGet(sprintf('v1/acl/info/%s', $id), $opts)); $ret = new ACLEntriesResponse(); @@ -62,7 +62,7 @@ public function Info(string $id, ?QueryOptions $opts = null): ACLEntriesResponse return $ret; } - public function List(?QueryOptions $opts = null): ACLEntriesResponse + public function List(null|QueryOptions $opts = null): ACLEntriesResponse { $resp = $this->_requireOK($this->_doGet('v1/acl/list', $opts)); $ret = new ACLEntriesResponse(); @@ -70,7 +70,7 @@ public function List(?QueryOptions $opts = null): ACLEntriesResponse return $ret; } - public function Replication(?QueryOptions $opts = null): ACLReplicationStatusResponse + public function Replication(null|QueryOptions $opts = null): ACLReplicationStatusResponse { $resp = $this->_requireOK($this->_doGet('/v1/acl/replication', $opts)); $ret = new ACLReplicationStatusResponse(); @@ -78,7 +78,7 @@ public function Replication(?QueryOptions $opts = null): ACLReplicationStatusRes return $ret; } - public function TokenCreate(ACLToken $token, ?WriteOptions $opts = null): ACLTokenWriteResponse + public function TokenCreate(ACLToken $token, null|WriteOptions $opts = null): ACLTokenWriteResponse { $resp = $this->_requireOK($this->_doPut('/v1/acl/token', $token, $opts)); $ret = new ACLTokenWriteResponse(); @@ -86,7 +86,7 @@ public function TokenCreate(ACLToken $token, ?WriteOptions $opts = null): ACLTok return $ret; } - public function TokenUpdate(ACLToken $token, ?WriteOptions $opts = null): ACLTokenWriteResponse + public function TokenUpdate(ACLToken $token, null|WriteOptions $opts = null): ACLTokenWriteResponse { $ret = new ACLTokenWriteResponse(); if ('' === $token->AccessorID) { @@ -98,34 +98,44 @@ public function TokenUpdate(ACLToken $token, ?WriteOptions $opts = null): ACLTok return $ret; } - public function TokenClone(string $tokenID, string $description, ?WriteOptions $opts = null): ACLTokenWriteResponse + public function TokenClone(string $accessorID, string $description, null|WriteOptions $opts = null): ACLTokenWriteResponse { $ret = new ACLTokenWriteResponse(); - if ('' === $tokenID) { + if ('' === $accessorID) { $ret->Err = new Error('must specify tokenID for Token Cloning'); return $ret; } $resp = $this->_requireOK( - $this->_doPut(sprintf('/v1/acl/token/%s/clone', $tokenID), ['description' => $description], $opts) + $this->_doPut(sprintf('/v1/acl/token/%s/clone', $accessorID), ['description' => $description], $opts) ); $this->_unmarshalResponse($resp, $ret); return $ret; } - public function TokenDelete(string $tokenID, ?WriteOptions $opts = null): WriteResponse + public function TokenDelete(string $accessorID, null|WriteOptions $opts = null): WriteResponse { - return $this->_executeDelete(sprintf('/v1/acl/token/%s', $tokenID), $opts); + return $this->_executeDelete(sprintf('/v1/acl/token/%s', $accessorID), $opts); } - public function TokenRead(string $tokenID, ?QueryOptions $opts = null): ACLTokenQueryResponse + public function TokenRead(string $accessorID, null|QueryOptions $opts = null): ACLTokenQueryResponse { - $resp = $this->_requireOK($this->_doGet(sprintf('/v1/acl/token/%s', $tokenID), $opts)); + $resp = $this->_requireOK($this->_doGet(sprintf('/v1/acl/token/%s', $accessorID), $opts)); $ret = new ACLTokenQueryResponse(); $this->_unmarshalResponse($resp, $ret); return $ret; } - public function TokenReadSelf(?QueryOptions $opts = null): ACLTokenQueryResponse + public function TokenReadExpanded(string $accessorID, null|QueryOptions $opts = null): ACLTokenExpandedQueryResponse + { + $req = $this->_newGetRequest(sprintf('/v1/acl/token/%s', $accessorID), $opts); + $req->params->set('expanded', 'true'); + $resp = $this->_requireOK($this->_do($req)); + $ret = new ACLTokenExpandedQueryResponse(); + $this->_unmarshalResponse($resp, $ret); + return $ret; + } + + public function TokenReadSelf(null|QueryOptions $opts = null): ACLTokenQueryResponse { $resp = $this->_requireOK($this->_doGet('/v1/acl/token/self', $opts)); $ret = new ACLTokenQueryResponse(); @@ -133,7 +143,7 @@ public function TokenReadSelf(?QueryOptions $opts = null): ACLTokenQueryResponse return $ret; } - public function TokenList(?QueryOptions $opts = null): ACLTokenListEntryQueryResponse + public function TokenList(null|QueryOptions $opts = null): ACLTokenListEntryQueryResponse { $resp = $this->_requireOK($this->_doGet('/v1/acl/tokens', $opts)); $ret = new ACLTokenListEntryQueryResponse(); @@ -141,7 +151,7 @@ public function TokenList(?QueryOptions $opts = null): ACLTokenListEntryQueryRes return $ret; } - public function PolicyCreate(ACLPolicy $policy, ?WriteOptions $opts = null): ACLPolicyWriteResponse + public function PolicyCreate(ACLPolicy $policy, null|WriteOptions $opts = null): ACLPolicyWriteResponse { $ret = new ACLPolicyWriteResponse(); if ('' !== $policy->ID) { @@ -153,7 +163,7 @@ public function PolicyCreate(ACLPolicy $policy, ?WriteOptions $opts = null): ACL return $ret; } - public function PolicyUpdate(ACLPolicy $policy, ?WriteOptions $opts = null): ACLPolicyWriteResponse + public function PolicyUpdate(ACLPolicy $policy, null|WriteOptions $opts = null): ACLPolicyWriteResponse { $ret = new ACLPolicyWriteResponse(); if ('' === $policy->ID) { @@ -165,12 +175,12 @@ public function PolicyUpdate(ACLPolicy $policy, ?WriteOptions $opts = null): ACL return $ret; } - public function PolicyDelete(string $policyID, ?WriteOptions $opts = null): WriteResponse + public function PolicyDelete(string $policyID, null|WriteOptions $opts = null): WriteResponse { return $this->_executeDelete(sprintf('/v1/acl/policy/%s', $policyID), $opts); } - public function PolicyRead(string $policyID, ?QueryOptions $opts = null): ACLPolicyQueryResponse + public function PolicyRead(string $policyID, null|QueryOptions $opts = null): ACLPolicyQueryResponse { $resp = $this->_requireOK($this->_doGet(sprintf('/v1/acl/policy/%s', $policyID), $opts)); $ret = new ACLPolicyQueryResponse(); @@ -178,7 +188,7 @@ public function PolicyRead(string $policyID, ?QueryOptions $opts = null): ACLPol return $ret; } - public function PolicyReadByName(string $policyName, ?QueryOptions $opts = null): ACLPolicyQueryResponse + public function PolicyReadByName(string $policyName, null|QueryOptions $opts = null): ACLPolicyQueryResponse { $resp = $this->_requireOK($this->_doGet(sprintf('/v1/acl/policy/name/%s', $policyName), $opts)); $ret = new ACLPolicyQueryResponse(); @@ -186,7 +196,7 @@ public function PolicyReadByName(string $policyName, ?QueryOptions $opts = null) return $ret; } - public function PolicyList(?QueryOptions $opts = null): ACLPolicyListEntryQueryResponse + public function PolicyList(null|QueryOptions $opts = null): ACLPolicyListEntryQueryResponse { $resp = $this->_requireOK($this->_doGet('/v1/acl/policies', $opts)); $ret = new ACLPolicyListEntryQueryResponse(); @@ -194,7 +204,7 @@ public function PolicyList(?QueryOptions $opts = null): ACLPolicyListEntryQueryR return $ret; } - public function RoleCreate(ACLRole $role, ?WriteOptions $opts = null): ACLRoleWriteResponse + public function RoleCreate(ACLRole $role, null|WriteOptions $opts = null): ACLRoleWriteResponse { $ret = new ACLRoleWriteResponse(); if ('' !== $role->ID) { @@ -206,7 +216,7 @@ public function RoleCreate(ACLRole $role, ?WriteOptions $opts = null): ACLRoleWr return $ret; } - public function RoleUpdate(ACLRole $role, ?WriteOptions $opts = null): ACLRoleWriteResponse + public function RoleUpdate(ACLRole $role, null|WriteOptions $opts = null): ACLRoleWriteResponse { $ret = new ACLRoleWriteResponse(); if ('' === $role->ID) { @@ -218,12 +228,12 @@ public function RoleUpdate(ACLRole $role, ?WriteOptions $opts = null): ACLRoleWr return $ret; } - public function RoleDelete(string $roleID, ?WriteOptions $opts = null): WriteResponse + public function RoleDelete(string $roleID, null|WriteOptions $opts = null): WriteResponse { return $this->_executeDelete(sprintf('/v1/acl/role/%s', $roleID), $opts); } - public function RoleRead(string $roleID, ?QueryOptions $opts = null): ACLRoleQueryResponse + public function RoleRead(string $roleID, null|QueryOptions $opts = null): ACLRoleQueryResponse { $resp = $this->_requireNotFoundOrOK($this->_doGet(sprintf('/v1/acl/role/%s', $roleID), $opts)); $ret = new ACLRoleQueryResponse(); @@ -231,7 +241,7 @@ public function RoleRead(string $roleID, ?QueryOptions $opts = null): ACLRoleQue return $ret; } - public function RoleReadByName(string $roleName, ?QueryOptions $opts = null): ACLRoleQueryResponse + public function RoleReadByName(string $roleName, null|QueryOptions $opts = null): ACLRoleQueryResponse { $resp = $this->_requireOK($this->_doGet(sprintf('/v1/acl/role/name/%s', $roleName), $opts)); $ret = new ACLRoleQueryResponse(); @@ -239,7 +249,7 @@ public function RoleReadByName(string $roleName, ?QueryOptions $opts = null): AC return $ret; } - public function RoleList(?QueryOptions $opts = null): ACLRolesQueryResponse + public function RoleList(null|QueryOptions $opts = null): ACLRolesQueryResponse { $resp = $this->_requireOK($this->_doGet('/v1/acl/roles', $opts)); $ret = new ACLRolesQueryResponse(); @@ -247,7 +257,7 @@ public function RoleList(?QueryOptions $opts = null): ACLRolesQueryResponse return $ret; } - public function AuthMethodCreate(ACLAuthMethod $authMethod, ?WriteOptions $opts = null): ACLAuthMethodWriteResponse + public function AuthMethodCreate(ACLAuthMethod $authMethod, null|WriteOptions $opts = null): ACLAuthMethodWriteResponse { $ret = new ACLAuthMethodWriteResponse(); if ('' !== $authMethod->Name) { @@ -259,24 +269,24 @@ public function AuthMethodCreate(ACLAuthMethod $authMethod, ?WriteOptions $opts return $ret; } - public function AuthMethodUpdate(ACLAuthMethod $authMethod, ?WriteOptions $opts = null): ACLAuthMethodWriteResponse + public function AuthMethodUpdate(ACLAuthMethod $authMethod, null|WriteOptions $opts = null): ACLAuthMethodWriteResponse { $ret = new ACLAuthMethodWriteResponse(); - if ('' === $authMethod->ID) { - $ret->Err = new Error('must specify an ID in AuthMethod Update'); + if ('' === $authMethod->Name) { + $ret->Err = new Error('must specify an Name in AuthMethod Update'); return $ret; } - $resp = $this->_requireOK($this->_doPut(sprintf('/v1/acl/auth-method/%s', $authMethod->ID), $authMethod, $opts)); + $resp = $this->_requireOK($this->_doPut(sprintf('/v1/acl/auth-method/%s', $authMethod->Name), $authMethod, $opts)); $this->_unmarshalResponse($resp, $ret); return $ret; } - public function AuthMethodDelete(string $authMethodID, ?WriteOptions $opts = null): WriteResponse + public function AuthMethodDelete(string $authMethodID, null|WriteOptions $opts = null): WriteResponse { return $this->_executeDelete(sprintf('/v1/acl/authMethod/%s', $authMethodID), $opts); } - public function AuthMethodRead(string $authMethodID, ?QueryOptions $opts = null): ACLAuthMethodQueryResponse + public function AuthMethodRead(string $authMethodID, null|QueryOptions $opts = null): ACLAuthMethodQueryResponse { $resp = $this->_requireNotFoundOrOK($this->_doGet(sprintf('/v1/acl/authMethod/%s', $authMethodID), $opts)); $ret = new ACLAuthMethodQueryResponse(); @@ -284,7 +294,7 @@ public function AuthMethodRead(string $authMethodID, ?QueryOptions $opts = null) return $ret; } - public function AuthMethodList(?QueryOptions $opts = null): ACLAuthMethodListEntryQueryResponse + public function AuthMethodList(null|QueryOptions $opts = null): ACLAuthMethodListEntryQueryResponse { $resp = $this->_requireOK($this->_doGet('/v1/acl/auth-methods', $opts)); $ret = new ACLAuthMethodListEntryQueryResponse(); @@ -292,10 +302,8 @@ public function AuthMethodList(?QueryOptions $opts = null): ACLAuthMethodListEnt return $ret; } - public function BindingRuleCreate( - ACLBindingRule $bindingRule, - ?WriteOptions $opts = null - ): ACLBindingRuleWriteResponse { + public function BindingRuleCreate(ACLBindingRule $bindingRule, null|WriteOptions $opts = null): ACLBindingRuleWriteResponse + { $ret = new ACLBindingRuleWriteResponse(); if ('' !== $bindingRule->ID) { $ret->Err = new Error('cannot specify an id in BindingRule Create'); @@ -306,10 +314,8 @@ public function BindingRuleCreate( return $ret; } - public function BindingRuleUpdate( - ACLBindingRule $bindingRule, - ?WriteOptions $opts = null - ): ACLBindingRuleWriteResponse { + public function BindingRuleUpdate(ACLBindingRule $bindingRule, null|WriteOptions $opts = null): ACLBindingRuleWriteResponse + { $ret = new ACLBindingRuleWriteResponse(); if ('' === $bindingRule->ID) { $ret->Err = new Error('must specify an ID in BindingRule Update'); @@ -320,12 +326,12 @@ public function BindingRuleUpdate( return $ret; } - public function BindingRuleDelete(string $bindingRuleID, ?WriteOptions $opts = null): WriteResponse + public function BindingRuleDelete(string $bindingRuleID, null|WriteOptions $opts = null): WriteResponse { return $this->_executeDelete(sprintf('/v1/acl/binding-rule/%s', $bindingRuleID), $opts); } - public function BindingRuleRead(string $bindingRuleID, ?QueryOptions $opts = null): ACLBindingRuleQueryResponse + public function BindingRuleRead(string $bindingRuleID, null|QueryOptions $opts = null): ACLBindingRuleQueryResponse { $resp = $this->_requireNotFoundOrOK($this->_doGet(sprintf('/v1/acl/binding-rule/%s', $bindingRuleID), $opts)); $ret = new ACLBindingRuleQueryResponse(); @@ -333,7 +339,7 @@ public function BindingRuleRead(string $bindingRuleID, ?QueryOptions $opts = nul return $ret; } - public function BindingRuleList(?QueryOptions $opts = null): ACLBindingRulesQueryResponse + public function BindingRuleList(null|QueryOptions $opts = null): ACLBindingRulesQueryResponse { $resp = $this->_requireOK($this->_doGet('/v1/acl/binding-rules', $opts)); $ret = new ACLBindingRulesQueryResponse(); @@ -341,7 +347,7 @@ public function BindingRuleList(?QueryOptions $opts = null): ACLBindingRulesQuer return $ret; } - public function Login(ACLLoginParams $login, ?WriteOptions $opts = null): ACLTokenWriteResponse + public function Login(ACLLoginParams $login, null|WriteOptions $opts = null): ACLTokenWriteResponse { $resp = $this->_requireOK($this->_doPost('/v1/acl/login', $login, $opts)); $ret = new ACLTokenWriteResponse(); @@ -349,12 +355,12 @@ public function Login(ACLLoginParams $login, ?WriteOptions $opts = null): ACLTok return $ret; } - public function Logout(?WriteOptions $opts = null): WriteResponse + public function Logout(null|WriteOptions $opts = null): WriteResponse { return $this->_executePost('/v1/acl/logout', null, $opts); } - public function OIDCAuthURL(ACLOIDCAuthURLParams $auth, ?WriteOptions $opts = null): ValuedWriteStringResponse + public function OIDCAuthURL(ACLOIDCAuthURLParams $auth, null|WriteOptions $opts = null): ValuedWriteStringResponse { $ret = new ValuedWriteStringResponse(); if ('' === $auth->AuthMethod) { @@ -366,7 +372,7 @@ public function OIDCAuthURL(ACLOIDCAuthURLParams $auth, ?WriteOptions $opts = nu return $ret; } - public function OIDCCallback(ACLOIDCCallbackParams $auth, ?WriteOptions $opts = null): ACLTokenWriteResponse + public function OIDCCallback(ACLOIDCCallbackParams $auth, null|WriteOptions $opts = null): ACLTokenWriteResponse { $ret = new ACLTokenWriteResponse(); if ('' === $auth->AuthMethod) { diff --git a/src/ACL/ACLEntriesResponse.php b/src/ACL/ACLEntriesResponse.php index f9c4af8f..a686d375 100644 --- a/src/ACL/ACLEntriesResponse.php +++ b/src/ACL/ACLEntriesResponse.php @@ -20,22 +20,27 @@ limitations under the License. */ -use DCarbone\PHPConsulAPI\AbstractValuedQueryResponse; -use DCarbone\PHPConsulAPI\UnmarshalledResponseInterface; +use DCarbone\PHPConsulAPI\PHPLib\AbstractValuedQueryResponse; +use DCarbone\PHPConsulAPI\PHPLib\UnmarshalledResponseInterface; class ACLEntriesResponse extends AbstractValuedQueryResponse implements UnmarshalledResponseInterface { + /** @var \DCarbone\PHPConsulAPI\ACL\ACLEntry[] */ public array $ACLEntries = []; - public function getValue(): ?array + /** + * @return \DCarbone\PHPConsulAPI\ACL\ACLEntry[] + */ + public function getValue(): array { return $this->ACLEntries; } - public function unmarshalValue(mixed $decodedData): void + public function unmarshalValue(mixed $decoded): void { - foreach ($decodedData as $entry) { - $this->ACLEntries[] = new ACLEntry($entry); + $this->ACLEntries = []; + foreach ($decoded as $entry) { + $this->ACLEntries[] = ACLEntry::jsonUnserialize($entry); } } } diff --git a/src/ACL/ACLEntry.php b/src/ACL/ACLEntry.php index 4bc149f5..c90a7952 100644 --- a/src/ACL/ACLEntry.php +++ b/src/ACL/ACLEntry.php @@ -20,25 +20,41 @@ limitations under the License. */ -use DCarbone\PHPConsulAPI\AbstractModel; +use DCarbone\PHPConsulAPI\PHPLib\AbstractType; -class ACLEntry extends AbstractModel +class ACLEntry extends AbstractType { - public int $CreateIndex = 0; - public int $ModifyIndex = 0; - public string $ID = ''; - public string $Name = ''; - public string $Type = ''; - public string $Rules = ''; + public int $CreateIndex; + public int $ModifyIndex; + public string $ID; + public string $Name; + public string $Type; + public string $Rules; + + public function __construct( + int $CreateIndex = 0, + int $ModifyIndex = 0, + string $ID = '', + string $Name = '', + string $Type = '', + string $Rules = '', + ) { + $this->CreateIndex = $CreateIndex; + $this->ModifyIndex = $ModifyIndex; + $this->ID = $ID; + $this->Name = $Name; + $this->Type = $Type; + $this->Rules = $Rules; + } public function getCreateIndex(): int { return $this->CreateIndex; } - public function setCreateIndex(int $createIndex): self + public function setCreateIndex(int $CreateIndex): self { - $this->CreateIndex = $createIndex; + $this->CreateIndex = $CreateIndex; return $this; } @@ -47,9 +63,9 @@ public function getModifyIndex(): int return $this->ModifyIndex; } - public function setModifyIndex(int $modifyIndex): self + public function setModifyIndex(int $ModifyIndex): self { - $this->ModifyIndex = $modifyIndex; + $this->ModifyIndex = $ModifyIndex; return $this; } @@ -58,9 +74,9 @@ public function getID(): string return $this->ID; } - public function setID(string $id): self + public function setID(string $ID): self { - $this->ID = $id; + $this->ID = $ID; return $this; } @@ -69,9 +85,9 @@ public function getName(): string return $this->Name; } - public function setName(string $name): self + public function setName(string $Name): self { - $this->Name = $name; + $this->Name = $Name; return $this; } @@ -80,9 +96,9 @@ public function getType(): string return $this->Type; } - public function setType(string $type): self + public function setType(string $Type): self { - $this->Type = $type; + $this->Type = $Type; return $this; } @@ -91,9 +107,30 @@ public function getRules(): string return $this->Rules; } - public function setRules(string $rules): self + public function setRules(string $Rules): self { - $this->Rules = $rules; + $this->Rules = $Rules; return $this; } + + public static function jsonUnserialize(\stdClass $decoded): self + { + $n = new self(); + foreach ((array)$decoded as $k => $v) { + $n->{$k} = $v; + } + return $n; + } + + public function jsonSerialize(): \stdClass + { + $out = $this->_startJsonSerialize(); + $out->CreateIndex = $this->CreateIndex; + $out->ModifyIndex = $this->ModifyIndex; + $out->ID = $this->ID; + $out->Name = $this->Name; + $out->Type = $this->Type; + $out->Rules = $this->Rules; + return $out; + } } diff --git a/src/ACL/ACLLink.php b/src/ACL/ACLLink.php index 905e0a98..803ba203 100644 --- a/src/ACL/ACLLink.php +++ b/src/ACL/ACLLink.php @@ -20,20 +20,55 @@ limitations under the License. */ -use DCarbone\PHPConsulAPI\AbstractModel; +use DCarbone\PHPConsulAPI\PHPLib\AbstractType; -class ACLLink extends AbstractModel +class ACLLink extends AbstractType { - public string $ID = ''; - public string $Name = ''; + public string $ID; + public string $Name; + + public function __construct(string $ID = '', string $Name = '') + { + $this->ID = $ID; + $this->Name = $Name; + } public function getID(): string { return $this->ID; } + public function setID(string $ID): self + { + $this->ID = $ID; + return $this; + } + public function getName(): string { return $this->Name; } + + public function setName(string $Name): self + { + $this->Name = $Name; + return $this; + } + + public static function jsonUnserialize(\stdClass $decoded): self + { + $n = new self(); + foreach ((array)$decoded as $k => $v) { + $n->{$k} = $v; + } + return $n; + } + + public function jsonSerialize(): \stdClass + { + $out = $this->_startJsonSerialize(); + $out->ID = $this->ID; + $out->Name = $this->Name; + return $out; + } } diff --git a/src/ACL/ACLLoginParams.php b/src/ACL/ACLLoginParams.php index 19ce55aa..c546f1ba 100644 --- a/src/ACL/ACLLoginParams.php +++ b/src/ACL/ACLLoginParams.php @@ -20,21 +20,28 @@ limitations under the License. */ -use DCarbone\PHPConsulAPI\AbstractModel; -use DCarbone\PHPConsulAPI\FakeMap; -use DCarbone\PHPConsulAPI\Transcoding; +use DCarbone\PHPConsulAPI\PHPLib\AbstractType; +use DCarbone\PHPConsulAPI\PHPLib\MetaField; -class ACLLoginParams extends AbstractModel +class ACLLoginParams extends AbstractType { - protected const FIELDS = [ - self::FIELD_META => Transcoding::MAP_FIELD + [Transcoding::FIELD_OMITEMPTY => true], - ]; - - private const FIELD_META = 'Meta'; - - public string $AuthMethod = ''; - public string $BearerToken = ''; - public ?FakeMap $Meta = null; + use MetaField; + + public string $AuthMethod; + public string $BearerToken; + + /** + * @param array $Meta + */ + public function __construct( + string $AuthMethod = '', + string $BearerToken = '', + array $Meta = [], + ) { + $this->AuthMethod = $AuthMethod; + $this->BearerToken = $BearerToken; + $this->setMeta($Meta); + } public function getAuthMethod(): string { @@ -58,14 +65,27 @@ public function setBearerToken(string $BearerToken): self return $this; } - public function getMeta(): ?FakeMap + public static function jsonUnserialize(\stdClass $decoded): self { - return $this->Meta; + $n = new self(); + foreach ((array)$decoded as $k => $v) { + if ('Meta' === $k) { + $n->setMeta($v); + } else { + $n->{$k} = $v; + } + } + return $n; } - public function setMeta(mixed $Meta): self + public function jsonSerialize(): \stdClass { - $this->Meta = FakeMap::parse($Meta); - return $this; + $out = $this->_startJsonSerialize(); + $out->AuthMethod = $this->AuthMethod; + $out->BearerToken = $this->BearerToken; + if (null !== $this->Meta) { + $out->Meta = $this->Meta; + } + return $out; } } diff --git a/src/ACL/ACLNodeIdentity.php b/src/ACL/ACLNodeIdentity.php index 400aca2d..45c63d2c 100644 --- a/src/ACL/ACLNodeIdentity.php +++ b/src/ACL/ACLNodeIdentity.php @@ -20,20 +20,55 @@ limitations under the License. */ -use DCarbone\PHPConsulAPI\AbstractModel; +use DCarbone\PHPConsulAPI\PHPLib\AbstractType; -class ACLNodeIdentity extends AbstractModel +class ACLNodeIdentity extends AbstractType { - public string $NodeName = ''; - public string $Datacenter = ''; + public string $NodeName; + public string $Datacenter; + + public function __construct(string $NodeName = '', string $Datacenter = '') + { + $this->NodeName = $NodeName; + $this->Datacenter = $Datacenter; + } public function getNodeName(): string { return $this->NodeName; } + public function setNodeName(string $NodeName): self + { + $this->NodeName = $NodeName; + return $this; + } + public function getDatacenter(): string { return $this->Datacenter; } + + public function setDatacenter(string $Datacenter): self + { + $this->Datacenter = $Datacenter; + return $this; + } + + public static function jsonUnserialize(\stdClass $decoded): self + { + $n = new self(); + foreach ((array)$decoded as $k => $v) { + $n->{$k} = $v; + } + return $n; + } + + public function jsonSerialize(): \stdClass + { + $out = $this->_startJsonSerialize(); + $out->NodeName = $this->NodeName; + $out->Datacenter = $this->Datacenter; + return $out; + } } diff --git a/src/ACL/ACLOIDCAuthURLParams.php b/src/ACL/ACLOIDCAuthURLParams.php index e5384cb7..84258ba3 100644 --- a/src/ACL/ACLOIDCAuthURLParams.php +++ b/src/ACL/ACLOIDCAuthURLParams.php @@ -20,22 +20,31 @@ limitations under the License. */ -use DCarbone\PHPConsulAPI\AbstractModel; -use DCarbone\PHPConsulAPI\FakeMap; -use DCarbone\PHPConsulAPI\Transcoding; +use DCarbone\PHPConsulAPI\PHPLib\AbstractType; +use DCarbone\PHPConsulAPI\PHPLib\MetaField; -class ACLOIDCAuthURLParams extends AbstractModel +class ACLOIDCAuthURLParams extends AbstractType { - protected const FIELDS = [ - self::FIELD_META => Transcoding::MAP_FIELD + [Transcoding::FIELD_OMITEMPTY => true], - ]; - - private const FIELD_META = 'Meta'; - - public string $AuthMethod = ''; - public string $RedirectURI = ''; - public string $ClientNonce = ''; - public ?FakeMap $Meta = null; + use MetaField; + + public string $AuthMethod; + public string $RedirectURI; + public string $ClientNonce; + + /** + * @param array $Meta + */ + public function __construct( + string $AuthMethod = '', + string $RedirectURI = '', + string $ClientNonce = '', + array $Meta = [], + ) { + $this->AuthMethod = $AuthMethod; + $this->RedirectURI = $RedirectURI; + $this->ClientNonce = $ClientNonce; + $this->setMeta($Meta); +} public function getAuthMethod(): string { @@ -70,14 +79,28 @@ public function setClientNonce(string $ClientNonce): self return $this; } - public function getMeta(): ?FakeMap + public static function jsonUnserialize(\stdClass $decoded): self { - return $this->Meta; + $n = new self(); + foreach ((array)$decoded as $k => $v) { + if ('Meta' === $k) { + $n->setMeta($v); + } else { + $n->{$k} = $v; + } + } + return $n; } - public function setMeta(mixed $Meta): self + public function jsonSerialize(): \stdClass { - $this->Meta = FakeMap::parse($Meta); - return $this; + $out = $this->_startJsonSerialize(); + $out->AuthMethod = $this->AuthMethod; + $out->RedirectURI = $this->RedirectURI; + $out->ClientNonce = $this->ClientNonce; + if (null !== $this->Meta) { + $out->Meta = $this->Meta; + } + return $out; } } diff --git a/src/ACL/ACLOIDCCallbackParams.php b/src/ACL/ACLOIDCCallbackParams.php index 1d7b196a..89d2b1a4 100644 --- a/src/ACL/ACLOIDCCallbackParams.php +++ b/src/ACL/ACLOIDCCallbackParams.php @@ -20,14 +20,26 @@ limitations under the License. */ -use DCarbone\PHPConsulAPI\AbstractModel; +use DCarbone\PHPConsulAPI\PHPLib\AbstractType; -class ACLOIDCCallbackParams extends AbstractModel +class ACLOIDCCallbackParams extends AbstractType { - public string $AuthMethod = ''; - public string $State = ''; - public string $Code = ''; - public string $ClientNonce = ''; + public string $AuthMethod; + public string $State; + public string $Code; + public string $ClientNonce; + + public function __construct( + string $AuthMethod = '', + string $State = '', + string $Code = '', + string $ClientNonce = '', + ) { + $this->AuthMethod = $AuthMethod; + $this->State = $State; + $this->Code = $Code; + $this->ClientNonce = $ClientNonce; +} public function getAuthMethod(): string { @@ -72,4 +84,23 @@ public function setClientNonce(string $ClientNonce): self $this->ClientNonce = $ClientNonce; return $this; } + + public static function jsonUnserialize(\stdClass $decoded): self + { + $n = new self(); + foreach ((array)$decoded as $k => $v) { + $n->{$k} = $v; + } + return $n; + } + + public function jsonSerialize(): \stdClass + { + $out = $this->_startJsonSerialize(); + $out->AuthMethod = $this->AuthMethod; + $out->State = $this->State; + $out->Code = $this->Code; + $out->ClientNonce = $this->ClientNonce; + return $out; + } } diff --git a/src/ACL/ACLPolicy.php b/src/ACL/ACLPolicy.php index 88dd5d56..db60d8a7 100644 --- a/src/ACL/ACLPolicy.php +++ b/src/ACL/ACLPolicy.php @@ -20,26 +20,48 @@ limitations under the License. */ -use DCarbone\PHPConsulAPI\AbstractModel; -use DCarbone\PHPConsulAPI\Transcoding; +use DCarbone\PHPConsulAPI\PHPLib\AbstractType; -class ACLPolicy extends AbstractModel +class ACLPolicy extends AbstractType { - protected const FIELDS = [ - self::FIELD_NAMESPACE => Transcoding::OMITEMPTY_STRING_FIELD, - ]; - - private const FIELD_NAMESPACE = 'Namespace'; - - public string $ID = ''; - public string $Name = ''; - public string $Description = ''; - public string $Rules = ''; - public array $Datacenters = []; - public string $Hash = ''; - public int $CreateIndex = 0; - public int $ModifyIndex = 0; - public string $Namespace = ''; + public string $ID; + public string $Name; + public string $Description; + public string $Rules; + /** @var string[] */ + public array $Datacenters; + public string $Hash; + public int $CreateIndex; + public int $ModifyIndex; + public string $Namespace; + public string $Partition; + + /** + * @param array $Datacenters + */ + public function __construct( + string $ID = '', + string $Name = '', + string $Description = '', + string $Rules = '', + array $Datacenters = [], + string $Hash = '', + int $CreateIndex = 0, + int $ModifyIndex = 0, + string $Namespace = '', + string $Partition = '', + ) { + $this->ID = $ID; + $this->Name = $Name; + $this->Description = $Description; + $this->Rules = $Rules; + $this->setDatacenters(...$Datacenters); + $this->Hash = $Hash; + $this->CreateIndex = $CreateIndex; + $this->ModifyIndex = $ModifyIndex; + $this->Namespace = $Namespace; + $this->Partition = $Partition; +} public function getID(): string { @@ -85,12 +107,15 @@ public function setRules(string $Rules): self return $this; } + /** + * @return string[] + */ public function getDatacenters(): array { return $this->Datacenters; } - public function setDatacenters(array $Datacenters): self + public function setDatacenters(string ...$Datacenters): self { $this->Datacenters = $Datacenters; return $this; @@ -139,4 +164,48 @@ public function setNamespace(string $Namespace): self $this->Namespace = $Namespace; return $this; } + + public function getPartition(): string + { + return $this->Partition; + } + + public function setPartition(string $Partition): self + { + $this->Partition = $Partition; + return $this; + } + + public static function jsonUnserialize(\stdClass $decoded): self + { + $n = new self(); + foreach ((array)$decoded as $k => $v) { + if ('Datacenters' === $k) { + $n->setDatacenters(...$v); + } else { + $n->{$k} = $v; + } + } + return $n; + } + + public function jsonSerialize(): \stdClass + { + $out = $this->_startJsonSerialize(); + $out->ID = $this->ID; + $out->Name = $this->Name; + $out->Description = $this->Description; + $out->Rules = $this->Rules; + $out->Datacenters = $this->Datacenters; + $out->Hash = $this->Hash; + $out->CreateIndex = $this->CreateIndex; + $out->ModifyIndex = $this->ModifyIndex; + if ('' !== $this->Namespace) { + $out->Namespace = $this->Namespace; + } + if ('' !== $this->Partition) { + $out->Partition = $this->Partition; + } + return $out; + } } diff --git a/src/ACL/ACLPolicyListEntry.php b/src/ACL/ACLPolicyListEntry.php index 6cb4e67e..048fbfd4 100644 --- a/src/ACL/ACLPolicyListEntry.php +++ b/src/ACL/ACLPolicyListEntry.php @@ -20,25 +20,45 @@ limitations under the License. */ -use DCarbone\PHPConsulAPI\AbstractModel; -use DCarbone\PHPConsulAPI\Transcoding; +use DCarbone\PHPConsulAPI\PHPLib\AbstractType; -class ACLPolicyListEntry extends AbstractModel +class ACLPolicyListEntry extends AbstractType { - protected const FIELDS = [ - self::FIELD_NAMESPACE => Transcoding::OMITEMPTY_STRING_FIELD, - ]; - - private const FIELD_NAMESPACE = 'Namespace'; - - public string $ID = ''; - public string $Name = ''; - public string $Description = ''; - public array $Datacenters = []; - public string $Hash = ''; - public int $CreateIndex = 0; - public int $ModifyIndex = 0; - public string $Namespace = ''; + public string $ID; + public string $Name; + public string $Description; + /** @var array */ + public array $Datacenters; + public string $Hash; + public int $CreateIndex; + public int $ModifyIndex; + public string $Namespace; + public string $Partition; + + /** + * @param array $Datacenters + */ + public function __construct( + string $ID = '', + string $Name = '', + string $Description = '', + array $Datacenters = [], + string $Hash = '', + int $CreateIndex = 0, + int $ModifyIndex = 0, + string $Namespace = '', + string $Partition = '', + ) { + $this->ID = $ID; + $this->Name = $Name; + $this->Description = $Description; + $this->setDatacenters(...$Datacenters); + $this->Hash = $Hash; + $this->CreateIndex = $CreateIndex; + $this->ModifyIndex = $ModifyIndex; + $this->Namespace = $Namespace; + $this->Partition = $Partition; +} public function getID(): string { @@ -73,12 +93,15 @@ public function setDescription(string $Description): self return $this; } + /** + * @return array + */ public function getDatacenters(): array { return $this->Datacenters; } - public function setDatacenters(array $Datacenters): self + public function setDatacenters(string ...$Datacenters): self { $this->Datacenters = $Datacenters; return $this; @@ -127,4 +150,47 @@ public function setNamespace(string $Namespace): self $this->Namespace = $Namespace; return $this; } + + public function getPartition(): string + { + return $this->Partition; + } + + public function setPartition(string $Partition): self + { + $this->Partition = $Partition; + return $this; + } + + public static function jsonUnserialize(\stdClass $decoded): self + { + $n = new self(); + foreach ((array)$decoded as $k => $v) { + if ('Datacenters' === $k) { + $n->setDatacenters(...$v); + } else { + $n->{$k} = $v; + } + } + return $n; + } + + public function jsonSerialize(): \stdClass + { + $out = $this->_startJsonSerialize(); + $out->ID = $this->ID; + $out->Name = $this->Name; + $out->Description = $this->Description; + $out->Datacenters = $this->Datacenters; + $out->Hash = $this->Hash; + $out->CreateIndex = $this->CreateIndex; + $out->ModifyIndex = $this->ModifyIndex; + if ('' !== $this->Namespace) { + $out->Namespace = $this->Namespace; + } + if ('' !== $this->Partition) { + $out->Partition = $this->Partition; + } + return $out; + } } diff --git a/src/ACL/ACLPolicyListEntryQueryResponse.php b/src/ACL/ACLPolicyListEntryQueryResponse.php index 96f28700..41688af2 100644 --- a/src/ACL/ACLPolicyListEntryQueryResponse.php +++ b/src/ACL/ACLPolicyListEntryQueryResponse.php @@ -20,23 +20,27 @@ limitations under the License. */ -use DCarbone\PHPConsulAPI\AbstractValuedQueryResponse; -use DCarbone\PHPConsulAPI\UnmarshalledResponseInterface; +use DCarbone\PHPConsulAPI\PHPLib\AbstractValuedQueryResponse; +use DCarbone\PHPConsulAPI\PHPLib\UnmarshalledResponseInterface; class ACLPolicyListEntryQueryResponse extends AbstractValuedQueryResponse implements UnmarshalledResponseInterface { - public ?array $ACLPolicyListEntries = []; + /** @var \DCarbone\PHPConsulAPI\ACL\ACLPolicyListEntry[] */ + public array $ACLPolicyListEntries = []; - public function getValue(): ?array + /** + * @return \DCarbone\PHPConsulAPI\ACL\ACLPolicyListEntry[] + */ + public function getValue(): array { return $this->ACLPolicyListEntries; } - public function unmarshalValue(mixed $decodedData): void + public function unmarshalValue(mixed $decoded): void { $this->ACLPolicyListEntries = []; - foreach ($decodedData as $datum) { - $this->ACLPolicyListEntries[] = new ACLPolicyListEntry($datum); + foreach ($decoded as $datum) { + $this->ACLPolicyListEntries[] = ACLPolicyListEntry::jsonUnserialize($datum); } } } diff --git a/src/ACL/ACLPolicyQueryResponse.php b/src/ACL/ACLPolicyQueryResponse.php index e8aeb668..58ef1492 100644 --- a/src/ACL/ACLPolicyQueryResponse.php +++ b/src/ACL/ACLPolicyQueryResponse.php @@ -20,20 +20,24 @@ limitations under the License. */ -use DCarbone\PHPConsulAPI\AbstractValuedQueryResponse; -use DCarbone\PHPConsulAPI\UnmarshalledResponseInterface; +use DCarbone\PHPConsulAPI\PHPLib\AbstractValuedQueryResponse; +use DCarbone\PHPConsulAPI\PHPLib\UnmarshalledResponseInterface; class ACLPolicyQueryResponse extends AbstractValuedQueryResponse implements UnmarshalledResponseInterface { - public ?ACLPolicy $ACLPolicy = null; + public null|ACLPolicy $ACLPolicy = null; - public function getValue(): ?ACLPolicy + public function getValue(): null|ACLPolicy { return $this->ACLPolicy; } - public function unmarshalValue(mixed $decodedData): void + public function unmarshalValue(mixed $decoded): void { - $this->ACLPolicy = new ACLPolicy((array)$decodedData); + if (null === $decoded) { + $this->ACLPolicy = null; + return; + } + $this->ACLPolicy = ACLPolicy::jsonUnserialize($decoded); } } diff --git a/src/ACL/ACLPolicyWriteResponse.php b/src/ACL/ACLPolicyWriteResponse.php index 1e9439d5..9cea121e 100644 --- a/src/ACL/ACLPolicyWriteResponse.php +++ b/src/ACL/ACLPolicyWriteResponse.php @@ -20,20 +20,24 @@ limitations under the License. */ -use DCarbone\PHPConsulAPI\AbstractValuedWriteResponse; -use DCarbone\PHPConsulAPI\UnmarshalledResponseInterface; +use DCarbone\PHPConsulAPI\PHPLib\AbstractValuedWriteResponse; +use DCarbone\PHPConsulAPI\PHPLib\UnmarshalledResponseInterface; class ACLPolicyWriteResponse extends AbstractValuedWriteResponse implements UnmarshalledResponseInterface { - public ?ACLPolicy $ACLPolicy = null; + public null|ACLPolicy $ACLPolicy = null; - public function getValue(): ?ACLPolicy + public function getValue(): null|ACLPolicy { return $this->ACLPolicy; } - public function unmarshalValue(mixed $decodedData): void + public function unmarshalValue(mixed $decoded): void { - $this->ACLPolicy = new ACLPolicy((array)$decodedData); + if (null === $decoded) { + $this->ACLPolicy = null; + return; + } + $this->ACLPolicy = ACLPolicy::jsonUnserialize($decoded); } } diff --git a/src/ACL/ACLReplicationStatus.php b/src/ACL/ACLReplicationStatus.php index 479bc9c2..5c7a8794 100644 --- a/src/ACL/ACLReplicationStatus.php +++ b/src/ACL/ACLReplicationStatus.php @@ -21,80 +21,154 @@ */ use DCarbone\Go\Time; -use DCarbone\PHPConsulAPI\AbstractModel; -use DCarbone\PHPConsulAPI\Transcoding; +use DCarbone\PHPConsulAPI\PHPLib\AbstractType; +use function DCarbone\PHPConsulAPI\PHPLib\parse_time; -class ACLReplicationStatus extends AbstractModel +class ACLReplicationStatus extends AbstractType { - protected const FIELDS = [ - self::FIELD_LAST_SUCCESS => [ - Transcoding::FIELD_UNMARSHAL_CALLBACK => Transcoding::UNMARSHAL_TIME, - ], - self::FIELD_LAST_ERROR => [ - Transcoding::FIELD_UNMARSHAL_CALLBACK => Transcoding::UNMARSHAL_TIME, - ], - ]; - - private const FIELD_LAST_SUCCESS = 'LastSuccess'; - private const FIELD_LAST_ERROR = 'LastError'; - - public bool $Enabled = false; - public bool $Running = false; - public string $SourceDatacenter = ''; - public int $ReplicatedIndex = 0; - public int $ReplicatedRoleIndex = 0; - public int $ReplicatedTokenIndex = 0; + public bool $Enabled; + public bool $Running; + public string $SourceDatacenter; + public int $ReplicatedIndex; + public int $ReplicatedRoleIndex; + public int $ReplicatedTokenIndex; public Time\Time $LastSuccess; public Time\Time $LastError; - public function __construct(?array $data = null) - { - parent::__construct($data); - if (!isset($this->LastSuccess)) { - $this->LastSuccess = Time::New(); - } - if (!isset($this->LastError)) { - $this->LastError = Time::New(); - } - } + public function __construct( + bool $Enabled = false, + bool $Running = false, + string $SourceDatacenter = '', + int $ReplicatedIndex = 0, + int $ReplicatedRoleIndex = 0, + int $ReplicatedTokenIndex = 0, + null|Time\Time $LastSuccess = null, + null|Time\Time $LastError = null, + ) { + $this->Enabled = $Enabled; + $this->Running = $Running; + $this->SourceDatacenter = $SourceDatacenter; + $this->ReplicatedIndex = $ReplicatedIndex; + $this->ReplicatedRoleIndex = $ReplicatedRoleIndex; + $this->ReplicatedTokenIndex = $ReplicatedTokenIndex; + $this->LastSuccess = $LastSuccess ?? Time::New(); + $this->LastError = $LastError ?? Time::New(); +} public function isEnabled(): bool { return $this->Enabled; } + public function setEnabled(bool $Enabled): self + { + $this->Enabled = $Enabled; + return $this; + } + public function isRunning(): bool { return $this->Running; } + public function setRunning(bool $Running): self + { + $this->Running = $Running; + return $this; + } + public function getSourceDatacenter(): string { return $this->SourceDatacenter; } + public function setSourceDatacenter(string $SourceDatacenter): self + { + $this->SourceDatacenter = $SourceDatacenter; + return $this; + } + public function getReplicatedIndex(): int { return $this->ReplicatedIndex; } + public function setReplicatedIndex(int $ReplicatedIndex): self + { + $this->ReplicatedIndex = $ReplicatedIndex; + return $this; + } + public function getReplicatedRoleIndex(): int { return $this->ReplicatedRoleIndex; } + public function setReplicatedRoleIndex(int $ReplicatedRoleIndex): self + { + $this->ReplicatedRoleIndex = $ReplicatedRoleIndex; + return $this; + } + public function getReplicatedTokenIndex(): int { return $this->ReplicatedTokenIndex; } + public function setReplicatedTokenIndex(int $ReplicatedTokenIndex): self + { + $this->ReplicatedTokenIndex = $ReplicatedTokenIndex; + return $this; + } + public function getLastSuccess(): Time\Time { return $this->LastSuccess; } + public function setLastSuccess(Time\Time $LastSuccess): self + { + $this->LastSuccess = $LastSuccess; + return $this; + } + public function getLastError(): Time\Time { return $this->LastError; } + + public function setLastError(Time\Time $LastError): self + { + $this->LastError = $LastError; + return $this; + } + + public static function jsonUnserialize(\stdClass $decoded): self + { + $n = new self(); + foreach ((array)$decoded as $k => $v) { + if ('LastSuccess' === $k) { + $n->LastSuccess = parse_time($v); + } elseif ('LastError' === $k) { + $n->LastError = parse_time($v); + } else { + $n->{$k} = $v; + } + } + return $n; + } + + public function jsonSerialize(): \stdClass + { + $out = $this->_startJsonSerialize(); + $out->Enabled = $this->Enabled; + $out->Running = $this->Running; + $out->SourceDatacenter = $this->SourceDatacenter; + $out->ReplicatedIndex = $this->ReplicatedIndex; + $out->ReplicatedRoleIndex = $this->ReplicatedRoleIndex; + $out->ReplicatedTokenIndex = $this->ReplicatedTokenIndex; + $out->LastSuccess = $this->LastSuccess->format(DATE_RFC3339); + $out->LastError = $this->LastError->format(DATE_RFC3339); + return $out; + } } diff --git a/src/ACL/ACLReplicationStatusResponse.php b/src/ACL/ACLReplicationStatusResponse.php index df71f30f..61f12b9c 100644 --- a/src/ACL/ACLReplicationStatusResponse.php +++ b/src/ACL/ACLReplicationStatusResponse.php @@ -20,20 +20,24 @@ limitations under the License. */ -use DCarbone\PHPConsulAPI\AbstractValuedQueryResponse; -use DCarbone\PHPConsulAPI\UnmarshalledResponseInterface; +use DCarbone\PHPConsulAPI\PHPLib\AbstractValuedQueryResponse; +use DCarbone\PHPConsulAPI\PHPLib\UnmarshalledResponseInterface; class ACLReplicationStatusResponse extends AbstractValuedQueryResponse implements UnmarshalledResponseInterface { - public ?ACLReplicationStatus $ACLReplicationStatus = null; + public null|ACLReplicationStatus $ACLReplicationStatus = null; - public function getValue(): ?ACLReplicationStatus + public function getValue(): null|ACLReplicationStatus { return $this->ACLReplicationStatus; } - public function unmarshalValue(mixed $decodedData): void + public function unmarshalValue(mixed $decoded): void { - $this->ACLReplicationStatus = new ACLReplicationStatus((array)$decodedData); + if (null === $decoded) { + $this->ACLReplicationStatus = null; + return; + } + $this->ACLReplicationStatus = ACLReplicationStatus::jsonUnserialize($decoded); } } diff --git a/src/ACL/ACLRole.php b/src/ACL/ACLRole.php index 1913ea18..c5f2f0f4 100644 --- a/src/ACL/ACLRole.php +++ b/src/ACL/ACLRole.php @@ -20,48 +20,60 @@ limitations under the License. */ -use DCarbone\PHPConsulAPI\AbstractModel; -use DCarbone\PHPConsulAPI\Transcoding; +use DCarbone\PHPConsulAPI\PHPLib\AbstractType; -class ACLRole extends AbstractModel +class ACLRole extends AbstractType { - protected const FIELDS = [ - self::FIELD_POLICIES => [ - Transcoding::FIELD_TYPE => Transcoding::ARRAY, - Transcoding::FIELD_CLASS => ACLTokenPolicyLink::class, - Transcoding::FIELD_ARRAY_TYPE => Transcoding::OBJECT, - Transcoding::FIELD_OMITEMPTY => true, - ], - self::FIELD_SERVICE_IDENTITIES => [ - Transcoding::FIELD_TYPE => Transcoding::ARRAY, - Transcoding::FIELD_CLASS => ACLServiceIdentity::class, - Transcoding::FIELD_ARRAY_TYPE => Transcoding::OBJECT, - Transcoding::FIELD_OMITEMPTY => true, - ], - self::FIELD_NODE_IDENTITIES => [ - Transcoding::FIELD_TYPE => Transcoding::ARRAY, - Transcoding::FIELD_CLASS => ACLNodeIdentity::class, - Transcoding::FIELD_ARRAY_TYPE => Transcoding::OBJECT, - Transcoding::FIELD_OMITEMPTY => true, - ], - self::FIELD_NAMESPACE => Transcoding::OMITEMPTY_STRING_FIELD, - ]; - - private const FIELD_POLICIES = 'Policies'; - private const FIELD_SERVICE_IDENTITIES = 'ServiceIdentities'; - private const FIELD_NODE_IDENTITIES = 'NodeIdentities'; - private const FIELD_NAMESPACE = 'Namespace'; - - public string $ID = ''; - public string $Name = ''; - public string $Description = ''; - public array $Policies = []; - public array $ServiceIdentities = []; - public array $NodeIdentities = []; - public string $Hash = ''; - public int $CreateIndex = 0; - public int $ModifyIndex = 0; - public string $Namespace = ''; + public string $ID; + public string $Name; + public string $Description; + /** @var \DCarbone\PHPConsulAPI\ACL\ACLRolePolicyLink[] */ + public array $Policies; + /** @var \DCarbone\PHPConsulAPI\ACL\ACLServiceIdentity[] */ + public array $ServiceIdentities; + /** @var \DCarbone\PHPConsulAPI\ACL\ACLNodeIdentity[] */ + public array $NodeIdentities; + /** @var \DCarbone\PHPConsulAPI\ACL\ACLTemplatedPolicy[] */ + public array $TemplatedPolicies; + public string $Hash; + public int $CreateIndex; + public int $ModifyIndex; + public string $Namespace; + public string $Partition; + + /** + * @param array<\DCarbone\PHPConsulAPI\ACL\ACLRolePolicyLink> $Policies + * @param array<\DCarbone\PHPConsulAPI\ACL\ACLServiceIdentity> $ServiceIdentities + * @param array<\DCarbone\PHPConsulAPI\ACL\ACLNodeIdentity> $NodeIdentities + * @param array<\DCarbone\PHPConsulAPI\ACL\ACLTemplatedPolicy> $TemplatedPolicies + */ + public function __construct( + string $ID = '', + string $Name = '', + string $Description = '', + array $Policies = [], + array $ServiceIdentities = [], + array $NodeIdentities = [], + array $TemplatedPolicies = [], + string $Hash = '', + int $CreateIndex = 0, + int $ModifyIndex = 0, + string $Namespace = '', + string $Partition = '', + ) { + $this->ID = $ID; + $this->Name = $Name; + $this->Description = $Description; + $this->setPolicies(...$Policies); + $this->setServiceIdentities(...$ServiceIdentities); + $this->setNodeIdentities(...$NodeIdentities); + $this->setTemplatedPolicies(...$TemplatedPolicies); + $this->Hash = $Hash; + $this->CreateIndex = $CreateIndex; + $this->ModifyIndex = $ModifyIndex; + $this->Namespace = $Namespace; + $this->Partition = $Partition; +} public function getID(): string { @@ -96,39 +108,62 @@ public function setDescription(string $Description): self return $this; } + /** + * @return \DCarbone\PHPConsulAPI\ACL\ACLRolePolicyLink[] + */ public function getPolicies(): array { return $this->Policies; } - public function setPolicies(array $Policies): self + public function setPolicies(ACLRolePolicyLink ...$Policies): self { $this->Policies = $Policies; return $this; } + /** + * @return \DCarbone\PHPConsulAPI\ACL\ACLServiceIdentity[] + */ public function getServiceIdentities(): array { return $this->ServiceIdentities; } - public function setServiceIdentities(array $ServiceIdentities): self + public function setServiceIdentities(ACLServiceIdentity ...$ServiceIdentities): self { $this->ServiceIdentities = $ServiceIdentities; return $this; } + /** + * @return \DCarbone\PHPConsulAPI\ACL\ACLNodeIdentity[] + */ public function getNodeIdentities(): array { return $this->NodeIdentities; } - public function setNodeIdentities(array $NodeIdentities): self + public function setNodeIdentities(ACLNodeIdentity ...$NodeIdentities): self { $this->NodeIdentities = $NodeIdentities; return $this; } + /** + * @return \DCarbone\PHPConsulAPI\ACL\ACLTemplatedPolicy[] + */ + public function getTemplatedPolicies(): array + { + return $this->TemplatedPolicies; + } + + public function setTemplatedPolicies(ACLTemplatedPolicy ...$TemplatedPolicies): self + { + $this->TemplatedPolicies = $TemplatedPolicies; + return $this; + } + public function getHash(): string { return $this->Hash; @@ -172,4 +207,76 @@ public function setNamespace(string $Namespace): self $this->Namespace = $Namespace; return $this; } + + public function getPartition(): string + { + return $this->Partition; + } + + public function setPartition(string $Partition): self + { + $this->Partition = $Partition; + return $this; + } + + public static function jsonUnserialize(\stdClass $decoded): self + { + $n = new self(); + foreach ((array)$decoded as $k => $v) { + if ('Policies' === $k) { + $n->Policies = []; + foreach ($v as $vv) { + $n->Policies[] = ACLRolePolicyLink::jsonUnserialize($vv); + } + } elseif ('ServiceIdentities' === $k) { + $n->ServiceIdentities = []; + foreach ($v as $vv) { + $n->ServiceIdentities[] = ACLServiceIdentity::jsonUnserialize($vv); + } + } elseif ('NodeIdentities' === $k) { + $n->NodeIdentities = []; + foreach ($v as $vv) { + $n->NodeIdentities[] = ACLNodeIdentity::jsonUnserialize($vv); + } + } elseif ('TemplatedPolicies' === $k) { + $n->TemplatedPolicies = []; + foreach ($v as $vv) { + $n->TemplatedPolicies[] = ACLTemplatedPolicy::jsonUnserialize($vv); + } + } else { + $n->{$k} = $v; + } + } + return $n; + } + + public function jsonSerialize(): \stdClass + { + $out = $this->_startJsonSerialize(); + $out->ID = $this->ID; + $out->Name = $this->Name; + $out->Description = $this->Description; + $out->Hash = $this->Hash; + if ([] !== $this->Policies) { + $out->Policies = $this->Policies; + } + if ([] !== $this->ServiceIdentities) { + $out->ServiceIdentities = $this->ServiceIdentities; + } + if ([] !== $this->NodeIdentities) { + $out->NodeIdentities = $this->NodeIdentities; + } + if ([] !== $this->TemplatedPolicies) { + $out->TemplatedPolicies = $this->TemplatedPolicies; + } + $out->CreateIndex = $this->CreateIndex; + $out->ModifyIndex = $this->ModifyIndex; + if ('' !== $this->Namespace) { + $out->Namespace = $this->Namespace; + } + if ('' !== $this->Partition) { + $out->Partition = $this->Partition; + } + return $out; + } } diff --git a/src/ACL/ACLRolePolicyLink.php b/src/ACL/ACLRolePolicyLink.php index 649dbc90..5dfd0ab2 100644 --- a/src/ACL/ACLRolePolicyLink.php +++ b/src/ACL/ACLRolePolicyLink.php @@ -22,4 +22,12 @@ class ACLRolePolicyLink extends ACLLink { + public static function jsonUnserialize(\stdClass $decoded): self + { + $n = new self(); + foreach ((array)$decoded as $k => $v) { + $n->{$k} = $v; + } + return $n; + } } diff --git a/src/ACL/ACLRoleQueryResponse.php b/src/ACL/ACLRoleQueryResponse.php index 4ffbe236..814c6f5c 100644 --- a/src/ACL/ACLRoleQueryResponse.php +++ b/src/ACL/ACLRoleQueryResponse.php @@ -20,20 +20,24 @@ limitations under the License. */ -use DCarbone\PHPConsulAPI\AbstractValuedQueryResponse; -use DCarbone\PHPConsulAPI\UnmarshalledResponseInterface; +use DCarbone\PHPConsulAPI\PHPLib\AbstractValuedQueryResponse; +use DCarbone\PHPConsulAPI\PHPLib\UnmarshalledResponseInterface; class ACLRoleQueryResponse extends AbstractValuedQueryResponse implements UnmarshalledResponseInterface { - public ?ACLRole $ACLRole = null; + public null|ACLRole $ACLRole = null; - public function getValue(): ?ACLRole + public function getValue(): null|ACLRole { return $this->ACLRole; } - public function unmarshalValue(mixed $decodedData): void + public function unmarshalValue(mixed $decoded): void { - $this->ACLRole = new ACLRole((array)$decodedData); + if (null === $decoded) { + $this->ACLRole = null; + return; + } + $this->ACLRole = ACLRole::jsonUnserialize($decoded); } } diff --git a/src/ACL/ACLRoleWriteResponse.php b/src/ACL/ACLRoleWriteResponse.php index cb94ff4e..3dcb49cf 100644 --- a/src/ACL/ACLRoleWriteResponse.php +++ b/src/ACL/ACLRoleWriteResponse.php @@ -20,20 +20,24 @@ limitations under the License. */ -use DCarbone\PHPConsulAPI\AbstractValuedWriteResponse; -use DCarbone\PHPConsulAPI\UnmarshalledResponseInterface; +use DCarbone\PHPConsulAPI\PHPLib\AbstractValuedWriteResponse; +use DCarbone\PHPConsulAPI\PHPLib\UnmarshalledResponseInterface; class ACLRoleWriteResponse extends AbstractValuedWriteResponse implements UnmarshalledResponseInterface { - public ?ACLRole $ACLRole = null; + public null|ACLRole $ACLRole = null; - public function getValue(): ?ACLRole + public function getValue(): null|ACLRole { return $this->ACLRole; } - public function unmarshalValue(mixed $decodedData): void + public function unmarshalValue(mixed $decoded): void { - $this->ACLRole = new ACLRole((array)$decodedData); + if (null === $decoded) { + $this->ACLRole = null; + return; + } + $this->ACLRole = ACLRole::jsonUnserialize($decoded); } } diff --git a/src/ACL/ACLRolesQueryResponse.php b/src/ACL/ACLRolesQueryResponse.php index 37d58657..52ff3612 100644 --- a/src/ACL/ACLRolesQueryResponse.php +++ b/src/ACL/ACLRolesQueryResponse.php @@ -20,23 +20,27 @@ limitations under the License. */ -use DCarbone\PHPConsulAPI\AbstractValuedQueryResponse; -use DCarbone\PHPConsulAPI\UnmarshalledResponseInterface; +use DCarbone\PHPConsulAPI\PHPLib\AbstractValuedQueryResponse; +use DCarbone\PHPConsulAPI\PHPLib\UnmarshalledResponseInterface; class ACLRolesQueryResponse extends AbstractValuedQueryResponse implements UnmarshalledResponseInterface { - public ?array $ACLRoles = []; + /** @var \DCarbone\PHPConsulAPI\ACL\ACLRole[] */ + public array $ACLRoles = []; - public function getValue(): ?array + /** + * @return \DCarbone\PHPConsulAPI\ACL\ACLRole[] + */ + public function getValue(): array { return $this->ACLRoles; } - public function unmarshalValue(mixed $decodedData): void + public function unmarshalValue(mixed $decoded): void { $this->ACLRoles = []; - foreach ($decodedData as $datum) { - $this->ACLRoles[] = new ACLRole($datum); + foreach ($decoded as $datum) { + $this->ACLRoles[] = ACLRole::jsonUnserialize($datum); } } } diff --git a/src/ACL/ACLServiceIdentity.php b/src/ACL/ACLServiceIdentity.php index 99d7d938..52f80994 100644 --- a/src/ACL/ACLServiceIdentity.php +++ b/src/ACL/ACLServiceIdentity.php @@ -20,31 +20,68 @@ limitations under the License. */ -use DCarbone\PHPConsulAPI\AbstractModel; -use DCarbone\PHPConsulAPI\Transcoding; +use DCarbone\PHPConsulAPI\PHPLib\AbstractType; -class ACLServiceIdentity extends AbstractModel +class ACLServiceIdentity extends AbstractType { - protected const FIELDS = [ - self::FIELD_DATACENTERS => [ - Transcoding::FIELD_TYPE => Transcoding::ARRAY, - Transcoding::FIELD_ARRAY_TYPE => Transcoding::STRING, - Transcoding::FIELD_OMITEMPTY => true, - ], - ]; + public string $ServiceName; + /** @var string[] */ + public array $Datacenters; - private const FIELD_DATACENTERS = 'Datacenters'; - - public string $ServiceName = ''; - public array $Datacenters = []; + /** + * @param array $Datacenters + */ + public function __construct(string $ServiceName = '', array $Datacenters = []) + { + $this->ServiceName = $ServiceName; + $this->setDatacenters(...$Datacenters); + } public function getServiceName(): string { return $this->ServiceName; } + public function setServiceName(string $ServiceName): self + { + $this->ServiceName = $ServiceName; + return $this; + } + + /** + * @return string[] + */ public function getDatacenters(): array { return $this->Datacenters; } + + public function setDatacenters(string ...$Datacenters): self + { + $this->Datacenters = $Datacenters; + return $this; + } + + public static function jsonUnserialize(\stdClass $decoded): self + { + $n = new self(); + foreach ((array)$decoded as $k => $v) { + if ('Datacenters' === $k) { + $n->setDatacenters(...$v); + } else { + $n->{$k} = $v; + } + } + return $n; + } + + public function jsonSerialize(): \stdClass + { + $out = $this->_startJsonSerialize(); + $out->ServiceName = $this->ServiceName; + if ([] !== $this->Datacenters) { + $out->Datacenters = $this->Datacenters; + } + return $out; + } } diff --git a/src/ACL/ACLTemplatedPolicy.php b/src/ACL/ACLTemplatedPolicy.php new file mode 100644 index 00000000..87edf789 --- /dev/null +++ b/src/ACL/ACLTemplatedPolicy.php @@ -0,0 +1,108 @@ + $Datacenters + */ + public function __construct( + string $TemplateName = '', + null|ACLTemplatedPolicyVariables $TemplateVariables = null, + array $Datacenters = [], + ) { + $this->TemplateName = $TemplateName; + $this->TemplateVariables = $TemplateVariables; + $this->setDatacenters(...$Datacenters); + } + + public function getTemplateName(): string + { + return $this->TemplateName; + } + + public function setTemplateName(string $TemplateName): self + { + $this->TemplateName = $TemplateName; + return $this; + } + + public function getTemplateVariables(): null|ACLTemplatedPolicyVariables + { + return $this->TemplateVariables; + } + + public function setTemplateVariables(null|ACLTemplatedPolicyVariables $TemplateVariables): self + { + $this->TemplateVariables = $TemplateVariables; + return $this; + } + + /** + * @return string[] + */ + public function getDatacenters(): array + { + return $this->Datacenters; + } + + public function setDatacenters(string ...$Datacenters): self + { + $this->Datacenters = $Datacenters; + return $this; + } + + public static function jsonUnserialize(\stdClass $decoded): self + { + $n = new self(); + foreach ((array)$decoded as $k => $v) { + if ('TemplateVariables' === $k) { + $n->setTemplateVariables($v); + } elseif ('Datacenters' === $k) { + $n->setDatacenters(...$v); + } else { + $n->{$k} = $v; + } + } + return $n; + } + + public function jsonSerialize(): \stdClass + { + $out = $this->_startJsonSerialize(); + $out->TemplateName = $this->TemplateName; + if (null !== $this->TemplateVariables) { + $out->TemplateVariables = $this->TemplateVariables; + } + if ([] !== $this->Datacenters) { + $out->Datacenters = $this->Datacenters; + } + return $out; + } +} diff --git a/src/ACL/ACLTemplatedPolicyVariables.php b/src/ACL/ACLTemplatedPolicyVariables.php new file mode 100644 index 00000000..8b56c6ec --- /dev/null +++ b/src/ACL/ACLTemplatedPolicyVariables.php @@ -0,0 +1,60 @@ +Name = $Name; + } + + public function getName(): string + { + return $this->Name; + } + + public function setName(string $Name): self + { + $this->Name = $Name; + return $this; + } + + public static function jsonUnserialize(\stdClass $decoded): self + { + $n = new self(); + foreach ((array)$decoded as $k => $v) { + $n->{$k} = $v; + } + return $n; + } + + public function jsonSerialize(): \stdClass + { + $out = $this->_startJsonSerialize(); + $out->Name = $this->Name; + return $out; + } +} \ No newline at end of file diff --git a/src/ACL/ACLToken.php b/src/ACL/ACLToken.php index d417a98d..7da4165f 100644 --- a/src/ACL/ACLToken.php +++ b/src/ACL/ACLToken.php @@ -21,279 +21,78 @@ */ use DCarbone\Go\Time; -use DCarbone\PHPConsulAPI\AbstractModel; -use DCarbone\PHPConsulAPI\Transcoding; +use DCarbone\PHPConsulAPI\PHPLib\AbstractType; -class ACLToken extends AbstractModel +class ACLToken extends AbstractType { - protected const FIELDS = [ - self::FIELD_POLICIES => [ - Transcoding::FIELD_TYPE => Transcoding::ARRAY, - Transcoding::FIELD_CLASS => ACLTokenPolicyLink::class, - Transcoding::FIELD_ARRAY_TYPE => Transcoding::OBJECT, - Transcoding::FIELD_OMITEMPTY => true, - ], - self::FIELD_ROLES => [ - Transcoding::FIELD_TYPE => Transcoding::ARRAY, - Transcoding::FIELD_CLASS => ACLTokenRoleLink::class, - Transcoding::FIELD_ARRAY_TYPE => Transcoding::OBJECT, - Transcoding::FIELD_OMITEMPTY => true, - ], - self::FIELD_SERVICE_IDENTITIES => [ - Transcoding::FIELD_TYPE => Transcoding::ARRAY, - Transcoding::FIELD_CLASS => ACLServiceIdentity::class, - Transcoding::FIELD_ARRAY_TYPE => Transcoding::OBJECT, - Transcoding::FIELD_OMITEMPTY => true, - ], - self::FIELD_NODE_IDENTITIES => [ - Transcoding::FIELD_TYPE => Transcoding::ARRAY, - Transcoding::FIELD_CLASS => ACLNodeIdentity::class, - Transcoding::FIELD_ARRAY_TYPE => Transcoding::OBJECT, - Transcoding::FIELD_OMITEMPTY => true, - ], - self::FIELD_AUTH_METHOD => Transcoding::OMITEMPTY_STRING_FIELD, - self::FIELD_EXPIRATION_TTL => [ - Transcoding::FIELD_UNMARSHAL_CALLBACK => Transcoding::UNMARSHAL_DURATION, - Transcoding::FIELD_OMITEMPTY => true, - ], - self::FIELD_EXPIRATION_TIME => [ - Transcoding::FIELD_UNMARSHAL_CALLBACK => Transcoding::UNMARSHAL_NULLABLE_TIME, - Transcoding::FIELD_NULLABLE => true, - Transcoding::FIELD_OMITEMPTY => true, - ], - self::FIELD_CREATE_TIME => [ - Transcoding::FIELD_UNMARSHAL_CALLBACK => Transcoding::UNMARSHAL_TIME, - Transcoding::FIELD_OMITEMPTY => true, - ], - self::FIELD_RULES => Transcoding::OMITEMPTY_STRING_FIELD, - self::FIELD_NAMESPACE => Transcoding::OMITEMPTY_STRING_FIELD, - ]; - - private const FIELD_POLICIES = 'Policies'; - private const FIELD_ROLES = 'Roles'; - private const FIELD_SERVICE_IDENTITIES = 'ServiceIdentities'; - private const FIELD_NODE_IDENTITIES = 'NodeIdentities'; - private const FIELD_AUTH_METHOD = 'AuthMethod'; - private const FIELD_EXPIRATION_TTL = 'ExpirationTTL'; - private const FIELD_EXPIRATION_TIME = 'ExpirationTime'; - private const FIELD_CREATE_TIME = 'CreateTime'; - private const FIELD_RULES = 'Rules'; - private const FIELD_NAMESPACE = 'Namespace'; - - public int $CreateIndex = 0; - public int $ModifyIndex = 0; - public string $AccessorID = ''; - public string $SecretID = ''; - public string $Description = ''; - public array $Policies = []; - public array $Roles = []; - public array $ServiceIdentities = []; - public array $NodeIdentities = []; - public bool $Local = false; - public string $AuthMethod = ''; - public Time\Duration $ExpirationTTL; - public ?Time\Time $ExpirationTime = null; - public Time\Time $CreateTime; - public string $Hash = ''; - public string $Namespace = ''; - - public string $Rules = ''; - - public function __construct(?array $data = null) - { - parent::__construct($data); - if (!isset($this->ExpirationTTL)) { - $this->ExpirationTTL = new Time\Duration(); - } - if (!isset($this->CreateTime)) { - $this->CreateTime = Time::New(); - } - } - - public function getCreateIndex(): int - { - return $this->CreateIndex; - } - - public function setCreateIndex(int $CreateIndex): self - { + use ACLTokenFields; + + /** + * @param array<\DCarbone\PHPConsulAPI\ACL\ACLTokenPolicyLink> $Policies + * @param array<\DCarbone\PHPConsulAPI\ACL\ACLTokenRoleLink> $Roles + * @param array<\DCarbone\PHPConsulAPI\ACL\ACLServiceIdentity> $ServiceIdentities + * @param array<\DCarbone\PHPConsulAPI\ACL\ACLNodeIdentity> $NodeIdentities + * @param array<\DCarbone\PHPConsulAPI\ACL\ACLTemplatedPolicy> $TemplatePolicies + */ + public function __construct( + int $CreateIndex = 0, + int $ModifyIndex = 0, + string $AccessorID = '', + string $SecretID = '', + string $Description = '', + array $Policies = [], + array $Roles = [], + array $ServiceIdentities = [], + array $NodeIdentities = [], + array $TemplatePolicies = [], + bool $Local = false, + string $AuthMethod = '', + null|int|float|string|\DateInterval|Time\Duration $ExpirationTTL = null, + null|Time\Time $ExpirationTime = null, + null|Time\Time $CreateTime = null, + string $Hash = '', + string $Namespace = '', + string $Rules = '', + string $Partition = '', + string $AuthMethodNamespace = '', + ) { $this->CreateIndex = $CreateIndex; - return $this; - } - - public function getModifyIndex(): int - { - return $this->ModifyIndex; - } - - public function setModifyIndex(int $ModifyIndex): self - { $this->ModifyIndex = $ModifyIndex; - return $this; - } - - public function getAccessorID(): string - { - return $this->AccessorID; - } - - public function setAccessorID(string $AccessorID): self - { $this->AccessorID = $AccessorID; - return $this; - } - - public function getSecretID(): string - { - return $this->SecretID; - } - - public function setSecretID(string $SecretID): self - { $this->SecretID = $SecretID; - return $this; - } - - public function getDescription(): string - { - return $this->Description; - } - - public function setDescription(string $Description): self - { $this->Description = $Description; - return $this; - } - - public function getPolicies(): array - { - return $this->Policies; - } - - public function setPolicies(array $Policies): self - { - $this->Policies = $Policies; - return $this; - } - - public function getRoles(): array - { - return $this->Roles; - } - - public function setRoles(array $Roles): self - { - $this->Roles = $Roles; - return $this; - } - - public function getServiceIdentities(): array - { - return $this->ServiceIdentities; - } - - public function setServiceIdentities(array $ServiceIdentities): self - { - $this->ServiceIdentities = $ServiceIdentities; - return $this; - } - - public function getNodeIdentities(): array - { - return $this->NodeIdentities; - } - - public function setNodeIdentities(array $NodeIdentities): self - { - $this->NodeIdentities = $NodeIdentities; - return $this; - } - - public function isLocal(): bool - { - return $this->Local; - } - - public function setLocal(bool $Local): self - { + $this->setPolicies(...$Policies); + $this->setRoles(...$Roles); + $this->setServiceIdentities(...$ServiceIdentities); + $this->setNodeIdentities(...$NodeIdentities); + $this->setTemplatePolicies(...$TemplatePolicies); $this->Local = $Local; - return $this; - } - - public function getAuthMethod(): string - { - return $this->AuthMethod; - } - - public function setAuthMethod(string $AuthMethod): self - { $this->AuthMethod = $AuthMethod; - return $this; - } - - public function getExpirationTTL(): Time\Duration - { - return $this->ExpirationTTL; - } - - public function setExpirationTTL(Time\Duration $ExpirationTTL): self - { - $this->ExpirationTTL = $ExpirationTTL; - return $this; - } - - public function getExpirationTime(): ?Time\Time - { - return $this->ExpirationTime; - } - - public function setExpirationTime(?Time\Time $ExpirationTime): self - { - $this->ExpirationTime = $ExpirationTime; - return $this; - } - - public function getCreateTime(): Time\Time - { - return $this->CreateTime; - } - - public function setCreateTime(Time\Time $CreateTime): self - { - $this->CreateTime = $CreateTime; - return $this; - } - - public function getHash(): string - { - return $this->Hash; - } - - public function setHash(string $Hash): self - { + $this->setExpirationTTL($ExpirationTTL); + $this->setExpirationTime($ExpirationTime); + $this->CreateTime = $CreateTime ?? Time::New(); $this->Hash = $Hash; - return $this; - } - - public function getNamespace(): string - { - return $this->Namespace; - } - - public function setNamespace(string $Namespace): self - { $this->Namespace = $Namespace; - return $this; - } + $this->Rules = $Rules; + $this->Partition = $Partition; + $this->AuthMethodNamespace = $AuthMethodNamespace; +} - public function getRules(): string + public static function jsonUnserialize(\stdClass $decoded): self { - return $this->Rules; + $n = new self(); + foreach ((array)$decoded as $k => $v) { + if (!$n->_jsonUnserializeField($k, $v, $n)) { + $n->{$k} = $v; + } + } + return $n; } - public function setRules(string $Rules): self + public function jsonSerialize(): \stdClass { - $this->Rules = $Rules; - return $this; + $out = $this->_startJsonSerialize(); + $this->_jsonSerialize($out); + return $out; } } diff --git a/src/ACL/ACLTokenExpanded.php b/src/ACL/ACLTokenExpanded.php new file mode 100644 index 00000000..070ae552 --- /dev/null +++ b/src/ACL/ACLTokenExpanded.php @@ -0,0 +1,240 @@ + $ExpandedPolicies + * @param array<\DCarbone\PHPConsulAPI\ACL\ACLRole> $ExpandedRoles + * @param array $NamespaceDefaultPolicyIDs + * @param array $NamespaceDefaultRoleIDs + * @param array<\DCarbone\PHPConsulAPI\ACL\ACLTokenPolicyLink> $Policies + * @param array<\DCarbone\PHPConsulAPI\ACL\ACLTokenRoleLink> $Roles + * @param array<\DCarbone\PHPConsulAPI\ACL\ACLServiceIdentity> $ServiceIdentities + * @param array<\DCarbone\PHPConsulAPI\ACL\ACLNodeIdentity> $NodeIdentities + * @param array<\DCarbone\PHPConsulAPI\ACL\ACLTemplatedPolicy> $TemplatePolicies + */ + public function __construct( + array $ExpandedPolicies = [], + array $ExpandedRoles = [], + array $NamespaceDefaultPolicyIDs = [], + array $NamespaceDefaultRoleIDs = [], + string $AgentACLDefaultPolicy = '', + string $AgentACLDownPolicy = '', + string $ResolvedByAgent = '', + int $CreateIndex = 0, + int $ModifyIndex = 0, + string $AccessorID = '', + string $SecretID = '', + string $Description = '', + array $Policies = [], + array $Roles = [], + array $ServiceIdentities = [], + array $NodeIdentities = [], + array $TemplatePolicies = [], + bool $Local = false, + string $AuthMethod = '', + null|int|float|string|\DateInterval|Time\Duration $ExpirationTTL = null, + null|Time\Time $ExpirationTime = null, + null|Time\Time $CreateTime = null, + string $Hash = '', + string $Namespace = '', + string $Rules = '', + string $Partition = '', + string $AuthMethodNamespace = '' + ) { + parent::__construct( + CreateIndex: $CreateIndex, + ModifyIndex: $ModifyIndex, + AccessorID: $AccessorID, + SecretID: $SecretID, + Description: $Description, + Policies: $Policies, + Roles: $Roles, + ServiceIdentities: $ServiceIdentities, + NodeIdentities: $NodeIdentities, + TemplatePolicies: $TemplatePolicies, + Local: $Local, + AuthMethod: $AuthMethod, + ExpirationTTL: $ExpirationTTL, + ExpirationTime: $ExpirationTime, + CreateTime: $CreateTime, + Hash: $Hash, + Namespace: $Namespace, + Rules: $Rules, + Partition: $Partition, + AuthMethodNamespace: $AuthMethodNamespace + ); + $this->setExpandedPolicies(...$ExpandedPolicies); + $this->setExpandedRoles(...$ExpandedRoles); + $this->setNamespaceDefaultPolicyIDs(...$NamespaceDefaultPolicyIDs); + $this->setNamespaceDefaultRoleIDs(...$NamespaceDefaultRoleIDs); + $this->AgentACLDefaultPolicy = $AgentACLDefaultPolicy; + $this->AgentACLDownPolicy = $AgentACLDownPolicy; + $this->ResolvedByAgent = $ResolvedByAgent; +} + + /** + * @return \DCarbone\PHPConsulAPI\ACL\ACLPolicy[] + */ + public function getExpandedPolicies(): array + { + return $this->ExpandedPolicies; + } + + public function setExpandedPolicies(ACLPolicy ...$ExpandedPolicies): self + { + $this->ExpandedPolicies = $ExpandedPolicies; + return $this; + } + + /** + * @return array<\DCarbone\PHPConsulAPI\ACL\ACLRole> + */ + public function getExpandedRoles(): array + { + return $this->ExpandedRoles; + } + + public function setExpandedRoles(ACLRole ...$ExpandedRoles): self + { + $this->ExpandedRoles = $ExpandedRoles; + return $this; + } + + /** + * @return string[] + */ + public function getNamespaceDefaultPolicyIDs(): array + { + return $this->NamespaceDefaultPolicyIDs; + } + + public function setNamespaceDefaultPolicyIDs(string ...$NamespaceDefaultPolicyIDs): self + { + $this->NamespaceDefaultPolicyIDs = $NamespaceDefaultPolicyIDs; + return $this; + } + + /** + * @return string[] + */ + public function getNamespaceDefaultRoleIDs(): array + { + return $this->NamespaceDefaultRoleIDs; + } + + public function setNamespaceDefaultRoleIDs(string ...$NamespaceDefaultRoleIDs): self + { + $this->NamespaceDefaultRoleIDs = $NamespaceDefaultRoleIDs; + return $this; + } + + public function getAgentACLDefaultPolicy(): string + { + return $this->AgentACLDefaultPolicy; + } + + public function setAgentACLDefaultPolicy(string $AgentACLDefaultPolicy): self + { + $this->AgentACLDefaultPolicy = $AgentACLDefaultPolicy; + return $this; + } + + public function getAgentACLDownPolicy(): string + { + return $this->AgentACLDownPolicy; + } + + public function setAgentACLDownPolicy(string $AgentACLDownPolicy): self + { + $this->AgentACLDownPolicy = $AgentACLDownPolicy; + return $this; + } + + public function getResolvedByAgent(): string + { + return $this->ResolvedByAgent; + } + + public function setResolvedByAgent(string $ResolvedByAgent): self + { + $this->ResolvedByAgent = $ResolvedByAgent; + return $this; + } + + public static function jsonUnserialize(\stdClass $decoded): self + { + $n = new self(); + foreach ((array)$decoded as $k => $v) { + if ($n->_jsonUnserializeField($k, $v, $n)) { + continue; + } + + if ('ExpandedPolicies' === $k) { + foreach ($v as $vv) { + $n->ExpandedPolicies[] = ACLPolicy::jsonUnserialize($vv); + } + } elseif ('ExpandedRoles' === $k) { + foreach ($v as $vv) { + $n->ExpandedRoles[] = ACLRole::jsonUnserialize($vv); + } + } elseif ('NamespaceDefaultPolicyIDs' === $k) { + $n->setNamespaceDefaultPolicyIDs(...$v); + } elseif ('NamespaceDefaultRoleIDs' === $k) { + $n->setNamespaceDefaultRoleIDs(...$v); + } else { + $n->{$k} = $v; + } + } + return $n; + } + + public function jsonSerialize(): \stdClass + { + $out = parent::jsonSerialize(); + + $out->ExpandedPolicies = $this->ExpandedPolicies; + $out->ExpandedRoles = $this->ExpandedRoles; + $out->NamespaceDefaultPolicyIDs = $this->NamespaceDefaultPolicyIDs; + $out->NamespaceDefaultRoleIDs = $this->NamespaceDefaultRoleIDs; + $out->AgentACLDefaultPolicy = $this->AgentACLDefaultPolicy; + $out->AgentACLDownPolicy = $this->AgentACLDownPolicy; + $out->ResolvedByAgent = $this->ResolvedByAgent; + + return $out; + } +} diff --git a/src/ACL/ACLTokenExpandedQueryResponse.php b/src/ACL/ACLTokenExpandedQueryResponse.php new file mode 100644 index 00000000..953e6b51 --- /dev/null +++ b/src/ACL/ACLTokenExpandedQueryResponse.php @@ -0,0 +1,43 @@ +ACLTokenExpanded; + } + + public function unmarshalValue(mixed $decoded): void + { + if (null === $decoded) { + $this->ACLTokenExpanded = null; + return; + } + $this->ACLTokenExpanded = ACLTokenExpanded::jsonUnserialize($decoded); + } +} diff --git a/src/ACL/ACLTokenFields.php b/src/ACL/ACLTokenFields.php new file mode 100644 index 00000000..dc376d0e --- /dev/null +++ b/src/ACL/ACLTokenFields.php @@ -0,0 +1,374 @@ + */ + public array $Policies; + /** @var array<\DCarbone\PHPConsulAPI\ACL\ACLTokenRoleLink> */ + public array $Roles; + /** @var array<\DCarbone\PHPConsulAPI\ACL\ACLServiceIdentity> */ + public array $ServiceIdentities; + /** @var array<\DCarbone\PHPConsulAPI\ACL\ACLNodeIdentity> */ + public array $NodeIdentities; + /** @var array<\DCarbone\PHPConsulAPI\ACL\ACLTemplatedPolicy> */ + public array $TemplatePolicies; + public bool $Local; + public string $AuthMethod; + public Time\Duration $ExpirationTTL; + public null|Time\Time $ExpirationTime = null; + public null|Time\Time $CreateTime; + public string $Hash; + public string $Namespace; + public string $Partition; + public string $AuthMethodNamespace; + + public string $Rules; + + public function getCreateIndex(): int + { + return $this->CreateIndex; + } + + public function setCreateIndex(int $CreateIndex): self + { + $this->CreateIndex = $CreateIndex; + return $this; + } + + public function getModifyIndex(): int + { + return $this->ModifyIndex; + } + + public function setModifyIndex(int $ModifyIndex): self + { + $this->ModifyIndex = $ModifyIndex; + return $this; + } + + public function getAccessorID(): string + { + return $this->AccessorID; + } + + public function setAccessorID(string $AccessorID): self + { + $this->AccessorID = $AccessorID; + return $this; + } + + public function getSecretID(): string + { + return $this->SecretID; + } + + public function setSecretID(string $SecretID): self + { + $this->SecretID = $SecretID; + return $this; + } + + public function getDescription(): string + { + return $this->Description; + } + + public function setDescription(string $Description): self + { + $this->Description = $Description; + return $this; + } + + /** + * @return \DCarbone\PHPConsulAPI\ACL\ACLTokenPolicyLink[] + */ + public function getPolicies(): array + { + return $this->Policies; + } + + public function setPolicies(ACLTokenPolicyLink ...$Policies): self + { + $this->Policies = $Policies; + return $this; + } + + /** + * @return \DCarbone\PHPConsulAPI\ACL\ACLTokenRoleLink[] + */ + public function getRoles(): array + { + return $this->Roles; + } + + public function setRoles(ACLTokenRoleLink ...$Roles): self + { + $this->Roles = $Roles; + return $this; + } + + /** + * @return \DCarbone\PHPConsulAPI\ACL\ACLServiceIdentity[] + */ + public function getServiceIdentities(): array + { + return $this->ServiceIdentities; + } + + public function setServiceIdentities(ACLServiceIdentity ...$ServiceIdentities): self + { + $this->ServiceIdentities = $ServiceIdentities; + return $this; + } + + /** + * @return \DCarbone\PHPConsulAPI\ACL\ACLNodeIdentity[] + */ + public function getNodeIdentities(): array + { + return $this->NodeIdentities; + } + + public function setNodeIdentities(ACLNodeIdentity ...$NodeIdentities): self + { + $this->NodeIdentities = $NodeIdentities; + return $this; + } + + /** + * @return \DCarbone\PHPConsulAPI\ACL\ACLTemplatedPolicy[] + */ + public function getTemplatePolicies(): array + { + return $this->TemplatePolicies; + } + + public function setTemplatePolicies(ACLTemplatedPolicy ...$TemplatePolicies): self + { + $this->TemplatePolicies = $TemplatePolicies; + return $this; + } + + public function isLocal(): bool + { + return $this->Local; + } + + public function setLocal(bool $Local): self + { + $this->Local = $Local; + return $this; + } + + public function getAuthMethod(): string + { + return $this->AuthMethod; + } + + public function setAuthMethod(string $AuthMethod): self + { + $this->AuthMethod = $AuthMethod; + return $this; + } + + public function getExpirationTTL(): Time\Duration + { + return $this->ExpirationTTL; + } + + public function setExpirationTTL(null|int|float|string|\DateInterval|Time\Duration $ExpirationTTL): self + { + $this->ExpirationTTL = Time::Duration($ExpirationTTL); + return $this; + } + + public function getExpirationTime(): null|Time\Time + { + return $this->ExpirationTime; + } + + public function setExpirationTime(null|Time\Time $ExpirationTime): self + { + $this->ExpirationTime = $ExpirationTime; + return $this; + } + + public function getCreateTime(): null|Time\Time + { + return $this->CreateTime; + } + + public function setCreateTime(null|Time\Time $CreateTime): self + { + $this->CreateTime = $CreateTime; + return $this; + } + + public function getHash(): string + { + return $this->Hash; + } + + public function setHash(string $Hash): self + { + $this->Hash = $Hash; + return $this; + } + + public function getNamespace(): string + { + return $this->Namespace; + } + + public function setNamespace(string $Namespace): self + { + $this->Namespace = $Namespace; + return $this; + } + + public function getRules(): string + { + return $this->Rules; + } + + public function setRules(string $Rules): self + { + $this->Rules = $Rules; + return $this; + } + + public function getPartition(): string + { + return $this->Partition; + } + + public function setPartition(string $Partition): self + { + $this->Partition = $Partition; + return $this; + } + + public function getAuthMethodNamespace(): string + { + return $this->AuthMethodNamespace; + } + + public function setAuthMethodNamespace(string $AuthMethodNamespace): self + { + $this->AuthMethodNamespace = $AuthMethodNamespace; + return $this; + } + + protected function _jsonUnserializeField(string $k, mixed $v, object $n): bool + { + if ('Policies' === $k) { + foreach ($v as $vv) { + $n->Policies[] = ACLTokenPolicyLink::jsonUnserialize($vv); + } + } elseif ('Roles' === $k) { + foreach ($v as $vv) { + $n->Roles[] = ACLTokenRoleLink::jsonUnserialize($vv); + } + } elseif ('ServiceIdentities' === $k) { + foreach ($v as $vv) { + $n->ServiceIdentities[] = ACLServiceIdentity::jsonUnserialize($vv); + } + } elseif ('NodeIdentities' === $k) { + foreach ($v as $vv) { + $n->NodeIdentities[] = ACLNodeIdentity::jsonUnserialize($vv); + } + } elseif ('TemplatePolicies' === $k) { + foreach ($v as $vv) { + $n->TemplatePolicies[] = ACLTemplatedPolicy::jsonUnserialize($vv); + } + } elseif ('ExpirationTTL' === $k) { + $n->setExpirationTTL($v); + } elseif ('ExpirationTime' === $k) { + $n->ExpirationTime = (null === $v ? $v : parse_time($v)); + } elseif ('CreateTime' === $k) { + $n->CreateTime = parse_time($v); + } else { + return false; + } + + return true; + } + + protected function _jsonSerialize(\stdClass $out): void + { + $out->CreateIndex = $this->CreateIndex; + $out->ModifyIndex = $this->ModifyIndex; + $out->AccessorID = $this->AccessorID; + $out->SecretID = $this->SecretID; + $out->Description = $this->Description; + if ([] !== $this->Policies) { + $out->Policies = $this->Policies; + } + if ([] !== $this->Roles) { + $out->Roles = $this->Roles; + } + if ([] !== $this->ServiceIdentities) { + $out->ServiceIdentities = $this->ServiceIdentities; + } + if ([] !== $this->NodeIdentities) { + $out->NodeIdentities = $this->NodeIdentities; + } + if ([] !== $this->TemplatePolicies) { + $out->TemplatePolicies = $this->TemplatePolicies; + } + $out->Local = $this->Local; + if ('' !== $this->AuthMethod) { + $out->AuthMethod = $this->AuthMethod; + } + if (0 !== $this->ExpirationTTL->Nanoseconds()) { + $out->ExpirationTTL = $this->ExpirationTTL; + } + if (null !== $this->ExpirationTime) { + $out->ExpirationTime = $this->ExpirationTime->format(DATE_RFC3339); + } + if (null !== $this->CreateTime && !$this->CreateTime->isZero()) { + $out->CreateTime = $this->CreateTime->format(DATE_RFC3339); + } + $out->Hash = $this->Hash; + if ('' !== $this->Rules) { + $out->Rules = $this->Rules; + } + if ('' !== $this->Namespace) { + $out->Namespace = $this->Namespace; + } + if ('' !== $this->Partition) { + $out->Partition = $this->Partition; + } + if ('' !== $this->AuthMethodNamespace) { + $out->AuthMethodNamespace = $this->AuthMethodNamespace; + } + } +} diff --git a/src/ACL/ACLTokenListEntry.php b/src/ACL/ACLTokenListEntry.php index eff21026..3ccedf64 100644 --- a/src/ACL/ACLTokenListEntry.php +++ b/src/ACL/ACLTokenListEntry.php @@ -21,80 +21,84 @@ */ use DCarbone\Go\Time; -use DCarbone\PHPConsulAPI\AbstractModel; -use DCarbone\PHPConsulAPI\Transcoding; +use DCarbone\PHPConsulAPI\PHPLib\AbstractType; +use function DCarbone\PHPConsulAPI\PHPLib\parse_time; -class ACLTokenListEntry extends AbstractModel +class ACLTokenListEntry extends AbstractType { - protected const FIELDS = [ - self::FIELD_POLICIES => [ - Transcoding::FIELD_TYPE => Transcoding::ARRAY, - Transcoding::FIELD_CLASS => ACLTokenPolicyLink::class, - Transcoding::FIELD_ARRAY_TYPE => Transcoding::OBJECT, - Transcoding::FIELD_OMITEMPTY => true, - ], - self::FIELD_ROLES => [ - Transcoding::FIELD_TYPE => Transcoding::ARRAY, - Transcoding::FIELD_CLASS => ACLTokenRoleLink::class, - Transcoding::FIELD_ARRAY_TYPE => Transcoding::OBJECT, - Transcoding::FIELD_OMITEMPTY => true, - ], - self::FIELD_SERVICE_IDENTITIES => [ - Transcoding::FIELD_TYPE => Transcoding::ARRAY, - Transcoding::FIELD_CLASS => ACLServiceIdentity::class, - Transcoding::FIELD_ARRAY_TYPE => Transcoding::OBJECT, - Transcoding::FIELD_OMITEMPTY => true, - ], - self::FIELD_NODE_IDENTITIES => [ - Transcoding::FIELD_TYPE => Transcoding::ARRAY, - Transcoding::FIELD_CLASS => ACLNodeIdentity::class, - Transcoding::FIELD_ARRAY_TYPE => Transcoding::OBJECT, - Transcoding::FIELD_OMITEMPTY => true, - ], - self::FIELD_AUTH_METHOD => Transcoding::OMITEMPTY_STRING_FIELD, - self::FIELD_EXPIRATION_TIME => [ - Transcoding::FIELD_UNMARSHAL_CALLBACK => Transcoding::UNMARSHAL_NULLABLE_TIME, - Transcoding::FIELD_NULLABLE => true, - Transcoding::FIELD_OMITEMPTY => true, - ], - self::FIELD_CREATE_TIME => [ - Transcoding::FIELD_UNMARSHAL_CALLBACK => Transcoding::UNMARSHAL_TIME, - ], - self::FIELD_NAMESPACE => Transcoding::OMITEMPTY_STRING_FIELD, - ]; - - private const FIELD_POLICIES = 'Policies'; - private const FIELD_ROLES = 'Roles'; - private const FIELD_SERVICE_IDENTITIES = 'ServiceIdentities'; - private const FIELD_NODE_IDENTITIES = 'NodeIdentities'; - private const FIELD_AUTH_METHOD = 'AuthMethod'; - private const FIELD_EXPIRATION_TIME = 'ExpirationTime'; - private const FIELD_CREATE_TIME = 'CreateTime'; - private const FIELD_NAMESPACE = 'Namespace'; - - public int $CreateIndex = 0; - public int $ModifyIndex = 0; - public string $AccessorID = ''; - public string $Description = ''; - public array $Policies = []; - public array $Roles = []; - public array $ServiceIdentities = []; - public array $NodeIdentities = []; - public bool $Local = false; - public string $AuthMethod = ''; - public ?Time\Time $ExpirationTime = null; - public Time\Time $CreateTime; - public string $Hash = ''; - public bool $Legacy = false; - public string $Namespace = ''; - - public function __construct(?array $data = null) - { - parent::__construct($data); - if (!isset($this->CreateTime)) { - $this->CreateTime = Time::New(); - } - } + public int $CreateIndex; + public int $ModifyIndex; + public string $AccessorID; + public string $SecretID; + public string $Description; + /** @var array<\DCarbone\PHPConsulAPI\ACL\ACLTokenPolicyLink> */ + public array $Policies; + /** @var array<\DCarbone\PHPConsulAPI\ACL\ACLTokenRoleLink> */ + public array $Roles; + /** @var array<\DCarbone\PHPConsulAPI\ACL\ACLServiceIdentity> */ + public array $ServiceIdentities; + /** @var array<\DCarbone\PHPConsulAPI\ACL\ACLNodeIdentity> */ + public array $NodeIdentities; + /** @var array<\DCarbone\PHPConsulAPI\ACL\ACLTemplatedPolicy> */ + public array $TemplatedPolicies; + public bool $Local; + public string $AuthMethod; + public null|Time\Time $ExpirationTime = null; + public null|Time\Time $CreateTime; + public string $Hash; + public bool $Legacy; + public string $Namespace; + public string $Partition; + public string $AuthMethodNamespace; + + /** + * @param array<\DCarbone\PHPConsulAPI\ACL\ACLTokenPolicyLink> $Policies + * @param array<\DCarbone\PHPConsulAPI\ACL\ACLTokenRoleLink> $Roles + * @param array<\DCarbone\PHPConsulAPI\ACL\ACLServiceIdentity> $ServiceIdentities + * @param array<\DCarbone\PHPConsulAPI\ACL\ACLNodeIdentity> $NodeIdentities + * @param array<\DCarbone\PHPConsulAPI\ACL\ACLTemplatedPolicy> $TemplatedPolicies + */ + public function __construct( + int $CreateIndex = 0, + int $ModifyIndex = 0, + string $AccessorID = '', + string $SecretID = '', + string $Description = '', + array $Policies = [], + array $Roles = [], + array $ServiceIdentities = [], + array $NodeIdentities = [], + array $TemplatedPolicies = [], + bool $Local = false, + string $AuthMethod = '', + null|Time\Time $ExpirationTime = null, + null|Time\Time $CreateTime = null, + string $Hash = '', + bool $Legacy = false, + string $Namespace = '', + string $Partition = '', + string $AuthMethodNamespace = '', + ) { + $this->CreateIndex = $CreateIndex; + $this->ModifyIndex = $ModifyIndex; + $this->AccessorID = $AccessorID; + $this->SecretID = $SecretID; + $this->Description = $Description; + $this->setPolicies(...$Policies); + $this->setRoles(...$Roles); + $this->setServiceIdentities(...$ServiceIdentities); + $this->setNodeIdentities(...$NodeIdentities); + $this->setTemplatedPolicies(...$TemplatedPolicies); + $this->Local = $Local; + $this->AuthMethod = $AuthMethod; + $this->setExpirationTime($ExpirationTime); + $this->CreateTime = $CreateTime ?? Time::New(); + $this->Hash = $Hash; + $this->Legacy = $Legacy; + $this->Namespace = $Namespace; + $this->Partition = $Partition; + $this->AuthMethodNamespace = $AuthMethodNamespace; +} public function getCreateIndex(): int { @@ -129,6 +133,17 @@ public function setAccessorID(string $AccessorID): self return $this; } + public function getSecretID(): string + { + return $this->SecretID; + } + + public function setSecretID(string $SecretID): self + { + $this->SecretID = $SecretID; + return $this; + } + public function getDescription(): string { return $this->Description; @@ -140,50 +155,76 @@ public function setDescription(string $Description): self return $this; } + /** + * @return \DCarbone\PHPConsulAPI\ACL\ACLTokenPolicyLink[] + */ public function getPolicies(): array { return $this->Policies; } - public function setPolicies(array $Policies): self + public function setPolicies(ACLTokenPolicyLink ...$Policies): self { $this->Policies = $Policies; return $this; } + /** + * @return \DCarbone\PHPConsulAPI\ACL\ACLTokenRoleLink[] + */ public function getRoles(): array { return $this->Roles; } - public function setRoles(array $Roles): self + public function setRoles(ACLTokenRoleLink ...$Roles): self { $this->Roles = $Roles; return $this; } + /** + * @return \DCarbone\PHPConsulAPI\ACL\ACLServiceIdentity[] + */ public function getServiceIdentities(): array { return $this->ServiceIdentities; } - public function setServiceIdentities(array $ServiceIdentities): self + public function setServiceIdentities(ACLServiceIdentity ...$ServiceIdentities): self { $this->ServiceIdentities = $ServiceIdentities; return $this; } + /** + * @return \DCarbone\PHPConsulAPI\ACL\ACLNodeIdentity[] + */ public function getNodeIdentities(): array { return $this->NodeIdentities; } - public function setNodeIdentities(array $NodeIdentities): self + public function setNodeIdentities(ACLNodeIdentity ...$NodeIdentities): self { $this->NodeIdentities = $NodeIdentities; return $this; } + /** + * @return \DCarbone\PHPConsulAPI\ACL\ACLTemplatedPolicy[] + */ + public function getTemplatedPolicies(): array + { + return $this->TemplatedPolicies; + } + + public function setTemplatedPolicies(ACLTemplatedPolicy ...$TemplatedPolicies): self + { + $this->TemplatedPolicies = $TemplatedPolicies; + return $this; + } + public function isLocal(): bool { return $this->Local; @@ -206,23 +247,23 @@ public function setAuthMethod(string $AuthMethod): self return $this; } - public function getExpirationTime(): ?Time\Time + public function getExpirationTime(): null|Time\Time { return $this->ExpirationTime; } - public function setExpirationTime(?Time\Time $ExpirationTime): self + public function setExpirationTime(null|Time\Time $ExpirationTime): self { $this->ExpirationTime = $ExpirationTime; return $this; } - public function getCreateTime(): Time\Time + public function getCreateTime(): null|Time\Time { return $this->CreateTime; } - public function setCreateTime(Time\Time $CreateTime): self + public function setCreateTime(null|Time\Time $CreateTime): self { $this->CreateTime = $CreateTime; return $this; @@ -260,4 +301,107 @@ public function setNamespace(string $Namespace): self $this->Namespace = $Namespace; return $this; } + + public function getPartition(): string + { + return $this->Partition; + } + + public function setPartition(string $Partition): self + { + $this->Partition = $Partition; + return $this; + } + + public function getAuthMethodNamespace(): string + { + return $this->AuthMethodNamespace; + } + + public function setAuthMethodNamespace(string $AuthMethodNamespace): self + { + $this->AuthMethodNamespace = $AuthMethodNamespace; + return $this; + } + + public static function jsonUnserialize(\stdClass $decoded): self + { + $n = new self(); + foreach ((array)$decoded as $k => $v) { + if ('Policies' === $k) { + foreach ($v as $vv) { + $n->Policies[] = ACLTokenPolicyLink::jsonUnserialize($vv); + } + } elseif ('Roles' === $k) { + foreach ($v as $vv) { + $n->Roles[] = ACLTokenRoleLink::jsonUnserialize($vv); + } + } elseif ('ServiceIdentities' === $k) { + foreach ($v as $vv) { + $n->ServiceIdentities[] = ACLServiceIdentity::jsonUnserialize($vv); + } + } elseif ('NodeIdentities' === $k) { + foreach ($v as $vv) { + $n->NodeIdentities[] = ACLNodeIdentity::jsonUnserialize($vv); + } + } elseif ('TemplatedPolicies' === $k) { + foreach ($v as $vv) { + $n->TemplatedPolicies[] = ACLTemplatedPolicy::jsonUnserialize($vv); + } + } elseif ('ExpirationTime' === $k) { + $n->ExpirationTime = (null === $v ? null : parse_time($v)); + } elseif ('CreateTime' === $k) { + $n->CreateTime = parse_time($v); + } else { + $n->{$k} = $v; + } + } + return $n; + } + + public function jsonSerialize(): \stdClass + { + $out = $this->_startJsonSerialize(); + $out->CreateIndex = $this->CreateIndex; + $out->ModifyIndex = $this->ModifyIndex; + $out->AccessorID = $this->AccessorID; + $out->SecretID = $this->SecretID; + $out->Description = $this->Description; + if ([] !== $this->Policies) { + $out->Policies = $this->Policies; + } + if ([] !== $this->Roles) { + $out->Roles = $this->Roles; + } + if ([] !== $this->ServiceIdentities) { + $out->ServiceIdentities = $this->ServiceIdentities; + } + if ([] !== $this->NodeIdentities) { + $out->NodeIdentities = $this->NodeIdentities; + } + if ([] !== $this->TemplatedPolicies) { + $out->TemplatedPolicies = $this->TemplatedPolicies; + } + $out->Local = $this->Local; + if ('' !== $this->AuthMethod) { + $out->AuthMethod = $this->AuthMethod; + } + if (null !== $this->ExpirationTime) { + $out->ExpirationTime = $this->ExpirationTime->format(DATE_RFC3339); + } + if (null !== $this->CreateTime) { + $out->CreateTime = $this->CreateTime->format(DATE_RFC3339); + } + $out->Hash = $this->Hash; + if ('' !== $this->Namespace) { + $out->Namespace = $this->Namespace; + } + if ('' !== $this->Partition) { + $out->Partition = $this->Partition; + } + if ('' !== $this->AuthMethodNamespace) { + $out->AuthMethodNamespace = $this->AuthMethodNamespace; + } + return $out; + } } diff --git a/src/ACL/ACLTokenListEntryQueryResponse.php b/src/ACL/ACLTokenListEntryQueryResponse.php index 529e314b..8ecebb6e 100644 --- a/src/ACL/ACLTokenListEntryQueryResponse.php +++ b/src/ACL/ACLTokenListEntryQueryResponse.php @@ -20,23 +20,27 @@ limitations under the License. */ -use DCarbone\PHPConsulAPI\AbstractValuedQueryResponse; -use DCarbone\PHPConsulAPI\UnmarshalledResponseInterface; +use DCarbone\PHPConsulAPI\PHPLib\AbstractValuedQueryResponse; +use DCarbone\PHPConsulAPI\PHPLib\UnmarshalledResponseInterface; class ACLTokenListEntryQueryResponse extends AbstractValuedQueryResponse implements UnmarshalledResponseInterface { - public ?array $ACLTokenListEntries = []; + /** @var \DCarbone\PHPConsulAPI\ACL\ACLTokenListEntry[] */ + public array $ACLTokenListEntries = []; - public function getValue(): ?array + /** + * @return \DCarbone\PHPConsulAPI\ACL\ACLTokenListEntry[] + */ + public function getValue(): array { return $this->ACLTokenListEntries; } - public function unmarshalValue(mixed $decodedData): void + public function unmarshalValue(mixed $decoded): void { $this->ACLTokenListEntries = []; - foreach ($decodedData as $datum) { - $this->ACLTokenListEntries[] = new ACLTokenListEntry($datum); + foreach ($decoded as $datum) { + $this->ACLTokenListEntries[] = ACLTokenListEntry::jsonUnserialize($datum); } } } diff --git a/src/ACL/ACLTokenPolicyLink.php b/src/ACL/ACLTokenPolicyLink.php index 5cc163c0..f09beb3a 100644 --- a/src/ACL/ACLTokenPolicyLink.php +++ b/src/ACL/ACLTokenPolicyLink.php @@ -22,4 +22,12 @@ class ACLTokenPolicyLink extends ACLLink { + public static function jsonUnserialize(\stdClass $decoded): self + { + $n = new self(); + foreach ((array)$decoded as $k => $v) { + $n->{$k} = $v; + } + return $n; + } } diff --git a/src/ACL/ACLTokenQueryResponse.php b/src/ACL/ACLTokenQueryResponse.php index 5092f215..1c72a9bc 100644 --- a/src/ACL/ACLTokenQueryResponse.php +++ b/src/ACL/ACLTokenQueryResponse.php @@ -20,20 +20,24 @@ limitations under the License. */ -use DCarbone\PHPConsulAPI\AbstractValuedQueryResponse; -use DCarbone\PHPConsulAPI\UnmarshalledResponseInterface; +use DCarbone\PHPConsulAPI\PHPLib\AbstractValuedQueryResponse; +use DCarbone\PHPConsulAPI\PHPLib\UnmarshalledResponseInterface; class ACLTokenQueryResponse extends AbstractValuedQueryResponse implements UnmarshalledResponseInterface { - public ?ACLToken $ACLToken = null; + public null|ACLToken $ACLToken = null; - public function getValue(): ?ACLToken + public function getValue(): null|ACLToken { return $this->ACLToken; } - public function unmarshalValue(mixed $decodedData): void + public function unmarshalValue(mixed $decoded): void { - $this->ACLToken = new ACLToken((array)$decodedData); + if (null === $decoded) { + $this->ACLToken = null; + return; + } + $this->ACLToken = ACLToken::jsonUnserialize($decoded); } } diff --git a/src/ACL/ACLTokenRoleLink.php b/src/ACL/ACLTokenRoleLink.php index 22133f1d..f5b96b89 100644 --- a/src/ACL/ACLTokenRoleLink.php +++ b/src/ACL/ACLTokenRoleLink.php @@ -22,4 +22,12 @@ class ACLTokenRoleLink extends ACLLink { + public static function jsonUnserialize(\stdClass $decoded): self + { + $n = new self(); + foreach ((array)$decoded as $k => $v) { + $n->{$k} = $v; + } + return $n; + } } diff --git a/src/ACL/ACLTokenWriteResponse.php b/src/ACL/ACLTokenWriteResponse.php index 1a1a4d91..55ad8ce2 100644 --- a/src/ACL/ACLTokenWriteResponse.php +++ b/src/ACL/ACLTokenWriteResponse.php @@ -20,20 +20,24 @@ limitations under the License. */ -use DCarbone\PHPConsulAPI\AbstractValuedWriteResponse; -use DCarbone\PHPConsulAPI\UnmarshalledResponseInterface; +use DCarbone\PHPConsulAPI\PHPLib\AbstractValuedWriteResponse; +use DCarbone\PHPConsulAPI\PHPLib\UnmarshalledResponseInterface; class ACLTokenWriteResponse extends AbstractValuedWriteResponse implements UnmarshalledResponseInterface { - public ?ACLToken $ACLToken = null; + public null|ACLToken $ACLToken = null; - public function getValue(): ?ACLToken + public function getValue(): null|ACLToken { return $this->ACLToken; } - public function unmarshalValue(mixed $decodedData): void + public function unmarshalValue(mixed $decoded): void { - $this->ACLToken = new ACLToken((array)$decodedData); + if (null === $decoded) { + $this->ACLToken = null; + return; + } + $this->ACLToken = ACLToken::jsonUnserialize($decoded); } } diff --git a/src/ACL/BindingRuleBindType.php b/src/ACL/BindingRuleBindType.php new file mode 100644 index 00000000..d42ece3c --- /dev/null +++ b/src/ACL/BindingRuleBindType.php @@ -0,0 +1,32 @@ + Transcoding::OMITEMPTY_STRING_FIELD, - self::FIELD_CA_CERT => Transcoding::OMITEMPTY_STRING_FIELD, - self::FIELD_SERVICE_ACCOUNT_JWT => Transcoding::OMITEMPTY_STRING_FIELD, - ]; + public string $Host; + public string $CACert; + public string $ServiceAccountJWT; - private const FIELD_HOST = 'Host'; - private const FIELD_CA_CERT = 'CACert'; - private const FIELD_SERVICE_ACCOUNT_JWT = 'ServiceAccountJWT'; - - public string $Host = ''; - public string $CACert = ''; - public string $ServiceAccountJWT = ''; + public function __construct(string $Host = '', string $CACert = '', string $ServiceAccountJWT = '') + { + $this->Host = $Host; + $this->CACert = $CACert; + $this->ServiceAccountJWT = $ServiceAccountJWT; + } public function getHost(): string { @@ -77,16 +72,38 @@ public function setServiceAccountJWT(string $ServiceAccountJWT): self * RenderToConfig converts this into a map[string]interface{} suitable for use * in the ACLAuthMethod.Config field. * - * @return \DCarbone\PHPConsulAPI\FakeMap + * @return array */ - public function RenderToConfig(): FakeMap + public function RenderToConfig(): array + { + return [ + 'Host' => $this->Host, + 'CACert' => $this->CACert, + 'ServiceAccountJWT' => $this->ServiceAccountJWT, + ]; + } + + public static function jsonUnserialize(\stdClass $decoded): self + { + $n = new self(); + foreach ((array)$decoded as $k => $v) { + $n->{$k} = $v; + } + return $n; + } + + public function jsonSerialize(): \stdClass { - return new FakeMap( - [ - self::FIELD_HOST => $this->Host, - self::FIELD_CA_CERT => $this->CACert, - self::FIELD_SERVICE_ACCOUNT_JWT => $this->ServiceAccountJWT, - ] - ); + $out = $this->_startJsonSerialize(); + if ('' !== $this->Host) { + $out->Host = $this->Host; + } + if ('' !== $this->CACert) { + $out->CACert = $this->CACert; + } + if ('' !== $this->ServiceAccountJWT) { + $out->ServiceAccountJWT = $this->ServiceAccountJWT; + } + return $out; } } diff --git a/src/ACL/OIDCAuthMethodConfig.php b/src/ACL/OIDCAuthMethodConfig.php index d8568659..a2ee0114 100644 --- a/src/ACL/OIDCAuthMethodConfig.php +++ b/src/ACL/OIDCAuthMethodConfig.php @@ -20,8 +20,448 @@ limitations under the License. */ -use DCarbone\PHPConsulAPI\AbstractModel; +use DCarbone\Go\Time; +use DCarbone\PHPConsulAPI\PHPLib\AbstractType; -class OIDCAuthMethodConfig extends AbstractModel +class OIDCAuthMethodConfig extends AbstractType { + /** @var array */ + public array $JWTSupportedAlgs; + /** @var array */ + public array $BoundAudiences; + /** @var array */ + public array $ClaimMappings; + /** @var array */ + public array $ListClaimMappings; + public string $OIDCDiscoveryURL; + public string $OIDCDiscoveryCACert; + public string $OIDCClientID; + public string $OIDCClientSecret; + /** @var array */ + public array $OIDCScopes; + /** @var array */ + public array $OIDCACRValues; + /** @var array */ + public array $AllowedRedirectURIs; + public bool $VerboseOIDCLogging; + public string $JWKSURL; + public string $JWKSCACert; + /** @var array */ + public array $JWTValidationPubKeys; + public string $BoundIssuer; + public Time\Duration $ExpirationLeeway; + public Time\Duration $NotBeforeLeeway; + public Time\Duration $ClockSkewLeeway; + + /** + * @param array $JWTSupportedAlgs + * @param array $BoundAudiences + * @param array $ClaimMappings + * @param array $ListClaimMappings + * @param array $OIDCScopes + * @param array $OIDCACRValues + * @param array $AllowedRedirectURIs + * @param array $JWTValidationPubKeys + */ + public function __construct( + array $JWTSupportedAlgs = [], + array $BoundAudiences = [], + array $ClaimMappings = [], + array $ListClaimMappings = [], + string $OIDCDiscoveryURL = '', + string $OIDCDiscoveryCACert = '', + string $OIDCClientID = '', + string $OIDCClientSecret = '', + array $OIDCScopes = [], + array $OIDCACRValues = [], + array $AllowedRedirectURIs = [], + bool $VerboseOIDCLogging = false, + string $JWKSURL = '', + string $JWKSCACert = '', + array $JWTValidationPubKeys = [], + string $BoundIssuer = '', + null|int|float|string|\DateInterval|Time\Duration $ExpirationLeeway = null, + null|int|float|string|\DateInterval|Time\Duration $NotBeforeLeeway = null, + null|int|float|string|\DateInterval|Time\Duration $ClockSkewLeeway = null, + ) { + $this->setJWTSupportedAlgs(...$JWTSupportedAlgs); + $this->setBoundAudiences(...$BoundAudiences); + $this->setClaimMappings($ClaimMappings); + $this->setListClaimMappings($ListClaimMappings); + $this->OIDCDiscoveryURL = $OIDCDiscoveryURL; + $this->OIDCDiscoveryCACert = $OIDCDiscoveryCACert; + $this->OIDCClientID = $OIDCClientID; + $this->OIDCClientSecret = $OIDCClientSecret; + $this->setOIDCScopes(...$OIDCScopes); + $this->setOIDCACRValues(...$OIDCACRValues); + $this->setAllowedRedirectURIs(...$AllowedRedirectURIs); + $this->VerboseOIDCLogging = $VerboseOIDCLogging; + $this->JWKSURL = $JWKSURL; + $this->JWKSCACert = $JWKSCACert; + $this->setJWTValidationPubKeys(...$JWTValidationPubKeys); + $this->BoundIssuer = $BoundIssuer; + $this->setExpirationLeeway($ExpirationLeeway); + $this->setNotBeforeLeeway($NotBeforeLeeway); + $this->setClockSkewLeeway($ClockSkewLeeway); + } + + /** + * @return array + */ + public function getJWTSupportedAlgs(): array + { + return $this->JWTSupportedAlgs; + } + + public function setJWTSupportedAlgs(string ...$JWTSupportedAlgs): self + { + $this->JWTSupportedAlgs = $JWTSupportedAlgs; + return $this; + } + + /** + * @return array + */ + public function getBoundAudiences(): array + { + return $this->BoundAudiences; + } + + public function setBoundAudiences(string ...$BoundAudiences): self + { + $this->BoundAudiences = $BoundAudiences; + return $this; + } + + /** + * @return array + */ + public function getClaimMappings(): array + { + return $this->ClaimMappings; + } + + public function setClaimMapping(string $k, string $v): self + { + $this->ClaimMappings[$k] = $v; + return $this; + } + + /** + * @param array|\stdClass|null $ClaimMappings + */ + public function setClaimMappings(null|array|\stdClass $ClaimMappings): self + { + $this->ClaimMappings = []; + if (null === $ClaimMappings) { + return $this; + } + foreach ($ClaimMappings as $k => $v) { + $this->setClaimMapping($k, $v); + } + return $this; + } + + /** + * @return array + */ + public function getListClaimMappings(): array + { + return $this->ListClaimMappings; + } + + public function setListClaimMapping(string $k, string $v): self + { + $this->ListClaimMappings[$k] = $v; + return $this; + } + + /** + * @param array|\stdClass|null $ListClaimMappings + */ + public function setListClaimMappings(null|array|\stdClass $ListClaimMappings): self + { + $this->ListClaimMappings = []; + if (null === $ListClaimMappings) { + return $this; + } + foreach ($ListClaimMappings as $k => $v) { + $this->setListClaimMapping($k, $v); + } + return $this; + } + + public function getOIDCDiscoveryURL(): string + { + return $this->OIDCDiscoveryURL; + } + + public function setOIDCDiscoveryURL(string $OIDCDiscoveryURL): self + { + $this->OIDCDiscoveryURL = $OIDCDiscoveryURL; + return $this; + } + + public function getOIDCDiscoveryCACert(): string + { + return $this->OIDCDiscoveryCACert; + } + + public function setOIDCDiscoveryCACert(string $OIDCDiscoveryCACert): self + { + $this->OIDCDiscoveryCACert = $OIDCDiscoveryCACert; + return $this; + } + + public function getOIDCClientID(): string + { + return $this->OIDCClientID; + } + + public function setOIDCClientID(string $OIDCClientID): self + { + $this->OIDCClientID = $OIDCClientID; + return $this; + } + + public function getOIDCClientSecret(): string + { + return $this->OIDCClientSecret; + } + + public function setOIDCClientSecret(string $OIDCClientSecret): self + { + $this->OIDCClientSecret = $OIDCClientSecret; + return $this; + } + + /** + * @return array + */ + public function getOIDCScopes(): array + { + return $this->OIDCScopes; + } + + public function setOIDCScopes(string ...$OIDCScopes): self + { + $this->OIDCScopes = $OIDCScopes; + return $this; + } + + /** + * @return array + */ + public function getOIDCACRValues(): array + { + return $this->OIDCACRValues; + } + + public function setOIDCACRValues(string ...$OIDCACRValues): self + { + $this->OIDCACRValues = $OIDCACRValues; + return $this; + } + + /** + * @return array + */ + public function getAllowedRedirectURIs(): array + { + return $this->AllowedRedirectURIs; + } + + public function setAllowedRedirectURIs(string ...$AllowedRedirectURIs): self + { + $this->AllowedRedirectURIs = $AllowedRedirectURIs; + return $this; + } + + public function isVerboseOIDCLogging(): bool + { + return $this->VerboseOIDCLogging; + } + + public function setVerboseOIDCLogging(bool $VerboseOIDCLogging): self + { + $this->VerboseOIDCLogging = $VerboseOIDCLogging; + return $this; + } + + public function getJWKSURL(): string + { + return $this->JWKSURL; + } + + public function setJWKSURL(string $JWKSURL): self + { + $this->JWKSURL = $JWKSURL; + return $this; + } + + public function getJWKSCACert(): string + { + return $this->JWKSCACert; + } + + public function setJWKSCACert(string $JWKSCACert): self + { + $this->JWKSCACert = $JWKSCACert; + return $this; + } + + /** + * @return array + */ + public function getJWTValidationPubKeys(): array + { + return $this->JWTValidationPubKeys; + } + + public function setJWTValidationPubKeys(string ...$JWTValidationPubKeys): self + { + $this->JWTValidationPubKeys = $JWTValidationPubKeys; + return $this; + } + + public function getBoundIssuer(): string + { + return $this->BoundIssuer; + } + + public function setBoundIssuer(string $BoundIssuer): self + { + $this->BoundIssuer = $BoundIssuer; + return $this; + } + + public function getExpirationLeeway(): Time\Duration + { + return $this->ExpirationLeeway; + } + + public function setExpirationLeeway(null|int|float|string|\DateInterval|Time\Duration $ExpirationLeeway): self + { + $this->ExpirationLeeway = Time::Duration($ExpirationLeeway); + return $this; + } + + public function getNotBeforeLeeway(): Time\Duration + { + return $this->NotBeforeLeeway; + } + + public function setNotBeforeLeeway(null|int|float|string|\DateInterval|Time\Duration $NotBeforeLeeway): self + { + $this->NotBeforeLeeway = Time::Duration($NotBeforeLeeway); + return $this; + } + + public function getClockSkewLeeway(): Time\Duration + { + return $this->ClockSkewLeeway; + } + + public function setClockSkewLeeway(null|int|float|string|\DateInterval|Time\Duration $ClockSkewLeeway): self + { + $this->ClockSkewLeeway = Time::Duration($ClockSkewLeeway); + return $this; + } + + public static function jsonUnserialize(\stdClass $decoded): self + { + $n = new self(); + foreach ((array)$decoded as $k => $v) { + if ('JWTSupportedAlgs' === $k) { + $n->setJWTSupportedAlgs(...$v); + } elseif ('BoundAudiences' === $k) { + $n->setBoundAudiences(...$v); + } elseif ('ClaimMappings' === $k) { + $n->setClaimMappings($v); + } elseif ('ListClaimMappings' === $k) { + $n->setListClaimMappings($v); + } elseif ('OIDCScopes' === $k) { + $n->setOIDCScopes(...$v); + } elseif ('OIDCACRValues' === $k) { + $n->setOIDCACRValues(...$v); + } elseif ('AllowedRedirectURIs' === $k) { + $n->setAllowedRedirectURIs(...$v); + } elseif ('JWTValidationPubKeys' === $k) { + $n->setJWTValidationPubKeys(...$v); + } elseif ('ExpirationLeeway' === $k) { + $n->setExpirationLeeway($v); + } elseif ('NotBeforeLeeway' === $k) { + $n->setNotBeforeLeeway($v); + } elseif ('ClockSkewLeeway' === $k) { + $n->setClockSkewLeeway($v); + } else { + $n->{$k} = $v; + } + } + return $n; + } + + public function jsonSerialize(): \stdClass + { + $out = $this->_startJsonSerialize(); + + if ([] !== $this->JWTSupportedAlgs) { + $out->JWTSupportedAlgs = $this->JWTSupportedAlgs; + } + if ([] !== $this->BoundAudiences) { + $out->BoundAudiences = $this->BoundAudiences; + } + if ([] !== $this->ClaimMappings) { + $out->ClaimMappings = $this->ClaimMappings; + } + if ([] !== $this->ListClaimMappings) { + $out->ListClaimMappings = $this->ListClaimMappings; + } + if ('' !== $this->OIDCDiscoveryURL) { + $out->OIDCDiscoveryURL = $this->OIDCDiscoveryURL; + } + if ('' !== $this->OIDCDiscoveryCACert) { + $out->OIDCDiscoveryCACert = $this->OIDCDiscoveryCACert; + } + if ('' !== $this->OIDCClientID) { + $out->OIDCClientID = $this->OIDCClientID; + } + if ('' !== $this->OIDCClientSecret) { + $out->OIDCClientSecret = $this->OIDCClientSecret; + } + if ([] !== $this->OIDCScopes) { + $out->OIDCScopes = $this->OIDCScopes; + } + if ([] !== $this->OIDCACRValues) { + $out->OIDCACRValues = $this->OIDCACRValues; + } + if ([] !== $this->AllowedRedirectURIs) { + $out->AllowedRedirectURIs = $this->AllowedRedirectURIs; + } + if ($this->VerboseOIDCLogging) { + $out->VerboseOIDCLogging = $this->VerboseOIDCLogging; + } + if ('' !== $this->JWKSURL) { + $out->JWKSURL = $this->JWKSURL; + } + if ('' !== $this->JWKSCACert) { + $out->JWKSCACert = $this->JWKSCACert; + } + if ([] !== $this->JWTValidationPubKeys) { + $out->JWTValidationPubKeys = $this->JWTValidationPubKeys; + } + if ('' !== $this->BoundIssuer) { + $out->BoundIssuer = $this->BoundIssuer; + } + if (0 !== $this->ExpirationLeeway->Nanoseconds()) { + $out->ExpirationLeeway = $this->ExpirationLeeway; + } + if (0 !== $this->NotBeforeLeeway->Nanoseconds()) { + $out->NotBeforeLeeway = $this->NotBeforeLeeway; + } + if (0 !== $this->ClockSkewLeeway->Nanoseconds()) { + $out->ClockSkewLeeway = $this->ClockSkewLeeway; + } + return $out; + } } diff --git a/src/AbstractModel.php b/src/AbstractModel.php deleted file mode 100644 index d38bae8b..00000000 --- a/src/AbstractModel.php +++ /dev/null @@ -1,93 +0,0 @@ - $value) { - $this->unmarshalField($field, $value); - } - } - - public function __set(string $field, $value): void - { - $this->_dyn[$field] = $value; - } - - public function &__get(string $field) - { - if (!array_key_exists($field, $this->_dyn)) { - $this->_dyn[$field] = null; - } - return $this->_dyn[$field]; - } - - /** - * todo: this picks up non-public fields. externalize this at some point. - * - * @return array - */ - public function jsonSerialize(): array - { - $out = []; - // marshal fields - foreach ((array)$this as $field => $value) { - // marshal dynamically defined fields - // todo: this is crap. - if (substr($field, -4) === '_dyn') { - if ([] !== $value) { - foreach ($value as $k => $v) { - $this->marshalField($out, $k, $v); - } - } - } else { - $this->marshalField($out, $field, $value); - } - } - return $out; - } - - public function __toString(): string - { - return static::class; - } -} diff --git a/src/Agent/AgentCheck.php b/src/Agent/AgentCheck.php index 55235175..564cadac 100644 --- a/src/Agent/AgentCheck.php +++ b/src/Agent/AgentCheck.php @@ -20,42 +20,51 @@ limitations under the License. */ -use DCarbone\PHPConsulAPI\AbstractModel; use DCarbone\PHPConsulAPI\Health\HealthCheckDefinition; -use DCarbone\PHPConsulAPI\Transcoding; +use DCarbone\PHPConsulAPI\PHPLib\AbstractType; -class AgentCheck extends AbstractModel +class AgentCheck extends AbstractType { - protected const FIELDS = [ - self::FIELD_DEFINITION => [ - Transcoding::FIELD_TYPE => Transcoding::OBJECT, - Transcoding::FIELD_CLASS => HealthCheckDefinition::class, - ], - self::FIELD_NAMESPACE => Transcoding::OMITEMPTY_STRING_FIELD, - ]; - - private const FIELD_DEFINITION = 'Definition'; - private const FIELD_NAMESPACE = 'Namespace'; - - public string $Node = ''; - public string $CheckID = ''; - public string $Name = ''; - public string $Status = ''; - public string $Notes = ''; - public string $Output = ''; - public string $ServiceID = ''; - public string $ServiceName = ''; - public string $Type = ''; + public string $Node; + public string $CheckID; + public string $Name; + public string $Status; + public string $Notes; + public string $Output; + public string $ServiceID; + public string $ServiceName; + public string $Type; public HealthCheckDefinition $Definition; - public string $Namespace = ''; - - public function __construct(?array $data = null) - { - parent::__construct($data); - if (!isset($this->Definition)) { - $this->Definition = new HealthCheckDefinition(null); - } - } + public string $Namespace; + public string $Partition; + + public function __construct( + string $Node = '', + string $CheckID = '', + string $Name = '', + string $Status = '', + string $Notes = '', + string $Output = '', + string $ServiceID = '', + string $ServiceName = '', + string $Type = '', + null|HealthCheckDefinition $Definition = null, + string $Namespace = '', + string $Partition = '', + ) { + $this->Node = $Node; + $this->CheckID = $CheckID; + $this->Name = $Name; + $this->Status = $Status; + $this->Notes = $Notes; + $this->Output = $Output; + $this->ServiceID = $ServiceID; + $this->ServiceName = $ServiceName; + $this->Type = $Type; + $this->Definition = $Definition ?? new HealthCheckDefinition(); + $this->Namespace = $Namespace; + $this->Partition = $Partition; +} public function getNode(): string { @@ -177,6 +186,42 @@ public function setNamespace(string $Namespace): self $this->Namespace = $Namespace; return $this; } + + public static function jsonUnserialize(\stdClass $decoded): self + { + $n = new self(); + foreach ((array)$decoded as $k => $v) { + if ('Definition' === $k) { + $n->Definition = HealthCheckDefinition::jsonUnserialize($v); + } else { + $n->{$k} = $v; + } + } + return $n; + } + + public function jsonSerialize(): \stdClass + { + $out = $this->_startJsonSerialize(); + $out->Node = $this->Node; + $out->CheckID = $this->CheckID; + $out->Name = $this->Name; + $out->Status = $this->Status; + $out->Notes = $this->Notes; + $out->Output = $this->Output; + $out->ServiceID = $this->ServiceID; + $out->ServiceName = $this->ServiceName; + $out->Type = $this->Type; + $out->Definition = $this->Definition; + if ('' !== $this->Namespace) { + $out->Namespace = $this->Namespace; + } + if ('' !== $this->Partition) { + $out->Partition = $this->Partition; + } + return $out; + } + public function __toString(): string { return $this->CheckID; diff --git a/src/Agent/AgentCheckRegistration.php b/src/Agent/AgentCheckRegistration.php index 0a2210f0..e4c8a0e5 100644 --- a/src/Agent/AgentCheckRegistration.php +++ b/src/Agent/AgentCheckRegistration.php @@ -20,23 +20,79 @@ limitations under the License. */ -use DCarbone\PHPConsulAPI\Transcoding; +use DCarbone\PHPConsulAPI\PHPLib\Values; class AgentCheckRegistration extends AgentServiceCheck { - protected const FIELDS = [ - self::FIELD_ID => Transcoding::OMITEMPTY_STRING_FIELD, - self::FIELD_SERVICE_ID => Transcoding::OMITEMPTY_STRING_FIELD, - self::FIELD_NAMESPACE => Transcoding::OMITEMPTY_STRING_FIELD, - ]; - - private const FIELD_ID = 'ID'; - private const FIELD_SERVICE_ID = 'ServiceID'; - private const FIELD_NAMESPACE = 'Namespace'; - - public string $ID = ''; - public string $ServiceID = ''; - public string $Namespace = ''; + public string $ID; + public string $ServiceID; + public string $Namespace; + public string $Partition; + + /** + * @param array $Args + */ + public function __construct( + string $ID = '', + string $ServiceID = '', + string $CheckID = '', + string $Name = '', + array $Args = [], + string $DockerContainerID = '', + string $Shell = '', + string $Interval = '', + string $Timeout = '', + string $TTL = '', + string $HTTP = '', + null|\stdClass|array|Values $Header = null, + string $Method = '', + string $TCP = '', + string $Status = '', + string $Notes = '', + bool $TLSSkipVerify = false, + string $GRPC = '', + bool $GRPCUseTLS = false, + string $H2PING = '', + bool $H2PingUseTLS = false, + string $AliasNode = '', + string $AliasService = '', + int $SuccessBeforePassing = 0, + int $FailuresBeforeCritical = 0, + string $DeregisterCriticalServiceAfter = '', + string $Namespace = '', + string $Partition = '', + ) { + parent::__construct( + CheckID: $CheckID, + Name: $Name, + Args: $Args, + DockerContainerID: $DockerContainerID, + Shell: $Shell, + Interval: $Interval, + Timeout: $Timeout, + TTL: $TTL, + HTTP: $HTTP, + Header: $Header, + Method: $Method, + TCP: $TCP, + Status: $Status, + Notes: $Notes, + TLSSkipVerify: $TLSSkipVerify, + GRPC: $GRPC, + GRPCUseTLS: $GRPCUseTLS, + H2PING: $H2PING, + H2PINGUseTLS: $H2PingUseTLS, + AliasNode: $AliasNode, + AliasService: $AliasService, + SuccessBeforePassing: $SuccessBeforePassing, + FailuresBeforeCritical: $FailuresBeforeCritical, + DeregisterCriticalServiceAfter: $DeregisterCriticalServiceAfter, + ); + $this->ID = $ID; + $this->ServiceID = $ServiceID; + $this->Namespace = $Namespace; + $this->Partition = $Partition; + } public function getID(): string { @@ -70,4 +126,39 @@ public function setNamespace(string $Namespace): self $this->Namespace = $Namespace; return $this; } + + public function getPartition(): string + { + return $this->Partition; + } + + public function setPartition(string $Partition): self + { + $this->Partition = $Partition; + return $this; + } + + public function jsonSerialize(): \stdClass + { + $out = parent::jsonSerialize(); + if ('' !== $this->ID) { + $out->ID = $this->ID; + } + if ('' !== $this->ServiceID) { + $out->ServiceID = $this->ServiceID; + } + if ('' !== $this->Namespace) { + $out->Namespace = $this->Namespace; + } + if (isset($out->Name) && $out->Name === '') { + unset($out->Name); + } + if (isset($out->Notes) && $out->Notes === '') { + unset($out->Notes); + } + if ('' !== $this->Partition) { + $out->Partition = $this->Partition; + } + return $out; + } } diff --git a/src/Agent/AgentCheckUpdate.php b/src/Agent/AgentCheckUpdate.php index aed5f53a..a5276315 100644 --- a/src/Agent/AgentCheckUpdate.php +++ b/src/Agent/AgentCheckUpdate.php @@ -20,21 +20,27 @@ limitations under the License. */ -use DCarbone\PHPConsulAPI\AbstractModel; +use DCarbone\PHPConsulAPI\PHPLib\AbstractType; -final class AgentCheckUpdate extends AbstractModel +class AgentCheckUpdate extends AbstractType { - public string $Status = ''; - public string $Output = ''; + public string $Status; + public string $Output; + + public function __construct(string $Status = '', string $Output = '') + { + $this->Status = $Status; + $this->Output = $Output; + } public function getStatus(): string { return $this->Status; } - public function setStatus(string $status): self + public function setStatus(string $Status): self { - $this->Status = $status; + $this->Status = $Status; return $this; } @@ -43,12 +49,29 @@ public function getOutput(): string return $this->Output; } - public function setOutput(string $output): self + public function setOutput(string $Output): self { - $this->Output = $output; + $this->Output = $Output; return $this; } + public static function jsonUnserialize(\stdClass $decoded): self + { + $n = new self(); + foreach ((array)$decoded as $k => $v) { + $n->{$k} = $v; + } + return $n; + } + + public function jsonSerialize(): \stdClass + { + $out = $this->_startJsonSerialize(); + $out->Status = $this->Status; + $out->Output = $this->Output; + return $out; + } + public function __toString(): string { return sprintf('%s: %s', $this->Status, $this->Output); diff --git a/src/Agent/AgentChecksResponse.php b/src/Agent/AgentChecksResponse.php index 4cf50761..99fbd7ee 100644 --- a/src/Agent/AgentChecksResponse.php +++ b/src/Agent/AgentChecksResponse.php @@ -20,23 +20,27 @@ limitations under the License. */ -use DCarbone\PHPConsulAPI\AbstractValuedResponse; -use DCarbone\PHPConsulAPI\UnmarshalledResponseInterface; +use DCarbone\PHPConsulAPI\PHPLib\AbstractValuedResponse; +use DCarbone\PHPConsulAPI\PHPLib\UnmarshalledResponseInterface; class AgentChecksResponse extends AbstractValuedResponse implements UnmarshalledResponseInterface { - public ?array $Checks = null; + /** @var \DCarbone\PHPConsulAPI\Agent\AgentCheck[] */ + public array $Checks = []; - public function getValue(): ?array + /** + * @return \DCarbone\PHPConsulAPI\Agent\AgentCheck[]|null + */ + public function getValue(): null|array { return $this->Checks; } - public function unmarshalValue(mixed $decodedData): void + public function unmarshalValue(mixed $decoded): void { $this->Checks = []; - foreach ($decodedData as $k => $v) { - $this->Checks[$k] = new AgentCheck($v); + foreach ($decoded as $k => $v) { + $this->Checks[$k] = AgentCheck::jsonUnserialize($v); } } } diff --git a/src/Agent/AgentClient.php b/src/Agent/AgentClient.php index 7e896ead..25aac427 100644 --- a/src/Agent/AgentClient.php +++ b/src/Agent/AgentClient.php @@ -21,21 +21,27 @@ */ use DCarbone\Go\HTTP; -use DCarbone\PHPConsulAPI\AbstractClient; +use DCarbone\PHPConsulAPI\PHPLib\AbstractClient; use DCarbone\PHPConsulAPI\Consul; -use DCarbone\PHPConsulAPI\Error; -use DCarbone\PHPConsulAPI\MapResponse; +use DCarbone\PHPConsulAPI\PHPLib\Error; +use DCarbone\PHPConsulAPI\PHPLib\MapResponse; +use DCarbone\PHPConsulAPI\PHPLib\ValuedStringResponse; use DCarbone\PHPConsulAPI\QueryOptions; -use DCarbone\PHPConsulAPI\Request; -use DCarbone\PHPConsulAPI\ValuedStringResponse; +use DCarbone\PHPConsulAPI\PHPLib\Request; class AgentClient extends AbstractClient { - private ?MapResponse $_self = null; - + /** @var \DCarbone\PHPConsulAPI\PHPLib\MapResponse|null */ + private null|MapResponse $_self = null; + + /** + * @param bool $refresh + * @return \DCarbone\PHPConsulAPI\PHPLib\MapResponse + * @throws \Exception + */ public function Self(bool $refresh = false): MapResponse { - if (!$refresh && isset($this->_self)) { + if (!$refresh && null !== $this->_self) { return $this->_self; } $resp = $this->_requireOK($this->_doGet('v1/agent/self', null)); @@ -47,6 +53,10 @@ public function Self(bool $refresh = false): MapResponse return $ret; } + /** + * @return \DCarbone\PHPConsulAPI\PHPLib\MapResponse + * @throws \Exception + */ public function Host(): MapResponse { $resp = $this->_requireOK($this->_doGet('v1/agent/host', null)); @@ -63,7 +73,7 @@ public function Metrics(): MetricsInfoResponse return $ret; } - public function Reload(): ?Error + public function Reload(): null|Error { return $this->_executePut('v1/agent/reload', null, null)->Err; } @@ -76,8 +86,8 @@ public function NodeName(bool $refresh = false): ValuedStringResponse if (null !== $self->Err) { return $ret; } - if (isset($self->Map['Config'], $self->Map['Config']['NodeName'])) { - $ret->Value = $self->Map['Config']['NodeName']; + if (isset($self->Map['Config']->NodeName)) { + $ret->Value = $self->Map['Config']->NodeName; } return $ret; } @@ -146,29 +156,28 @@ public function AgentHealthServiceByName(string $service): AgentHealthServicesRe $resp = $this->_requireOK($this->_do($r)); if (null !== $resp->Err) { - return new AgentHealthServicesResponse(Consul::HealthCritical, null, $resp->Err); + return new AgentHealthServicesResponse(Consul::HealthCritical, [], $resp->Err); } if (HTTP\StatusNotFound === $resp->Response->getStatusCode()) { - return new AgentHealthServicesResponse(Consul::HealthCritical, null, null); + return new AgentHealthServicesResponse(Consul::HealthCritical, [], null); } $dec = $this->_decodeBody($resp->Response->getBody()); if (null !== $dec->Err) { - return new AgentHealthServicesResponse(Consul::HealthCritical, null, $dec->Err); + return new AgentHealthServicesResponse(Consul::HealthCritical, [], $dec->Err); } $status = match ($resp->Response->getStatusCode()) { HTTP\StatusOK => Consul::HealthPassing, HTTP\StatusTooManyRequests => Consul::HealthWarning, - HTTP\StatusServiceUnavailable => Consul::HealthCritical, default => Consul::HealthCritical, }; return new AgentHealthServicesResponse($status, $dec->Decoded, null); } - public function Service(string $serviceID, ?QueryOptions $opts = null): AgentServiceResponse + public function Service(string $serviceID, null|QueryOptions $opts = null): AgentServiceResponse { $resp = $this->_requireOK($this->_doGet(sprintf('v1/agent/service/%s', $serviceID), $opts)); $ret = new AgentServiceResponse(); @@ -197,7 +206,7 @@ public function MemberOpts(MemberOpts $memberOpts): AgentMembersResponse return $ret; } - public function ServiceRegisterOpts(AgentServiceRegistration $service, ServiceRegisterOpts $registerOpts): ?Error + public function ServiceRegisterOpts(AgentServiceRegistration $service, ServiceRegisterOpts $registerOpts): null|Error { $r = $this->_newPutRequest('v1/agent/service/register', $service, null); if ($registerOpts->ReplaceExistingChecks) { @@ -206,33 +215,33 @@ public function ServiceRegisterOpts(AgentServiceRegistration $service, ServiceRe return $this->_requireOK($this->_do($r))->Err; } - public function ServiceRegister(AgentServiceRegistration $service): ?Error + public function ServiceRegister(AgentServiceRegistration $service): null|Error { - return $this->ServiceRegisterOpts($service, new ServiceRegisterOpts(['ReplaceExistingChecks' => false])); + return $this->ServiceRegisterOpts($service, new ServiceRegisterOpts(ReplaceExistingChecks: false)); } - public function ServiceDeregister(string $serviceID): ?Error + public function ServiceDeregister(string $serviceID): null|Error { $r = new Request(HTTP\MethodPut, sprintf('v1/agent/service/deregister/%s', $serviceID), $this->_config, null); return $this->_requireOK($this->_do($r))->Err; } - public function PassTTL(string $checkID, string $note): ?Error + public function PassTTL(string $checkID, string $note): null|Error { return $this->UpdateTTL($checkID, $note, 'pass'); } - public function WarnTTL(string $checkID, string $note): ?Error + public function WarnTTL(string $checkID, string $note): null|Error { return $this->UpdateTTL($checkID, $note, 'warn'); } - public function FailTTL(string $checkID, string $note): ?Error + public function FailTTL(string $checkID, string $note): null|Error { return $this->UpdateTTL($checkID, $note, 'fail'); } - public function UpdateTTL(string $checkID, string $output, string $status): ?Error + public function UpdateTTL(string $checkID, string $output, string $status): null|Error { switch ($status) { case Consul::HealthPassing: @@ -256,23 +265,23 @@ public function UpdateTTL(string $checkID, string $output, string $status): ?Err HTTP\MethodPut, sprintf('v1/agent/check/update/%s', $checkID), $this->_config, - new AgentCheckUpdate(['Output' => $output, 'Status' => $status]) + new AgentCheckUpdate(Status: $status, Output: $output) ); return $this->_requireOK($this->_do($r))->Err; } - public function CheckRegister(AgentCheckRegistration $check): ?Error + public function CheckRegister(AgentCheckRegistration $check): null|Error { return $this->_executePut('v1/agent/check/register', $check, null)->Err; } - public function CheckDeregister(string $checkID): ?Error + public function CheckDeregister(string $checkID): null|Error { return $this->_executePut(sprintf('v1/agent/check/deregister/%s', $checkID), null, null)->Err; } - public function Join(string $addr, bool $wan = false): ?Error + public function Join(string $addr, bool $wan = false): null|Error { $r = $this->_newPutRequest(sprintf('v1/agent/join/%s', $addr), null, null); if ($wan) { @@ -281,24 +290,24 @@ public function Join(string $addr, bool $wan = false): ?Error return $this->_requireOK($this->_do($r))->Err; } - public function Leave(): ?Error + public function Leave(): null|Error { return $this->_executePut('v1/agent/leave', null, null)->Err; } - public function ForceLeave(string $node): ?Error + public function ForceLeave(string $node): null|Error { return $this->_executePut(sprintf('v1/agent/force-leave/%s', $node), null, null)->Err; } - public function ForceLeavePrune(string $node): ?Error + public function ForceLeavePrune(string $node): null|Error { $r = $this->_newPutRequest(sprintf('v1/agent/force-leave/%s', $node), null, null); $r->params->set('prune', '1'); return $this->_requireOK($this->_do($r))->Err; } - public function EnableServiceMaintenance(string $serviceID, string $reason = ''): ?Error + public function EnableServiceMaintenance(string $serviceID, string $reason = ''): null|Error { $r = $this->_newPutRequest(sprintf('v1/agent/service/maintenance/%s', $serviceID), null, null); $r->params->set('enable', 'true'); @@ -306,14 +315,14 @@ public function EnableServiceMaintenance(string $serviceID, string $reason = '') return $this->_requireOK($this->_do($r))->Err; } - public function DisableServiceMaintenance(string $serviceID): ?Error + public function DisableServiceMaintenance(string $serviceID): null|Error { $r = $this->_newPutRequest(sprintf('v1/agent/service/maintenance/%s', $serviceID), null, null); $r->params->set('enable', 'false'); return $this->_requireOK($this->_do($r))->Err; } - public function EnableNodeMaintenance(string $reason = ''): ?Error + public function EnableNodeMaintenance(string $reason = ''): null|Error { $r = $this->_newPutRequest('v1/agent/maintenance', null, null); $r->params->set('enable', 'true'); @@ -321,7 +330,7 @@ public function EnableNodeMaintenance(string $reason = ''): ?Error return $this->_requireOK($this->_do($r))->Err; } - public function DisableNodeMaintenance(): ?Error + public function DisableNodeMaintenance(): null|Error { $r = $this->_newPutRequest('v1/agent/maintenance', null, null); $r->params->set('enable', 'false'); diff --git a/src/Agent/AgentHealthServiceResponse.php b/src/Agent/AgentHealthServiceResponse.php index 1da8b3c8..b7764403 100644 --- a/src/Agent/AgentHealthServiceResponse.php +++ b/src/Agent/AgentHealthServiceResponse.php @@ -20,23 +20,28 @@ limitations under the License. */ -use DCarbone\PHPConsulAPI\AbstractResponse; -use DCarbone\PHPConsulAPI\Error; -use DCarbone\PHPConsulAPI\ErrorContainer; +use DCarbone\PHPConsulAPI\PHPLib\Error; +use DCarbone\PHPConsulAPI\PHPLib\AbstractResponse; +/** + * @extends AbstractResponse + */ class AgentHealthServiceResponse extends AbstractResponse { - use ErrorContainer; - public string $AggregatedStatus = ''; - public ?AgentServiceChecksInfo $AgentServiceChecksInfo = null; + public string $AggregatedStatus; + public null|AgentServiceChecksInfo $AgentServiceChecksInfo; - public function __construct(string $aggregatedStatus, ?array $checkInfo, ?Error $err) - { + public function __construct( + string $aggregatedStatus, + null|\stdClass $checksInfo, + null|Error $err + ) { $this->AggregatedStatus = $aggregatedStatus; - if (null !== $checkInfo) { - $this->AgentServiceChecksInfo = new AgentServiceChecksInfo($checkInfo); + if (null !== $checksInfo) { + $checksInfo = AgentServiceChecksInfo::jsonUnserialize($checksInfo); } + $this->AgentServiceChecksInfo = $checksInfo; $this->Err = $err; } @@ -45,17 +50,17 @@ public function getAggregatedStatus(): string return $this->AggregatedStatus; } - public function getAgentServiceChecksInfos(): ?AgentServiceChecksInfo + public function getAgentServiceChecksInfos(): null|AgentServiceChecksInfo { return $this->AgentServiceChecksInfo; } public function offsetExists(mixed $offset): bool { - return \is_int($offset) && 0 <= $offset && $offset < 3; + return is_int($offset) && 0 <= $offset && $offset < 3; } - public function offsetGet(mixed $offset): Error|string|null|AgentServiceChecksInfo + public function offsetGet(mixed $offset): string|AgentServiceChecksInfo|Error|null { if (0 === $offset) { return $this->AggregatedStatus; diff --git a/src/Agent/AgentHealthServicesResponse.php b/src/Agent/AgentHealthServicesResponse.php index d6d3a4c6..2cea87f8 100644 --- a/src/Agent/AgentHealthServicesResponse.php +++ b/src/Agent/AgentHealthServicesResponse.php @@ -20,25 +20,26 @@ limitations under the License. */ -use DCarbone\PHPConsulAPI\AbstractResponse; -use DCarbone\PHPConsulAPI\Error; -use DCarbone\PHPConsulAPI\ErrorContainer; +use DCarbone\PHPConsulAPI\PHPLib\Error; +use DCarbone\PHPConsulAPI\PHPLib\AbstractResponse; class AgentHealthServicesResponse extends AbstractResponse { - use ErrorContainer; + public string $AggregatedStatus; + /** @var \DCarbone\PHPConsulAPI\Agent\AgentServiceChecksInfo[] */ + public array $AgentServiceChecksInfos; - public string $AggregatedStatus = ''; - public ?array $AgentServiceChecksInfos = null; - - public function __construct(string $aggregatedStatus, ?array $checkInfos, ?Error $err) + /** + * @param string $aggregatedStatus + * @param \stdClass[] $checkInfos + * @param \DCarbone\PHPConsulAPI\PHPLib\Error|null $err + */ + public function __construct(string $aggregatedStatus, array $checkInfos, null|Error $err) { $this->AggregatedStatus = $aggregatedStatus; - if (null !== $checkInfos) { - $this->AgentServiceChecksInfos = []; - foreach ($checkInfos as $checkInfo) { - $this->AgentServiceChecksInfos[] = new AgentServiceChecksInfo($checkInfo); - } + $this->AgentServiceChecksInfos = []; + foreach ($checkInfos as $checkInfo) { + $this->AgentServiceChecksInfos[] = AgentServiceChecksInfo::jsonUnserialize($checkInfo); } $this->Err = $err; } @@ -48,17 +49,24 @@ public function getAggregatedStatus(): string return $this->AggregatedStatus; } - public function getAgentServiceChecksInfos(): ?array + /** + * @return \DCarbone\PHPConsulAPI\Agent\AgentServiceChecksInfo[] + */ + public function getAgentServiceChecksInfos(): array { return $this->AgentServiceChecksInfos; } public function offsetExists(mixed $offset): bool { - return \is_int($offset) && 0 <= $offset && $offset < 3; + return is_int($offset) && 0 <= $offset && $offset < 3; } - public function offsetGet(mixed $offset): mixed + /** + * @param mixed $offset + * @return string|\DCarbone\PHPConsulAPI\Agent\AgentServiceChecksInfo[]|\DCarbone\PHPConsulAPI\PHPLib\Error|null + */ + public function offsetGet(mixed $offset): string|array|Error|null { if (0 === $offset) { return $this->AggregatedStatus; diff --git a/src/Agent/AgentMember.php b/src/Agent/AgentMember.php index 80167a8c..e3e84877 100644 --- a/src/Agent/AgentMember.php +++ b/src/Agent/AgentMember.php @@ -20,24 +20,67 @@ limitations under the License. */ -use DCarbone\PHPConsulAPI\AbstractModel; use DCarbone\PHPConsulAPI\Consul; -use DCarbone\PHPConsulAPI\HasStringTags; +use DCarbone\PHPConsulAPI\PHPLib\AbstractType; -class AgentMember extends AbstractModel +class AgentMember extends AbstractType { - use HasStringTags; - - public string $Name = ''; - public string $Addr = ''; - public int $Port = 0; - public string $Status = ''; - public int $ProtocolMin = 0; - public int $ProtocolMax = 0; - public int $ProtocolCur = 0; - public int $DelegateMin = 0; - public int $DelegateMax = 0; - public int $DelegateCur = 0; + public string $Name; + public string $Addr; + public int $Port; + /** @var array */ + public array $Tags; + /** + * Status of the Member which corresponds to github.com/hashicorp/serf/serf.MemberStatus + * Value is one of: + * AgentMemberNone = 0 + * AgentMemberAlive = 1 + * AgentMemberLeaving = 2 + * AgentMemberLeft = 3 + * AgentMemberFailed = 4 + * @var int + */ + public int $Status; + public int $ProtocolMin; + public int $ProtocolMax; + public int $ProtocolCur; + public int $DelegateMin; + public int $DelegateMax; + public int $DelegateCur; + + /** + * @param null|\stdClass|array $Tags + */ + public function __construct( + string $Name = '', + string $Addr = '', + int $Port = 0, + null|\stdClass|array $Tags = null, + int $Status = 0, + int $ProtocolMin = 0, + int $ProtocolMax = 0, + int $ProtocolCur = 0, + int $DelegateMin = 0, + int $DelegateMax = 0, + int $DelegateCur = 0, + ) { + $this->Name = $Name; + $this->Addr = $Addr; + $this->Port = $Port; + $this->Tags = []; + if (null !== $Tags) { + foreach ($Tags as $k => $v) { + $this->Tags[$k] = $v; + } + } + $this->Status = $Status; + $this->ProtocolMin = $ProtocolMin; + $this->ProtocolMax = $ProtocolMax; + $this->ProtocolCur = $ProtocolCur; + $this->DelegateMin = $DelegateMin; + $this->DelegateMax = $DelegateMax; + $this->DelegateCur = $DelegateCur; + } public function getName(): string { @@ -54,7 +97,7 @@ public function getPort(): int return $this->Port; } - public function getStatus(): string + public function getStatus(): int { return $this->Status; } @@ -89,13 +132,13 @@ public function getDelegateCur(): int return $this->DelegateCur; } - public function ACLMode(): string + public function ACLMode(): MemberACLMode { return match ($this->Tags[Consul::MemberTagKeyACLMode] ?? null) { - Consul::ACLModeDisabled => Consul::ACLModeDisabled, - Consul::ACLModeEnabled => Consul::ACLModeEnabled, - Consul::ACLModeLegacy => Consul::ACLModeLegacy, - default => Consul::ACLModeUnknown, + MemberACLMode::Disabled->value => MemberACLMode::Disabled, + MemberACLMode::Enabled->value => MemberACLMode::Enabled, + MemberACLMode::Legacy->value => MemberACLMode::Legacy, + default => MemberACLMode::Unknown, }; } @@ -105,6 +148,40 @@ public function IsConsulServer(): bool Consul::MemberTagValueRoleServer === $this->Tags[Consul::MemberTagKeyACLMode]; } + public static function jsonUnserialize(\stdClass $decoded): self + { + $n = new self(); + foreach ((array)$decoded as $k => $v) { + if ('Tags' === $k) { + if (null !== $v) { + foreach ($v as $kk => $vv) { + $n->Tags[$kk] = $vv; + } + } + } else { + $n->{$k} = $v; + } + } + return $n; + } + + public function jsonSerialize(): \stdClass + { + $out = $this->_startJsonSerialize(); + $out->Name = $this->Name; + $out->Addr = $this->Addr; + $out->Port = $this->Port; + $out->Tags = $this->Tags; + $out->Status = $this->Status; + $out->ProtocolMin = $this->ProtocolMin; + $out->ProtocolMax = $this->ProtocolMax; + $out->ProtocolCur = $this->ProtocolCur; + $out->DelegateMin = $this->DelegateMin; + $out->DelegateMax = $this->DelegateMax; + $out->DelegateCur = $this->DelegateCur; + return $out; + } + public function __toString(): string { return $this->Name; diff --git a/src/Agent/AgentMembersResponse.php b/src/Agent/AgentMembersResponse.php index 816c924e..aea65ae6 100644 --- a/src/Agent/AgentMembersResponse.php +++ b/src/Agent/AgentMembersResponse.php @@ -20,23 +20,27 @@ limitations under the License. */ -use DCarbone\PHPConsulAPI\AbstractValuedResponse; -use DCarbone\PHPConsulAPI\UnmarshalledResponseInterface; +use DCarbone\PHPConsulAPI\PHPLib\AbstractValuedResponse; +use DCarbone\PHPConsulAPI\PHPLib\UnmarshalledResponseInterface; class AgentMembersResponse extends AbstractValuedResponse implements UnmarshalledResponseInterface { - public ?array $Members = null; + /** @var \DCarbone\PHPConsulAPI\Agent\AgentMember[] */ + public array $Members = []; - public function getValue(): ?array + /** + * @return \DCarbone\PHPConsulAPI\Agent\AgentMember[] + */ + public function getValue(): array { return $this->Members; } - public function unmarshalValue(mixed $decodedData): void + public function unmarshalValue(mixed $decoded): void { $this->Members = []; - foreach ($decodedData as $member) { - $this->Members[] = new AgentMember($member); + foreach ($decoded as $member) { + $this->Members[] = AgentMember::jsonUnserialize($member); } } } diff --git a/src/Agent/AgentService.php b/src/Agent/AgentService.php index dd4de64e..6c254c4f 100644 --- a/src/Agent/AgentService.php +++ b/src/Agent/AgentService.php @@ -20,96 +20,96 @@ limitations under the License. */ -use DCarbone\PHPConsulAPI\AbstractModel; -use DCarbone\PHPConsulAPI\Catalog\ServiceAddress; -use DCarbone\PHPConsulAPI\FakeMap; -use DCarbone\PHPConsulAPI\HasStringTags; -use DCarbone\PHPConsulAPI\Transcoding; +use DCarbone\PHPConsulAPI\Peering\Locality; +use DCarbone\PHPConsulAPI\PHPLib\AbstractType; +use DCarbone\PHPConsulAPI\PHPLib\MetaField; -class AgentService extends AbstractModel +class AgentService extends AbstractType { - use HasStringTags; - - protected const FIELDS = [ - self::FIELD_KIND => Transcoding::OMITEMPTY_STRING_FIELD, - self::FIELD_META => Transcoding::MAP_FIELD, - self::FIELD_TAGGED_ADDRESSES => [ - Transcoding::FIELD_TYPE => Transcoding::ARRAY, - Transcoding::FIELD_CLASS => ServiceAddress::class, - Transcoding::FIELD_ARRAY_TYPE => Transcoding::OBJECT, - Transcoding::FIELD_OMITEMPTY => true, - ], - self::FIELD_WEIGHTS => [ - Transcoding::FIELD_TYPE => Transcoding::OBJECT, - Transcoding::FIELD_CLASS => AgentWeights::class, - ], - self::FIELD_CREATE_INDEX => Transcoding::OMITEMPTY_INTEGER_FIELD, - self::FIELD_MODIFY_INDEX => Transcoding::OMITEMPTY_INTEGER_FIELD, - self::FIELD_CONTENT_HASH => Transcoding::OMITEMPTY_STRING_FIELD, - self::FIELD_PROXY => [ - Transcoding::FIELD_TYPE => Transcoding::OBJECT, - Transcoding::FIELD_CLASS => AgentServiceConnectProxyConfig::class, - Transcoding::FIELD_NULLABLE => true, - Transcoding::FIELD_OMITEMPTY => true, - ], - self::FIELD_CONNECT => [ - Transcoding::FIELD_TYPE => Transcoding::OBJECT, - Transcoding::FIELD_CLASS => AgentServiceConnect::class, - Transcoding::FIELD_NULLABLE => true, - Transcoding::FIELD_OMITEMPTY => true, - ], - self::FIELD_NAMESPACE => Transcoding::OMITEMPTY_STRING_FIELD, - self::FIELD_DATACENTER => Transcoding::OMITEMPTY_STRING_FIELD, - ]; - - private const FIELD_KIND = 'Kind'; - private const FIELD_META = 'Meta'; - private const FIELD_TAGGED_ADDRESSES = 'TaggedAddresses'; - private const FIELD_WEIGHTS = 'Weights'; - private const FIELD_CREATE_INDEX = 'CreateIndex'; - private const FIELD_MODIFY_INDEX = 'ModifyIndex'; - private const FIELD_CONTENT_HASH = 'ContentHash'; - private const FIELD_PROXY = 'Proxy'; - private const FIELD_CONNECT = 'Connect'; - private const FIELD_NAMESPACE = 'Namespace'; - private const FIELD_DATACENTER = 'Datacenter'; - - public string $Kind = ''; - public string $ID = ''; - public string $Service = ''; - public FakeMap $Meta; - public int $Port = 0; - public string $Address = ''; - public array $TaggedAddresses = []; + use MetaField; + + public ServiceKind $Kind; + public string $ID; + public string $Service; + /** @var array */ + public array $Tags; + public int $Port; + public string $Address; + public string $SocketPath; + /** @var null|array */ + public null|array $TaggedAddresses = null; public AgentWeights $Weights; - public bool $EnableTagOverride = false; - public int $CreateIndex = 0; - public int $ModifyIndex = 0; - public string $ContentHash = ''; - public ?AgentServiceConnectProxyConfig $Proxy = null; - public ?AgentServiceConnect $Connect = null; - public string $Namespace = ''; - public string $Datacenter = ''; - - public function __construct(?array $data = []) - { - parent::__construct($data); - if (!isset($this->Weights)) { - $this->Weights = new AgentWeights(null); - } - if (!isset($this->Meta)) { - $this->Meta = new FakeMap(null); - } + public bool $EnableTagOverride; + public int $CreateIndex; + public int $ModifyIndex; + public string $ContentHash; + public null|AgentServiceConnectProxyConfig $Proxy; + public null|AgentServiceConnect $Connect; + public string $PeerName; + public string $Namespace; + public string $Partition; + public string $Datacenter; + public null|Locality $Locality; + + /** + * @param array $Tags + * @param array $Meta + * @param array $TaggedAddresses + */ + public function __construct( + string|ServiceKind $Kind = '', + string $ID = '', + string $Service = '', + string $SocketPath = '', + array $Tags = [], + array $Meta = [], + int $Port = 0, + string $Address = '', + array $TaggedAddresses = [], + null|AgentWeights $Weights = null, + bool $EnableTagOverride = false, + int $CreateIndex = 0, + int $ModifyIndex = 0, + string $ContentHash = '', + null|AgentServiceConnectProxyConfig $Proxy = null, + null|AgentServiceConnect $Connect = null, + string $PeerName = '', + string $Namespace = '', + string $Partition = '', + string $Datacenter = '', + null|Locality $Locality = null, + ) { + $this->Kind = is_string($Kind) ? ServiceKind::from($Kind) : $Kind; + $this->ID = $ID; + $this->Service = $Service; + $this->setMeta($Meta); + $this->Port = $Port; + $this->setTags(...$Tags); + $this->Address = $Address; + $this->SocketPath = $SocketPath; + $this->setTaggedAddresses($TaggedAddresses ?: null); + $this->Weights = $Weights ?? new AgentWeights(); + $this->EnableTagOverride = $EnableTagOverride; + $this->CreateIndex = $CreateIndex; + $this->ModifyIndex = $ModifyIndex; + $this->ContentHash = $ContentHash; + $this->Proxy = $Proxy; + $this->Connect = $Connect; + $this->PeerName = $PeerName; + $this->Namespace = $Namespace; + $this->Partition = $Partition; + $this->Datacenter = $Datacenter; + $this->Locality = $Locality; } - public function getKind(): string + public function getKind(): ServiceKind { return $this->Kind; } - public function setKind(string $Kind): self + public function setKind(string|ServiceKind $Kind): self { - $this->Kind = $Kind; + $this->Kind = is_string($Kind) ? ServiceKind::from($Kind) : $Kind; return $this; } @@ -135,14 +135,17 @@ public function setService(string $Service): self return $this; } - public function getMeta(): FakeMap + /** + * @return array + */ + public function getTags(): array { - return $this->Meta; + return $this->Tags; } - public function setMeta(FakeMap $Meta): self + public function setTags(string ...$Tags): self { - $this->Meta = $Meta; + $this->Tags = $Tags; return $this; } @@ -168,14 +171,25 @@ public function setAddress(string $Address): self return $this; } - public function getTaggedAddresses(): array + /** + * @return null|array<\DCarbone\PHPConsulAPI\Catalog\ServiceAddress> + */ + public function getTaggedAddresses(): null|array { return $this->TaggedAddresses; } - public function setTaggedAddresses(array $TaggedAddresses): self + /** + * @param null|\stdClass|array<\DCarbone\PHPConsulAPI\Catalog\ServiceAddress> $TaggedAddresses + * @return $this + */ + public function setTaggedAddresses(null|\stdClass|array $TaggedAddresses): self { - $this->TaggedAddresses = $TaggedAddresses; + if (null === $TaggedAddresses || [] === $TaggedAddresses) { + $this->TaggedAddresses = null; + return $this; + } + $this->TaggedAddresses = (array)$TaggedAddresses; return $this; } @@ -234,28 +248,39 @@ public function setContentHash(string $ContentHash): self return $this; } - public function getProxy(): ?AgentServiceConnectProxyConfig + public function getProxy(): null|AgentServiceConnectProxyConfig { return $this->Proxy; } - public function setProxy(?AgentServiceConnectProxyConfig $Proxy): self + public function setProxy(null|AgentServiceConnectProxyConfig $Proxy): self { $this->Proxy = $Proxy; return $this; } - public function getConnect(): ?AgentServiceConnect + public function getConnect(): null|AgentServiceConnect { return $this->Connect; } - public function setConnect(?AgentServiceConnect $Connect): self + public function setConnect(null|AgentServiceConnect $Connect): self { $this->Connect = $Connect; return $this; } + public function getPeerName(): string + { + return $this->PeerName; + } + + public function setPeerName(string $PeerName): self + { + $this->PeerName = $PeerName; + return $this; + } + public function getNamespace(): string { return $this->Namespace; @@ -267,6 +292,17 @@ public function setNamespace(string $Namespace): self return $this; } + public function getPartition(): string + { + return $this->Partition; + } + + public function setPartition(string $Partition): self + { + $this->Partition = $Partition; + return $this; + } + public function getDatacenter(): string { return $this->Datacenter; @@ -277,4 +313,95 @@ public function setDatacenter(string $Datacenter): self $this->Datacenter = $Datacenter; return $this; } + + public function getLocality(): null|Locality + { + return $this->Locality; + } + + public function setLocality(null|Locality $Locality): self + { + $this->Locality = $Locality; + return $this; + } + + public static function jsonUnserialize(\stdClass $decoded): self + { + $n = new self(); + foreach ((array)$decoded as $k => $v) { + if ('Kind' === $k) { + $n->Kind = ServiceKind::from($v); + } elseif ('Tags' === $k) { + $n->setTags(...$v); + } elseif ('Proxy' === $k) { + $n->Proxy = null === $v ? null : AgentServiceConnectProxyConfig::jsonUnserialize($v); + } elseif ('Weights' === $k) { + $n->Weights = AgentWeights::jsonUnserialize($v); + } elseif ('TaggedAddresses' === $k) { + $n->setTaggedAddresses($v); + } elseif ('Connect' === $k) { + $n->Connect = null === $v ? null : AgentServiceConnect::jsonUnserialize($v); + } elseif ('Locality' === $k) { + $n->Locality = null === $v ? null : Locality::jsonUnserialize($v); + } elseif ('Meta' === $k) { + $n->setMeta($v); + } else { + $n->{$k} = $v; + } + } + return $n; + } + + public function jsonSerialize(): \stdClass + { + $out = $this->_startJsonSerialize(); + if (ServiceKind::Typical !== $this->Kind) { + $out->Kind = $this->Kind; + } + $out->ID = $this->ID; + $out->Service = $this->Service; + $out->Tags = $this->Tags; + $out->Meta = $this->getMeta(); + $out->Port = $this->Port; + $out->Address = $this->Address; + if ('' !== $this->SocketPath) { + $out->SocketPath = $this->SocketPath; + } + if (null !== $this->TaggedAddresses) { + $out->TaggedAddresses = $this->TaggedAddresses; + } + $out->Weights = $this->Weights; + $out->EnableTagOverride = $this->EnableTagOverride; + if (0 !== $this->CreateIndex) { + $out->CreateIndex = $this->CreateIndex; + } + if (0 !== $this->ModifyIndex) { + $out->ModifyIndex = $this->ModifyIndex; + } + if ('' !== $this->ContentHash) { + $out->ContentHash = $this->ContentHash; + } + if (null !== $this->Proxy) { + $out->Proxy = $this->Proxy; + } + if (null !== $this->Connect) { + $out->Connect = $this->Connect; + } + if ('' !== $this->PeerName) { + $out->PeerName = $this->PeerName; + } + if ('' !== $this->Namespace) { + $out->Namespace = $this->Namespace; + } + if ('' !== $this->Partition) { + $out->Partition = $this->Partition; + } + if ('' !== $this->Datacenter) { + $out->Datacenter = $this->Datacenter; + } + if (null !== $this->Locality) { + $out->Locality = $this->Locality; + } + return $out; + } } diff --git a/src/Agent/AgentServiceCheck.php b/src/Agent/AgentServiceCheck.php index c31a3319..e9ae26ed 100644 --- a/src/Agent/AgentServiceCheck.php +++ b/src/Agent/AgentServiceCheck.php @@ -20,101 +20,102 @@ limitations under the License. */ -use DCarbone\PHPConsulAPI\AbstractModel; -use DCarbone\PHPConsulAPI\Transcoding; +use DCarbone\PHPConsulAPI\PHPLib\AbstractType; +use DCarbone\PHPConsulAPI\PHPLib\Values; -class AgentServiceCheck extends AbstractModel +class AgentServiceCheck extends AbstractType { - protected const FIELDS = [ - self::FIELD_CHECK_ID => Transcoding::OMITEMPTY_STRING_FIELD, - self::FIELD_NAME => Transcoding::OMITEMPTY_STRING_FIELD, - self::FIELD_SCRIPT_ARGS => [ - Transcoding::FIELD_TYPE => Transcoding::ARRAY, - Transcoding::FIELD_ARRAY_TYPE => Transcoding::STRING, - Transcoding::FIELD_OMITEMPTY => true, - ], - self::FIELD_DOCKER_CONTAINER_ID => Transcoding::OMITEMPTY_STRING_FIELD, - self::FIELD_SHELL => Transcoding::OMITEMPTY_STRING_FIELD, - self::FIELD_INTERVAL => Transcoding::OMITEMPTY_STRING_FIELD, - self::FIELD_TIMEOUT => Transcoding::OMITEMPTY_STRING_FIELD, - self::FIELD_TTL => Transcoding::OMITEMPTY_STRING_FIELD, - self::FIELD_HTTP => Transcoding::OMITEMPTY_STRING_FIELD, - self::FIELD_HEADER => [ - Transcoding::FIELD_TYPE => Transcoding::ARRAY, - Transcoding::FIELD_ARRAY_TYPE => Transcoding::MIXED, - Transcoding::FIELD_OMITEMPTY => true, - ], - self::FIELD_METHOD => Transcoding::OMITEMPTY_STRING_FIELD, - self::FIELD_BODY => Transcoding::OMITEMPTY_STRING_FIELD, - self::FIELD_TCP => Transcoding::OMITEMPTY_STRING_FIELD, - self::FIELD_STATUS => Transcoding::OMITEMPTY_STRING_FIELD, - self::FIELD_NOTES => Transcoding::OMITEMPTY_STRING_FIELD, - self::FIELD_TLS_SKIP_VERIFY => Transcoding::OMITEMPTY_BOOLEAN_FIELD, - self::FIELD_GRPC => Transcoding::OMITEMPTY_STRING_FIELD, - self::FIELD_GRPC_USE_TLS => Transcoding::OMITEMPTY_BOOLEAN_FIELD, - self::FIELD_ALIAS_NODE => Transcoding::OMITEMPTY_STRING_FIELD, - self::FIELD_ALIAS_SERVICE => Transcoding::OMITEMPTY_STRING_FIELD, - self::FIELD_SUCCESS_BEFORE_PASSING => Transcoding::OMITEMPTY_INTEGER_FIELD, - self::FIELD_FAILURES_BEFORE_CRITICAL => Transcoding::OMITEMPTY_INTEGER_FIELD, - self::FIELD_DEREGISTER_CRITICAL_SERVICE_AFTER => Transcoding::OMITEMPTY_BOOLEAN_FIELD, - ]; - - private const FIELD_CHECK_ID = 'CheckID'; - private const FIELD_NAME = 'Name'; - private const FIELD_SCRIPT_ARGS = 'ScriptArgs'; - private const FIELD_DOCKER_CONTAINER_ID = 'DockerContainerID'; - private const FIELD_SHELL = 'Shell'; - private const FIELD_INTERVAL = 'Interval'; - private const FIELD_TIMEOUT = 'Timeout'; - private const FIELD_TTL = 'TTL'; - private const FIELD_HTTP = 'HTTP'; - private const FIELD_HEADER = 'Header'; - private const FIELD_METHOD = 'Method'; - private const FIELD_BODY = 'Body'; - private const FIELD_TCP = 'TCP'; - private const FIELD_STATUS = 'Status'; - private const FIELD_NOTES = 'Notes'; - private const FIELD_TLS_SKIP_VERIFY = 'TLSSkipVerify'; - private const FIELD_GRPC = 'GRPC'; - private const FIELD_GRPC_USE_TLS = 'GRPCUseTLS'; - private const FIELD_ALIAS_NODE = 'AliasNode'; - private const FIELD_ALIAS_SERVICE = 'AliasService'; - private const FIELD_SUCCESS_BEFORE_PASSING = 'SuccessBeforePassing'; - private const FIELD_FAILURES_BEFORE_CRITICAL = 'FailuresBeforeCritical'; - private const FIELD_DEREGISTER_CRITICAL_SERVICE_AFTER = 'DeregisterCriticalServiceAfter'; - - public string $CheckID = ''; - public string $Name = ''; - public array $ScriptArgs = []; - public string $DockerContainerID = ''; - public string $Shell = ''; - public string $Interval = ''; - public string $Timeout = ''; - public string $TTL = ''; - public string $HTTP = ''; - public array $Header = []; - public string $Method = ''; - public string $TCP = ''; - public string $Status = ''; - public string $Notes = ''; - public bool $TLSSkipVerify = false; - public string $GRPC = ''; - public bool $GRPCUseTLS = false; - public string $AliasNode = ''; - public string $AliasService = ''; - public int $SuccessBeforePassing = 0; - public int $FailuresBeforeCritical = 0; - - public string $DeregisterCriticalServiceAfter = ''; + public string $CheckID; + public string $Name; + /** @var string[] */ + public array $Args; + public string $DockerContainerID; + public string $Shell; + public string $Interval; + public string $Timeout; + public string $TTL; + public string $HTTP; + public null|Values $Header = null; + public string $Method; + public string $TCP; + public string $Status; + public string $Notes; + public bool $TLSSkipVerify; + public string $GRPC; + public bool $GRPCUseTLS; + public string $H2PING; + public bool $H2PINGUseTLS; + public string $AliasNode; + public string $AliasService; + public int $SuccessBeforePassing; + public int $FailuresBeforeCritical; + public string $DeregisterCriticalServiceAfter; + + /** + * @param array $Args + * @param null|array>|\DCarbone\PHPConsulAPI\PHPLib\Values $Header + */ + public function __construct( + string $CheckID = '', + string $Name = '', + array $Args = [], + string $DockerContainerID = '', + string $Shell = '', + string $Interval = '', + string $Timeout = '', + string $TTL = '', + string $HTTP = '', + null|array|Values $Header = null, + string $Method = '', + string $TCP = '', + string $Status = '', + string $Notes = '', + bool $TLSSkipVerify = false, + string $GRPC = '', + bool $GRPCUseTLS = false, + string $H2PING = '', + bool $H2PINGUseTLS = false, + string $AliasNode = '', + string $AliasService = '', + int $SuccessBeforePassing = 0, + int $FailuresBeforeCritical = 0, + string $DeregisterCriticalServiceAfter = '', + ) { + $this->CheckID = $CheckID; + $this->Name = $Name; + $this->Args = []; + $this->setArgs(...$Args); + $this->DockerContainerID = $DockerContainerID; + $this->Shell = $Shell; + $this->Interval = $Interval; + $this->Timeout = $Timeout; + $this->TTL = $TTL; + $this->HTTP = $HTTP; + $this->setHeader($Header); + $this->Method = $Method; + $this->TCP = $TCP; + $this->Status = $Status; + $this->Notes = $Notes; + $this->TLSSkipVerify = $TLSSkipVerify; + $this->GRPC = $GRPC; + $this->GRPCUseTLS = $GRPCUseTLS; + $this->H2PING = $H2PING; + $this->H2PINGUseTLS = $H2PINGUseTLS; + $this->AliasNode = $AliasNode; + $this->AliasService = $AliasService; + $this->SuccessBeforePassing = $SuccessBeforePassing; + $this->FailuresBeforeCritical = $FailuresBeforeCritical; + $this->DeregisterCriticalServiceAfter = $DeregisterCriticalServiceAfter; + } public function getCheckID(): string { return $this->CheckID; } - public function setCheckID(string $checkID): self + public function setCheckID(string $CheckID): self { - $this->CheckID = $checkID; + $this->CheckID = $CheckID; return $this; } @@ -123,20 +124,23 @@ public function getName(): string return $this->Name; } - public function setName(string $name): self + public function setName(string $Name): self { - $this->Name = $name; + $this->Name = $Name; return $this; } - public function getScriptArgs(): array + /** + * @return array + */ + public function getArgs(): array { - return $this->ScriptArgs; + return $this->Args; } - public function setScriptArgs(array $args): self + public function setArgs(string ...$Args): self { - $this->ScriptArgs = $args; + $this->Args = $Args; return $this; } @@ -145,9 +149,9 @@ public function getDockerContainerID(): string return $this->DockerContainerID; } - public function setDockerContainerID(string $dockerContainerID): self + public function setDockerContainerID(string $DockerContainerID): self { - $this->DockerContainerID = $dockerContainerID; + $this->DockerContainerID = $DockerContainerID; return $this; } @@ -156,9 +160,9 @@ public function getShell(): string return $this->Shell; } - public function setShell(string $shell): self + public function setShell(string $Shell): self { - $this->Shell = $shell; + $this->Shell = $Shell; return $this; } @@ -167,9 +171,9 @@ public function getInterval(): string return $this->Interval; } - public function setInterval(string $interval): self + public function setInterval(string $Interval): self { - $this->Interval = $interval; + $this->Interval = $Interval; return $this; } @@ -178,9 +182,9 @@ public function getTimeout(): string return $this->Timeout; } - public function setTimeout(string $timeout): self + public function setTimeout(string $Timeout): self { - $this->Timeout = $timeout; + $this->Timeout = $Timeout; return $this; } @@ -189,9 +193,9 @@ public function getTTL(): string return $this->TTL; } - public function setTTL(string $ttl): self + public function setTTL(string $TTL): self { - $this->TTL = $ttl; + $this->TTL = $TTL; return $this; } @@ -200,20 +204,31 @@ public function getHTTP(): string return $this->HTTP; } - public function setHTTP(string $http): self + public function setHTTP(string $HTTP): self { - $this->HTTP = $http; + $this->HTTP = $HTTP; return $this; } - public function getHeader(): array + public function getHeader(): null|Values { return $this->Header; } - public function setHeader(array $header): self - { - $this->Header = $header; + /** + * @param \stdClass|array>|\DCarbone\PHPConsulAPI\PHPLib\Values|null $Header + * @return $this + */ + public function setHeader(null|\stdClass|array|Values $Header): self + { + if (null === $Header) { + $this->Header = null; + return $this; + } + if (!$Header instanceof Values) { + $Header = Values::fromArray((array)$Header); + } + $this->Header = $Header; return $this; } @@ -222,9 +237,9 @@ public function getMethod(): string return $this->Method; } - public function setMethod(string $method): self + public function setMethod(string $Method): self { - $this->Method = $method; + $this->Method = $Method; return $this; } @@ -233,9 +248,9 @@ public function getTCP(): string return $this->TCP; } - public function setTCP(string $tcp): self + public function setTCP(string $TCP): self { - $this->TCP = $tcp; + $this->TCP = $TCP; return $this; } @@ -244,9 +259,9 @@ public function getStatus(): string return $this->Status; } - public function setStatus(string $status): self + public function setStatus(string $Status): self { - $this->Status = $status; + $this->Status = $Status; return $this; } @@ -255,9 +270,9 @@ public function getNotes(): string return $this->Notes; } - public function setNotes(string $notes): self + public function setNotes(string $Notes): self { - $this->Notes = $notes; + $this->Notes = $Notes; return $this; } @@ -266,9 +281,9 @@ public function isTLSSkipVerify(): bool return $this->TLSSkipVerify; } - public function setTLSSkipVerify(bool $tlsSkipVerify): self + public function setTLSSkipVerify(bool $TLSSkipVerify): self { - $this->TLSSkipVerify = $tlsSkipVerify; + $this->TLSSkipVerify = $TLSSkipVerify; return $this; } @@ -288,6 +303,28 @@ public function isGRPCUseTLS(): bool return $this->GRPCUseTLS; } + public function getH2PING(): string + { + return $this->H2PING; + } + + public function setH2PING(string $H2PING): self + { + $this->H2PING = $H2PING; + return $this; + } + + public function isH2PINGUseTLS(): bool + { + return $this->H2PINGUseTLS; + } + + public function setH2PINGUseTLS(bool $H2PINGUseTLS): self + { + $this->H2PINGUseTLS = $H2PINGUseTLS; + return $this; + } + public function setGRPCUseTLS(bool $GRPCUseTLS): self { $this->GRPCUseTLS = $GRPCUseTLS; @@ -343,9 +380,102 @@ public function getDeregisterCriticalServiceAfter(): string return $this->DeregisterCriticalServiceAfter; } - public function setDeregisterCriticalServiceAfter(string $deregisterCriticalServiceAfter): self + public function setDeregisterCriticalServiceAfter(string $DeregisterCriticalServiceAfter): self { - $this->DeregisterCriticalServiceAfter = $deregisterCriticalServiceAfter; + $this->DeregisterCriticalServiceAfter = $DeregisterCriticalServiceAfter; return $this; } + + public static function jsonUnserialize(\stdClass $decoded): self + { + $n = new self(); + foreach ((array)$decoded as $k => $v) { + if ('ScriptArgs' === $k) { + $n->Args = $v; + } elseif ('Header' === $k) { + $n->setHeader($v); + } else { + $n->{$k} = $v; + } + } + return $n; + } + + public function jsonSerialize(): \stdClass + { + $out = $this->_startJsonSerialize(); + if ('' !== $this->CheckID) { + $out->CheckID = $this->CheckID; + } + if ('' !== $this->Name) { + $out->Name = $this->Name; + } + if ([] !== $this->Args) { + $out->ScriptArgs = $this->Args; + } + if ('' !== $this->DockerContainerID) { + $out->DockerContainerID = $this->DockerContainerID; + } + if ('' !== $this->Shell) { + $out->Shell = $this->Shell; + } + if ('' !== $this->Interval) { + $out->Interval = $this->Interval; + } + if ('' !== $this->Timeout) { + $out->Timeout = $this->Timeout; + } + if ('' !== $this->TTL) { + $out->TTL = $this->TTL; + } + if ('' !== $this->HTTP) { + $out->HTTP = $this->HTTP; + } + if (null !== $this->Header) { + $out->Header = $this->Header; + } + if ('' !== $this->Method) { + $out->Method = $this->Method; + } + if ('' !== $this->TCP) { + $out->TCP = $this->TCP; + } + if ('' !== $this->Status) { + $out->Status = $this->Status; + } + if ('' !== $this->Notes) { + $out->Notes = $this->Notes; + } + if ($this->TLSSkipVerify) { + $out->TLSSkipVerify = $this->TLSSkipVerify; + } + if ('' !== $this->GRPC) { + $out->GRPC = $this->GRPC; + } + if ($this->GRPCUseTLS) { + $out->GRPCUseTLS = $this->GRPCUseTLS; + } + if ('' !== $this->H2PING) { + $out->H2PING = $this->H2PING; + } + if ($this->H2PINGUseTLS) { + $out->H2PINGUseTLS = $this->H2PINGUseTLS; + } + if ('' !== $this->AliasNode) { + $out->AliasNode = $this->AliasNode; + } + if ('' !== $this->AliasService) { + $out->AliasService = $this->AliasService; + } + if (0 !== $this->SuccessBeforePassing) { + $out->SuccessBeforePassing = $this->SuccessBeforePassing; + } + if (0 !== $this->FailuresBeforeCritical) { + $out->FailuresBeforeCritical = $this->FailuresBeforeCritical; + } + if ('' !== $this->DeregisterCriticalServiceAfter) { + $out->DeregisterCriticalServiceAfter = $this->DeregisterCriticalServiceAfter; + } + return $out; + } } diff --git a/src/Agent/AgentServiceChecks.php b/src/Agent/AgentServiceChecks.php index 314f9339..78bbea05 100644 --- a/src/Agent/AgentServiceChecks.php +++ b/src/Agent/AgentServiceChecks.php @@ -20,15 +20,99 @@ limitations under the License. */ -use DCarbone\PHPConsulAPI\AbstractModel; -use DCarbone\PHPConsulAPI\FakeSlice; - -class AgentServiceChecks extends FakeSlice +/** + * @implements \ArrayAccess + */ +class AgentServiceChecks implements \JsonSerializable, \Countable, \ArrayAccess { - protected string $containedClass = AgentServiceCheck::class; + /** @var \DCarbone\PHPConsulAPI\Agent\AgentServiceCheck[] */ + public array $Checks; + + /** + * @param iterable $Checks + */ + public function __construct( + iterable $Checks = [], + ) { + $this->setChecks(...$Checks); + } + + /** + * @return \DCarbone\PHPConsulAPI\Agent\AgentServiceCheck[] + */ + public function getChecks(): array + { + return $this->Checks; + } + + public function setChecks(AgentServiceCheck ...$Checks): self + { + $this->Checks = $Checks; + return $this; + } + + /** + * @return iterable + */ + public function getIterator(): iterable + { + if ([] === $this->Checks) { + return new \EmptyIterator(); + } + return new \ArrayIterator($this->Checks); + } + + public function count(): int + { + return count($this->Checks); + } + + public function offsetExists(mixed $offset): bool + { + return isset($this->Checks[$offset]); + } + + public function offsetGet(mixed $offset): null|AgentServiceCheck + { + return $this->Checks[$offset] ?? null; + } + + public function offsetSet(mixed $offset, mixed $value): void + { + if (is_int($offset) && $value instanceof AgentServiceCheck) { + $this->Checks[$offset] = $value; + } else { + throw new \InvalidArgumentException(sprintf( + 'Invalid offset %s or value %s, expected int and %s.', + var_export($offset, true), + var_export($value, true), + AgentServiceCheck::class + )); + } + } + + public function offsetUnset(mixed $offset): void + { + unset($this->Checks[$offset]); + } + + /** + * @param array<\stdClass> $decoded + */ + public static function jsonUnserialize(array $decoded): self + { + $n = new self(); + foreach ($decoded as $v) { + $n->Checks[] = AgentServiceCheck::jsonUnserialize($v); + } + return $n; + } - protected function newChild(array $data): AbstractModel + /** + * @return array + */ + public function jsonSerialize(): array { - return new AgentServiceCheck($data); + return $this->Checks; } } diff --git a/src/Agent/AgentServiceChecksInfo.php b/src/Agent/AgentServiceChecksInfo.php index f2fb3dd6..b35aee11 100644 --- a/src/Agent/AgentServiceChecksInfo.php +++ b/src/Agent/AgentServiceChecksInfo.php @@ -20,38 +20,24 @@ limitations under the License. */ -use DCarbone\PHPConsulAPI\AbstractModel; use DCarbone\PHPConsulAPI\Health\HealthChecks; -use DCarbone\PHPConsulAPI\Transcoding; +use DCarbone\PHPConsulAPI\PHPLib\AbstractType; -class AgentServiceChecksInfo extends AbstractModel +class AgentServiceChecksInfo extends AbstractType { - protected const FIELDS = [ - self::FIELD_SERVICE => [ - Transcoding::FIELD_TYPE => Transcoding::OBJECT, - Transcoding::FIELD_CLASS => AgentService::class, - Transcoding::FIELD_NULLABLE => true, - ], - self::FIELD_CHECKS => [ - Transcoding::FIELD_TYPE => Transcoding::OBJECT, - Transcoding::FIELD_CLASS => HealthChecks::class, - ], - ]; - - private const FIELD_SERVICE = 'Service'; - private const FIELD_CHECKS = 'Checks'; - - public string $AggregatedStatus = ''; - public ?AgentService $Service = null; + public string $AggregatedStatus; + public null|AgentService $Service; public HealthChecks $Checks; - public function __construct(?array $data = null) - { - parent::__construct($data); - if (!isset($this->Checks)) { - $this->Checks = new HealthChecks(); - } - } + public function __construct( + string $AggregatedStatus = '', + null|AgentService $Service = null, + null|HealthChecks $Checks = null, + ) { + $this->AggregatedStatus = $AggregatedStatus; + $this->Service = $Service; + $this->Checks = $Checks ?? new HealthChecks(); +} public function getAggregatedStatus(): string { @@ -64,12 +50,12 @@ public function setAggregatedStatus(string $AggregatedStatus): self return $this; } - public function getService(): ?AgentService + public function getService(): null|AgentService { return $this->Service; } - public function setService(?AgentService $Service): self + public function setService(null|AgentService $Service): self { $this->Service = $Service; return $this; @@ -85,6 +71,31 @@ public function setChecks(HealthChecks $Checks): self $this->Checks = $Checks; return $this; } + + public static function jsonUnserialize(\stdClass $decoded): self + { + $n = new self(); + foreach ((array)$decoded as $k => $v) { + if ('Checks' === $k) { + $n->Checks = HealthChecks::jsonUnserialize($v); + } elseif ('Service' === $k) { + $n->Service = null === $v ? null : AgentService::jsonUnserialize($v); + } else { + $n->{$k} = $v; + } + } + return $n; + } + + public function jsonSerialize(): \stdClass + { + $out = $this->_startJsonSerialize(); + $out->AggregatedStatus = $this->AggregatedStatus; + $out->Service = $this->Service; + $out->Checks = $this->Checks; + return $out; + } + public function __toString(): string { return $this->AggregatedStatus; diff --git a/src/Agent/AgentServiceConnect.php b/src/Agent/AgentServiceConnect.php index 3f629e57..c98892dc 100644 --- a/src/Agent/AgentServiceConnect.php +++ b/src/Agent/AgentServiceConnect.php @@ -20,25 +20,20 @@ limitations under the License. */ -use DCarbone\PHPConsulAPI\AbstractModel; -use DCarbone\PHPConsulAPI\Transcoding; +use DCarbone\PHPConsulAPI\PHPLib\AbstractType; -class AgentServiceConnect extends AbstractModel +class AgentServiceConnect extends AbstractType { - protected const FIELDS = [ - self::FIELD_NATIVE => Transcoding::OMITEMPTY_BOOLEAN_FIELD, - self::FIELD_SIDECAR_SERVICE => [ - Transcoding::FIELD_TYPE => Transcoding::ARRAY, - Transcoding::FIELD_CLASS => AgentServiceRegistration::class, - Transcoding::FIELD_OMITEMPTY => true, - ], - ]; + public bool $Native; + public null|AgentServiceRegistration $SidecarService; - private const FIELD_NATIVE = 'Native'; - private const FIELD_SIDECAR_SERVICE = 'SidecarService'; - - public bool $Native = false; - public array $SidecarService = []; + public function __construct( + bool $Native = false, + null|AgentServiceRegistration $SidecarService = null, + ) { + $this->Native = $Native; + $this->SidecarService = $SidecarService; +} public function isNative(): bool { @@ -51,14 +46,39 @@ public function setNative(bool $Native): self return $this; } - public function getSidecarService(): array + public function getSidecarService(): null|AgentServiceRegistration { return $this->SidecarService; } - public function setSidecarService(array $SidecarService): self + public function setSidecarService(AgentServiceRegistration $SidecarService): self { $this->SidecarService = $SidecarService; return $this; } + + public static function jsonUnserialize(\stdClass $decoded): self + { + $n = new self(); + foreach ((array)$decoded as $k => $v) { + if ('SidecarService' === $k) { + $n->SidecarService = AgentServiceRegistration::jsonUnserialize($v); + } else { + $n->{$k} = $v; + } + } + return $n; + } + + public function jsonSerialize(): \stdClass + { + $out = $this->_startJsonSerialize(); + if ($this->Native) { + $out->Native = $this->Native; + } + if (null !== $this->SidecarService) { + $out->SidecarService = $this->SidecarService; + } + return $out; + } } diff --git a/src/Agent/AgentServiceConnectProxyConfig.php b/src/Agent/AgentServiceConnectProxyConfig.php index 0fc59582..f63016b1 100644 --- a/src/Agent/AgentServiceConnectProxyConfig.php +++ b/src/Agent/AgentServiceConnectProxyConfig.php @@ -20,77 +20,71 @@ limitations under the License. */ -use DCarbone\PHPConsulAPI\AbstractModel; +use DCarbone\PHPConsulAPI\ConfigEntry\AccessLogsConfig; +use DCarbone\PHPConsulAPI\ConfigEntry\EnvoyExtension; use DCarbone\PHPConsulAPI\ConfigEntry\ExposeConfig; use DCarbone\PHPConsulAPI\ConfigEntry\MeshGatewayConfig; -use DCarbone\PHPConsulAPI\FakeMap; -use DCarbone\PHPConsulAPI\Transcoding; +use DCarbone\PHPConsulAPI\ConfigEntry\ProxyMode; +use DCarbone\PHPConsulAPI\ConfigEntry\TransparentProxyConfig; +use DCarbone\PHPConsulAPI\PHPLib\AbstractType; -class AgentServiceConnectProxyConfig extends AbstractModel +class AgentServiceConnectProxyConfig extends AbstractType { - protected const FIELDS = [ - self::FIELD_ENVOY_EXTENSIONS => [ - Transcoding::FIELD_CLASS => EnvoyExtension::class, - Transcoding::FIELD_TYPE => Transcoding::ARRAY, - Transcoding::FIELD_ARRAY_TYPE => Transcoding::OBJECT, - Transcoding::FIELD_OMITEMPTY => true, - ], - self::FIELD_DESTINATION_SERVICE_NAME => Transcoding::OMITEMPTY_STRING_FIELD, - self::FIELD_DESTINATION_SERVICE_ID => Transcoding::OMITEMPTY_STRING_FIELD, - self::FIELD_LOCAL_SERVICE_ADDRESS => Transcoding::OMITEMPTY_STRING_FIELD, - self::FIELD_LOCAL_SERVICE_PORT => Transcoding::OMITEMPTY_INTEGER_FIELD, - self::FIELD_CONFIG => Transcoding::OMITEMPTY_MAP_FIELD, - self::FIELD_UPSTREAMS => [ - Transcoding::FIELD_TYPE => Transcoding::ARRAY, - Transcoding::FIELD_CLASS => Upstream::class, - Transcoding::FIELD_ARRAY_TYPE => Transcoding::OBJECT, - Transcoding::FIELD_OMITEMPTY => true, - ], - self::FIELD_MESH_GATEWAY => [ - Transcoding::FIELD_TYPE => Transcoding::OBJECT, - Transcoding::FIELD_CLASS => MeshGatewayConfig::class, - Transcoding::FIELD_OMITEMPTY => true, - ], - self::FIELD_EXPOSE => [ - Transcoding::FIELD_TYPE => Transcoding::OBJECT, - Transcoding::FIELD_CLASS => ExposeConfig::class, - ], - ]; - - private const FIELD_ENVOY_EXTENSIONS = 'EnvoyExtension'; - private const FIELD_DESTINATION_SERVICE_NAME = 'DestinationServiceName'; - private const FIELD_DESTINATION_SERVICE_ID = 'DestinationServiceID'; - private const FIELD_LOCAL_SERVICE_ADDRESS = 'LocalServiceAddress'; - private const FIELD_LOCAL_SERVICE_PORT = 'LocalServicePort'; - private const FIELD_CONFIG = 'Config'; - private const FIELD_UPSTREAMS = 'Upstreams'; - private const FIELD_MESH_GATEWAY = 'MeshGateway'; - private const FIELD_EXPOSE = 'Expose'; - - public array $EnvoyExtensions = []; - public string $DestinationServiceName = ''; - public string $DestinationServiceID = ''; - public string $LocalServiceAddress = ''; - public int $LocalServicePort = 0; - public ?FakeMap $Config = null; - public string $LocalServiceSocketPath = ''; - public string $Mode = ''; - public ?TransparentProxyConfig $TransparentProxy = null; - public array $Upstreams = []; - public MeshGatewayConfig $MeshGateway; - public ExposeConfig $Expose; - - public function __construct(?array $data = []) - { - parent::__construct($data); - if (!isset($this->MeshGateway)) { - $this->MeshGateway = new MeshGatewayConfig(null); - } - if (!isset($this->Expose)) { - $this->Expose = new ExposeConfig(null); - } + /** @var array<\DCarbone\PHPConsulAPI\ConfigEntry\EnvoyExtension> */ + public array $EnvoyExtensions; + public string $DestinationServiceName; + public string $DestinationServiceID; + public string $LocalServiceAddress; + public int $LocalServicePort; + public string $LocalServiceSocketPath; + public ProxyMode $Mode; + public null|TransparentProxyConfig $TransparentProxy; + /** @var null|array */ + public null|array $Config = null; + /** @var \DCarbone\PHPConsulAPI\Agent\Upstream[] */ + public array $Upstreams; + public null|MeshGatewayConfig $MeshGateway; + public null|ExposeConfig $Expose; + public null|AccessLogsConfig $AccessLogs; + + /** + * @param array<\DCarbone\PHPConsulAPI\ConfigEntry\EnvoyExtension> $EnvoyExtensions + * @param array $Config + * @param array<\DCarbone\PHPConsulAPI\Agent\Upstream> $Upstreams + */ + public function __construct( + iterable $EnvoyExtensions = [], + string $DestinationServiceName = '', + string $DestinationServiceID = '', + string $LocalServiceAddress = '', + int $LocalServicePort = 0, + string $LocalServiceSocketPath = '', + string|ProxyMode $Mode = ProxyMode::Default, + null|TransparentProxyConfig $TransparentProxy = null, + array $Config = [], + iterable $Upstreams = [], + null|MeshGatewayConfig $MeshGateway = null, + null|ExposeConfig $Expose = null, + null|AccessLogsConfig $AccessLogs = null, + ) { + $this->setEnvoyExtensions(...$EnvoyExtensions); + $this->DestinationServiceName = $DestinationServiceName; + $this->DestinationServiceID = $DestinationServiceID; + $this->LocalServiceAddress = $LocalServiceAddress; + $this->LocalServicePort = $LocalServicePort; + $this->setConfig($Config); + $this->LocalServiceSocketPath = $LocalServiceSocketPath; + $this->Mode = $Mode instanceof ProxyMode ? $Mode : ProxyMode::from($Mode); + $this->TransparentProxy = $TransparentProxy; + $this->setUpstreams(...$Upstreams); + $this->MeshGateway = $MeshGateway; + $this->Expose = $Expose; + $this->AccessLogs = $AccessLogs; } + /** + * @return \DCarbone\PHPConsulAPI\ConfigEntry\EnvoyExtension[] + */ public function getEnvoyExtensions(): array { return $this->EnvoyExtensions; @@ -102,7 +96,7 @@ public function addEnvoyExtension(EnvoyExtension $envoyExtension): self return $this; } - public function setEnvoyExtensions(array $EnvoyExtensions): self + public function setEnvoyExtensions(EnvoyExtension ...$EnvoyExtensions): self { $this->EnvoyExtensions = $EnvoyExtensions; return $this; @@ -163,69 +157,173 @@ public function setLocalServiceSocketPath(string $LocalServiceSocketPath): self return $this; } - public function getMode(): string + public function getMode(): ProxyMode { return $this->Mode; } - public function setMode(string $Mode): self + public function setMode(string|ProxyMode $Mode): self { - $this->Mode = $Mode; + $this->Mode = $Mode instanceof ProxyMode ? $Mode : ProxyMode::from($Mode); return $this; } - public function getTransparentProxy(): ?TransparentProxyConfig + public function getTransparentProxy(): null|TransparentProxyConfig { return $this->TransparentProxy; } - public function setTransparentProxy(?TransparentProxyConfig $TransparentProxy): self + public function setTransparentProxy(null|TransparentProxyConfig $TransparentProxy): self { $this->TransparentProxy = $TransparentProxy; return $this; } - public function getConfig(): ?FakeMap + /** + * @return array|null + */ + public function getConfig(): null|array { return $this->Config; } - public function setConfig(array|FakeMap|\stdClass|null $Config): self + /** + * @param \stdClass|array|null $Config + * @return $this + */ + public function setConfig(null|\stdClass|array $Config): self { - $this->Config = FakeMap::parse($Config); + if (null === $Config) { + $this->Config = null; + return $this; + } + $this->Config = []; + foreach ($Config as $k => $v) { + $this->Config[$k] = $v; + } return $this; } + /** + * @return \DCarbone\PHPConsulAPI\Agent\Upstream[] + */ public function getUpstreams(): array { return $this->Upstreams; } - public function setUpstreams(array $Upstreams): self + public function setUpstreams(Upstream ...$Upstreams): self { $this->Upstreams = $Upstreams; return $this; } - public function getMeshGateway(): MeshGatewayConfig + public function getMeshGateway(): null|MeshGatewayConfig { return $this->MeshGateway; } - public function setMeshGateway(MeshGatewayConfig $MeshGateway): self + public function setMeshGateway(null|MeshGatewayConfig $MeshGateway): self { $this->MeshGateway = $MeshGateway; return $this; } - public function getExpose(): ExposeConfig + public function getExpose(): null|ExposeConfig { return $this->Expose; } - public function setExpose(ExposeConfig $Expose): self + public function setExpose(null|ExposeConfig $Expose): self { $this->Expose = $Expose; return $this; } + + public function getAccessLogs(): null|AccessLogsConfig + { + return $this->AccessLogs; + } + + public function setAccessLogs(null|AccessLogsConfig $AccessLogs): self + { + $this->AccessLogs = $AccessLogs; + return $this; + } + + public static function jsonUnserialize(\stdClass $decoded): self + { + $n = new self(); + foreach ((array)$decoded as $k => $v) { + if ('EnvoyExtensions' === $k) { + foreach ($v as $vv) { + $n->EnvoyExtensions[] = EnvoyExtension::jsonUnserialize($vv); + } + } elseif ('Mode' === $k) { + $n->setMode($v); + } elseif ('TransparentProxy' === $k) { + $n->TransparentProxy = TransparentProxyConfig::jsonUnserialize($v); + } elseif ('Upstreams' === $k) { + foreach ($v as $vv) { + $n->Upstreams[] = Upstream::jsonUnserialize($vv); + } + } elseif ('MeshGateway' === $k) { + $n->MeshGateway = MeshGatewayConfig::jsonUnserialize($v); + } elseif ('Expose' === $k) { + $n->Expose = ExposeConfig::jsonUnserialize($v); + } elseif ('AccessLogs' === $k) { + $n->AccessLogs = null === $v ? null : AccessLogsConfig::jsonUnserialize($v); + } elseif ('Config' === $k) { + $n->setConfig($v); + } else { + $n->{$k} = $v; + } + } + return $n; + } + + public function jsonSerialize(): \stdClass + { + $out = $this->_startJsonSerialize(); + if ([] !== $this->EnvoyExtensions) { + $out->EnvoyExtensions = $this->EnvoyExtensions; + } + if ('' !== $this->DestinationServiceName) { + $out->DestinationServiceName = $this->DestinationServiceName; + } + if ('' !== $this->DestinationServiceID) { + $out->DestinationServiceID = $this->DestinationServiceID; + } + if ('' !== $this->LocalServiceAddress) { + $out->LocalServiceAddress = $this->LocalServiceAddress; + } + if (0 !== $this->LocalServicePort) { + $out->LocalServicePort = $this->LocalServicePort; + } + if (null !== $this->Config) { + $out->Config = $this->Config; + } + if ('' !== $this->LocalServiceSocketPath) { + $out->LocalServiceSocketPath = $this->LocalServiceSocketPath; + } + if (ProxyMode::Default !== $this->Mode) { + $out->Mode = $this->Mode->value; + } + if (null !== $this->TransparentProxy) { + $out->TransparentProxy = $this->TransparentProxy; + } + if ([] !== $this->Upstreams) { + $out->Upstreams = $this->Upstreams; + } + if (null !== $this->MeshGateway) { + $out->MeshGateway = $this->MeshGateway; + } + if (null !== $this->Expose) { + $out->Expose = $this->Expose; + } + if (null !== $this->AccessLogs) { + $out->AccessLogs = $this->AccessLogs; + } + return $out; + } } diff --git a/src/Agent/AgentServiceRegistration.php b/src/Agent/AgentServiceRegistration.php index f565821b..0f09819e 100644 --- a/src/Agent/AgentServiceRegistration.php +++ b/src/Agent/AgentServiceRegistration.php @@ -20,112 +20,85 @@ limitations under the License. */ -use DCarbone\PHPConsulAPI\AbstractModel; use DCarbone\PHPConsulAPI\Catalog\ServiceAddress; -use DCarbone\PHPConsulAPI\HasSettableStringTags; -use DCarbone\PHPConsulAPI\HasStringTags; -use DCarbone\PHPConsulAPI\Transcoding; +use DCarbone\PHPConsulAPI\Peering\Locality; +use DCarbone\PHPConsulAPI\PHPLib\AbstractType; +use DCarbone\PHPConsulAPI\PHPLib\MetaField; -class AgentServiceRegistration extends AbstractModel +class AgentServiceRegistration extends AbstractType { - use HasSettableStringTags; - use HasStringTags; - - protected const FIELDS = [ - self::FIELD_KIND => Transcoding::OMITEMPTY_STRING_FIELD, - self::FIELD_ID => Transcoding::OMITEMPTY_STRING_FIELD, - self::FIELD_NAME => Transcoding::OMITEMPTY_STRING_FIELD, - self::FIELD_PORT => Transcoding::OMITEMPTY_INTEGER_FIELD, - self::FIELD_ADDRESS => Transcoding::OMITEMPTY_STRING_FIELD, - self::FIELD_TAGGED_ADDRESSES => [ - Transcoding::FIELD_TYPE => Transcoding::ARRAY, - Transcoding::FIELD_CLASS => ServiceAddress::class, - Transcoding::FIELD_ARRAY_TYPE => Transcoding::OBJECT, - Transcoding::FIELD_OMITEMPTY => true, - ], - self::FIELD_ENABLE_TAG_OVERRIDE => Transcoding::OMITEMPTY_BOOLEAN_FIELD, - self::FIELD_META => [ - Transcoding::FIELD_TYPE => Transcoding::ARRAY, - Transcoding::FIELD_ARRAY_TYPE => Transcoding::MIXED, - Transcoding::FIELD_OMITEMPTY => true, - ], - self::FIELD_WEIGHTS => [ - Transcoding::FIELD_TYPE => Transcoding::OBJECT, - Transcoding::FIELD_CLASS => AgentWeights::class, - Transcoding::FIELD_NULLABLE => true, - Transcoding::FIELD_OMITEMPTY => true, - ], - self::FIELD_CHECK => [ - Transcoding::FIELD_TYPE => Transcoding::OBJECT, - Transcoding::FIELD_CLASS => AgentServiceCheck::class, - Transcoding::FIELD_NULLABLE => true, - ], - self::FIELD_CHECKS => [ - Transcoding::FIELD_TYPE => Transcoding::ARRAY, - Transcoding::FIELD_CLASS => AgentServiceChecks::class, - Transcoding::FIELD_ARRAY_TYPE => Transcoding::OBJECT, - ], - self::FIELD_PROXY => [ - Transcoding::FIELD_TYPE => Transcoding::OBJECT, - Transcoding::FIELD_CLASS => AgentServiceConnectProxyConfig::class, - Transcoding::FIELD_NULLABLE => true, - Transcoding::FIELD_OMITEMPTY => true, - ], - self::FIELD_CONNECT => [ - Transcoding::FIELD_TYPE => Transcoding::OBJECT, - Transcoding::FIELD_CLASS => AgentServiceConnect::class, - Transcoding::FIELD_NULLABLE => true, - Transcoding::FIELD_OMITEMPTY => true, - ], - self::FIELD_NAMESPACE => Transcoding::OMITEMPTY_STRING_FIELD, - ]; - - private const FIELD_KIND = 'Kind'; - private const FIELD_ID = 'ID'; - private const FIELD_NAME = 'Name'; - private const FIELD_PORT = 'Port'; - private const FIELD_ADDRESS = 'Address'; - private const FIELD_TAGGED_ADDRESSES = 'TaggedAddresses'; - private const FIELD_ENABLE_TAG_OVERRIDE = 'EnableTagOverride'; - private const FIELD_META = 'Meta'; - private const FIELD_WEIGHTS = 'Weights'; - private const FIELD_CHECK = 'Check'; - private const FIELD_CHECKS = 'Checks'; - private const FIELD_PROXY = 'Proxy'; - private const FIELD_CONNECT = 'Connect'; - private const FIELD_NAMESPACE = 'Namespace'; - - public string $Kind = ''; - public string $ID = ''; - public string $Name = ''; - public int $Port = 0; - public string $Address = ''; - public array $TaggedAddresses = []; - public bool $EnableTagOverride = false; - public array $Meta = []; - public ?AgentWeights $Weights = null; - public ?AgentServiceCheck $Check = null; + use MetaField; + + public ServiceKind $Kind; + public string $ID; + public string $Name; + /** @var string[] */ + public array $Tags; + public int $Port; + public string $Address; + /** @var null|array<\DCarbone\PHPConsulAPI\Catalog\ServiceAddress> */ + public null|array $TaggedAddresses = null; + public bool $EnableTagOverride; + public null|AgentWeights $Weights; + public null|AgentServiceCheck $Check; public AgentServiceChecks $Checks; - public ?AgentServiceConnectProxyConfig $Proxy = null; - public ?AgentServiceConnect $Connect = null; - public string $Namespace = ''; - - public function __construct(?array $data = []) - { - parent::__construct($data); - if (!isset($this->Checks)) { - $this->Checks = new AgentServiceChecks(null); - } + public null|AgentServiceConnectProxyConfig $Proxy; + public null|AgentServiceConnect $Connect; + public string $Namespace; + public string $Partition; + public null|Locality $Locality; + + /** + * @param array $Tags + * @param array $TaggedAddresses + * @param array $Meta + */ + public function __construct( + string|ServiceKind $Kind = ServiceKind::Typical, + string $ID = '', + string $Name = '', + array $Tags = [], + int $Port = 0, + string $Address = '', + array $TaggedAddresses = [], + bool $EnableTagOverride = false, + array $Meta = [], + null|AgentWeights $Weights = null, + null|AgentServiceCheck $Check = null, + null|AgentServiceChecks $Checks = null, + null|AgentServiceConnectProxyConfig $Proxy = null, + null|AgentServiceConnect $Connect = null, + string $Namespace = '', + string $Partition = '', + null|Locality $Locality = null, + ) { + $this->Kind = is_string($Kind) ? ServiceKind::from($Kind) : $Kind; + $this->ID = $ID; + $this->Name = $Name; + $this->setTags(...$Tags); + $this->Port = $Port; + $this->Address = $Address; + $this->setTaggedAddresses($TaggedAddresses ?: null); + $this->EnableTagOverride = $EnableTagOverride; + $this->setMeta($Meta); + $this->Weights = $Weights; + $this->Check = $Check; + $this->Checks = $Checks ?? new AgentServiceChecks(); + $this->Proxy = $Proxy; + $this->Connect = $Connect; + $this->Namespace = $Namespace; + $this->Partition = $Partition; + $this->Locality = $Locality; } - public function getKind(): string + public function getKind(): ServiceKind { return $this->Kind; } - public function setKind(string $Kind): self + public function setKind(string|ServiceKind $Kind): self { - $this->Kind = $Kind; + $this->Kind = $Kind instanceof ServiceKind ? $Kind : ServiceKind::from($Kind); return $this; } @@ -151,6 +124,20 @@ public function setName(string $Name): self return $this; } + /** + * @return string[] + */ + public function getTags(): array + { + return $this->Tags; + } + + public function setTags(string ...$Tags): self + { + $this->Tags = $Tags; + return $this; + } + public function getPort(): int { return $this->Port; @@ -173,56 +160,68 @@ public function setAddress(string $Address): self return $this; } - public function getTaggedAddresses(): ?array + /** + * @return array|null + */ + public function getTaggedAddresses(): null|array { return $this->TaggedAddresses; } - public function setTaggedAddresses(array $TaggedAddresses): self + public function setTaggedAddress(string $Tag, ServiceAddress $Address): self { - $this->TaggedAddresses = $TaggedAddresses; + if (null === $this->TaggedAddresses) { + $this->TaggedAddresses = []; + } + $this->TaggedAddresses[$Tag] = $Address; return $this; } - public function isEnableTagOverride(): bool - { - return $this->EnableTagOverride; - } - - public function setEnableTagOverride(bool $EnableTagOverride): self + /** + * @param array|null $TaggedAddresses + * @return $this + */ + public function setTaggedAddresses(null|array $TaggedAddresses): self { - $this->EnableTagOverride = $EnableTagOverride; + if (null === $TaggedAddresses) { + $this->TaggedAddresses = null; + return $this; + } + $this->TaggedAddresses = []; + foreach ($TaggedAddresses as $k => $v) { + $this->setTaggedAddress($k, $v); + } return $this; } - public function getMeta(): ?array + public function isEnableTagOverride(): bool { - return $this->Meta; + return $this->EnableTagOverride; } - public function setMeta(array $Meta): self + public function setEnableTagOverride(bool $EnableTagOverride): self { - $this->Meta = $Meta; + $this->EnableTagOverride = $EnableTagOverride; return $this; } - public function getWeights(): ?AgentWeights + public function getWeights(): null|AgentWeights { return $this->Weights; } - public function setWeights(?AgentWeights $Weights): self + public function setWeights(null|AgentWeights $Weights): self { $this->Weights = $Weights; return $this; } - public function getCheck(): ?AgentServiceCheck + public function getCheck(): null|AgentServiceCheck { return $this->Check; } - public function setCheck(?AgentServiceCheck $Check): self + public function setCheck(null|AgentServiceCheck $Check): self { $this->Check = $Check; return $this; @@ -239,23 +238,23 @@ public function setChecks(AgentServiceChecks $Checks): self return $this; } - public function getProxy(): ?AgentServiceConnectProxyConfig + public function getProxy(): null|AgentServiceConnectProxyConfig { return $this->Proxy; } - public function setProxy(?AgentServiceConnectProxyConfig $Proxy): self + public function setProxy(null|AgentServiceConnectProxyConfig $Proxy): self { $this->Proxy = $Proxy; return $this; } - public function getConnect(): ?AgentServiceConnect + public function getConnect(): null|AgentServiceConnect { return $this->Connect; } - public function setConnect(?AgentServiceConnect $Connect): self + public function setConnect(null|AgentServiceConnect $Connect): self { $this->Connect = $Connect; return $this; @@ -271,6 +270,116 @@ public function setNamespace(string $Namespace): self $this->Namespace = $Namespace; return $this; } + + public function getPartition(): string + { + return $this->Partition; + } + + public function setPartition(string $Partition): self + { + $this->Partition = $Partition; + return $this; + } + + public function getLocality(): null|Locality + { + return $this->Locality; + } + + public function setLocality(null|Locality $Locality): self + { + $this->Locality = $Locality; + return $this; + } + + public static function jsonUnserialize(\stdClass $decoded): self + { + $n = new self(); + foreach ((array)$decoded as $k => $v) { + if ('Kind' === $k) { + $n->setKind($v); + } elseif ('Tags' === $k) { + $n->setTags(...$v); + } elseif ('TaggedAddresses' === $k) { + $n->TaggedAddresses = []; + foreach ($v as $kk => $vv) { + $n->TaggedAddresses[$kk] = ServiceAddress::jsonUnserialize($vv); + } + } elseif ('Weights' === $k) { + $n->Weights = AgentWeights::jsonUnserialize($v); + } elseif ('Check' === $k) { + $n->Check = AgentServiceCheck::jsonUnserialize($v); + } elseif ('Checks' === $k) { + $n->Checks = AgentServiceChecks::jsonUnserialize($v); + } elseif ('Proxy' === $k) { + $n->Proxy = AgentServiceConnectProxyConfig::jsonUnserialize($v); + } elseif ('Connect' === $k) { + $n->Connect = AgentServiceConnect::jsonUnserialize($v); + } elseif ('Locality' === $k) { + $n->Locality = Locality::jsonUnserialize($v); + } elseif ('Meta' === $k) { + $n->setMeta($v); + } else { + $n->{$k} = $v; + } + } + return $n; + } + + public function jsonSerialize(): \stdClass + { + $out = $this->_startJsonSerialize(); + if ($this->Kind !== ServiceKind::Typical) { + $out->Kind = $this->Kind; + } + if ('' !== $this->ID) { + $out->ID = $this->ID; + } + if ('' !== $this->Name) { + $out->Name = $this->Name; + } + if ([] !== $this->Tags) { + $out->Tags = $this->Tags; + } + if (0 !== $this->Port) { + $out->Port = $this->Port; + } + if ('' !== $this->Address) { + $out->Address = $this->Address; + } + if (null !== $this->TaggedAddresses && [] !== $this->TaggedAddresses) { + $out->TaggedAddresses = $this->TaggedAddresses; + } + if ($this->EnableTagOverride) { + $out->EnableTagOverride = $this->EnableTagOverride; + } + if (null !== $this->Meta) { + $out->Meta = $this->Meta; + } + if (null !== $this->Weights) { + $out->Weights = $this->Weights; + } + $out->Check = $this->Check; + $out->Checks = $this->Checks; + if (null !== $this->Proxy) { + $out->Proxy = $this->Proxy; + } + if (null !== $this->Connect) { + $out->Connect = $this->Connect; + } + if ('' !== $this->Namespace) { + $out->Namespace = $this->Namespace; + } + if ('' !== $this->Partition) { + $out->Partition = $this->Partition; + } + if (null !== $this->Locality) { + $out->Locality = $this->Locality; + } + return $out; + } + public function __toString(): string { return $this->Name; diff --git a/src/Agent/AgentServiceResponse.php b/src/Agent/AgentServiceResponse.php index 35e871ad..1af541e7 100644 --- a/src/Agent/AgentServiceResponse.php +++ b/src/Agent/AgentServiceResponse.php @@ -20,20 +20,24 @@ limitations under the License. */ -use DCarbone\PHPConsulAPI\AbstractValuedResponse; -use DCarbone\PHPConsulAPI\UnmarshalledResponseInterface; +use DCarbone\PHPConsulAPI\PHPLib\AbstractValuedResponse; +use DCarbone\PHPConsulAPI\PHPLib\UnmarshalledResponseInterface; class AgentServiceResponse extends AbstractValuedResponse implements UnmarshalledResponseInterface { - public ?AgentService $Service = null; + public null|AgentService $Service = null; - public function getValue(): ?AgentService + public function getValue(): null|AgentService { return $this->Service; } - public function unmarshalValue(mixed $decodedData): void + public function unmarshalValue(mixed $decoded): void { - $this->Service = new AgentService((array)$decodedData); + if (null === $decoded) { + $this->Service = null; + return; + } + $this->Service = AgentService::jsonUnserialize($decoded); } } diff --git a/src/Agent/AgentServicesResponse.php b/src/Agent/AgentServicesResponse.php index 2d559cbb..2f837091 100644 --- a/src/Agent/AgentServicesResponse.php +++ b/src/Agent/AgentServicesResponse.php @@ -20,23 +20,31 @@ limitations under the License. */ -use DCarbone\PHPConsulAPI\AbstractValuedResponse; -use DCarbone\PHPConsulAPI\UnmarshalledResponseInterface; +use DCarbone\PHPConsulAPI\PHPLib\AbstractValuedResponse; +use DCarbone\PHPConsulAPI\PHPLib\UnmarshalledResponseInterface; class AgentServicesResponse extends AbstractValuedResponse implements UnmarshalledResponseInterface { - public ?array $Services = null; + /** @var null|array */ + public null|array $Services = null; - public function getValue(): ?array + /** + * @return array|null + */ + public function getValue(): null|array { return $this->Services; } - public function unmarshalValue(mixed $decodedData): void + public function unmarshalValue(mixed $decoded): void { + if (null === $decoded) { + $this->Services = null; + return; + } $this->Services = []; - foreach ($decodedData as $k => $service) { - $this->Services[$k] = new AgentService($service); + foreach ($decoded as $k => $v) { + $this->Services[$k] = AgentService::jsonUnserialize($v); } } } diff --git a/src/Agent/AgentToken.php b/src/Agent/AgentToken.php index 4f95dba6..5b84ad07 100644 --- a/src/Agent/AgentToken.php +++ b/src/Agent/AgentToken.php @@ -20,11 +20,17 @@ limitations under the License. */ -use DCarbone\PHPConsulAPI\AbstractModel; +use DCarbone\PHPConsulAPI\PHPLib\AbstractType; -class AgentToken extends AbstractModel +class AgentToken extends AbstractType { - public string $Token = ''; + public string $Token; + + public function __construct( + string $Token = '', + ) { + $this->Token = $Token; +} public function getToken(): string { @@ -36,4 +42,20 @@ public function setToken(string $Token): self $this->Token = $Token; return $this; } + + public static function jsonUnserialize(\stdClass $decoded): self + { + $n = new self(); + foreach ((array)$decoded as $k => $v) { + $n->{$k} = $v; + } + return $n; + } + + public function jsonSerialize(): \stdClass + { + $out = $this->_startJsonSerialize(); + $out->Token = $this->Token; + return $out; + } } diff --git a/src/Agent/AgentWeights.php b/src/Agent/AgentWeights.php index 19dcb0b4..1fb248d9 100644 --- a/src/Agent/AgentWeights.php +++ b/src/Agent/AgentWeights.php @@ -20,20 +20,57 @@ limitations under the License. */ -use DCarbone\PHPConsulAPI\AbstractModel; +use DCarbone\PHPConsulAPI\PHPLib\AbstractType; -class AgentWeights extends AbstractModel +class AgentWeights extends AbstractType { - public int $Passing = 0; - public int $Warning = 0; + public int $Passing; + public int $Warning; + + public function __construct( + int $Passing = 0, + int $Warning = 0, + ) { + $this->Passing = $Passing; + $this->Warning = $Warning; +} public function getPassing(): int { return $this->Passing; } + public function setPassing(int $Passing): self + { + $this->Passing = $Passing; + return $this; + } + public function getWarning(): int { return $this->Warning; } + + public function setWarning(int $Warning): self + { + $this->Warning = $Warning; + return $this; + } + + public static function jsonUnserialize(\stdClass $decoded): self + { + $n = new self(); + foreach ((array)$decoded as $k => $v) { + $n->{$k} = $v; + } + return $n; + } + + public function jsonSerialize(): \stdClass + { + $out = $this->_startJsonSerialize(); + $out->Passing = $this->Passing; + $out->Warning = $this->Warning; + return $out; + } } diff --git a/src/Agent/ConnectProxyConfig.php b/src/Agent/ConnectProxyConfig.php new file mode 100644 index 00000000..7341d8de --- /dev/null +++ b/src/Agent/ConnectProxyConfig.php @@ -0,0 +1,168 @@ + */ + public null|array $Config = null; + /** @var array<\DCarbone\PHPConsulAPI\Agent\Upstream> */ + public array $Upstreams; + + /** + * @param array $Config + * @param array<\DCarbone\PHPConsulAPI\Agent\Upstream> $Upstreams + */ + public function __construct( + string $ProxyServiceID = '', + string $TargetServiceID = '', + string $TargetServiceName = '', + string $ContentHash = '', + array $Config = [], + array $Upstreams = [], + ) { + $this->ProxyServiceID = $ProxyServiceID; + $this->TargetServiceID = $TargetServiceID; + $this->TargetServiceName = $TargetServiceName; + $this->ContentHash = $ContentHash; + $this->setConfig($Config); + $this->setUpstreams(...$Upstreams); +} + + public function getProxyServiceID(): string + { + return $this->ProxyServiceID; + } + + public function setProxyServiceID(string $ProxyServiceID): self + { + $this->ProxyServiceID = $ProxyServiceID; + return $this; + } + + public function getTargetServiceID(): string + { + return $this->TargetServiceID; + } + + public function setTargetServiceID(string $TargetServiceID): self + { + $this->TargetServiceID = $TargetServiceID; + return $this; + } + + public function getTargetServiceName(): string + { + return $this->TargetServiceName; + } + + public function setTargetServiceName(string $TargetServiceName): self + { + $this->TargetServiceName = $TargetServiceName; + return $this; + } + + public function getContentHash(): string + { + return $this->ContentHash; + } + + public function setContentHash(string $ContentHash): self + { + $this->ContentHash = $ContentHash; + return $this; + } + + /** + * @return null|array + */ + public function getConfig(): null|array + { + return $this->Config; + } + + /** + * @param \stdClass|array|null $Config + * @return $this + */ + public function setConfig(null|\stdClass|array $Config): self + { + if (null === $Config) { + $this->Config = null; + return $this; + } + $this->Config = []; + foreach ($Config as $k => $v) { + $this->Config[$k] = $v; + } + return $this; + } + + /** + * @return \DCarbone\PHPConsulAPI\Agent\Upstream[] + */ + public function getUpstreams(): array + { + return $this->Upstreams; + } + + public function setUpstreams(Upstream ...$Upstreams): self + { + $this->Upstreams = $Upstreams; + return $this; + } + + public static function jsonUnserialize(\stdClass $decoded): self + { + $n = new self(); + foreach ((array)$decoded as $k => $v) { + if ('Upstreams' === $k) { + $n->Upstreams = []; + foreach ($v as $vv) { + $n->Upstreams[] = Upstream::jsonUnserialize($vv); + } + } elseif ('Config' === $k) { + $n->setConfig($v); + } else { + $n->{$k} = $v; + } + } + return $n; + } + + public function jsonSerialize(): \stdClass + { + $out = $this->_startJsonSerialize(); + $out->ProxyServiceID = $this->ProxyServiceID; + $out->TargetServiceID = $this->TargetServiceID; + $out->TargetServiceName = $this->TargetServiceName; + $out->ContentHash = $this->ContentHash; + $out->Config = $this->getConfig(); + $out->Upstreams = $this->Upstreams; + return $out; + } +} diff --git a/src/Agent/EnvoyExtension.php b/src/Agent/EnvoyExtension.php deleted file mode 100644 index e433e843..00000000 --- a/src/Agent/EnvoyExtension.php +++ /dev/null @@ -1,103 +0,0 @@ - Transcoding::MAP_FIELD, - ]; - - private const FIELD_ARGUMENTS = 'Arguments'; - - public string $Name = ''; - public bool $Required = false; - public FakeMap $Arguments; - public string $ConsulVersion = ''; - public string $EnvoyVersion = ''; - - public function __construct(?array $data = []) - { - parent::__construct($data); - if (!isset($this->Arguments)) { - $this->Arguments = new FakeMap(null); - } - } - - public function getName(): string - { - return $this->Name; - } - - public function setName(string $Name): self - { - $this->Name = $Name; - return $this; - } - - public function isRequired(): bool - { - return $this->Required; - } - - public function setRequired(bool $Required): self - { - $this->Required = $Required; - return $this; - } - - public function getArguments(): ?FakeMap - { - return $this->Arguments; - } - - public function setArguments(array|FakeMap|\stdClass|null $Arguments): self - { - $this->Arguments = FakeMap::parse($Arguments); - return $this; - } - - public function getConsulVersion(): string - { - return $this->ConsulVersion; - } - - public function setConsulVersion(string $ConsulVersion): self - { - $this->ConsulVersion = $ConsulVersion; - return $this; - } - - public function getEnvoyVersion(): string - { - return $this->EnvoyVersion; - } - - public function setEnvoyVersion(string $EnvoyVersion): self - { - $this->EnvoyVersion = $EnvoyVersion; - return $this; - } -} diff --git a/src/Agent/GaugeValue.php b/src/Agent/GaugeValue.php index e1ec1a6b..f7c954cf 100644 --- a/src/Agent/GaugeValue.php +++ b/src/Agent/GaugeValue.php @@ -20,22 +20,36 @@ limitations under the License. */ -use DCarbone\PHPConsulAPI\AbstractModel; +use DCarbone\PHPConsulAPI\PHPLib\AbstractType; -class GaugeValue extends AbstractModel +class GaugeValue extends AbstractType { - public string $Name = ''; - public float $Value = 0.0; - public array $Labels = []; + public string $Name; + public float $Value; + /** @var null|array */ + public null|array $Labels = null; + + /** + * @param array $Labels + */ + public function __construct( + string $Name = '', + float $Value = 0.0, + array $Labels = [], + ) { + $this->Name = $Name; + $this->Value = $Value; + $this->setLabels($Labels); + } public function getName(): string { return $this->Name; } - public function setName(string $name): self + public function setName(string $Name): self { - $this->Name = $name; + $this->Name = $Name; return $this; } @@ -44,20 +58,56 @@ public function getValue(): float return $this->Value; } - public function setValue(float $value): self + public function setValue(float $Value): self { - $this->Value = $value; + $this->Value = $Value; return $this; } - public function getLabels(): array + /** + * @return null|array + */ + public function getLabels(): null|array { return $this->Labels; } - public function setLabels(array $labels): self + /** + * @param \stdClass|array|null $Labels + * @return $this + */ + public function setLabels(null|\stdClass|array $Labels): self { - $this->Labels = $labels; + if (null === $Labels) { + $this->Labels = null; + return $this; + } + $this->Labels = []; + foreach ($Labels as $k => $v) { + $this->Labels[$k] = $v; + } return $this; } + + public static function jsonUnserialize(\stdClass $decoded): self + { + $n = new self(); + foreach ((array)$decoded as $k => $v) { + if ('Labels' === $k) { + $n->setLabels($v); + } else { + $n->{$k} = $v; + } + } + return $n; + } + + public function jsonSerialize(): \stdClass + { + $out = $this->_startJsonSerialize(); + $out->Name = $this->Name; + $out->Value = $this->Value; + $out->Labels = $this->getLabels(); + return $out; + } } diff --git a/src/Agent/MemberACLMode.php b/src/Agent/MemberACLMode.php new file mode 100644 index 00000000..0d0e9607 --- /dev/null +++ b/src/Agent/MemberACLMode.php @@ -0,0 +1,47 @@ +WAN = $WAN; + $this->Segment = $Segment; + $this->Filter = $Filter; + } public function isWAN(): bool { return $this->WAN; } - public function setWAN(bool $wan): self + public function setWAN(bool $WAN): self { - $this->WAN = $wan; + $this->WAN = $WAN; return $this; } @@ -43,9 +54,44 @@ public function getSegment(): string return $this->Segment; } - public function setSegment(string $segment): self + public function setSegment(string $Segment): self { - $this->Segment = $segment; + $this->Segment = $Segment; return $this; } + + public function getFilter(): string + { + return $this->Filter; + } + + public function setFilter(string $Filter): self + { + $this->Filter = $Filter; + return $this; + } + + public static function jsonUnserialize(\stdClass $decoded): self + { + $n = new self(); + foreach ((array)$decoded as $k => $v) { + $n->{$k} = $v; + } + return $n; + } + + public function jsonSerialize(): \stdClass + { + $out = $this->_startJsonSerialize(); + if ($this->WAN) { + $out->WAN = $this->WAN; + } + if ('' !== $this->Segment) { + $out->Segment = $this->Segment; + } + if ('' !== $this->Filter) { + $out->Filter = $this->Filter; + } + return $out; + } } diff --git a/src/Agent/MetricsInfo.php b/src/Agent/MetricsInfo.php index d580ab99..09cfe40b 100644 --- a/src/Agent/MetricsInfo.php +++ b/src/Agent/MetricsInfo.php @@ -20,97 +20,146 @@ limitations under the License. */ -use DCarbone\PHPConsulAPI\AbstractModel; -use DCarbone\PHPConsulAPI\Transcoding; +use DCarbone\PHPConsulAPI\PHPLib\AbstractType; -class MetricsInfo extends AbstractModel +class MetricsInfo extends AbstractType { - protected const FIELDS = [ - self::FIELD_GAUGES => [ - Transcoding::FIELD_TYPE => Transcoding::ARRAY, - Transcoding::FIELD_CLASS => GaugeValue::class, - Transcoding::FIELD_ARRAY_TYPE => Transcoding::OBJECT, - ], - self::FIELD_POINTS => [ - Transcoding::FIELD_TYPE => Transcoding::ARRAY, - Transcoding::FIELD_CLASS => PointValue::class, - Transcoding::FIELD_ARRAY_TYPE => Transcoding::OBJECT, - ], - self::FIELD_COUNTERS => [ - Transcoding::FIELD_TYPE => Transcoding::ARRAY, - Transcoding::FIELD_CLASS => SampledValue::class, - Transcoding::FIELD_ARRAY_TYPE => Transcoding::OBJECT, - ], - self::FIELD_SAMPLES => [ - Transcoding::FIELD_TYPE => Transcoding::ARRAY, - Transcoding::FIELD_CLASS => SampledValue::class, - Transcoding::FIELD_ARRAY_TYPE => Transcoding::OBJECT, - ], - ]; - - private const FIELD_GAUGES = 'Gauges'; - private const FIELD_POINTS = 'Points'; - private const FIELD_COUNTERS = 'Counters'; - private const FIELD_SAMPLES = 'Samples'; - - public string $Timestamp = ''; - public array $Gauges = []; - public array $Points = []; - public array $Counters = []; - public array $Samples = []; + public string $Timestamp; + /** @var \DCarbone\PHPConsulAPI\Agent\GaugeValue[] */ + public array $Gauges; + /** @var \DCarbone\PHPConsulAPI\Agent\PointValue[] */ + public array $Points; + /** @var \DCarbone\PHPConsulAPI\Agent\SampledValue[] */ + public array $Counters; + /** @var \DCarbone\PHPConsulAPI\Agent\SampledValue[] */ + public array $Samples; + + /** + * @param array<\DCarbone\PHPConsulAPI\Agent\GaugeValue> $Gauges + * @param array<\DCarbone\PHPConsulAPI\Agent\PointValue> $Points + * @param array<\DCarbone\PHPConsulAPI\Agent\SampledValue> $Counters + * @param array<\DCarbone\PHPConsulAPI\Agent\SampledValue> $Samples + */ + public function __construct( + string $Timestamp = '', + array $Gauges = [], + array $Points = [], + array $Counters = [], + array $Samples = [], + ) { + $this->Timestamp = $Timestamp; + $this->setGauges(...$Gauges); + $this->setPoints(...$Points); + $this->setCounters(...$Counters); + $this->setSamples(...$Samples); + } public function getTimestamp(): string { return $this->Timestamp; } - public function setTimestamp(string $timestamp): self + public function setTimestamp(string $Timestamp): self { - $this->Timestamp = $timestamp; + $this->Timestamp = $Timestamp; return $this; } + /** + * @return \DCarbone\PHPConsulAPI\Agent\GaugeValue[] + */ public function getGauges(): array { return $this->Gauges; } - public function setGauges(array $gauges): self + public function setGauges(GaugeValue ...$gauges): self { $this->Gauges = $gauges; return $this; } + /** + * @return \DCarbone\PHPConsulAPI\Agent\PointValue[] + */ public function getPoints(): array { return $this->Points; } - public function setPoints(array $points): self + public function setPoints(PointValue ...$points): self { $this->Points = $points; return $this; } + /** + * @return \DCarbone\PHPConsulAPI\Agent\SampledValue[] + */ public function getCounters(): array { return $this->Counters; } - public function setCounters(array $counters): self + public function setCounters(SampledValue ...$counters): self { $this->Counters = $counters; return $this; } + /** + * @return \DCarbone\PHPConsulAPI\Agent\SampledValue[] + */ public function getSamples(): array { return $this->Samples; } - public function setSamples(array $samples): self + public function setSamples(SampledValue ...$samples): self { $this->Samples = $samples; return $this; } + + public static function jsonUnserialize(\stdClass $decoded): self + { + $n = new self(); + foreach ((array)$decoded as $k => $v) { + if ('Gauges' === $k) { + $n->Gauges = []; + foreach ($v as $vv) { + $n->Gauges[] = GaugeValue::jsonUnserialize($vv); + } + } elseif ('Points' === $k) { + $n->Points = []; + foreach ($v as $vv) { + $n->Points[] = PointValue::jsonUnserialize($vv); + } + } elseif ('Counters' === $k) { + $n->Counters = []; + foreach ($v as $vv) { + $n->Counters[] = SampledValue::jsonUnserialize($vv); + } + } elseif ('Samples' === $k) { + $n->Samples = []; + foreach ($v as $vv) { + $n->Samples[] = SampledValue::jsonUnserialize($vv); + } + } else { + $n->{$k} = $v; + } + } + return $n; + } + + public function jsonSerialize(): \stdClass + { + $out = $this->_startJsonSerialize(); + $out->Timestamp = $this->Timestamp; + $out->Gauges = $this->Gauges; + $out->Points = $this->Points; + $out->Counters = $this->Counters; + $out->Samples = $this->Samples; + return $out; + } } diff --git a/src/Agent/MetricsInfoResponse.php b/src/Agent/MetricsInfoResponse.php index da7e1ed9..1cb65e7f 100644 --- a/src/Agent/MetricsInfoResponse.php +++ b/src/Agent/MetricsInfoResponse.php @@ -20,20 +20,24 @@ limitations under the License. */ -use DCarbone\PHPConsulAPI\AbstractValuedResponse; -use DCarbone\PHPConsulAPI\UnmarshalledResponseInterface; +use DCarbone\PHPConsulAPI\PHPLib\AbstractValuedResponse; +use DCarbone\PHPConsulAPI\PHPLib\UnmarshalledResponseInterface; class MetricsInfoResponse extends AbstractValuedResponse implements UnmarshalledResponseInterface { - public ?MetricsInfo $MetricsInfo = null; + public null|MetricsInfo $MetricsInfo = null; - public function getValue(): ?MetricsInfo + public function getValue(): null|MetricsInfo { return $this->MetricsInfo; } - public function unmarshalValue(mixed $decodedData): void + public function unmarshalValue(mixed $decoded): void { - $this->MetricsInfo = new MetricsInfo((array)$decodedData); + if (null === $decoded) { + $this->MetricsInfo = null; + return; + } + $this->MetricsInfo = MetricsInfo::jsonUnserialize($decoded); } } diff --git a/src/Agent/PointValue.php b/src/Agent/PointValue.php index 00cd83fa..870679aa 100644 --- a/src/Agent/PointValue.php +++ b/src/Agent/PointValue.php @@ -20,32 +20,64 @@ limitations under the License. */ -use DCarbone\PHPConsulAPI\AbstractModel; +use DCarbone\PHPConsulAPI\PHPLib\AbstractType; -class PointValue extends AbstractModel +class PointValue extends AbstractType { - public string $Name = ''; - public array $Points = []; + public string $Name; + /** @var float[] */ + public array $Points; + + /** + * @param iterable $Points + */ + public function __construct( + string $Name = '', + iterable $Points = [], + ) { + $this->Name = $Name; + $this->setPoints(...$Points); +} public function getName(): string { return $this->Name; } - public function setName(string $name): self + public function setName(string $Name): self { - $this->Name = $name; + $this->Name = $Name; return $this; } + /** + * @return float[] + */ public function getPoints(): array { return $this->Points; } - public function setPoints(array $points): self + public function setPoints(float ...$points): self { $this->Points = $points; return $this; } + + public static function jsonUnserialize(\stdClass $decoded): self + { + $n = new self(); + foreach ((array)$decoded as $k => $v) { + $n->{$k} = $v; + } + return $n; + } + + public function jsonSerialize(): \stdClass + { + $out = $this->_startJsonSerialize(); + $out->Name = $this->Name; + $out->Points = $this->Points; + return $out; + } } diff --git a/src/Agent/SampledValue.php b/src/Agent/SampledValue.php index 9c177c95..15b5ef6b 100644 --- a/src/Agent/SampledValue.php +++ b/src/Agent/SampledValue.php @@ -20,27 +20,51 @@ limitations under the License. */ -use DCarbone\PHPConsulAPI\AbstractModel; +use DCarbone\PHPConsulAPI\PHPLib\AbstractType; -class SampledValue extends AbstractModel +class SampledValue extends AbstractType { - public string $Name = ''; - public int $Count = 0; - public float $Sum = 0.0; - public float $Min = 0.0; - public float $Max = 0.0; - public float $Mean = 0.0; - public float $Stddev = 0.0; - public array $Labels = []; + public string $Name; + public int $Count; + public float $Sum; + public float $Min; + public float $Max; + public float $Mean; + public float $Stddev; + /** @var null|array */ + public null|array $Labels = null; + + /** + * @param array $Labels + */ + public function __construct( + string $Name = '', + int $Count = 0, + float $Sum = 0.0, + float $Min = 0.0, + float $Max = 0.0, + float $Mean = 0.0, + float $Stddev = 0.0, + array $Labels = [], + ) { + $this->Name = $Name; + $this->Count = $Count; + $this->Sum = $Sum; + $this->Min = $Min; + $this->Max = $Max; + $this->Mean = $Mean; + $this->Stddev = $Stddev; + $this->setLabels($Labels); + } public function getName(): string { return $this->Name; } - public function setName(string $name): self + public function setName(string $Name): self { - $this->Name = $name; + $this->Name = $Name; return $this; } @@ -49,9 +73,9 @@ public function getCount(): int return $this->Count; } - public function setCount(int $count): self + public function setCount(int $Count): self { - $this->Count = $count; + $this->Count = $Count; return $this; } @@ -60,9 +84,9 @@ public function getSum(): float return $this->Sum; } - public function setSum(float $sum): self + public function setSum(float $Sum): self { - $this->Sum = $sum; + $this->Sum = $Sum; return $this; } @@ -71,9 +95,9 @@ public function getMin(): float return $this->Min; } - public function setMin(float $min): self + public function setMin(float $Min): self { - $this->Min = $min; + $this->Min = $Min; return $this; } @@ -82,9 +106,9 @@ public function getMax(): float return $this->Max; } - public function setMax(float $max): self + public function setMax(float $Max): self { - $this->Max = $max; + $this->Max = $Max; return $this; } @@ -93,9 +117,9 @@ public function getMean(): float return $this->Mean; } - public function setMean(float $mean): self + public function setMean(float $Mean): self { - $this->Mean = $mean; + $this->Mean = $Mean; return $this; } @@ -110,14 +134,55 @@ public function setStddev(float $Stddev): self return $this; } - public function getLabels(): array + /** + * @return array|null + */ + public function getLabels(): null|array { return $this->Labels; } - public function setLabels(array $labels): self - { - $this->Labels = $labels; + /** + * @param \stdClass|array|null $Labels + * @return $this + */ + public function setLabels(null|\stdClass|array $Labels): self + { + if (null === $Labels) { + $this->Labels = null; + return $this; + } + $this->Labels = []; + foreach ($Labels as $k => $v) { + $this->Labels[$k] = $v; + } return $this; } + + public static function jsonUnserialize(\stdClass $decoded): self + { + $n = new self(); + foreach ((array)$decoded as $k => $v) { + if ('Labels' === $k) { + $n->setLabels($v); + } else { + $n->{$k} = $v; + } + } + return $n; + } + + public function jsonSerialize(): \stdClass + { + $out = $this->_startJsonSerialize(); + $out->Name = $this->Name; + $out->Count = $this->Count; + $out->Sum = $this->Sum; + $out->Min = $this->Min; + $out->Max = $this->Max; + $out->Mean = $this->Mean; + $out->Stddev = $this->Stddev; + $out->Labels = $this->getLabels(); + return $out; + } } diff --git a/src/Agent/ServiceKind.php b/src/Agent/ServiceKind.php new file mode 100644 index 00000000..08c57c6c --- /dev/null +++ b/src/Agent/ServiceKind.php @@ -0,0 +1,66 @@ +ReplaceExistingChecks = $ReplaceExistingChecks; + $this->Token = $Token; +} public function isReplaceExistingChecks(): bool { return $this->ReplaceExistingChecks; } - public function setReplaceExistingChecks(bool $replaceExistingChecks): self + public function setReplaceExistingChecks(bool $ReplaceExistingChecks): self { - $this->ReplaceExistingChecks = $replaceExistingChecks; + $this->ReplaceExistingChecks = $ReplaceExistingChecks; return $this; } + + public function getToken(): string + { + return $this->Token; + } + + public function setToken(string $Token): self + { + $this->Token = $Token; + return $this; + } + + public static function jsonUnserialize(\stdClass $decoded): self + { + $n = new self(); + foreach ((array)$decoded as $k => $v) { + $n->{$k} = $v; + } + return $n; + } + + public function jsonSerialize(): \stdClass + { + $out = $this->_startJsonSerialize(); + $out->ReplaceExistingChecks = $this->ReplaceExistingChecks; + $out->Token = $this->Token; + return $out; + } } diff --git a/src/Agent/Upstream.php b/src/Agent/Upstream.php index 96672596..2bc7e7c0 100644 --- a/src/Agent/Upstream.php +++ b/src/Agent/Upstream.php @@ -20,63 +20,78 @@ limitations under the License. */ -use DCarbone\PHPConsulAPI\AbstractModel; use DCarbone\PHPConsulAPI\ConfigEntry\MeshGatewayConfig; -use DCarbone\PHPConsulAPI\Transcoding; +use DCarbone\PHPConsulAPI\PHPLib\AbstractType; -class Upstream extends AbstractModel +class Upstream extends AbstractType { - protected const FIELDS = [ - self::FIELD_DESTINATION_TYPE => Transcoding::OMITEMPTY_STRING_FIELD, - self::FIELD_DESTINATION_NAMESPACE => Transcoding::OMITEMPTY_STRING_FIELD, - self::FIELD_DATACENTER => Transcoding::OMITEMPTY_STRING_FIELD, - self::FIELD_LOCAL_BIND_ADDRESS => Transcoding::OMITEMPTY_STRING_FIELD, - self::FIELD_LOCAL_BIND_PORT => Transcoding::OMITEMPTY_INTEGER_FIELD, - self::FIELD_CONFIG => [ - Transcoding::FIELD_TYPE => Transcoding::ARRAY, - Transcoding::FIELD_ARRAY_TYPE => Transcoding::MIXED, - Transcoding::FIELD_OMITEMPTY => true, - ], - self::FIELD_MESH_GATEWAY => [ - Transcoding::FIELD_TYPE => Transcoding::OBJECT, - Transcoding::FIELD_CLASS => MeshGatewayConfig::class, - Transcoding::FIELD_OMITEMPTY => true, - ], - ]; - - private const FIELD_DESTINATION_TYPE = 'DestinationType'; - private const FIELD_DESTINATION_NAMESPACE = 'DestinationNamespace'; - private const FIELD_DATACENTER = 'Datacenter'; - private const FIELD_LOCAL_BIND_ADDRESS = 'LocalBindAddress'; - private const FIELD_LOCAL_BIND_PORT = 'LocalBindPort'; - private const FIELD_CONFIG = 'Config'; - private const FIELD_MESH_GATEWAY = 'MeshGateway'; - - public string $DestinationType = ''; - public string $DestinationNamespace = ''; - public string $DestinationName = ''; - public string $Datacenter = ''; - public string $LocalBindAddress = ''; - public int $LocalBindPort = 0; - public array $Config = []; - public MeshGatewayConfig $MeshGatewayConfig; - - public function __construct(?array $data = []) - { - parent::__construct($data); - if (!isset($this->MeshGatewayConfig)) { - $this->MeshGatewayConfig = new MeshGatewayConfig(null); - } + public UpstreamDestType $DestinationType; + public string $DestinationPartition; + public string $DestinationNamespace; + public string $DestinationPeer; + public string $DestinationName; + public string $Datacenter; + public string $LocalBindAddress; + public int $LocalBindPort; + public string $LocalBindSocketPath; + public string $LocalBindSocketMode; + /** @var array */ + public null|array $Config; + public null|MeshGatewayConfig $MeshGateway; + public bool $CentrallyConfigured; + + /** + * @param array $Config + */ + public function __construct( + string|UpstreamDestType $DestinationType = UpstreamDestType::UNDEFINED, + string $DestinationPartition = '', + string $DestinationNamespace = '', + string $DestinationPeer = '', + string $DestinationName = '', + string $Datacenter = '', + string $LocalBindAddress = '', + int $LocalBindPort = 0, + string $LocalBindSocketPath = '', + string $LocalBindSocketMode = '', + array $Config = [], + null|MeshGatewayConfig $MeshGateway = null, + bool $CentrallyConfigured = false, + ) { + $this->setDestinationType($DestinationType); + $this->DestinationPartition = $DestinationPartition; + $this->DestinationNamespace = $DestinationNamespace; + $this->DestinationPeer = $DestinationPeer; + $this->DestinationName = $DestinationName; + $this->Datacenter = $Datacenter; + $this->LocalBindAddress = $LocalBindAddress; + $this->LocalBindPort = $LocalBindPort; + $this->LocalBindSocketPath = $LocalBindSocketPath; + $this->LocalBindSocketMode = $LocalBindSocketMode; + $this->setConfig($Config); + $this->MeshGateway = $MeshGateway; + $this->CentrallyConfigured = $CentrallyConfigured; } - public function getDestinationType(): string + public function getDestinationType(): UpstreamDestType { return $this->DestinationType; } - public function setDestinationType(string $DestinationType): self + public function setDestinationType(string|UpstreamDestType $DestinationType): self + { + $this->DestinationType = $DestinationType instanceof UpstreamDestType ? $DestinationType : UpstreamDestType::from($DestinationType); + return $this; + } + + public function getDestinationPartition(): string + { + return $this->DestinationPartition; + } + + public function setDestinationPartition(string $DestinationPartition): self { - $this->DestinationType = $DestinationType; + $this->DestinationPartition = $DestinationPartition; return $this; } @@ -91,6 +106,17 @@ public function setDestinationNamespace(string $DestinationNamespace): self return $this; } + public function getDestinationPeer(): string + { + return $this->DestinationPeer; + } + + public function setDestinationPeer(string $DestinationPeer): self + { + $this->DestinationPeer = $DestinationPeer; + return $this; + } + public function getDestinationName(): string { return $this->DestinationName; @@ -135,25 +161,132 @@ public function setLocalBindPort(int $LocalBindPort): self return $this; } - public function getConfig(): array + public function getLocalBindSocketPath(): string + { + return $this->LocalBindSocketPath; + } + + public function setLocalBindSocketPath(string $LocalBindSocketPath): self + { + $this->LocalBindSocketPath = $LocalBindSocketPath; + return $this; + } + + public function getLocalBindSocketMode(): string + { + return $this->LocalBindSocketMode; + } + + public function setLocalBindSocketMode(string $LocalBindSocketMode): self + { + $this->LocalBindSocketMode = $LocalBindSocketMode; + return $this; + } + + /** + * @return null|array + */ + public function getConfig(): null|array { return $this->Config; } - public function setConfig(array $Config): self + /** + * @param \stdClass|array|null $Config + * @return $this + */ + public function setConfig(null|\stdClass|array $Config): self + { + if (null == $Config) { + $this->Config = null; + return $this; + } + $this->Config = []; + foreach ($Config as $k => $v) { + $this->Config[$k] = $v; + } + return $this; + } + + public function getMeshGateway(): null|MeshGatewayConfig + { + return $this->MeshGateway; + } + + public function setMeshGateway(null|MeshGatewayConfig $MeshGateway): self { - $this->Config = $Config; + $this->MeshGateway = $MeshGateway; return $this; } - public function getMeshGatewayConfig(): MeshGatewayConfig + public function isCentrallyConfigured(): bool { - return $this->MeshGatewayConfig; + return $this->CentrallyConfigured; } - public function setMeshGatewayConfig(MeshGatewayConfig $MeshGatewayConfig): self + public function setCentrallyConfigured(bool $CentrallyConfigured): self { - $this->MeshGatewayConfig = $MeshGatewayConfig; + $this->CentrallyConfigured = $CentrallyConfigured; return $this; } + + public static function jsonUnserialize(\stdClass $decoded): self + { + $n = new self(); + foreach ((array)$decoded as $k => $v) { + if ('DestinationType' === $k) { + $n->setDestinationType($v); + } elseif ('MeshGateway' === $k) { + $n->MeshGateway = MeshGatewayConfig::jsonUnserialize($v); + } elseif ('Config' === $k) { + $n->setConfig($v); + } else { + $n->{$k} = $v; + } + } + return $n; + } + + public function jsonSerialize(): \stdClass + { + $out = $this->_startJsonSerialize(); + if ($this->DestinationType !== UpstreamDestType::UNDEFINED) { + $out->DestinationType = $this->DestinationType; + } + if ('' !== $this->DestinationPartition) { + $out->DestinationPartition = $this->DestinationPartition; + } + if ('' !== $this->DestinationNamespace) { + $out->DestinationNamespace = $this->DestinationNamespace; + } + if ('' !== $this->DestinationPeer) { + $out->DestinationPeer = $this->DestinationPeer; + } + $out->DestinationName = $this->DestinationName; + if ('' !== $this->Datacenter) { + $out->Datacenter = $this->Datacenter; + } + if ('' !== $this->LocalBindAddress) { + $out->LocalBindAddress = $this->LocalBindAddress; + } + if (0 !== $this->LocalBindPort) { + $out->LocalBindPort = $this->LocalBindPort; + } + if ('' !== $this->LocalBindSocketPath) { + $out->LocalBindSocketPath = $this->LocalBindSocketPath; + } + if ('' !== $this->LocalBindSocketMode) { + $out->LocalBindSocketMode = $this->LocalBindSocketMode; + } + if (null !== $this->Config) { + $out->Config = $this->Config; + } + if (null !== $this->MeshGateway) { + $out->MeshGateway = $this->MeshGateway; + } + if ($this->CentrallyConfigured) { + $out->CentrallyConfigured = $this->CentrallyConfigured; + } + return $out; + } } diff --git a/src/KV/KVTxnOps.php b/src/Agent/UpstreamDestType.php similarity index 65% rename from src/KV/KVTxnOps.php rename to src/Agent/UpstreamDestType.php index a1c1ac8f..856ccef2 100644 --- a/src/KV/KVTxnOps.php +++ b/src/Agent/UpstreamDestType.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace DCarbone\PHPConsulAPI\KV; +namespace DCarbone\PHPConsulAPI\Agent; /* Copyright 2016-2025 Daniel Carbone (daniel.p.carbone@gmail.com) @@ -20,15 +20,15 @@ limitations under the License. */ -use DCarbone\PHPConsulAPI\AbstractModel; -use DCarbone\PHPConsulAPI\FakeSlice; - -class KVTxnOps extends FakeSlice +enum UpstreamDestType: string { - protected string $containedClass = KVTxnOp::class; + // Service discovers instances via healthy service lookup. + case Service = 'service'; + + // PreparedQuery discovers instances via prepared query + // execution. + case PreparedQuery = 'prepared_query'; - protected function newChild(array $data): AbstractModel - { - return new KVTxnOp($data); - } + // Default case for when value is not set. + case UNDEFINED = ''; } diff --git a/src/Catalog/CatalogClient.php b/src/Catalog/CatalogClient.php index c778c499..a5dc6966 100644 --- a/src/Catalog/CatalogClient.php +++ b/src/Catalog/CatalogClient.php @@ -20,21 +20,21 @@ limitations under the License. */ -use DCarbone\PHPConsulAPI\AbstractClient; +use DCarbone\PHPConsulAPI\PHPLib\AbstractClient; +use DCarbone\PHPConsulAPI\PHPLib\ValuedQueryStringsResponse; +use DCarbone\PHPConsulAPI\PHPLib\ValuedStringsResponse; +use DCarbone\PHPConsulAPI\PHPLib\WriteResponse; use DCarbone\PHPConsulAPI\QueryOptions; -use DCarbone\PHPConsulAPI\ValuedQueryStringsResponse; -use DCarbone\PHPConsulAPI\ValuedStringsResponse; use DCarbone\PHPConsulAPI\WriteOptions; -use DCarbone\PHPConsulAPI\WriteResponse; class CatalogClient extends AbstractClient { - public function Register(CatalogRegistration $catalogRegistration, ?WriteOptions $opts = null): WriteResponse + public function Register(CatalogRegistration $catalogRegistration, null|WriteOptions $opts = null): WriteResponse { return $this->_executePut('v1/catalog/register', $catalogRegistration, $opts); } - public function Deregister(CatalogDeregistration $catalogDeregistration, ?WriteOptions $opts = null): WriteResponse + public function Deregister(CatalogDeregistration $catalogDeregistration, null|WriteOptions $opts = null): WriteResponse { return $this->_executePut('v1/catalog/deregister', $catalogDeregistration, $opts); } @@ -47,7 +47,7 @@ public function Datacenters(): ValuedStringsResponse return $ret; } - public function Nodes(?QueryOptions $opts = null): NodesResponse + public function Nodes(null|QueryOptions $opts = null): NodesResponse { $resp = $this->_requireOK($this->_doGet('v1/catalog/nodes', $opts)); $ret = new NodesResponse(); @@ -55,7 +55,7 @@ public function Nodes(?QueryOptions $opts = null): NodesResponse return $ret; } - public function Services(?QueryOptions $opts = null): ValuedQueryStringsResponse + public function Services(null|QueryOptions $opts = null): ValuedQueryStringsResponse { $resp = $this->_requireOK($this->_doGet('v1/catalog/services', $opts)); $ret = new ValuedQueryStringsResponse(); @@ -63,7 +63,7 @@ public function Services(?QueryOptions $opts = null): ValuedQueryStringsResponse return $ret; } - public function NodeServicesList(string $node, ?QueryOptions $opts = null): CatalogNodeServicesListResponse + public function NodeServicesList(string $node, null|QueryOptions $opts = null): CatalogNodeServicesListResponse { $resp = $this->_requireOK($this->_doGet(sprintf('v1/catalog/node-services/%s', urlencode($node)), $opts)); $ret = new CatalogNodeServicesListResponse(); @@ -71,10 +71,13 @@ public function NodeServicesList(string $node, ?QueryOptions $opts = null): Cata return $ret; } + /** + * @param array $tags + */ public function ServiceMultipleTags( string $service, array $tags, - ?QueryOptions $opts = null + null|QueryOptions $opts = null ): CatalogServicesResponse { $r = $this->_newGetRequest(sprintf('v1/catalog/service/%s', $service), $opts); if ([] !== $tags) { @@ -86,12 +89,12 @@ public function ServiceMultipleTags( return $ret; } - public function Service(string $service, string $tag = '', ?QueryOptions $opts = null): CatalogServicesResponse + public function Service(string $service, string $tag = '', null|QueryOptions $opts = null): CatalogServicesResponse { return $this->ServiceMultipleTags($service, '' !== $tag ? [$tag] : [], $opts); } - public function Node(string $node, ?QueryOptions $opts = null): CatalogNodeResponse + public function Node(string $node, null|QueryOptions $opts = null): CatalogNodeResponse { $resp = $this->_requireOK($this->_doGet(sprintf('v1/catalog/node/%s', $node), $opts)); $ret = new CatalogNodeResponse(); @@ -99,7 +102,7 @@ public function Node(string $node, ?QueryOptions $opts = null): CatalogNodeRespo return $ret; } - public function GatewayServices(string $gateway, ?QueryOptions $opts = null): GatewayServicesResponse + public function GatewayServices(string $gateway, null|QueryOptions $opts = null): GatewayServicesResponse { $resp = $this->_requireOK($this->_doGet(sprintf('v1/catalog/gateway-services/%s', urlencode($gateway)), $opts)); $ret = new GatewayServicesResponse(); diff --git a/src/Catalog/CatalogDeregistration.php b/src/Catalog/CatalogDeregistration.php index 139008fc..cc91c9a3 100644 --- a/src/Catalog/CatalogDeregistration.php +++ b/src/Catalog/CatalogDeregistration.php @@ -20,33 +20,44 @@ limitations under the License. */ -use DCarbone\PHPConsulAPI\AbstractModel; -use DCarbone\PHPConsulAPI\Transcoding; +use DCarbone\PHPConsulAPI\PHPLib\AbstractType; -class CatalogDeregistration extends AbstractModel +class CatalogDeregistration extends AbstractType { - protected const FIELDS = [ - self::FIELD_ADDRESS => Transcoding::OMITEMPTY_STRING_FIELD, - self::FIELD_NAMESPACE => Transcoding::OMITEMPTY_STRING_FIELD, - ]; - - private const FIELD_ADDRESS = 'Address'; - private const FIELD_NAMESPACE = 'Namespace'; - - public string $Node = ''; - public string $Address = ''; - public string $Datacenter = ''; - public string $ServiceID = ''; - public string $CheckID = ''; + public string $Node; + public string $Address; + public string $Datacenter; + public string $ServiceID; + public string $CheckID; + public string $Namespace; + public string $Partition; + + public function __construct( + string $Node = '', + string $Address = '', + string $Datacenter = '', + string $ServiceID = '', + string $CheckID = '', + string $Namespace = '', + string $Partition = '', + ) { + $this->Node = $Node; + $this->Address = $Address; + $this->Datacenter = $Datacenter; + $this->ServiceID = $ServiceID; + $this->CheckID = $CheckID; + $this->Namespace = $Namespace; + $this->Partition = $Partition; + } public function getNode(): string { return $this->Node; } - public function setNode(string $node): self + public function setNode(string $Node): self { - $this->Node = $node; + $this->Node = $Node; return $this; } @@ -55,9 +66,9 @@ public function getAddress(): string return $this->Address; } - public function setAddress(string $address): self + public function setAddress(string $Address): self { - $this->Address = $address; + $this->Address = $Address; return $this; } @@ -66,9 +77,9 @@ public function getDatacenter(): string return $this->Datacenter; } - public function setDatacenter(string $datacenter): self + public function setDatacenter(string $Datacenter): self { - $this->Datacenter = $datacenter; + $this->Datacenter = $Datacenter; return $this; } @@ -77,9 +88,9 @@ public function getServiceID(): string return $this->ServiceID; } - public function setServiceID(string $serviceID): self + public function setServiceID(string $ServiceID): self { - $this->ServiceID = $serviceID; + $this->ServiceID = $ServiceID; return $this; } @@ -88,9 +99,59 @@ public function getCheckID(): string return $this->CheckID; } - public function setCheckID(string $checkID): self + public function setCheckID(string $CheckID): self + { + $this->CheckID = $CheckID; + return $this; + } + + public function getNamespace(): string + { + return $this->Namespace; + } + + public function setNamespace(string $Namespace): self { - $this->CheckID = $checkID; + $this->Namespace = $Namespace; return $this; } + + public function getPartition(): string + { + return $this->Partition; + } + + public function setPartition(string $Partition): self + { + $this->Partition = $Partition; + return $this; + } + + public static function jsonUnserialize(\stdClass $decoded): self + { + $n = new self(); + foreach ((array)$decoded as $k => $v) { + $n->{$k} = $v; + } + return $n; + } + + public function jsonSerialize(): \stdClass + { + $out = $this->_startJsonSerialize(); + $out->Node = $this->Node; + if ('' !== $this->Address) { + $out->Address = $this->Address; + } + $out->Datacenter = $this->Datacenter; + $out->ServiceID = $this->ServiceID; + $out->CheckID = $this->CheckID; + if ('' !== $this->Namespace) { + $out->Namespace = $this->Namespace; + } + if ('' !== $this->Partition) { + $out->Partition = $this->Partition; + } + return $out; + } } diff --git a/src/Catalog/CatalogNode.php b/src/Catalog/CatalogNode.php index 1f947d62..49de4aca 100644 --- a/src/Catalog/CatalogNode.php +++ b/src/Catalog/CatalogNode.php @@ -20,49 +20,77 @@ limitations under the License. */ -use DCarbone\PHPConsulAPI\AbstractModel; use DCarbone\PHPConsulAPI\Agent\AgentService; -use DCarbone\PHPConsulAPI\Transcoding; +use DCarbone\PHPConsulAPI\PHPLib\AbstractType; -class CatalogNode extends AbstractModel +class CatalogNode extends AbstractType { - protected const FIELDS = [ - self::FIELD_NODE => [ - Transcoding::FIELD_TYPE => Transcoding::OBJECT, - Transcoding::FIELD_CLASS => Node::class, - ], - self::FIELD_SERVICES => [ - Transcoding::FIELD_TYPE => Transcoding::ARRAY, - Transcoding::FIELD_CLASS => AgentService::class, - Transcoding::FIELD_ARRAY_TYPE => Transcoding::OBJECT, - ], - ]; + public null|Node $Node; + /** @var array */ + public array $Services; - private const FIELD_NODE = 'Node'; - private const FIELD_SERVICES = 'Services'; - - public ?Node $Node = null; - public array $Services = []; + /** + * @param array $Services + */ + public function __construct( + null|Node $Node = null, + array $Services = [], + ) { + $this->Node = $Node; + $this->Services = $Services; + } - public function getNode(): ?Node + public function getNode(): null|Node { return $this->Node; } - public function setNode(?Node $Node): self + public function setNode(null|Node $Node): self { $this->Node = $Node; return $this; } + /** + * @return array + */ public function getServices(): array { return $this->Services; } + /** + * @param array $Services + */ public function setServices(array $Services): self { $this->Services = $Services; return $this; } + + public static function jsonUnserialize(\stdClass $decoded): self + { + $n = new self(); + foreach ((array)$decoded as $k => $v) { + if ('Node' === $k) { + $n->Node = null === $v ? null : Node::jsonUnserialize($v); + } elseif ('Services' === $k) { + $n->Services = []; + foreach ($v as $kk => $vv) { + $n->Services[$kk] = AgentService::jsonUnserialize($vv); + } + } else { + $n->{$k} = $v; + } + } + return $n; + } + + public function jsonSerialize(): \stdClass + { + $out = $this->_startJsonSerialize(); + $out->Node = $this->getNode(); + $out->Services = $this->getServices(); + return $out; + } } diff --git a/src/Catalog/CatalogNodeResponse.php b/src/Catalog/CatalogNodeResponse.php index b3095658..29f998cc 100644 --- a/src/Catalog/CatalogNodeResponse.php +++ b/src/Catalog/CatalogNodeResponse.php @@ -20,20 +20,24 @@ limitations under the License. */ -use DCarbone\PHPConsulAPI\AbstractValuedQueryResponse; -use DCarbone\PHPConsulAPI\UnmarshalledResponseInterface; +use DCarbone\PHPConsulAPI\PHPLib\AbstractValuedQueryResponse; +use DCarbone\PHPConsulAPI\PHPLib\UnmarshalledResponseInterface; class CatalogNodeResponse extends AbstractValuedQueryResponse implements UnmarshalledResponseInterface { - public ?CatalogNode $Node = null; + public null|CatalogNode $Node = null; - public function getValue(): ?CatalogNode + public function getValue(): null|CatalogNode { return $this->Node; } - public function unmarshalValue(mixed $decodedData): void + public function unmarshalValue(mixed $decoded): void { - $this->Node = new CatalogNode((array)$decodedData); + if (null === $decoded) { + $this->Node = null; + return; + } + $this->Node = CatalogNode::jsonUnserialize($decoded); } } diff --git a/src/Catalog/CatalogNodeServiceList.php b/src/Catalog/CatalogNodeServiceList.php index abae0f3a..b0e9579a 100644 --- a/src/Catalog/CatalogNodeServiceList.php +++ b/src/Catalog/CatalogNodeServiceList.php @@ -20,49 +20,75 @@ limitations under the License. */ -use DCarbone\PHPConsulAPI\AbstractModel; use DCarbone\PHPConsulAPI\Agent\AgentService; -use DCarbone\PHPConsulAPI\Transcoding; +use DCarbone\PHPConsulAPI\PHPLib\AbstractType; -class CatalogNodeServiceList extends AbstractModel +class CatalogNodeServiceList extends AbstractType { - protected const FIELDS = [ - self::FIELD_NODE => [ - Transcoding::FIELD_TYPE => Transcoding::OBJECT, - Transcoding::FIELD_CLASS => Node::class, - ], - self::FIELD_SERVICES => [ - Transcoding::FIELD_TYPE => Transcoding::ARRAY, - Transcoding::FIELD_CLASS => AgentService::class, - Transcoding::FIELD_ARRAY_TYPE => Transcoding::OBJECT, - ], - ]; + public null|Node $Node; + /** @var array<\DCarbone\PHPConsulAPI\Agent\AgentService> */ + public array $Services; - private const FIELD_NODE = 'Node'; - private const FIELD_SERVICES = 'Services'; - - public ?Node $Node = null; - public array $Services = []; + /** + * @param \DCarbone\PHPConsulAPI\Catalog\Node|null $Node + * @param array<\DCarbone\PHPConsulAPI\Agent\AgentService> $Services + */ + public function __construct( + null|Node $Node = null, + array $Services = [], + ) { + $this->Node = $Node; + $this->setServices(...$Services); + } - public function getNode(): ?Node + public function getNode(): null|Node { return $this->Node; } - public function setNode(?Node $Node): self + public function setNode(null|Node $Node): self { $this->Node = $Node; return $this; } + /** + * @return array<\DCarbone\PHPConsulAPI\Agent\AgentService> + */ public function getServices(): array { return $this->Services; } - public function setServices(array $Services): self + public function setServices(AgentService ...$Services): self { $this->Services = $Services; return $this; } + + public static function jsonUnserialize(\stdClass $decoded): self + { + $n = new self(); + foreach ((array)$decoded as $k => $v) { + if ('Node' === $k) { + $n->Node = null === $v ? null : Node::jsonUnserialize($v); + } elseif ('Services' === $k) { + $n->Services = []; + foreach ($v as $vv) { + $n->Services[] = AgentService::jsonUnserialize($vv); + } + } else { + $n->{$k} = $v; + } + } + return $n; + } + + public function jsonSerialize(): \stdClass + { + $out = $this->_startJsonSerialize(); + $out->Node = $this->Node; + $out->Services = $this->Services; + return $out; + } } diff --git a/src/Catalog/CatalogNodeServicesListResponse.php b/src/Catalog/CatalogNodeServicesListResponse.php index d7f712fd..e3917927 100644 --- a/src/Catalog/CatalogNodeServicesListResponse.php +++ b/src/Catalog/CatalogNodeServicesListResponse.php @@ -20,20 +20,24 @@ limitations under the License. */ -use DCarbone\PHPConsulAPI\AbstractValuedQueryResponse; -use DCarbone\PHPConsulAPI\UnmarshalledResponseInterface; +use DCarbone\PHPConsulAPI\PHPLib\AbstractValuedQueryResponse; +use DCarbone\PHPConsulAPI\PHPLib\UnmarshalledResponseInterface; class CatalogNodeServicesListResponse extends AbstractValuedQueryResponse implements UnmarshalledResponseInterface { - public ?CatalogNodeServiceList $CatalogNodeServiceList = null; + public null|CatalogNodeServiceList $CatalogNodeServiceList = null; - public function getValue(): ?CatalogNodeServiceList + public function getValue(): null|CatalogNodeServiceList { return $this->CatalogNodeServiceList; } - public function unmarshalValue(mixed $decodedData): void + public function unmarshalValue(mixed $decoded): void { - $this->CatalogNodeServiceList = new CatalogNodeServiceList((array)$decodedData); + if (null === $decoded) { + $this->CatalogNodeServiceList = null; + return; + } + $this->CatalogNodeServiceList = CatalogNodeServiceList::jsonUnserialize($decoded); } } diff --git a/src/Catalog/CatalogRegistration.php b/src/Catalog/CatalogRegistration.php index 5175edc2..63bfbb50 100644 --- a/src/Catalog/CatalogRegistration.php +++ b/src/Catalog/CatalogRegistration.php @@ -20,61 +20,60 @@ limitations under the License. */ -use DCarbone\PHPConsulAPI\AbstractModel; use DCarbone\PHPConsulAPI\Agent\AgentCheck; use DCarbone\PHPConsulAPI\Agent\AgentService; -use DCarbone\PHPConsulAPI\FakeMap; use DCarbone\PHPConsulAPI\Health\HealthChecks; -use DCarbone\PHPConsulAPI\Transcoding; +use DCarbone\PHPConsulAPI\Peering\Locality; +use DCarbone\PHPConsulAPI\PHPLib\AbstractType; +use DCarbone\PHPConsulAPI\PHPLib\NodeMetaField; +use DCarbone\PHPConsulAPI\PHPLib\TaggedAddressField; -class CatalogRegistration extends AbstractModel +class CatalogRegistration extends AbstractType { - protected const FIELDS = [ - self::FIELD_TAGGED_ADDRESSES => Transcoding::MAP_FIELD, - self::FIELD_NODE_META => Transcoding::MAP_FIELD, - self::FIELD_SERVICE => [ - Transcoding::FIELD_TYPE => Transcoding::OBJECT, - Transcoding::FIELD_CLASS => AgentService::class, - ], - self::FIELD_CHECK => [ - Transcoding::FIELD_TYPE => Transcoding::OBJECT, - Transcoding::FIELD_CLASS => AgentCheck::class, - ], - self::FIELD_CHECKS => [ - Transcoding::FIELD_TYPE => Transcoding::OBJECT, - Transcoding::FIELD_CLASS => HealthChecks::class, - ], - ]; - - private const FIELD_TAGGED_ADDRESSES = 'TaggedAddresses'; - private const FIELD_NODE_META = 'NodeMeta'; - private const FIELD_SERVICE = 'Service'; - private const FIELD_CHECK = 'Check'; - private const FIELD_CHECKS = 'Checks'; - - public string $ID = ''; - public string $Node = ''; - public string $Address = ''; - public FakeMap $TaggedAddresses; - public FakeMap $NodeMeta; - public string $Datacenter = ''; - public ?AgentService $Service = null; - public ?AgentCheck $Check = null; - public HealthChecks $Checks; - public bool $SkipNodeUpdate = false; - - public function __construct(?array $data = []) - { - parent::__construct($data); - if (!isset($this->Checks)) { - $this->Checks = new HealthChecks(null); - } - if (!isset($this->TaggedAddresses)) { - $this->TaggedAddresses = new FakeMap(null); - } - if (!isset($this->NodeMeta)) { - $this->NodeMeta = new FakeMap(null); - } + use TaggedAddressField; + use NodeMetaField; + + public string $ID; + public string $Node; + public string $Address; + public string $Datacenter; + public null|AgentService $Service; + public null|AgentCheck $Check; + public null|HealthChecks $Checks; + public bool $SkipNodeUpdate; + public string $Partition; + public null|Locality $Locality; + + /** + * @param array $TaggedAddresses + * @param array $NodeMeta + */ + public function __construct( + string $ID = '', + string $Node = '', + string $Address = '', + array $TaggedAddresses = [], + array $NodeMeta = [], + string $Datacenter = '', + null|AgentService $Service = null, + null|AgentCheck $Check = null, + null|HealthChecks $Checks = null, + bool $SkipNodeUpdate = false, + string $Partition = '', + null|Locality $Locality = null, + ) { + $this->ID = $ID; + $this->Node = $Node; + $this->Address = $Address; + $this->setTaggedAddresses($TaggedAddresses); + $this->setNodeMeta($NodeMeta); + $this->Datacenter = $Datacenter; + $this->Service = $Service; + $this->Check = $Check; + $this->Checks = $Checks; + $this->SkipNodeUpdate = $SkipNodeUpdate; + $this->Partition = $Partition; + $this->Locality = $Locality; } public function getID(): string @@ -110,28 +109,6 @@ public function setAddress(string $Address): self return $this; } - public function getTaggedAddresses(): FakeMap - { - return $this->TaggedAddresses; - } - - public function setTaggedAddresses(FakeMap $TaggedAddresses): self - { - $this->TaggedAddresses = $TaggedAddresses; - return $this; - } - - public function getNodeMeta(): FakeMap - { - return $this->NodeMeta; - } - - public function setNodeMeta(FakeMap $NodeMeta): self - { - $this->NodeMeta = $NodeMeta; - return $this; - } - public function getDatacenter(): string { return $this->Datacenter; @@ -143,23 +120,23 @@ public function setDatacenter(string $Datacenter): self return $this; } - public function getService(): ?AgentService + public function getService(): null|AgentService { return $this->Service; } - public function setService(?AgentService $Service): self + public function setService(null|AgentService $Service): self { $this->Service = $Service; return $this; } - public function getCheck(): ?AgentCheck + public function getCheck(): null|AgentCheck { return $this->Check; } - public function setCheck(?AgentCheck $Check): self + public function setCheck(null|AgentCheck $Check): self { $this->Check = $Check; return $this; @@ -170,9 +147,9 @@ public function getChecks(): HealthChecks return $this->Checks; } - public function setChecks(HealthChecks $checks): self + public function setChecks(HealthChecks $Checks): self { - $this->Checks = $checks; + $this->Checks = $Checks; return $this; } @@ -186,4 +163,71 @@ public function setSkipNodeUpdate(bool $SkipNodeUpdate): self $this->SkipNodeUpdate = $SkipNodeUpdate; return $this; } + + public function getPartition(): string + { + return $this->Partition; + } + + public function setPartition(string $Partition): self + { + $this->Partition = $Partition; + return $this; + } + + public function getLocality(): null|Locality + { + return $this->Locality; + } + + public function setLocality(null|Locality $Locality): self + { + $this->Locality = $Locality; + return $this; + } + + public static function jsonUnserialize(\stdClass $decoded): self + { + $n = new self(); + foreach ((array)$decoded as $k => $v) { + if ('TaggedAddresses' === $k) { + $n->setTaggedAddresses($v); + } elseif ('NodeMeta' === $k) { + $n->setNodeMeta($v); + } elseif ('Service' === $k) { + $n->Service = null === $v ? null : AgentService::jsonUnserialize($v); + } elseif ('Check' === $k) { + $n->Check = null === $v ? null : AgentCheck::jsonUnserialize($v); + } elseif ('Checks' === $k) { + $n->Checks = null === $v ? null : HealthChecks::jsonUnserialize($v); + } elseif ('Locality' === $k) { + $n->Locality = null === $v ? null : Locality::jsonUnserialize($v); + } else { + $n->{$k} = $v; + } + } + return $n; + } + + public function jsonSerialize(): \stdClass + { + $out = $this->_startJsonSerialize(); + $out->ID = $this->ID; + $out->Node = $this->Node; + $out->Address = $this->Address; + $out->TaggedAddresses = $this->getTaggedAddresses(); + $out->NodeMeta = $this->getNodeMeta(); + $out->Datacenter = $this->Datacenter; + $out->Service = $this->Service; + $out->Check = $this->Check; + $out->Checks = $this->Checks; + $out->SkipNodeUpdate = $this->SkipNodeUpdate; + if ('' !== $this->Partition) { + $out->Partition = $this->Partition; + } + if (null !== $this->Locality) { + $out->Locality = $this->Locality; + } + return $out; + } } diff --git a/src/Catalog/CatalogService.php b/src/Catalog/CatalogService.php index deb51345..ae86217d 100644 --- a/src/Catalog/CatalogService.php +++ b/src/Catalog/CatalogService.php @@ -20,60 +20,96 @@ limitations under the License. */ -use DCarbone\PHPConsulAPI\AbstractModel; use DCarbone\PHPConsulAPI\Agent\AgentServiceConnectProxyConfig; use DCarbone\PHPConsulAPI\Health\HealthChecks; -use DCarbone\PHPConsulAPI\Transcoding; +use DCarbone\PHPConsulAPI\Peering\Locality; +use DCarbone\PHPConsulAPI\PHPLib\AbstractType; +use DCarbone\PHPConsulAPI\PHPLib\NodeMetaField; +use DCarbone\PHPConsulAPI\PHPLib\ServiceMetaField; +use DCarbone\PHPConsulAPI\PHPLib\TaggedAddressField; -class CatalogService extends AbstractModel +class CatalogService extends AbstractType { - protected const FIELDS = [ - self::FIELD_SERVICE_TAGGED_ADDRESSES => [ - Transcoding::FIELD_TYPE => Transcoding::ARRAY, - Transcoding::FIELD_CLASS => ServiceAddress::class, - Transcoding::FIELD_ARRAY_TYPE => Transcoding::OBJECT, - ], - self::FIELD_SERVICE_WEIGHTS => [ - Transcoding::FIELD_TYPE => Transcoding::OBJECT, - Transcoding::FIELD_CLASS => Weights::class, - ], - self::FIELD_SERVICE_PROXY => [ - Transcoding::FIELD_TYPE => Transcoding::OBJECT, - Transcoding::FIELD_CLASS => AgentServiceConnectProxyConfig::class, - Transcoding::FIELD_NULLABLE => true, - ], - self::FIELD_HEALTH_CHECKS => [ - Transcoding::FIELD_TYPE => Transcoding::OBJECT, - Transcoding::FIELD_CLASS => HealthChecks::class, - ], - self::FIELD_NAMESPACE => Transcoding::OMITEMPTY_STRING_FIELD, - ]; - - private const FIELD_SERVICE_TAGGED_ADDRESSES = 'ServiceTaggedAddresses'; - private const FIELD_SERVICE_WEIGHTS = 'ServiceWeights'; - private const FIELD_SERVICE_PROXY = 'ServiceProxy'; - private const FIELD_HEALTH_CHECKS = 'HealthChecks'; - private const FIELD_NAMESPACE = 'Namespace'; - - public string $ID = ''; - public string $Node = ''; - public string $Address = ''; - public string $Datacenter = ''; - public array $TaggedAddresses = []; - public array $NodeMeta = []; - public string $ServiceID = ''; - public string $ServiceName = ''; - public string $ServiceAddress = ''; - public array $ServiceTaggedAddresses = []; - public array $ServiceTags = []; - public array $ServiceMeta = []; - public int $ServicePort = 0; + use TaggedAddressField; + use NodeMetaField; + use ServiceMetaField; + + public string $ID; + public string $Node; + public string $Address; + public string $Datacenter; + public string $ServiceID; + public string $ServiceName; + public string $ServiceAddress; + /** @var null|array */ + public null|array $ServiceTaggedAddresses = null; + /** @var array */ + public array $ServiceTags; + public int $ServicePort; public Weights $ServiceWeights; - public bool $ServiceEnableTagOverride = false; - public int $CreateIndex = 0; - public ?AgentServiceConnectProxyConfig $ServiceProxy = null; - public int $ModifyIndex = 0; - public string $Namespace = ''; + public bool $ServiceEnableTagOverride; + public null|AgentServiceConnectProxyConfig $ServiceProxy; + public null|Locality $ServiceLocality; + public int $CreateIndex; + public HealthChecks $Checks; + public int $ModifyIndex; + public string $Namespace; + public string $Partition; + + /** + * @param array $TaggedAddresses + * @param array $NodeMeta + * @param array $ServiceTaggedAddresses + * @param array $ServiceTags + * @param array $ServiceMeta + */ + public function __construct( + string $ID = '', + string $Node = '', + string $Address = '', + string $Datacenter = '', + array $TaggedAddresses = [], + array $NodeMeta = [], + string $ServiceID = '', + string $ServiceName = '', + string $ServiceAddress = '', + array $ServiceTaggedAddresses = [], + array $ServiceTags = [], + array $ServiceMeta = [], + int $ServicePort = 0, + null|Weights $ServiceWeights = null, + bool $ServiceEnableTagOverride = false, + null|AgentServiceConnectProxyConfig $ServiceProxy = null, + null|Locality $ServiceLocality = null, + int $CreateIndex = 0, + int $ModifyIndex = 0, + null|HealthChecks $Checks = null, + string $Namespace = '', + string $Partition = '', + ) { + $this->ID = $ID; + $this->Node = $Node; + $this->Address = $Address; + $this->Datacenter = $Datacenter; + $this->setTaggedAddresses($TaggedAddresses); + $this->setNodeMeta($NodeMeta); + $this->ServiceID = $ServiceID; + $this->ServiceName = $ServiceName; + $this->ServiceAddress = $ServiceAddress; + $this->setServiceTags(...$ServiceTags); + $this->setServiceTaggedAddresses($ServiceTaggedAddresses); + $this->setServiceMeta($ServiceMeta); + $this->ServicePort = $ServicePort; + $this->ServiceWeights = $ServiceWeights ?? new Weights(); + $this->ServiceEnableTagOverride = $ServiceEnableTagOverride; + $this->ServiceProxy = $ServiceProxy; + $this->ServiceLocality = $ServiceLocality; + $this->CreateIndex = $CreateIndex; + $this->Checks = $Checks ?? new HealthChecks(); + $this->ModifyIndex = $ModifyIndex; + $this->Namespace = $Namespace; + $this->Partition = $Partition; + } public function getID(): string { @@ -119,28 +155,6 @@ public function setDatacenter(string $Datacenter): self return $this; } - public function getTaggedAddresses(): array - { - return $this->TaggedAddresses; - } - - public function setTaggedAddresses(array $TaggedAddresses): self - { - $this->TaggedAddresses = $TaggedAddresses; - return $this; - } - - public function getNodeMeta(): array - { - return $this->NodeMeta; - } - - public function setNodeMeta(array $NodeMeta): self - { - $this->NodeMeta = $NodeMeta; - return $this; - } - public function getServiceID(): string { return $this->ServiceID; @@ -174,36 +188,50 @@ public function setServiceAddress(string $ServiceAddress): self return $this; } - public function getServiceTaggedAddresses(): array + /** + * @return array|null + */ + public function getServiceTaggedAddresses(): null|array { return $this->ServiceTaggedAddresses; } - public function setServiceTaggedAddresses(array $ServiceTaggedAddresses): self + public function setServiceTaggedAddress(string $Tag, ServiceAddress $ServiceAddress): self { - $this->ServiceTaggedAddresses = $ServiceTaggedAddresses; + if (null === $this->ServiceTaggedAddresses) { + $this->ServiceTaggedAddresses = []; + } + $this->ServiceTaggedAddresses[$Tag] = $ServiceAddress; return $this; } - public function getServiceTags(): array - { - return $this->ServiceTags; - } - - public function setServiceTags(array $ServiceTags): self + /** + * @param array|null $ServiceTaggedAddresses + */ + public function setServiceTaggedAddresses(null|array $ServiceTaggedAddresses): self { - $this->ServiceTags = $ServiceTags; + if (null === $ServiceTaggedAddresses) { + $this->TaggedAddresses = null; + return $this; + } + $this->TaggedAddresses = null; + foreach ($ServiceTaggedAddresses as $k => $v) { + $this->setServiceTaggedAddress($k, $v); + } return $this; } - public function getServiceMeta(): array + /** + * @return array + */ + public function getServiceTags(): array { - return $this->ServiceMeta; + return $this->ServiceTags; } - public function setServiceMeta(array $ServiceMeta): self + public function setServiceTags(string ...$ServiceTags): self { - $this->ServiceMeta = $ServiceMeta; + $this->ServiceTags = $ServiceTags; return $this; } @@ -240,6 +268,28 @@ public function setServiceEnableTagOverride(bool $ServiceEnableTagOverride): sel return $this; } + public function getServiceProxy(): null|AgentServiceConnectProxyConfig + { + return $this->ServiceProxy; + } + + public function setServiceProxy(null|AgentServiceConnectProxyConfig $ServiceProxy): self + { + $this->ServiceProxy = $ServiceProxy; + return $this; + } + + public function getServiceLocality(): null|Locality + { + return $this->ServiceLocality; + } + + public function setServiceLocality(null|Locality $ServiceLocality): self + { + $this->ServiceLocality = $ServiceLocality; + return $this; + } + public function getCreateIndex(): int { return $this->CreateIndex; @@ -251,14 +301,14 @@ public function setCreateIndex(int $CreateIndex): self return $this; } - public function getServiceProxy(): ?AgentServiceConnectProxyConfig + public function getChecks(): HealthChecks { - return $this->ServiceProxy; + return $this->Checks; } - public function setServiceProxy(?AgentServiceConnectProxyConfig $ServiceProxy): self + public function setChecks(HealthChecks $Checks): self { - $this->ServiceProxy = $ServiceProxy; + $this->Checks = $Checks; return $this; } @@ -273,14 +323,94 @@ public function setModifyIndex(int $ModifyIndex): self return $this; } - public function getNamespace(): ?string + public function getNamespace(): string { return $this->Namespace; } - public function setNamespace(?string $Namespace): self + public function setNamespace(string $Namespace): self { $this->Namespace = $Namespace; return $this; } + + public function getPartition(): string + { + return $this->Partition; + } + + public function setPartition(string $Partition): self + { + $this->Partition = $Partition; + return $this; + } + + public static function jsonUnserialize(\stdClass $decoded): self + { + $n = new self(); + foreach ((array)$decoded as $k => $v) { + if ('TaggedAddresses' === $k) { + $n->setTaggedAddresses($v); + } elseif ('NodeMeta' === $k) { + $n->setNodeMeta($v); + } elseif ('ServiceTaggedAddresses' === $k) { + foreach ($v as $kk => $vv) { + $n->setServiceTaggedAddress($kk, ServiceAddress::jsonUnserialize($vv)); + } + } elseif ('Weights' === $k || 'ServiceWeights' === $k) { + $n->ServiceWeights = Weights::jsonUnserialize($v); + } elseif ('ServiceProxy' === $k) { + if (null !== $v) { + $n->ServiceProxy = AgentServiceConnectProxyConfig::jsonUnserialize($v); + } + } elseif ('ServiceLocality' === $k) { + if (null !== $v) { + $n->ServiceLocality = Locality::jsonUnserialize($v); + } + } elseif ('Checks' === $k) { + if (null !== $v) { + $n->Checks = HealthChecks::jsonUnserialize($v); + } + } elseif ('ServiceMeta' === $k) { + $n->setServiceMeta($v); + } else { + $n->{$k} = $v; + } + } + return $n; + } + + public function jsonSerialize(): \stdClass + { + $out = $this->_startJsonSerialize(); + $out->ID = $this->ID; + $out->Node = $this->Node; + $out->Address = $this->Address; + $out->Datacenter = $this->Datacenter; + $out->TaggedAddresses = $this->getTaggedAddresses(); + $out->NodeMeta = $this->getNodeMeta(); + $out->ServiceID = $this->ServiceID; + $out->ServiceName = $this->ServiceName; + $out->ServiceAddress = $this->ServiceAddress; + $out->ServiceTaggedAddresses = $this->getServiceTaggedAddresses(); + $out->ServiceTags = $this->ServiceTags; + $out->ServiceMeta = $this->getServiceMeta(); + $out->ServicePort = $this->ServicePort; + $out->ServiceWeights = $this->ServiceWeights; + $out->ServiceEnableTagOverride = $this->ServiceEnableTagOverride; + $out->ServiceProxy = $this->ServiceProxy; + if (null !== $this->ServiceLocality) { + $out->ServiceLocality = $this->ServiceLocality; + } + $out->CreateIndex = $this->CreateIndex; + $out->Checks = $this->Checks; + $out->ModifyIndex = $this->ModifyIndex; + if ('' !== $this->Namespace) { + $out->Namespace = $this->Namespace; + } + if ('' !== $this->Partition) { + $out->Partition = $this->Partition; + } + return $out; + } } diff --git a/src/Catalog/CatalogServicesResponse.php b/src/Catalog/CatalogServicesResponse.php index 6cbbc8f1..2fbb2162 100644 --- a/src/Catalog/CatalogServicesResponse.php +++ b/src/Catalog/CatalogServicesResponse.php @@ -20,23 +20,27 @@ limitations under the License. */ -use DCarbone\PHPConsulAPI\AbstractValuedQueryResponse; -use DCarbone\PHPConsulAPI\UnmarshalledResponseInterface; +use DCarbone\PHPConsulAPI\PHPLib\AbstractValuedQueryResponse; +use DCarbone\PHPConsulAPI\PHPLib\UnmarshalledResponseInterface; class CatalogServicesResponse extends AbstractValuedQueryResponse implements UnmarshalledResponseInterface { - public ?array $Services = null; + /** @var array<\DCarbone\PHPConsulAPI\Catalog\CatalogService> */ + public array $Services = []; - public function getValue(): ?array + /** + * @return array<\DCarbone\PHPConsulAPI\Catalog\CatalogService> + */ + public function getValue(): array { return $this->Services; } - public function unmarshalValue(mixed $decodedData): void + public function unmarshalValue(mixed $decoded): void { $this->Services = []; - foreach ($decodedData as $node) { - $this->Services[] = new CatalogService($node); + foreach ($decoded as $node) { + $this->Services[] = CatalogService::jsonUnserialize($node); } } } diff --git a/src/Catalog/CompoundServiceName.php b/src/Catalog/CompoundServiceName.php index 31d32162..41852136 100644 --- a/src/Catalog/CompoundServiceName.php +++ b/src/Catalog/CompoundServiceName.php @@ -20,19 +20,23 @@ limitations under the License. */ -use DCarbone\PHPConsulAPI\AbstractModel; -use DCarbone\PHPConsulAPI\Transcoding; +use DCarbone\PHPConsulAPI\PHPLib\AbstractType; -class CompoundServiceName extends AbstractModel +class CompoundServiceName extends AbstractType { - protected const FIELDS = [ - self::FIELD_NAMESPACE => Transcoding::OMITEMPTY_STRING_FIELD, - ]; + public string $Name; + public string $Namespace; + public string $Partition; - private const FIELD_NAMESPACE = 'Namespace'; - - public string $Name = ''; - public string $Namespace = ''; + public function __construct( + string $Name = '', + string $Namespace = '', + string $Partition = '', + ) { + $this->Name = $Name; + $this->Namespace = $Namespace; + $this->Partition = $Partition; + } public function getName(): string { @@ -55,4 +59,37 @@ public function setNamespace(string $Namespace): self $this->Namespace = $Namespace; return $this; } + + public function getPartition(): string + { + return $this->Partition; + } + + public function setPartition(string $Partition): self + { + $this->Partition = $Partition; + return $this; + } + + public static function jsonUnserialize(\stdClass $decoded): self + { + $n = new self(); + foreach ((array)$decoded as $k => $v) { + $n->{$k} = $v; + } + return $n; + } + + public function jsonSerialize(): \stdClass + { + $out = $this->_startJsonSerialize(); + $out->Name = $this->Name; + if ('' !== $this->Namespace) { + $out->Namespace = $this->Namespace; + } + if ('' !== $this->Partition) { + $out->Partition = $this->Partition; + } + return $out; + } } diff --git a/src/Catalog/GatewayService.php b/src/Catalog/GatewayService.php index 2a47bee2..b277beec 100644 --- a/src/Catalog/GatewayService.php +++ b/src/Catalog/GatewayService.php @@ -20,66 +20,51 @@ limitations under the License. */ -use DCarbone\PHPConsulAPI\AbstractModel; -use DCarbone\PHPConsulAPI\Transcoding; +use DCarbone\PHPConsulAPI\Agent\ServiceKind; +use DCarbone\PHPConsulAPI\PHPLib\AbstractType; -class GatewayService extends AbstractModel +class GatewayService extends AbstractType { - protected const FIELDS = [ - self::FIELD_GATEWAY => [ - Transcoding::FIELD_TYPE => Transcoding::OBJECT, - Transcoding::FIELD_CLASS => CompoundServiceName::class, - ], - self::FIELD_SERVICE => [ - Transcoding::FIELD_TYPE => Transcoding::OBJECT, - Transcoding::FIELD_CLASS => CompoundServiceName::class, - ], - self::FIELD_PORT => Transcoding::OMITEMPTY_INTEGER_FIELD, - self::FIELD_PROTOCOL => Transcoding::OMITEMPTY_STRING_FIELD, - self::FIELD_HOSTS => [ - Transcoding::FIELD_TYPE => Transcoding::ARRAY, - Transcoding::FIELD_ARRAY_TYPE => Transcoding::STRING, - Transcoding::FIELD_OMITEMPTY => true, - ], - self::FIELD_CA_FILE => Transcoding::OMITEMPTY_STRING_FIELD, - self::FIELD_CERT_FILE => Transcoding::OMITEMPTY_STRING_FIELD, - self::FIELD_KEY_FILE => Transcoding::OMITEMPTY_STRING_FIELD, - self::FIELD_SNI => Transcoding::OMITEMPTY_STRING_FIELD, - self::FIELD_FROM_WILDCARD => Transcoding::OMITEMPTY_BOOLEAN_FIELD, - ]; - - private const FIELD_GATEWAY = 'Gateway'; - private const FIELD_SERVICE = 'Service'; - private const FIELD_PORT = 'Port'; - private const FIELD_PROTOCOL = 'Protocol'; - private const FIELD_HOSTS = 'Hosts'; - private const FIELD_CA_FILE = 'CAFile'; - private const FIELD_CERT_FILE = 'CertFile'; - private const FIELD_KEY_FILE = 'KeyFile'; - private const FIELD_SNI = 'SNI'; - private const FIELD_FROM_WILDCARD = 'FromWildcard'; - public CompoundServiceName $Gateway; public CompoundServiceName $Service; - public string $GatewayKind = ''; - public int $Port = 0; - public string $Protocol = ''; - public array $Hosts = []; - public string $CAFile = ''; - public string $CertFile = ''; - public string $KeyFile = ''; - public string $SNI = ''; - public string $FromWildCard = ''; - - public function __construct(?array $data = []) - { - parent::__construct($data); - if (!isset($this->Gateway)) { - $this->Gateway = new CompoundServiceName(); - } - if (!isset($this->Service)) { - $this->Service = new CompoundServiceName(); - } + public ServiceKind $GatewayKind; + public int $Port; + public string $Protocol; + /** @var array */ + public array $Hosts; + public string $CAFile; + public string $CertFile; + public string $KeyFile; + public string $SNI; + public string $FromWildCard; + + /** + * @param array $Hosts + */ + public function __construct( + null|CompoundServiceName $Gateway = null, + null|CompoundServiceName $Service = null, + string|ServiceKind $GatewayKind = '', + int $Port = 0, + string $Protocol = '', + array $Hosts = [], + string $CAFile = '', + string $CertFile = '', + string $KeyFile = '', + string $SNI = '', + string $FromWildCard = '', + ) { + $this->Gateway = $Gateway ?? new CompoundServiceName(); + $this->Service = $Service ?? new CompoundServiceName(); + $this->GatewayKind = $GatewayKind instanceof ServiceKind ? $GatewayKind : ServiceKind::from($GatewayKind); + $this->Port = $Port; + $this->Protocol = $Protocol; + $this->setHosts(...$Hosts); + $this->CAFile = $CAFile; + $this->CertFile = $CertFile; + $this->KeyFile = $KeyFile; + $this->SNI = $SNI; + $this->FromWildCard = $FromWildCard; } public function getGateway(): CompoundServiceName @@ -104,12 +89,12 @@ public function setService(CompoundServiceName $Service): self return $this; } - public function getGatewayKind(): string + public function getGatewayKind(): ServiceKind { return $this->GatewayKind; } - public function setGatewayKind(string $GatewayKind): self + public function setGatewayKind(ServiceKind $GatewayKind): self { $this->GatewayKind = $GatewayKind; return $this; @@ -137,12 +122,15 @@ public function setProtocol(string $Protocol): self return $this; } + /** + * @return array + */ public function getHosts(): array { return $this->Hosts; } - public function setHosts(array $Hosts): self + public function setHosts(string ...$Hosts): self { $this->Hosts = $Hosts; return $this; @@ -202,4 +190,57 @@ public function setFromWildCard(string $FromWildCard): self $this->FromWildCard = $FromWildCard; return $this; } + + public static function jsonUnserialize(\stdClass $decoded): self + { + $n = new self(); + foreach ((array)$decoded as $k => $v) { + if ('Gateway' === $k) { + $n->Gateway = CompoundServiceName::jsonUnserialize($v); + } elseif ('Service' === $k) { + $n->Service = CompoundServiceName::jsonUnserialize($v); + } elseif ('GatewayKind' === $k) { + $n->GatewayKind = ServiceKind::from($v); + } elseif ('Hosts' === $k) { + $n->setHosts(...$v); + } else { + $n->{$k} = $v; + } + } + return $n; + } + + + public function jsonSerialize(): \stdClass + { + $out = $this->_startJsonSerialize(); + $out->Gateway = $this->Gateway; + $out->Service = $this->Service; + $out->GatewayKind = $this->GatewayKind->value; + if (0 !== $this->Port) { + $out->Port = $this->Port; + } + if ('' !== $this->Protocol) { + $out->Protocol = $this->Protocol; + } + if ([] !== $this->Hosts) { + $out->Hosts = $this->Hosts; + } + if ('' !== $this->CAFile) { + $out->CAFile = $this->CAFile; + } + if ('' !== $this->CertFile) { + $out->CertFile = $this->CertFile; + } + if ('' !== $this->KeyFile) { + $out->KeyFile = $this->KeyFile; + } + if ('' !== $this->SNI) { + $out->SNI = $this->SNI; + } + if ('' !== $this->FromWildCard) { + $out->FromWildCard = $this->FromWildCard; + } + return $out; + } } diff --git a/src/Catalog/GatewayServicesResponse.php b/src/Catalog/GatewayServicesResponse.php index cbf9d620..933dd34d 100644 --- a/src/Catalog/GatewayServicesResponse.php +++ b/src/Catalog/GatewayServicesResponse.php @@ -20,23 +20,27 @@ limitations under the License. */ -use DCarbone\PHPConsulAPI\AbstractValuedQueryResponse; -use DCarbone\PHPConsulAPI\UnmarshalledResponseInterface; +use DCarbone\PHPConsulAPI\PHPLib\AbstractValuedQueryResponse; +use DCarbone\PHPConsulAPI\PHPLib\UnmarshalledResponseInterface; class GatewayServicesResponse extends AbstractValuedQueryResponse implements UnmarshalledResponseInterface { - public ?array $GatewayServices = null; + /** @var \DCarbone\PHPConsulAPI\Catalog\GatewayService[] */ + public array $GatewayServices = []; - public function getValue(): mixed + /** + * @return \DCarbone\PHPConsulAPI\Catalog\GatewayService[] + */ + public function getValue(): array { return $this->GatewayServices; } - public function unmarshalValue(mixed $decodedData): void + public function unmarshalValue(mixed $decoded): void { $this->GatewayServices = []; - foreach ($decodedData as $service) { - $this->GatewayServices[] = new GatewayService($service); + foreach ($decoded as $service) { + $this->GatewayServices[] = GatewayService::jsonUnserialize($service); } } } diff --git a/src/Catalog/Node.php b/src/Catalog/Node.php index 2a6d19fa..39a9c54f 100644 --- a/src/Catalog/Node.php +++ b/src/Catalog/Node.php @@ -20,35 +20,54 @@ limitations under the License. */ -use DCarbone\PHPConsulAPI\AbstractModel; -use DCarbone\PHPConsulAPI\FakeMap; -use DCarbone\PHPConsulAPI\Transcoding; +use DCarbone\PHPConsulAPI\Peering\Locality; +use DCarbone\PHPConsulAPI\PHPLib\AbstractType; +use DCarbone\PHPConsulAPI\PHPLib\MetaField; +use DCarbone\PHPConsulAPI\PHPLib\TaggedAddressField; -class Node extends AbstractModel +class Node extends AbstractType { - protected const FIELDS = [ - self::FIELD_TAGGED_ADDRESSES => Transcoding::MAP_FIELD, - self::FIELD_META => Transcoding::MAP_FIELD, - ]; - - private const FIELD_TAGGED_ADDRESSES = 'TaggedAddresses'; - private const FIELD_META = 'Meta'; - - public string $ID = ''; - public string $Node = ''; - public string $Address = ''; - public string $Datacenter = ''; - public FakeMap $TaggedAddresses; - public FakeMap $Meta; - public int $CreateIndex = 0; - public int $ModifyIndex = 0; - - public function __construct(?array $data = []) - { - parent::__construct($data); - if (!isset($this->Meta)) { - $this->Meta = new FakeMap(null); - } + use MetaField; + use TaggedAddressField; + + public string $ID; + public string $Node; + public string $Address; + public string $Datacenter; + public int $CreateIndex; + public int $ModifyIndex; + public string $Partition; + public string $PeerName; + public null|Locality $Locality; + + /** + * @param array $TaggedAddresses + * @param array $Meta + */ + public function __construct( + string $ID = '', + string $Node = '', + string $Address = '', + string $Datacenter = '', + array $TaggedAddresses = [], + array $Meta = [], + int $CreateIndex = 0, + int $ModifyIndex = 0, + string $Partition = '', + string $PeerName = '', + null|Locality $Locality = null, + ) { + $this->ID = $ID; + $this->Node = $Node; + $this->Address = $Address; + $this->Datacenter = $Datacenter; + $this->setTaggedAddresses($TaggedAddresses); + $this->setMeta($Meta); + $this->CreateIndex = $CreateIndex; + $this->ModifyIndex = $ModifyIndex; + $this->Partition = $Partition; + $this->PeerName = $PeerName; + $this->Locality = $Locality; } public function getID(): string @@ -95,47 +114,98 @@ public function setDatacenter(string $Datacenter): self return $this; } - public function getTaggedAddresses(): FakeMap + public function getCreateIndex(): int { - return $this->TaggedAddresses; + return $this->CreateIndex; } - public function setTaggedAddresses(FakeMap $TaggedAddresses): self + public function setCreateIndex(int $CreateIndex): self { - $this->TaggedAddresses = $TaggedAddresses; + $this->CreateIndex = $CreateIndex; return $this; } - public function getMeta(): FakeMap + public function getModifyIndex(): int { - return $this->Meta; + return $this->ModifyIndex; } - public function setMeta(FakeMap $Meta): self + public function setModifyIndex(int $ModifyIndex): self { - $this->Meta = $Meta; + $this->ModifyIndex = $ModifyIndex; return $this; } - public function getCreateIndex(): int + public function getPartition(): string { - return $this->CreateIndex; + return $this->Partition; } - public function setCreateIndex(int $CreateIndex): self + public function setPartition(string $Partition): self { - $this->CreateIndex = $CreateIndex; + $this->Partition = $Partition; return $this; } - public function getModifyIndex(): int + public function getPeerName(): string { - return $this->ModifyIndex; + return $this->PeerName; } - public function setModifyIndex(int $ModifyIndex): self + public function setPeerName(string $PeerName): self { - $this->ModifyIndex = $ModifyIndex; + $this->PeerName = $PeerName; + return $this; + } + + public function getLocality(): null|Locality + { + return $this->Locality; + } + + public function setLocality(null|Locality $Locality): self + { + $this->Locality = $Locality; return $this; } + + public static function jsonUnserialize(\stdClass $decoded): self + { + $n = new self(); + foreach ((array)$decoded as $k => $v) { + if ('Locality' === $k) { + $n->Locality = Locality::jsonUnserialize($v); + } elseif ('Meta' === $k) { + $n->setMeta($v); + } elseif ('TaggedAddresses' === $k) { + $n->setTaggedAddresses($v); + } else { + $n->{$k} = $v; + } + } + return $n; + } + + public function jsonSerialize(): \stdClass + { + $out = $this->_startJsonSerialize(); + $out->ID = $this->ID; + $out->Node = $this->Node; + $out->Address = $this->Address; + $out->Datacenter = $this->Datacenter; + $out->TaggedAddresses = $this->getTaggedAddresses(); + $out->Meta = $this->getMeta(); + $out->CreateIndex = $this->CreateIndex; + $out->ModifyIndex = $this->ModifyIndex; + if ('' !== $this->Partition) { + $out->Partition = $this->Partition; + } + if ('' !== $this->PeerName) { + $out->PeerName = $this->PeerName; + } + if (null !== $this->Locality) { + $out->Locality = $this->Locality; + } + return $out; + } } diff --git a/src/Catalog/NodesResponse.php b/src/Catalog/NodesResponse.php index f38cddd9..06db580c 100644 --- a/src/Catalog/NodesResponse.php +++ b/src/Catalog/NodesResponse.php @@ -20,23 +20,27 @@ limitations under the License. */ -use DCarbone\PHPConsulAPI\AbstractValuedQueryResponse; -use DCarbone\PHPConsulAPI\UnmarshalledResponseInterface; +use DCarbone\PHPConsulAPI\PHPLib\AbstractValuedQueryResponse; +use DCarbone\PHPConsulAPI\PHPLib\UnmarshalledResponseInterface; class NodesResponse extends AbstractValuedQueryResponse implements UnmarshalledResponseInterface { - public ?array $Nodes = null; + /** @var \DCarbone\PHPConsulAPI\Catalog\Node[] */ + public array $Nodes = []; - public function getValue(): mixed + /** + * @return \DCarbone\PHPConsulAPI\Catalog\Node[] + */ + public function getValue(): array { return $this->Nodes; } - public function unmarshalValue(mixed $decodedData): void + public function unmarshalValue(mixed $decoded): void { $this->Nodes = []; - foreach ($decodedData as $node) { - $this->Nodes[] = new Node($node); + foreach ($decoded as $node) { + $this->Nodes[] = Node::jsonUnserialize($node); } } } diff --git a/src/Catalog/ServiceAddress.php b/src/Catalog/ServiceAddress.php index 27d1fb6b..6fa62893 100644 --- a/src/Catalog/ServiceAddress.php +++ b/src/Catalog/ServiceAddress.php @@ -20,21 +20,27 @@ limitations under the License. */ -use DCarbone\PHPConsulAPI\AbstractModel; +use DCarbone\PHPConsulAPI\PHPLib\AbstractType; -class ServiceAddress extends AbstractModel +class ServiceAddress extends AbstractType { - public string $Address = ''; - public int $Port = 0; + public string $Address; + public int $Port; + + public function __construct(string $Address = '', int $Port = 0) + { + $this->Address = $Address; + $this->Port = $Port; + } public function getAddress(): string { return $this->Address; } - public function setAddress(string $address): self + public function setAddress(string $Address): self { - $this->Address = $address; + $this->Address = $Address; return $this; } @@ -43,9 +49,26 @@ public function getPort(): int return $this->Port; } - public function setPort(int $port): self + public function setPort(int $Port): self { - $this->Port = $port; + $this->Port = $Port; return $this; } + + public static function jsonUnserialize(\stdClass $decoded): self + { + $n = new self(); + foreach ((array)$decoded as $k => $v) { + $n->{$k} = $v; + } + return $n; + } + + public function jsonSerialize(): \stdClass + { + $out = $this->_startJsonSerialize(); + $out->Address = $this->Address; + $out->Port = $this->Port; + return $out; + } } diff --git a/src/Catalog/Weights.php b/src/Catalog/Weights.php index 08021e75..f4940d5e 100644 --- a/src/Catalog/Weights.php +++ b/src/Catalog/Weights.php @@ -20,12 +20,18 @@ limitations under the License. */ -use DCarbone\PHPConsulAPI\AbstractModel; +use DCarbone\PHPConsulAPI\PHPLib\AbstractType; -class Weights extends AbstractModel +class Weights extends AbstractType { - public int $Passing = 0; - public int $Warning = 0; + public int $Passing; + public int $Warning; + + public function __construct(int $Passing = 0, int $Warning = 0) + { + $this->Passing = $Passing; + $this->Warning = $Warning; + } public function getPassing(): int { @@ -48,4 +54,21 @@ public function setWarning(int $Warning): self $this->Warning = $Warning; return $this; } + + public static function jsonUnserialize(\stdClass $decoded): self + { + $n = new self(); + foreach ((array)$decoded as $k => $v) { + $n->{$k} = $v; + } + return $n; + } + + public function jsonSerialize(): \stdClass + { + $out = $this->_startJsonSerialize(); + $out->Passing = $this->Passing; + $out->Warning = $this->Warning; + return $out; + } } diff --git a/src/Config.php b/src/Config.php index 7f652148..010cf8ea 100644 --- a/src/Config.php +++ b/src/Config.php @@ -27,63 +27,38 @@ class Config { - use Unmarshaller; - public const DEFAULT_REQUEST_OPTIONS = [ RequestOptions::HTTP_ERRORS => false, RequestOptions::DECODE_CONTENT => false, ]; - protected const FIELDS = [ - self::FIELD_HTTP_AUTH => [ - Transcoding::FIELD_UNMARSHAL_CALLBACK => 'setHttpAuth', - ], - self::FIELD_WAIT_TIME => [ - Transcoding::FIELD_UNMARSHAL_CALLBACK => Transcoding::UNMARSHAL_NULLABLE_DURATION, - ], - ]; + public const DEFAULT_ADDRESS = '127.0.0.1:8500'; + public const DEFAULT_SCHEME = 'http'; - private const FIELD_HTTP_AUTH = 'HttpAuth'; - private const FIELD_WAIT_TIME = 'WaitTime'; - private const FIELD_ADDRESS = 'Address'; - private const FIELD_SCHEME = 'Scheme'; - private const FIELD_JSON_ENCODE_OPTS = 'JSONEncodeOpts'; - private const FIELD_TOKEN = 'Token'; - private const FIELD_TOKEN_FILE = 'TokenFile'; - private const FIELD_CA_FILE = 'CAFile'; - private const FIELD_CERT_FILE = 'CertFile'; - private const FIELD_KEY_FILE = 'KeyFile'; - private const FIELD_INSECURE_SKIP_VERIFY = 'InsecureSkipVerify'; - - private const DEFAULT_CONFIG = [ - self::FIELD_ADDRESS => '127.0.0.1:8500', - self::FIELD_SCHEME => 'http', - self::FIELD_JSON_ENCODE_OPTS => \JSON_UNESCAPED_SLASHES, - ]; /** * The address, including port, of your Consul Agent * * @var string */ - public string $Address = ''; + public string $Address; - public string $Scheme = ''; + public string $Scheme; - public string $Datacenter = ''; + public string $Datacenter; - public string $Namespace = ''; + public string $Namespace; /** * HTTP authentication, if used * * @var \DCarbone\PHPConsulAPI\HttpAuth|null */ - public ?HttpAuth $HttpAuth = null; + public null|HttpAuth $HttpAuth; - public ?Time\Duration $WaitTime = null; + public null|Time\Duration $WaitTime; - public string $Token = ''; + public string $Token; /** * File containing the current token to use for this client. @@ -92,35 +67,63 @@ class Config * * @var string */ - public string $TokenFile = ''; + public string $TokenFile; - public string $CAFile = ''; + public string $CAFile; /** * Optional path to certificate. If set, KeyFile must also be set * * @var string */ - public string $CertFile = ''; + public string $CertFile; /** * Optional path to private key. If set, CertFile must also be set * * @var string */ - public string $KeyFile = ''; + public string $KeyFile; - public bool $InsecureSkipVerify = false; + public bool $InsecureSkipVerify; public ClientInterface $HttpClient; - public int $JSONEncodeOpts = 0; - - public function __construct(array $config = []) - { - foreach ($config + self::_getDefaultConfig() as $k => $v) { - $this->unmarshalField($k, $v); - } + public int $JSONEncodeOpts; + public int $JSONDecodeMaxDepth; + public int $JSONDecodeOpts; + + public function __construct( + string $Address = self::DEFAULT_ADDRESS, + string $Scheme = self::DEFAULT_SCHEME, + string $Datacenter = '', + string $Namespace = '', + null|string|HttpAuth $HttpAuth = null, + null|string|int|float|\DateInterval|Time\Duration $WaitTime = null, + string $Token = '', + string $TokenFile = '', + string $CAFile = '', + string $CertFile = '', + string $KeyFile = '', + bool $InsecureSkipVerify = false, + null|ClientInterface $HttpClient = null, + int $JSONEncodeOpts = JSON_UNESCAPED_SLASHES, + int $JSONDecodeMaxDepth = 512, + int $JSONDecodeOpts = 0, + ) { + $this->Address = self::_resolveValue($Address, Consul::HTTPAddrEnvName, self::DEFAULT_ADDRESS); + $this->setScheme(self::_resolveValue($Scheme, Consul::HTTPSSLEnvName, self::DEFAULT_SCHEME)); + $this->Datacenter = $Datacenter; + $this->Namespace = $Namespace; + $this->setHttpAuth(self::_resolveValue($HttpAuth, Consul::HTTPAuthEnvName, null)); + $this->setWaitTime($WaitTime); + $this->Token = self::_resolveValue($Token, Consul::HTTPTokenEnvName, ''); + $this->TokenFile = self::_resolveValue($TokenFile, Consul::HTTPTokenFileEnvName, ''); + $this->CAFile = self::_resolveValue($CAFile, Consul::HTTPCAFileEnvName, ''); + $this->CertFile = self::_resolveValue($CertFile, Consul::HTTPClientCertEnvName, ''); + $this->KeyFile = self::_resolveValue($KeyFile, Consul::HTTPClientKeyEnvName, ''); + $skipVerify = self::_resolveValue($InsecureSkipVerify, Consul::HTTPSSLVerifyEnvName, false); + $this->InsecureSkipVerify = is_string($skipVerify) ? strtolower($skipVerify) === 'true' : $skipVerify; // quick validation on key/cert combo $c = $this->CertFile; @@ -136,13 +139,14 @@ public function __construct(array $config = []) ); } - // if client hasn't been constructed, construct. - if (!isset($this->HttpClient)) { - $this->HttpClient = new Client(); - } + $this->HttpClient = $HttpClient ?? new Client(); + + $this->JSONEncodeOpts = $JSONEncodeOpts; + $this->JSONDecodeMaxDepth = $JSONDecodeMaxDepth; + $this->JSONDecodeOpts = $JSONDecodeOpts; } - public static function merge(?self $inc): self + public static function merge(null|Config $inc): Config { $actual = static::newDefaultConfig(); if (null === $inc) { @@ -184,18 +188,22 @@ public static function merge(?self $inc): self if ($inc->InsecureSkipVerify) { $actual->InsecureSkipVerify = true; } - if (null !== $inc->HttpClient) { + if (isset($inc->HttpClient)) { $actual->HttpClient = $inc->HttpClient; } if (0 !== $inc->JSONEncodeOpts) { $actual->JSONEncodeOpts = $inc->JSONEncodeOpts; } + if (0 !== $inc->JSONDecodeMaxDepth) { + $actual->JSONDecodeMaxDepth = $inc->JSONDecodeMaxDepth; + } + $actual->JSONDecodeOpts = self::_resolveValue($inc->JSONDecodeOpts, '', $actual->JSONDecodeOpts); return $actual; } public static function newDefaultConfig(): self { - return new static(self::_getDefaultConfig()); + return new self(); } public function getAddress(): string @@ -214,9 +222,13 @@ public function getScheme(): string return $this->Scheme; } - public function setScheme(string $scheme): self + public function setScheme(bool|string $scheme): self { - $this->Scheme = $scheme; + $this->Scheme = match (is_string($scheme) ? strtolower($scheme) : $scheme) { + true, 'true', '1' => 'https', + false, 'false', '0' => 'http', + default => $scheme, + }; return $this; } @@ -236,9 +248,10 @@ public function getNamespace(): string return $this->Namespace; } - public function setNamespace(string $namespace): void + public function setNamespace(string $namespace): self { $this->Namespace = $namespace; + return $this; } public function getWaitTime(): Time\Duration @@ -246,7 +259,7 @@ public function getWaitTime(): Time\Duration return $this->WaitTime; } - public function setWaitTime(mixed $waitTime): self + public function setWaitTime(null|string|int|float|\DateInterval|Time\Duration $waitTime): self { $this->WaitTime = Time::Duration($waitTime); return $this; @@ -290,9 +303,14 @@ public function getHttpAuth(): HttpAuth return $this->HttpAuth; } - public function setHttpAuth(HttpAuth|string $httpAuth): self + public function setHttpAuth(null|string|HttpAuth $httpAuth): self { - if (\is_string($httpAuth)) { + if (null === $httpAuth) { + $this->HttpAuth = null; + return $this; + } + + if (is_string($httpAuth)) { $colon = strpos($httpAuth, ':'); if (false === $colon) { $username = $httpAuth; @@ -304,18 +322,8 @@ public function setHttpAuth(HttpAuth|string $httpAuth): self $httpAuth = new HttpAuth($username, $password); } - if ($httpAuth instanceof HttpAuth) { - $this->HttpAuth = $httpAuth; - return $this; - } - - throw new \InvalidArgumentException( - sprintf( - '%s::setHttpAuth - Value is expected to be string of "username:password" or instance of "\\DCarbone\\PHPConsulApi\\HttpAuth", %s seen.', - static::class, - \is_string($httpAuth) ? $httpAuth : \gettype($httpAuth) - ) - ); + $this->HttpAuth = $httpAuth; + return $this; } public function getCAFile(): string @@ -373,77 +381,44 @@ public function setJSONEncodeOpts(int $jsonEncodeOpts): self return $this; } - public static function getEnvironmentConfig(): array - { - $ret = []; - foreach ( - [ - Consul::HTTPAddrEnvName => static::_tryGetEnvParam(Consul::HTTPAddrEnvName), - Consul::HTTPTokenEnvName => static::_tryGetEnvParam(Consul::HTTPTokenEnvName), - Consul::HTTPTokenFileEnvName => static::_tryGetEnvParam(Consul::HTTPTokenFileEnvName), - Consul::HTTPAuthEnvName => static::_tryGetEnvParam(Consul::HTTPAuthEnvName), - Consul::HTTPCAFileEnvName => static::_tryGetEnvParam(Consul::HTTPCAFileEnvName), - Consul::HTTPClientCertEnvName => static::_tryGetEnvParam(Consul::HTTPClientCertEnvName), - Consul::HTTPClientKeyEnvName => static::_tryGetEnvParam(Consul::HTTPClientKeyEnvName), - Consul::HTTPSSLEnvName => static::_tryGetEnvParam(Consul::HTTPSSLEnvName), - Consul::HTTPSSLVerifyEnvName => static::_tryGetEnvParam(Consul::HTTPSSLVerifyEnvName), - ] as $k => $v - ) { - if (null !== $v) { - $ret[$k] = $v; - } - } - return $ret; + public function getJSONDecodeMaxDepth(): int + { + return $this->JSONDecodeMaxDepth; } - protected static function _tryGetEnvParam(string $param): ?string + public function setJSONDecodeMaxDepth(int $JSONDecodeMaxDepth): self { - if (isset($_ENV[$param])) { - return $_ENV[$param]; - } + $this->JSONDecodeMaxDepth = $JSONDecodeMaxDepth; + return $this; + } - if (false !== ($value = getenv($param))) { - return $value; - } + public function getJSONDecodeOpts(): int + { + return $this->JSONDecodeOpts; + } - if (isset($_SERVER[$param])) { - return $_SERVER[$param]; + public function setJSONDecodeOpts(int $JSONDecodeOpts): self + { + $this->JSONDecodeOpts = $JSONDecodeOpts; + return $this; + } + + protected static function _resolveValue(mixed $explicit, string $env, mixed $default): mixed + { + if ($explicit !== $default) { + return $explicit; } - return null; - } - - private static function _getDefaultConfig(): array - { - $conf = self::DEFAULT_CONFIG; - - // parse env vars - foreach (static::getEnvironmentConfig() as $k => $v) { - if (Consul::HTTPAddrEnvName === $k) { - $conf[self::FIELD_ADDRESS] = $v; - } elseif (Consul::HTTPTokenEnvName === $k) { - $conf[self::FIELD_TOKEN] = $v; - } elseif (Consul::HTTPTokenFileEnvName === $k) { - $conf[self::FIELD_TOKEN_FILE] = $v; - } elseif (Consul::HTTPAuthEnvName === $k) { - $conf[self::FIELD_HTTP_AUTH] = $v; - } elseif (Consul::HTTPCAFileEnvName === $k) { - $conf[self::FIELD_CA_FILE] = $v; - } elseif (Consul::HTTPClientCertEnvName === $k) { - $conf[self::FIELD_CERT_FILE] = $v; - } elseif (Consul::HTTPClientKeyEnvName === $k) { - $conf[self::FIELD_KEY_FILE] = $v; - } elseif (Consul::HTTPSSLEnvName === $k) { - if ((bool)$v) { - $conf[self::FIELD_SCHEME] = 'https'; - } - } elseif (Consul::HTTPSSLVerifyEnvName === $k) { - if ((bool)$v) { - $conf[self::FIELD_INSECURE_SKIP_VERIFY] = true; - } + if ($env !== '') { + if (isset($_ENV[$env])) { + return $_ENV[$env]; + } elseif (false !== ($value = getenv($env))) { + return $value; + } elseif (isset($_SERVER[$env])) { + return $_SERVER[$env]; } } - return $conf; + return $default; } } diff --git a/src/ConfigEntry/AccessLogsConfig.php b/src/ConfigEntry/AccessLogsConfig.php new file mode 100644 index 00000000..7fec5ec0 --- /dev/null +++ b/src/ConfigEntry/AccessLogsConfig.php @@ -0,0 +1,152 @@ +Enabled = $Enabled; + $this->DisableListenerLogs = $DisableListenerLogs; + $this->Type = $Type instanceof LogSinkType ? $Type : LogSinkType::from($Type); + $this->Path = $Path; + $this->JSONFormat = $JSONFormat; + $this->TextFormat = $TextFormat; + } + + public function isEnabled(): bool + { + return $this->Enabled; + } + + public function setEnabled(bool $Enabled): self + { + $this->Enabled = $Enabled; + return $this; + } + + public function isDisableListenerLogs(): bool + { + return $this->DisableListenerLogs; + } + + public function setDisableListenerLogs(bool $DisableListenerLogs): self + { + $this->DisableListenerLogs = $DisableListenerLogs; + return $this; + } + + public function getType(): LogSinkType + { + return $this->Type; + } + + public function setType(string|LogSinkType $Type): self + { + $this->Type = $Type instanceof LogSinkType ? $Type : LogSinkType::from($Type); + return $this; + } + + public function getPath(): string + { + return $this->Path; + } + + public function setPath(string $Path): self + { + $this->Path = $Path; + return $this; + } + + public function getJSONFormat(): string + { + return $this->JSONFormat; + } + + public function setJSONFormat(string $JSONFormat): self + { + $this->JSONFormat = $JSONFormat; + return $this; + } + + public function getTextFormat(): string + { + return $this->TextFormat; + } + + public function setTextFormat(string $TextFormat): self + { + $this->TextFormat = $TextFormat; + return $this; + } + + public static function jsonUnserialize(\stdClass $decoded): self + { + $n = new self(); + foreach ((array)$decoded as $k => $v) { + if ('Type' === $k) { + $n->setType($v); + } else { + $n->{$k} = $v; + } + } + return $n; + } + + public function jsonSerialize(): \stdClass + { + $out = $this->_startJsonSerialize(); + if ($this->Enabled) { + $out->Enabled = $this->Enabled; + } + if ($this->DisableListenerLogs) { + $out->DisableListenerLogs = $this->DisableListenerLogs; + } + if ($this->Type !== LogSinkType::Default) { + $out->Type = $this->Type->value; + } + if ('' !== $this->Path) { + $out->Path = $this->Path; + } + if ('' !== $this->JSONFormat) { + $out->JSONFormat = $this->JSONFormat; + } + if ('' !== $this->TextFormat) { + $out->TextFormat = $this->TextFormat; + } + return $out; + } +} diff --git a/src/ConfigEntry/ConfigEntry.php b/src/ConfigEntry/ConfigEntry.php index 23789581..e90438a5 100644 --- a/src/ConfigEntry/ConfigEntry.php +++ b/src/ConfigEntry/ConfigEntry.php @@ -20,9 +20,6 @@ limitations under the License. */ -use DCarbone\PHPConsulAPI\FakeMap; -use DCarbone\PHPConsulAPI\Transcoding; - /** * Interface ConfigEntry * @@ -31,21 +28,16 @@ */ interface ConfigEntry { - public const INTERFACE_FIELDS = [ - self::FIELD_NAMESPACE => Transcoding::OMITEMPTY_STRING_FIELD, - self::FIELD_META => Transcoding::MAP_FIELD, - ]; - - public const FIELD_NAMESPACE = 'Namespace'; - public const FIELD_META = 'Meta'; - public function GetKind(): string; public function GetName(): string; public function GetNamespace(): string; - public function GetMeta(): ?FakeMap; + /** + * @return array|null + */ + public function GetMeta(): null|array; public function GetCreateIndex(): int; diff --git a/src/ConfigEntry/ConfigEntryTrait.php b/src/ConfigEntry/ConfigEntryTrait.php index 3a302dc1..38d9bb86 100644 --- a/src/ConfigEntry/ConfigEntryTrait.php +++ b/src/ConfigEntry/ConfigEntryTrait.php @@ -20,67 +20,33 @@ limitations under the License. */ -use DCarbone\PHPConsulAPI\FakeMap; +use DCarbone\PHPConsulAPI\PHPLib\MetaField; trait ConfigEntryTrait { - public string $Kind = ''; - public string $Name = ''; - public string $Namespace = ''; - public ?FakeMap $Meta = null; - public int $CreateIndex = 0; - public int $ModifyIndex = 0; + use MetaField; - public function getKind(): string - { - return $this->Kind; - } - - public function setKind(string $Kind): ConfigEntry - { - $this->Kind = $Kind; - return $this; - } - - public function getName(): string - { - return $this->Name; - } - - public function setName(string $Name): ConfigEntry - { - $this->Name = $Name; - return $this; - } + public string $Namespace; + public int $CreateIndex; + public int $ModifyIndex; public function getNamespace(): string { return $this->Namespace; } - public function setNamespace(string $Namespace): ConfigEntry + public function setNamespace(string $Namespace): self { $this->Namespace = $Namespace; return $this; } - public function getMeta(): ?FakeMap - { - return $this->Meta; - } - - public function setMeta(mixed $Meta): ProxyConfigEntry - { - $this->Meta = FakeMap::parse($Meta); - return $this; - } - public function getCreateIndex(): int { return $this->CreateIndex; } - public function setCreateIndex(int $CreateIndex): ProxyConfigEntry + public function setCreateIndex(int $CreateIndex): self { $this->CreateIndex = $CreateIndex; return $this; @@ -91,7 +57,7 @@ public function getModifyIndex(): int return $this->ModifyIndex; } - public function setModifyIndex(int $ModifyIndex): ProxyConfigEntry + public function setModifyIndex(int $ModifyIndex): self { $this->ModifyIndex = $ModifyIndex; return $this; diff --git a/src/ConfigEntry/CookieConfig.php b/src/ConfigEntry/CookieConfig.php new file mode 100644 index 00000000..a0ff4caa --- /dev/null +++ b/src/ConfigEntry/CookieConfig.php @@ -0,0 +1,103 @@ +Session = $Session; + $this->TTL = Time::Duration($TTL); + $this->Path = $Path; + } + + public function getSession(): bool + { + return $this->Session; + } + + public function setSession(bool $Session): self + { + $this->Session = $Session; + return $this; + } + + public function getTTL(): Time\Duration + { + return $this->TTL; + } + + public function setTTL(Time\Duration $TTL): self + { + $this->TTL = $TTL; + return $this; + } + + public function getPath(): string + { + return $this->Path; + } + + public function setPath(string $Path): self + { + $this->Path = $Path; + return $this; + } + + public static function jsonUnserialize(\stdClass $decoded): self + { + $n = new self(); + foreach ((array)$decoded as $k => $v) { + if ('TTL' === $k) { + $n->TTL = Time::Duration($v); + } else { + $n->{$k} = $v; + } + } + return $n; + } + + public function jsonSerialize(): \stdClass + { + $out = $this->_startJsonSerialize(); + if ($this->Session) { + $out->Session = $this->Session; + } + $ns = $this->TTL->Nanoseconds(); + if ((0 !== $ns)) { + $out->TTL = $ns; + } + if ('' !== $this->Path) { + $out->Path = $this->Path; + } + return $out; + } +} \ No newline at end of file diff --git a/src/ConfigEntry/DestinationConfig.php b/src/ConfigEntry/DestinationConfig.php new file mode 100644 index 00000000..0c32524e --- /dev/null +++ b/src/ConfigEntry/DestinationConfig.php @@ -0,0 +1,85 @@ + */ + public array $Addresses; + public int $Port; + + /** + * @param array $Addresses + */ + public function __construct(array $Addresses = [], int $Port = 0) + { + $this->setAddresses(...$Addresses); + $this->Port = $Port; + } + + /** + * @return array + */ + public function getAddresses(): array + { + return $this->Addresses; + } + + public function setAddresses(string ...$Addresses): self + { + $this->Addresses = $Addresses; + return $this; + } + + public function getPort(): int + { + return $this->Port; + } + + public function setPort(int $Port): self + { + $this->Port = $Port; + return $this; + } + + public static function jsonUnserialize(\stdClass $decoded): self + { + $n = new self(); + foreach ((array)$decoded as $k => $v) { + $n->{$k} = $v; + } + return $n; + } + + public function jsonSerialize(): \stdClass + { + $out = $this->_startJsonSerialize(); + if ([] !== $this->Addresses) { + $out->Addresses = $this->Addresses; + } + if (0 !== $this->Port) { + $out->Port = $this->Port; + } + return $out; + } +} diff --git a/src/ConfigEntry/EnvoyExtension.php b/src/ConfigEntry/EnvoyExtension.php new file mode 100644 index 00000000..fbfb67c6 --- /dev/null +++ b/src/ConfigEntry/EnvoyExtension.php @@ -0,0 +1,151 @@ + */ + public null|array $Arguments = null; + public string $ConsulVersion; + public string $EnvoyVersion; + + /** + * @param array $Arguments + */ + public function __construct( + string $Name = '', + bool $Required = false, + array $Arguments = [], + string $ConsulVersion = '', + string $EnvoyVersion = '', + ) { + $this->Name = $Name; + $this->Required = $Required; + $this->setArguments($Arguments); + $this->ConsulVersion = $ConsulVersion; + $this->EnvoyVersion = $EnvoyVersion; +} + + public function getName(): string + { + return $this->Name; + } + + public function setName(string $Name): self + { + $this->Name = $Name; + return $this; + } + + public function isRequired(): bool + { + return $this->Required; + } + + public function setRequired(bool $Required): self + { + $this->Required = $Required; + return $this; + } + + /** + * @return null|array + */ + public function getArguments(): null|array + { + return $this->Arguments; + } + + public function setArgument(string $k, mixed $v): self + { + if (null === $this->Arguments) { + $this->Arguments = []; + } + $this->Arguments[$k] = $v; + return $this; + } + + /** + * @param \stdClass|array|null $Arguments + */ + public function setArguments(null|\stdClass|array $Arguments): self + { + if (null === $Arguments) { + $this->Arguments = null; + return $this; + } + $this->Arguments = []; + foreach ($Arguments as $k => $v) { + $this->setArgument($k, $v); + } + return $this; + } + + public function getConsulVersion(): string + { + return $this->ConsulVersion; + } + + public function setConsulVersion(string $ConsulVersion): self + { + $this->ConsulVersion = $ConsulVersion; + return $this; + } + + public function getEnvoyVersion(): string + { + return $this->EnvoyVersion; + } + + public function setEnvoyVersion(string $EnvoyVersion): self + { + $this->EnvoyVersion = $EnvoyVersion; + return $this; + } + + public static function jsonUnserialize(\stdClass $decoded): self + { + $n = new self(); + foreach ((array)$decoded as $k => $v) { + if ('Arguments' === $k) { + $n->setArguments($v); + } else { + $n->{$k} = $v; + } + } + return $n; + } + + public function jsonSerialize(): \stdClass + { + $out = $this->_startJsonSerialize(); + $out->Name = $this->Name; + $out->Required = $this->Required; + $out->Arguments = $this->getArguments(); + $out->ConsulVersion = $this->ConsulVersion; + $out->EnvoyVersion = $this->EnvoyVersion; + return $out; + } +} diff --git a/src/ConfigEntry/ExposeConfig.php b/src/ConfigEntry/ExposeConfig.php index de9d7867..abda7143 100644 --- a/src/ConfigEntry/ExposeConfig.php +++ b/src/ConfigEntry/ExposeConfig.php @@ -20,26 +20,24 @@ limitations under the License. */ -use DCarbone\PHPConsulAPI\AbstractModel; -use DCarbone\PHPConsulAPI\Transcoding; +use DCarbone\PHPConsulAPI\PHPLib\AbstractType; -class ExposeConfig extends AbstractModel +class ExposeConfig extends AbstractType { - protected const FIELDS = [ - self::FIELD_CHECKS => Transcoding::OMITEMPTY_STRING_FIELD, - self::FIELD_PATHS => [ - Transcoding::FIELD_TYPE => Transcoding::ARRAY, - Transcoding::FIELD_CLASS => ExposePath::class, - Transcoding::FIELD_ARRAY_TYPE => Transcoding::OBJECT, - Transcoding::FIELD_OMITEMPTY => true, - ], - ]; + public bool $Checks; + /** @var array<\DCarbone\PHPConsulAPI\ConfigEntry\ExposePath> */ + public array $Paths; - private const FIELD_CHECKS = 'Checks'; - private const FIELD_PATHS = 'Paths'; - - public bool $Checks = false; - public array $Paths = []; + /** + * @param array<\DCarbone\PHPConsulAPI\ConfigEntry\ExposePath> $Paths + */ + public function __construct( + bool $Checks = false, + array $Paths = [], + ) { + $this->Checks = $Checks; + $this->setPaths(...$Paths); +} public function isChecks(): bool { @@ -52,14 +50,44 @@ public function setChecks(bool $Checks): self return $this; } + /** + * @return \DCarbone\PHPConsulAPI\ConfigEntry\ExposePath[] + */ public function getPaths(): array { return $this->Paths; } - public function setPaths(array $Paths): self + public function setPaths(ExposePath ...$Paths): self { $this->Paths = $Paths; return $this; } + + public static function jsonUnserialize(\stdClass $decoded, null|self $n = null): self + { + $n = $n ?? new self(); + foreach ((array)$decoded as $k => $v) { + if ('Paths' === $k) { + foreach ($v as $vv) { + $n->Paths[] = ExposePath::jsonUnserialize($vv); + } + } else { + $n->{$k} = $v; + } + } + return $n; + } + + public function jsonSerialize(): \stdClass + { + $out = $this->_startJsonSerialize(); + if ($this->Checks) { + $out->Checks = true; + } + if ([] !== $this->Paths) { + $out->Paths = $this->Paths; + } + return $out; + } } diff --git a/src/ConfigEntry/ExposePath.php b/src/ConfigEntry/ExposePath.php index 78d0ddb4..258b2f7e 100644 --- a/src/ConfigEntry/ExposePath.php +++ b/src/ConfigEntry/ExposePath.php @@ -20,28 +20,29 @@ limitations under the License. */ -use DCarbone\PHPConsulAPI\AbstractModel; -use DCarbone\PHPConsulAPI\Transcoding; +use DCarbone\PHPConsulAPI\PHPLib\AbstractType; -class ExposePath extends AbstractModel +class ExposePath extends AbstractType { - protected const FIELDS = [ - self::FIELD_LISTENER_PORT => Transcoding::OMITEMPTY_INTEGER_FIELD, - self::FIELD_PATH => Transcoding::OMITEMPTY_STRING_FIELD, - self::FIELD_LOCAL_PORT_PATH => Transcoding::OMITEMPTY_INTEGER_FIELD, - self::FIELD_PROTOCOL => Transcoding::OMITEMPTY_STRING_FIELD, - ]; - - private const FIELD_LISTENER_PORT = 'ListenerPort'; - private const FIELD_PATH = 'Path'; - private const FIELD_LOCAL_PORT_PATH = 'LocalPortPath'; - private const FIELD_PROTOCOL = 'Protocol'; - - public int $ListenerPort = 0; - public string $Path = ''; - public int $LocalPathPort = 0; - public string $Protocol = ''; - public bool $ParsedFromCheck = false; + public int $ListenerPort; + public string $Path; + public int $LocalPathPort; + public string $Protocol; + public bool $ParsedFromCheck; + + public function __construct( + int $ListenerPort = 0, + string $Path = '', + int $LocalPathPort = 0, + string $Protocol = '', + bool $ParsedFromCheck = false + ) { + $this->ListenerPort = $ListenerPort; + $this->Path = $Path; + $this->LocalPathPort = $LocalPathPort; + $this->Protocol = $Protocol; + $this->ParsedFromCheck = $ParsedFromCheck; +} public function getListenerPort(): int { @@ -97,4 +98,40 @@ public function setParsedFromCheck(bool $ParsedFromCheck): self $this->ParsedFromCheck = $ParsedFromCheck; return $this; } + + public static function jsonUnserialize(\stdClass $decoded, null|self $n = null): self + { + $n = $n ?? new self(); + foreach ((array)$decoded as $k => $v) { + if ('listener_port' === $k) { + $n->ListenerPort = $v; + } elseif ('local_path_port' === $k) { + $n->LocalPathPort = $v; + } else { + $n->{$k} = $v; + } + } + return $n; + } + + public function jsonSerialize(): \stdClass + { + $out = $this->_startJsonSerialize(); + if (0 !== $this->ListenerPort) { + $out->ListenerPort = $this->ListenerPort; + } + if ('' !== $this->Path) { + $out->Path = $this->Path; + } + if (0 !== $this->LocalPathPort) { + $out->LocalPathPort = $this->LocalPathPort; + } + if ('' !== $this->Protocol) { + $out->Protocol = $this->Protocol; + } + if ($this->ParsedFromCheck) { + $out->ParsedFromCheck = true; + } + return $out; + } } diff --git a/src/ConfigEntry/GatewayServiceTLSConfig.php b/src/ConfigEntry/GatewayServiceTLSConfig.php new file mode 100644 index 00000000..46e423a4 --- /dev/null +++ b/src/ConfigEntry/GatewayServiceTLSConfig.php @@ -0,0 +1,66 @@ +SDS = $SDS; + } + + public function getSDS(): null|GatewayTLSSDSConfig + { + return $this->SDS; + } + + public function setSDS(null|GatewayTLSSDSConfig $SDS): self + { + $this->SDS = $SDS; + return $this; + } + + public static function jsonUnserialize(\stdClass $decoded): self + { + $n = new self(); + foreach((array)$decoded as $k => $v) { + if ('SDS' === $k) { + $n->SDS = GatewayTLSSDSConfig::jsonUnserialize($v); + } else { + $n->{$k} = $v; + } + } + return $n; + } + + public function jsonSerialize(): \stdClass + { + $out = $this->_startJsonSerialize(); + if (null !== $this->SDS) { + $out->SDS = $this->SDS->jsonSerialize(); + } + return $out; + } +} \ No newline at end of file diff --git a/src/ConfigEntry/GatewayTLSConfig.php b/src/ConfigEntry/GatewayTLSConfig.php new file mode 100644 index 00000000..fdcc3b05 --- /dev/null +++ b/src/ConfigEntry/GatewayTLSConfig.php @@ -0,0 +1,146 @@ + */ + public array $CipherSuites; + + /** + * @param array $CipherSuites + */ + public function __construct( + bool $Enabled = false, + null|GatewayTLSSDSConfig $SDS = null, + string $TLSMinVersion = '', + string $TLSMaxVersion = '', + array $CipherSuites = [] + ) { + $this->Enabled = $Enabled; + $this->SDS = $SDS; + $this->TLSMinVersion = $TLSMinVersion; + $this->TLSMaxVersion = $TLSMaxVersion; + $this->setCipherSuites(...$CipherSuites); + } + + public function isEnabled(): bool + { + return $this->Enabled; + } + + public function setEnabled(bool $Enabled): self + { + $this->Enabled = $Enabled; + return $this; + } + + public function getSDS(): null|GatewayTLSSDSConfig + { + return $this->SDS; + } + + public function setSDS(null|GatewayTLSSDSConfig $SDS): self + { + $this->SDS = $SDS; + return $this; + } + + public function getTLSMinVersion(): string + { + return $this->TLSMinVersion; + } + + public function setTLSMinVersion(string $TLSMinVersion): self + { + $this->TLSMinVersion = $TLSMinVersion; + return $this; + } + + public function getTLSMaxVersion(): string + { + return $this->TLSMaxVersion; + } + + public function setTLSMaxVersion(string $TLSMaxVersion): self + { + $this->TLSMaxVersion = $TLSMaxVersion; + return $this; + } + + /** + * @return array + */ + public function getCipherSuites(): array + { + return $this->CipherSuites; + } + + public function setCipherSuites(string ...$CipherSuites): self + { + $this->CipherSuites = $CipherSuites; + return $this; + } + + public static function jsonUnserialize(\stdClass $decoded): self + { + $n = new self(); + foreach ((array)$decoded as $k => $v) { + if ('tls_min_version' === $k) { + $n->TLSMinVersion = (string)$v; + } elseif ('tls_max_version' === $k) { + $n->TLSMaxVersion = (string)$v; + } elseif ('CipherSuites' === $k || 'cipher_suites' === $k) { + $n->setcipherSuites(...$v); + } elseif ('SDS' === $k) { + $n->SDS = GatewayTLSSDSConfig::jsonUnserialize($v); + } else { + $n->{$k} = $v; + } + } + return $n; + } + + public function jsonSerialize(): \stdClass + { + $out = $this->_startJsonSerialize(); + $out->Enabled = $this->Enabled; + if (null !== $this->SDS) { + $out->SDS = $this->SDS->jsonSerialize(); + } + if ('' !== $this->TLSMinVersion) { + $out->TLSMinVersion = $this->TLSMinVersion; + } + if ('' !== $this->TLSMaxVersion) { + $out->TLSMaxVersion = $this->TLSMaxVersion; + } + if ([] !== $this->CipherSuites) { + $out->CipherSuites = $this->CipherSuites; + } + return $out; + } +} diff --git a/src/ConfigEntry/GatewayTLSSDSConfig.php b/src/ConfigEntry/GatewayTLSSDSConfig.php new file mode 100644 index 00000000..51c6991f --- /dev/null +++ b/src/ConfigEntry/GatewayTLSSDSConfig.php @@ -0,0 +1,86 @@ +ClusterName = $ClusterName; + $this->CertResource = $CertResource; + } + + public function getClusterName(): string + { + return $this->ClusterName; + } + + public function setClusterName(string $ClusterName): self + { + $this->ClusterName = $ClusterName; + return $this; + } + + public function getCertResource(): string + { + return $this->CertResource; + } + + public function setCertResource(string $CertResource): self + { + $this->CertResource = $CertResource; + return $this; + } + + public static function jsonUnserialize(\stdClass $decoded): self + { + $n = new self(); + foreach ((array)$decoded as $k => $v) { + if ('cluster_name' === $k) { + $n->ClusterName = (string)$v; + } elseif ('cert_resource' === $k) { + $n->CertResource = (string)$v; + } else { + $n->{$k} = $v; + } + } + return $n; + } + + public function jsonSerialize(): \stdClass + { + $out = $this->_startJsonSerialize(); + if ('' !== $this->ClusterName) { + $out->ClusterName = $this->ClusterName; + } + if ('' !== $this->CertResource) { + $out->CertResource = $this->CertResource; + } + return $out; + } +} diff --git a/src/ConfigEntry/HTTPHeaderModifiers.php b/src/ConfigEntry/HTTPHeaderModifiers.php new file mode 100644 index 00000000..50243fb4 --- /dev/null +++ b/src/ConfigEntry/HTTPHeaderModifiers.php @@ -0,0 +1,156 @@ + */ + public array $Add = []; + /** @var array */ + public array $Set = []; + /** @var array */ + public array $Remove = []; + + /** + * @param null|array $Add + * @param null|array $Set + * @param null|array $Remove + */ + public function __construct( + null|array $Add = null, + null|array $Set = null, + null|array $Remove = null, + ) { + $this->setAdd($Add); + $this->setSet($Set); + if (null !== $Remove) { + $this->setRemove(...$Remove); + } + } + + /** + * @return array + */ + public function getAdd(): array + { + return $this->Add; + } + + public function setAddKey(string $k, string $v): self + { + $this->Add[$k] = $v; + return $this; + } + + /** + * @param null|\stdClass|array $Add + */ + public function setAdd(null|\stdClass|array $Add): self + { + $this->Add = []; + if (null === $Add) { + return $this; + } + foreach ($Add as $k => $v) { + $this->Add[$k] = $v; + } + return $this; + } + + /** + * @return array + */ + public function getSet(): array + { + return $this->Set; + } + + public function setSetKey(string $k, string $v): self + { + $this->Set[$k] = $v; + return $this; + } + + /** + * @param null|\stdClass|array $Set + */ + public function setSet(null|\stdClass|array $Set): self + { + $this->Set = []; + if (null === $Set) { + return $this; + } + foreach ($Set as $k => $v) { + $this->Set[$k] = $v; + } + return $this; + } + + /** + * @return array + */ + public function getRemove(): array + { + return $this->Remove; + } + + public function setRemove(string ...$Remove): self + { + $this->Remove = $Remove; + return $this; + } + + public static function jsonUnserialize(\stdClass $decoded): self + { + $n = new self(); + foreach ((array)$decoded as $k => $v) { + if ('Set' === $k) { + $n->setSet($v); + } elseif ('Add' === $k) { + $n->setAdd($v); + } elseif ('Remove' === $k) { + if (null !== $v) { + $n->setRemove(...$v); + } + } else { + $n->{$k} = $v; + } + } + return $n; + } + + public function jsonSerialize(): \stdClass + { + $out = $this->_startJsonSerialize(); + if ([] !== $this->Add) { + $out->Add = $this->Add; + } + if ([] !== $this->Set) { + $out->Set = $this->Set; + } + if ([] !== $this->Remove) { + $out->Remove = $this->Remove; + } + return $out; + } +} diff --git a/src/ConfigEntry/HashPolicy.php b/src/ConfigEntry/HashPolicy.php new file mode 100644 index 00000000..575bf597 --- /dev/null +++ b/src/ConfigEntry/HashPolicy.php @@ -0,0 +1,139 @@ +Field = $Field; + $this->FieldValue = $FieldValue; + $this->CookieConfig = $CookieConfig; + $this->SourceIP = $SourceIP; + $this->Terminal = $Terminal; + } + + public function getField(): string + { + return $this->Field; + } + + public function setField(string $Field): self + { + $this->Field = $Field; + return $this; + } + + public function getFieldValue(): string + { + return $this->FieldValue; + } + + public function setFieldValue(string $FieldValue): self + { + $this->FieldValue = $FieldValue; + return $this; + } + + public function getCookieConfig(): null|CookieConfig + { + return $this->CookieConfig; + } + + public function setCookieConfig(null|CookieConfig $CookieConfig): self + { + $this->CookieConfig = $CookieConfig; + return $this; + } + + public function isSourceIP(): bool + { + return $this->SourceIP; + } + + public function setSourceIP(bool $SourceIP): self + { + $this->SourceIP = $SourceIP; + return $this; + } + + public function isTerminal(): bool + { + return $this->Terminal; + } + + public function setTerminal(bool $Terminal): self + { + $this->Terminal = $Terminal; + return $this; + } + + public static function jsonUnserialize(\stdClass $decoded): self + { + $n = new self(); + foreach ((array)$decoded as $k => $v) { + if ('field_value' === $k) { + $n->FieldValue = $v; + } elseif ('CookieConfig' === $k || 'cookie_config' === $k) { + $n->CookieConfig = CookieConfig::jsonUnserialize($v); + } elseif ('source_ip' === $k) { + $n->SourceIP = $v; + } else { + $n->{$k} = $v; + } + } + return $n; + } + + public function jsonSerialize(): \stdClass + { + $out = $this->_startJsonSerialize(); + if ('' !== $this->Field) { + $out->Field = $this->Field; + } + if ('' !== $this->FieldValue) { + $out->FieldValue = $this->FieldValue; + } + if (null !== $this->CookieConfig) { + $out->CookieConfig = $this->CookieConfig; + } + if ($this->SourceIP) { + $out->SourceIP = $this->SourceIP; + } + if ($this->Terminal) { + $out->Terminal = $this->Terminal; + } + return $out; + } +} diff --git a/src/ConfigEntry/IngressGatewayConfigEntry.php b/src/ConfigEntry/IngressGatewayConfigEntry.php new file mode 100644 index 00000000..adc6b8ee --- /dev/null +++ b/src/ConfigEntry/IngressGatewayConfigEntry.php @@ -0,0 +1,182 @@ + */ + public array $Listeners; + public null|IngressServiceConfig $Defaults; + + /** + * @param array<\DCarbone\PHPConsulAPI\ConfigEntry\IngressListener> $Listeners + * @param array $Meta + */ + public function __construct( + string $Kind = '', + string $Name = '', + string $Partition = '', + string $Namespace = '', + null|GatewayTLSConfig $TLS = null, + array $Listeners = [], + array $Meta = [], + null|IngressServiceConfig $Defaults = null, + int $CreateIndex = 0, + int $ModifyIndex = 0, + ) { + $this->Kind = $Kind; + $this->Name = $Name; + $this->Partition = $Partition; + $this->Namespace = $Namespace; + $this->TLS = $TLS ?? new GatewayTLSConfig(); + $this->setListeners(...$Listeners); + $this->setMeta($Meta); + $this->Defaults = $Defaults; + $this->CreateIndex = $CreateIndex; + $this->ModifyIndex = $ModifyIndex; + } + + public function getKind(): string + { + return $this->Kind; + } + + public function setKind(string $Kind): self + { + $this->Kind = $Kind; + return $this; + } + + public function getName(): string + { + return $this->Name; + } + + public function setName(string $Name): self + { + $this->Name = $Name; + return $this; + } + + public function getPartition(): string + { + return $this->Partition; + } + + public function setPartition(string $Partition): self + { + $this->Partition = $Partition; + return $this; + } + + public function getTLS(): GatewayTLSConfig + { + return $this->TLS; + } + + public function setTLS(GatewayTLSConfig $TLS): self + { + $this->TLS = $TLS; + return $this; + } + + /** + * @return array<\DCarbone\PHPConsulAPI\ConfigEntry\IngressListener> + */ + public function getListeners(): array + { + return $this->Listeners; + } + + /** + * @param \DCarbone\PHPConsulAPI\ConfigEntry\IngressListener ...$Listeners + */ + public function setListeners(IngressListener ...$Listeners): self + { + $this->Listeners = $Listeners; + return $this; + } + + public function getDefaults(): null|IngressServiceConfig + { + return $this->Defaults; + } + + public function setDefaults(null|IngressServiceConfig $Defaults): self + { + $this->Defaults = $Defaults; + return $this; + } + + public static function jsonUnserialize(\stdClass $decoded): self + { + $n = new self(); + foreach ((array)$decoded as $k => $v) { + if ('TLS' === $k) { + $n->TLS = GatewayTLSConfig::jsonUnserialize($v); + } elseif ('Listeners' === $k) { + $n->Listeners = []; + foreach ($v as $vv) { + $n->Listeners[] = IngressListener::jsonUnserialize($vv); + } + } elseif ('Defaults' === $k) { + $n->Defaults = null === $v ? null : IngressServiceConfig::jsonUnserialize($v); + } elseif ('Meta' === $k) { + $n->setMeta($v); + } else { + $n->{$k} = $v; + } + } + return $n; + } + + public function jsonSerialize(): \stdClass + { + $out = $this->_startJsonSerialize(); + $out->Kind = $this->Kind; + $out->Name = $this->Name; + if ('' !== $this->Partition) { + $out->Partition = $this->Partition; + } + if ('' !== $this->Namespace) { + $out->Namespace = $this->Namespace; + } + $out->TLS = $this->TLS; + $out->Listeners = $this->Listeners; + if (null !== $this->Meta) { + $out->Meta = $this->Meta; + } + if (null !== $this->Defaults) { + $out->Defaults = $this->Defaults; + } + $out->CreateIndex = $this->CreateIndex; + $out->ModifyIndex = $this->ModifyIndex; + return $out; + } +} diff --git a/src/ConfigEntry/IngressListener.php b/src/ConfigEntry/IngressListener.php new file mode 100644 index 00000000..158262db --- /dev/null +++ b/src/ConfigEntry/IngressListener.php @@ -0,0 +1,125 @@ + */ + public array $Services; + public null|GatewayTLSConfig $TLS; + + /** + * @param array<\DCarbone\PHPConsulAPI\ConfigEntry\IngressService> $Services + */ + public function __construct( + int $Port = 0, + string $Protocol = '', + array $Services = [], + null|GatewayTLSConfig $TLS = null + ) { + $this->Port = $Port; + $this->Protocol = $Protocol; + $this->setServices(...$Services); + $this->TLS = $TLS; + } + + public function getPort(): int + { + return $this->Port; + } + + public function setPort(int $Port): self + { + $this->Port = $Port; + return $this; + } + + public function getProtocol(): string + { + return $this->Protocol; + } + + public function setProtocol(string $Protocol): self + { + $this->Protocol = $Protocol; + return $this; + } + + /** + * @return array<\DCarbone\PHPConsulAPI\ConfigEntry\IngressService> + */ + public function getServices(): array + { + return $this->Services; + } + + public function setServices(IngressService ...$Services): self + { + $this->Services = $Services; + return $this; + } + + public function getTLS(): null|GatewayTLSConfig + { + return $this->TLS; + } + + public function setTLS(null|GatewayTLSConfig $TLS): self + { + $this->TLS = $TLS; + return $this; + } + + public static function jsonUnserialize(\stdClass $decoded): self + { + $n = new self(); + foreach ((array)$decoded as $k => $v) { + if ('Services' === $k) { + $n->Services = []; + foreach ($v as $vv) { + $n->Services[] = IngressService::jsonUnserialize($vv); + } + } elseif ('TLS' === $k) { + $n->TLS = null === $v ? null : GatewayTLSConfig::jsonUnserialize($v); + } else { + $n->{$k} = $v; + } + } + return $n; + } + + public function jsonSerialize(): \stdClass + { + $out = $this->_startJsonSerialize(); + $out->Port = $this->Port; + $out->Protocol = $this->Protocol; + $out->Services = $this->Services; + if (null !== $this->TLS) { + $out->TLS = $this->TLS; + } + return $out; + } +} diff --git a/src/ConfigEntry/IngressService.php b/src/ConfigEntry/IngressService.php new file mode 100644 index 00000000..51454e98 --- /dev/null +++ b/src/ConfigEntry/IngressService.php @@ -0,0 +1,247 @@ + */ + public array $Hosts; + public string $Namespace; + public string $Partition; + public null|GatewayServiceTLSConfig $TLS; + public null|HTTPHeaderModifiers $RequestHeaders; + public null|HTTPHeaderModifiers $ResponseHeaders; + + public null|int $MaxConnections; + public null|int $MaxPendingRequests; + public null|int $MaxConcurrentRequests; + public null|PassiveHealthCheck $PassiveHealthCheck; + + /** + * @param array $Hosts + */ + public function __construct( + string $Name = '', + array $Hosts = [], + string $Namespace = '', + string $Partition = '', + null|GatewayServiceTLSConfig $TLS = null, + null|HTTPHeaderModifiers $RequestHeaders = null, + null|HTTPHeaderModifiers $ResponseHeaders = null, + null|int $MaxConnections = null, + null|int $MaxPendingRequests = null, + null|int $MaxConcurrentRequests = null, + null|PassiveHealthCheck $PassiveHealthCheck = null + ) { + $this->Name = $Name; + $this->setHosts(...$Hosts); + $this->Namespace = $Namespace; + $this->Partition = $Partition; + $this->TLS = $TLS; + $this->RequestHeaders = $RequestHeaders; + $this->ResponseHeaders = $ResponseHeaders; + $this->MaxConnections = $MaxConnections; + $this->MaxPendingRequests = $MaxPendingRequests; + $this->MaxConcurrentRequests = $MaxConcurrentRequests; + $this->PassiveHealthCheck = $PassiveHealthCheck; + } + + public function getName(): string + { + return $this->Name; + } + + public function setName(string $Name): self + { + $this->Name = $Name; + return $this; + } + + /** + * @return array + */ + public function getHosts(): array + { + return $this->Hosts; + } + + public function setHosts(string ...$Hosts): self + { + $this->Hosts = $Hosts; + return $this; + } + + public function getNamespace(): string + { + return $this->Namespace; + } + + public function setNamespace(string $Namespace): self + { + $this->Namespace = $Namespace; + return $this; + } + + public function getPartition(): string + { + return $this->Partition; + } + + public function setPartition(string $Partition): self + { + $this->Partition = $Partition; + return $this; + } + + public function getTLS(): null|GatewayServiceTLSConfig + { + return $this->TLS; + } + + public function setTLS(null|GatewayServiceTLSConfig $TLS): self + { + $this->TLS = $TLS; + return $this; + } + + public function getRequestHeaders(): null|HTTPHeaderModifiers + { + return $this->RequestHeaders; + } + + public function setRequestHeaders(null|HTTPHeaderModifiers $RequestHeaders): self + { + $this->RequestHeaders = $RequestHeaders; + return $this; + } + + public function getResponseHeaders(): null|HTTPHeaderModifiers + { + return $this->ResponseHeaders; + } + + public function setResponseHeaders(null|HTTPHeaderModifiers $ResponseHeaders): self + { + $this->ResponseHeaders = $ResponseHeaders; + return $this; + } + + public function getMaxConnections(): null|int + { + return $this->MaxConnections; + } + + public function setMaxConnections(null|int $MaxConnections): self + { + $this->MaxConnections = $MaxConnections; + return $this; + } + + public function getMaxPendingRequests(): null|int + { + return $this->MaxPendingRequests; + } + + public function setMaxPendingRequests(null|int $MaxPendingRequests): self + { + $this->MaxPendingRequests = $MaxPendingRequests; + return $this; + } + + public function getMaxConcurrentRequests(): null|int + { + return $this->MaxConcurrentRequests; + } + + public function setMaxConcurrentRequests(null|int $MaxConcurrentRequests): self + { + $this->MaxConcurrentRequests = $MaxConcurrentRequests; + return $this; + } + + public function getPassiveHealthCheck(): null|PassiveHealthCheck + { + return $this->PassiveHealthCheck; + } + + public function setPassiveHealthCheck(null|PassiveHealthCheck $PassiveHealthCheck): self + { + $this->PassiveHealthCheck = $PassiveHealthCheck; + return $this; + } + + public static function jsonUnserialize(\stdClass $decoded): self + { + $n = new self(); + foreach((array)$decoded as $k => $v) { + if ('RequestHeaders' === $k || 'request_headers' === $k) { + $n->RequestHeaders = HTTPHeaderModifiers::jsonUnserialize($v); + } elseif ('ResponseHeaders' === $k || 'response_headers' === $k) { + $n->ResponseHeaders = HTTPHeaderModifiers::jsonUnserialize($v); + } elseif ('TLS' === $k) { + $n->TLS = GatewayServiceTLSConfig::jsonUnserialize($v); + } elseif ('PassiveHealthCheck' === $k || 'passive_health_check' === $k) { + $n->PassiveHealthCheck = PassiveHealthCheck::jsonUnserialize($v); + } else { + $n->{$k} = $v; + } + } + return $n; + } + + public function jsonSerialize(): \stdClass + { + $out = $this->_startJsonSerialize(); + $out->Name = $this->Name; + $out->Hosts = $this->Hosts; + if ('' !== $this->Namespace) { + $out->Namespace = $this->Namespace; + } + if ('' !== $this->Partition) { + $out->Partition = $this->Partition; + } + if (null !== $this->TLS) { + $out->TLS = $this->TLS; + } + if (null !== $this->RequestHeaders) { + $out->RequestHeaders = $this->RequestHeaders; + } + if (null !== $this->ResponseHeaders) { + $out->ResponseHeaders = $this->ResponseHeaders; + } + if (null !== $this->MaxConnections) { + $out->MaxConnections = $this->MaxConnections; + } + if (null !== $this->MaxPendingRequests) { + $out->MaxPendingRequests = $this->MaxPendingRequests; + } + if (null !== $this->MaxConcurrentRequests) { + $out->MaxConcurrentRequests = $this->MaxConcurrentRequests; + } + if (null !== $this->PassiveHealthCheck) { + $out->PassiveHealthCheck = $this->PassiveHealthCheck; + } + return $out; + } +} diff --git a/src/ConfigEntry/IngressServiceConfig.php b/src/ConfigEntry/IngressServiceConfig.php new file mode 100644 index 00000000..b3c1dcde --- /dev/null +++ b/src/ConfigEntry/IngressServiceConfig.php @@ -0,0 +1,112 @@ +MaxConnections = $MaxConnections; + $this->MaxPendingRequests = $MaxPendingRequests; + $this->MaxConcurrentRequests = $MaxConcurrentRequests; + $this->PassiveHealthCheck = $PassiveHealthCheck; + } + + public function getMaxConnections(): null|int + { + return $this->MaxConnections; + } + + public function setMaxConnections(null|int $MaxConnections): self + { + $this->MaxConnections = $MaxConnections; + return $this; + } + + public function getMaxPendingRequests(): null|int + { + return $this->MaxPendingRequests; + } + + public function setMaxPendingRequests(null|int $MaxPendingRequests): self + { + $this->MaxPendingRequests = $MaxPendingRequests; + return $this; + } + + public function getMaxConcurrentRequests(): null|int + { + return $this->MaxConcurrentRequests; + } + + public function setMaxConcurrentRequests(null|int $MaxConcurrentRequests): self + { + $this->MaxConcurrentRequests = $MaxConcurrentRequests; + return $this; + } + + public function getPassiveHealthCheck(): null|PassiveHealthCheck + { + return $this->PassiveHealthCheck; + } + + public function setPassiveHealthCheck(null|PassiveHealthCheck $PassiveHealthCheck): self + { + $this->PassiveHealthCheck = $PassiveHealthCheck; + return $this; + } + + public static function jsonUnserialize(\stdClass $decoded): self + { + $n = new self(); + foreach ((array)$decoded as $k => $v) { + if ('PassiveHealthCheck' === $k || 'passive_health_check' === $k) { + $n->PassiveHealthCheck = null === $v ? null : PassiveHealthCheck::jsonUnserialize($v); + } else { + $n->{$k} = $v; + } + } + return $n; + } + + public function jsonSerialize(): \stdClass + { + $out = $this->_startJsonSerialize(); + $out->MaxConnections = $this->MaxConnections; + $out->MaxPendingRequests = $this->MaxPendingRequests; + $out->MaxConcurrentRequests = $this->MaxConcurrentRequests; + if (null !== $this->PassiveHealthCheck) { + $out->PassiveHealthCheck = $this->PassiveHealthCheck->jsonSerialize(); + } + return $out; + } +} diff --git a/src/ConfigEntry/InstanceLevelRateLimits.php b/src/ConfigEntry/InstanceLevelRateLimits.php new file mode 100644 index 00000000..40a5b20d --- /dev/null +++ b/src/ConfigEntry/InstanceLevelRateLimits.php @@ -0,0 +1,109 @@ + */ + public array $Routes; + + /** + * @param array<\DCarbone\PHPConsulAPI\ConfigEntry\InstanceLevelRouteRateLimits> $Routes + */ + public function __construct( + int $RequestsPerSecond = 0, + int $RequestsMaxBurst = 0, + array $Routes = [] + ) { + $this->RequestsPerSecond = $RequestsPerSecond; + $this->RequestsMaxBurst = $RequestsMaxBurst; + $this->SetRoutes(...$Routes); + } + + public function getRequestsPerSecond(): int + { + return $this->RequestsPerSecond; + } + + public function setRequestsPerSecond(int $RequestsPerSecond): self + { + $this->RequestsPerSecond = $RequestsPerSecond; + return $this; + } + + public function getRequestsMaxBurst(): int + { + return $this->RequestsMaxBurst; + } + + public function setRequestsMaxBurst(int $RequestsMaxBurst): self + { + $this->RequestsMaxBurst = $RequestsMaxBurst; + return $this; + } + + /** + * @return array<\DCarbone\PHPConsulAPI\ConfigEntry\InstanceLevelRouteRateLimits> + */ + public function getRoutes(): array + { + return $this->Routes; + } + + public function setRoutes(InstanceLevelRouteRateLimits ...$Routes): self + { + $this->Routes = $Routes; + return $this; + } + + public static function jsonUnserialize(\stdClass $decoded): self + { + $n = new self(); + foreach ((array)$decoded as $k => $v) { + if ('requests_per_second' === $k) { + $n->RequestsPerSecond = $v; + } elseif ('requests_max_burst' === $k) { + $n->RequestsMaxBurst = $v; + } elseif ('Routes' === $k) { + $n->Routes = []; + foreach ($v as $rv) { + $n->Routes[] = InstanceLevelRouteRateLimits::jsonUnserialize($rv); + } + } else { + $n->{$k} = $v; + } + } + return $n; + } + + public function jsonSerialize(): \stdClass + { + $out = $this->_startJsonSerialize(); + $out->RequestsPerSecond = $this->RequestsPerSecond; + $out->RequestsMaxBurst = $this->RequestsMaxBurst; + $out->Routes = $this->Routes; + return $out; + } +} diff --git a/src/ConfigEntry/InstanceLevelRouteRateLimits.php b/src/ConfigEntry/InstanceLevelRouteRateLimits.php new file mode 100644 index 00000000..831e8eee --- /dev/null +++ b/src/ConfigEntry/InstanceLevelRouteRateLimits.php @@ -0,0 +1,133 @@ +PathExact = $PathExact; + $this->PathPrefix = $PathPrefix; + $this->PathRegex = $PathRegex; + $this->RequestsPerSecond = $RequestsPerSecond; + $this->RequestsMaxBurst = $RequestsMaxBurst; + } + + public function getPathExact(): string + { + return $this->PathExact; + } + + public function setPathExact(string $PathExact): self + { + $this->PathExact = $PathExact; + return $this; + } + + public function getPathPrefix(): string + { + return $this->PathPrefix; + } + + public function setPathPrefix(string $PathPrefix): self + { + $this->PathPrefix = $PathPrefix; + return $this; + } + + public function getPathRegex(): string + { + return $this->PathRegex; + } + + public function setPathRegex(string $PathRegex): self + { + $this->PathRegex = $PathRegex; + return $this; + } + + public function getRequestsPerSecond(): int + { + return $this->RequestsPerSecond; + } + + public function setRequestsPerSecond(int $RequestsPerSecond): self + { + $this->RequestsPerSecond = $RequestsPerSecond; + return $this; + } + + public function getRequestsMaxBurst(): int + { + return $this->RequestsMaxBurst; + } + + public function setRequestsMaxBurst(int $RequestsMaxBurst): self + { + $this->RequestsMaxBurst = $RequestsMaxBurst; + return $this; + } + + public static function jsonUnserialize(\stdClass $decoded): self + { + $n = new self(); + foreach ((array)$decoded as $k => $v) { + if ('path_exact' === $k) { + $n->PathExact = $v; + } elseif ('path_prefix' === $k) { + $n->PathPrefix = $v; + } elseif ('path_regex' === $k) { + $n->PathRegex = $v; + } elseif ('requests_per_second' === $k) { + $n->RequestsPerSecond = (int)$v; + } elseif ('requests_max_burst' === $k) { + $n->RequestsMaxBurst = (int)$v; + } else { + $n->{$k} = $v; + } + } + return $n; + } + + public function jsonSerialize(): \stdClass + { + $out = $this->_startJsonSerialize(); + $out->PathExact = $this->PathExact; + $out->PathPrefix = $this->PathPrefix; + $out->PathRegex = $this->PathRegex; + $out->RequestsPerSecond = $this->RequestsPerSecond; + $out->RequestsMaxBurst = $this->RequestsMaxBurst; + return $out; + } +} diff --git a/src/WriteMetaContainer.php b/src/ConfigEntry/IntentionAction.php similarity index 77% rename from src/WriteMetaContainer.php rename to src/ConfigEntry/IntentionAction.php index 76c5d857..e97f19d8 100644 --- a/src/WriteMetaContainer.php +++ b/src/ConfigEntry/IntentionAction.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace DCarbone\PHPConsulAPI; +namespace DCarbone\PHPConsulAPI\ConfigEntry; /* Copyright 2016-2025 Daniel Carbone (daniel.p.carbone@gmail.com) @@ -20,12 +20,11 @@ limitations under the License. */ -trait WriteMetaContainer +enum IntentionAction: string { - public ?WriteMeta $WriteMeta = null; + case Allow = 'allow'; + case Deny = 'deny'; - public function getWriteMeta(): ?WriteMeta - { - return $this->WriteMeta; - } -} + // Default case for when value is not set. + case UNDEFINED = ''; +} \ No newline at end of file diff --git a/src/ConfigEntry/IntentionHTTPHeaderPermission.php b/src/ConfigEntry/IntentionHTTPHeaderPermission.php new file mode 100644 index 00000000..404f9f63 --- /dev/null +++ b/src/ConfigEntry/IntentionHTTPHeaderPermission.php @@ -0,0 +1,157 @@ +Name = $Name; + $this->Present = $Present; + $this->Exact = $Exact; + $this->Prefix = $Prefix; + $this->Suffix = $Suffix; + $this->Regex = $Regex; + $this->Invert = $Invert; + } + + public function getName(): string + { + return $this->Name; + } + + public function setName(string $Name): self + { + $this->Name = $Name; + return $this; + } + + public function isPresent(): bool + { + return $this->Present; + } + + public function setPresent(bool $Present): self + { + $this->Present = $Present; + return $this; + } + + public function getExact(): string + { + return $this->Exact; + } + + public function setExact(string $Exact): self + { + $this->Exact = $Exact; + return $this; + } + + public function getPrefix(): string + { + return $this->Prefix; + } + + public function setPrefix(string $Prefix): self + { + $this->Prefix = $Prefix; + return $this; + } + + public function getSuffix(): string + { + return $this->Suffix; + } + + public function setSuffix(string $Suffix): self + { + $this->Suffix = $Suffix; + return $this; + } + + public function getRegex(): string + { + return $this->Regex; + } + + public function setRegex(string $Regex): self + { + $this->Regex = $Regex; + return $this; + } + + public function isInvert(): bool + { + return $this->Invert; + } + + public function setInvert(bool $Invert): self + { + $this->Invert = $Invert; + return $this; + } + + public function jsonSerialize(): \stdClass + { + $out = $this->_startJsonSerialize(); + $out->Name = $this->Name; + if ($this->Present) { + $out->Present = $this->Present; + } + if ('' !== $this->Exact) { + $out->Exact = $this->Exact; + } + if ('' !== $this->Prefix) { + $out->Prefix = $this->Prefix; + } + if ('' !== $this->Suffix) { + $out->Suffix = $this->Suffix; + } + if ('' !== $this->Regex) { + $out->Regex = $this->Regex; + } + if ($this->Invert) { + $out->Invert = $this->Invert; + } + return $out; + } +} diff --git a/src/ConfigEntry/IntentionHTTPPermission.php b/src/ConfigEntry/IntentionHTTPPermission.php new file mode 100644 index 00000000..b83ca3ff --- /dev/null +++ b/src/ConfigEntry/IntentionHTTPPermission.php @@ -0,0 +1,156 @@ + */ + public array $Header; + /** @var array */ + public array $Methods; + + /** + * @param array<\DCarbone\PHPConsulAPI\ConfigEntry\IntentionHTTPHeaderPermission> $Header + * @param array $Methods + */ + public function __construct( + string $PathExact = '', + string $PathPrefix = '', + string $PathRegex = '', + array $Header = [], + array $Methods = [] + ) { + $this->PathExact = $PathExact; + $this->PathPrefix = $PathPrefix; + $this->PathRegex = $PathRegex; + $this->setHeader(...$Header); + $this->setMethods(...$Methods); + } + + public function getPathExact(): string + { + return $this->PathExact; + } + + public function setPathExact(string $PathExact): self + { + $this->PathExact = $PathExact; + return $this; + } + + public function getPathPrefix(): string + { + return $this->PathPrefix; + } + + public function setPathPrefix(string $PathPrefix): self + { + $this->PathPrefix = $PathPrefix; + return $this; + } + + public function getPathRegex(): string + { + return $this->PathRegex; + } + + public function setPathRegex(string $PathRegex): self + { + $this->PathRegex = $PathRegex; + return $this; + } + + /** + * @return array<\DCarbone\PHPConsulAPI\ConfigEntry\IntentionHTTPHeaderPermission> + */ + public function getHeader(): array + { + return $this->Header; + } + + public function setHeader(IntentionHTTPHeaderPermission ...$Header): self + { + $this->Header = $Header; + return $this; + } + + /** + * @return array + */ + public function getMethods(): array + { + return $this->Methods; + } + + public function setMethods(string ...$Methods): self + { + $this->Methods = $Methods; + return $this; + } + + public static function jsonUnserialize(\stdClass $decoded): self + { + $n = new self(); + foreach ((array)$decoded as $k => $v) { + if ('path_exact' === $k) { + $n->PathExact = $v; + } elseif ('path_prefix' === $k) { + $n->PathPrefix = $v; + } elseif ('path_regex' === $k) { + $n->PathRegex = $v; + } elseif ('Header' === $k) { + $n->Header = []; + foreach ($v as $vv) { + $n->Header[] = IntentionHTTPHeaderPermission::jsonUnserialize($vv); + } + } else { + $n->{$k} = $v; + } + } + return $n; + } + + public function jsonSerialize(): \stdClass + { + $out = $this->_startJsonSerialize(); + if ('' !== $this->PathExact) { + $out->PathExact = $this->PathExact; + } + if ('' !== $this->PathPrefix) { + $out->PathPrefix = $this->PathPrefix; + } + if ('' !== $this->PathRegex) { + $out->PathRegex = $this->PathRegex; + } + if ([] === $this->Header) { + $out->Header = $this->Header; + } + if ([] !== $this->Methods) { + $out->Methods = $this->Methods; + } + return $out; + } +} diff --git a/src/ConfigEntry/IntentionJWTClaimVerification.php b/src/ConfigEntry/IntentionJWTClaimVerification.php new file mode 100644 index 00000000..307d7a4d --- /dev/null +++ b/src/ConfigEntry/IntentionJWTClaimVerification.php @@ -0,0 +1,79 @@ + */ + public array $Path; + public string $Value; + + /** + * @param array $Path + */ + public function __construct(array $Path = [], string $Value = '') + { + $this->setPath(...$Path); + $this->Value = $Value; + } + + /** + * @return array + */ + public function getPath(): array + { + return $this->Path; + } + + public function setPath(string ...$Path): self + { + $this->Path = $Path; + return $this; + } + + public function getValue(): string + { + return $this->Value; + } + + public function setValue(string $Value): self + { + $this->Value = $Value; + return $this; + } + + public function jsonSerialize(): \stdClass + { + $out = $this->_startJsonSerialize(); + if ([] !== $this->Path) { + $out->Path = $this->Path; + } + if ('' !== $this->Value) { + $out->Value = $this->Value; + } + return $out; + } +} diff --git a/src/ConfigEntry/IntentionJWTRequirement.php b/src/ConfigEntry/IntentionJWTRequirement.php new file mode 100644 index 00000000..328ce644 --- /dev/null +++ b/src/ConfigEntry/IntentionJWTRequirement.php @@ -0,0 +1,92 @@ + */ + public array $VerifyClaims; + + /** + * @param array<\DCarbone\PHPConsulAPI\ConfigEntry\IntentionJWTClaimVerification> $VerifyClaims + */ + public function __construct(string $Name = '', array $VerifyClaims = []) + { + $this->Name = $Name; + $this->setVerifyClaims(...$VerifyClaims); + } + + public function getName(): string + { + return $this->Name; + } + + public function setName(string $Name): self + { + $this->Name = $Name; + return $this; + } + + /** + * @return array<\DCarbone\PHPConsulAPI\ConfigEntry\IntentionJWTClaimVerification> + */ + public function getVerifyClaims(): array + { + return $this->VerifyClaims; + } + + public function setVerifyClaims(IntentionJWTClaimVerification ...$VerifyClaims): self + { + $this->VerifyClaims = $VerifyClaims; + return $this; + } + + public static function jsonUnserialize(\stdClass $decoded): self + { + $n = new self(); + foreach ((array)$decoded as $k => $v) { + if ('VerifyClaims' === $k || 'verify_claims' === $k) { + $n->VerifyClaims = []; + foreach ($v as $vv) { + $n->VerifyClaims[] = IntentionJWTClaimVerification::jsonUnserialize($vv); + } + } else { + $n->{$k} = $v; + } + } + return $n; + } + + public function jsonSerialize(): \stdClass + { + $out = $this->_startJsonSerialize(); + if ('' !== $this->Name) { + $out->Name = $this->Name; + } + if ([] !== $this->VerifyClaims) { + $out->VerifyClaims = $this->VerifyClaims; + } + return $out; + } +} diff --git a/src/ConfigEntry/IntentionMatchType.php b/src/ConfigEntry/IntentionMatchType.php new file mode 100644 index 00000000..704b76d1 --- /dev/null +++ b/src/ConfigEntry/IntentionMatchType.php @@ -0,0 +1,30 @@ +Action = $Action instanceof IntentionAction ? $Action : IntentionAction::from($Action); + $this->HTTP = $HTTP; + $this->JWT = $JWT; + } + + public function getAction(): IntentionAction + { + return $this->Action; + } + + public function setAction(IntentionAction $Action): self + { + $this->Action = $Action; + return $this; + } + + public function getHTTP(): null|IntentionHTTPPermission + { + return $this->HTTP; + } + + public function setHTTP(null|IntentionHTTPPermission $HTTP): self + { + $this->HTTP = $HTTP; + return $this; + } + + public function getJWT(): null|IntentionJWTRequirement + { + return $this->JWT; + } + + public function setJWT(null|IntentionJWTRequirement $JWT): self + { + $this->JWT = $JWT; + return $this; + } + + public static function jsonUnserialize(\stdClass $decoded): self + { + $n = new self(); + foreach ((array)$decoded as $k => $v) { + if ($k === 'Action') { + $n->{$k} = IntentionAction::from($v); + } elseif ($k === 'HTTP') { + $n->{$k} = null === $v ? null : IntentionHTTPPermission::jsonUnserialize($v); + } elseif ($k === 'JWT') { + $n->{$k} = null === $v ? null : IntentionJWTRequirement::jsonUnserialize($v); + } else { + $n->{$k} = $v; + } + } + return $n; + } + + public function jsonSerialize(): \stdClass + { + $out = $this->_startJsonSerialize(); + $out->Action = $this->Action->value; + if (null !== $this->HTTP) { + $out->HTTP = $this->HTTP; + } + if (null !== $this->JWT) { + $out->JWT = $this->JWT; + } + return $out; + } +} diff --git a/src/HasStringTags.php b/src/ConfigEntry/IntentionSourceType.php similarity index 78% rename from src/HasStringTags.php rename to src/ConfigEntry/IntentionSourceType.php index 9546a477..69dca2a1 100644 --- a/src/HasStringTags.php +++ b/src/ConfigEntry/IntentionSourceType.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace DCarbone\PHPConsulAPI; +namespace DCarbone\PHPConsulAPI\ConfigEntry; /* Copyright 2016-2025 Daniel Carbone (daniel.p.carbone@gmail.com) @@ -20,12 +20,10 @@ limitations under the License. */ -trait HasStringTags +enum IntentionSourceType: string { - public array $Tags = []; + case Consul = 'consul'; - public function getTags(): array - { - return $this->Tags; - } -} + // Default case for when value is not set. + case UNDEFINED = ''; +} \ No newline at end of file diff --git a/src/ConfigEntry/LeastRequestConfig.php b/src/ConfigEntry/LeastRequestConfig.php new file mode 100644 index 00000000..a606e854 --- /dev/null +++ b/src/ConfigEntry/LeastRequestConfig.php @@ -0,0 +1,66 @@ +ChoiceCount = $ChoiceCount; + } + + public function getChoiceCount(): int + { + return $this->ChoiceCount; + } + + public function setChoiceCount(int $ChoiceCount): self + { + $this->ChoiceCount = $ChoiceCount; + return $this; + } + + public static function jsonUnserialize(\stdClass $decoded): self + { + $n = new self(); + foreach ((array)$decoded as $k => $v) { + if ('choice_count' === $k) { + $n->ChoiceCount = $v; + } else { + $n->{$k}= $v; + } + } + return $n; + } + + public function jsonSerialize(): \stdClass + { + $out = $this->_startJsonSerialize(); + if (0 !== $this->ChoiceCount) { + $out->ChoiceCount = $this->ChoiceCount; + } + return $out; + } +} \ No newline at end of file diff --git a/src/ConfigEntry/LinkedService.php b/src/ConfigEntry/LinkedService.php new file mode 100644 index 00000000..a994e256 --- /dev/null +++ b/src/ConfigEntry/LinkedService.php @@ -0,0 +1,156 @@ +Namespace = $Namespace; + $this->Name = $Name; + $this->CAFile = $CAFile; + $this->CertFile = $CertFile; + $this->KeyFile = $KeyFile; + $this->SNI = $SNI; + } + + public function getNamespace(): string + { + return $this->Namespace; + } + + public function setNamespace(string $Namespace): self + { + $this->Namespace = $Namespace; + return $this; + } + + public function getName(): string + { + return $this->Name; + } + + public function setName(string $Name): self + { + $this->Name = $Name; + return $this; + } + + public function getCAFile(): string + { + return $this->CAFile; + } + + public function setCAFile(string $CAFile): self + { + $this->CAFile = $CAFile; + return $this; + } + + public function getCertFile(): string + { + return $this->CertFile; + } + + public function setCertFile(string $CertFile): self + { + $this->CertFile = $CertFile; + return $this; + } + + public function getKeyFile(): string + { + return $this->KeyFile; + } + + public function setKeyFile(string $KeyFile): self + { + $this->KeyFile = $KeyFile; + return $this; + } + + public function getSNI(): string + { + return $this->SNI; + } + + public function setSNI(string $SNI): self + { + $this->SNI = $SNI; + return $this; + } + + public static function jsonUnserialize(\stdClass $decoded): self + { + $n = new self(); + foreach ((array)$decoded as $k => $v) { + if ('ca_file' === $k) { + $n->CAFile = $v; + } elseif ('cert_file' === $k) { + $n->CertFile = $v; + } elseif ('key_file' === $k) { + $n->KeyFile = $v; + } else { + $n->{$k} = $v; + } + } + return $n; + } + + public function jsonSerialize(): \stdClass + { + $out = $this->_startJsonSerialize(); + if ('' !== $this->Namespace) { + $out->Namespace = $this->Namespace; + } + if ('' !== $this->Name) { + $out->Name = $this->Name; + } + if ('' !== $this->CAFile) { + $out->CAFile = $this->CAFile; + } + if ('' !== $this->CertFile) { + $out->CertFile = $this->CertFile; + } + if ('' !== $this->KeyFile) { + $out->KeyFile = $this->KeyFile; + } + if ('' !== $this->SNI) { + $out->SNI = $this->SNI; + } + return $out; + } +} diff --git a/src/ConfigEntry/LoadBalancer.php b/src/ConfigEntry/LoadBalancer.php new file mode 100644 index 00000000..0e53ee8c --- /dev/null +++ b/src/ConfigEntry/LoadBalancer.php @@ -0,0 +1,138 @@ + */ + public null|array $HashPolicies = null; + + /** + * @param array<\DCarbone\PHPConsulAPI\ConfigEntry\HashPolicy> $HashPolicies + */ + public function __construct( + string $Policy = '', + null|RingHashConfig $RingHashConfig = null, + null|LeastRequestConfig $LeastRequestConfig = null, + null|array $HashPolicies = null + ) { + $this->Policy = $Policy; + $this->RingHashConfig = $RingHashConfig; + $this->LeastRequestConfig = $LeastRequestConfig; + if (null !== $HashPolicies) { + $this->setHashPolicies(...$HashPolicies); + } + } + + public function getPolicy(): string + { + return $this->Policy; + } + + public function setPolicy(string $Policy): self + { + $this->Policy = $Policy; + return $this; + } + + public function getRingHashConfig(): null|RingHashConfig + { + return $this->RingHashConfig; + } + + public function setRingHashConfig(null|RingHashConfig $RingHashConfig): self + { + $this->RingHashConfig = $RingHashConfig; + return $this; + } + + public function getLeastRequestConfig(): null|LeastRequestConfig + { + return $this->LeastRequestConfig; + } + + public function setLeastRequestConfig(null|LeastRequestConfig $LeastRequestConfig): self + { + $this->LeastRequestConfig = $LeastRequestConfig; + return $this; + } + + /** + * @return array<\DCarbone\PHPConsulAPI\ConfigEntry\HashPolicy> + */ + public function getHashPolicies(): array + { + return $this->HashPolicies; + } + + /** + * @param \DCarbone\PHPConsulAPI\ConfigEntry\HashPolicy ...$HashPolicies + */ + public function setHashPolicies(HashPolicy ...$HashPolicies): self + { + $this->HashPolicies = $HashPolicies; + return $this; + } + + public static function jsonUnserialize(\stdClass $decoded): self + { + $n = new self(); + foreach ((array)$decoded as $k => $v) { + if ('RingHashConfig' === $k || 'ring_hash_config' === $k) { + $n->RingHashConfig = RingHashConfig::jsonUnserialize($v); + } elseif ('LeastRequestConfig' === $k || 'least_request_config' === $k) { + $n->LeastRequestConfig = LeastRequestConfig::jsonUnserialize($v); + } elseif ('HashPolicies' === $k || 'hash_policies' === $k) { + if (null !== $v) { + foreach ($v as $hp) { + $n->HashPolicies[] = HashPolicy::jsonUnserialize($hp); + } + } + } else { + $n->{$k} = $v; + } + } + return $n; + } + + public function jsonSerialize(): \stdClass + { + $out = $this->_startJsonSerialize(); + if ('' !== $this->Policy) { + $out->Policy = $this->Policy; + } + if (null !== $this->RingHashConfig) { + $out->RingHashConfig = $this->RingHashConfig; + } + if (null !== $this->LeastRequestConfig) { + $out->LeastRequestConfig = $this->LeastRequestConfig; + } + if (null !== $this->HashPolicies) { + $out->HashPolicies = $this->HashPolicies; + } + return $out; + } +} diff --git a/src/ErrorContainer.php b/src/ConfigEntry/LogSinkType.php similarity index 79% rename from src/ErrorContainer.php rename to src/ConfigEntry/LogSinkType.php index 0eb20750..099d032a 100644 --- a/src/ErrorContainer.php +++ b/src/ConfigEntry/LogSinkType.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace DCarbone\PHPConsulAPI; +namespace DCarbone\PHPConsulAPI\ConfigEntry; /* Copyright 2016-2025 Daniel Carbone (daniel.p.carbone@gmail.com) @@ -20,12 +20,10 @@ limitations under the License. */ -trait ErrorContainer +enum LogSinkType: string { - public ?Error $Err = null; - - public function getErr(): ?Error - { - return $this->Err; - } -} + case Default = ''; + case File = 'file'; + case StdErr = 'stderr'; + case StdOut = 'stdout'; +} \ No newline at end of file diff --git a/src/ConfigEntry/MeshConfigEntry.php b/src/ConfigEntry/MeshConfigEntry.php index 27414433..b436bae1 100644 --- a/src/ConfigEntry/MeshConfigEntry.php +++ b/src/ConfigEntry/MeshConfigEntry.php @@ -20,34 +20,160 @@ limitations under the License. */ -use DCarbone\PHPConsulAPI\AbstractModel; -use DCarbone\PHPConsulAPI\Transcoding; +use DCarbone\PHPConsulAPI\Consul; +use DCarbone\PHPConsulAPI\PHPLib\AbstractType; -class MeshConfigEntry extends AbstractModel implements ConfigEntry +class MeshConfigEntry extends AbstractType implements ConfigEntry { use ConfigEntryTrait; - protected const FIELDS = COnfigEntry::INTERFACE_FIELDS + [ - self::FIELD_TRANSPARENT_PROXY => [ - Transcoding::FIELD_TYPE => Transcoding::OBJECT, - Transcoding::FIELD_CLASS => TransparentProxyConfig::class, - Transcoding::FIELD_NULLABLE => false, - Transcoding::FIELD_OMITEMPTY => false, - ], - ]; + public string $Partition; + public TransparentProxyMeshConfig $TransparentProxy; + public bool $AllowEnablingPermissiveMutualTLS; + public null|MeshTLSConfig $TLS; + public null|MeshHTTPConfig $HTTP; + public null|PeeringMeshConfig $Peering; - private const FIELD_TRANSPARENT_PROXY = 'TransparentProxy'; + /** + * @param array $Meta + */ + public function __construct( + string $Partition = '', + string $Namespace = '', + null|TransparentProxyMeshConfig $TransparentProxy = null, + bool $AllowEnablingPermissiveMutualTLS = false, + null|MeshTLSConfig $TLS = null, + null|MeshHTTPConfig $HTTP = null, + null|PeeringMeshConfig $Peering = null, + array $Meta = [], + int $CreateIndex = 0, + int $ModifyIndex = 0 + ) { + $this->Partition = $Partition; + $this->Namespace = $Namespace; + $this->setMeta($Meta); + $this->CreateIndex = $CreateIndex; + $this->ModifyIndex = $ModifyIndex; + $this->TransparentProxy = $TransparentProxy ?? new TransparentProxyMeshConfig(); + $this->AllowEnablingPermissiveMutualTLS = $AllowEnablingPermissiveMutualTLS; + $this->TLS = $TLS; + $this->HTTP = $HTTP; + $this->Peering = $Peering; +} - public TransparentProxyConfig $TransparentProxy; + public function getKind(): string + { + return Consul::MeshConfig; + } + + public function getName(): string + { + return Consul::MeshConfigMesh; + } - public function getTransparentProxy(): TransparentProxyConfig + public function getTransparentProxy(): TransparentProxyMeshConfig { return $this->TransparentProxy; } - public function setTransparentProxy(TransparentProxyConfig $TransparentProxy): self + public function setTransparentProxy(TransparentProxyMeshConfig $TransparentProxy): self { $this->TransparentProxy = $TransparentProxy; return $this; } + + public function isAllowEnablingPermissiveMutualTLS(): bool + { + return $this->AllowEnablingPermissiveMutualTLS; + } + + public function setAllowEnablingPermissiveMutualTLS(bool $AllowEnablingPermissiveMutualTLS): self + { + $this->AllowEnablingPermissiveMutualTLS = $AllowEnablingPermissiveMutualTLS; + return $this; + } + + public function getTLS(): null|MeshTLSConfig + { + return $this->TLS; + } + + public function setTLS(null|MeshTLSConfig $TLS): self + { + $this->TLS = $TLS; + return $this; + } + + public function getHTTP(): null|MeshHTTPConfig + { + return $this->HTTP; + } + + public function setHTTP(null|MeshHTTPConfig $HTTP): self + { + $this->HTTP = $HTTP; + return $this; + } + + public function getPeering(): null|PeeringMeshConfig + { + return $this->Peering; + } + + public function setPeering(null|PeeringMeshConfig $Peering): self + { + $this->Peering = $Peering; + return $this; + } + + public static function jsonUnserialize(\stdClass $decoded, null|self $n = null): self + { + $n = $n ?? new self(); + foreach ((array)$decoded as $k => $v) { + if ('TransparentProxy' === $k || 'transparent_proxy' === $k) { + $n->TransparentProxy = null === $v ? new TransparentProxyMeshConfig() : TransparentProxyMeshConfig::jsonUnserialize($v); + } elseif ('TLS' === $k) { + $n->TLS = null === $v ? null : MeshTLSConfig::jsonUnserialize($v); + } elseif ('HTTP' === $k) { + $n->HTTP = null === $v ? null : MeshHTTPConfig::jsonUnserialize($v); + } elseif ('Peering' === $k) { + $n->Peering = null === $v ? null : PeeringMeshConfig::jsonUnserialize($v); + } elseif ('allow_enabling_permissive_mutual_tls' === $k) { + $n->AllowEnablingPermissiveMutualTLS = $v; + } elseif ('Meta' === $k) { + $n->setMeta($v); + } else { + $n->{$k} = $v; + } + } + return $n; + } + + public function jsonSerialize(): \stdClass + { + $out = $this->_startJsonSerialize(); + $out->Kind = Consul::MeshConfigMesh; + if ('' !== $this->Partition) { + $out->Partition = $this->Partition; + } + $out->TransparentProxy = $this->TransparentProxy; + if ($this->AllowEnablingPermissiveMutualTLS) { + $out->AllowEnablingPermissiveMutualTLS = true; + } + if (null !== $this->TLS) { + $out->TLS = $this->TLS; + } + if (null !== $this->HTTP) { + $out->HTTP = $this->HTTP; + } + if (null !== $this->Peering) { + $out->Peering = $this->Peering; + } + if (null !== $this->Meta) { + $out->Meta = $this->Meta; + } + $out->CreateIndex = $this->CreateIndex; + $out->ModifyIndex = $this->ModifyIndex; + return $out; + } } diff --git a/src/ConfigEntry/MeshDirectionalTLSConfig.php b/src/ConfigEntry/MeshDirectionalTLSConfig.php new file mode 100644 index 00000000..8c609797 --- /dev/null +++ b/src/ConfigEntry/MeshDirectionalTLSConfig.php @@ -0,0 +1,112 @@ + */ + public array $CipherSuites; + + /** + * @param array $CipherSuites + */ + public function __construct( + string $TLSMinVersion = '', + string $TLSMaxVersion = '', + array $CipherSuites = [], + ) { + $this->TLSMinVersion = $TLSMinVersion; + $this->TLSMaxVersion = $TLSMaxVersion; + $this->setCipherSuites(...$CipherSuites); + } + + public function getTLSMinVersion(): string + { + return $this->TLSMinVersion; + } + + public function setTLSMinVersion(string $TLSMinVersion): self + { + $this->TLSMinVersion = $TLSMinVersion; + return $this; + } + + public function getTLSMaxVersion(): string + { + return $this->TLSMaxVersion; + } + + public function setTLSMaxVersion(string $TLSMaxVersion): self + { + $this->TLSMaxVersion = $TLSMaxVersion; + return $this; + } + + /** + * @return array + */ + public function getCipherSuites(): array + { + return $this->CipherSuites; + } + + public function setCipherSuites(string ...$CipherSuites): self + { + $this->CipherSuites = $CipherSuites; + return $this; + } + + public static function jsonUnserialize(\stdClass $decoded): self + { + $n = new self(); + foreach ((array)$decoded as $k => $v) { + if ('CipherSuites' === $k || 'cipher_suites' === $k) { + $n->setCipherSuites(...$v); + } elseif ('tls_min_version' === $k) { + $n->TLSMinVersion = $v; + } elseif ('tls_max_version' === $k) { + $n->TLSMaxVersion = $v; + } else { + $n->{$k} = (string)$v; + } + } + return $n; + } + + public function jsonSerialize(): \stdClass + { + $out = $this->_startJsonSerialize(); + if ('' !== $this->TLSMinVersion) { + $out->TLSMinVersion = $this->TLSMinVersion; + } + if ('' !== $this->TLSMaxVersion) { + $out->TLSMaxVersion = $this->TLSMaxVersion; + } + if ([] !== $this->CipherSuites) { + $out->CipherSuites = $this->CipherSuites; + } + return $out; + } +} \ No newline at end of file diff --git a/src/ConfigEntry/MeshGatewayConfig.php b/src/ConfigEntry/MeshGatewayConfig.php index 68074e57..850da89c 100644 --- a/src/ConfigEntry/MeshGatewayConfig.php +++ b/src/ConfigEntry/MeshGatewayConfig.php @@ -20,27 +20,45 @@ limitations under the License. */ -use DCarbone\PHPConsulAPI\AbstractModel; -use DCarbone\PHPConsulAPI\Transcoding; +use DCarbone\PHPConsulAPI\PHPLib\AbstractType; -class MeshGatewayConfig extends AbstractModel +class MeshGatewayConfig extends AbstractType { - protected const FIELDS = [ - self::FIELD_MODE => Transcoding::OMITEMPTY_STRING_FIELD, - ]; + public MeshGatewayMode $Mode; - private const FIELD_MODE = 'Mode'; - - public string $Mode = ''; + public function __construct( + string|MeshGatewayMode $mode = MeshGatewayMode::Default, + ) { + $this->setMode($mode); +} - public function getMode(): string + public function getMode(): MeshGatewayMode { return $this->Mode; } - public function setMode(string $mode): self + public function setMode(string|MeshGatewayMode $Mode): self { - $this->Mode = $mode; + $this->Mode = $Mode instanceof MeshGatewayMode ? $Mode : MeshGatewayMode::from($Mode); return $this; } + + public static function jsonUnserialize(\stdClass $decoded): self + { + $n = new self(); + foreach ((array)$decoded as $k => $v) { + if ('Mode' === $k) { + $n->setMode($v); + } else { + $n->{$k} = $v; + } + } + return $n; + } + + public function jsonSerialize(): \stdClass + { + $out = $this->_startJsonSerialize(); + return $out; + } } diff --git a/src/ConfigEntry/MeshGatewayMode.php b/src/ConfigEntry/MeshGatewayMode.php new file mode 100644 index 00000000..0f2f2311 --- /dev/null +++ b/src/ConfigEntry/MeshGatewayMode.php @@ -0,0 +1,46 @@ +SanitizeXForwardClientCert = $SanitizeXForwardClientCert; + } + + public function isSanitizeXForwardClientCert(): bool + { + return $this->SanitizeXForwardClientCert; + } + + public function setSanitizeXForwardClientCert(bool $SanitizeXForwardClientCert): self + { + $this->SanitizeXForwardClientCert = $SanitizeXForwardClientCert; + return $this; + } + + public static function jsonUnserialize(\stdClass $decoded): self + { + $n = new self(); + foreach ((array)$decoded as $k => $v) { + $n->{$k} = $v; + } + return $n; + } + + public function jsonSerialize(): \stdClass + { + $out = $this->_startJsonSerialize(); + $out->SanitizeXForwardClientCert = $this->SanitizeXForwardClientCert; + return $out; + } +} diff --git a/src/ConfigEntry/MeshTLSConfig.php b/src/ConfigEntry/MeshTLSConfig.php new file mode 100644 index 00000000..c3310099 --- /dev/null +++ b/src/ConfigEntry/MeshTLSConfig.php @@ -0,0 +1,85 @@ +Incoming = $Incoming; + $this->Outgoing = $Outgoing; + } + + public function getIncoming(): null|MeshDirectionalTLSConfig + { + return $this->Incoming; + } + public function setIncoming(null|MeshDirectionalTLSConfig $Incoming): self + { + $this->Incoming = $Incoming; + return $this; + } + + public function getOutgoing(): null|MeshDirectionalTLSConfig + { + return $this->Outgoing; + } + + public function setOutgoing(null|MeshDirectionalTLSConfig $Outgoing): self + { + $this->Outgoing = $Outgoing; + return $this; + } + + public static function jsonUnserialize(\stdClass $decoded): self + { + $n = new self(); + foreach ((array)$decoded as $k => $V) { + if ('Incoming' === $k) { + $n->Incoming = null === $V ? null : MeshDirectionalTLSConfig::jsonUnserialize($V); + } elseif ('Outgoing' === $k) { + $n->Outgoing = null === $V ? null : MeshDirectionalTLSConfig::jsonUnserialize($V); + } else { + $n->{$k} = $V; + } + } + return $n; + } + + public function jsonSerialize(): \stdClass + { + $out = $this->_startJsonSerialize(); + if (null !== $this->Incoming) { + $out->Incoming = $this->Incoming; + } + if (null !== $this->Outgoing) { + $out->Outgoing = $this->Outgoing; + } + return $out; + } +} diff --git a/src/ConfigEntry/MutualTLSMode.php b/src/ConfigEntry/MutualTLSMode.php new file mode 100644 index 00000000..c12604ca --- /dev/null +++ b/src/ConfigEntry/MutualTLSMode.php @@ -0,0 +1,39 @@ + [ - Transcoding::FIELD_UNMARSHAL_CALLBACK => Transcoding::UNMARSHAL_DURATION, - Transcoding::FIELD_OMITEMPTY => true, - ], - ]; + public Time\Duration $Interval; + public int $MaxFailures; - private const FIELD_INTERVAL = 'Interval'; + public null|int $EnforcingConsecutive5xx; + public null|int $MaxEjectionPercent; - public Time\Duration $Interval; - public int $MaxFailures = 0; + public null|Time\Duration $BaseEjectionTime; - public function __construct(?array $data = []) - { - parent::__construct($data); - if (!isset($this->Interval)) { - $this->Interval = new Time\Duration(); - } - } + public function __construct( + null|string|int|float|\DateInterval|Time\Duration $Interval = null, + int $MaxFailures = 0, + null|int $EnforcingConsecutive5xx = null, + null|int $MaxEjectionPercent = null, + null|string|int|float|\DateInterval|Time\Duration $BaseEjectionTime = null, + ) { + $this->Interval = Time::Duration($Interval); + $this->MaxFailures = $MaxFailures; + $this->EnforcingConsecutive5xx = $EnforcingConsecutive5xx; + $this->MaxEjectionPercent = $MaxEjectionPercent; + $this->BaseEjectionTime = null !== $BaseEjectionTime ? Time::Duration($BaseEjectionTime) : null; +} public function getInterval(): Time\Duration { return $this->Interval; } - public function setInterval(Time\Duration $Interval): self + public function setInterval(null|string|int|float|\DateInterval|Time\Duration $Interval): self { - $this->Interval = $Interval; + $this->Interval = Time::Duration($Interval); return $this; } @@ -67,4 +68,77 @@ public function setMaxFailures(int $MaxFailures): self $this->MaxFailures = $MaxFailures; return $this; } + + public function getEnforcingConsecutive5xx(): null|int + { + return $this->EnforcingConsecutive5xx; + } + + public function setEnforcingConsecutive5xx(null|int $EnforcingConsecutive5xx): self + { + $this->EnforcingConsecutive5xx = $EnforcingConsecutive5xx; + return $this; + } + + public function getMaxEjectionPercent(): null|int + { + return $this->MaxEjectionPercent; + } + + public function setMaxEjectionPercent(null|int $MaxEjectionPercent): self + { + $this->MaxEjectionPercent = $MaxEjectionPercent; + return $this; + } + + public function getBaseEjectionTime(): null|Time\Duration + { + return $this->BaseEjectionTime; + } + + public function setBaseEjectionTime(null|Time\Duration $BaseEjectionTime): self + { + $this->BaseEjectionTime = $BaseEjectionTime; + return $this; + } + + public static function jsonUnserialize(\stdClass $decoded): self + { + $n = new self(); + foreach ((array)$decoded as $k => $v) { + if ('Interval' === $k) { + $n->Interval = Time::ParseDuration($v); + } elseif ('max_failures' === $k) { + $n->MaxFailures = $v; + } elseif ('enforcing_consecutive_5xx' === $k) { + $n->EnforcingConsecutive5xx = $v; + } elseif ('max_ejection_percent' === $k) { + $n->MaxEjectionPercent = $v; + } elseif ('base_ejection_time' === $k) { + $n->BaseEjectionTime = Time::ParseDuration($v); + } else { + $n->{$k} = $v; + } + } + return $n; + } + + public function jsonSerialize(): \stdClass + { + $out = $this->_startJsonSerialize(); + if ($this->Interval->Nanoseconds() !== 0) { + $out->Interval = $this->Interval; + } + $out->MaxFailures = $this->MaxFailures; + if (null !== $this->EnforcingConsecutive5xx) { + $out->EnforcingConsecutive5xx = $this->EnforcingConsecutive5xx; + } + if (null !== $this->MaxEjectionPercent) { + $out->MaxEjectionPercent = $this->MaxEjectionPercent; + } + if (null !== $this->BaseEjectionTime) { + $out->BaseEjectionTime = $this->BaseEjectionTime; + } + return $out; + } } diff --git a/src/ConfigEntry/PeeringMeshConfig.php b/src/ConfigEntry/PeeringMeshConfig.php new file mode 100644 index 00000000..f024460b --- /dev/null +++ b/src/ConfigEntry/PeeringMeshConfig.php @@ -0,0 +1,60 @@ +PeerThroughMeshGateways = $PeerThroughMeshGateways; + } + + public function isPeerThroughMeshGateways(): bool + { + return $this->PeerThroughMeshGateways; + } + + public function setPeerThroughMeshGateways(bool $PeerThroughMeshGateways): self + { + $this->PeerThroughMeshGateways = $PeerThroughMeshGateways; + return $this; + } + + public static function jsonUnserialize(\stdClass $decoded): self + { + $n = new self(); + foreach ((array)$decoded as $k => $v) { + $n->{$k} = $v; + } + return $n; + } + + public function jsonSerialize(): \stdClass + { + $out = $this->_startJsonSerialize(); + $out->PeerThroughMeshGateways = $this->PeerThroughMeshGateways; + return $out; + } +} diff --git a/src/ConfigEntry/ProxyConfigEntry.php b/src/ConfigEntry/ProxyConfigEntry.php index d8896dd8..65dc3138 100644 --- a/src/ConfigEntry/ProxyConfigEntry.php +++ b/src/ConfigEntry/ProxyConfigEntry.php @@ -20,77 +20,162 @@ limitations under the License. */ -use DCarbone\PHPConsulAPI\AbstractModel; -use DCarbone\PHPConsulAPI\FakeMap; -use DCarbone\PHPConsulAPI\Transcoding; +use DCarbone\PHPConsulAPI\Consul; +use DCarbone\PHPConsulAPI\PHPLib\AbstractType; +use function DCarbone\PHPConsulAPI\PHPLib\_enc_obj_if_valued; -class ProxyConfigEntry extends AbstractModel implements ConfigEntry +class ProxyConfigEntry extends AbstractType implements ConfigEntry { use ConfigEntryTrait; - protected const FIELDS = ConfigEntry::INTERFACE_FIELDS + [ - self::FIELD_MODE => Transcoding::OMITEMPTY_STRING_FIELD, - self::FIELD_CONFIG => Transcoding::MAP_FIELD, - self::FIELD_TRANSPARENT_PROXY => [ - Transcoding::FIELD_TYPE => Transcoding::OBJECT, - Transcoding::FIELD_CLASS => TransparentProxyConfig::class, - Transcoding::FIELD_NULLABLE => true, - Transcoding::FIELD_OMITEMPTY => true, - ], - self::FIELD_MESH_GATEWAY => [ - Transcoding::FIELD_TYPE => Transcoding::OBJECT, - Transcoding::FIELD_CLASS => MeshGatewayConfig::class, - Transcoding::FIELD_OMITEMPTY => true, // todo: does nothing as field is not nullable.. - ], - self::FIELD_EXPOSE => [ - Transcoding::FIELD_TYPE => Transcoding::OBJECT, - Transcoding::FIELD_CLASS => ExposeConfig::class, - Transcoding::FIELD_OMITEMPTY => true, // todo: does nothing as field is not nullable, - ], - ]; - - private const FIELD_MODE = 'Mode'; - private const FIELD_TRANSPARENT_PROXY = 'TransparentProxy'; - private const FIELD_CONFIG = 'Config'; - private const FIELD_MESH_GATEWAY = 'MeshGateway'; - private const FIELD_EXPOSE = 'Expose'; - - public string $Mode = ''; - public ?TransparentProxyConfig $TransparentProxy = null; - public ?FakeMap $Config = null; + public string $Kind; + public string $Name; + public string $Partition; + public null|ProxyMode $Mode; + public null|TransparentProxyConfig $TransparentProxy; + public MutualTLSMode $MutualTLSMode; + /** @var array */ + public array $Config; + public MeshGatewayConfig $MeshGateway; public ExposeConfig $Expose; + public null|AccessLogsConfig $AccessLogs; + /** @var array<\DCarbone\PHPConsulAPI\ConfigEntry\EnvoyExtension> */ + public array $EnvoyExtensions; + public null|ServiceResolverFailoverPolicy $FailoverPolicy; + public null|ServiceResolverPrioritizeByLocality $PrioritizeByLocality; - public function getMode(): string + /** + * @param array $Config + * @param array<\DCarbone\PHPConsulAPI\ConfigEntry\EnvoyExtension> $EnvoyExtensions + * @param array $Meta + */ + public function __construct( + string $Kind = '', + string $Name = '', + string $Partition = '', + string|ProxyMode $Mode = ProxyMode::Default, + null|TransparentProxyConfig $TransparentProxy = null, + string|MutualTLSMode $MutualTLSMode = MutualTLSMode::Default, + array $Config = [], + null|MeshGatewayConfig $MeshGateway = null, + null|ExposeConfig $Expose = null, + null|AccessLogsConfig $AccessLogs = null, + array $EnvoyExtensions = [], + null|ServiceResolverFailoverPolicy $FailoverPolicy = null, + null|ServiceResolverPrioritizeByLocality $PrioritizeByLocality = null, + string $Namespace = '', + array $Meta = [], + int $CreateIndex = 0, + int $ModifyIndex = 0, + ) { + { + $this->Kind = $Kind; + $this->Name = $Name; + $this->Partition = $Partition; + $this->Namespace = $Namespace; + $this->Mode = $Mode instanceof ProxyMode ? $Mode : ProxyMode::from($Mode); + $this->TransparentProxy = $TransparentProxy; + $this->MutualTLSMode = $MutualTLSMode instanceof MutualTLSMode ? $MutualTLSMode : MutualTLSMode::from($MutualTLSMode); + $this->setConfig($Config); + $this->MeshGateway = $MeshGateway ?? new MeshGatewayConfig(); + $this->Expose = $Expose ?? new ExposeConfig(); + $this->AccessLogs = $AccessLogs; + $this->setEnvoyExtensions(...$EnvoyExtensions); + $this->FailoverPolicy = $FailoverPolicy; + $this->PrioritizeByLocality = $PrioritizeByLocality; + $this->setMeta($Meta); + $this->CreateIndex = $CreateIndex; + $this->ModifyIndex = $ModifyIndex; +} + } + + public function getKind(): string + { + return $this->Kind; + } + + public function setKind(string $Kind): self + { + $this->Kind = $Kind; + return $this; + } + + public function getName(): string + { + return Consul::ProxyConfigGlobal; + } + + public function setName(string $Name): self + { + $this->Name = $Name; + return $this; + } + + public function getPartition(): string + { + return $this->Partition; + } + + public function setPartition(string $Partition): self + { + $this->Partition = $Partition; + return $this; + } + + public function getMode(): ProxyMode { return $this->Mode; } - public function setMode(string $Mode): self + public function setMode(ProxyMode $Mode): self { $this->Mode = $Mode; return $this; } - public function getTransparentProxy(): ?TransparentProxyConfig + public function getTransparentProxy(): null|TransparentProxyConfig { return $this->TransparentProxy; } - public function setTransparentProxy(?TransparentProxyConfig $TransparentProxy): self + public function setTransparentProxy(null|TransparentProxyConfig $TransparentProxy): self { $this->TransparentProxy = $TransparentProxy; return $this; } - public function getConfig(): ?FakeMap + public function getMutualTLSMode(): MutualTLSMode + { + return $this->MutualTLSMode; + } + + public function setMutualTLSMode(MutualTLSMode $MutualTLSMode): self + { + $this->MutualTLSMode = $MutualTLSMode; + return $this; + } + + /** + * @return array + */ + public function getConfig(): array { return $this->Config; } - public function setConfig(mixed $Config): self + /** + * @param null|\stdClass|array $Config + * @return $this + */ + public function setConfig(null|\stdClass|array $Config): self { - $this->Config = FakeMap::parse($Config); + $this->Config = []; + if (null !== $Config) { + foreach ($Config as $k => $v) { + $this->Config[$k] = $v; + } + } return $this; } @@ -115,4 +200,133 @@ public function setExpose(ExposeConfig $Expose): self $this->Expose = $Expose; return $this; } + + public function getAccessLogs(): null|AccessLogsConfig + { + return $this->AccessLogs; + } + + public function setAccessLogs(null|AccessLogsConfig $AccessLogs): self + { + $this->AccessLogs = $AccessLogs; + return $this; + } + + /** + * @return array<\DCarbone\PHPConsulAPI\ConfigEntry\EnvoyExtension> + */ + public function getEnvoyExtensions(): array + { + return $this->EnvoyExtensions; + } + + /** + * @param \DCarbone\PHPConsulAPI\ConfigEntry\EnvoyExtension ...$EnvoyExtensions + */ + public function setEnvoyExtensions(EnvoyExtension ...$EnvoyExtensions): self + { + $this->EnvoyExtensions = $EnvoyExtensions; + return $this; + } + + public function getFailoverPolicy(): null|ServiceResolverFailoverPolicy + { + return $this->FailoverPolicy; + } + + public function setFailoverPolicy(null|ServiceResolverFailoverPolicy $FailoverPolicy): self + { + $this->FailoverPolicy = $FailoverPolicy; + return $this; + } + + public function getPrioritizeByLocality(): null|ServiceResolverPrioritizeByLocality + { + return $this->PrioritizeByLocality; + } + + public function setPrioritizeByLocality(null|ServiceResolverPrioritizeByLocality $PrioritizeByLocality): self + { + $this->PrioritizeByLocality = $PrioritizeByLocality; + return $this; + } + + public static function jsonUnserialize(\stdClass $decoded): self + { + $n = new self(); + foreach ((array)$decoded as $k => $v) { + if ('ProxyMode' === $k) { + $n->Mode = ProxyMode::from($v); + } elseif ('TransparentProxy' === $k || 'transparent_proxy' === $k) { + $n->TransparentProxy = TransparentProxyConfig::jsonUnserialize($v); + } elseif ('MutualTLSMode' === $k || 'mutual_tls_mode' === $k) { + $n->MutualTLSMode = MutualTLSMode::from($v); + } elseif ('MeshGateway' === $k || 'mesh_gateway' === $k) { + $n->MeshGateway = MeshGatewayConfig::jsonUnserialize($v); + } elseif ('Expose' === $k) { + $n->Expose = ExposeConfig::jsonUnserialize($v); + } elseif ('AccessLogs' === $k || 'access_logs' === $k) { + $n->AccessLogs = AccessLogsConfig::jsonUnserialize($v); + } elseif ('EnvoyExtensions' === $k || 'envoy_extensions' === $k) { + foreach ($v as $ext) { + $n->EnvoyExtensions[] = EnvoyExtension::jsonUnserialize($ext); + } + } elseif ('FailoverPolicy' === $k || 'failover_policy' === $k) { + $n->FailoverPolicy = ServiceResolverFailoverPolicy::jsonUnserialize($v); + } elseif ('PrioritizeByLocality' === $k || 'prioritize_by_locality' === $k) { + $n->PrioritizeByLocality = ServiceResolverPrioritizeByLocality::jsonUnserialize($v); + } elseif ('Config' === $k) { + $n->setConfig($v); + } elseif ('Meta' === $k) { + $n->setMeta($v); + } else { + $n->{$k} = $v; + } + } + return $n; + } + + public function jsonSerialize(): \stdClass + { + $out = $this->_startJsonSerialize(); + $out->Kind = $this->Kind; + $out->Name = $this->Name; + if ('' !== $this->Partition) { + $out->Partition = $this->Partition; + } + if (ProxyMode::Default !== $this->Mode) { + $out->ProxyMode = $this->Mode->value; + } + if (null !== $this->TransparentProxy) { + $out->TransparentProxy = $this->TransparentProxy; + } + if (MutualTLSMode::Default !== $this->MutualTLSMode) { + $out->MutualTLSMode = $this->MutualTLSMode->value; + } + if ([] !== $this->Config) { + $out->Config = $this->Config; + } + _enc_obj_if_valued($out, 'MeshGateway', $this->MeshGateway); + _enc_obj_if_valued($out, 'Expose', $this->Expose); + if (null !== $this->AccessLogs) { + $out->AccessLogs = $this->AccessLogs; + } if ([] !== $this->EnvoyExtensions) { + $out->EnvoyExtensions = $this->EnvoyExtensions; + } + if (null !== $this->FailoverPolicy) { + $out->FailoverPolicy = $this->FailoverPolicy; + } + if (null !== $this->PrioritizeByLocality) { + $out->PrioritizeByLocality = $this->PrioritizeByLocality; + } + if ('' !== $this->Namespace) { + $out->Namespace = $this->Namespace; + } + if ([] !== $this->Meta) { + $out->Meta = $this->Meta; + } + $out->CreateIndex = $this->CreateIndex; + $out->ModifyIndex = $this->ModifyIndex; + return $out; + } } diff --git a/src/ConfigEntry/ProxyMode.php b/src/ConfigEntry/ProxyMode.php new file mode 100644 index 00000000..c416a423 --- /dev/null +++ b/src/ConfigEntry/ProxyMode.php @@ -0,0 +1,43 @@ +InstanceLevel = $instanceLevel ?? new InstanceLevelRateLimits(); + } + + public function getInstanceLevel(): InstanceLevelRateLimits + { + return $this->InstanceLevel; + } + + public function setInstanceLevel(InstanceLevelRateLimits $InstanceLevel): self + { + $this->InstanceLevel = $InstanceLevel; + return $this; + } + + public static function jsonUnserialize(\stdClass $decoded): self + { + $n = new self(); + foreach ((array)$decoded as $k => $v) { + if ('InstanceLevel' === $k || 'instance_level' === $k) { + $n->InstanceLevel = InstanceLevelRateLimits::jsonUnserialize($v); + } else { + $n->{$k} = $v; + } + } + return $n; + } + + public function jsonSerialize(): \stdClass + { + $out = $this->_startJsonSerialize(); + $out->InstanceLevel = $this->InstanceLevel; + return $out; + } +} diff --git a/src/ConfigEntry/RingHashConfig.php b/src/ConfigEntry/RingHashConfig.php index 6b7fad97..7c763742 100644 --- a/src/ConfigEntry/RingHashConfig.php +++ b/src/ConfigEntry/RingHashConfig.php @@ -20,16 +20,65 @@ limitations under the License. */ -use DCarbone\PHPConsulAPI\AbstractModel; -use DCarbone\PHPConsulAPI\Transcoding; +use DCarbone\PHPConsulAPI\PHPLib\AbstractType; -class RingHashConfig extends AbstractModel +class RingHashConfig extends AbstractType { - protected const FIELDS = [ - self::FIELD_MINIMUM_RING_SIZE => Transcoding::OMITEMPTY_INTEGER_FIELD, - self::FIELD_MAXIMUM_RING_SIZE => Transcoding::OMITEMPTY_INTEGER_FIELD, - ]; + public int $MinimumRingSize = 0; + public int $MaximumRingSize = 0; - private const FIELD_MINIMUM_RING_SIZE = 'MinimumRingSize'; - private const FIELD_MAXIMUM_RING_SIZE = 'MaximumRingSize'; + public function __construct(int $MinimumRingSize = 0, int $MaximumRingSize = 0) + { + $this->MinimumRingSize = $MinimumRingSize; + $this->MaximumRingSize = $MaximumRingSize; + } + + public function getMinimumRingSize(): int + { + return $this->MinimumRingSize; + } + + public function setMinimumRingSize(int $MinimumRingSize): self + { + $this->MinimumRingSize = $MinimumRingSize; + return $this; + } + + public function getMaximumRingSize(): int + { + return $this->MaximumRingSize; + } + + public function setMaximumRingSize(int $MaximumRingSize): self + { + $this->MaximumRingSize = $MaximumRingSize; + return $this; + } + + public static function jsonUnserialize(\stdClass $decoded): self + { + $n = new self(); + foreach ((array)$decoded as $k => $v) { + if ('minimum_ring_size' === $k) { + $n->MinimumRingSize = $v; + } elseif ('maximum_ring_size' === $k) { + $n->MaximumRingSize = $v; + } else { + $n->{$k} = $v; + } + } + return $n; + } + + public function jsonSerialize(): \stdClass + { + $out = $this->_startJsonSerialize(); + if (0 !== $this->MinimumRingSize) { + $out->MinimumRingSize = $this->MinimumRingSize; + } + if (0 !== $this->MaximumRingSize) { + $out->MaximumRingSize = $this->MaximumRingSize; + } + return $out; + } } diff --git a/src/ConfigEntry/ServiceConfigEntry.php b/src/ConfigEntry/ServiceConfigEntry.php index 750fe4ce..d1c2770c 100644 --- a/src/ConfigEntry/ServiceConfigEntry.php +++ b/src/ConfigEntry/ServiceConfigEntry.php @@ -20,56 +20,118 @@ limitations under the License. */ -use DCarbone\PHPConsulAPI\AbstractModel; -use DCarbone\PHPConsulAPI\Transcoding; +use DCarbone\PHPConsulAPI\PHPLib\AbstractType; +use function DCarbone\PHPConsulAPI\PHPLib\_enc_obj_if_valued; -class ServiceConfigEntry extends AbstractModel implements ConfigEntry +class ServiceConfigEntry extends AbstractType implements ConfigEntry { use ConfigEntryTrait; - protected const FIELDS = ConfigEntry::INTERFACE_FIELDS + [ - self::FIELD_PROTOCOL => Transcoding::OMITEMPTY_STRING_FIELD, - self::FIELD_MODE => Transcoding::OMITEMPTY_STRING_FIELD, - self::FIELD_TRANSPARENT_PROXY => [ - Transcoding::FIELD_TYPE => Transcoding::OBJECT, - Transcoding::FIELD_CLASS => TransparentProxyConfig::class, - Transcoding::FIELD_NULLABLE => true, - Transcoding::FIELD_OMITEMPTY => true, - ], - self::FIELD_MESH_GATEWAY => [ - Transcoding::FIELD_TYPE => Transcoding::OBJECT, - Transcoding::FIELD_CLASS => MeshGatewayConfig::class, - Transcoding::FIELD_OMITEMPTY => true, // todo: does nothing as it isn't nullable... - ], - self::FIELD_EXPOSE => [ - Transcoding::FIELD_TYPE => Transcoding::OBJECT, - Transcoding::FIELD_CLASS => ExposeConfig::class, - Transcoding::FIELD_OMITEMPTY => true, // todo: does nothing as isn't nullable.. - ], - self::FIELD_EXTERNAL_SNI => Transcoding::OMITEMPTY_STRING_FIELD, - self::FIELD_UPSTREAM_CONFIG => [ - Transcoding::FIELD_TYPE => Transcoding::OBJECT, - Transcoding::FIELD_CLASS => UpstreamConfiguration::class, - Transcoding::FIELD_NULLABLE => true, - Transcoding::FIELD_OMITEMPTY => true, - ], - ]; - - private const FIELD_PROTOCOL = 'Protocol'; - private const FIELD_MODE = 'Mode'; - private const FIELD_TRANSPARENT_PROXY = 'TransparentProxy'; - private const FIELD_MESH_GATEWAY = 'MeshGateway'; - private const FIELD_EXPOSE = 'Expose'; - private const FIELD_EXTERNAL_SNI = 'ExternalSNI'; - private const FIELD_UPSTREAM_CONFIG = 'UpstreamConfig'; - - public string $Protocol = ''; - public string $Mode = ''; - public ?TransparentProxyConfig $TransparentProxy = null; + public string $Kind; + public string $Name; + public string $Partition; + public string $Protocol; + public ProxyMode $Mode; + public null|TransparentProxyConfig $TransparentProxy; + + public MutualTLSMode $MutualTLSMode; public MeshGatewayConfig $MeshGateway; public ExposeConfig $Expose; - public string $ExternalSNI = ''; - public ?UpstreamConfiguration $UpstreamConfig = null; + public string $ExternalSNI; + public null|UpstreamConfiguration $UpstreamConfig; + public null|DestinationConfig $Destination; + public int $MaxInboundConnections; + public int $LocalConnectTimeoutMs; + public int $LocalRequestTimeoutMs; + public string $BalanceInboundConnections; + public null|RateLimits $RateLimits; + /** @var array<\DCarbone\PHPConsulAPI\ConfigEntry\EnvoyExtension> */ + public array $EnvoyExtensions; + + /** + * @param array<\DCarbone\PHPConsulAPI\ConfigEntry\EnvoyExtension> $EnvoyExtensions + * @param array $Meta + */ + public function __construct( + string $Kind = '', + string $Name = '', + string $Partition = '', + string $Namespace = '', + string $Protocol = '', + string|ProxyMode $Mode = ProxyMode::Default, + null|TransparentProxyConfig $TransparentProxy = null, + string|MutualTLSMode $MutualTLSMode = MutualTLSMode::Default, + null|MeshGatewayConfig $MeshGateway = null, + null|ExposeConfig $Expose = null, + string $ExternalSNI = '', + null|UpstreamConfiguration $UpstreamConfig = null, + null|DestinationConfig $Destination = null, + int $MaxInboundConnections = 0, + int $LocalConnectTimeoutMs = 0, + int $LocalRequestTimeoutMs = 0, + string $BalanceInboundConnections = '', + null|RateLimits $RateLimits = null, + array $EnvoyExtensions = [], + array $Meta = [], + int $CreateIndex = 0, + int $ModifyIndex = 0, + ) { + $this->Kind = $Kind; + $this->Name = $Name; + $this->Partition = $Partition; + $this->Namespace = $Namespace; + $this->Protocol = $Protocol; + $this->Mode = is_string($Mode) ? ProxyMode::from($Mode) : $Mode; + $this->TransparentProxy = $TransparentProxy; + $this->MutualTLSMode = is_string($MutualTLSMode) ? MutualTLSMode::from($MutualTLSMode) : $MutualTLSMode; + $this->MeshGateway = $MeshGateway ?? new MeshGatewayConfig(); + $this->Expose = $Expose ?? new ExposeConfig(); + $this->ExternalSNI = $ExternalSNI; + $this->UpstreamConfig = $UpstreamConfig; + $this->Destination = $Destination; + $this->MaxInboundConnections = $MaxInboundConnections; + $this->LocalConnectTimeoutMs = $LocalConnectTimeoutMs; + $this->LocalRequestTimeoutMs = $LocalRequestTimeoutMs; + $this->BalanceInboundConnections = $BalanceInboundConnections; + $this->RateLimits = $RateLimits; + $this->setEnvoyExtensions(...$EnvoyExtensions); + $this->setMeta($Meta); + $this->CreateIndex = $CreateIndex; + $this->ModifyIndex = $ModifyIndex; + } + + public function getKind(): string + { + return $this->Kind; + } + + public function setKind(string $Kind): self + { + $this->Kind = $Kind; + return $this; + } + + public function getName(): string + { + return $this->Name; + } + + public function setName(string $Name): self + { + $this->Name = $Name; + return $this; + } + + public function getPartition(): string + { + return $this->Partition; + } + + public function setPartition(string $Partition): self + { + $this->Partition = $Partition; + return $this; + } public function getProtocol(): string { @@ -82,28 +144,39 @@ public function setProtocol(string $Protocol): self return $this; } - public function getMode(): string + public function getMode(): ProxyMode { return $this->Mode; } - public function setMode(string $Mode): self + public function setMode(ProxyMode $Mode): self { $this->Mode = $Mode; return $this; } - public function getTransparentProxy(): ?TransparentProxyConfig + public function getTransparentProxy(): null|TransparentProxyConfig { return $this->TransparentProxy; } - public function setTransparentProxy(?TransparentProxyConfig $TransparentProxy): self + public function setTransparentProxy(null|TransparentProxyConfig $TransparentProxy): self { $this->TransparentProxy = $TransparentProxy; return $this; } + public function getMutualTLSMode(): MutualTLSMode + { + return $this->MutualTLSMode; + } + + public function setMutualTLSMode(MutualTLSMode $MutualTLSMode): self + { + $this->MutualTLSMode = $MutualTLSMode; + return $this; + } + public function getMeshGateway(): MeshGatewayConfig { return $this->MeshGateway; @@ -137,14 +210,197 @@ public function setExternalSNI(string $ExternalSNI): self return $this; } - public function getUpstreamConfig(): ?UpstreamConfiguration + public function getUpstreamConfig(): null|UpstreamConfiguration { return $this->UpstreamConfig; } - public function setUpstreamConfig(?UpstreamConfiguration $UpstreamConfig): self + public function setUpstreamConfig(null|UpstreamConfiguration $UpstreamConfig): self { $this->UpstreamConfig = $UpstreamConfig; return $this; } + + public function getDestination(): null|DestinationConfig + { + return $this->Destination; + } + + public function setDestination(null|DestinationConfig $Destination): self + { + $this->Destination = $Destination; + return $this; + } + + public function getMaxInboundConnections(): int + { + return $this->MaxInboundConnections; + } + + public function setMaxInboundConnections(int $MaxInboundConnections): self + { + $this->MaxInboundConnections = $MaxInboundConnections; + return $this; + } + + public function getLocalConnectTimeoutMs(): int + { + return $this->LocalConnectTimeoutMs; + } + + public function setLocalConnectTimeoutMs(int $LocalConnectTimeoutMs): self + { + $this->LocalConnectTimeoutMs = $LocalConnectTimeoutMs; + return $this; + } + + public function getLocalRequestTimeoutMs(): int + { + return $this->LocalRequestTimeoutMs; + } + + public function setLocalRequestTimeoutMs(int $LocalRequestTimeoutMs): self + { + $this->LocalRequestTimeoutMs = $LocalRequestTimeoutMs; + return $this; + } + + public function getBalanceInboundConnections(): string + { + return $this->BalanceInboundConnections; + } + + public function setBalanceInboundConnections(string $BalanceInboundConnections): self + { + $this->BalanceInboundConnections = $BalanceInboundConnections; + return $this; + } + + public function getRateLimits(): null|RateLimits + { + return $this->RateLimits; + } + + public function setRateLimits(null|RateLimits $RateLimits): self + { + $this->RateLimits = $RateLimits; + return $this; + } + + /** + * @return array<\DCarbone\PHPConsulAPI\ConfigEntry\EnvoyExtension> + */ + public function getEnvoyExtensions(): array + { + return $this->EnvoyExtensions; + } + + public function setEnvoyExtensions(EnvoyExtension ...$EnvoyExtensions): self + { + $this->EnvoyExtensions = $EnvoyExtensions; + return $this; + } + + public static function jsonUnserialize(\stdClass $decoded): self + { + $n = new self(); + foreach ((array)$decoded as $k => $v) { + if ('Mode' === $k) { + $n->Mode = ProxyMode::from($v); + } elseif ('TransparentProxy' === $k || 'transparent_proxy' === $k) { + $n->TransparentProxy = null === $v ? null : TransparentProxyConfig::jsonUnserialize($v); + } elseif ('MutualTLSMode' === $k || 'mutual_tls_mode' === $k) { + $n->MutualTLSMode = MutualTLSMode::from($v); + } elseif ('MeshGateway' === $k || 'mesh_gateway' === $k) { + $n->MeshGateway = MeshGatewayConfig::jsonUnserialize($v); + } elseif ('Expose' === $k) { + $n->Expose = ExposeConfig::jsonUnserialize($v); + } elseif ('external_sni' === $k) { + $n->ExternalSNI = $v; + } elseif ('UpstreamConfig' === $k || 'upstream_config' === $k) { + $n->UpstreamConfig = null === $v ? null : UpstreamConfiguration::jsonUnserialize($v); + } elseif ('Destination' === $k) { + $n->Destination = null === $v ? null : DestinationConfig::jsonUnserialize($v); + } elseif ('max_inbound_connections' === $k) { + $n->MaxInboundConnections = $v; + } elseif ('local_connect_timeout_ms' === $k) { + $n->LocalConnectTimeoutMs = $v; + } elseif ('local_request_timeout_ms' === $k) { + $n->LocalRequestTimeoutMs = $v; + } elseif ('balance_inbound_connections' === $k) { + $n->BalanceInboundConnections = $v; + } elseif ('RateLimits' === $k || 'rate_limits' === $k) { + $n->RateLimits = null === $v ? null : RateLimits::jsonUnserialize($v); + } elseif ('EnvoyExtensions' === $k || 'envoy_extensions' === $k) { + foreach ($v as $ext) { + $n->EnvoyExtensions[] = EnvoyExtension::jsonUnserialize($ext); + } + } elseif ('Meta' === $k) { + $n->setMeta($v); + } else { + $n->{$k} = $v; + } + } + return $n; + } + + public function jsonSerialize(): \stdClass + { + $out = $this->_startJsonSerialize(); + $out->Kind = $this->Kind; + $out->Name = $this->Name; + if ('' !== $this->Partition) { + $out->Partition = $this->Partition; + } + if ('' !== $this->Namespace) { + $out->Namespace = $this->Namespace; + } + if ('' !== $this->Protocol) { + $out->Protocol = $this->Protocol; + } + if (ProxyMode::Default !== $this->Mode) { + $out->Mode = $this->Mode->value; + } + if (null !== $this->TransparentProxy) { + $out->TransparentProxy = $this->TransparentProxy; + } + if (MutualTLSMode::Default !== $this->MutualTLSMode) { + $out->MutualTLSMode = $this->MutualTLSMode->value; + } + _enc_obj_if_valued($out, 'MeshGateway', $this->MeshGateway); + _enc_obj_if_valued($out, 'Expose', $this->Expose); + if ('' !== $this->ExternalSNI) { + $out->ExternalSNI = $this->ExternalSNI; + } + if (null !== $this->UpstreamConfig) { + $out->UpstreamConfig = $this->UpstreamConfig; + } + if (null !== $this->Destination) { + $out->Destination = $this->Destination; + } + if (0 !== $this->MaxInboundConnections) { + $out->MaxInboundConnections = $this->MaxInboundConnections; + } + if (0 !== $this->LocalConnectTimeoutMs) { + $out->LocalConnectTimeoutMs = $this->LocalConnectTimeoutMs; + } + if (0 !== $this->LocalRequestTimeoutMs) { + $out->LocalRequestTimeoutMs = $this->LocalRequestTimeoutMs; + } + if ('' !== $this->BalanceInboundConnections) { + $out->BalanceInboundConnections = $this->BalanceInboundConnections; + } + if (null !== $this->RateLimits) { + $out->RateLimits = $this->RateLimits; + } + if ([] !== $this->EnvoyExtensions) { + $out->EnvoyExtensions = $this->EnvoyExtensions; + } + if ([] !== $this->Meta) { + $out->Meta = $this->Meta; + } + $out->CreateIndex = $this->CreateIndex; + $out->ModifyIndex = $this->ModifyIndex; + return $out; + } } diff --git a/src/ConfigEntry/ServiceIntentionsConfigEntry.php b/src/ConfigEntry/ServiceIntentionsConfigEntry.php new file mode 100644 index 00000000..741086f4 --- /dev/null +++ b/src/ConfigEntry/ServiceIntentionsConfigEntry.php @@ -0,0 +1,176 @@ + */ + public array $Sources; + public null|IntentionJWTRequirement $JWT; + + /** + * @param array $Sources + * @param array $Meta + */ + public function __construct( + string $Kind = '', + string $name = '', + string $Partition = '', + string $Namespace = '', + array $Sources = [], + null|IntentionJWTRequirement $JWT = null, + array $Meta = null, + int $CreateIndex = 0, + int $ModifyIndex = 0, + ) { + $this->Kind = $Kind; + $this->name = $name; + $this->Partition = $Partition; + $this->Namespace = $Namespace; + $this->setSources(...$Sources); + $this->JWT = $JWT; + $this->setMeta($Meta); + $this->CreateIndex = $CreateIndex; + $this->ModifyIndex = $ModifyIndex; + } + + public function getKind(): string + { + return $this->Kind; + } + + public function setKind(string $Kind): self + { + $this->Kind = $Kind; + return $this; + } + + public function getName(): string + { + return $this->name; + } + + public function setName(string $name): self + { + $this->name = $name; + return $this; + } + + public function getPartition(): string + { + return $this->Partition; + } + + public function setPartition(string $Partition): self + { + $this->Partition = $Partition; + return $this; + } + + public function getNamespace(): string + { + return $this->Namespace; + } + + public function setNamespace(string $Namespace): self + { + $this->Namespace = $Namespace; + return $this; + } + + /** + * @return array + */ + public function getSources(): array + { + return $this->Sources; + } + + public function setSources(null|SourceIntention ...$Sources): self + { + $this->Sources = $Sources; + return $this; + } + + public function getJWT(): null|IntentionJWTRequirement + { + return $this->JWT; + } + + public function setJWT(null|IntentionJWTRequirement $JWT): self + { + $this->JWT = $JWT; + return $this; + } + + public static function jsonUnserialize(\stdClass $decoded): self + { + $n = new self(); + foreach ((array)$decoded as $k => $v) { + if ('Sources' === $k) { + $n->Sources = []; + foreach ($v as $vv) { + $n->Sources[] = null === $vv ? null : SourceIntention::jsonUnserialize($vv); + } + } elseif ('JWT' === $k) { + $n->JWT = null === $v ? null : IntentionJWTRequirement::jsonUnserialize($v); + } elseif ('Meta' === $k) { + $n->setMeta($v); + } else { + $n->{$k} = $v; + } + } + return $n; + } + + public function jsonSerialize(): \stdClass + { + $out = $this->_startJsonSerialize(); + $out->Kind = $this->Kind; + $out->Name = $this->name; + if ('' !== $this->Partition) { + $out->Partition = $this->Partition; + } + if ('' !== $this->Namespace) { + $out->Namespace = $this->Namespace; + } + if ([] !== $this->Sources) { + $out->Sources = $this->Sources; + } + if (null !== $this->JWT) { + $out->JWT = $this->JWT; + } + if (null !== $this->Meta) { + $out->Meta = $this->Meta; + } + $out->CreateIndex = $this->CreateIndex; + $out->ModifyIndex = $this->ModifyIndex; + return $out; + } +} diff --git a/src/ConfigEntry/ServiceResolverConfigEntry.php b/src/ConfigEntry/ServiceResolverConfigEntry.php index 7766fbd2..0d35b3e6 100644 --- a/src/ConfigEntry/ServiceResolverConfigEntry.php +++ b/src/ConfigEntry/ServiceResolverConfigEntry.php @@ -20,16 +20,303 @@ limitations under the License. */ -use DCarbone\PHPConsulAPI\AbstractModel; +use DCarbone\Go\Time; +use DCarbone\PHPConsulAPI\PHPLib\AbstractType; -class ServiceResolverConfigEntry extends AbstractModel implements ConfigEntry +class ServiceResolverConfigEntry extends AbstractType implements ConfigEntry { use ConfigEntryTrait; - private const FIELD_DEFAULT_SUBSET = 'DefaultSubset'; - private const FIELD_SUBSETS = 'Subsets'; - private const FIELD_REDIRECT = 'Redirect'; - private const FIELD_FAILOVER = 'Failover'; - private const FIELD_CONNECT_TIMEOUT = 'ConnectTimeout'; - private const FIELD_LOAD_BALANCER = 'LoadBalancer'; + public string $Kind; + public string $Name; + public string $Partition; + public string $DefaultSubset; + /** @var null|array */ + public null|array $Subsets = null; + public null|ServiceResolverRedirect $Redirect; + /** @var null|array */ + public null|array $Failover = null; + public Time\Duration $ConnectTimeout; + public Time\Duration $RequestTimeout; + public null|ServiceResolverPrioritizeByLocality $PrioritizeByLocality; + public null|LoadBalancer $LoadBalancer; + + /** + * @param null|array $Subsets + * @param null|array $Failover + * @param null|array $Meta + */ + public function __construct( + string $Kind = '', + string $Name = '', + string $Partition = '', + string $Namespace = '', + string $DefaultSubnet = '', + null|array $Subsets = null, + null|ServiceResolverRedirect $Redirect = null, + null|array $Failover = null, + null|string|int|float|\DateInterval|Time\Duration $ConnectTimeout = null, + null|string|int|float|\DateInterval|Time\Duration $RequestTimeout = null, + null|ServiceResolverPrioritizeByLocality $PrioritizeByLocality = null, + null|LoadBalancer $LoadBalancer = null, + null|array $Meta = null, + int $CreateIndex = 0, + int $ModifyIndex = 0, + ) { + $this->Kind = $Kind; + $this->Name = $Name; + $this->Partition = $Partition; + $this->Namespace = $Namespace; + $this->DefaultSubset = $DefaultSubnet; + $this->setSubsets($Subsets); + $this->Redirect = $Redirect; + $this->setFailover($Failover); + $this->ConnectTimeout = Time::Duration($ConnectTimeout); + $this->RequestTimeout = Time::Duration($RequestTimeout); + $this->PrioritizeByLocality = $PrioritizeByLocality; + $this->LoadBalancer = $LoadBalancer; + $this->setMeta($Meta); + $this->CreateIndex = $CreateIndex; + $this->ModifyIndex = $ModifyIndex; + } + + public function getKind(): string + { + return $this->Kind; + } + + public function setKind(string $Kind): self + { + $this->Kind = $Kind; + return $this; + } + + + public function getName(): string + { + return $this->Name; + } + + public function setName(string $Name): self + { + $this->Name = $Name; + return $this; + } + + public function getPartition(): string + { + return $this->Partition; + } + + public function setPartition(string $Partition): self + { + $this->Partition = $Partition; + return $this; + } + + public function getDefaultSubset(): string + { + return $this->DefaultSubset; + } + + public function setDefaultSubset(string $DefaultSubset): self + { + $this->DefaultSubset = $DefaultSubset; + return $this; + } + + /** + * @return null|array + */ + public function getSubsets(): null|array + { + return $this->Subsets; + } + + public function setSubsetKey(string $key, ServiceResolverSubset $subset): self + { + if (null === $this->Subsets) { + $this->Subsets = []; + } + $this->Subsets[$key] = $subset; + return $this; + } + + /** + * @param null|array $Subsets + */ + public function setSubsets(null|array $Subsets): self + { + $this->Subsets = null; + if (null === $Subsets) { + return $this; + } + foreach ($Subsets as $k => $v) { + $this->setSubsetKey($k, $v); + } + return $this; + } + + public function getRedirect(): null|ServiceResolverRedirect + { + return $this->Redirect; + } + + public function setRedirect(null|ServiceResolverRedirect $Redirect): self + { + $this->Redirect = $Redirect; + return $this; + } + + /** + * @return null|array + */ + public function getFailover(): null|array + { + return $this->Failover; + } + + public function setFailoverKey(string $key, ServiceResolverFailover $failover): self + { + if (null === $this->Failover) { + $this->Failover = []; + } + $this->Failover[$key] = $failover; + return $this; + } + + /** + * @param null|array $Failover + */ + public function setFailover(null|array $Failover): self + { + $this->Failover = null; + if (null === $Failover) { + return $this; + } + foreach ($Failover as $k => $v) { + $this->setFailoverKey($k, $v); + } + return $this; + } + + public function getConnectTimeout(): Time\Duration + { + return $this->ConnectTimeout; + } + + public function setConnectTimeout(Time\Duration $ConnectTimeout): self + { + $this->ConnectTimeout = $ConnectTimeout; + return $this; + } + + public function getRequestTimeout(): Time\Duration + { + return $this->RequestTimeout; + } + + public function setRequestTimeout(Time\Duration $RequestTimeout): self + { + $this->RequestTimeout = $RequestTimeout; + return $this; + } + + public function getPrioritizeByLocality(): null|ServiceResolverPrioritizeByLocality + { + return $this->PrioritizeByLocality; + } + + public function setPrioritizeByLocality(null|ServiceResolverPrioritizeByLocality $PrioritizeByLocality): self + { + $this->PrioritizeByLocality = $PrioritizeByLocality; + return $this; + } + + public function getLoadBalancer(): null|LoadBalancer + { + return $this->LoadBalancer; + } + + public function setLoadBalancer(null|LoadBalancer $LoadBalancer): self + { + $this->LoadBalancer = $LoadBalancer; + return $this; + } + + public static function jsonUnserialize(\stdClass $decoded): self + { + $n = new self(); + foreach ((array)$decoded as $k => $v) { + if ('default_subset' === $k) { + $n->DefaultSubset = $v; + } elseif ('Subsets' === $k) { + foreach ($v as $kk => $vv) { + $n->setSubsetKey($kk, ServiceResolverSubset::jsonUnserialize($vv)); + } + } elseif ('Redirect' === $k) { + $n->Redirect = ServiceResolverRedirect::jsonUnserialize($v); + } elseif ('Failover' === $k) { + foreach ($v as $kk => $vv) { + $n->setFailoverKey($kk, ServiceResolverFailover::jsonUnserialize($vv)); + } + } elseif ('ConnectTimeout' === $k || 'connect_timeout' === $k) { + $n->ConnectTimeout = Time::ParseDuration($v); + } elseif ('RequestTimeout' === $k || 'request_timeout' === $k) { + $n->RequestTimeout = Time::ParseDuration($v); + } elseif ('PrioritizeByLocality' === $k || 'prioritize_by_locality' === $k) { + $n->PrioritizeByLocality = ServiceResolverPrioritizeByLocality::jsonUnserialize($v); + } elseif ('LoadBalancer' === $k || 'load_balancer' === $k) { + $n->LoadBalancer = LoadBalancer::jsonUnserialize($v); + } elseif ('Meta' === $k) { + $n->setMeta($v); + } else { + $n->{$k} = $v; + } + } + return $n; + } + + public function jsonSerialize(): \stdClass + { + $out = $this->_startJsonSerialize(); + $out->Kind = $this->Kind; + $out->Name = $this->Name; + if ('' !== $this->Partition) { + $out->Partition = $this->Partition; + } + if ('' !== $this->Namespace) { + $out->Namespace = $this->Namespace; + } + if ('' !== $this->DefaultSubset) { + $out->DefaultSubset = $this->DefaultSubset; + } + if (null !== $this->Subsets) { + $out->Subsets = $this->Subsets; + } + if (null !== $this->Redirect) { + $out->Redirect = $this->Redirect; + } + if (null !== $this->Failover) { + $out->Failover = $this->Failover; + } + if (0 !== $this->ConnectTimeout->Nanoseconds()) { + $out->ConnectTimeout = (string)$this->ConnectTimeout; + } + if (0 !== $this->RequestTimeout->Nanoseconds()) { + $out->RequestTimeout = (string)$this->RequestTimeout; + } + if (null !== $this->PrioritizeByLocality) { + $out->PrioritizeByLocality = $this->PrioritizeByLocality; + } + if (null !== $this->LoadBalancer) { + $out->LoadBalancer = $this->LoadBalancer; + } + if (null !== $this->Meta) { + $out->Meta = $this->Meta; + } + $out->CreateIndex = $this->CreateIndex; + $out->ModifyIndex = $this->ModifyIndex; + return $out; + } } diff --git a/src/ConfigEntry/ServiceResolverFailover.php b/src/ConfigEntry/ServiceResolverFailover.php index 54fad4ca..f8ba23c7 100644 --- a/src/ConfigEntry/ServiceResolverFailover.php +++ b/src/ConfigEntry/ServiceResolverFailover.php @@ -20,27 +20,41 @@ limitations under the License. */ -use DCarbone\PHPConsulAPI\AbstractModel; -use DCarbone\PHPConsulAPI\Transcoding; +use DCarbone\PHPConsulAPI\PHPLib\AbstractType; -class ServiceResolverFailover extends AbstractModel +class ServiceResolverFailover extends AbstractType { - protected const FIELDS = [ - self::FIELD_SERVICE => Transcoding::OMITEMPTY_STRING_FIELD, - self::FIELD_SERVICE_SUBSET => Transcoding::OMITEMPTY_STRING_FIELD, - self::FIELD_NAMESPACE => Transcoding::OMITEMPTY_STRING_FIELD, - self::FIELD_DATACENTERS => Transcoding::OMITEMPTY_STRING_ARRAY_FIELD, - ]; - - private const FIELD_SERVICE = 'Service'; - private const FIELD_SERVICE_SUBSET = 'ServiceSubset'; - private const FIELD_NAMESPACE = 'Namespace'; - private const FIELD_DATACENTERS = 'Datacenters'; - - public string $Service = ''; - public string $ServiceSubset = ''; - public string $Namespace = ''; - public array $Datacenters = []; + public string $Service; + public string $ServiceSubset; + public string $Namespace; + /** @var array */ + public array $Datacenters; + /** @var array<\DCarbone\PHPConsulAPI\ConfigEntry\ServiceResolverFailoverTarget> */ + public array $Targets; + public null|ServiceResolverFailoverPolicy $Policy; + public string $SamenessGroup; + + /** + * @param array $Datacenters + * @param array<\DCarbone\PHPConsulAPI\ConfigEntry\ServiceResolverFailoverTarget> $Targets + */ + public function __construct( + string $Service = '', + string $ServiceSubset = '', + string $Namespace = '', + array $Datacenters = [], + array $Targets = [], + null|ServiceResolverFailoverPolicy $Policy = null, + string $SamenessGroup = '' + ) { + $this->Service = $Service; + $this->ServiceSubset = $ServiceSubset; + $this->Namespace = $Namespace; + $this->setDatacenters(...$Datacenters); + $this->setTargets(...$Targets); + $this->Policy = $Policy; + $this->SamenessGroup = $SamenessGroup; + } public function getService(): string { @@ -75,14 +89,100 @@ public function setNamespace(string $Namespace): self return $this; } + /** + * @return array + */ public function getDatacenters(): array { return $this->Datacenters; } - public function setDatacenters(array $Datacenters): self + public function setDatacenters(string ...$Datacenters): self { $this->Datacenters = $Datacenters; return $this; } + + /** + * @return array<\DCarbone\PHPConsulAPI\ConfigEntry\ServiceResolverFailoverTarget> + */ + public function getTargets(): array + { + return $this->Targets; + } + + public function setTargets(ServiceResolverFailoverTarget ...$Targets): self + { + $this->Targets = $Targets; + return $this; + } + + public function getPolicy(): null|ServiceResolverFailoverPolicy + { + return $this->Policy; + } + + public function setPolicy(null|ServiceResolverFailoverPolicy $Policy): self + { + $this->Policy = $Policy; + return $this; + } + + public function getSamenessGroup(): string + { + return $this->SamenessGroup; + } + + public function setSamenessGroup(string $SamenessGroup): self + { + $this->SamenessGroup = $SamenessGroup; + return $this; + } + + public static function jsonUnserialize(\stdClass $decoded): self + { + $n = new self(); + foreach ((array)$decoded as $k => $v) { + if ('Targtes' === $k) { + $n->Targets = []; + foreach ($v as $vv) { + $n->Targets[] = ServiceResolverFailoverTarget::jsonUnserialize($vv); + } + } elseif ('service_subset' === $k) { + $n->ServiceSubset = $v; + } elseif ('sameness_group' === $k) { + $n->SamenessGroup = $v; + } else { + $n->{$k} = $v; + } + } + return $n; + } + + public function jsonSerialize(): \stdClass + { + $out = $this->_startJsonSerialize(); + if ('' !== $this->Service) { + $out->Service = $this->Service; + } + if ('' !== $this->ServiceSubset) { + $out->ServiceSubset = $this->ServiceSubset; + } + if ('' !== $this->Namespace) { + $out->Namespace = $this->Namespace; + } + if ([] !== $this->Datacenters) { + $out->Datacenters = $this->Datacenters; + } + if ([] !== $this->Targets) { + $out->Targets = $this->Targets; + } + if (null !== $this->Policy) { + $out->Policy = $this->Policy; + } + if ('' !== $this->SamenessGroup) { + $out->SamenessGroup = $this->SamenessGroup; + } + return $out; + } } diff --git a/src/ConfigEntry/ServiceResolverFailoverPolicy.php b/src/ConfigEntry/ServiceResolverFailoverPolicy.php new file mode 100644 index 00000000..f74e52fb --- /dev/null +++ b/src/ConfigEntry/ServiceResolverFailoverPolicy.php @@ -0,0 +1,85 @@ + */ + public array $Regions; + + /** + * @param array $Regions + */ + public function __construct(string $Mode = '', array $Regions = []) + { + $this->Mode = $Mode; + $this->Regions = $Regions; + } + + public function getMode(): string + { + return $this->Mode; + } + + public function setMode(string $Mode): self + { + $this->Mode = $Mode; + return $this; + } + + /** + * @return array + */ + public function getRegions(): array + { + return $this->Regions; + } + + public function setRegions(string ...$Regions): self + { + $this->Regions = $Regions; + return $this; + } + + public static function jsonUnserialize(\stdClass $decoded): self + { + $n = new self(); + foreach ((array)$decoded as $k => $v) { + $n->{$k} = $v; + } + return $n; + } + + public function jsonSerialize(): \stdClass + { + $out = $this->_startJsonSerialize(); + if ('' !== $this->Mode) { + $out->Mode = $this->Mode; + } + if ([] !== $this->Regions) { + $out->Regions = $this->Regions; + } + return $out; + } +} \ No newline at end of file diff --git a/src/ConfigEntry/ServiceResolverFailoverTarget.php b/src/ConfigEntry/ServiceResolverFailoverTarget.php new file mode 100644 index 00000000..25c58710 --- /dev/null +++ b/src/ConfigEntry/ServiceResolverFailoverTarget.php @@ -0,0 +1,140 @@ +Service = $Service; + $this->ServiceSubset = $ServiceSubset; + $this->Partition = $Partition; + $this->Namespace = $Namespace; + $this->Datacenter = $Datacenter; + $this->Peer = $Peer; + } + + public function getService(): string + { + return $this->Service; + } + + public function setService(string $Service): self + { + $this->Service = $Service; + return $this; + } + + public function getServiceSubset(): string + { + return $this->ServiceSubset; + } + + public function setServiceSubset(string $ServiceSubset): self + { + $this->ServiceSubset = $ServiceSubset; + return $this; + } + + public function getPartition(): string + { + return $this->Partition; + } + + public function setPartition(string $Partition): self + { + $this->Partition = $Partition; + return $this; + } + + public function getNamespace(): string + { + return $this->Namespace; + } + + public function setNamespace(string $Namespace): self + { + $this->Namespace = $Namespace; + return $this; + } + + public function getDatacenter(): string + { + return $this->Datacenter; + } + + public function setDatacenter(string $Datacenter): self + { + $this->Datacenter = $Datacenter; + return $this; + } + + public function getPeer(): string + { + return $this->Peer; + } + + public function setPeer(string $Peer): self + { + $this->Peer = $Peer; + return $this; + } + + public static function jsonUnserialize(\stdClass $decoded): self + { + $n = new self(); + foreach ((array)$decoded as $k => $v) { + if ('service_subset' === $k) { + $n->ServiceSubset = $v; + } else { + $n->{$k} = $v; + } + } + return $n; + } + + public function jsonSerialize(): \stdClass + { + $out = $this->_startJsonSerialize(); + $out->Service = $this->Service; + $out->ServiceSubset = $this->ServiceSubset; + $out->Partition = $this->Partition; + $out->Namespace = $this->Namespace; + $out->Datacenter = $this->Datacenter; + $out->Peer = $this->Peer; + return $out; + } +} diff --git a/src/ConfigEntry/ServiceResolverPrioritizeByLocality.php b/src/ConfigEntry/ServiceResolverPrioritizeByLocality.php new file mode 100644 index 00000000..b22a4bce --- /dev/null +++ b/src/ConfigEntry/ServiceResolverPrioritizeByLocality.php @@ -0,0 +1,62 @@ +Mode = $Mode; + } + + public function getMode(): string + { + return $this->Mode; + } + + public function setMode(string $Mode): self + { + $this->Mode = $Mode; + return $this; + } + + public static function jsonUnserialize(\stdClass $decoded): self + { + $n = new self(); + foreach ((array)$decoded as $k => $v) { + $n->{$k} = $v; + } + return $n; + } + + public function jsonSerialize(): \stdClass + { + $out = $this->_startJsonSerialize(); + if ('' !== $this->Mode) { + $out->Mode = $this->Mode; + } + return $out; + } +} \ No newline at end of file diff --git a/src/ConfigEntry/ServiceResolverRedirect.php b/src/ConfigEntry/ServiceResolverRedirect.php index a8410274..103f38e7 100644 --- a/src/ConfigEntry/ServiceResolverRedirect.php +++ b/src/ConfigEntry/ServiceResolverRedirect.php @@ -20,27 +20,35 @@ limitations under the License. */ -use DCarbone\PHPConsulAPI\AbstractModel; -use DCarbone\PHPConsulAPI\Transcoding; +use DCarbone\PHPConsulAPI\PHPLib\AbstractType; -class ServiceResolverRedirect extends AbstractModel +class ServiceResolverRedirect extends AbstractType { - protected const FIELDS = [ - self::FIELD_SERVICE => Transcoding::OMITEMPTY_STRING_FIELD, - self::FIELD_SERVICE_SUBSET => Transcoding::OMITEMPTY_STRING_FIELD, - self::FIELD_NAMESPACE => Transcoding::OMITEMPTY_STRING_FIELD, - self::FIELD_DATACENTER => Transcoding::OMITEMPTY_STRING_FIELD, - ]; - - private const FIELD_SERVICE = 'Service'; - private const FIELD_SERVICE_SUBSET = 'ServiceSubset'; - private const FIELD_NAMESPACE = 'Namespace'; - private const FIELD_DATACENTER = 'Datacenter'; - - public string $Service = ''; - public string $ServiceSubset = ''; - public string $Namespace = ''; - public string $Datacenter = ''; + public string $Service; + public string $ServiceSubset; + public string $Namespace; + public string $Partition; + public string $Datacenter; + public string $Peer; + public string $SamenessGroup; + + public function __construct( + string $Service = '', + string $ServiceSubset = '', + string $Namespace = '', + string $Partition = '', + string $Datacenter = '', + string $Peer = '', + string $SamenessGroup = '' + ) { + $this->Service = $Service; + $this->ServiceSubset = $ServiceSubset; + $this->Namespace = $Namespace; + $this->Partition = $Partition; + $this->Datacenter = $Datacenter; + $this->Peer = $Peer; + $this->SamenessGroup = $SamenessGroup; + } public function getService(): string { @@ -75,6 +83,17 @@ public function setNamespace(string $Namespace): self return $this; } + public function getPartition(): string + { + return $this->Partition; + } + + public function setPartition(string $Partition): self + { + $this->Partition = $Partition; + return $this; + } + public function getDatacenter(): string { return $this->Datacenter; @@ -85,4 +104,68 @@ public function setDatacenter(string $Datacenter): self $this->Datacenter = $Datacenter; return $this; } + + public function getPeer(): string + { + return $this->Peer; + } + + public function setPeer(string $Peer): self + { + $this->Peer = $Peer; + return $this; + } + + public function getSamenessGroup(): string + { + return $this->SamenessGroup; + } + + public function setSamenessGroup(string $SamenessGroup): self + { + $this->SamenessGroup = $SamenessGroup; + return $this; + } + + public static function jsonUnserialize(\stdClass $decoded): self + { + $n = new self(); + foreach ((array)$decoded as $k => $v) { + if ('service_subset' === $k) { + $n->ServiceSubset = $v; + } elseif ('sameness_group' === $k) { + $n->SamenessGroup = $v; + } else { + $n->{$k} = $v; + } + } + return $n; + } + + public function jsonSerialize(): \stdClass + { + $out = $this->_startJsonSerialize(); + if ('' !== $this->Service) { + $out->Service = $this->Service; + } + if ('' !== $this->ServiceSubset) { + $out->service_subset = $this->ServiceSubset; + } + if ('' !== $this->Namespace) { + $out->Namespace = $this->Namespace; + } + if ('' !== $this->Partition) { + $out->Partition = $this->Partition; + } + if ('' !== $this->Datacenter) { + $out->Datacenter = $this->Datacenter; + } + if ('' !== $this->Peer) { + $out->Peer = $this->Peer; + } + if ('' !== $this->SamenessGroup) { + $out->sameness_group = $this->SamenessGroup; + } + return $out; + } } diff --git a/src/ConfigEntry/ServiceResolverSubset.php b/src/ConfigEntry/ServiceResolverSubset.php index 7a1f8909..04347677 100644 --- a/src/ConfigEntry/ServiceResolverSubset.php +++ b/src/ConfigEntry/ServiceResolverSubset.php @@ -20,21 +20,18 @@ limitations under the License. */ -use DCarbone\PHPConsulAPI\AbstractModel; -use DCarbone\PHPConsulAPI\Transcoding; +use DCarbone\PHPConsulAPI\PHPLib\AbstractType; -class ServiceResolverSubset extends AbstractModel +class ServiceResolverSubset extends AbstractType { - protected const FIELDS = [ - self::FIELD_FILTER => Transcoding::OMITEMPTY_STRING_FIELD, - self::FIELD_ONLY_PASSING => Transcoding::OMITEMPTY_BOOLEAN_FIELD, - ]; + public string $Filter; + public bool $OnlyPassing; - private const FIELD_FILTER = 'Filter'; - private const FIELD_ONLY_PASSING = 'OnlyPassing'; - - public string $Filter = ''; - public bool $OnlyPassing = false; + public function __construct(string $Filter = '', bool $OnlyPassing = false) + { + $this->Filter = $Filter; + $this->OnlyPassing = $OnlyPassing; + } public function getFilter(): string { @@ -57,4 +54,29 @@ public function setOnlyPassing(bool $OnlyPassing): self $this->OnlyPassing = $OnlyPassing; return $this; } + + public static function jsonUnserialize(\stdClass $decoded): self + { + $n = new self(); + foreach ((array)$decoded as $k => $v) { + if ('only_passing' === $k) { + $n->OnlyPassing = $v; + } else { + $n->{$k} = $v; + } + } + return $n; + } + + public function jsonSerialize(): \stdClass + { + $out = $this->_startJsonSerialize(); + if ('' !== $this->Filter) { + $out->Filter = $this->Filter; + } + if ($this->OnlyPassing) { + $out->OnlyPassing = $this->OnlyPassing; + } + return $out; + } } diff --git a/src/ConfigEntry/ServiceRoute.php b/src/ConfigEntry/ServiceRoute.php index c8c60400..f5df8c1d 100644 --- a/src/ConfigEntry/ServiceRoute.php +++ b/src/ConfigEntry/ServiceRoute.php @@ -20,12 +20,67 @@ limitations under the License. */ -use DCarbone\PHPConsulAPI\AbstractModel; +use DCarbone\PHPConsulAPI\PHPLib\AbstractType; -class ServiceRoute extends AbstractModel +class ServiceRoute extends AbstractType { - protected const FIELDS = []; + public null|ServiceRouteMatch $Match; + public null|ServiceRouteDestination $Destination; - private const FIELD_MATCH = 'Match'; - private const FIELD_DESTINATION = 'Destination'; + public function __construct( + null|ServiceRouteMatch $Match = null, + null|ServiceRouteDestination $Destination = null, + ) { + $this->Match = $Match; + $this->Destination = $Destination; + } + + public function getMatch(): null|ServiceRouteMatch + { + return $this->Match; + } + + public function setMatch(null|ServiceRouteMatch $Match): self + { + $this->Match = $Match; + return $this; + } + + public function getDestination(): null|ServiceRouteDestination + { + return $this->Destination; + } + + public function setDestination(null|ServiceRouteDestination $Destination): self + { + $this->Destination = $Destination; + return $this; + } + + public static function jsonUnserialize(\stdClass $decoded): self + { + $n = new self(); + foreach ((array)$decoded as $k => $v) { + if ('Match' === $k) { + $n->Match = null === $v ? null : ServiceRouteMatch::jsonUnserialize($v); + } elseif ('Destination' === $k) { + $n->Destination = null === $v ? null : ServiceRouteDestination::jsonUnserialize($v); + } else { + $n->{$k} = $v; + } + } + return $n; + } + + public function jsonSerialize(): \stdClass + { + $out = $this->_startJsonSerialize(); + if (null !== $this->Match) { + $out->Match = $this->Match; + } + if (null !== $this->Destination) { + $out->Destination = $this->Destination; + } + return $out; + } } diff --git a/src/ConfigEntry/ServiceRouteDestination.php b/src/ConfigEntry/ServiceRouteDestination.php index 22db2b68..f2d45a37 100644 --- a/src/ConfigEntry/ServiceRouteDestination.php +++ b/src/ConfigEntry/ServiceRouteDestination.php @@ -21,42 +21,59 @@ */ use DCarbone\Go\Time; -use DCarbone\PHPConsulAPI\AbstractModel; -use DCarbone\PHPConsulAPI\Transcoding; +use DCarbone\PHPConsulAPI\PHPLib\AbstractType; -class ServiceRouteDestination extends AbstractModel +class ServiceRouteDestination extends AbstractType { - protected const FIELDS = [ - self::FIELD_SERVICE => Transcoding::OMITEMPTY_STRING_FIELD, - self::FIELD_SERVICE_SUBSET => Transcoding::OMITEMPTY_STRING_FIELD, - self::FIELD_NAMESPACE => Transcoding::OMITEMPTY_STRING_FIELD, - self::FIELD_PREFIX_REWRITE => Transcoding::OMITEMPTY_STRING_FIELD, - self::FIELD_REQUEST_TIMEOUT => Transcoding::DURATION_FIELD + [ - Transcoding::FIELD_UNMARSHAL_AS => Transcoding::STRING, - Transcoding::FIELD_OMITEMPTY => true, - ], - self::FIELD_NUM_RETRIES => Transcoding::OMITEMPTY_INTEGER_FIELD, - self::FIELD_RETRY_ON_CONNECT_FAILURE => Transcoding::OMITEMPTY_BOOLEAN_FIELD, - self::FIELD_RETRY_ON_STATUS_CODES => Transcoding::OMITEMPTY_INTEGER_ARRAY_FIELD, - ]; - - private const FIELD_SERVICE = 'Service'; - private const FIELD_SERVICE_SUBSET = 'ServiceSubset'; - private const FIELD_NAMESPACE = 'Namespace'; - private const FIELD_PREFIX_REWRITE = 'PrefixRewrite'; - private const FIELD_REQUEST_TIMEOUT = 'RequestTimeout'; - private const FIELD_NUM_RETRIES = 'NumRetries'; - private const FIELD_RETRY_ON_CONNECT_FAILURE = 'RetryOnConnectFailure'; - private const FIELD_RETRY_ON_STATUS_CODES = 'RetryOnStatusCodes'; - - public string $Service = ''; - public string $ServiceSubset = ''; - public string $Namespace = ''; - public string $PrefixRewrite = ''; + public string $Service; + public string $ServiceSubset; + public string $Namespace; + public string $Partition; + public string $PrefixRewrite; public Time\Duration $RequestTimeout; - public int $NumRetries = 0; - public bool $RetryOnConnectFailure = false; - public array $RetryOnStatusCodes = []; + public Time\Duration $IdleTimeout; + public int $NumRetries; + public bool $RetryOnConnectFailure; + /** @var array */ + public array $RetryOnStatusCodes; + /** @var array */ + public array $RetryOn; + public null|HTTPHeaderModifiers $RequestHeaders; + public null|HTTPHeaderModifiers $ResponseHeaders; + + /** + * @param array $RetryOnStatusCodes + * @param array $RetryOn + */ + public function __construct( + string $Service = '', + string $ServiceSubset = '', + string $Namespace = '', + string $Partition = '', + string $PrefixRewrite = '', + null|string|int|float|\DateInterval|Time\Duration $RequestTimeout = null, + null|string|int|float|\DateInterval|Time\Duration $IdleTimeout = null, + int $NumRetries = 0, + bool $RetryOnConnectFailure = false, + array $RetryOnStatusCodes = [], + array $RetryOn = [], + null|HTTPHeaderModifiers $RequestHeaders = null, + null|HTTPHeaderModifiers $ResponseHeaders = null, + ) { + $this->Service = $Service; + $this->ServiceSubset = $ServiceSubset; + $this->Namespace = $Namespace; + $this->Partition = $Partition; + $this->PrefixRewrite = $PrefixRewrite; + $this->RequestTimeout = Time::Duration($RequestTimeout); + $this->IdleTimeout = Time::Duration($IdleTimeout); + $this->NumRetries = $NumRetries; + $this->RetryOnConnectFailure = $RetryOnConnectFailure; + $this->setRetryOnStatusCodes(...$RetryOnStatusCodes); + $this->setRetryOn(...$RetryOn); + $this->RequestHeaders = $RequestHeaders; + $this->ResponseHeaders = $ResponseHeaders; + } public function getService(): string { @@ -91,6 +108,17 @@ public function setNamespace(string $Namespace): self return $this; } + public function getPartition(): string + { + return $this->Partition; + } + + public function setPartition(string $Partition): self + { + $this->Partition = $Partition; + return $this; + } + public function getPrefixRewrite(): string { return $this->PrefixRewrite; @@ -107,9 +135,20 @@ public function getRequestTimeout(): Time\Duration return $this->RequestTimeout; } - public function setRequestTimeout(Time\Duration $RequestTimeout): self + public function setRequestTimeout(null|string|int|float|\DateInterval|Time\Duration $RequestTimeout): self + { + $this->RequestTimeout = Time::Duration($RequestTimeout); + return $this; + } + + public function getIdleTimeout(): Time\Duration { - $this->RequestTimeout = $RequestTimeout; + return $this->IdleTimeout; + } + + public function setIdleTimeout(null|string|int|float|\DateInterval|Time\Duration $IdleTimeout): self + { + $this->IdleTimeout = Time::Duration($IdleTimeout); return $this; } @@ -135,14 +174,129 @@ public function setRetryOnConnectFailure(bool $RetryOnConnectFailure): self return $this; } + /** + * @return array + */ public function getRetryOnStatusCodes(): array { return $this->RetryOnStatusCodes; } - public function setRetryOnStatusCodes(array $RetryOnStatusCodes): self + public function setRetryOnStatusCodes(int ...$RetryOnStatusCodes): self { $this->RetryOnStatusCodes = $RetryOnStatusCodes; return $this; } + + /** + * @return array + */ + public function getRetryOn(): array + { + return $this->RetryOn; + } + + public function setRetryOn(string ...$RetryOn): self + { + $this->RetryOn = $RetryOn; + return $this; + } + + public function getRequestHeaders(): null|HTTPHeaderModifiers + { + return $this->RequestHeaders; + } + + public function setRequestHeaders(null|HTTPHeaderModifiers $RequestHeaders): self + { + $this->RequestHeaders = $RequestHeaders; + return $this; + } + + public function getResponseHeaders(): null|HTTPHeaderModifiers + { + return $this->ResponseHeaders; + } + + public function setResponseHeaders(null|HTTPHeaderModifiers $ResponseHeaders): self + { + $this->ResponseHeaders = $ResponseHeaders; + return $this; + } + + public static function jsonUnserialize(\stdClass $decoded): self + { + $n = new self(); + foreach ((array)$decoded as $k => $v) { + if ('service_subset' === $k) { + $n->ServiceSubset = $v; + } elseif ('prefix_rewrite' === $k) { + $n->PrefixRewrite = $v; + } elseif ('RequestTimeout' === $k || 'request_timeout' === $k) { + $n->RequestTimeout = Time::Duration($v); + } elseif ('IdleTimeout' === $k || 'idle_timeout' === $k) { + $n->IdleTimeout = Time::Duration($v); + } elseif ('num_retries' === $k) { + $n->NumRetries = $v; + } elseif ('retry_on_connect_failure' === $k) { + $n->RetryOnConnectFailure = $v; + } elseif ('retry_on_status_codes' === $k) { + $n->RetryOnStatusCodes = $v; + } elseif ('retry_on' === $k) { + $n->RetryOn = $v; + } elseif ('RequestHeaders' === $k || 'request_headers' === $k) { + $n->RequestHeaders = null === $v ? null : HTTPHeaderModifiers::jsonUnserialize($v); + } elseif ('ResponseHeaders' === $k || 'response_headers' === $k) { + $n->ResponseHeaders = null === $v ? null : HTTPHeaderModifiers::jsonUnserialize($v); + } else { + $n->{$k} = $v; + } + } + return $n; + } + + public function jsonSerialize(): \stdClass + { + $out = $this->_startJsonSerialize(); + if ('' !== $this->Service) { + $out->Service = $this->Service; + } + if ('' !== $this->ServiceSubset) { + $out->ServiceSubset = $this->ServiceSubset; + } + if ('' !== $this->Namespace) { + $out->Namespace = $this->Namespace; + } + if ('' !== $this->Partition) { + $out->Partition = $this->Partition; + } + if ('' !== $this->PrefixRewrite) { + $out->PrefixRewrite = $this->PrefixRewrite; + } + if (0 !== $this->RequestTimeout->Nanoseconds()) { + $out->RequestTimeout = (string)$this->RequestTimeout; + } + if (0 !== $this->IdleTimeout->Nanoseconds()) { + $out->IdleTimeout = (string)$this->IdleTimeout; + } + if (0 !== $this->NumRetries) { + $out->NumRetries = $this->NumRetries; + } + if ($this->RetryOnConnectFailure) { + $out->RetryOnConnectFailure = $this->RetryOnConnectFailure; + } + if ([] !== $this->RetryOnStatusCodes) { + $out->RetryOnStatusCodes = $this->RetryOnStatusCodes; + } + if ([] !== $this->RetryOn) { + $out->RetryOn = $this->RetryOn; + } + if (null !== $this->RequestHeaders) { + $out->RequestHeaders = $this->RequestHeaders; + } + if (null !== $this->ResponseHeaders) { + $out->ResponseHeaders = $this->ResponseHeaders; + } + return $out; + } } diff --git a/src/ConfigEntry/ServiceRouteHTTPMatch.php b/src/ConfigEntry/ServiceRouteHTTPMatch.php index 6e0e4211..105637e3 100644 --- a/src/ConfigEntry/ServiceRouteHTTPMatch.php +++ b/src/ConfigEntry/ServiceRouteHTTPMatch.php @@ -20,43 +20,43 @@ limitations under the License. */ -use DCarbone\PHPConsulAPI\AbstractModel; -use DCarbone\PHPConsulAPI\Transcoding; +use DCarbone\PHPConsulAPI\PHPLib\AbstractType; -class ServiceRouteHTTPMatch extends AbstractModel +class ServiceRouteHTTPMatch extends AbstractType { - protected const FIELDS = [ - self::FIELD_PATH_EXACT => Transcoding::OMITEMPTY_STRING_FIELD, - self::FIELD_PATH_PREFIX => Transcoding::OMITEMPTY_STRING_FIELD, - self::FIELD_PATH_REGEX => Transcoding::OMITEMPTY_STRING_FIELD, - self::FIELD_HEADER => [ - Transcoding::FIELD_TYPE => Transcoding::ARRAY, - Transcoding::FIELD_CLASS => self::class, - Transcoding::FIELD_ARRAY_TYPE => Transcoding::OBJECT, - Transcoding::FIELD_OMITEMPTY => true, - ], - self::FIELD_QUERY_PARAM => [ - Transcoding::FIELD_TYPE => Transcoding::ARRAY, - Transcoding::FIELD_CLASS => ServiceRouteHTTPMatchQueryParam::class, - Transcoding::FIELD_ARRAY_TYPE => Transcoding::OBJECT, - Transcoding::FIELD_OMITEMPTY => true, - ], - self::FIELD_METHODS => Transcoding::OMITEMPTY_STRING_ARRAY_FIELD, - ]; - - private const FIELD_PATH_EXACT = 'PathExact'; - private const FIELD_PATH_PREFIX = 'PathPrefix'; - private const FIELD_PATH_REGEX = 'PathRegex'; - private const FIELD_HEADER = 'Header'; - private const FIELD_QUERY_PARAM = 'QueryParam'; - private const FIELD_METHODS = 'Methods'; - - public string $PathExact = ''; - public string $PathPrefix = ''; - public string $PathRegex = ''; - public array $Header = []; - public array $QueryParam = []; - public array $Methods = []; + public string $PathExact; + public string $PathPrefix; + public string $PathRegex; + public bool $CaseInsensitive; + /** @var array<\DCarbone\PHPConsulAPI\ConfigEntry\ServiceRouteHTTPMatchHeader> */ + public array $Header; + /** @var array<\DCarbone\PHPConsulAPI\ConfigEntry\ServiceRouteHTTPMatchQueryParam> */ + public array $QueryParam; + /** @var array */ + public array $Methods; + + /** + * @param array<\DCarbone\PHPConsulAPI\ConfigEntry\ServiceRouteHTTPMatchHeader> $Header + * @param array<\DCarbone\PHPConsulAPI\ConfigEntry\ServiceRouteHTTPMatchQueryParam> $QueryParam + * @param array $Methods + */ + public function __construct( + string $PathExact = '', + string $PathPrefix = '', + string $PathRegex = '', + bool $CaseInsensitive = false, + array $Header = [], + array $QueryParam = [], + array $Methods = [], + ) { + $this->PathExact = $PathExact; + $this->PathPrefix = $PathPrefix; + $this->PathRegex = $PathRegex; + $this->CaseInsensitive = $CaseInsensitive; + $this->setHeader(...$Header); + $this->setQueryParam(...$QueryParam); + $this->setMethods(...$Methods); + } public function getPathExact(): string { @@ -91,36 +91,101 @@ public function setPathRegex(string $PathRegex): self return $this; } + /** + * @return \DCarbone\PHPConsulAPI\ConfigEntry\ServiceRouteHTTPMatchHeader[] + */ public function getHeader(): array { return $this->Header; } - public function setHeader(array $Header): self + public function setHeader(ServiceRouteHTTPMatchHeader ...$Header): self { $this->Header = $Header; return $this; } + /** + * @return \DCarbone\PHPConsulAPI\ConfigEntry\ServiceRouteHTTPMatchQueryParam[] + */ public function getQueryParam(): array { return $this->QueryParam; } - public function setQueryParam(array $QueryParam): self + public function setQueryParam(ServiceRouteHTTPMatchQueryParam ...$QueryParam): self { $this->QueryParam = $QueryParam; return $this; } + /** + * @return string[] + */ public function getMethods(): array { return $this->Methods; } - public function setMethods(array $Methods): self + public function setMethods(string ...$Methods): self { $this->Methods = $Methods; return $this; } + + public static function jsonUnserialize(\stdClass $decoded): self + { + $n = new self(); + foreach ((array)$decoded as $k => $v) { + if ('path_exact' === $k) { + $n->PathExact = $v; + } elseif ('path_prefix' === $k) { + $n->PathPrefix = $v; + } elseif ('path_regex' === $k) { + $n->PathRegex = $v; + } elseif ('case_insensitive' === $k) { + $n->CaseInsensitive = $v; + } elseif ('Header' === $k) { + $n->Header = []; + foreach ($v as $vv) { + $n->Header[] = ServiceRouteHTTPMatchHeader::jsonUnserialize($vv); + } + } elseif ('QueryParam' === $k || 'query_param' === $k) { + $n->QueryParam = []; + foreach ($v as $vv) { + $n->QueryParam[] = ServiceRouteHTTPMatchQueryParam::jsonUnserialize($vv); + } + } else { + $n->{$k} = $v; + } + } + return $n; + } + + public function jsonSerialize(): \stdClass + { + $out = $this->_startJsonSerialize(); + if ('' !== $this->PathExact) { + $out->PathExact = $this->PathExact; + } + if ('' !== $this->PathPrefix) { + $out->PathPrefix = $this->PathPrefix; + } + if ('' !== $this->PathRegex) { + $out->PathRegex = $this->PathRegex; + } + if ($this->CaseInsensitive) { + $out->CaseInsensitive = $this->CaseInsensitive; + } + if ([] !== $this->Header) { + $out->Header = $this->Header; + } + if ([] !== $this->QueryParam) { + $out->QueryParam = $this->QueryParam; + } + if ([] !== $this->Methods) { + $out->Methods = $this->Methods; + } + return $out; + } } diff --git a/src/ConfigEntry/ServiceRouteHTTPMatchHeader.php b/src/ConfigEntry/ServiceRouteHTTPMatchHeader.php index b7181eea..1ae3c979 100644 --- a/src/ConfigEntry/ServiceRouteHTTPMatchHeader.php +++ b/src/ConfigEntry/ServiceRouteHTTPMatchHeader.php @@ -20,34 +20,35 @@ limitations under the License. */ -use DCarbone\PHPConsulAPI\AbstractModel; -use DCarbone\PHPConsulAPI\Transcoding; +use DCarbone\PHPConsulAPI\PHPLib\AbstractType; -class ServiceRouteHTTPMatchHeader extends AbstractModel +class ServiceRouteHTTPMatchHeader extends AbstractType { - protected const FIELDS = [ - self::FIELD_PRESENT => Transcoding::OMITEMPTY_BOOLEAN_FIELD, - self::FIELD_EXACT => Transcoding::OMITEMPTY_STRING_FIELD, - self::FIELD_PREFIX => Transcoding::OMITEMPTY_STRING_FIELD, - self::FIELD_SUFFIX => Transcoding::OMITEMPTY_STRING_FIELD, - self::FIELD_REGEX => Transcoding::OMITEMPTY_STRING_FIELD, - self::FIELD_INVERT => Transcoding::OMITEMPTY_BOOLEAN_FIELD, - ]; - - private const FIELD_PRESENT = 'Present'; - private const FIELD_EXACT = 'Exact'; - private const FIELD_PREFIX = 'Prefix'; - private const FIELD_SUFFIX = 'Suffix'; - private const FIELD_REGEX = 'Regex'; - private const FIELD_INVERT = 'Invert'; - - public string $Name = ''; - public bool $Present = false; - public string $Exact = ''; - public string $Prefix = ''; - public string $Suffix = ''; - public string $Regex = ''; - public bool $Invert = false; + public string $Name; + public bool $Present; + public string $Exact; + public string $Prefix; + public string $Suffix; + public string $Regex; + public bool $Invert; + + public function __construct( + string $Name = '', + bool $Present = false, + string $Exact = '', + string $Prefix = '', + string $Suffix = '', + string $Regex = '', + bool $Invert = false, + ) { + $this->Name = $Name; + $this->Present = $Present; + $this->Exact = $Exact; + $this->Prefix = $Prefix; + $this->Suffix = $Suffix; + $this->Regex = $Regex; + $this->Invert = $Invert; + } public function getName(): string { @@ -115,14 +116,48 @@ public function setRegex(string $Regex): self return $this; } - public function getInvert(): bool|string + public function getInvert(): bool { return $this->Invert; } - public function setInvert(bool|string $Invert): static + public function setInvert(bool $Invert): self { $this->Invert = $Invert; return $this; } + + public static function jsonUnserialize(\stdClass $decoded): self + { + $n = new self(); + foreach ((array)$decoded as $k => $v) { + $n->{$k} = $v; + } + return $n; + } + + public function jsonSerialize(): \stdClass + { + $out = $this->_startJsonSerialize(); + $out->Name = $this->Name; + if ($this->Present) { + $out->Present = $this->Present; + } + if ('' !== $this->Exact) { + $out->Exact = $this->Exact; + } + if ('' !== $this->Prefix) { + $out->Prefix = $this->Prefix; + } + if ('' !== $this->Suffix) { + $out->Suffix = $this->Suffix; + } + if ('' !== $this->Regex) { + $out->Regex = $this->Regex; + } + if ($this->Invert) { + $out->Invert = $this->Invert; + } + return $out; + } } diff --git a/src/ConfigEntry/ServiceRouteHTTPMatchQueryParam.php b/src/ConfigEntry/ServiceRouteHTTPMatchQueryParam.php index 0063f23b..f407f349 100644 --- a/src/ConfigEntry/ServiceRouteHTTPMatchQueryParam.php +++ b/src/ConfigEntry/ServiceRouteHTTPMatchQueryParam.php @@ -20,25 +20,26 @@ limitations under the License. */ -use DCarbone\PHPConsulAPI\AbstractModel; -use DCarbone\PHPConsulAPI\Transcoding; +use DCarbone\PHPConsulAPI\PHPLib\AbstractType; -class ServiceRouteHTTPMatchQueryParam extends AbstractModel +class ServiceRouteHTTPMatchQueryParam extends AbstractType { - protected const FIELDS = [ - self::FIELD_PRESENT => Transcoding::OMITEMPTY_BOOLEAN_FIELD, - self::FIELD_EXACT => Transcoding::OMITEMPTY_STRING_FIELD, - self::FIELD_REGEX => Transcoding::OMITEMPTY_STRING_FIELD, - ]; - - private const FIELD_PRESENT = 'Present'; - private const FIELD_EXACT = 'Exact'; - private const FIELD_REGEX = 'Regex'; - - public string $Name = ''; - public bool $Present = false; - public string $Exact = ''; - public string $Regex = ''; + public string $Name; + public bool $Present; + public string $Exact; + public string $Regex; + + public function __construct( + string $Name = '', + bool $Present = false, + string $Exact = '', + string $Regex = '', + ) { + $this->Name = $Name; + $this->Present = $Present; + $this->Exact = $Exact; + $this->Regex = $Regex; + } public function getName(): string { @@ -83,4 +84,29 @@ public function setRegex(string $Regex): self $this->Regex = $Regex; return $this; } + + public static function jsonUnserialize(\stdClass $decoded): self + { + $n = new self(); + foreach ((array)$decoded as $k => $v) { + $n->{$k} = $v; + } + return $n; + } + + public function jsonSerialize(): \stdClass + { + $out = $this->_startJsonSerialize(); + $out->Name = $this->Name; + if ($this->Present) { + $out->Present = $this->Present; + } + if ('' !== $this->Exact) { + $out->Exact = $this->Exact; + } + if ('' !== $this->Regex) { + $out->Regex = $this->Regex; + } + return $out; + } } diff --git a/src/ConfigEntry/ServiceRouteMatch.php b/src/ConfigEntry/ServiceRouteMatch.php index dfb7f5d6..c3d5877e 100644 --- a/src/ConfigEntry/ServiceRouteMatch.php +++ b/src/ConfigEntry/ServiceRouteMatch.php @@ -20,32 +20,47 @@ limitations under the License. */ -use DCarbone\PHPConsulAPI\AbstractModel; -use DCarbone\PHPConsulAPI\Transcoding; +use DCarbone\PHPConsulAPI\PHPLib\AbstractType; -class ServiceRouteMatch extends AbstractModel +class ServiceRouteMatch extends AbstractType { - protected const FIELDS = [ - self::FIELD_HTTP => [ - Transcoding::FIELD_TYPE => Transcoding::OBJECT, - Transcoding::FIELD_CLASS => ServiceRouteHTTPMatch::class, - Transcoding::FIELD_NULLABLE => true, - Transcoding::FIELD_OMITEMPTY => true, - ], - ]; + public null|ServiceRouteHTTPMatch $HTTP = null; - private const FIELD_HTTP = 'HTTP'; - - public ?ServiceRouteHTTPMatch $HTTP = null; + public function __construct(null|ServiceRouteHTTPMatch $HTTP = null) + { + $this->HTTP = $HTTP; + } - public function getHTTP(): ?ServiceRouteHTTPMatch + public function getHTTP(): null|ServiceRouteHTTPMatch { return $this->HTTP; } - public function setHTTP(?ServiceRouteHTTPMatch $HTTP): self + public function setHTTP(null|ServiceRouteHTTPMatch $HTTP): self { $this->HTTP = $HTTP; return $this; } + + public static function jsonUnserialize(\stdClass $decoded): self + { + $n = new self(); + foreach ((array)$decoded as $k => $v) { + if ('HTTP' === $k) { + $n->HTTP = ServiceRouteHTTPMatch::jsonUnserialize($v); + } else { + $n->{$k} = $v; + } + } + return $n; + } + + public function jsonSerialize(): \stdClass + { + $out = $this->_startJsonSerialize(); + if (null !== $this->HTTP) { + $out->HTTP = $this->HTTP; + } + return $out; + } } diff --git a/src/ConfigEntry/ServiceRouterConfigEntry.php b/src/ConfigEntry/ServiceRouterConfigEntry.php index 5ae2d93c..1afa0746 100644 --- a/src/ConfigEntry/ServiceRouterConfigEntry.php +++ b/src/ConfigEntry/ServiceRouterConfigEntry.php @@ -20,34 +20,126 @@ limitations under the License. */ -use DCarbone\PHPConsulAPI\AbstractModel; -use DCarbone\PHPConsulAPI\Transcoding; +use DCarbone\PHPConsulAPI\PHPLib\AbstractType; -class ServiceRouterConfigEntry extends AbstractModel implements ConfigEntry +class ServiceRouterConfigEntry extends AbstractType implements ConfigEntry { use ConfigEntryTrait; - protected const FIELDS = ConfigEntry::INTERFACE_FIELDS + [ - self::FIELD_ROUTES => [ - Transcoding::FIELD_TYPE => Transcoding::ARRAY, - Transcoding::FIELD_ARRAY_TYPE => Transcoding::OBJECT, - Transcoding::FIELD_CLASS => ServiceRoute::class, - Transcoding::FIELD_OMITEMPTY => true, - ], - ]; + public string $Kind; + public string $Name; + public string $Partition; + /** @var array<\DCarbone\PHPConsulAPI\ConfigEntry\ServiceRoute> */ + public array $Routes; - private const FIELD_ROUTES = 'Routes'; + /** + * @param array<\DCarbone\PHPConsulAPI\ConfigEntry\ServiceRoute> $Routes + * @param null|array $Meta + */ + public function __construct( + string $Kind = '', + string $Name = '', + string $Partition = '', + string $Namespace = '', + array $Routes = [], + null|array $Meta = null, + int $CreateIndex = 0, + int $ModifyIndex = 0, + ) { + $this->Kind = $Kind; + $this->Name = $Name; + $this->Partition = $Partition; + $this->Namespace = $Namespace; + $this->setRoutes(...$Routes); + $this->setMeta($Meta); + $this->CreateIndex = $CreateIndex; + $this->ModifyIndex = $ModifyIndex; + } + + public function getKind(): string + { + return $this->Kind; + } + + public function setKind(string $Kind): self + { + $this->Kind = $Kind; + return $this; + } + + public function getName(): string + { + return $this->Name; + } - public array $Routes = []; + public function setName(string $Name): self + { + $this->Name = $Name; + return $this; + } + public function getPartition(): string + { + return $this->Partition; + } + + public function setPartition(string $Partition): self + { + $this->Partition = $Partition; + return $this; + } + + /** + * @return array<\DCarbone\PHPConsulAPI\ConfigEntry\ServiceRoute> + */ public function getRoutes(): array { return $this->Routes; } - public function setRoutes(array $Routes): self + public function setRoutes(ServiceRoute ...$Routes): self { $this->Routes = $Routes; return $this; } + + public static function jsonUnserialize(\stdClass $decoded): self + { + $n = new self(); + foreach ((array)$decoded as $k => $v) { + if ('Routes' === $k) { + $n->Routes = []; + foreach ($v as $vv) { + $n->Routes[] = ServiceRoute::jsonUnserialize($vv); + } + } elseif ('Meta' === $k) { + $n->setMeta($v); + } else { + $n->{$k} = $v; + } + } + return $n; + } + + public function jsonSerialize(): \stdClass + { + $out = $this->_startJsonSerialize(); + $out->Kind = $this->Kind; + $out->Name = $this->Name; + if ('' !== $this->Partition) { + $out->Partition = $this->Partition; + } + if ('' !== $this->Namespace) { + $out->Namespace = $this->Namespace; + } + if ([] !== $this->Routes) { + $out->Routes = $this->Routes; + } + if (null !== $this->Meta) { + $out->Meta = $this->Meta; + } + $out->CreateIndex = $this->CreateIndex; + $out->ModifyIndex = $this->ModifyIndex; + return $out; + } } diff --git a/src/ConfigEntry/ServiceSplit.php b/src/ConfigEntry/ServiceSplit.php index 96319b07..df44a514 100644 --- a/src/ConfigEntry/ServiceSplit.php +++ b/src/ConfigEntry/ServiceSplit.php @@ -20,25 +20,35 @@ limitations under the License. */ -use DCarbone\PHPConsulAPI\AbstractModel; -use DCarbone\PHPConsulAPI\Transcoding; +use DCarbone\PHPConsulAPI\PHPLib\AbstractType; -class ServiceSplit extends AbstractModel +class ServiceSplit extends AbstractType { - protected const FIELDS = [ - self::FIELD_SERVICE => Transcoding::OMITEMPTY_STRING_FIELD, - self::FIELD_SERVICE_SUBSET => Transcoding::OMITEMPTY_STRING_FIELD, - self::FIELD_NAMESPACE => Transcoding::OMITEMPTY_STRING_FIELD, - ]; - - private const FIELD_SERVICE = 'Service'; - private const FIELD_SERVICE_SUBSET = 'ServiceSubset'; - private const FIELD_NAMESPACE = 'Namespace'; - - public float $Weight = 0.0; - public string $Service = ''; - public string $ServiceSubset = ''; - public string $Namespace = ''; + public float $Weight; + public string $Service; + public string $ServiceSubset; + public string $Namespace; + public string $Partition; + public null|HTTPHeaderModifiers $RequestHeaders; + public null|HTTPHeaderModifiers $ResponseHeaders; + + public function __construct( + float $Weight = 0.0, + string $Service = '', + string $ServiceSubset = '', + string $Namespace = '', + string $Partition = '', + null|HTTPHeaderModifiers $RequestHeaders = null, + null|HTTPHeaderModifiers $ResponseHeaders = null + ) { + $this->Weight = $Weight; + $this->Service = $Service; + $this->ServiceSubset = $ServiceSubset; + $this->Namespace = $Namespace; + $this->Partition = $Partition; + $this->RequestHeaders = $RequestHeaders; + $this->ResponseHeaders = $ResponseHeaders; + } public function getWeight(): float { @@ -83,4 +93,79 @@ public function setNamespace(string $Namespace): self $this->Namespace = $Namespace; return $this; } + + public function getPartition(): string + { + return $this->Partition; + } + + public function setPartition(string $Partition): self + { + $this->Partition = $Partition; + return $this; + } + + public function getRequestHeaders(): null|HTTPHeaderModifiers + { + return $this->RequestHeaders; + } + + public function setRequestHeaders(null|HTTPHeaderModifiers $RequestHeaders): self + { + $this->RequestHeaders = $RequestHeaders; + return $this; + } + + public function getResponseHeaders(): null|HTTPHeaderModifiers + { + return $this->ResponseHeaders; + } + + public function setResponseHeaders(null|HTTPHeaderModifiers $ResponseHeaders): self + { + $this->ResponseHeaders = $ResponseHeaders; + return $this; + } + + public static function jsonUnserialize(\stdClass $decoded): self + { + $n = new self(); + foreach ((array)$decoded as $k => $v) { + if ('service_subset' === $k) { + $n->ServiceSubset = $v; + } elseif ('RequestHeaders' === $k || 'request_headers' === $k) { + $n->RequestHeaders = HTTPHeaderModifiers::jsonUnserialize($v); + } elseif ('ResponseHeaders' === $k || 'response_headers' === $k) { + $n->ResponseHeaders = HTTPHeaderModifiers::jsonUnserialize($v); + } else { + $n->{$k} = $v; + } + } + return $n; + } + + public function jsonSerialize(): \stdClass + { + $out = $this->_startJsonSerialize(); + $out->Weight = $this->Weight; + if ('' !== $this->Service) { + $out->Service = $this->Service; + } + if ('' !== $this->ServiceSubset) { + $out->ServiceSubset = $this->ServiceSubset; + } + if ('' !== $this->Namespace) { + $out->Namespace = $this->Namespace; + } + if ('' !== $this->Partition) { + $out->Partition = $this->Partition; + } + if (null !== $this->RequestHeaders) { + $out->RequestHeaders = $this->RequestHeaders; + } + if (null !== $this->ResponseHeaders) { + $out->ResponseHeaders = $this->ResponseHeaders; + } + return $out; + } } diff --git a/src/ConfigEntry/ServiceSplitterConfigEntry.php b/src/ConfigEntry/ServiceSplitterConfigEntry.php index b821f2cb..f063f6f3 100644 --- a/src/ConfigEntry/ServiceSplitterConfigEntry.php +++ b/src/ConfigEntry/ServiceSplitterConfigEntry.php @@ -20,34 +20,126 @@ limitations under the License. */ -use DCarbone\PHPConsulAPI\AbstractModel; -use DCarbone\PHPConsulAPI\Transcoding; +use DCarbone\PHPConsulAPI\PHPLib\AbstractType; -class ServiceSplitterConfigEntry extends AbstractModel implements ConfigEntry +class ServiceSplitterConfigEntry extends AbstractType implements ConfigEntry { use ConfigEntryTrait; - protected const FIELDS = ConfigEntry::INTERFACE_FIELDS + [ - self::FIELD_SPLITS => [ - Transcoding::FIELD_TYPE => Transcoding::ARRAY, - Transcoding::FIELD_ARRAY_TYPE => Transcoding::OBJECT, - Transcoding::FIELD_CLASS => ServiceSplit::class, - Transcoding::FIELD_OMITEMPTY => true, - ], - ]; + public string $Kind; + public string $Name; + public string $Partition; + /** @var array<\DCarbone\PHPConsulAPI\ConfigEntry\ServiceSplit> */ + public array $Splits; - private const FIELD_SPLITS = 'Splits'; + /** + * @param array<\DCarbone\PHPConsulAPI\ConfigEntry\ServiceSplit> $Splits + * @param array $Meta + */ + public function __construct( + string $Kind = '', + string $Name = '', + string $Partition = '', + string $Namespace = '', + array $Splits = [], + null|\stdClass|array $Meta = null, + int $CreateIndex = 0, + int $ModifyIndex = 0, + ) { + $this->Kind = $Kind; + $this->Name = $Name; + $this->Partition = $Partition; + $this->Namespace = $Namespace; + $this->setSplits(...$Splits); + $this->setMeta($Meta); + $this->CreateIndex = $CreateIndex; + $this->ModifyIndex = $ModifyIndex; + } + + public function getKind(): string + { + return $this->Kind; + } + + public function setKind(string $Kind): self + { + $this->Kind = $Kind; + return $this; + } + + public function getName(): string + { + return $this->Name; + } - public array $Splits = []; + public function setName(string $Name): self + { + $this->Name = $Name; + return $this; + } + public function getPartition(): string + { + return $this->Partition; + } + + public function setPartition(string $Partition): self + { + $this->Partition = $Partition; + return $this; + } + + /** + * @return array<\DCarbone\PHPConsulAPI\ConfigEntry\ServiceSplit> + */ public function getSplits(): array { return $this->Splits; } - public function setSplits(array $Splits): self + public function setSplits(ServiceSplit ...$Splits): self { $this->Splits = $Splits; return $this; } + + public static function jsonUnserialize(\stdClass $decoded): self + { + $n = new self(); + foreach ((array)$decoded as $k => $v) { + if ('Splits' === $k) { + $n->Splits = []; + foreach ($v as $vv) { + $n->Splits[] = ServiceSplit::jsonUnserialize($vv); + } + } elseif ('Meta' === $k) { + $n->setMeta($v); + } else { + $n->{$k} = $v; + } + } + return $n; + } + + public function jsonSerialize(): \stdClass + { + $out = $this->_startJsonSerialize(); + $out->Kind = $this->Kind; + $out->Name = $this->Name; + if ('' !== $this->Partition) { + $out->Partition = $this->Partition; + } + if ('' !== $this->Namespace) { + $out->Namespace = $this->Namespace; + } + if ([] !== $this->Splits) { + $out->Splits = $this->Splits; + } + if (null !== $this->Meta) { + $out->Meta = $this->Meta; + } + $out->CreateIndex = $this->CreateIndex; + $out->ModifyIndex = $this->ModifyIndex; + return $out; + } } diff --git a/src/ConfigEntry/SourceIntention.php b/src/ConfigEntry/SourceIntention.php new file mode 100644 index 00000000..45a6a358 --- /dev/null +++ b/src/ConfigEntry/SourceIntention.php @@ -0,0 +1,308 @@ + */ + public array $Permissions; + public int $Precedence; + public IntentionSourceType $Type; + public string $Description; + public string $LegacyID; + public null|\stdClass $LegacyMeta; + public null|Time\Time $LegacyCreateTime; + public null|Time\Time $LegacyUpdateTime; + + /** + * @param array $Permissions + */ + public function __construct( + string $Name = '', + string $Peer = '', + string $Partition = '', + string $Namespace = '', + string $SamenessGroup = '', + string|IntentionAction $Action = IntentionAction::UNDEFINED, + array $Permissions = [], + int $Precedence = 0, + string|IntentionSourceType $Type = IntentionSourceType::UNDEFINED, + string $Description = '', + string $LegacyID = '', + null|\stdClass $LegacyMeta = null, + null|Time\Time $LegacyCreateTime = null, + null|Time\Time $LegacyUpdateTime = null, + ) { + $this->Name = $Name; + $this->Peer = $Peer; + $this->Partition = $Partition; + $this->Namespace = $Namespace; + $this->SamenessGroup = $SamenessGroup; + $this->Action = $Action instanceof IntentionAction ? $Action : IntentionAction::from($Action); + $this->setPermissions(...$Permissions); + $this->Precedence = $Precedence; + $this->Type = $Type instanceof IntentionSourceType ? $Type : IntentionSourceType::from($Type); + $this->Description = $Description; + $this->LegacyID = $LegacyID; + $this->LegacyMeta = $LegacyMeta; + $this->LegacyCreateTime = $LegacyCreateTime; + $this->LegacyUpdateTime = $LegacyUpdateTime; + } + + public function getName(): string + { + return $this->Name; + } + + public function setName(string $Name): self + { + $this->Name = $Name; + return $this; + } + + public function getPeer(): string + { + return $this->Peer; + } + + public function setPeer(string $Peer): self + { + $this->Peer = $Peer; + return $this; + } + + public function getPartition(): string + { + return $this->Partition; + } + + public function setPartition(string $Partition): self + { + $this->Partition = $Partition; + return $this; + } + + public function getNamespace(): string + { + return $this->Namespace; + } + + public function setNamespace(string $Namespace): self + { + $this->Namespace = $Namespace; + return $this; + } + + public function getSamenessGroup(): string + { + return $this->SamenessGroup; + } + + public function setSamenessGroup(string $SamenessGroup): self + { + $this->SamenessGroup = $SamenessGroup; + return $this; + } + + public function getAction(): IntentionAction + { + return $this->Action; + } + + public function setAction(IntentionAction $Action): self + { + $this->Action = $Action; + return $this; + } + + /** + * @return array + */ + public function getPermissions(): array + { + return $this->Permissions; + } + + public function setPermissions(null|IntentionPermission ...$Permissions): self + { + $this->Permissions = $Permissions; + return $this; + } + + public function getPrecedence(): int + { + return $this->Precedence; + } + + public function setPrecedence(int $Precedence): self + { + $this->Precedence = $Precedence; + return $this; + } + + public function getType(): IntentionSourceType + { + return $this->Type; + } + + public function setType(IntentionSourceType $Type): self + { + $this->Type = $Type; + return $this; + } + + public function getDescription(): string + { + return $this->Description; + } + + public function setDescription(string $Description): self + { + $this->Description = $Description; + return $this; + } + + public function getLegacyID(): string + { + return $this->LegacyID; + } + + public function setLegacyID(string $LegacyID): self + { + $this->LegacyID = $LegacyID; + return $this; + } + + public function getLegacyMeta(): null|\stdClass + { + return $this->LegacyMeta; + } + + public function setLegacyMeta(null|\stdClass $LegacyMeta): self + { + $this->LegacyMeta = $LegacyMeta; + return $this; + } + + public function getLegacyCreateTime(): null|Time\Time + { + return $this->LegacyCreateTime; + } + + public function setLegacyCreateTime(null|Time\Time $LegacyCreateTime): self + { + $this->LegacyCreateTime = $LegacyCreateTime; + return $this; + } + + public function getLegacyUpdateTime(): null|Time\Time + { + return $this->LegacyUpdateTime; + } + + public function setLegacyUpdateTime(null|Time\Time $LegacyUpdateTime): self + { + $this->LegacyUpdateTime = $LegacyUpdateTime; + return $this; + } + + public static function jsonUnserialize(\stdClass $decoded): self + { + $n = new self(); + foreach ((array)$decoded as $k => $v) { + if ('sameness_group' === $k) { + $n->SamenessGroup = $v; + } elseif ('Action' === $k) { + $n->Action = IntentionAction::from($v); + } elseif ('Permissions' === $k) { + $n->Permissions = []; + foreach ($v as $vv) { + $n->Permissions[] = null === $vv ? null : IntentionPermission::jsonUnserialize($vv); + } + } elseif ('Type' === $k) { + $n->Type = IntentionSourceType::from($v); + } elseif ('legacy_id' === $k) { + $n->LegacyID = $v; + } elseif ('legacy_meta' === $k) { + $n->LegacyMeta = $v; + } elseif ('legacy_create_time' === $k) { + $n->LegacyCreateTime = null === $v ? null : parse_time($v); + } elseif ('legacy_update_time' === $k) { + $n->LegacyUpdateTime = null === $v ? null : parse_time($v); + } else { + $n->{$k} = $v; + } + } + return $n; + } + + public function jsonSerialize(): \stdClass + { + $out = $this->_startJsonSerialize(); + $out->Name = $this->Name; + if ('' !== $this->Peer) { + $out->Peer = $this->Peer; + } + if ('' !== $this->Partition) { + $out->Partition = $this->Partition; + } + if ('' !== $this->Namespace) { + $out->Namespace = $this->Namespace; + } + if ('' !== $this->SamenessGroup) { + $out->SamenessGroup = $this->SamenessGroup; + } + if (IntentionAction::UNDEFINED !== $this->Action) { + $out->Action = $this->Action->value; + } + if ([] !== $this->Permissions) { + $out->Permissions = $this->Permissions; + } + $out->Precedence = $this->Precedence; + $out->Type = $this->Type; + if ('' !== $this->Description) { + $out->Description = $this->Description; + } + if ('' !== $this->LegacyID) { + $out->LegacyID = $this->LegacyID; + } + if (null !== $this->LegacyMeta) { + $out->LegacyMeta = $this->LegacyMeta; + } + if (null !== $this->LegacyCreateTime) { + $out->LegacyCreateTime = $this->LegacyCreateTime->format(DATE_RFC3339); + } + if (null !== $this->LegacyUpdateTime) { + $out->LegacyUpdateTime = $this->LegacyUpdateTime->format(DATE_RFC3339); + } + return $out; + } +} diff --git a/src/ConfigEntry/TerminatingGatewayConfigEntry.php b/src/ConfigEntry/TerminatingGatewayConfigEntry.php new file mode 100644 index 00000000..b59f0afb --- /dev/null +++ b/src/ConfigEntry/TerminatingGatewayConfigEntry.php @@ -0,0 +1,159 @@ + */ + public array $Services; + public string $Partition; + + /** + * @param array<\DCarbone\PHPConsulAPI\ConfigEntry\LinkedService> $Services + * @param array $Meta + */ + public function __construct( + string $Kind = '', + string $Name = '', + array $Services = [], + null|\stdClass|array $Meta = null, + int $CreateIndex = 0, + int $ModifyIndex = 0, + string $Partition = '', + string $Namespace = '', + ) { + $this->Kind = $Kind; + $this->Name = $Name; + $this->setServices(...$Services); + $this->setMeta($Meta); + $this->CreateIndex = $CreateIndex; + $this->ModifyIndex = $ModifyIndex; + $this->Partition = $Partition; + $this->Namespace = $Namespace; + } + + public function getKind(): string + { + return $this->Kind; + } + + public function setKind(string $Kind): self + { + $this->Kind = $Kind; + return $this; + } + + public function getName(): string + { + return $this->Name; + } + + public function setName(string $Name): self + { + $this->Name = $Name; + return $this; + } + + /** + * @return array<\DCarbone\PHPConsulAPI\ConfigEntry\LinkedService> + */ + public function getServices(): array + { + return $this->Services; + } + + /** + * @param \DCarbone\PHPConsulAPI\ConfigEntry\LinkedService ...$Services + */ + public function setServices(LinkedService ...$Services): self + { + $this->Services = $Services; + return $this; + } + + public function getPartition(): string + { + return $this->Partition; + } + + public function setPartition(string $Partition): self + { + $this->Partition = $Partition; + return $this; + } + + public function getNamespace(): string + { + return $this->Namespace; + } + + public function setNamespace(string $Namespace): self + { + $this->Namespace = $Namespace; + return $this; + } + + public static function jsonUnserialize(\stdClass $decoded): self + { + $n = new self(); + foreach ((array)$decoded as $k => $v) { + if ('Services' === $k) { + $n->Services = []; + foreach ($v as $vv) { + $n->Services[] = LinkedService::jsonUnserialize($vv); + } + } elseif ('Meta' === $k) { + $n->setMeta($v); + } else { + $n->{$k} = $v; + } + } + return $n; + } + + public function jsonSerialize(): \stdClass + { + $out = $this->_startJsonSerialize(); + $out->Kind = $this->Kind; + $out->Name = $this->Name; + if ([] !== $this->Services) { + $out->Services = $this->Services; + } + if (null !== $this->Meta) { + $out->Meta = $this->Meta; + } + $out->CreateIndex = $this->CreateIndex; + $out->ModifyIndex = $this->ModifyIndex; + if ('' !== $this->Partition) { + $out->Partition = $this->Partition; + } + if ('' !== $this->Namespace) { + $out->Namespace = $this->Namespace; + } + return $out; + } +} diff --git a/src/ConfigEntry/TransparentProxyConfig.php b/src/ConfigEntry/TransparentProxyConfig.php index 0f6d5b30..a25892d2 100644 --- a/src/ConfigEntry/TransparentProxyConfig.php +++ b/src/ConfigEntry/TransparentProxyConfig.php @@ -20,21 +20,20 @@ limitations under the License. */ -use DCarbone\PHPConsulAPI\AbstractModel; -use DCarbone\PHPConsulAPI\Transcoding; +use DCarbone\PHPConsulAPI\PHPLib\AbstractType; -class TransparentProxyConfig extends AbstractModel +class TransparentProxyConfig extends AbstractType { - protected const FIELDS = [ - self::FIELD_OUTBOUND_LISTENER_PORT => Transcoding::OMITEMPTY_STRING_FIELD, - self::FIELD_DIALED_DIRECTLY => Transcoding::OMITEMPTY_BOOLEAN_FIELD, - ]; + public int $OutboundListenerPort; + public bool $DialedDirectly; - private const FIELD_OUTBOUND_LISTENER_PORT = 'OutboundListenerPort'; - private const FIELD_DIALED_DIRECTLY = 'DialedDirectly'; - - public int $OutboundListenerPort = 0; - public bool $DialedDirectly = false; + public function __construct( + int $OutboundListenerPort = 0, + bool $DialedDirectly = false + ) { + $this->OutboundListenerPort = $OutboundListenerPort; + $this->DialedDirectly = $DialedDirectly; +} public function getOutboundListenerPort(): int { @@ -57,4 +56,25 @@ public function setDialedDirectly(bool $DialedDirectly): self $this->DialedDirectly = $DialedDirectly; return $this; } + + public static function jsonUnserialize(\stdClass $decoded): self + { + $n = new self(); + foreach ((array)$decoded as $k => $v) { + $n->{$k} = $v; + } + return $n; + } + + public function jsonSerialize(): \stdClass + { + $out = $this->_startJsonSerialize(); + if (0 !== $this->OutboundListenerPort) { + $out->OutboundListenerPort = $this->OutboundListenerPort; + } + if ($this->DialedDirectly) { + $out->DialedDirectly = $this->DialedDirectly; + } + return $out; + } } diff --git a/src/ConfigEntry/TransparentProxyMeshConfig.php b/src/ConfigEntry/TransparentProxyMeshConfig.php new file mode 100644 index 00000000..aea2d7d4 --- /dev/null +++ b/src/ConfigEntry/TransparentProxyMeshConfig.php @@ -0,0 +1,64 @@ +MeshDestinationsOnly = $MeshDestinationsOnly; + } + + public function isMeshDestinationsOnly(): bool + { + return $this->MeshDestinationsOnly; + } + + public function setMeshDestinationsOnly(bool $MeshDestinationsOnly): self + { + $this->MeshDestinationsOnly = $MeshDestinationsOnly; + return $this; + } + + public static function jsonUnserialize(\stdClass $decoded): self + { + $n = new self(); + foreach ((array)$decoded as $k => $v) { + if ('mesh_destinations_only' === $k) { + $n->MeshDestinationsOnly = $v; + } else { + $n->{$k} = $v; + } + } + return $n; + } + + public function jsonSerialize(): \stdClass + { + $o = new \stdClass(); + $o->MeshDestinationsOnly = $this->MeshDestinationsOnly; + return $o; + } +} diff --git a/src/ConfigEntry/UpstreamConfig.php b/src/ConfigEntry/UpstreamConfig.php new file mode 100644 index 00000000..ef846510 --- /dev/null +++ b/src/ConfigEntry/UpstreamConfig.php @@ -0,0 +1,264 @@ +Name = $Name; + $this->Partition = $Partition; + $this->Namespace = $Namespace; + $this->Peer = $Peer; + $this->EnvoyListenerJSON = $EnvoyListenerJSON; + $this->EnvoyClusterJSON = $EnvoyClusterJSON; + $this->Protocol = $Protocol; + $this->ConnectTimeoutMs = $ConnectTimeoutMs; + $this->Limits = $Limits; + $this->PassiveHealthCheck = $PassiveHealthCheck; + $this->MeshGateway = $MeshGateway ?? new MeshGatewayConfig(); + $this->BalanceOutboundConnections = $BalanceOutboundConnections; + } + + public function getName(): string + { + return $this->Name; + } + + public function setName(string $Name): self + { + $this->Name = $Name; + return $this; + } + + public function getPartition(): string + { + return $this->Partition; + } + + public function setPartition(string $Partition): self + { + $this->Partition = $Partition; + return $this; + } + + public function getNamespace(): string + { + return $this->Namespace; + } + + public function setNamespace(string $Namespace): self + { + $this->Namespace = $Namespace; + return $this; + } + + public function getPeer(): string + { + return $this->Peer; + } + + public function setPeer(string $Peer): self + { + $this->Peer = $Peer; + return $this; + } + + public function getEnvoyListenerJSON(): string + { + return $this->EnvoyListenerJSON; + } + + public function setEnvoyListenerJSON(string $EnvoyListenerJSON): self + { + $this->EnvoyListenerJSON = $EnvoyListenerJSON; + return $this; + } + + public function getEnvoyClusterJSON(): string + { + return $this->EnvoyClusterJSON; + } + + public function setEnvoyClusterJSON(string $EnvoyClusterJSON): self + { + $this->EnvoyClusterJSON = $EnvoyClusterJSON; + return $this; + } + + public function getProtocol(): string + { + return $this->Protocol; + } + + public function setProtocol(string $Protocol): self + { + $this->Protocol = $Protocol; + return $this; + } + + public function getConnectTimeoutMs(): int + { + return $this->ConnectTimeoutMs; + } + + public function setConnectTimeoutMs(int $ConnectTimeoutMs): self + { + $this->ConnectTimeoutMs = $ConnectTimeoutMs; + return $this; + } + + public function getLimits(): null|UpstreamLimits + { + return $this->Limits; + } + + public function setLimits(null|UpstreamLimits $Limits): self + { + $this->Limits = $Limits; + return $this; + } + + public function getPassiveHealthCheck(): null|PassiveHealthCheck + { + return $this->PassiveHealthCheck; + } + + public function setPassiveHealthCheck(null|PassiveHealthCheck $PassiveHealthCheck): self + { + $this->PassiveHealthCheck = $PassiveHealthCheck; + return $this; + } + + public function getMeshGateway(): MeshGatewayConfig + { + return $this->MeshGateway; + } + + public function setMeshGateway(MeshGatewayConfig $MeshGateway): self + { + $this->MeshGateway = $MeshGateway; + return $this; + } + + public function getBalanceOutboundConnections(): string + { + return $this->BalanceOutboundConnections; + } + + public function setBalanceOutboundConnections(string $BalanceOutboundConnections): self + { + $this->BalanceOutboundConnections = $BalanceOutboundConnections; + return $this; + } + + public static function jsonUnserialize(\stdClass $decoded): self + { + $n = new self(); + foreach ((array)$decoded as $k => $v) { + if ('envoy_listener_json' === $k) { + $n->EnvoyListenerJSON = $v; + } elseif ('connect_timeout_ms' === $k) { + $n->ConnectTimeoutMs = $v; + } elseif ('Limits' === $k) { + $n->Limits = null === $v ? null : UpstreamLimits::jsonUnserialize($v); + } elseif ('PassiveHealthCheck' === $k || 'passive_health_check' === $k) { + $n->PassiveHealthCheck = null === $v ? null : PassiveHealthCheck::jsonUnserialize($v); + } elseif ('MeshGateway' === $k) { + $n->MeshGateway = MeshGatewayConfig::jsonUnserialize($v); + } elseif ('balance_outbound_connections' === $k) { + $n->BalanceOutboundConnections = $v; + } else { + $n->{$k} = $v; + } + } + return $n; + } + + public function jsonSerialize(): \stdClass + { + $out = $this->_startJsonSerialize(); + if ('' !== $this->Name) { + $out->Name = $this->Name; + } + if ('' !== $this->Partition) { + $out->Partition = $this->Partition; + } + if ('' !== $this->Namespace) { + $out->Namespace = $this->Namespace; + } + if ('' !== $this->Peer) { + $out->Peer = $this->Peer; + } + if ('' !== $this->EnvoyListenerJSON) { + $out->EnvoyListenerJSON = $this->EnvoyListenerJSON; + } + if ('' !== $this->EnvoyClusterJSON) { + $out->EnvoyClusterJSON = $this->EnvoyClusterJSON; + } + if ('' !== $this->Protocol) { + $out->Protocol = $this->Protocol; + } + if (0 !== $this->ConnectTimeoutMs) { + $out->ConnectTimeoutMs = $this->ConnectTimeoutMs; + } + if (null !== $this->Limits) { + $out->Limits = $this->Limits; + } + if (null !== $this->PassiveHealthCheck) { + $out->PassiveHealthCheck = $this->PassiveHealthCheck; + } + _enc_obj_if_valued($out, 'MeshGateway', $this->MeshGateway); + if ('' !== $this->BalanceOutboundConnections) { + $out->BalanceOutboundConnections = $this->BalanceOutboundConnections; + } + return $out; + } +} diff --git a/src/ConfigEntry/UpstreamConfiguration.php b/src/ConfigEntry/UpstreamConfiguration.php index 7aa0b584..4564c3b8 100644 --- a/src/ConfigEntry/UpstreamConfiguration.php +++ b/src/ConfigEntry/UpstreamConfiguration.php @@ -20,154 +20,77 @@ limitations under the License. */ -use DCarbone\PHPConsulAPI\AbstractModel; -use DCarbone\PHPConsulAPI\Transcoding; +use DCarbone\PHPConsulAPI\PHPLib\AbstractType; -class UpstreamConfiguration extends AbstractModel +class UpstreamConfiguration extends AbstractType { - protected const FIELDS = [ - self::FIELD_NAME => Transcoding::OMITEMPTY_STRING_FIELD, - self::FIELD_NAMESPACE => Transcoding::OMITEMPTY_STRING_FIELD, - self::FIELD_ENJOY_LISTENER_JSON => Transcoding::OMITEMPTY_STRING_FIELD, - self::FIELD_ENVOY_CLUSTER_JSON => Transcoding::OMITEMPTY_STRING_FIELD, - self::FIELD_PROTOCOL => Transcoding::OMITEMPTY_STRING_FIELD, - self::FIELD_CONNECT_TIMEOUT_MS => Transcoding::OMITEMPTY_INTEGER_FIELD, - self::FIELD_LIMITS => [ - Transcoding::FIELD_TYPE => Transcoding::OBJECT, - Transcoding::FIELD_CLASS => UpstreamLimits::class, - Transcoding::FIELD_OMITEMPTY => true, - Transcoding::FIELD_NULLABLE => true, - ], - self::FIELD_PASSIVE_HEALTH_CHECK => [ - Transcoding::FIELD_TYPE => Transcoding::OBJECT, - Transcoding::FIELD_CLASS => PassiveHealthCheck::class, - Transcoding::FIELD_OMITEMPTY => true, - Transcoding::FIELD_NULLABLE => true, - ], - self::FIELD_MESH_GATEWAY => [ - Transcoding::FIELD_TYPE => Transcoding::OBJECT, - Transcoding::FIELD_CLASS => MeshGatewayConfig::class, - Transcoding::FIELD_OMITEMPTY => true, - Transcoding::FIELD_NULLABLE => true, - ], - ]; + /** @var array */ + public array $Overrides; + public null|UpstreamConfig $Defaults; - private const FIELD_NAME = 'Name'; - private const FIELD_NAMESPACE = 'Namespace'; - private const FIELD_ENJOY_LISTENER_JSON = 'EnvoyListenerJSON'; - private const FIELD_ENVOY_CLUSTER_JSON = 'EnvoyClusterJSON'; - private const FIELD_PROTOCOL = 'Protocol'; - private const FIELD_CONNECT_TIMEOUT_MS = 'ConnectTimeoutMs'; - private const FIELD_LIMITS = 'Limits'; - private const FIELD_PASSIVE_HEALTH_CHECK = 'PassiveHealthCheck'; - private const FIELD_MESH_GATEWAY = 'MeshGateway'; - - public string $Name = ''; - public string $Namespace = ''; - public string $EnvoyListenerJSON = ''; - public string $EnvoyClusterJSON = ''; - public string $Protocol = ''; - public int $ConnectTimeoutMs = 0; - public ?UpstreamLimits $UpstreamLimits = null; - public ?PassiveHealthCheck $PassiveHealthCheck = null; - public ?MeshGatewayConfig $MeshGateway = null; - - public function getName(): string - { - return $this->Name; - } - - public function setName(string $Name): self - { - $this->Name = $Name; - return $this; - } - - public function getNamespace(): string - { - return $this->Namespace; - } - - public function setNamespace(string $Namespace): self - { - $this->Namespace = $Namespace; - return $this; - } - - public function getEnvoyListenerJSON(): string - { - return $this->EnvoyListenerJSON; - } - - public function setEnvoyListenerJSON(string $EnvoyListenerJSON): self - { - $this->EnvoyListenerJSON = $EnvoyListenerJSON; - return $this; + /** + * @param array<\DCarbone\PHPConsulAPI\ConfigEntry\UpstreamConfig> $Overrides + */ + public function __construct( + array $Overrides = [], + null|UpstreamConfig $Defaults = null + ) { + $this->setOverrides(...$Overrides); + $this->Defaults = $Defaults; } - public function getEnvoyClusterJSON(): string + /** + * @return array + */ + public function getOverrides(): array { - return $this->EnvoyClusterJSON; + return $this->Overrides; } - public function setEnvoyClusterJSON(string $EnvoyClusterJSON): self + public function setOverrides(null|UpstreamConfig ...$Overrides): self { - $this->EnvoyClusterJSON = $EnvoyClusterJSON; + $this->Overrides = $Overrides; return $this; } - public function getProtocol(): string + public function getDefaults(): null|UpstreamConfig { - return $this->Protocol; + return $this->Defaults; } - public function setProtocol(string $Protocol): self + public function setDefaults(null|UpstreamConfig $Defaults): self { - $this->Protocol = $Protocol; + $this->Defaults = $Defaults; return $this; } - public function getConnectTimeoutMs(): int - { - return $this->ConnectTimeoutMs; - } - - public function setConnectTimeoutMs(int $ConnectTimeoutMs): self - { - $this->ConnectTimeoutMs = $ConnectTimeoutMs; - return $this; - } - - public function getUpstreamLimits(): ?UpstreamLimits - { - return $this->UpstreamLimits; - } - - public function setUpstreamLimits(?UpstreamLimits $UpstreamLimits): self - { - $this->UpstreamLimits = $UpstreamLimits; - return $this; - } - - public function getPassiveHealthCheck(): ?PassiveHealthCheck - { - return $this->PassiveHealthCheck; - } - - public function setPassiveHealthCheck(?PassiveHealthCheck $PassiveHealthCheck): self - { - $this->PassiveHealthCheck = $PassiveHealthCheck; - return $this; - } - - public function getMeshGateway(): ?MeshGatewayConfig - { - return $this->MeshGateway; - } - - public function setMeshGateway(?MeshGatewayConfig $MeshGateway): self - { - $this->MeshGateway = $MeshGateway; - return $this; + public static function jsonUnserialize(\stdClass $decoded): self + { + $n = new self(); + foreach ((array)$decoded as $k => $v) { + if ('Overrides' === $k) { + $n->Overrides = []; + foreach ($v as $vv) { + $n->Overrides[] = UpstreamConfig::jsonUnserialize($vv); + } + } elseif ('Defaults' === $k) { + $n->Defaults = null === $v ? null : UpstreamConfig::jsonUnserialize($v); + } else { + $n->{$k} = $v; + } + } + return $n; + } + + public function jsonSerialize(): \stdClass + { + $out = $this->_startJsonSerialize(); + if ([] !== $this->Overrides) { + $out->Overrides = $this->Overrides; + } + if (null !== $this->Defaults) { + $out->Defaults = $this->Defaults; + } + return $out; } } diff --git a/src/ConfigEntry/UpstreamLimits.php b/src/ConfigEntry/UpstreamLimits.php index 10868d89..290dd042 100644 --- a/src/ConfigEntry/UpstreamLimits.php +++ b/src/ConfigEntry/UpstreamLimits.php @@ -20,61 +20,80 @@ limitations under the License. */ -use DCarbone\PHPConsulAPI\AbstractModel; -use DCarbone\PHPConsulAPI\Transcoding; +use DCarbone\PHPConsulAPI\PHPLib\AbstractType; -class UpstreamLimits extends AbstractModel +class UpstreamLimits extends AbstractType { - protected const FIELDS = [ - self::FIELD_MAX_CONNECTIONS => [ - Transcoding::FIELD_NULLABLE => true, - ], - self::FIELD_MAX_PENDING_REQUESTS => [ - Transcoding::FIELD_NULLABLE => true, - ], - self::FIELD_MAX_CONCURRENT_REQUESTS => [ - Transcoding::FIELD_NULLABLE => true, - ], - ]; - - private const FIELD_MAX_CONNECTIONS = 'MaxConnections'; - private const FIELD_MAX_PENDING_REQUESTS = 'MaxPendingRequests'; - private const FIELD_MAX_CONCURRENT_REQUESTS = 'MaxConcurrentRequests'; - - public ?int $MaxConnections = null; - public ?int $MaxPendingRequests = null; - public ?int $MaxConcurrentRequests = null; - - public function getMaxConnections(): ?int + public null|int $MaxConnections; + public null|int $MaxPendingRequests; + public null|int $MaxConcurrentRequests; + + public function __construct( + null|int $MaxConnections = null, + null|int $MaxPendingRequests = null, + null|int $MaxConcurrentRequests = null, + ) { + $this->MaxConnections = $MaxConnections; + $this->MaxPendingRequests = $MaxPendingRequests; + $this->MaxConcurrentRequests = $MaxConcurrentRequests; + } + + public function getMaxConnections(): null|int { return $this->MaxConnections; } - public function setMaxConnections(?int $MaxConnections): self + public function setMaxConnections(null|int $MaxConnections): self { $this->MaxConnections = $MaxConnections; return $this; } - public function getMaxPendingRequests(): ?int + public function getMaxPendingRequests(): null|int { return $this->MaxPendingRequests; } - public function setMaxPendingRequests(?int $MaxPendingRequests): self + public function setMaxPendingRequests(null|int $MaxPendingRequests): self { $this->MaxPendingRequests = $MaxPendingRequests; return $this; } - public function getMaxConcurrentRequests(): ?int + public function getMaxConcurrentRequests(): null|int { return $this->MaxConcurrentRequests; } - public function setMaxConcurrentRequests(?int $MaxConcurrentRequests): self + public function setMaxConcurrentRequests(null|int $MaxConcurrentRequests): self { $this->MaxConcurrentRequests = $MaxConcurrentRequests; return $this; } + + public static function jsonUnserialize(\stdClass $decoded): self + { + $n = new self(); + foreach ((array)$decoded as $k => $v) { + if ('max_connections' === $k) { + $n->MaxConnections = $v; + } elseif ('max_pending_requests' === $k) { + $n->MaxPendingRequests = $v; + } elseif ('max_concurrent_requests' === $k) { + $n->MaxConcurrentRequests = $v; + } else { + $n->{$k} = $v; + } + } + return $n; + } + + public function jsonSerialize(): \stdClass + { + $out = $this->_startJsonSerialize(); + $out->MaxConnections = $this->MaxConnections; + $out->MaxPendingRequests = $this->MaxPendingRequests; + $out->MaxConcurrentRequests = $this->MaxConcurrentRequests; + return $out; + } } diff --git a/src/Consul.php b/src/Consul.php index 3f0aa212..cb7959df 100644 --- a/src/Consul.php +++ b/src/Consul.php @@ -73,43 +73,6 @@ class Consul public const SessionBehaviorRelease = 'release'; public const SessionBehaviorDelete = 'delete'; - public const ServiceKindTypical = ''; - public const ServiceKindConnectProxy = 'connect-proxy'; - public const ServiceKindMeshGateway = 'mesh-gateway'; - public const ServiceKindTerminatingGateway = 'terminating-gateway'; - public const ServiceKindIngressGateway = 'ingress-gateway'; - - public const UpstreamDestTypeService = 'service'; - public const UpstreamDestTypePreparedQuery = 'prepared_query'; - - public const AutopilotServerNone = 'none'; - public const AutopilotServerLeader = 'leader'; - public const AutopilotServerVoter = 'voter'; - public const AutopilotServerNonVoter = 'non-voter'; - public const AutopilotServerStaging = 'staging'; - - public const AutopilotTypeVoter = 'voter'; - public const AutopilotTypeReadReplica = 'read-replica'; - public const AutopilotTypeZoneVoter = 'zone-voter'; - public const AutopilotTypeZoneExtraVoter = 'zone-extra-voter'; - public const AutopilotTypeZoneStandby = 'zone-standby'; - - public const AutopilotUpgradeIdle = 'idle'; - public const AutopilotUpgradeAwaitNewVoters = 'await-new-voters'; - public const AutopilotUpgradePromoting = 'promoting'; - public const AutopilotUpgradeDemoting = 'demoting'; - public const AutopilotUpgradeLeaderTransfer = 'leader-transfer'; - public const AutopilotUpgradeAwaitNewServers = 'await-new-servers'; - public const AutopilotUpgradeAwaitServerRemoval = 'await-server-removal'; - public const AutopilotUpgradeDisabled = 'disabled'; - - public const BindingRuleBindTypeService = 'service'; - public const BindingRuleBindTypeRole = 'role'; - - public const MeshGatewayModeDefault = ''; - public const MeshGatewayModeNone = 'none'; - public const MeshGatewayModeLocal = 'local'; - public const MeshGatewayModeRemote = 'remote'; public const MemberTagKeyACLMode = 'acls'; public const MemberTagKeyRole = 'role'; @@ -123,14 +86,27 @@ class Consul public const MemberTagKeyReadReplica = 'read_replica'; public const MemberTagValueReadReplica = '1'; - public const ACLModeDisabled = '0'; - public const ACLModeEnabled = '1'; - public const ACLModeLegacy = '2'; - public const ACLModeUnknown = '3'; - - public const ProxyModeDefault = ''; - public const ProxyModeTransparent = 'transparent'; - public const ProxyModeDirect = 'direct'; + // config_entry.go + public const ServiceDefaults = 'service-defaults'; + public const ProxyDefaults = 'proxy-defaults'; + public const ServiceRouter = 'service-router'; + public const ServiceSplitter = 'service-splitter'; + public const ServiceResolver = 'service-resolver'; + public const IngressGateway = 'ingress-gateway'; + public const TerminatingGateway = 'terminating-gateway'; + public const ServiceIntentions = 'service-intentions'; + public const MeshConfig = 'mesh'; + public const ExportedServices = 'exported-services'; + public const SamenessGroup = 'sameness-group'; + public const RateLimitIPConfig = 'control-plane-request-limit'; + + public const ProxyConfigGlobal = 'global'; + public const MeshConfigMesh = 'mesh'; + public const APIGateway = "api-gateway"; + public const TCPRoute = "tcp-route"; + public const InlineCertificate = 'inline-certificate'; + public const HTTPRoute = 'http-route'; + public const JWTProvider = 'jwt-provider'; // "private" constants @@ -154,7 +130,7 @@ class Consul public SessionClient $Session; public StatusClient $Status; - public function __construct(?Config $config = null) + public function __construct(null|Config $config = null) { $config = Config::merge($config); @@ -240,4 +216,20 @@ public function Status(): StatusClient { return $this->Status; } + + public static function MakeConfigEntry(string $kind, string $name): ConfigEntry\ConfigEntry + { + return match ($kind) { + Consul::ServiceDefaults => new ConfigEntry\ServiceConfigEntry(Kind: $kind, Name: $name), + Consul::ProxyDefaults => new ConfigEntry\ProxyConfigEntry(Kind: $kind, Name: $name), + Consul::ServiceRouter => new ConfigEntry\ServiceRouterConfigEntry(Kind: $kind, Name: $name), + Consul::ServiceSplitter => new ConfigEntry\ServiceSplitterConfigEntry(Kind: $kind, Name: $name), + Consul::ServiceResolver => new ConfigEntry\ServiceResolverConfigEntry(Kind: $kind, Name: $name), + Consul::IngressGateway => new ConfigEntry\IngressGatewayConfigEntry(Kind: $kind, Name: $name), + Consul::TerminatingGateway => new ConfigEntry\TerminatingGatewayConfigEntry(Kind: $kind, Name: $name), + Consul::ServiceIntentions => new ConfigEntry\ServiceIntentionsConfigEntry(Kind: $kind, name: $name), + + default => throw new \InvalidArgumentException(sprintf('Unknown kind "%s"', $kind)), + }; + } } diff --git a/src/Coordinate/Coordinate.php b/src/Coordinate/Coordinate.php index 5ccb6a58..9d90253e 100644 --- a/src/Coordinate/Coordinate.php +++ b/src/Coordinate/Coordinate.php @@ -21,67 +21,95 @@ */ use DCarbone\Go\Time; -use DCarbone\PHPConsulAPI\AbstractModel; +use DCarbone\PHPConsulAPI\PHPLib\AbstractType; /** * Class Coordinate * * From github.com/hashicorp/serf/coordinate/coordinate.go */ -class Coordinate extends AbstractModel +class Coordinate extends AbstractType { - public array $Vec = []; - public float $Error = 0.0; - public float $Adjustment = 0.0; - public float $Height = 0.0; - - public function __construct($data = []) - { - if (\is_array($data)) { - parent::__construct($data); - } elseif ($data instanceof CoordinateConfig) { - $this->Vec = array_fill(0, $data->Dimensionality, 0.0); - $this->Error = $data->VivaldiErrorMax; + public const ZeroThreshold = 1.0e-6; + private const secondsToNanoseconds = 1.0e9; + + /** @var array */ + public array $Vec; + public float $Error; + public float $Adjustment; + public float $Height; + + /** + * @param array $Vec + */ + public function __construct( + null|CoordinateConfig $config = null, + array $Vec = [], + float $Error = 0.0, + float $Adjustment = 0.0, + float $Height = 0.0, + ) { + if (null !== $config) { + $this->Vec = array_fill(0, $config->Dimensionality, 0.0); + $this->Error = $config->VivaldiErrorMax; $this->Adjustment = 0.0; - $this->Height = $data->HeightMin; + $this->Height = $config->HeightMin; } else { - throw new \InvalidArgumentException( - sprintf( - '%s::__construct - Argument 1 must be array of values or instance of %s, %s seen', - static::class, - CoordinateConfig::class, - \is_object($data) ? \get_class($data) : \gettype($data) - ) - ); + $this->setVec(...$Vec); + $this->Error = $Error; + $this->Adjustment = $Adjustment; + $this->Height = $Height; } } + /** + * @return float[] + */ public function getVec(): array { return $this->Vec; } + public function setVec(float ...$Vec): self + { + $this->Vec = $Vec; + return $this; + } + public function getError(): float { return $this->Error; } + public function setError(float $Error): self + { + $this->Error = $Error; + return $this; + } + public function getAdjustment(): float { return $this->Adjustment; } + public function setAdjustment(float $Adjustment): self + { + $this->Adjustment = $Adjustment; + return $this; + } + public function getHeight(): float { return $this->Height; } - /** - * todo: prevent php-cs-fixer from being dumb. - * - * @return \DCarbone\PHPConsulAPI\Coordinate\Coordinate - */ - public function Clone(): Coordinate|static + public function setHeight(float $Height): self + { + $this->Height = $Height; + return $this; + } + + public function Clone(): self { return clone $this; } @@ -89,16 +117,18 @@ public function Clone(): Coordinate|static public function IsValid(): bool { foreach ($this->Vec as $vec) { - if (!is_finite($vec)) { + if (!self::_componentIsValid($vec)) { return false; } } - return is_finite($this->Error) && is_finite($this->Adjustment) && is_finite($this->Height); + return self::_componentIsValid($this->Error) && + self::_componentIsValid($this->Adjustment) && + self::_componentIsValid($this->Height); } public function IsCompatibleWith(self $other): bool { - return \count($this->Vec) === \count($other->Vec); + return count($this->Vec) === count($other->Vec); } public function ApplyForce(CoordinateConfig $config, float $force, self $other): self @@ -107,11 +137,11 @@ public function ApplyForce(CoordinateConfig $config, float $force, self $other): throw new DimensionalityConflictException(); } - $ret = clone $this; - [$unit, $mag] = unitVectorAt($this->Vec, $other->Vec); - $ret->Vec = add($ret->Vec, mul($unit, $force)); - if ($mag > ZeroThreshold) { - $ret->Height = max(($ret->Height + $other->Height) * $force / $mag + $ret->Height, $config->HeightMin); + $ret = clone $this; + $va = self::_unitVectorAt($this->Vec, $other->Vec); + $ret->Vec = self::_add($ret->Vec, self::_mul($va->vec, $force)); + if ($va->mag > self::ZeroThreshold) { + $ret->Height = max(($ret->Height + $other->Height) * $force / $va->mag + $ret->Height, $config->HeightMin); } return $ret; @@ -119,22 +149,127 @@ public function ApplyForce(CoordinateConfig $config, float $force, self $other): public function DistanceTo(self $other): Time\Duration { - static $secondsToNanoseconds = 1.0e9; - if (!$this->IsCompatibleWith($other)) { throw new DimensionalityConflictException(); } - $dist = $this->rawDistanceTo($other); + $dist = $this->rawDistanceTo($other); $adjustedDist = $dist + $this->Adjustment + $other->Adjustment; if ($adjustedDist > 0.0) { $dist = $adjustedDist; } - return Time::Duration($dist * $secondsToNanoseconds); + return Time::Duration($dist * self::secondsToNanoseconds); } protected function rawDistanceTo(self $other): float { - return magnitude(diff($this->Vec, $other->Vec)) + $this->Height + $other->Height; + return self::_magnitude(self::_diff($this->Vec, $other->Vec)) + $this->Height + $other->Height; + } + + private static function _componentIsValid(float $f): bool + { + return !is_nan($f) && is_finite($f); + } + + /** + * @param array $vec1 + * @param array $vec2 + * @return array + */ + public static function _add(array $vec1, array $vec2): array + { + $ret = []; + foreach ($vec1 as $k => $v) { + $ret[$k] = $v + $vec2[$k]; + } + return $ret; + } + + /** + * @param array $vec1 + * @param array $vec2 + * @return array + */ + public static function _diff(array $vec1, array $vec2): array + { + $ret = []; + foreach ($vec1 as $k => $v) { + $ret[$k] = $v - $vec2[$k]; + } + return $ret; + } + + /** + * @param array $vec + * @return array + */ + private static function _mul(array $vec, float $factor): array + { + $ret = []; + foreach ($vec as $k => $v) { + $ret[$k] = $v * $factor; + } + return $ret; + } + + /** + * @param array $vec + * @return float + */ + public static function _magnitude(array $vec): float + { + $sum = 0.0; + foreach ($vec as $k => $v) { + $sum += ($v * $v); + } + return sqrt($sum); + } + + /** + * @param array $vec1 + * @param array $vec2 + */ + public static function _unitVectorAt(array $vec1, array $vec2): CoordinateUnitVectorAt + { + $ret = self::_diff($vec1, $vec2); + + if (($mag = self::_magnitude($ret)) && $mag > self::ZeroThreshold) { + return new CoordinateUnitVectorAt(vec: self::_mul($ret, 1.0 / $mag), mag: $mag); + } + + foreach ($ret as $k => &$v) { + $v = lcg_value() - 0.5; + } + + if (($mag = self::_magnitude($ret)) && $mag > self::ZeroThreshold) { + return new CoordinateUnitVectorAt(vec: self::_mul($ret, 1.0 / $mag), mag: 0.0); + } + + $ret = array_fill(0, count($ret), 0.0); + $ret[0] = 1.0; + return new CoordinateUnitVectorAt(vec: $ret, mag: 0.0); + } + + public static function jsonUnserialize(\stdClass $decoded): self + { + $n = new self(); + foreach ((array)$decoded as $k => $v) { + if ('Vec' === $k) { + $n->Vec = (array)$v; + } else { + $n->{$k} = $v; + } + } + return $n; + } + + public function jsonSerialize(): \stdClass + { + $out = $this->_startJsonSerialize(); + $out->Vec = $this->Vec; + $out->Error = $this->Error; + $out->Adjustment = $this->Adjustment; + $out->Height = $this->Height; + return $out; } } diff --git a/src/Coordinate/CoordinateClient.php b/src/Coordinate/CoordinateClient.php index 42aed10e..47ebf65d 100644 --- a/src/Coordinate/CoordinateClient.php +++ b/src/Coordinate/CoordinateClient.php @@ -20,11 +20,10 @@ limitations under the License. */ -use DCarbone\Go\HTTP; -use DCarbone\PHPConsulAPI\AbstractClient; +use DCarbone\PHPConsulAPI\PHPLib\AbstractClient; +use DCarbone\PHPConsulAPI\PHPLib\WriteResponse; use DCarbone\PHPConsulAPI\QueryOptions; use DCarbone\PHPConsulAPI\WriteOptions; -use DCarbone\PHPConsulAPI\WriteResponse; class CoordinateClient extends AbstractClient { @@ -36,7 +35,7 @@ public function Datacenters(): CoordinateDatacentersResponse return $ret; } - public function Nodes(?QueryOptions $opts = null): CoordinateEntriesResponse + public function Nodes(null|QueryOptions $opts = null): CoordinateEntriesResponse { $resp = $this->_requireOK($this->_doGet('v1/coordinate/nodes', $opts)); $ret = new CoordinateEntriesResponse(); @@ -44,12 +43,12 @@ public function Nodes(?QueryOptions $opts = null): CoordinateEntriesResponse return $ret; } - public function Update(CoordinateEntry $coordinateEntry, ?WriteOptions $opts = null): WriteResponse + public function Update(CoordinateEntry $coordinateEntry, null|WriteOptions $opts = null): WriteResponse { return $this->_executePut('v1/coordinate/update', $coordinateEntry, $opts); } - public function Node(string $node, ?QueryOptions $opts = null): CoordinateEntriesResponse + public function Node(string $node, null|QueryOptions $opts = null): CoordinateEntriesResponse { $resp = $this->_requireOK($this->_doGet(sprintf('v1/coordinate/node/%s', $node), $opts)); $ret = new CoordinateEntriesResponse(); diff --git a/src/Coordinate/CoordinateConfig.php b/src/Coordinate/CoordinateConfig.php index 9ec4d450..d89949fd 100644 --- a/src/Coordinate/CoordinateConfig.php +++ b/src/Coordinate/CoordinateConfig.php @@ -20,9 +20,10 @@ limitations under the License. */ -use DCarbone\PHPConsulAPI\AbstractModel; +use DCarbone\PHPConsulAPI\Metrics\Label; +use DCarbone\PHPConsulAPI\PHPLib\AbstractType; -class CoordinateConfig extends AbstractModel +class CoordinateConfig extends AbstractType { public const DefaultDimensionality = 8; public const DefaultVivaldiErrorMax = 1.5; @@ -33,29 +34,51 @@ class CoordinateConfig extends AbstractModel public const DefaultLatencyFilterSize = 3; public const DefaultGravityRho = 150.0; - public int $Dimensionality = 0; - public float $VivaldiErrorMax = 0.0; - public float $VivaldiCE = 0.0; - public float $VivaldiCC = 0.0; - public int $AdjustmentWindowSize = 0; - public float $HeightMin = 0.0; - public int $LatencyFilterSize = 0; - public float $GravityRho = 0.0; - + public int $Dimensionality; + public float $VivaldiErrorMax; + public float $VivaldiCE; + public float $VivaldiCC; + public int $AdjustmentWindowSize; + public float $HeightMin; + public int $LatencyFilterSize; + public float $GravityRho; + /** @var array<\DCarbone\PHPConsulAPI\Metrics\Label> */ + public array $MetricsLabels; + + /** + * @param array<\DCarbone\PHPConsulAPI\Metrics\Label> $MetricsLabels + */ + public function __construct( + int $Dimensionality = self::DefaultDimensionality, + float $VivaldiErrorMax = self::DefaultVivaldiErrorMax, + float $VivaldiCE = self::DefaultVivaldiCE, + float $VivaldiCC = self::DefaultVivaldiCC, + int $AdjustmentWindowSize = self::DefaultAdjustmentWindowSize, + float $HeightMin = self::DefaultHeightMin, + int $LatencyFilterSize = self::DefaultLatencyFilterSize, + float $GravityRho = self::DefaultGravityRho, + array $MetricsLabels = [], + ) { + $this->Dimensionality = $Dimensionality; + $this->VivaldiErrorMax = $VivaldiErrorMax; + $this->VivaldiCE = $VivaldiCE; + $this->VivaldiCC = $VivaldiCC; + $this->AdjustmentWindowSize = $AdjustmentWindowSize; + $this->HeightMin = $HeightMin; + $this->LatencyFilterSize = $LatencyFilterSize; + $this->GravityRho = $GravityRho; + $this->setMetricsLabels(...$MetricsLabels); + } + + /** + * Create a new CoordinateConfig with default values. + * + * @deprecated Just call new CoordinateConfig() instead. + * @return self + */ public static function Default(): self { - return new static( - [ - 'Dimensionality' => static::DefaultDimensionality, - 'VivaldiErrorMax' => static::DefaultVivaldiErrorMax, - 'VivaldiCE' => static::DefaultVivaldiCE, - 'VivaldiCC' => static::DefaultVivaldiCC, - 'AdjustmentWindowSize' => static::DefaultAdjustmentWindowSize, - 'HeightMin' => static::DefaultHeightMin, - 'LatencyFilterSize' => static::DefaultLatencyFilterSize, - 'GravityRho' => static::DefaultGravityRho, - ] - ); + return new self(); } public function getDimensionality(): int @@ -63,9 +86,9 @@ public function getDimensionality(): int return $this->Dimensionality; } - public function setDimensionality(int $dimensionality): self + public function setDimensionality(int $Dimensionality): self { - $this->Dimensionality = $dimensionality; + $this->Dimensionality = $Dimensionality; return $this; } @@ -74,9 +97,9 @@ public function getVivaldiErrorMax(): float return $this->VivaldiErrorMax; } - public function setVivaldiErrorMax(float $vivaldiErrorMax): self + public function setVivaldiErrorMax(float $VivaldiErrorMax): self { - $this->VivaldiErrorMax = $vivaldiErrorMax; + $this->VivaldiErrorMax = $VivaldiErrorMax; return $this; } @@ -85,9 +108,9 @@ public function getVivaldiCE(): float return $this->VivaldiCE; } - public function setVivaldiCE(float $vivaldiCE): self + public function setVivaldiCE(float $VivaldiCE): self { - $this->VivaldiCE = $vivaldiCE; + $this->VivaldiCE = $VivaldiCE; return $this; } @@ -96,9 +119,9 @@ public function getVivaldiCC(): float return $this->VivaldiCC; } - public function setVivaldiCC(float $vivaldiCC): self + public function setVivaldiCC(float $VivaldiCC): self { - $this->VivaldiCC = $vivaldiCC; + $this->VivaldiCC = $VivaldiCC; return $this; } @@ -107,9 +130,9 @@ public function getAdjustmentWindowSize(): int return $this->AdjustmentWindowSize; } - public function setAdjustmentWindowSize(int $adjustmentWindowSize): self + public function setAdjustmentWindowSize(int $AdjustmentWindowSize): self { - $this->AdjustmentWindowSize = $adjustmentWindowSize; + $this->AdjustmentWindowSize = $AdjustmentWindowSize; return $this; } @@ -118,9 +141,9 @@ public function getHeightMin(): float return $this->HeightMin; } - public function setHeightMin(float $heightMin): self + public function setHeightMin(float $HeightMin): self { - $this->HeightMin = $heightMin; + $this->HeightMin = $HeightMin; return $this; } @@ -129,9 +152,9 @@ public function getLatencyFilterSize(): int return $this->LatencyFilterSize; } - public function setLatencyFilterSize(int $latencyFilterSize): self + public function setLatencyFilterSize(int $LatencyFilterSize): self { - $this->LatencyFilterSize = $latencyFilterSize; + $this->LatencyFilterSize = $LatencyFilterSize; return $this; } @@ -140,9 +163,54 @@ public function getGravityRho(): float return $this->GravityRho; } - public function setGravityRho(float $gravityRho): self + public function setGravityRho(float $GravityRho): self + { + $this->GravityRho = $GravityRho; + return $this; + } + + /** + * @return array<\DCarbone\PHPConsulAPI\Metrics\Label> + */ + public function getMetricsLabels(): array { - $this->GravityRho = $gravityRho; + return $this->MetricsLabels; + } + + public function setMetricsLabels(Label ...$MetricsLabels): self + { + $this->MetricsLabels = $MetricsLabels; return $this; } + + public static function jsonUnserialize(\stdClass $decoded): self + { + $n = new self(); + foreach ((array)$decoded as $k => $v) { + if ('MetricsLabels' === $k) { + $n->MetricsLabels = []; + foreach ($v as $vv) { + $n->MetricsLabels[] = Label::jsonUnserialize($vv); + } + } else { + $n->{$k} = $v; + } + } + return $n; + } + + public function jsonSerialize(): \stdClass + { + $out = $this->_startJsonSerialize(); + $out->Dimensionality = $this->Dimensionality; + $out->VivaldiErrorMax = $this->VivaldiErrorMax; + $out->VivaldiCE = $this->VivaldiCE; + $out->VivaldiCC = $this->VivaldiCC; + $out->AdjustmentWindowSize = $this->AdjustmentWindowSize; + $out->HeightMin = $this->HeightMin; + $out->LatencyFilterSize = $this->LatencyFilterSize; + $out->GravityRho = $this->GravityRho; + $out->MetricsLabels = $this->MetricsLabels; + return $out; + } } diff --git a/src/Coordinate/CoordinateDatacenterMap.php b/src/Coordinate/CoordinateDatacenterMap.php index 6cf83530..d8cf52ee 100644 --- a/src/Coordinate/CoordinateDatacenterMap.php +++ b/src/Coordinate/CoordinateDatacenterMap.php @@ -20,37 +20,86 @@ limitations under the License. */ -use DCarbone\PHPConsulAPI\AbstractModel; -use DCarbone\PHPConsulAPI\Transcoding; +use DCarbone\PHPConsulAPI\PHPLib\AbstractType; -class CoordinateDatacenterMap extends AbstractModel +class CoordinateDatacenterMap extends AbstractType { - protected const FIELDS = [ - self::FIELD_COORDINATES => [ - Transcoding::FIELD_TYPE => Transcoding::ARRAY, - Transcoding::FIELD_CLASS => Coordinate::class, - Transcoding::FIELD_ARRAY_TYPE => Transcoding::OBJECT, - ], - ]; + public string $Datacenter; + public string $AreaID; + /** @var array<\DCarbone\PHPConsulAPI\Coordinate\CoordinateEntry> */ + public array $Coordinates; - private const FIELD_COORDINATES = 'Coordinates'; - - public string $Datacenter = ''; - public string $AreaID = ''; - public array $Coordinates = []; + /** + * @param array<\DCarbone\PHPConsulAPI\Coordinate\CoordinateEntry> $Coordinates + */ + public function __construct( + string $Datacenter = '', + string $AreaID = '', + array $Coordinates = [], + ) { + $this->Datacenter = $Datacenter; + $this->AreaID = $AreaID; + $this->setCoordinates(...$Coordinates); + } public function getDatacenter(): string { return $this->Datacenter; } + public function setDatacenter(string $Datacenter): self + { + $this->Datacenter = $Datacenter; + return $this; + } + public function getAreaID(): string { return $this->AreaID; } + public function setAreaID(string $AreaID): self + { + $this->AreaID = $AreaID; + return $this; + } + + /** + * @return \DCarbone\PHPConsulAPI\Coordinate\CoordinateEntry[] + */ public function getCoordinates(): array { return $this->Coordinates; } + + public function setCoordinates(CoordinateEntry ...$Coordinates): self + { + $this->Coordinates = $Coordinates; + return $this; + } + + public static function jsonUnserialize(\stdClass $decoded): self + { + $n = new self(); + foreach ((array)$decoded as $k => $v) { + if ('Coordinates' === $k) { + $n->Coordinates = []; + foreach ($v as $vv) { + $n->Coordinates[] = CoordinateEntry::jsonUnserialize($vv); + } + } else { + $n->{$k} = $v; + } + } + return $n; + } + + public function jsonSerialize(): \stdClass + { + $out = $this->_startJsonSerialize(); + $out->Datacenter = $this->Datacenter; + $out->AreaID = $this->AreaID; + $out->Coordinates = $this->Coordinates; + return $out; + } } diff --git a/src/Coordinate/CoordinateDatacentersResponse.php b/src/Coordinate/CoordinateDatacentersResponse.php index 7953d3b4..6ee8c599 100644 --- a/src/Coordinate/CoordinateDatacentersResponse.php +++ b/src/Coordinate/CoordinateDatacentersResponse.php @@ -20,23 +20,27 @@ limitations under the License. */ -use DCarbone\PHPConsulAPI\AbstractValuedResponse; -use DCarbone\PHPConsulAPI\UnmarshalledResponseInterface; +use DCarbone\PHPConsulAPI\PHPLib\AbstractValuedResponse; +use DCarbone\PHPConsulAPI\PHPLib\UnmarshalledResponseInterface; class CoordinateDatacentersResponse extends AbstractValuedResponse implements UnmarshalledResponseInterface { - public ?array $DatacenterMap = null; + /** @var \DCarbone\PHPConsulAPI\Coordinate\CoordinateDatacenterMap[] */ + public array $DatacenterMap = []; - public function getValue(): ?array + /** + * @return \DCarbone\PHPConsulAPI\Coordinate\CoordinateDatacenterMap[] + */ + public function getValue(): array { return $this->DatacenterMap; } - public function unmarshalValue(mixed $decodedData): void + public function unmarshalValue(mixed $decoded): void { $this->DatacenterMap = []; - foreach ($decodedData as $item) { - $this->DatacenterMap[] = new CoordinateDatacenterMap($item); + foreach ($decoded as $item) { + $this->DatacenterMap[] = CoordinateDatacenterMap::jsonUnserialize($item); } } } diff --git a/src/Coordinate/CoordinateEntriesResponse.php b/src/Coordinate/CoordinateEntriesResponse.php index af95e426..863b44f9 100644 --- a/src/Coordinate/CoordinateEntriesResponse.php +++ b/src/Coordinate/CoordinateEntriesResponse.php @@ -20,23 +20,27 @@ limitations under the License. */ -use DCarbone\PHPConsulAPI\AbstractValuedQueryResponse; -use DCarbone\PHPConsulAPI\UnmarshalledResponseInterface; +use DCarbone\PHPConsulAPI\PHPLib\AbstractValuedQueryResponse; +use DCarbone\PHPConsulAPI\PHPLib\UnmarshalledResponseInterface; class CoordinateEntriesResponse extends AbstractValuedQueryResponse implements UnmarshalledResponseInterface { - public ?array $Nodes = null; + /** @var \DCarbone\PHPConsulAPI\Coordinate\CoordinateEntry[] */ + public array $Nodes = []; - public function getValue(): ?array + /** + * @return \DCarbone\PHPConsulAPI\Coordinate\CoordinateEntry[] + */ + public function getValue(): array { return $this->Nodes; } - public function unmarshalValue(mixed $decodedData): void + public function unmarshalValue(mixed $decoded): void { $this->Nodes = []; - foreach ($decodedData as $node) { - $this->Nodes[] = new CoordinateEntry($node); + foreach ($decoded as $node) { + $this->Nodes[] = CoordinateEntry::jsonUnserialize($node); } } } diff --git a/src/Coordinate/CoordinateEntry.php b/src/Coordinate/CoordinateEntry.php index d6503694..7cbba1a6 100644 --- a/src/Coordinate/CoordinateEntry.php +++ b/src/Coordinate/CoordinateEntry.php @@ -20,24 +20,26 @@ limitations under the License. */ -use DCarbone\PHPConsulAPI\AbstractModel; -use DCarbone\PHPConsulAPI\Transcoding; +use DCarbone\PHPConsulAPI\PHPLib\AbstractType; -class CoordinateEntry extends AbstractModel +class CoordinateEntry extends AbstractType { - protected const FIELDS = [ - self::FIELD_COORDINATE => [ - Transcoding::FIELD_TYPE => Transcoding::OBJECT, - Transcoding::FIELD_CLASS => Coordinate::class, - Transcoding::FIELD_NULLABLE => true, - ], - ]; - - private const FIELD_COORDINATE = 'Coord'; - - public string $Node = ''; - public string $Segment = ''; - public ?Coordinate $Coord = null; + public string $Node; + public string $Segment; + public string $Partition; + public null|Coordinate $Coord; + + public function __construct( + string $Node = '', + string $Segment = '', + string $Partition = '', + null|Coordinate $Coord = null, + ) { + $this->Node = $Node; + $this->Segment = $Segment; + $this->Partition = $Partition; + $this->Coord = $Coord; + } public function getNode(): string { @@ -61,14 +63,50 @@ public function setSegment(string $Segment): self return $this; } - public function getCoord(): ?Coordinate + public function getPartition(): string + { + return $this->Partition; + } + + public function setPartition(string $Partition): self + { + $this->Partition = $Partition; + return $this; + } + + public function getCoord(): null|Coordinate { return $this->Coord; } - public function setCoord(?Coordinate $Coord): self + public function setCoord(null|Coordinate $Coord): self { $this->Coord = $Coord; return $this; } + + public static function jsonUnserialize(\stdClass $decoded): self + { + $n = new self(); + foreach ((array)$decoded as $k => $v) { + if ('Coord' === $k) { + $n->Coord = Coordinate::jsonUnserialize($v); + } else { + $n->{$k} = $v; + } + } + return $n; + } + + public function jsonSerialize(): \stdClass + { + $out = $this->_startJsonSerialize(); + $out->Node = $this->Node; + $out->Segment = $this->Segment; + if ('' !== $this->Partition) { + $out->Partition = $this->Partition; + } + $out->Coord = $this->Coord; + return $out; + } } diff --git a/src/Coordinate/CoordinateUnitVectorAt.php b/src/Coordinate/CoordinateUnitVectorAt.php new file mode 100644 index 00000000..7e9bb395 --- /dev/null +++ b/src/Coordinate/CoordinateUnitVectorAt.php @@ -0,0 +1,67 @@ +|float> + */ +final class CoordinateUnitVectorAt implements \ArrayAccess +{ + /** @var array */ + public array $vec; + public float $mag; + + /** + * @param array $vec + */ + public function __construct(array $vec, float $mag) + { + $this->vec = $vec; + $this->mag = $mag; + } + + public function offsetExists(mixed $offset): bool + { + return 0 === $offset || 1 === $offset; + } + + /** + * @return array|float + */ + public function offsetGet(mixed $offset): array|float + { + return match ($offset) { + 0 => $this->vec, + 1 => $this->mag, + default => throw new \OutOfBoundsException("Invalid offset: $offset"), + }; + } + + public function offsetSet(mixed $offset, mixed $value): void + { + throw new \BadMethodCallException('CoordinateUnitVectorAt cannot be mutated as if it were an array.'); + } + + public function offsetUnset(mixed $offset): void + { + throw new \BadMethodCallException('CoordinateUnitVectorAt cannot be mutated as if it were an array.'); + } +} diff --git a/src/Coordinate/funcs.php b/src/Coordinate/funcs.php deleted file mode 100644 index 88d0eadd..00000000 --- a/src/Coordinate/funcs.php +++ /dev/null @@ -1,100 +0,0 @@ - ZeroThreshold) { - return [mul($ret, 1.0 / $mag), $mag]; - } - - foreach ($ret as $k => &$v) { - $v = lcg_value() - 0.5; - } - - if (($mag = magnitude($ret)) && $mag > ZeroThreshold) { - return [mul($ret, 1.0 / $mag), 0.0]; - } - - $ret = array_fill(0, \count($ret), 0.0); - $ret[0] = 1.0; - return $ret; -} - -/** - * @param array $vec1 - * @param array $vec2 - * @return array - */ -function add(array $vec1, array $vec2): array -{ - $ret = []; - foreach ($vec1 as $k => $v) { - $ret[$k] = $v + $vec2[$k]; - } - return $ret; -} - -/** - * @param array $vec1 - * @param array $vec2 - * @return array - */ -function diff(array $vec1, array $vec2): array -{ - $ret = []; - foreach ($vec1 as $k => $v) { - $ret[$k] = $v - $vec2[$k]; - } - return $ret; -} - -function mul(array $vec, float $factor): array -{ - $ret = []; - foreach ($vec as $k => $v) { - $ret[$k] = $v * $factor; - } - return $ret; -} - -function magnitude(array $vec): float -{ - $sum = 0.0; - foreach ($vec as $k => $v) { - $sum += ($v * $v); - } - return sqrt($sum); -} diff --git a/src/Debug/DebugClient.php b/src/Debug/DebugClient.php index a96f89aa..0ee42b07 100644 --- a/src/Debug/DebugClient.php +++ b/src/Debug/DebugClient.php @@ -21,9 +21,9 @@ */ use DCarbone\Go\HTTP; -use DCarbone\PHPConsulAPI\AbstractClient; -use DCarbone\PHPConsulAPI\Error; -use DCarbone\PHPConsulAPI\ValuedStringResponse; +use DCarbone\PHPConsulAPI\PHPLib\AbstractClient; +use DCarbone\PHPConsulAPI\PHPLib\Error; +use DCarbone\PHPConsulAPI\PHPLib\ValuedStringResponse; class DebugClient extends AbstractClient { diff --git a/src/Event/EventClient.php b/src/Event/EventClient.php index aa76bed0..07a51a3a 100644 --- a/src/Event/EventClient.php +++ b/src/Event/EventClient.php @@ -20,13 +20,13 @@ limitations under the License. */ -use DCarbone\PHPConsulAPI\AbstractClient; +use DCarbone\PHPConsulAPI\PHPLib\AbstractClient; use DCarbone\PHPConsulAPI\QueryOptions; use DCarbone\PHPConsulAPI\WriteOptions; class EventClient extends AbstractClient { - public function Fire(UserEvent $event, ?WriteOptions $opts = null): UserEventResponse + public function Fire(UserEvent $event, null|WriteOptions $opts = null): UserEventResponse { $r = $this->_newPutRequest(sprintf('v1/event/fire/%s', $event->Name), '' !== $event->Payload ? $event->Payload : null, $opts); if ('' !== ($nf = $event->NodeFilter)) { @@ -44,7 +44,7 @@ public function Fire(UserEvent $event, ?WriteOptions $opts = null): UserEventRes return $ret; } - public function List(string $name = '', ?QueryOptions $opts = null): UserEventsResponse + public function List(string $name = '', null|QueryOptions $opts = null): UserEventsResponse { $r = $this->_newGetRequest('v1/event/list', $opts); if ('' !== $name) { @@ -58,17 +58,17 @@ public function List(string $name = '', ?QueryOptions $opts = null): UserEventsR public function IDToIndex(string $uuid): int { - if (36 !== \strlen($uuid)) { + if (36 !== strlen($uuid)) { throw new \InvalidArgumentException("{$uuid} is not a valid UUID"); } - $lower = substr($uuid, 0, 8) + substr($uuid, 9, 4) + substr($uuid, 14, 4); - $upper = substr($uuid, 19, 4) + substr($uuid, 24, 12); - $lowVal = \intval($lower, 10); + $lower = sprintf('%s%s%s', substr($uuid, 0, 8), substr($uuid, 9, 4), substr($uuid, 14, 4)); + $upper = sprintf('%s%s', substr($uuid, 19, 4), substr($uuid, 24, 12)); + $lowVal = intval($lower, 10); if (0 >= $lowVal) { throw new \InvalidArgumentException("{$lower} is not greater than 0"); } - $highVal = \intval($upper, 10); + $highVal = intval($upper, 10); if (0 >= $highVal) { throw new \InvalidArgumentException("{$upper} is not greater than 0"); } diff --git a/src/Event/UserEvent.php b/src/Event/UserEvent.php index ae640733..50fbf991 100644 --- a/src/Event/UserEvent.php +++ b/src/Event/UserEvent.php @@ -20,35 +20,37 @@ limitations under the License. */ -use DCarbone\PHPConsulAPI\AbstractModel; +use DCarbone\PHPConsulAPI\PHPLib\AbstractType; -class UserEvent extends AbstractModel +class UserEvent extends AbstractType { - public string $ID = ''; - public string $Name = ''; - public string $Payload = ''; - public string $NodeFilter = ''; - public string $ServiceFilter = ''; - public string $TagFilter = ''; - public int $Version = 0; - public int $LTime = 0; - - /** - * UserEvent constructor. - * - * @param array $data - * @param bool $_decodeValue - */ - public function __construct(array $data = [], bool $_decodeValue = false) - { - parent::__construct($data); - if ($_decodeValue) { - $dec = base64_decode($this->Payload, true); - if (false === $dec) { - throw new \InvalidArgumentException(sprintf('Could not base64 decode payload "%s"', $this->Payload)); - } - $this->Payload = $dec; - } + public string $ID; + public string $Name; + public string $Payload; + public string $NodeFilter; + public string $ServiceFilter; + public string $TagFilter; + public int $Version; + public int $LTime; + + public function __construct( + string $ID = '', + string $Name = '', + string $Payload = '', + string $NodeFilter = '', + string $ServiceFilter = '', + string $TagFilter = '', + int $Version = 0, + int $LTime = 0, + ) { + $this->ID = $ID; + $this->Name = $Name; + $this->Payload = $Payload; + $this->NodeFilter = $NodeFilter; + $this->ServiceFilter = $ServiceFilter; + $this->TagFilter = $TagFilter; + $this->Version = $Version; + $this->LTime = $LTime; } public function getID(): string @@ -56,38 +58,109 @@ public function getID(): string return $this->ID; } + public function setID(string $ID): self + { + $this->ID = $ID; + return $this; + } + public function getName(): string { return $this->Name; } + public function setName(string $Name): self + { + $this->Name = $Name; + return $this; + } + public function getPayload(): string { return $this->Payload; } + public function setPayload(string $Payload): self + { + $this->Payload = $Payload; + return $this; + } + public function getNodeFilter(): string { return $this->NodeFilter; } + public function setNodeFilter(string $NodeFilter): self + { + $this->NodeFilter = $NodeFilter; + return $this; + } + public function getServiceFilter(): string { return $this->ServiceFilter; } + public function setServiceFilter(string $ServiceFilter): self + { + $this->ServiceFilter = $ServiceFilter; + return $this; + } + public function getTagFilter(): string { return $this->TagFilter; } + public function setTagFilter(string $TagFilter): self + { + $this->TagFilter = $TagFilter; + return $this; + } + public function getVersion(): int { return $this->Version; } + public function setVersion(int $Version): self + { + $this->Version = $Version; + return $this; + } + public function getLTime(): int { return $this->LTime; } + + public function setLTime(int $LTime): self + { + $this->LTime = $LTime; + return $this; + } + + public static function jsonUnserialize(\stdClass $decoded): self + { + $n = new self(); + foreach ((array)$decoded as $k => $v) { + $n->{$k} = $v; + } + return $n; + } + + public function jsonSerialize(): \stdClass + { + $out = $this->_startJsonSerialize(); + $out->ID = $this->ID; + $out->Name = $this->Name; + $out->Payload = $this->Payload; + $out->NodeFilter = $this->NodeFilter; + $out->ServiceFilter = $this->ServiceFilter; + $out->TagFilter = $this->TagFilter; + $out->Version = $this->Version; + $out->LTime = $this->LTime; + return $out; + } } diff --git a/src/Event/UserEventResponse.php b/src/Event/UserEventResponse.php index 1b854d71..eb03c7c4 100644 --- a/src/Event/UserEventResponse.php +++ b/src/Event/UserEventResponse.php @@ -20,20 +20,24 @@ limitations under the License. */ -use DCarbone\PHPConsulAPI\AbstractValuedWriteResponse; -use DCarbone\PHPConsulAPI\UnmarshalledResponseInterface; +use DCarbone\PHPConsulAPI\PHPLib\AbstractValuedWriteResponse; +use DCarbone\PHPConsulAPI\PHPLib\UnmarshalledResponseInterface; class UserEventResponse extends AbstractValuedWriteResponse implements UnmarshalledResponseInterface { - public ?UserEvent $UserEvent = null; + public null|UserEvent $UserEvent = null; - public function getValue(): ?UserEvent + public function getValue(): null|UserEvent { return $this->UserEvent; } - public function unmarshalValue(mixed $decodedData): void + public function unmarshalValue(mixed $decoded): void { - $this->UserEvent = new UserEvent((array)$decodedData); + if (null === $decoded) { + $this->UserEvent = null; + return; + } + $this->UserEvent = UserEvent::jsonUnserialize($decoded); } } diff --git a/src/Event/UserEventsResponse.php b/src/Event/UserEventsResponse.php index b9eb5f61..50b967b1 100644 --- a/src/Event/UserEventsResponse.php +++ b/src/Event/UserEventsResponse.php @@ -20,23 +20,27 @@ limitations under the License. */ -use DCarbone\PHPConsulAPI\AbstractValuedQueryResponse; -use DCarbone\PHPConsulAPI\UnmarshalledResponseInterface; +use DCarbone\PHPConsulAPI\PHPLib\AbstractValuedQueryResponse; +use DCarbone\PHPConsulAPI\PHPLib\UnmarshalledResponseInterface; class UserEventsResponse extends AbstractValuedQueryResponse implements UnmarshalledResponseInterface { - public ?array $UserEvents = null; + /** @var \DCarbone\PHPConsulAPI\Event\UserEvent[] */ + public array $UserEvents = []; - public function getValue(): ?array + /** + * @return \DCarbone\PHPConsulAPI\Event\UserEvent[] + */ + public function getValue(): array { return $this->UserEvents; } - public function unmarshalValue(mixed $decodedData): void + public function unmarshalValue(mixed $decoded): void { $this->UserEvents = []; - foreach ($decodedData as $datum) { - $this->UserEvents[] = new UserEvent($datum); + foreach ($decoded as $datum) { + $this->UserEvents[] = UserEvent::jsonUnserialize($datum); } } } diff --git a/src/FakeMap.php b/src/FakeMap.php deleted file mode 100644 index 5376a1b2..00000000 --- a/src/FakeMap.php +++ /dev/null @@ -1,108 +0,0 @@ -_map = $data; - } - - public static function parse(array|FakeMap|\stdClass|null $input): ?self - { - if (null === $input) { - return null; - } - if (\is_object($input)) { - if ($input instanceof self) { - return $input; - } - return new self((array)$input); - } - if (\is_array($input)) { - return new self($input); - } - throw new \InvalidArgumentException( - sprintf('Cannot parse input of type %s to %s', \gettype($input), self::class) - ); - } - - public function current(): mixed - { - return current($this->_map); - } - - public function next(): void - { - next($this->_map); - } - - public function key(): int|string|null - { - return key($this->_map); - } - - public function valid(): bool - { - return null !== key($this->_map); - } - - public function rewind(): void - { - reset($this->_map); - } - - public function offsetExists(mixed $offset): bool - { - return isset($this->_map[$offset]) || \array_key_exists($offset, $this->_map); - } - - public function offsetGet(mixed $offset): mixed - { - return $this->_map[$offset] ?? null; - } - - public function offsetSet(mixed $offset, mixed $value): void - { - $this->_map[$offset] = $value; - } - - public function offsetUnset(mixed $offset): void - { - unset($this->_map[$offset]); - } - - public function count(): int - { - return \count($this->_map); - } - - public function jsonSerialize(): object - { - return (object)$this->getArrayCopy(); - } -} diff --git a/src/FakeSlice.php b/src/FakeSlice.php deleted file mode 100644 index 255bdf4d..00000000 --- a/src/FakeSlice.php +++ /dev/null @@ -1,188 +0,0 @@ -containedClass)) { - throw new \DomainException( - sprintf( - 'Class "%s" must define $containedClass', - static::class - ) - ); - } - // fastpath for "empty" - if (null === $children || [] === $children) { - return; - } - foreach ($children as $child) { - $this->append($child); - } - } - - public function append(array|AbstractModel|null $value): void - { - // validate provided value is either null or instance of allowed child class - $value = $this->_validateValue($value); - - // set offset to current value of _size, and iterate size by 1 - $offset = $this->_size++; - - // if value is passed, clone then set. - $this->_list[$offset] = $value; - } - - public function current(): bool|AbstractModel - { - return current($this->_list); - } - - public function next(): void - { - next($this->_list); - } - - public function key(): ?int - { - return key($this->_list); - } - - public function valid(): bool - { - return null !== key($this->_list); - } - - public function rewind(): void - { - reset($this->_list); - } - - public function offsetExists(mixed $offset): bool - { - return \is_int($offset) && isset($this->_list[$offset]); - } - - public function offsetGet(mixed $offset): ?AbstractModel - { - $this->_validateOffset($offset); - return $this->_list[$offset]; - } - - public function offsetSet(mixed $offset, mixed $value): void - { - // if incoming offset is null, assume [] (append) operation. - if (null === $offset) { - $this->append($value); - return; - } - - // validate provided offset value - $this->_validateOffset($offset); - - // validate value input and set - $this->_list[$offset] = $this->_validateValue($value); - } - - public function offsetUnset(mixed $offset): void - { - // validate provided offset value - $this->_validateOffset($offset); - - // null out value in list - $this->_list[$offset] = null; - } - - public function count(): int - { - return $this->_size; - } - - public function jsonSerialize(): array - { - if (0 === $this->_size) { - return []; - } - - $out = []; - foreach ($this->_list as $i => $item) { - if (null === $item) { - $out[$i] = null; - } else { - $out[$i] = clone $item; - } - } - return $out; - } - - abstract protected function newChild(array $data): AbstractModel; - - private function _validateOffset(mixed $offset): void - { - if (!\is_int($offset)) { - throw new \InvalidArgumentException( - sprintf( - 'Cannot use offset of type "%s" with "%s"', - \gettype($offset), - static::class - ) - ); - } - if (0 > $offset || $offset >= $this->_size) { - throw new \OutOfRangeException(sprintf('Offset %d does not exist in this list', $offset)); - } - } - - private function _validateValue(mixed $value): ?AbstractModel - { - // fast path for null values - if (null === $value) { - return null; - } - - // if instance of contained class, clone and move on - if ($value instanceof $this->containedClass) { - return clone $value; - } - - // if array, construct new child - if (\is_array($value)) { - return $this->newChild($value); - } - - // if we make it down here, fail. - throw new \InvalidArgumentException( - sprintf( - '%s accepts only objects of type %s, null, or associative array definition as values', - static::class, - $this->containedClass, - ) - ); - } -} diff --git a/src/Health/HealthCheck.php b/src/Health/HealthCheck.php index 6b6e88c1..441ef412 100644 --- a/src/Health/HealthCheck.php +++ b/src/Health/HealthCheck.php @@ -20,43 +20,68 @@ limitations under the License. */ -use DCarbone\PHPConsulAPI\AbstractModel; -use DCarbone\PHPConsulAPI\Transcoding; +use DCarbone\PHPConsulAPI\PHPLib\AbstractType; -class HealthCheck extends AbstractModel +class HealthCheck extends AbstractType { - protected const FIELDS = [ - self::FIELD_NAMESPACE => Transcoding::OMITEMPTY_STRING_FIELD, - self::FIELD_DEFINITION => [ - Transcoding::FIELD_TYPE => Transcoding::OBJECT, - Transcoding::FIELD_CLASS => HealthCheckDefinition::class, - ], - ]; - - private const FIELD_NAMESPACE = 'Namespace'; - private const FIELD_DEFINITION = 'Definition'; - - public string $Node = ''; - public string $CheckID = ''; - public string $Name = ''; - public string $Status = ''; - public string $Notes = ''; - public string $Output = ''; - public string $ServiceID = ''; - public string $ServiceName = ''; - public array $ServiceTags = []; - public string $Type = ''; - public string $Namespace = ''; + public string $Node; + public string $CheckID; + public string $Name; + public string $Status; + public string $Notes; + public string $Output; + public string $ServiceID; + public string $ServiceName; + /** @var array */ + public array $ServiceTags; + public string $Type; + public string $Namespace; + public string $Partition; + public int $ExposedPort; + public string $PeerName; public HealthCheckDefinition $Definition; - public int $CreateIndex = 0; - public int $ModifyIndex = 0; - - public function __construct(?array $data = []) - { - parent::__construct($data); - if (!isset($this->Definition)) { - $this->Definition = new HealthCheckDefinition(null); - } + public int $CreateIndex; + public int $ModifyIndex; + + /** + * @param array $ServiceTags + */ + public function __construct( + string $Node = '', + string $CheckID = '', + string $Name = '', + string $Status = '', + string $Notes = '', + string $Output = '', + string $ServiceID = '', + string $ServiceName = '', + array $ServiceTags = [], + string $Type = '', + string $Namespace = '', + string $Partition = '', + int $ExposedPort = 0, + string $PeerName = '', + null|HealthCheckDefinition $Definition = null, + int $CreateIndex = 0, + int $ModifyIndex = 0, + ) { + $this->Node = $Node; + $this->CheckID = $CheckID; + $this->Name = $Name; + $this->Status = $Status; + $this->Notes = $Notes; + $this->Output = $Output; + $this->ServiceID = $ServiceID; + $this->ServiceName = $ServiceName; + $this->setServiceTags(...$ServiceTags); + $this->Type = $Type; + $this->Namespace = $Namespace; + $this->Partition = $Partition; + $this->ExposedPort = $ExposedPort; + $this->PeerName = $PeerName; + $this->Definition = $Definition ?? new HealthCheckDefinition(); + $this->CreateIndex = $CreateIndex; + $this->ModifyIndex = $ModifyIndex; } public function getNode(): string @@ -147,12 +172,15 @@ public function setServiceName(string $ServiceName): self return $this; } + /** + * @return array + */ public function getServiceTags(): array { return $this->ServiceTags; } - public function setServiceTags(array $ServiceTags): self + public function setServiceTags(string ...$ServiceTags): self { $this->ServiceTags = $ServiceTags; return $this; @@ -180,6 +208,39 @@ public function setNamespace(string $Namespace): self return $this; } + public function getPartition(): string + { + return $this->Partition; + } + + public function setPartition(string $Partition): self + { + $this->Partition = $Partition; + return $this; + } + + public function getExposedPort(): int + { + return $this->ExposedPort; + } + + public function setExposedPort(int $ExposedPort): self + { + $this->ExposedPort = $ExposedPort; + return $this; + } + + public function getPeerName(): string + { + return $this->PeerName; + } + + public function setPeerName(string $PeerName): self + { + $this->PeerName = $PeerName; + return $this; + } + public function getDefinition(): HealthCheckDefinition { return $this->Definition; @@ -212,4 +273,48 @@ public function setModifyIndex(int $ModifyIndex): self $this->ModifyIndex = $ModifyIndex; return $this; } + + public static function jsonUnserialize(\stdClass $decoded): self + { + $n = new self(); + foreach ((array)$decoded as $k => $v) { + if ('Definition' === $k) { + $n->Definition = HealthCheckDefinition::jsonUnserialize($v); + } elseif ('ServiceTags' === $k) { + $n->setServiceTags(...$v); + } else { + $n->{$k} = $v; + } + } + return $n; + } + + public function jsonSerialize(): \stdClass + { + $out = $this->_startJsonSerialize(); + $out->Node = $this->Node; + $out->CheckID = $this->CheckID; + $out->Name = $this->Name; + $out->Status = $this->Status; + $out->Notes = $this->Notes; + $out->Output = $this->Output; + $out->ServiceID = $this->ServiceID; + $out->ServiceName = $this->ServiceName; + $out->ServiceTags = $this->ServiceTags; + $out->Type = $this->Type; + if ('' !== $this->Namespace) { + $out->Namespace = $this->Namespace; + } + if ('' !== $this->Partition) { + $out->Partition = $this->Partition; + } + $out->ExposedPort = $this->ExposedPort; + if ('' !== $this->PeerName) { + $out->PeerName = $this->PeerName; + } + $out->Definition = $this->Definition; + $out->CreateIndex = $this->CreateIndex; + $out->ModifyIndex = $this->ModifyIndex; + return $out; + } } diff --git a/src/Health/HealthCheckDefinition.php b/src/Health/HealthCheckDefinition.php index 1c6a1e1e..f03397fd 100644 --- a/src/Health/HealthCheckDefinition.php +++ b/src/Health/HealthCheckDefinition.php @@ -21,96 +21,59 @@ */ use DCarbone\Go\Time; -use DCarbone\Go\Time\Duration; -use DCarbone\PHPConsulAPI\AbstractModel; -use DCarbone\PHPConsulAPI\Operator\ReadableDuration; -use DCarbone\PHPConsulAPI\Transcoding; +use DCarbone\PHPConsulAPI\PHPLib\AbstractType; +use DCarbone\PHPConsulAPI\PHPLib\Values; -class HealthCheckDefinition extends AbstractModel implements \JsonSerializable +class HealthCheckDefinition extends AbstractType implements \JsonSerializable { - protected const FIELDS = [ - self::FIELD_INTERVAL_DURATION => [ - Transcoding::FIELD_UNMARSHAL_CALLBACK => Transcoding::UNMARSHAL_DURATION, - Transcoding::FIELD_SKIP => true, - ], - self::FIELD_TIMEOUT_DURATION => [ - Transcoding::FIELD_UNMARSHAL_CALLBACK => Transcoding::UNMARSHAL_DURATION, - Transcoding::FIELD_SKIP => true, - ], - self::FIELD_DEREGISTER_CRITICAL_SERVICE_AFTER_DURATION => [ - Transcoding::FIELD_UNMARSHAL_CALLBACK => Transcoding::UNMARSHAL_DURATION, - Transcoding::FIELD_SKIP => true, - ], - self::FIELD_TIMEOUT => [ - Transcoding::FIELD_UNMARSHAL_CALLBACK => [ReadableDuration::class, 'unmarshalJSON'], - ], - self::FIELD_INTERVAL => [ - Transcoding::FIELD_UNMARSHAL_CALLBACK => [ReadableDuration::class, 'unmarshalJSON'], - ], - self::FIELD_DEREGISTER_CRITICAL_SERVICE_AFTER => [ - Transcoding::FIELD_UNMARSHAL_CALLBACK => [ReadableDuration::class, 'unmarshalJSON'], - ], - ]; - - private const FIELD_HTTP = 'HTTP'; - private const FIELD_HEADER = 'Header'; - private const FIELD_METHOD = 'Method'; - private const FIELD_BODY = 'Body'; - private const FIELD_TLS_SKIP_VERIFY = 'TLSSkipVerify'; - private const FIELD_TCP = 'TCP'; - private const FIELD_INTERVAL_DURATION = 'IntervalDuration'; - private const FIELD_TIMEOUT_DURATION = 'TimeoutDuration'; - private const FIELD_DEREGISTER_CRITICAL_SERVICE_AFTER_DURATION = 'DeregisterCriticalServiceAfterDuration'; - private const FIELD_INTERVAL = 'Interval'; - private const FIELD_TIMEOUT = 'Timeout'; - private const FIELD_DEREGISTER_CRITICAL_SERVICE_AFTER = 'DeregisterCriticalServiceAfter'; - - public string $HTTP = ''; - public array $Header = []; - public string $Method = ''; - public string $Body = ''; - public bool $TLSSkipVerify = false; - public string $TCP = ''; - public Duration $IntervalDuration; - public Duration $TimeoutDuration; - public Duration $DeregisterCriticalServiceAfterDuration; - - public ReadableDuration $Interval; - public ReadableDuration $Timeout; - public ReadableDuration $DeregisterCriticalServiceAfter; - - public function __construct(?array $data = null) - { - parent::__construct($data); - if (!isset($this->Interval)) { - $this->Interval = new ReadableDuration(); - } - if (!isset($this->Timeout)) { - $this->Timeout = new ReadableDuration(); - } - if (!isset($this->DeregisterCriticalServiceAfter)) { - $this->DeregisterCriticalServiceAfter = new ReadableDuration(); - } + public string $HTTP; + public Values $Header; + public string $Method; + public string $Body; + public bool $TLSSkipVerify; + public string $TCP; + public bool $TCPUseTLS; + public string $UDP; + public string $GRPC; + public string $OSService; + public bool $GRPCUseTLS; + public Time\Duration $IntervalDuration; + public Time\Duration $TimeoutDuration; + public Time\Duration $DeregisterCriticalServiceAfterDuration; - if (!isset($this->IntervalDuration)) { - $this->IntervalDuration = Time::ParseDuration((string)$this->Interval); - } else { - $this->Interval = ReadableDuration::fromDuration((string)$this->IntervalDuration); - } - if (!isset($this->TimeoutDuration)) { - $this->TimeoutDuration = Time::ParseDuration((string)$this->Timeout); - } else { - $this->Timeout = ReadableDuration::fromDuration((string)$this->TimeoutDuration); - } - if (!isset($this->DeregisterCriticalServiceAfterDuration)) { - $this->DeregisterCriticalServiceAfterDuration = Time::ParseDuration( - (string)$this->DeregisterCriticalServiceAfter - ); - } else { - $this->DeregisterCriticalServiceAfter = ReadableDuration::fromDuration( - (string)$this->DeregisterCriticalServiceAfterDuration - ); - } + /** + * @param array>|\DCarbone\PHPConsulAPI\PHPLib\Values|null $Header + */ + public function __construct( + string $HTTP = '', + null|array|\stdClass|Values $Header = null, + string $Method = '', + string $Body = '', + bool $TLSSkipVerify = false, + string $TCP = '', + bool $TCPUseTLS = false, + string $UDP = '', + string $GRPC = '', + string $OSService = '', + bool $GRPCUseTLS = false, + null|int|float|string|\DateInterval|Time\Duration $IntervalDuration = null, + null|int|float|string|\DateInterval|Time\Duration $TimeoutDuration = null, + null|int|float|string|\DateInterval|Time\Duration $DeregisterCriticalServiceAfterDuration = null, + ) { + $this->HTTP = $HTTP; + $this->setHeader($Header); + $this->Method = $Method; + $this->Body = $Body; + $this->TLSSkipVerify = $TLSSkipVerify; + $this->TCP = $TCP; + $this->TCPUseTLS = $TCPUseTLS; + $this->UDP = $UDP; + $this->GRPC = $GRPC; + $this->OSService = $OSService; + $this->GRPCUseTLS = $GRPCUseTLS; + $this->IntervalDuration = Time::Duration($IntervalDuration); + $this->TimeoutDuration = Time::Duration($TimeoutDuration); + $this->DeregisterCriticalServiceAfterDuration = Time::Duration($DeregisterCriticalServiceAfterDuration); } public function getHTTP(): string @@ -118,16 +81,45 @@ public function getHTTP(): string return $this->HTTP; } - public function getHeader(): array + public function setHTTP(string $HTTP): self + { + $this->HTTP = $HTTP; + return $this; + } + + public function getHeader(): Values { return $this->Header; } + /** + * @param array>|\DCarbone\PHPConsulAPI\PHPLib\Values|null $Header + * @return $this + */ + public function setHeader(null|array|\stdClass|Values $Header = []): self + { + if (null === $Header) { + $this->Header = new Values(); + return $this; + } + if (!$Header instanceof Values) { + $Header = Values::fromArray((array)$Header); + } + $this->Header = $Header; + return $this; + } + public function getMethod(): string { return $this->Method; } + public function setMethod(string $Method): self + { + $this->Method = $Method; + return $this; + } + public function getBody(): string { return $this->Body; @@ -144,75 +136,148 @@ public function isTLSSkipVerify(): bool return $this->TLSSkipVerify; } + public function setTLSSkipVerify(bool $TLSSkipVerify): self + { + $this->TLSSkipVerify = $TLSSkipVerify; + return $this; + } + public function getTCP(): string { return $this->TCP; } - public function getIntervalDuration(): ?Duration + public function setTCP(string $TCP): self { - return $this->IntervalDuration; + $this->TCP = $TCP; + return $this; } - public function getTimeoutDuration(): ?Duration + public function isTCPUseTLS(): bool { - return $this->TimeoutDuration; + return $this->TCPUseTLS; } - public function getDeregisterCriticalServiceAfterDuration(): ?Duration + public function setTCPUseTLS(bool $TCPUseTLS): self { - return $this->DeregisterCriticalServiceAfterDuration; + $this->TCPUseTLS = $TCPUseTLS; + return $this; } - public function getInterval(): ?ReadableDuration + public function getUDP(): string { - return $this->Interval; + return $this->UDP; } - public function getTimeout(): ?ReadableDuration + public function setUDP(string $UDP): self { - return $this->Timeout; + $this->UDP = $UDP; + return $this; } - public function getDeregisterCriticalServiceAfter(): ?ReadableDuration + public function getGRPC(): string { - return $this->DeregisterCriticalServiceAfter; + return $this->GRPC; } - public function jsonSerialize(): array + public function setGRPC(string $GRPC): self { - // prepare base definition - $prep = [ - self::FIELD_HTTP => $this->HTTP, - self::FIELD_HEADER => $this->Header, - self::FIELD_METHOD => $this->Method, - self::FIELD_BODY => $this->Body, - self::FIELD_TLS_SKIP_VERIFY => $this->TLSSkipVerify, - self::FIELD_TCP => $this->TCP, + $this->GRPC = $GRPC; + return $this; + } - ]; - if (0 !== $this->IntervalDuration->Nanoseconds()) { - $prep[self::FIELD_INTERVAL] = (string)$this->IntervalDuration; - } elseif (0 !== $this->Interval->Nanoseconds()) { - $prep[self::FIELD_INTERVAL] = (string)$this->Interval; - } - if (0 !== $this->TimeoutDuration->Nanoseconds()) { - $prep[self::FIELD_TIMEOUT] = (string)$this->TimeoutDuration; - } elseif (0 !== $this->Timeout->Nanoseconds()) { - $prep[self::FIELD_TIMEOUT] = (string)$this->Timeout; - } - if (0 !== $this->DeregisterCriticalServiceAfterDuration->Nanoseconds()) { - $prep[self::FIELD_DEREGISTER_CRITICAL_SERVICE_AFTER] = (string)$this->DeregisterCriticalServiceAfterDuration; - } elseif (0 !== $this->DeregisterCriticalServiceAfter->Nanoseconds()) { - $prep[self::FIELD_DEREGISTER_CRITICAL_SERVICE_AFTER] = (string)$this->DeregisterCriticalServiceAfter; - } + public function getOSService(): string + { + return $this->OSService; + } - // handle per-field marshalling - $out = []; - foreach ($prep as $field => $value) { - $this->marshalField($out, $field, $value); + public function setOSService(string $OSService): self + { + $this->OSService = $OSService; + return $this; + } + + public function isGRPCUseTLS(): bool + { + return $this->GRPCUseTLS; + } + + public function setGRPCUseTLS(bool $GRPCUseTLS): self + { + $this->GRPCUseTLS = $GRPCUseTLS; + return $this; + } + + public function getIntervalDuration(): Time\Duration + { + return $this->IntervalDuration; + } + + public function setIntervalDuration(null|int|float|string|\DateInterval|Time\Duration $IntervalDuration): self + { + $this->IntervalDuration = Time::Duration($IntervalDuration); + return $this; + } + + public function getTimeoutDuration(): Time\Duration + { + return $this->TimeoutDuration; + } + + public function setTimeoutDuration(null|int|float|string|\DateInterval|Time\Duration $TimeoutDuration): self + { + $this->TimeoutDuration = Time::Duration($TimeoutDuration); + return $this; + } + + public function getDeregisterCriticalServiceAfterDuration(): Time\Duration + { + return $this->DeregisterCriticalServiceAfterDuration; + } + + public function setDeregisterCriticalServiceAfterDuration( + null|int|float|string|\DateInterval|Time\Duration $DeregisterCriticalServiceAfterDuration + ): self { + $this->DeregisterCriticalServiceAfterDuration = Time::Duration($DeregisterCriticalServiceAfterDuration); + return $this; + } + + public static function jsonUnserialize(\stdClass $decoded): self + { + $n = new self(); + foreach ((array)$decoded as $k => $v) { + if ('Interval' === $k || 'IntervalDuration' === $k) { + $n->IntervalDuration = Time::Duration($v); + } elseif ('Timeout' === $k || 'TimeoutDuration' === $k) { + $n->TimeoutDuration = Time::Duration($v); + } elseif ('DeregisterCriticalServiceAfter' === $k || 'DeregisterCriticalServiceAfterDuration' === $k) { + $n->DeregisterCriticalServiceAfterDuration = Time::Duration($v); + } elseif ('Header' === $k) { + $n->setHeader($v); + } else { + $n->{$k} = $v; + } } + return $n; + } + public function jsonSerialize(): \stdClass + { + $out = $this->_startJsonSerialize(); + $out->HTTP = $this->HTTP; + $out->Header = $this->Header; + $out->Method = $this->Method; + $out->Body = $this->Body; + $out->TLSSkipVerify = $this->TLSSkipVerify; + $out->TCP = $this->TCP; + $out->TCPUseTLS = $this->TCPUseTLS; + $out->UDP = $this->UDP; + $out->GRPC = $this->GRPC; + $out->OSService = $this->OSService; + $out->GRPCUseTLS = $this->GRPCUseTLS; + $out->Interval = (string)$this->IntervalDuration; + $out->Timeout = (string)$this->TimeoutDuration; + $out->DeregisterCriticalServiceAfter = (string)$this->DeregisterCriticalServiceAfterDuration; return $out; } } diff --git a/src/Health/HealthChecks.php b/src/Health/HealthChecks.php index f764dd26..bb5c56ac 100644 --- a/src/Health/HealthChecks.php +++ b/src/Health/HealthChecks.php @@ -20,19 +20,28 @@ limitations under the License. */ -use DCarbone\PHPConsulAPI\AbstractModel; use DCarbone\PHPConsulAPI\Consul; -use DCarbone\PHPConsulAPI\FakeSlice; +use DCarbone\PHPConsulAPI\PHPLib\AbstractType; -class HealthChecks extends FakeSlice +/** + * @implements \ArrayAccess + * @implements \IteratorAggregate + */ +class HealthChecks extends AbstractType implements \IteratorAggregate, \Countable, \ArrayAccess { - protected string $containedClass = HealthCheck::class; + /** @var \DCarbone\PHPConsulAPI\Health\HealthCheck[] */ + protected array $Checks = []; + + public function __construct(HealthCheck ...$Checks) + { + $this->Checks = $Checks; + } public function AggregatedStatus(): string { $passing = $warning = $critical = $maintenance = false; - foreach ($this as $check) { - if (Consul::NodeMaint === $check->CheckID || 0 === strpos($check->CheckID, Consul::ServiceMaintPrefix)) { + foreach ($this->Checks as $check) { + if (Consul::NodeMaint === $check->CheckID || str_starts_with($check->CheckID, Consul::ServiceMaintPrefix)) { // TODO: Maybe just return maintenance right now...? $maintenance = true; continue; @@ -68,8 +77,65 @@ public function AggregatedStatus(): string return Consul::HealthPassing; } - protected function newChild(array $data): AbstractModel + public function getIterator(): \Traversable + { + return new \ArrayIterator($this->Checks); + } + + public function count(): int + { + return count($this->Checks); + } + + public function offsetExists($offset): bool + { + return is_int($offset) && isset($this->Checks[$offset]); + } + + public function offsetGet($offset): null|HealthCheck + { + if (!isset($this[$offset])) { + throw new \OutOfRangeException("Offset $offset does not exist"); + } + return $this->Checks[$offset]; + } + + public function offsetSet($offset, $value): void + { + if (!$value instanceof HealthCheck) { + throw new \InvalidArgumentException(sprintf("Value must be an instance of %s", HealthCheck::class)); + } + if (null === $offset) { + $this->Checks[] = $value; + } elseif (!is_int($offset)) { + throw new \InvalidArgumentException('Offset must be an integer'); + } else { + $this->Checks[$offset] = $value; + } + } + + public function offsetUnset($offset): void + { + unset($this->Checks[$offset]); + } + + /** + * @param array<\stdClass> $decoded + */ + public static function jsonUnserialize(array $decoded): self + { + $n = new self(); + foreach ($decoded as $d) { + $n->Checks[] = HealthCheck::jsonUnserialize($d); + } + return $n; + } + + /** + * @return \DCarbone\PHPConsulAPI\Health\HealthCheck[] + */ + public function jsonSerialize(): array { - return new HealthCheck($data); + return $this->Checks; } } diff --git a/src/Health/HealthChecksResponse.php b/src/Health/HealthChecksResponse.php index 54852a40..94013bc9 100644 --- a/src/Health/HealthChecksResponse.php +++ b/src/Health/HealthChecksResponse.php @@ -20,20 +20,29 @@ limitations under the License. */ -use DCarbone\PHPConsulAPI\AbstractValuedQueryResponse; -use DCarbone\PHPConsulAPI\UnmarshalledResponseInterface; +use DCarbone\PHPConsulAPI\PHPLib\AbstractValuedQueryResponse; +use DCarbone\PHPConsulAPI\PHPLib\UnmarshalledResponseInterface; class HealthChecksResponse extends AbstractValuedQueryResponse implements UnmarshalledResponseInterface { - public ?HealthChecks $HealthChecks = null; + public HealthChecks $HealthChecks; - public function getValue(): ?HealthChecks + public function __construct() + { + $this->HealthChecks = new HealthChecks(); + } + + public function getValue(): HealthChecks { return $this->HealthChecks; } - public function unmarshalValue(mixed $decodedData): void + public function unmarshalValue(mixed $decoded): void { - $this->HealthChecks = new HealthChecks((array)$decodedData); + if (null === $decoded) { + $this->HealthChecks = new HealthChecks(); + return; + } + $this->HealthChecks = HealthChecks::jsonUnserialize($decoded); } } diff --git a/src/Health/HealthClient.php b/src/Health/HealthClient.php index b7ff2704..ffb45da4 100644 --- a/src/Health/HealthClient.php +++ b/src/Health/HealthClient.php @@ -20,8 +20,8 @@ limitations under the License. */ -use DCarbone\PHPConsulAPI\AbstractClient; -use DCarbone\PHPConsulAPI\Error; +use DCarbone\PHPConsulAPI\PHPLib\AbstractClient; +use DCarbone\PHPConsulAPI\PHPLib\Error; use DCarbone\PHPConsulAPI\QueryOptions; class HealthClient extends AbstractClient @@ -30,21 +30,24 @@ class HealthClient extends AbstractClient private const connectHealth = 'connect'; private const ingressHealth = 'ingress'; - public function Node(string $node, ?QueryOptions $opts = null): HealthChecksResponse + public function Node(string $node, null|QueryOptions $opts = null): HealthChecksResponse { return $this->_getHealthChecks(sprintf('v1/health/node/%s', $node), $opts); } - public function Checks(string $service, ?QueryOptions $opts = null): HealthChecksResponse + public function Checks(string $service, null|QueryOptions $opts = null): HealthChecksResponse { return $this->_getHealthChecks(sprintf('v1/health/checks/%s', $service), $opts); } + /** + * @param array $tags + */ public function ServiceMultipleTags( string $service, array $tags = [], bool $passingOnly = false, - ?QueryOptions $opts = null + null|QueryOptions $opts = null ): ServiceEntriesResponse { return $this->_getServiceEntries($service, $tags, $passingOnly, $opts, self::serviceHealth); } @@ -53,16 +56,19 @@ public function Service( string $service, string $tag = '', bool $passingOnly = false, - ?QueryOptions $opts = null + null|QueryOptions $opts = null ): ServiceEntriesResponse { return $this->ServiceMultipleTags($service, '' !== $tag ? [$tag] : [], $passingOnly, $opts); } + /** + * @param array $tags + */ public function IngressMultipleTags( string $service, array $tags = [], bool $passingOnly = false, - ?QueryOptions $opts = null + null|QueryOptions $opts = null ): ServiceEntriesResponse { return $this->_getServiceEntries($service, $tags, $passingOnly, $opts, self::ingressHealth); } @@ -71,16 +77,19 @@ public function Ingress( string $service, string $tag = '', bool $passingOnly = false, - ?QueryOptions $opts = null + null|QueryOptions $opts = null ): ServiceEntriesResponse { return $this->IngressMultipleTags($service, '' !== $tag ? [$tag] : [], $passingOnly, $opts); } + /** + * @param array $tags + */ public function ConnectMultipleTags( string $service, array $tags = [], bool $passingOnly = false, - ?QueryOptions $opts = null + null|QueryOptions $opts = null ): ServiceEntriesResponse { return $this->_getServiceEntries($service, $tags, $passingOnly, $opts, self::connectHealth); } @@ -89,16 +98,16 @@ public function Connect( string $service, string $tag = '', bool $passingOnly = false, - ?QueryOptions $opts = null + null|QueryOptions $opts = null ): ServiceEntriesResponse { return $this->ConnectMultipleTags($service, '' !== $tag ? [$tag] : [], $passingOnly, $opts); } - public function State(string $state, ?QueryOptions $opts = null): HealthChecksResponse + public function State(string $state, null|QueryOptions $opts = null): HealthChecksResponse { static $validStates = ['any', 'warning', 'critical', 'passing', 'unknown']; - if (!\in_array($state, $validStates, true)) { + if (!in_array($state, $validStates, true)) { $ret = new HealthChecksResponse(); $ret->Err = new Error( sprintf( @@ -114,7 +123,7 @@ public function State(string $state, ?QueryOptions $opts = null): HealthChecksRe return $this->_getHealthChecks(sprintf('v1/health/state/%s', $state), $opts); } - protected function _getHealthChecks(string $path, ?QueryOptions $opts): HealthChecksResponse + protected function _getHealthChecks(string $path, null|QueryOptions $opts): HealthChecksResponse { $resp = $this->_requireOK($this->_doGet($path, $opts)); $ret = new HealthChecksResponse(); @@ -122,11 +131,14 @@ protected function _getHealthChecks(string $path, ?QueryOptions $opts): HealthCh return $ret; } + /** + * @param array $tags + */ private function _getServiceEntries( string $service, array $tags, bool $passingOnly, - ?QueryOptions $opts, + null|QueryOptions $opts, string $healthType ): ServiceEntriesResponse { $uri = match ($healthType) { diff --git a/src/Health/ServiceEntriesResponse.php b/src/Health/ServiceEntriesResponse.php index 5ed674ea..81ba41c1 100644 --- a/src/Health/ServiceEntriesResponse.php +++ b/src/Health/ServiceEntriesResponse.php @@ -20,23 +20,27 @@ limitations under the License. */ -use DCarbone\PHPConsulAPI\AbstractValuedQueryResponse; -use DCarbone\PHPConsulAPI\UnmarshalledResponseInterface; +use DCarbone\PHPConsulAPI\PHPLib\AbstractValuedQueryResponse; +use DCarbone\PHPConsulAPI\PHPLib\UnmarshalledResponseInterface; class ServiceEntriesResponse extends AbstractValuedQueryResponse implements UnmarshalledResponseInterface { - public ?array $ServiceEntries = null; + /** @var \DCarbone\PHPConsulAPI\Health\ServiceEntry[] */ + public array $ServiceEntries; - public function getValue(): ?array + /** + * @return \DCarbone\PHPConsulAPI\Health\ServiceEntry[] + */ + public function getValue(): array { return $this->ServiceEntries; } - public function unmarshalValue(mixed $decodedData): void + public function unmarshalValue(mixed $decoded): void { $this->ServiceEntries = []; - foreach ($decodedData as $entry) { - $this->ServiceEntries[] = new ServiceEntry($entry); + foreach ($decoded as $entry) { + $this->ServiceEntries[] = ServiceEntry::jsonUnserialize($entry); } } } diff --git a/src/Health/ServiceEntry.php b/src/Health/ServiceEntry.php index 96773463..eaa1c0f6 100644 --- a/src/Health/ServiceEntry.php +++ b/src/Health/ServiceEntry.php @@ -20,63 +20,43 @@ limitations under the License. */ -use DCarbone\PHPConsulAPI\AbstractModel; use DCarbone\PHPConsulAPI\Agent\AgentService; use DCarbone\PHPConsulAPI\Catalog\Node; -use DCarbone\PHPConsulAPI\Transcoding; +use DCarbone\PHPConsulAPI\PHPLib\AbstractType; -class ServiceEntry extends AbstractModel +class ServiceEntry extends AbstractType { - protected const FIELDS = [ - self::FIELD_NODE => [ - Transcoding::FIELD_TYPE => Transcoding::OBJECT, - Transcoding::FIELD_CLASS => Node::class, - Transcoding::FIELD_NULLABLE => true, - ], - self::FIELD_SERVICE => [ - Transcoding::FIELD_TYPE => Transcoding::OBJECT, - Transcoding::FIELD_CLASS => AgentService::class, - Transcoding::FIELD_NULLABLE => true, - ], - self::FIELD_CHECKS => [ - Transcoding::FIELD_TYPE => Transcoding::OBJECT, - Transcoding::FIELD_CLASS => HealthChecks::class, - ], - ]; - - private const FIELD_NODE = 'Node'; - private const FIELD_SERVICE = 'Service'; - private const FIELD_CHECKS = 'Checks'; - - public ?Node $Node = null; - public ?AgentService $Service = null; + public null|Node $Node; + public null|AgentService $Service; public HealthChecks $Checks; - public function __construct(?array $data = []) - { - parent::__construct($data); - if (!isset($this->Checks)) { - $this->Checks = new HealthChecks(null); - } + public function __construct( + null|Node $Node = null, + null|AgentService $Service = null, + null|HealthChecks $Checks = null, + ) { + $this->Node = $Node; + $this->Service = $Service; + $this->setChecks($Checks); } - public function getNode(): ?Node + public function getNode(): null|Node { return $this->Node; } - public function setNode(?Node $Node): self + public function setNode(null|Node $Node): self { $this->Node = $Node; return $this; } - public function getService(): ?AgentService + public function getService(): null|AgentService { return $this->Service; } - public function setService(?AgentService $Service): self + public function setService(null|AgentService $Service): self { $this->Service = $Service; return $this; @@ -87,9 +67,38 @@ public function getChecks(): HealthChecks return $this->Checks; } - public function setChecks(HealthChecks $Checks): self + public function setChecks(null|HealthChecks $Checks): self { + if (null === $Checks) { + $Checks = new HealthChecks(); + } $this->Checks = $Checks; return $this; } + + public static function jsonUnserialize(\stdClass $decoded): self + { + $n = new self(); + foreach ((array)$decoded as $k => $v) { + if ('Node' === $k) { + $n->Node = null === $v ? null : Node::jsonUnserialize($v); + } elseif ('Service' === $k) { + $n->Service = null === $v ? null : AgentService::jsonUnserialize($v); + } elseif ('Checks' === $k) { + $n->Checks = HealthChecks::jsonUnserialize((array)$v); + } else { + $n->{$k} = $v; + } + } + return $n; + } + + public function jsonSerialize(): \stdClass + { + $out = $this->_startJsonSerialize(); + $out->Node = $this->Node; + $out->Service = $this->Service; + $out->Checks = $this->Checks; + return $out; + } } diff --git a/src/HttpAuth.php b/src/HttpAuth.php index 0e26216f..97057e30 100644 --- a/src/HttpAuth.php +++ b/src/HttpAuth.php @@ -22,11 +22,8 @@ class HttpAuth implements \JsonSerializable { - private const FIELD_USERNAME = 'username'; - private const FIELD_PASSWORD = 'password'; - - public string $username = ''; - public string $password = ''; + public string $username; + public string $password; public function __construct(string $username = '', string $password = '') { @@ -49,18 +46,23 @@ public function compileAuthString(): string return (string)$this; } - public function jsonSerialize(): array + public function jsonSerialize(): \stdClass { - return [self::FIELD_USERNAME => $this->username, self::FIELD_PASSWORD => $this->password]; + $out = new \stdClass(); + $out->username = $this->username; + if ('' !== $this->password) { + $out->password = $this->password; + } + return $out; } public function __debugInfo(): array { - return [self::FIELD_USERNAME => $this->username]; + return ['username' => $this->username]; } public function __toString(): string { - return trim(sprintf('%s:%s', $this->username, $this->password), ':'); + return $this->password !== '' ? "{$this->username}:{$this->password}" : $this->username; } } diff --git a/src/KV/CheckTxnOp.php b/src/KV/CheckTxnOp.php deleted file mode 100644 index 0ffce250..00000000 --- a/src/KV/CheckTxnOp.php +++ /dev/null @@ -1,70 +0,0 @@ - [ - Transcoding::FIELD_TYPE => Transcoding::OBJECT, - Transcoding::FIELD_CLASS => HealthCheck::class, - ], - ]; - - private const FIELD_CHECK = 'Check'; - - public string $Verb = ''; - public HealthCheck $Check; - - public function __construct(?array $data = []) - { - parent::__construct($data); - if (!isset($this->Check)) { - $this->Check = new HealthCheck(null); - } - } - - public function getVerb(): string - { - return $this->Verb; - } - - public function setVerb(string $Verb): self - { - $this->Verb = $Verb; - return $this; - } - - public function getCheck(): HealthCheck - { - return $this->Check; - } - - public function setCheck(HealthCheck $Check): self - { - $this->Check = $Check; - return $this; - } -} diff --git a/src/KV/KVClient.php b/src/KV/KVClient.php index 2fb51783..b59cb459 100644 --- a/src/KV/KVClient.php +++ b/src/KV/KVClient.php @@ -21,20 +21,24 @@ */ use DCarbone\Go\HTTP; -use DCarbone\PHPConsulAPI\AbstractClient; -use DCarbone\PHPConsulAPI\Error; +use DCarbone\PHPConsulAPI\PHPLib\AbstractClient; +use DCarbone\PHPConsulAPI\PHPLib\Error; +use DCarbone\PHPConsulAPI\PHPLib\ValuedQueryStringsResponse; +use DCarbone\PHPConsulAPI\PHPLib\ValuedWriteBoolResponse; +use DCarbone\PHPConsulAPI\PHPLib\WriteResponse; use DCarbone\PHPConsulAPI\QueryOptions; -use DCarbone\PHPConsulAPI\ValuedQueryStringsResponse; -use DCarbone\PHPConsulAPI\ValuedWriteBoolResponse; +use DCarbone\PHPConsulAPI\Txn\KVTxnAPIResponse; +use DCarbone\PHPConsulAPI\Txn\KVTxnResponse; +use DCarbone\PHPConsulAPI\Txn\TxnOp; +use DCarbone\PHPConsulAPI\Txn\TxnResponse; use DCarbone\PHPConsulAPI\WriteOptions; -use DCarbone\PHPConsulAPI\WriteResponse; class KVClient extends AbstractClient { - public function Get(string $key, ?QueryOptions $opts = null): KVPairResponse + public function Get(string $key, null|QueryOptions $opts = null): KVPairResponse { - $resp = $this->_doGet(sprintf('v1/kv/%s', $key), $opts); - $ret = new KVPairResponse(); + $resp = $this->_doGet(sprintf('v1/kv/%s', $key), $opts); + $ret = new KVPairResponse(); $ret->Err = $resp->Err; if (null !== $resp->Err) { return $ret; @@ -59,44 +63,45 @@ public function Get(string $key, ?QueryOptions $opts = null): KVPairResponse return $ret; } - public function Put(KVPair $p, ?WriteOptions $opts = null): WriteResponse + public function Put(KVPair $p, null|WriteOptions $opts = null): WriteResponse { $r = $this->_newPutRequest(sprintf('v1/kv/%s', $p->Key), $p->Value, $opts); if (0 !== $p->Flags) { $r->params->set('flags', (string)$p->Flags); } + $r->header->set('Content-Type', 'application/octet-stream'); $resp = $this->_requireOK($this->_do($r)); - $ret = new WriteResponse(); + $ret = new WriteResponse(); $this->_unmarshalResponse($resp, $ret); return $ret; } - public function Delete(string $key, ?WriteOptions $opts = null): WriteResponse + public function Delete(string $key, null|WriteOptions $opts = null): WriteResponse { return $this->_executeDelete(sprintf('v1/kv/%s', $key), $opts); } - public function List(string $prefix = '', ?QueryOptions $opts = null): KVPairsResponse + public function List(string $prefix = '', null|QueryOptions $opts = null): KVPairsResponse { $r = $this->_newGetRequest(sprintf('v1/kv/%s', $prefix), $opts); $r->params->set('recurse', ''); - $ret = new KVPairsResponse(); + $ret = new KVPairsResponse(); $resp = $this->_requireOK($this->_do($r)); $this->_unmarshalResponse($resp, $ret); return $ret; } - public function Keys(string $prefix = '', ?QueryOptions $opts = null): ValuedQueryStringsResponse + public function Keys(string $prefix = '', null|QueryOptions $opts = null): ValuedQueryStringsResponse { $r = $this->_newGetRequest(sprintf('v1/kv/%s', $prefix), $opts); $r->params->set('keys', ''); - $ret = new ValuedQueryStringsResponse(); + $ret = new ValuedQueryStringsResponse(); $resp = $this->_requireOK($this->_do($r)); $this->_unmarshalResponse($resp, $ret); return $ret; } - public function CAS(KVPair $p, ?WriteOptions $opts = null): ValuedWriteBoolResponse + public function CAS(KVPair $p, null|WriteOptions $opts = null): ValuedWriteBoolResponse { $r = $this->_newPutRequest(sprintf('v1/kv/%s', $p->Key), $p->Value, $opts); $r->params->set('cas', (string)$p->ModifyIndex); @@ -104,12 +109,12 @@ public function CAS(KVPair $p, ?WriteOptions $opts = null): ValuedWriteBoolRespo $r->params->set('flags', (string)$p->Flags); } $resp = $this->_requireOK($this->_do($r)); - $ret = new ValuedWriteBoolResponse(); + $ret = new ValuedWriteBoolResponse(); $this->_unmarshalResponse($resp, $ret); return $ret; } - public function Acquire(KVPair $p, ?WriteOptions $opts = null): WriteResponse + public function Acquire(KVPair $p, null|WriteOptions $opts = null): WriteResponse { $r = $this->_newPutRequest(sprintf('v1/kv/%s', $p->Key), $p->Value, $opts); $r->params->set('acquire', $p->Session); @@ -117,22 +122,22 @@ public function Acquire(KVPair $p, ?WriteOptions $opts = null): WriteResponse $r->params->set('flags', (string)$p->Flags); } $resp = $this->_requireOK($this->_do($r)); - $ret = new WriteResponse(); + $ret = new WriteResponse(); $this->_unmarshalResponse($resp, $ret); return $ret; } - public function DeleteCAS(KVPair $p, ?WriteOptions $opts = null): ValuedWriteBoolResponse + public function DeleteCAS(KVPair $p, null|WriteOptions $opts = null): ValuedWriteBoolResponse { - $r = $this->_newDeleteRequest(sprintf('v1/kv/%s', ltrim($p->Key, '/')), $opts); - $r->params['cas'] = (string)$p->ModifyIndex; - $resp = $this->_requireOK($this->_do($r)); - $ret = new ValuedWriteBoolResponse(); + $r = $this->_newDeleteRequest(sprintf('v1/kv/%s', ltrim($p->Key, '/')), $opts); + $r->params->set('cas', (string)$p->ModifyIndex); + $resp = $this->_requireOK($this->_do($r)); + $ret = new ValuedWriteBoolResponse(); $this->_unmarshalResponse($resp, $ret); return $ret; } - public function Release(KVPair $p, ?WriteOptions $opts = null): WriteResponse + public function Release(KVPair $p, null|WriteOptions $opts = null): WriteResponse { $r = $this->_newPutRequest(sprintf('v1/kv/%s', $p->Key), $p->Value, $opts); $r->params->set('release', $p->Session); @@ -145,26 +150,32 @@ public function Release(KVPair $p, ?WriteOptions $opts = null): WriteResponse return $ret; } - public function DeleteTree(string $prefix, ?WriteOptions $opts = null): WriteResponse + public function DeleteTree(string $prefix, null|WriteOptions $opts = null): WriteResponse { - $r = $this->_newDeleteRequest(sprintf('v1/kv/%s', $prefix), $opts); - $r->params['recurse'] = ''; - $resp = $this->_requireOK($this->_do($r)); - $ret = new WriteResponse(); + $r = $this->_newDeleteRequest(sprintf('v1/kv/%s', $prefix), $opts); + $r->params->set('recurse', ''); + $resp = $this->_requireOK($this->_do($r)); + $ret = new WriteResponse(); $this->_unmarshalResponse($resp, $ret); return $ret; } - public function Txn(KVTxnOps $txn, ?QueryOptions $opts = null): KVTxnAPIResponse + /** + * @param array<\DCarbone\PHPConsulAPI\Txn\TxnOp> $txn + * @param \DCarbone\PHPConsulAPI\QueryOptions|null $opts + * @return \DCarbone\PHPConsulAPI\Txn\KVTxnAPIResponse + */ + public function Txn(array $txn, null|QueryOptions $opts = null): KVTxnAPIResponse { - $txnOps = new KVTxnOps(); foreach ($txn as $op) { - $txnOps->append(clone $op); + if (!($op instanceof TxnOp)) { + throw new \InvalidArgumentException(sprintf('$txn must be array of %s, saw %s', TxnOp::class, gettype($op))); + } } $ret = new KVTxnAPIResponse(); - $resp = $this->_doPut('v1/txn', $txnOps, $opts); + $resp = $this->_doPut('v1/txn', $txn, $opts); if (null !== $resp->Err) { $ret->Err = $resp->Err; return $ret; @@ -183,8 +194,11 @@ public function Txn(KVTxnOps $txn, ?QueryOptions $opts = null): KVTxnAPIResponse } $ret->OK = true; // TODO: Maybe go straight to actual response? What is the benefit of this... - $internal = new TxnResponse($dec->Decoded); - $ret->KVTxnResponse = new KVTxnResponse(['Errors' => $internal->Errors, 'Results' => $internal->Results]); + $internal = new TxnResponse($dec->Decoded); + $kvr = new KVTxnResponse(); + $kvr->Errors = $internal->Errors; + $kvr->Results = $internal->Results; + $ret->KVTxnResponse = $kvr; return $ret; } @@ -196,78 +210,4 @@ public function Txn(KVTxnOps $txn, ?QueryOptions $opts = null): KVTxnAPIResponse $ret->Err = new Error('Failed request: ' . $body); return $ret; } - - /** - * @param string $prefix - * @param \DCarbone\PHPConsulAPI\QueryOptions|null $opts - * @throws \GuzzleHttp\Exception\GuzzleException - * @return array( - * @var \DCarbone\PHPConsulAPI\KV\KVPair[]|\DCarbone\PHPConsulAPI\KV\KVTree[]|null array of trees, values, or null on error - * @var \DCarbone\PHPConsulAPI\Error|null error, if any - * ) - */ - public function Tree(string $prefix = '', ?QueryOptions $opts = null): array - { - [$valueList, $_, $err] = $this->List($prefix, $opts); - - if (null !== $err) { - return [null, $err]; - } - - $treeHierarchy = []; - foreach ($valueList as $kvp) { - $path = $kvp->getKey(); - $slashPos = strpos($path, '/'); - if (false === $slashPos) { - $treeHierarchy[$path] = $kvp; - continue; - } - - $root = substr($path, 0, $slashPos + 1); - - if (!isset($treeHierarchy[$root])) { - $treeHierarchy[$root] = new KVTree($root); - } - - if (str_ends_with($path, '/')) { - $_path = ''; - foreach (explode('/', $prefix) as $part) { - if ('' === $part) { - continue; - } - - $_path .= "{$part}/"; - - if ($root === $_path) { - continue; - } - - if (!isset($treeHierarchy[$root][$_path])) { - $treeHierarchy[$root][$_path] = new KVTree($_path); - } - } - } else { - $kvPrefix = substr($path, 0, strrpos($path, '/') + 1); - $_path = ''; - foreach (explode('/', $kvPrefix) as $part) { - if ('' === $part) { - continue; - } - - $_path .= "{$part}/"; - - if ($root === $_path) { - continue; - } - - if (!isset($treeHierarchy[$root][$_path])) { - $treeHierarchy[$root][$_path] = new KVTree($_path); - } - } - - $treeHierarchy[$root][$path] = $kvp; - } - } - return [$treeHierarchy, null]; - } } diff --git a/src/KV/KVPair.php b/src/KV/KVPair.php index 0a81ec7a..79da0286 100644 --- a/src/KV/KVPair.php +++ b/src/KV/KVPair.php @@ -20,41 +20,40 @@ limitations under the License. */ -use DCarbone\PHPConsulAPI\AbstractModel; -use DCarbone\PHPConsulAPI\Transcoding; +use DCarbone\PHPConsulAPI\PHPLib\AbstractType; -class KVPair extends AbstractModel +class KVPair extends AbstractType { - protected const FIELDS = [ - self::FIELD_NAMESPACE => Transcoding::OMITEMPTY_STRING_FIELD, - ]; - - private const FIELD_NAMESPACE = 'Namespace'; - - public string $Key = ''; - public int $CreateIndex = 0; - public int $ModifyIndex = 0; - public int $LockIndex = 0; - public int $Flags = 0; - public string $Value = ''; - public string $Session = ''; - public string $Namespace = ''; - - /** - * KVPair constructor. - * @param array $data - * @param bool $_decodeValue - */ - public function __construct(array $data = [], bool $_decodeValue = false) - { - parent::__construct($data); - if ($_decodeValue) { - $dec = base64_decode($this->Value, true); - if (false === $dec) { - throw new \InvalidArgumentException(sprintf('Could not base64 decode value "%s"', $this->Value)); - } - $this->Value = $dec; - } + public string $Key; + public int $CreateIndex; + public int $ModifyIndex; + public int $LockIndex; + public int $Flags; + public string $Value; + public string $Session; + public string $Namespace; + public string $Partition; + + public function __construct( + string $Key = '', + int $CreateIndex = 0, + int $ModifyIndex = 0, + int $LockIndex = 0, + int $Flags = 0, + string $Value = '', + string $Session = '', + string $Namespace = '', + string $Partition = '', + ) { + $this->Key = $Key; + $this->CreateIndex = $CreateIndex; + $this->ModifyIndex = $ModifyIndex; + $this->LockIndex = $LockIndex; + $this->Flags = $Flags; + $this->Value = $Value; + $this->Session = $Session; + $this->Namespace = $Namespace; + $this->Partition = $Partition; } public function getKey(): string @@ -62,9 +61,9 @@ public function getKey(): string return $this->Key; } - public function setKey(string $key): self + public function setKey(string $Key): self { - $this->Key = $key; + $this->Key = $Key; return $this; } @@ -73,9 +72,9 @@ public function getCreateIndex(): int return $this->CreateIndex; } - public function setCreateIndex(int $createIndex): self + public function setCreateIndex(int $CreateIndex): self { - $this->CreateIndex = $createIndex; + $this->CreateIndex = $CreateIndex; return $this; } @@ -84,9 +83,9 @@ public function getModifyIndex(): int return $this->ModifyIndex; } - public function setModifyIndex(int $modifyIndex): self + public function setModifyIndex(int $ModifyIndex): self { - $this->ModifyIndex = $modifyIndex; + $this->ModifyIndex = $ModifyIndex; return $this; } @@ -95,9 +94,9 @@ public function getLockIndex(): int return $this->LockIndex; } - public function setLockIndex(int $lockIndex): self + public function setLockIndex(int $LockIndex): self { - $this->LockIndex = $lockIndex; + $this->LockIndex = $LockIndex; return $this; } @@ -106,9 +105,9 @@ public function getFlags(): int return $this->Flags; } - public function setFlags(int $flags): self + public function setFlags(int $Flags): self { - $this->Flags = $flags; + $this->Flags = $Flags; return $this; } @@ -117,9 +116,9 @@ public function getValue(): string return $this->Value; } - public function setValue(string $value): self + public function setValue(string $Value): self { - $this->Value = $value; + $this->Value = $Value; return $this; } @@ -128,9 +127,9 @@ public function getSession(): string return $this->Session; } - public function setSession(string $session): self + public function setSession(string $Session): self { - $this->Session = $session; + $this->Session = $Session; return $this; } @@ -139,9 +138,20 @@ public function getNamespace(): string return $this->Namespace; } - public function setNamespace(string $namespace): self + public function setNamespace(string $Namespace): self + { + $this->Namespace = $Namespace; + return $this; + } + + public function getPartition(): string { - $this->Namespace = $namespace; + return $this->Partition; + } + + public function setPartition(string $Partition): self + { + $this->Partition = $Partition; return $this; } @@ -149,4 +159,40 @@ public function __toString(): string { return $this->Value; } + + public static function jsonUnserialize(\stdClass $decoded): self + { + $n = new self(); + foreach ((array)$decoded as $k => $v) { + if ('Value' === $k) { + $val = base64_decode($v, true); + if (false === $val) { + throw new \DomainException(sprintf('Could not base64 decode value "%s"', $v)); + } + $n->Value = $val; + } else { + $n->{$k} = $v; + } + } + return $n; + } + + public function jsonSerialize(): \stdClass + { + $out = $this->_startJsonSerialize(); + $out->Key = $this->Key; + $out->CreateIndex = $this->CreateIndex; + $out->ModifyIndex = $this->ModifyIndex; + $out->LockIndex = $this->LockIndex; + $out->Flags = $this->Flags; + $out->Value = $this->Value; + $out->Session = $this->Session; + if ('' !== $this->Namespace) { + $out->Namespace = $this->Namespace; + } + if ('' !== $this->Partition) { + $out->Partition = $this->Partition; + } + return $out; + } } diff --git a/src/KV/KVPairResponse.php b/src/KV/KVPairResponse.php index f6abca82..a74bd6ae 100644 --- a/src/KV/KVPairResponse.php +++ b/src/KV/KVPairResponse.php @@ -20,20 +20,24 @@ limitations under the License. */ -use DCarbone\PHPConsulAPI\AbstractValuedQueryResponse; -use DCarbone\PHPConsulAPI\UnmarshalledResponseInterface; +use DCarbone\PHPConsulAPI\PHPLib\AbstractValuedQueryResponse; +use DCarbone\PHPConsulAPI\PHPLib\UnmarshalledResponseInterface; class KVPairResponse extends AbstractValuedQueryResponse implements UnmarshalledResponseInterface { - public ?KVPair $KVPair = null; + public null|KVPair $KVPair = null; - public function getValue(): ?KVPair + public function getValue(): null|KVPair { return $this->KVPair; } - public function unmarshalValue(mixed $decodedData): void + public function unmarshalValue(mixed $decoded): void { - $this->KVPair = new KVPair((array)$decodedData, true); + if (null === $decoded) { + $this->KVPair = null; + return; + } + $this->KVPair = KVPair::jsonUnserialize($decoded); } } diff --git a/src/KV/KVPairs.php b/src/KV/KVPairs.php index 1003b6aa..d4e5bf4d 100644 --- a/src/KV/KVPairs.php +++ b/src/KV/KVPairs.php @@ -20,15 +20,95 @@ limitations under the License. */ -use DCarbone\PHPConsulAPI\AbstractModel; -use DCarbone\PHPConsulAPI\FakeSlice; +use DCarbone\PHPConsulAPI\PHPLib\AbstractType; -class KVPairs extends FakeSlice +/** + * @implements \ArrayAccess + * @implements \IteratorAggregate + */ +class KVPairs extends AbstractType implements \IteratorAggregate, \Countable, \ArrayAccess { - protected string $containedClass = KVPair::class; + /** @var array<\DCarbone\PHPConsulAPI\KV\KVPair> */ + protected array $KVPairs = []; + + public function __construct(KVPair ...$KVPairs) + { + $this->KVPairs = $KVPairs; + } + + /** + * @return array + */ + public function getKVPairs(): array + { + return $this->KVPairs; + } + + public function setKVPairs(KVPair ...$KVPairs): self + { + $this->KVPairs = $KVPairs; + return $this; + } + + public function getIterator(): \Traversable + { + return new \ArrayIterator($this->KVPairs); + } + + public function offsetExists(mixed $offset): bool + { + return is_int($offset) && isset($this->KVPairs[$offset]); + } + + public function offsetGet(mixed $offset): mixed + { + if (!isset($this[$offset])) { + throw new \OutOfRangeException("Offset $offset does not exist"); + } + return $this->KVPairs[$offset]; + } + + public function offsetSet(mixed $offset, mixed $value): void + { + if (!$value instanceof KVPair) { + throw new \InvalidArgumentException(sprintf("Value must be instance of %s", KVPair::class)); + } + if (null === $offset) { + $this->KVPairs[] = $value; + } elseif (!is_int($offset)) { + throw new \InvalidArgumentException('Offset must be an integer'); + } else { + $this->KVPairs[$offset] = $value; + } + } + + public function offsetUnset(mixed $offset): void + { + unset($this->KVPairs[$offset]); + } + + public function count(): int + { + return count($this->KVPairs); + } + + /** + * @param array<\stdClass> $decoded + */ + public static function jsonUnserialize(array $decoded): self + { + $n = new self(); + foreach ($decoded as $kv) { + $n->KVPairs[] = KVPair::jsonUnserialize($kv); + } + return $n; + } - protected function newChild(array $data): AbstractModel + /** + * @return \DCarbone\PHPConsulAPI\KV\KVPair[] + */ + public function jsonSerialize(): array { - return new KVPair($data, true); + return $this->KVPairs; } } diff --git a/src/KV/KVPairsResponse.php b/src/KV/KVPairsResponse.php index 2c5a1a65..a8eb6c25 100644 --- a/src/KV/KVPairsResponse.php +++ b/src/KV/KVPairsResponse.php @@ -20,20 +20,29 @@ limitations under the License. */ -use DCarbone\PHPConsulAPI\AbstractValuedQueryResponse; -use DCarbone\PHPConsulAPI\UnmarshalledResponseInterface; +use DCarbone\PHPConsulAPI\PHPLib\AbstractValuedQueryResponse; +use DCarbone\PHPConsulAPI\PHPLib\UnmarshalledResponseInterface; class KVPairsResponse extends AbstractValuedQueryResponse implements UnmarshalledResponseInterface { - public ?KVPairs $KVPairs = null; + public KVPairs $KVPairs; - public function getValue(): ?KVPairs + public function __construct() + { + $this->KVPairs = new KVPairs(); + } + + public function getValue(): KVPairs { return $this->KVPairs; } - public function unmarshalValue(mixed $decodedData): void + public function unmarshalValue(mixed $decoded): void { - $this->KVPairs = new KVPairs((array)$decodedData); + if (null === $decoded) { + $this->KVPairs = new KVPairs(); + return; + } + $this->KVPairs = KVPairs::jsonUnserialize($decoded); } } diff --git a/src/KV/KVTree.php b/src/KV/KVTree.php deleted file mode 100644 index ecfd21e9..00000000 --- a/src/KV/KVTree.php +++ /dev/null @@ -1,172 +0,0 @@ -_prefix = $prefix; - } - - public function getPrefix(): string - { - return $this->_prefix; - } - - public function current(): KVTree|KVPair - { - return current($this->_children); - } - - public function next(): void - { - next($this->_children); - } - - /** - * @return string scalar on success, or null on failure - */ - public function key(): string - { - return key($this->_children); - } - - public function valid(): bool - { - return null !== key($this->_children); - } - - public function rewind(): void - { - reset($this->_children); - } - - /** - * @return bool true if the current entry can be iterated over, otherwise returns false - */ - public function hasChildren(): bool - { - return $this->current() instanceof self; - } - - public function getChildren(): \RecursiveIterator|KVTree|KVPair - { - return $this->current(); - } - - public function count(): int - { - return \count($this->_children); - } - - public function offsetExists(mixed $offset): bool - { - if (\is_string($offset)) { - $subPath = str_replace($this->_prefix, '', $offset); - $cnt = substr_count($subPath, '/'); - - if (1 < $cnt || (1 === $cnt && '/' !== substr($subPath, -1))) { - $childKey = $this->_prefix . substr($subPath, 0, strpos($subPath, '/') + 1); - if (isset($this->_children[$childKey])) { - return isset($this->_children[$childKey][$offset]); - } - } - } - - return isset($this->_children[$offset]) || \array_key_exists($offset, $this->_children); - } - - public function offsetGet(mixed $offset): KVTree|KVPair|null - { - if (\is_string($offset)) { - $subPath = str_replace($this->_prefix, '', $offset); - $cnt = substr_count($subPath, '/'); - if (1 < $cnt || (1 === $cnt && '/' !== substr($subPath, -1))) { - $childKey = $this->_prefix . substr($subPath, 0, strpos($subPath, '/') + 1); - if (isset($this[$childKey])) { - return $this->_children[$childKey][$offset]; - } - } - } - - if (isset($this[$offset])) { - return $this->_children[$offset]; - } - - trigger_error( - sprintf( - '%s - Requested offset %s does not exist in tree with prefix "%s".', - static::class, - $offset, - $this->getPrefix() - ) - ); - - return null; - } - - public function offsetSet(mixed $offset, mixed $value): void - { - if ('string' === \gettype($offset)) { - $subPath = str_replace($this->_prefix, '', $offset); - $cnt = substr_count($subPath, '/'); - - if (1 < $cnt || (1 === $cnt && '/' !== substr($subPath, -1))) { - $childKey = $this->_prefix . substr($subPath, 0, strpos($subPath, '/') + 1); - $this->_children[$childKey][$offset] = $value; - } else { - $this->_children[$offset] = $value; - } - } elseif (null === $offset) { - $this->_children[] = $value; - } else { - $this->_children[$offset] = $value; - } - } - - public function offsetUnset(mixed $offset): void - { - // do nothing, yo... - } - - public function jsonSerialize(): array - { - $json = [$this->_prefix => []]; - foreach ($this->_children as $k => $child) { - if ($child instanceof self) { - $json[$this->_prefix] = $child; - } elseif ($child instanceof KVPair) { - $json[$this->_prefix][$child->Key] = $child; - } - } - return $json; - } - - public function __toString() - { - return $this->_prefix; - } -} diff --git a/src/KV/KVTxnOp.php b/src/KV/KVTxnOp.php deleted file mode 100644 index f7cf0622..00000000 --- a/src/KV/KVTxnOp.php +++ /dev/null @@ -1,80 +0,0 @@ -Value, true); - if (false === $dec) { - throw new \InvalidArgumentException(sprintf('Could not base64 decode value "%s"', $this->Value)); - } - $this->Value = $dec; - } - } - - public function getVerb(): string - { - return $this->Verb; - } - - public function getKey(): string - { - return $this->Key; - } - - public function getValue(): string - { - return $this->Value; - } - - public function getFlags(): int - { - return $this->Flags; - } - - public function getIndex(): int - { - return $this->Index; - } - - public function getSession(): string - { - return $this->Session; - } -} diff --git a/src/KV/KVTxnResponse.php b/src/KV/KVTxnResponse.php deleted file mode 100644 index dfd2d9f1..00000000 --- a/src/KV/KVTxnResponse.php +++ /dev/null @@ -1,55 +0,0 @@ - [ - Transcoding::FIELD_TYPE => Transcoding::ARRAY, - Transcoding::FIELD_CLASS => KVPair::class, - Transcoding::FIELD_ARRAY_TYPE => Transcoding::OBJECT, - ], - self::FIELD_ERRORS => [ - Transcoding::FIELD_TYPE => Transcoding::OBJECT, - Transcoding::FIELD_CLASS => TxnErrors::class, - ], - ]; - - private const FIELD_RESULTS = 'Results'; - private const FIELD_ERRORS = 'Errors'; - - public array $Results = []; - public ?TxnErrors $Errors = null; - - public function getResults(): array - { - return $this->Results; - } - - public function getErrors(): ?TxnErrors - { - return $this->Errors; - } -} diff --git a/src/KV/NodeTxnOp.php b/src/KV/NodeTxnOp.php deleted file mode 100644 index 872f7d5d..00000000 --- a/src/KV/NodeTxnOp.php +++ /dev/null @@ -1,70 +0,0 @@ - [ - Transcoding::FIELD_TYPE => Transcoding::OBJECT, - Transcoding::FIELD_CLASS => Node::class, - ], - ]; - - private const FIELD_NODE = 'Node'; - - public string $Verb = ''; - public Node $Node; - - public function __construct(?array $data = []) - { - parent::__construct($data); - if (!isset($this->Node)) { - $this->Node = new Node(null); - } - } - - public function getVerb(): string - { - return $this->Verb; - } - - public function setVerb(string $Verb): self - { - $this->Verb = $Verb; - return $this; - } - - public function getNode(): Node - { - return $this->Node; - } - - public function setNode(Node $Node): self - { - $this->Node = $Node; - return $this; - } -} diff --git a/src/KV/ServiceTxnOp.php b/src/KV/ServiceTxnOp.php deleted file mode 100644 index 52c50964..00000000 --- a/src/KV/ServiceTxnOp.php +++ /dev/null @@ -1,80 +0,0 @@ - [ - Transcoding::FIELD_TYPE => Transcoding::OBJECT, - Transcoding::FIELD_CLASS => AgentService::class, - ], - ]; - - private const FIELD_SERVICE = 'Service'; - - public string $Verb = ''; - public string $Node = ''; - public AgentService $Service; - - public function __construct(?array $data = []) - { - parent::__construct($data); - $this->Service = new AgentService(null); - } - - public function getVerb(): string - { - return $this->Verb; - } - - public function setVerb(string $Verb): self - { - $this->Verb = $Verb; - return $this; - } - - public function getNode(): string - { - return $this->Node; - } - - public function setNode(string $Node): self - { - $this->Node = $Node; - return $this; - } - - public function getService(): AgentService - { - return $this->Service; - } - - public function setService(AgentService $Service): self - { - $this->Service = $Service; - return $this; - } -} diff --git a/src/KV/TxnErrors.php b/src/KV/TxnErrors.php deleted file mode 100644 index e09430bb..00000000 --- a/src/KV/TxnErrors.php +++ /dev/null @@ -1,34 +0,0 @@ - [ - Transcoding::FIELD_TYPE => Transcoding::OBJECT, - Transcoding::FIELD_CLASS => KVTxnOp::class, - Transcoding::FIELD_NULLABLE => true, - ], - self::FIELD_NODE => [ - Transcoding::FIELD_TYPE => Transcoding::OBJECT, - Transcoding::FIELD_CLASS => NodeTxnOp::class, - Transcoding::FIELD_NULLABLE => true, - ], - self::FIELD_SERVICE => [ - Transcoding::FIELD_TYPE => Transcoding::OBJECT, - Transcoding::FIELD_CLASS => ServiceTxnOp::class, - Transcoding::FIELD_NULLABLE => true, - ], - self::FIELD_CHECK => [ - Transcoding::FIELD_TYPE => Transcoding::OBJECT, - Transcoding::FIELD_CLASS => CheckTxnOp::class, - Transcoding::FIELD_NULLABLE => true, - ], - ]; - - private const FIELD_KV = 'KV'; - private const FIELD_NODE = 'Node'; - private const FIELD_SERVICE = 'Service'; - private const FIELD_CHECK = 'Check'; - - public ?KVTxnOp $KV = null; - public ?NodeTxnOp $Node = null; - public ?ServiceTxnOp $Service = null; - public ?CheckTxnOp $Check = null; - - public function getKV(): ?KVTxnOp - { - return $this->KV; - } - - public function setKV(?KVTxnOp $KV): self - { - $this->KV = $KV; - return $this; - } - - public function getNode(): ?NodeTxnOp - { - return $this->Node; - } - - public function setNode(?NodeTxnOp $Node): self - { - $this->Node = $Node; - return $this; - } - - public function getService(): ?ServiceTxnOp - { - return $this->Service; - } - - public function setService(?ServiceTxnOp $Service): self - { - $this->Service = $Service; - return $this; - } - - public function getCheck(): ?CheckTxnOp - { - return $this->Check; - } - - public function setCheck(?CheckTxnOp $Check): self - { - $this->Check = $Check; - return $this; - } -} diff --git a/src/KV/TxnOps.php b/src/KV/TxnOps.php deleted file mode 100644 index 28a37cc1..00000000 --- a/src/KV/TxnOps.php +++ /dev/null @@ -1,34 +0,0 @@ - [ - Transcoding::FIELD_TYPE => Transcoding::OBJECT, - Transcoding::FIELD_CLASS => TxnResults::class, - ], - self::FIELD_ERRORS => [ - Transcoding::FIELD_TYPE => Transcoding::OBJECT, - Transcoding::FIELD_CLASS => TxnErrors::class, - ], - ]; - - private const FIELD_RESULTS = 'Results'; - private const FIELD_ERRORS = 'Errors'; - - public TxnResults $Results; - public TxnErrors $Errors; - - public function __construct(?array $data = null) - { - parent::__construct($data); - if (!isset($this->Results)) { - $this->Results = new TxnResults(); - } - if (!isset($this->Errors)) { - $this->Errors = new TxnErrors(); - } - } - - public function getResults(): TxnResults - { - return $this->Results; - } - - public function setResults(TxnResults $Results): self - { - $this->Results = $Results; - return $this; - } - - public function getErrors(): TxnErrors - { - return $this->Errors; - } - - public function setErrors(TxnErrors $Errors): self - { - $this->Errors = $Errors; - return $this; - } -} diff --git a/src/KV/TxnResult.php b/src/KV/TxnResult.php deleted file mode 100644 index 1f7af537..00000000 --- a/src/KV/TxnResult.php +++ /dev/null @@ -1,107 +0,0 @@ - [ - Transcoding::FIELD_TYPE => Transcoding::OBJECT, - Transcoding::FIELD_CLASS => KVPair::class, - Transcoding::FIELD_NULLABLE => true, - ], - self::FIELD_NODE => [ - Transcoding::FIELD_TYPE => Transcoding::OBJECT, - Transcoding::FIELD_CLASS => Node::class, - Transcoding::FIELD_NULLABLE => true, - ], - self::FIELD_SERVICE => [ - Transcoding::FIELD_TYPE => Transcoding::OBJECT, - Transcoding::FIELD_CLASS => CatalogService::class, - Transcoding::FIELD_NULLABLE => true, - ], - self::FIELD_CHECK => [ - Transcoding::FIELD_TYPE => Transcoding::OBJECT, - Transcoding::FIELD_CLASS => HealthCheck::class, - Transcoding::FIELD_NULLABLE => true, - ], - ]; - - private const FIELD_KV = 'KV'; - private const FIELD_NODE = 'Node'; - private const FIELD_SERVICE = 'Service'; - private const FIELD_CHECK = 'Check'; - - public ?KVPair $KV = null; - public ?Node $Node = null; - public ?CatalogService $Service = null; - public ?HealthCheck $Check = null; - - public function getKV(): ?KVPair - { - return $this->KV; - } - - public function setKV(?KVPair $KV): self - { - $this->KV = $KV; - return $this; - } - - public function getNode(): ?Node - { - return $this->Node; - } - - public function setNode(?Node $Node): self - { - $this->Node = $Node; - return $this; - } - - public function getService(): ?CatalogService - { - return $this->Service; - } - - public function setService(?CatalogService $Service): self - { - $this->Service = $Service; - return $this; - } - - public function getCheck(): ?HealthCheck - { - return $this->Check; - } - - public function setCheck(?HealthCheck $Check): self - { - $this->Check = $Check; - return $this; - } -} diff --git a/src/KV/TxnResults.php b/src/KV/TxnResults.php deleted file mode 100644 index d4a87fb5..00000000 --- a/src/KV/TxnResults.php +++ /dev/null @@ -1,34 +0,0 @@ - (string)$value, - Transcoding::INTEGER => (int)$value, - Transcoding::DOUBLE => (float)$value, - Transcoding::BOOLEAN => (bool)$value, - default => throw new \InvalidArgumentException( - sprintf('Unable to handle serializing to %s', $def[Transcoding::FIELD_MARSHAL_AS]) - ), - }; - } - - // if this field is NOT explicitly marked as "omitempty", set and move on. - if (!isset($def[Transcoding::FIELD_OMITEMPTY]) || true !== $def[Transcoding::FIELD_OMITEMPTY]) { - $output[$field] = $value; - return; - } - - // otherwise, handle value setting on a per-type basis - - $type = \gettype($value); - - // strings must be non empty - if (Transcoding::STRING === $type) { - if ('' !== $value) { - $output[$field] = $value; - } - return; - } - - // integers must be non-zero (negatives are ok) - if (Transcoding::INTEGER === $type) { - if (0 !== $value) { - $output[$field] = $value; - } - return; - } - - // floats must be non-zero (negatives are ok) - if (Transcoding::DOUBLE === $type) { - if (0.0 !== $value) { - $output[$field] = $value; - } - return; - } - - // bools must be true - if (Transcoding::BOOLEAN === $type) { - if ($value) { - $output[$field] = $value; - } - return; - } - - // object "non-zero" calculations require a bit more finesse... - if (Transcoding::OBJECT === $type) { - // AbstractModels are collections, and are non-zero if they contain at least 1 entry - if ($value instanceof FakeSlice || $value instanceof FakeMap) { - if (0 < \count($value)) { - $output[$field] = $value; - } - return; - } - - // Time\Duration types are non-zero if their internal value is > 0 - if ($value instanceof Time\Duration) { - if (0 < $value->Nanoseconds()) { - $output[$field] = $value; - } - return; - } - - // Time\Time values are non-zero if they are anything greater than epoch - if ($value instanceof Time\Time) { - if (!$value->IsZero()) { - $output[$field] = $value; - } - return; - } - - // otherwise, by being defined it is non-zero, so add it. - $output[$field] = $value; - return; - } - - // arrays must have at least 1 value - if (Transcoding::ARRAY === $type) { - if ([] !== $value) { - $output[$field] = $value; - } - return; - } - - // todo: be more better about resources - if (Transcoding::RESOURCE === $type) { - $output[$field] = $value; - return; - } - - // once we get here the only possible value type is "NULL", which are always considered "empty". thus, do not - // set any value. - } -} diff --git a/src/Metrics/Label.php b/src/Metrics/Label.php new file mode 100644 index 00000000..9691cdd2 --- /dev/null +++ b/src/Metrics/Label.php @@ -0,0 +1,74 @@ +Name = $Name; + $this->Value = $Value; + } + + public function getName(): string + { + return $this->Name; + } + + public function setName(string $Name): self + { + $this->Name = $Name; + return $this; + } + + public function getValue(): string + { + return $this->Value; + } + + public function setValue(string $Value): self + { + $this->Value = $Value; + return $this; + } + + public static function jsonUnserialize(\stdClass $decoded): self + { + $n = new self(); + foreach ((array)$decoded as $k => $v) { + $n->{$k} = $v; + } + return $n; + } + + public function jsonSerialize(): \stdClass + { + $out = $this->_startJsonSerialize(); + $out->Name = $this->Name; + $out->Value = $this->Value; + return $out; + } +} diff --git a/src/Operator/Area.php b/src/Operator/Area.php index d922cf5c..e9e866b2 100644 --- a/src/Operator/Area.php +++ b/src/Operator/Area.php @@ -20,23 +20,39 @@ limitations under the License. */ -use DCarbone\PHPConsulAPI\AbstractModel; +use DCarbone\PHPConsulAPI\PHPLib\AbstractType; -class Area extends AbstractModel +class Area extends AbstractType { - public string $ID = ''; - public string $PeerDatacenter = ''; - public array $RetryJoin = []; - public bool $UseTLS = false; + public string $ID; + public string $PeerDatacenter; + /** @var array */ + public array $RetryJoin; + public bool $UseTLS; + + /** + * @param array $RetryJoin + */ + public function __construct( + string $ID = '', + string $PeerDatacenter = '', + array $RetryJoin = [], + bool $UseTLS = false, + ) { + $this->ID = $ID; + $this->PeerDatacenter = $PeerDatacenter; + $this->setRetryJoin(...$RetryJoin); + $this->UseTLS = $UseTLS; + } public function getID(): string { return $this->ID; } - public function setID(string $id): self + public function setID(string $ID): self { - $this->ID = $id; + $this->ID = $ID; return $this; } @@ -45,20 +61,23 @@ public function getPeerDatacenter(): string return $this->PeerDatacenter; } - public function setPeerDatacenter(string $peerDatacenter): self + public function setPeerDatacenter(string $PeerDatacenter): self { - $this->PeerDatacenter = $peerDatacenter; + $this->PeerDatacenter = $PeerDatacenter; return $this; } + /** + * @return array + */ public function getRetryJoin(): array { return $this->RetryJoin; } - public function setRetryJoin(array $retryJoin): self + public function setRetryJoin(string ...$RetryJoin): self { - $this->RetryJoin = $retryJoin; + $this->RetryJoin = $RetryJoin; return $this; } @@ -67,9 +86,28 @@ public function isUseTLS(): bool return $this->UseTLS; } - public function setUseTLS(bool $useTLS): self + public function setUseTLS(bool $UseTLS): self { - $this->UseTLS = $useTLS; + $this->UseTLS = $UseTLS; return $this; } + + public static function jsonUnserialize(\stdClass $decoded): self + { + $n = new self(); + foreach ((array)$decoded as $k => $v) { + $n->{$k} = $v; + } + return $n; + } + + public function jsonSerialize(): \stdClass + { + $out = $this->_startJsonSerialize(); + $out->ID = $this->ID; + $out->PeerDatacenter = $this->PeerDatacenter; + $out->RetryJoin = $this->RetryJoin; + $out->UseTLS = $this->UseTLS; + return $out; + } } diff --git a/src/Operator/AreaJoinResponse.php b/src/Operator/AreaJoinResponse.php index 895c24e5..c1f0c815 100644 --- a/src/Operator/AreaJoinResponse.php +++ b/src/Operator/AreaJoinResponse.php @@ -20,26 +20,72 @@ limitations under the License. */ -use DCarbone\PHPConsulAPI\AbstractModel; +use DCarbone\PHPConsulAPI\PHPLib\AbstractType; -class AreaJoinResponse extends AbstractModel +class AreaJoinResponse extends AbstractType { - public string $Address = ''; - public bool $Joined = false; - public string $Error = ''; + public string $Address; + public bool $Joined; + public string $Error; + + public function __construct( + string $Address = '', + bool $Joined = false, + string $Error = '', + ) { + $this->Address = $Address; + $this->Joined = $Joined; + $this->Error = $Error; + } public function getAddress(): string { return $this->Address; } + public function setAddress(string $Address): self + { + $this->Address = $Address; + return $this; + } + public function isJoined(): bool { return $this->Joined; } + public function setJoined(bool $Joined): self + { + $this->Joined = $Joined; + return $this; + } + public function getError(): string { return $this->Error; } + + public function setError(string $Error): self + { + $this->Error = $Error; + return $this; + } + + public static function jsonUnserialize(\stdClass $decoded): self + { + $n = new self(); + foreach ((array)$decoded as $k => $v) { + $n->{$k} = $v; + } + return $n; + } + + public function jsonSerialize(): \stdClass + { + $out = $this->_startJsonSerialize(); + $out->Address = $this->Address; + $out->Joined = $this->Joined; + $out->Error = $this->Error; + return $out; + } } diff --git a/src/Operator/AutopilotConfiguration.php b/src/Operator/AutopilotConfiguration.php index 0e2916f6..08744dfa 100644 --- a/src/Operator/AutopilotConfiguration.php +++ b/src/Operator/AutopilotConfiguration.php @@ -20,35 +20,45 @@ limitations under the License. */ -use DCarbone\PHPConsulAPI\AbstractModel; -use DCarbone\PHPConsulAPI\Transcoding; +use DCarbone\Go\Time; +use DCarbone\PHPConsulAPI\PHPLib\AbstractType; -class AutopilotConfiguration extends AbstractModel +class AutopilotConfiguration extends AbstractType { - protected const FIELDS = [ - self::FIELD_LAST_CONTACT_THRESHOLD => [ - Transcoding::FIELD_UNMARSHAL_CALLBACK => [ReadableDuration::class, 'unmarshalJSON'], - Transcoding::FIELD_NULLABLE => true, - ], - self::FIELD_SERVER_STABILIZATION_TIME => [ - Transcoding::FIELD_UNMARSHAL_CALLBACK => [ReadableDuration::class, 'unmarshalJSON'], - Transcoding::FIELD_NULLABLE => true, - ], - ]; - - private const FIELD_LAST_CONTACT_THRESHOLD = 'LastContactThreshold'; - private const FIELD_SERVER_STABILIZATION_TIME = 'ServerStabilizationTime'; - - public bool $CleanupDeadServers = false; - public ?ReadableDuration $LastContactThreshold = null; - public int $MaxTrailingLogs = 0; - public int $MinQuorum = 0; - public ?ReadableDuration $ServerStabilizationTime = null; - public string $RedundancyZoneTag = ''; - public bool $DisableUpgradeMigration = false; - public string $UpgradeVersionTag = ''; - public int $CreateIndex = 0; - public int $ModifyIndex = 0; + public bool $CleanupDeadServers; + public null|Time\Duration $LastContactThreshold; + public int $MaxTrailingLogs; + public int $MinQuorum; + public null|Time\Duration $ServerStabilizationTime; + public string $RedundancyZoneTag; + public bool $DisableUpgradeMigration; + public string $UpgradeVersionTag; + public int $CreateIndex; + public int $ModifyIndex; + + public function __construct( + bool $CleanupDeadServers = false, + null|string|int|float|\DateInterval|Time\Duration $LastContactThreshold = null, + int $MaxTrailingLogs = 0, + int $MinQuorum = 0, + null|string|int|float|\DateInterval|Time\Duration $ServerStabilizationTime = null, + string $RedundancyZoneTag = '', + bool $DisableUpgradeMigration = false, + string $UpgradeVersionTag = '', + int $CreateIndex = 0, + int $ModifyIndex = 0, + ) { + $this->CleanupDeadServers = $CleanupDeadServers; + $this->setLastContactThreshold($LastContactThreshold); + $this->MaxTrailingLogs = $MaxTrailingLogs; + $this->MinQuorum = $MinQuorum; + $this->setServerStabilizationTime($ServerStabilizationTime); + $this->RedundancyZoneTag = $RedundancyZoneTag; + $this->DisableUpgradeMigration = $DisableUpgradeMigration; + $this->UpgradeVersionTag = $UpgradeVersionTag; + $this->CreateIndex = $CreateIndex; + $this->ModifyIndex = $ModifyIndex; + } public function isCleanupDeadServers(): bool { @@ -61,14 +71,18 @@ public function setCleanupDeadServers(bool $CleanupDeadServers): self return $this; } - public function getLastContactThreshold(): ?ReadableDuration + public function getLastContactThreshold(): null|Time\Duration { return $this->LastContactThreshold; } - public function setLastContactThreshold(?ReadableDuration $LastContactThreshold): self + public function setLastContactThreshold(null|string|int|float|\DateInterval|Time\Duration $LastContactThreshold): self { - $this->LastContactThreshold = $LastContactThreshold; + if (null === $LastContactThreshold) { + $this->LastContactThreshold = null; + return $this; + } + $this->LastContactThreshold = Time::Duration($LastContactThreshold); return $this; } @@ -94,14 +108,18 @@ public function setMinQuorum(int $MinQuorum): self return $this; } - public function getServerStabilizationTime(): ?ReadableDuration + public function getServerStabilizationTime(): null|Time\Duration { return $this->ServerStabilizationTime; } - public function setServerStabilizationTime(?ReadableDuration $ServerStabilizationTime): self + public function setServerStabilizationTime(null|string|int|float|\DateInterval|Time\Duration $ServerStabilizationTime): self { - $this->ServerStabilizationTime = $ServerStabilizationTime; + if (null === $ServerStabilizationTime) { + $this->ServerStabilizationTime = null; + return $this; + } + $this->ServerStabilizationTime = Time::Duration($ServerStabilizationTime); return $this; } @@ -159,4 +177,43 @@ public function setModifyIndex(int $ModifyIndex): self $this->ModifyIndex = $ModifyIndex; return $this; } + + public static function jsonUnserialize(\stdClass $decoded): self + { + $n = new self(); + foreach ((array)$decoded as $k => $v) { + if ('LastContactThreshold' === $k) { + $n->setLastContactThreshold($v); + } elseif ('ServerStabilizationTime' === $k) { + $n->setServerStabilizationTime($v); + } else { + $n->{$k} = $v; + } + } + return $n; + } + + public function jsonSerialize(): \stdClass + { + $out = $this->_startJsonSerialize(); + $out->CleanupDeadServers = $this->CleanupDeadServers; + if (null !== $this->LastContactThreshold) { + $out->LastContactThreshold = (string)$this->LastContactThreshold; + } + $out->MaxTrailingLogs = $this->MaxTrailingLogs; + $out->MinQuorum = $this->MinQuorum; + if (null !== $this->ServerStabilizationTime) { + $out->ServerStabilizationTime = (string)$this->ServerStabilizationTime; + } + if ('' !== $this->RedundancyZoneTag) { + $out->RedundancyZoneTag = $this->RedundancyZoneTag; + } + $out->DisableUpgradeMigration = $this->DisableUpgradeMigration; + if ('' !== $this->UpgradeVersionTag) { + $out->UpgradeVersionTag = $this->UpgradeVersionTag; + } + $out->CreateIndex = $this->CreateIndex; + $out->ModifyIndex = $this->ModifyIndex; + return $out; + } } diff --git a/src/Operator/AutopilotServer.php b/src/Operator/AutopilotServer.php index 3e0ff8d0..e772131a 100644 --- a/src/Operator/AutopilotServer.php +++ b/src/Operator/AutopilotServer.php @@ -21,51 +21,67 @@ */ use DCarbone\Go\Time; -use DCarbone\PHPConsulAPI\AbstractModel; -use DCarbone\PHPConsulAPI\Transcoding; +use DCarbone\PHPConsulAPI\PHPLib\AbstractType; +use DCarbone\PHPConsulAPI\PHPLib\MetaField; +use function DCarbone\PHPConsulAPI\PHPLib\parse_time; -class AutopilotServer extends AbstractModel implements \JsonSerializable +class AutopilotServer extends AbstractType { - protected const FIELDS = [ - self::FIELD_LAST_CONTACT => [ - Transcoding::FIELD_UNMARSHAL_CALLBACK => [ReadableDuration::class, 'unmarshalJSON'], - Transcoding::FIELD_NULLABLE => true, - ], - self::FIELD_STABLE_SINCE => [ - Transcoding::FIELD_UNMARSHAL_CALLBACK => Transcoding::UNMARSHAL_TIME, - ], - self::FIELD_REDUNDANCY_ZONE => Transcoding::OMITEMPTY_STRING_FIELD, - self::FIELD_UPGRADE_VERSION => Transcoding::OMITEMPTY_STRING_FIELD, - ]; - - private const FIELD_LAST_CONTACT = 'LastContact'; - private const FIELD_STABLE_SINCE = 'StableSince'; - private const FIELD_REDUNDANCY_ZONE = 'RedundancyZone'; - private const FIELD_UPGRADE_VERSION = 'UpgradeVersion'; - - public string $ID = ''; - public string $Name = ''; - public string $Address = ''; - public string $NodeStatus = ''; - public string $Version = ''; - public ?ReadableDuration $LastContact = null; - public int $LastTerm = 0; - public int $LastIndex = 0; - public bool $Healthy = false; + use MetaField; + + public string $ID; + public string $Name; + public string $Address; + public string $NodeStatus; + public string $Version; + public null|Time\Duration $LastContact = null; + public int $LastTerm; + public int $LastIndex; + public bool $Healthy; public Time\Time $StableSince; - public string $RedundancyZone = ''; - public string $UpgradeVersion = ''; - public bool $ReadReplica = false; - public string $Status = ''; - public array $Meta = []; - public string $NodeType = ''; - - public function __construct(?array $data = []) - { - parent::__construct($data); - if (!isset($this->StableSince)) { - $this->StableSince = Time::New(); - } + public string $RedundancyZone; + public string $UpgradeVersion; + public bool $ReadReplica; + public AutopilotServerStatus $Status; + public AutopilotServerType $NodeType; + + /** + * @param \stdClass|array|null $Meta + */ + public function __construct( + string $ID = '', + string $Name = '', + string $Address = '', + string $NodeStatus = '', + string $Version = '', + null|string|int|float|\DateInterval|Time\Duration $LastContact = null, + int $LastTerm = 0, + int $LastIndex = 0, + bool $Healthy = false, + null|Time\Time $StableSince = null, + string $RedundancyZone = '', + string $UpgradeVersion = '', + bool $readReplica = false, + string|AutopilotServerStatus $status = AutopilotServerStatus::UNDEFINED, + null|\stdClass|array $Meta = null, + string|AutopilotServerType $NodeType = AutopilotServerType::UNDEFINED, + ) { + $this->ID = $ID; + $this->Name = $Name; + $this->Address = $Address; + $this->NodeStatus = $NodeStatus; + $this->Version = $Version; + $this->setLastContact($LastContact); + $this->LastTerm = $LastTerm; + $this->LastIndex = $LastIndex; + $this->Healthy = $Healthy; + $this->StableSince = $StableSince ?? new TIme\Time(); + $this->RedundancyZone = $RedundancyZone; + $this->UpgradeVersion = $UpgradeVersion; + $this->ReadReplica = $readReplica; + $this->setStatus($status); + $this->setMeta($Meta); + $this->setNodeType($NodeType); } public function getID(): string @@ -123,14 +139,18 @@ public function setVersion(string $Version): self return $this; } - public function getLastContact(): ?ReadableDuration + public function getLastContact(): null|Time\Duration { return $this->LastContact; } - public function setLastContact(?ReadableDuration $LastContact): self + public function setLastContact(null|string|int|float|\DateInterval|Time\Duration $LastContact): self { - $this->LastContact = $LastContact; + if (null === $LastContact) { + $this->LastContact = null; + return $this; + } + $this->LastContact = Time::Duration($LastContact); return $this; } @@ -211,45 +231,71 @@ public function setReadReplica(bool $ReadReplica): self return $this; } - public function getStatus(): string + public function getStatus(): AutopilotServerStatus { return $this->Status; } - public function setStatus(string $Status): self + public function setStatus(string|AutopilotServerStatus $Status): self { - $this->Status = $Status; + $this->Status = is_string($Status) ? AutopilotServerStatus::from($Status) : $Status; return $this; } - public function getMeta(): array - { - return $this->Meta; - } - - public function setMeta(array $Meta): self - { - $this->Meta = $Meta; - return $this; - } - - public function getNodeType(): string + public function getNodeType(): AutopilotServerType { return $this->NodeType; } - public function setNodeType(string $NodeType): self + public function setNodeType(string|AutopilotServerType $NodeType): self { - $this->NodeType = $NodeType; + $this->NodeType = is_string($NodeType) ? AutopilotServerType::from($NodeType) : $NodeType; return $this; } - public function jsonSerialize(): array - { - $arr = parent::jsonSerialize(); - if (isset($this->StableSince)) { - $arr[self::FIELD_STABLE_SINCE] = $this->StableSince->format(Time\Time::DefaultFormat); + public static function jsonUnserialize(\stdClass $decoded): self + { + $n = new self(); + foreach ((array)$decoded as $k => $v) { + if ('lastContact' === $k) { + $n->setLastContact($v); + } elseif ('StableSince' === $k) { + $n->StableSince = parse_time($v); + } elseif ('Meta' === $k) { + $n->setMeta($v); + } elseif ('Status' === $k) { + $n->setStatus($v); + } elseif ('NodeType' === $k) { + $n->setNodeType($v); + } else { + $n->{$k} = $v; + } + } + return $n; + } + + public function jsonSerialize(): \stdClass + { + $out = $this->_startJsonSerialize(); + $out->ID = $this->ID; + $out->Name = $this->Name; + $out->Address = $this->Address; + $out->NodeStatus = $this->NodeStatus; + $out->Version = $this->Version; + $out->lastContact = null !== $this->LastContact ? (string)$this->LastContact : null; + $out->LastTerm = $this->LastTerm; + $out->LastIndex = $this->LastIndex; + $out->Healthy = $this->Healthy; + $out->StableSince = $this->StableSince; + if ('' !== $this->RedundancyZone) { + $out->RedundancyZone = $this->RedundancyZone; + } + if ('' !== $this->UpgradeVersion) { + $out->UpgradeVersion = $this->UpgradeVersion; } - return $arr; + $out->ReadReplica = $this->ReadReplica; + $out->Meta = $this->getMeta(); + $out->NodeType = $this->NodeType; + return $out; } } diff --git a/src/Operator/AutopilotServerStatus.php b/src/Operator/AutopilotServerStatus.php new file mode 100644 index 00000000..e16fbaa1 --- /dev/null +++ b/src/Operator/AutopilotServerStatus.php @@ -0,0 +1,32 @@ +Tags = $tags; - return $this; - } - - public function addTag(string $tag): static - { - $this->Tags[] = $tag; - return $this; - } + case Voter = 'voter'; + case ReadReplica = 'read-replica'; + case ZoneVoter = 'zone-voter'; + case ZoneExtraVoter = 'zone-extra-voter'; + case ZoneStandby = 'zone-standby'; + + case UNDEFINED = ''; } diff --git a/src/Operator/AutopilotState.php b/src/Operator/AutopilotState.php index 881d8247..03437e79 100644 --- a/src/Operator/AutopilotState.php +++ b/src/Operator/AutopilotState.php @@ -20,47 +20,51 @@ limitations under the License. */ -use DCarbone\PHPConsulAPI\AbstractModel; -use DCarbone\PHPConsulAPI\Transcoding; +use DCarbone\PHPConsulAPI\PHPLib\AbstractType; -class AutopilotState extends AbstractModel +class AutopilotState extends AbstractType { - protected const FIELDS = [ - self::FIELD_SERVERS => [ - Transcoding::FIELD_TYPE => Transcoding::ARRAY, - Transcoding::FIELD_CLASS => AutopilotServer::class, - ], - self::FIELD_READ_REPLICAS => [ - Transcoding::FIELD_TYPE => Transcoding::ARRAY, - Transcoding::FIELD_ARRAY_TYPE => Transcoding::STRING, - Transcoding::FIELD_OMITEMPTY => true, - ], - self::FIELD_REDUNDANCY_ZONE => [ - Transcoding::FIELD_TYPE => Transcoding::ARRAY, - Transcoding::FIELD_CLASS => AutopilotZone::class, - Transcoding::FIELD_OMITEMPTY => true, - ], - self::FIELD_UPGRADE => [ - Transcoding::FIELD_TYPE => Transcoding::OBJECT, - Transcoding::FIELD_CLASS => AutopilotUpgrade::class, - Transcoding::FIELD_OMITEMPTY => true, - ], - ]; - - private const FIELD_SERVERS = 'Servers'; - private const FIELD_READ_REPLICAS = 'ReadReplicas'; - private const FIELD_REDUNDANCY_ZONE = 'RedundancyZone'; - private const FIELD_UPGRADE = 'Upgrade'; - - public bool $Healthy = false; - public int $FailureTolerance = 0; - public int $OptimisticFailureTolerance = 0; - public array $Servers = []; - public string $Leader = ''; - public array $Voters = []; - public array $ReadReplicas = []; - public array $RedundancyZone = []; - public ?AutopilotUpgrade $Upgrade = null; + public bool $Healthy; + public int $FailureTolerance; + public int $OptimisticFailureTolerance; + /** @var array */ + public array $Servers; + public string $Leader; + /** @var array */ + public array $Voters; + /** @var array */ + public array $ReadReplicas; + /** @var array */ + public array $RedundancyZone; + public null|AutopilotUpgrade $Upgrade; + + /** + * @param array $Servers + * @param array $Voters + * @param array $ReadReplicas + * @param array $RedundancyZone + */ + public function __construct( + bool $Healthy = false, + int $FailureTolerance = 0, + int $OptimisticFailureTolerance = 0, + array $Servers = [], + string $Leader = '', + array $Voters = [], + array $ReadReplicas = [], + array $RedundancyZone = [], + null|AutopilotUpgrade $Upgrade = null, + ) { + $this->Healthy = $Healthy; + $this->FailureTolerance = $FailureTolerance; + $this->OptimisticFailureTolerance = $OptimisticFailureTolerance; + $this->Servers = $Servers; + $this->Leader = $Leader; + $this->setVoters(...$Voters); + $this->setReadReplicas(...$ReadReplicas); + $this->RedundancyZone = $RedundancyZone; + $this->Upgrade = $Upgrade; + } public function isHealthy(): bool { @@ -95,11 +99,17 @@ public function setOptimisticFailureTolerance(int $OptimisticFailureTolerance): return $this; } + /** + * @return array + */ public function getServers(): array { return $this->Servers; } + /** + * @param array $Servers + */ public function setServers(array $Servers): self { $this->Servers = $Servers; @@ -117,47 +127,103 @@ public function setLeader(string $Leader): self return $this; } + /** + * @return array + */ public function getVoters(): array { return $this->Voters; } - public function setVoters(array $Voters): self + public function setVoters(string ...$Voters): self { $this->Voters = $Voters; return $this; } + /** + * @return array + */ public function getReadReplicas(): array { return $this->ReadReplicas; } - public function setReadReplicas(array $ReadReplicas): self + public function setReadReplicas(string ...$ReadReplicas): self { $this->ReadReplicas = $ReadReplicas; return $this; } + /** + * @return array + */ public function getRedundancyZone(): array { return $this->RedundancyZone; } + /** + * @param array $RedundancyZone + */ public function setRedundancyZone(array $RedundancyZone): self { $this->RedundancyZone = $RedundancyZone; return $this; } - public function getUpgrade(): ?AutopilotUpgrade + public function getUpgrade(): null|AutopilotUpgrade { return $this->Upgrade; } - public function setUpgrade(?AutopilotUpgrade $Upgrade): self + public function setUpgrade(null|AutopilotUpgrade $Upgrade): self { $this->Upgrade = $Upgrade; return $this; } + + public static function jsonUnserialize(\stdClass $decoded): self + { + $n = new self(); + foreach ((array)$decoded as $k => $v) { + if ('Servers' === $k) { + $n->Servers = []; + foreach ($v as $sk => $sv) { + $n->Servers[$sk] = AutopilotServer::jsonUnserialize($sv); + } + } elseif ('RedundancyZone' === $k) { + $n->RedundancyZone = []; + foreach ($v as $zk => $zv) { + $n->RedundancyZone[$zk] = AutopilotZone::jsonUnserialize($zv); + } + } elseif ('Upgrade' === $k) { + $n->Upgrade = null === $v ? null : AutopilotUpgrade::jsonUnserialize($v); + } else { + $n->{$k} = $v; + } + } + return $n; + } + + public function jsonSerialize(): \stdClass + { + $out = $this->_startJsonSerialize(); + $out->Healthy = $this->Healthy; + $out->FailureTolerance = $this->FailureTolerance; + $out->OptimisticFailureTolerance = $this->OptimisticFailureTolerance; + $out->Servers = $this->Servers; + $out->Leader = $this->Leader; + $out->Voters = $this->Voters; + if ([] !== $this->ReadReplicas) { + $out->ReadReplicas = $this->ReadReplicas; + } + if ([] !== $this->RedundancyZone) { + $out->RedundancyZone = $this->RedundancyZone; + } + if (null !== $this->Upgrade) { + $out->Upgrade = $this->Upgrade; + } + return $out; + } } diff --git a/src/Operator/AutopilotStateResponse.php b/src/Operator/AutopilotStateResponse.php index bf4add88..e889a8e0 100644 --- a/src/Operator/AutopilotStateResponse.php +++ b/src/Operator/AutopilotStateResponse.php @@ -20,20 +20,20 @@ limitations under the License. */ -use DCarbone\PHPConsulAPI\AbstractValuedResponse; -use DCarbone\PHPConsulAPI\UnmarshalledResponseInterface; +use DCarbone\PHPConsulAPI\PHPLib\AbstractValuedResponse; +use DCarbone\PHPConsulAPI\PHPLib\UnmarshalledResponseInterface; class AutopilotStateResponse extends AbstractValuedResponse implements UnmarshalledResponseInterface { - public ?AutopilotState $AutopilotState = null; + public null|AutopilotState $AutopilotState; - public function getValue(): ?AutopilotState + public function getValue(): null|AutopilotState { return $this->AutopilotState; } - public function unmarshalValue(mixed $decodedData): void + public function unmarshalValue(mixed $decoded): void { - $this->AutopilotState = new AutopilotState($decodedData); + $this->AutopilotState = AutopilotState::jsonUnserialize($decoded); } } diff --git a/src/Operator/AutopilotUpgrade.php b/src/Operator/AutopilotUpgrade.php index fa372a69..0d789a77 100644 --- a/src/Operator/AutopilotUpgrade.php +++ b/src/Operator/AutopilotUpgrade.php @@ -20,44 +20,57 @@ limitations under the License. */ -use DCarbone\PHPConsulAPI\AbstractModel; -use DCarbone\PHPConsulAPI\Transcoding; +use DCarbone\PHPConsulAPI\PHPLib\AbstractType; -class AutopilotUpgrade extends AbstractModel +class AutopilotUpgrade extends AbstractType { - protected const FIELDS = [ - self::FIELD_TARGET_VERSION => Transcoding::OMITEMPTY_STRING_FIELD, - self::FIELD_TARGET_VERSION_VOTERS => Transcoding::OMITEMPTY_STRING_ARRAY_FIELD, - self::FIELD_TARGET_VERSION_NON_VOTERS => Transcoding::OMITEMPTY_STRING_ARRAY_FIELD, - self::FIELD_TARGET_VERSION_READ_REPLICAS => Transcoding::OMITEMPTY_STRING_ARRAY_FIELD, - self::FIELD_OTHER_VERSION_VOTERS => Transcoding::OMITEMPTY_STRING_ARRAY_FIELD, - self::FIELD_OTHER_VERSION_NON_VOTERS => Transcoding::OMITEMPTY_STRING_ARRAY_FIELD, - self::FIELD_OTHER_VERSION_READ_REPLICAS => Transcoding::OMITEMPTY_STRING_ARRAY_FIELD, - self::FIELD_REDUNDANCY_ZONES => [ - Transcoding::FIELD_TYPE => Transcoding::ARRAY, - Transcoding::FIELD_CLASS => AutopilotZoneUpgradeVersions::class, - Transcoding::FIELD_ARRAY_TYPE => Transcoding::OBJECT, - ], - ]; - - private const FIELD_TARGET_VERSION = 'TargetVersion'; - private const FIELD_TARGET_VERSION_VOTERS = 'TargetVersionVoters'; - private const FIELD_TARGET_VERSION_NON_VOTERS = 'TargetVersionNonVoters'; - private const FIELD_TARGET_VERSION_READ_REPLICAS = 'TargetVersionReadReplicas'; - private const FIELD_OTHER_VERSION_VOTERS = 'OtherVersionVoters'; - private const FIELD_OTHER_VERSION_NON_VOTERS = 'OtherVersionNonVoters'; - private const FIELD_OTHER_VERSION_READ_REPLICAS = 'OtherVersionReadReplicas'; - private const FIELD_REDUNDANCY_ZONES = 'RedundancyZones'; - - public string $Status = ''; - public string $TargetVersion = ''; - public array $TargetVersionVoters = []; - public array $TargetVersionNonVoters = []; - public array $TargetVersionReadReplicas = []; - public array $OtherVersionVoters = []; - public array $OtherVersionNonVoters = []; - public array $OtherVersionReadReplicas = []; - public array $RedundancyZones = []; + public string $Status; + public string $TargetVersion; + /** @var array */ + public array $TargetVersionVoters; + /** @var array */ + public array $TargetVersionNonVoters; + /** @var array */ + public array $TargetVersionReadReplicas; + /** @var array */ + public array $OtherVersionVoters; + /** @var array */ + public array $OtherVersionNonVoters; + /** @var array */ + public array $OtherVersionReadReplicas; + /** @var array */ + public array $RedundancyZones; + + /** + * @param array $TargetVersionVoters + * @param array $TargetVersionNonVoters + * @param array $TargetVersionReadReplicas + * @param array $OtherVersionVoters + * @param array $OtherVersionNonVoters + * @param array $OtherVersionReadReplicas + * @param array $RedundancyZones + */ + public function __construct( + string $Status = '', + string $TargetVersion = '', + array $TargetVersionVoters = [], + array $TargetVersionNonVoters = [], + array $TargetVersionReadReplicas = [], + array $OtherVersionVoters = [], + array $OtherVersionNonVoters = [], + array $OtherVersionReadReplicas = [], + array $RedundancyZones = [], + ) { + $this->Status = $Status; + $this->TargetVersion = $TargetVersion; + $this->setTargetVersionVoters(...$TargetVersionVoters); + $this->setTargetVersionNonVoters(...$TargetVersionNonVoters); + $this->setTargetVersionReadReplicas(...$TargetVersionReadReplicas); + $this->setOtherVersionVoters(...$OtherVersionVoters); + $this->setOtherVersionNonVoters(...$OtherVersionNonVoters); + $this->setOtherVersionReadReplicas(...$OtherVersionReadReplicas); + $this->RedundancyZones = $RedundancyZones; + } public function getStatus(): string { @@ -81,80 +94,151 @@ public function setTargetVersion(string $TargetVersion): self return $this; } + /** + * @return array + */ public function getTargetVersionVoters(): array { return $this->TargetVersionVoters; } - public function setTargetVersionVoters(array $TargetVersionVoters): self + public function setTargetVersionVoters(string ...$TargetVersionVoters): self { $this->TargetVersionVoters = $TargetVersionVoters; return $this; } + /** + * @return array + */ public function getTargetVersionNonVoters(): array { return $this->TargetVersionNonVoters; } - public function setTargetVersionNonVoters(array $TargetVersionNonVoters): self + public function setTargetVersionNonVoters(string ...$TargetVersionNonVoters): self { $this->TargetVersionNonVoters = $TargetVersionNonVoters; return $this; } + /** + * @return array + */ public function getTargetVersionReadReplicas(): array { return $this->TargetVersionReadReplicas; } - public function setTargetVersionReadReplicas(array $TargetVersionReadReplicas): self + public function setTargetVersionReadReplicas(string ...$TargetVersionReadReplicas): self { $this->TargetVersionReadReplicas = $TargetVersionReadReplicas; return $this; } + /** + * @return array + */ public function getOtherVersionVoters(): array { return $this->OtherVersionVoters; } - public function setOtherVersionVoters(array $OtherVersionVoters): self + public function setOtherVersionVoters(string ...$OtherVersionVoters): self { $this->OtherVersionVoters = $OtherVersionVoters; return $this; } + /** + * @return array + */ public function getOtherVersionNonVoters(): array { return $this->OtherVersionNonVoters; } - public function setOtherVersionNonVoters(array $OtherVersionNonVoters): self + public function setOtherVersionNonVoters(string ...$OtherVersionNonVoters): self { $this->OtherVersionNonVoters = $OtherVersionNonVoters; return $this; } + /** + * @return array + */ public function getOtherVersionReadReplicas(): array { return $this->OtherVersionReadReplicas; } - public function setOtherVersionReadReplicas(array $OtherVersionReadReplicas): self + public function setOtherVersionReadReplicas(string ...$OtherVersionReadReplicas): self { $this->OtherVersionReadReplicas = $OtherVersionReadReplicas; return $this; } + /** + * @return array + */ public function getRedundancyZones(): array { return $this->RedundancyZones; } + /** + * @param array $RedundancyZones + */ public function setRedundancyZones(array $RedundancyZones): self { $this->RedundancyZones = $RedundancyZones; return $this; } + + public static function jsonUnserialize(\stdClass $decoded): self + { + $n = new self(); + foreach ((array)$decoded as $k => $v) { + if ('RedundancyZones' === $k) { + $n->RedundancyZones = []; + foreach ($v as $zk => $zv) { + $n->RedundancyZones[$zk] = AutopilotZoneUpgradeVersions::jsonUnserialize($zv); + } + } else { + $n->{$k} = $v; + } + } + return $n; + } + + public function jsonSerialize(): \stdClass + { + $out = $this->_startJsonSerialize(); + $out->Status = $this->Status; + if ('' !== $this->TargetVersion) { + $out->TargetVersion = $this->TargetVersion; + } + if ([] !== $this->TargetVersionVoters) { + $out->TargetVersionVoters = $this->TargetVersionVoters; + } + if ([] !== $this->TargetVersionNonVoters) { + $out->TargetVersionNonVoters = $this->TargetVersionNonVoters; + } + if ([] !== $this->TargetVersionReadReplicas) { + $out->TargetVersionReadReplicas = $this->TargetVersionReadReplicas; + } + if ([] !== $this->OtherVersionVoters) { + $out->OtherVersionVoters = $this->OtherVersionVoters; + } + if ([] !== $this->OtherVersionNonVoters) { + $out->OtherVersionNonVoters = $this->OtherVersionNonVoters; + } + if ([] !== $this->OtherVersionReadReplicas) { + $out->OtherVersionReadReplicas = $this->OtherVersionReadReplicas; + } + if ([] !== $this->RedundancyZones) { + $out->RedundancyZones = $this->RedundancyZones; + } + return $out; + } } diff --git a/src/Operator/AutopilotUpgradeStatus.php b/src/Operator/AutopilotUpgradeStatus.php new file mode 100644 index 00000000..1c40f86f --- /dev/null +++ b/src/Operator/AutopilotUpgradeStatus.php @@ -0,0 +1,33 @@ + */ + public array $Servers; + /** @var array */ + public array $Voters; + public int $FailureTolerance; + /** + * @param array $Servers + * @param array $Voters + */ + public function __construct( + array $Servers = [], + array $Voters = [], + int $FailureTolerance = 0, + ) { + $this->setServers(...$Servers); + $this->setVoters(...$Voters); + $this->FailureTolerance = $FailureTolerance; + } + + /** + * @return array + */ public function getServers(): array { return $this->Servers; } - public function setServers(array $Servers): self + public function setServers(string ...$Servers): self { $this->Servers = $Servers; return $this; } + /** + * @return array + */ public function getVoters(): array { return $this->Voters; } - public function setVoters(array $Voters): self + public function setVoters(string ...$Voters): self { $this->Voters = $Voters; return $this; @@ -60,4 +82,22 @@ public function setFailureTolerance(int $FailureTolerance): self $this->FailureTolerance = $FailureTolerance; return $this; } + + public static function jsonUnserialize(\stdClass $decoded): self + { + $n = new self(); + foreach ((array)$decoded as $k => $v) { + $n->{$k} = $v; + } + return $n; + } + + public function jsonSerialize(): \stdClass + { + $out = $this->_startJsonSerialize(); + $out->Servers = $this->Servers; + $out->Voters = $this->Voters; + $out->FailureTolerance = $this->FailureTolerance; + return $out; + } } diff --git a/src/Operator/AutopilotZoneUpgradeVersions.php b/src/Operator/AutopilotZoneUpgradeVersions.php index 9b07c349..9a3272a1 100644 --- a/src/Operator/AutopilotZoneUpgradeVersions.php +++ b/src/Operator/AutopilotZoneUpgradeVersions.php @@ -20,69 +20,117 @@ limitations under the License. */ -use DCarbone\PHPConsulAPI\AbstractModel; -use DCarbone\PHPConsulAPI\Transcoding; +use DCarbone\PHPConsulAPI\PHPLib\AbstractType; -class AutopilotZoneUpgradeVersions extends AbstractModel +class AutopilotZoneUpgradeVersions extends AbstractType { - protected const FIELDS = [ - self::FIELD_TARGET_VERSION_VOTERS => Transcoding::OMITEMPTY_STRING_ARRAY_FIELD, - self::FIELD_TARGET_VERSION_NON_VOTERS => Transcoding::OMITEMPTY_STRING_ARRAY_FIELD, - self::FIELD_OTHER_VERSION_VOTERS => Transcoding::OMITEMPTY_STRING_ARRAY_FIELD, - self::FIELD_OTHER_VERSION_NON_VOTERS => Transcoding::OMITEMPTY_STRING_ARRAY_FIELD, - ]; - - private const FIELD_TARGET_VERSION_VOTERS = 'TargetVersionVoters'; - private const FIELD_TARGET_VERSION_NON_VOTERS = 'TargetVersionNonVoters'; - private const FIELD_OTHER_VERSION_VOTERS = 'OtherVersionVoters'; - private const FIELD_OTHER_VERSION_NON_VOTERS = 'OtherVersionNonVoters'; - - public array $TargetVersionVoters = []; - public array $TargetVersionNonVoters = []; - public array $OtherVersionVoters = []; - public array $OtherVersionNonVoters = []; + /** @var array */ + public array $TargetVersionVoters; + /** @var array */ + public array $TargetVersionNonVoters; + /** @var array */ + public array $OtherVersionVoters; + /** @var array */ + public array $OtherVersionNonVoters; + + /** + * @param array $TargetVersionVoters + * @param array $TargetVersionNonVoters + * @param array $OtherVersionVoters + * @param array $OtherVersionNonVoters + */ + public function __construct( + array $TargetVersionVoters = [], + array $TargetVersionNonVoters = [], + array $OtherVersionVoters = [], + array $OtherVersionNonVoters = [], + ) { + $this->setTargetVersionVoters(...$TargetVersionVoters); + $this->setTargetVersionNonVoters(...$TargetVersionNonVoters); + $this->setOtherVersionVoters(...$OtherVersionVoters); + $this->setOtherVersionNonVoters(...$OtherVersionNonVoters); + } + /** + * @return array + */ public function getTargetVersionVoters(): array { return $this->TargetVersionVoters; } - public function setTargetVersionVoters(array $TargetVersionVoters): self + public function setTargetVersionVoters(string ...$TargetVersionVoters): self { $this->TargetVersionVoters = $TargetVersionVoters; return $this; } + /** + * @return array + */ public function getTargetVersionNonVoters(): array { return $this->TargetVersionNonVoters; } - public function setTargetVersionNonVoters(array $TargetVersionNonVoters): self + public function setTargetVersionNonVoters(string ...$TargetVersionNonVoters): self { $this->TargetVersionNonVoters = $TargetVersionNonVoters; return $this; } + /** + * @return array + */ public function getOtherVersionVoters(): array { return $this->OtherVersionVoters; } - public function setOtherVersionVoters(array $OtherVersionVoters): self + public function setOtherVersionVoters(string ...$OtherVersionVoters): self { $this->OtherVersionVoters = $OtherVersionVoters; return $this; } + /** + * @return array + */ public function getOtherVersionNonVoters(): array { return $this->OtherVersionNonVoters; } - public function setOtherVersionNonVoters(array $OtherVersionNonVoters): self + public function setOtherVersionNonVoters(string ...$OtherVersionNonVoters): self { $this->OtherVersionNonVoters = $OtherVersionNonVoters; return $this; } + + public static function jsonUnserialize(\stdClass $decoded): self + { + $n = new self(); + foreach ((array)$decoded as $k => $v) { + $n->{$k} = $v; + } + return $n; + } + + public function jsonSerialize(): \stdClass + { + $out = $this->_startJsonSerialize(); + if ([] !== $this->TargetVersionVoters) { + $out->TargetVersionVoters = $this->TargetVersionVoters; + } + if ([] !== $this->TargetVersionNonVoters) { + $out->TargetVersionNonVoters = $this->TargetVersionNonVoters; + } + if ([] !== $this->OtherVersionVoters) { + $out->OtherVersionVoters = $this->OtherVersionVoters; + } + if ([] !== $this->OtherVersionNonVoters) { + $out->OtherVersionNonVoters = $this->OtherVersionNonVoters; + } + return $out; + } } diff --git a/src/Operator/OperatorAreaJoinResponse.php b/src/Operator/OperatorAreaJoinResponse.php index b97836ae..f081b8a0 100644 --- a/src/Operator/OperatorAreaJoinResponse.php +++ b/src/Operator/OperatorAreaJoinResponse.php @@ -20,23 +20,27 @@ limitations under the License. */ -use DCarbone\PHPConsulAPI\AbstractValuedWriteResponse; -use DCarbone\PHPConsulAPI\UnmarshalledResponseInterface; +use DCarbone\PHPConsulAPI\PHPLib\AbstractValuedWriteResponse; +use DCarbone\PHPConsulAPI\PHPLib\UnmarshalledResponseInterface; class OperatorAreaJoinResponse extends AbstractValuedWriteResponse implements UnmarshalledResponseInterface { - public ?array $AreaJoinResponses = null; + /** @var \DCarbone\PHPConsulAPI\Operator\AreaJoinResponse[] */ + public array $AreaJoinResponses; - public function getValue(): ?array + /** + * @return \DCarbone\PHPConsulAPI\Operator\AreaJoinResponse[] + */ + public function getValue(): array { return $this->AreaJoinResponses; } - public function unmarshalValue(mixed $decodedData): void + public function unmarshalValue(mixed $decoded): void { $this->AreaJoinResponses = []; - foreach ($decodedData as $area) { - $this->AreaJoinResponses[] = new AreaJoinResponse($area); + foreach ($decoded as $area) { + $this->AreaJoinResponses[] = AreaJoinResponse::jsonUnserialize($area); } } } diff --git a/src/Operator/OperatorAreasResponse.php b/src/Operator/OperatorAreasResponse.php index 9e7417a4..19893d0b 100644 --- a/src/Operator/OperatorAreasResponse.php +++ b/src/Operator/OperatorAreasResponse.php @@ -20,23 +20,27 @@ limitations under the License. */ -use DCarbone\PHPConsulAPI\AbstractValuedQueryResponse; -use DCarbone\PHPConsulAPI\UnmarshalledResponseInterface; +use DCarbone\PHPConsulAPI\PHPLib\AbstractValuedQueryResponse; +use DCarbone\PHPConsulAPI\PHPLib\UnmarshalledResponseInterface; class OperatorAreasResponse extends AbstractValuedQueryResponse implements UnmarshalledResponseInterface { - public ?array $Areas = null; + /** @var \DCarbone\PHPConsulAPI\Operator\Area[] */ + public array $Areas; - public function getValue(): ?array + /** + * @return \DCarbone\PHPConsulAPI\Operator\Area[] + */ + public function getValue(): array { return $this->Areas; } - public function unmarshalValue(mixed $decodedData): void + public function unmarshalValue(mixed $decoded): void { $this->Areas = []; - foreach ($decodedData as $area) { - $this->Areas[] = new Area($area); + foreach ($decoded as $area) { + $this->Areas[] = Area::jsonUnserialize($area); } } } diff --git a/src/Operator/OperatorAutopilotConfigurationResponse.php b/src/Operator/OperatorAutopilotConfigurationResponse.php index 1bbe27ab..6e2a52d3 100644 --- a/src/Operator/OperatorAutopilotConfigurationResponse.php +++ b/src/Operator/OperatorAutopilotConfigurationResponse.php @@ -20,20 +20,20 @@ limitations under the License. */ -use DCarbone\PHPConsulAPI\AbstractValuedResponse; -use DCarbone\PHPConsulAPI\UnmarshalledResponseInterface; +use DCarbone\PHPConsulAPI\PHPLib\AbstractValuedResponse; +use DCarbone\PHPConsulAPI\PHPLib\UnmarshalledResponseInterface; class OperatorAutopilotConfigurationResponse extends AbstractValuedResponse implements UnmarshalledResponseInterface { - public ?AutopilotConfiguration $AutopilotConfiguration = null; + public null|AutopilotConfiguration $AutopilotConfiguration; - public function getValue(): ?AutopilotConfiguration + public function getValue(): null|AutopilotConfiguration { return $this->AutopilotConfiguration; } - public function unmarshalValue(mixed $decodedData): void + public function unmarshalValue(mixed $decoded): void { - $this->AutopilotConfiguration = new AutopilotConfiguration((array)$decodedData); + $this->AutopilotConfiguration = AutopilotConfiguration::jsonUnserialize($decoded); } } diff --git a/src/Operator/OperatorClient.php b/src/Operator/OperatorClient.php index f4ccf63c..3fc77faf 100644 --- a/src/Operator/OperatorClient.php +++ b/src/Operator/OperatorClient.php @@ -20,30 +20,30 @@ limitations under the License. */ -use DCarbone\PHPConsulAPI\AbstractClient; -use DCarbone\PHPConsulAPI\Error; +use DCarbone\PHPConsulAPI\PHPLib\AbstractClient; +use DCarbone\PHPConsulAPI\PHPLib\Error; +use DCarbone\PHPConsulAPI\PHPLib\RequestResponse; +use DCarbone\PHPConsulAPI\PHPLib\ValuedBoolResponse; +use DCarbone\PHPConsulAPI\PHPLib\ValuedWriteStringResponse; +use DCarbone\PHPConsulAPI\PHPLib\WriteResponse; use DCarbone\PHPConsulAPI\QueryOptions; -use DCarbone\PHPConsulAPI\RequestResponse; -use DCarbone\PHPConsulAPI\ValuedBoolResponse; -use DCarbone\PHPConsulAPI\ValuedWriteStringResponse; use DCarbone\PHPConsulAPI\WriteOptions; -use DCarbone\PHPConsulAPI\WriteResponse; class OperatorClient extends AbstractClient { - public function AreaCreate(Area $area, ?WriteOptions $opts = null): ValuedWriteStringResponse + public function AreaCreate(Area $area, null|WriteOptions $opts = null): ValuedWriteStringResponse { return $this->_writeIDResponse($this->_requireOK($this->_doPost('v1/operator/area', $area, $opts))); } - public function AreaUpdate(string $areaID, Area $area, ?WriteOptions $opts = null): ValuedWriteStringResponse + public function AreaUpdate(string $areaID, Area $area, null|WriteOptions $opts = null): ValuedWriteStringResponse { return $this->_writeIDResponse( $this->_requireOK($this->_doPut(sprintf('v1/operator/area/%s', $areaID), $area, $opts)) ); } - public function AreaGet(string $areaID, ?QueryOptions $opts = null): OperatorAreasResponse + public function AreaGet(string $areaID, null|QueryOptions $opts = null): OperatorAreasResponse { $resp = $this->_requireOK($this->_doGet(sprintf('v1/operator/area/%s', urlencode($areaID)), $opts)); $ret = new OperatorAreasResponse(); @@ -51,7 +51,7 @@ public function AreaGet(string $areaID, ?QueryOptions $opts = null): OperatorAre return $ret; } - public function AreaList(?QueryOptions $opts = null): OperatorAreasResponse + public function AreaList(null|QueryOptions $opts = null): OperatorAreasResponse { $resp = $this->_requireOK($this->_doGet('v1/operator/area', $opts)); $ret = new OperatorAreasResponse(); @@ -59,12 +59,15 @@ public function AreaList(?QueryOptions $opts = null): OperatorAreasResponse return $ret; } - public function AreaDelete(string $areaID, ?WriteOptions $opts = null): WriteResponse + public function AreaDelete(string $areaID, null|WriteOptions $opts = null): WriteResponse { return $this->_executeDelete(sprintf('v1/operator/area/%s', $areaID), $opts); } - public function AreaJoin(string $areaID, array $addresses, ?WriteOptions $opts = null): OperatorAreaJoinResponse + /** + * @param array $addresses + */ + public function AreaJoin(string $areaID, array $addresses, null|WriteOptions $opts = null): OperatorAreaJoinResponse { $resp = $this->_requireOK($this->_doPut(sprintf('v1/operator/area/%s/join', $areaID), $addresses, $opts)); $ret = new OperatorAreaJoinResponse(); @@ -72,7 +75,7 @@ public function AreaJoin(string $areaID, array $addresses, ?WriteOptions $opts = return $ret; } - public function AreaMembers(string $areaID, ?QueryOptions $opts = null): OperatorSerfMembersResponse + public function AreaMembers(string $areaID, null|QueryOptions $opts = null): OperatorSerfMembersResponse { $resp = $this->_requireOK($this->_doGet(sprintf('v1/operator/area/%s/members', $areaID), $opts)); $ret = new OperatorSerfMembersResponse(); @@ -80,7 +83,7 @@ public function AreaMembers(string $areaID, ?QueryOptions $opts = null): Operato return $ret; } - public function AutopilotGetConfiguration(?QueryOptions $opts = null): OperatorAutopilotConfigurationResponse + public function AutopilotGetConfiguration(null|QueryOptions $opts = null): OperatorAutopilotConfigurationResponse { $resp = $this->_requireOK($this->_doGet('v1/operator/autopilot/configuration', $opts)); $ret = new OperatorAutopilotConfigurationResponse(); @@ -88,14 +91,14 @@ public function AutopilotGetConfiguration(?QueryOptions $opts = null): OperatorA return $ret; } - public function AutopilotSetConfiguration(AutopilotConfiguration $conf, ?WriteOptions $opts = null): ?Error + public function AutopilotSetConfiguration(AutopilotConfiguration $conf, null|WriteOptions $opts = null): null|Error { return $this->_requireOK($this->_doPut('v1/operator/autopilot/configuration', $conf, $opts))->Err; } public function AutopilotCASConfiguration( AutopilotConfiguration $conf, - ?WriteOptions $opts = null + null|WriteOptions $opts = null ): ValuedBoolResponse { $resp = $this->_requireOK($this->_doPut('v1/operator/autopilot/configuration', $conf, $opts)); $ret = new ValuedBoolResponse(); @@ -103,7 +106,7 @@ public function AutopilotCASConfiguration( return $ret; } - public function AutopilotServerHealth(?QueryOptions $opts = null): OperatorHealthReplyResponse + public function AutopilotServerHealth(null|QueryOptions $opts = null): OperatorHealthReplyResponse { $resp = $this->_requireOK($this->_doGet('v1/operator/autopilot/health', $opts)); $ret = new OperatorHealthReplyResponse(); @@ -111,7 +114,7 @@ public function AutopilotServerHealth(?QueryOptions $opts = null): OperatorHealt return $ret; } - public function AutopilotState(?QueryOptions $opts = null): AutopilotStateResponse + public function AutopilotState(null|QueryOptions $opts = null): AutopilotStateResponse { $resp = $this->_requireOK($this->_doGet('v1/operator/autopilot/state', $opts)); $ret = new AutopilotStateResponse(); @@ -119,7 +122,7 @@ public function AutopilotState(?QueryOptions $opts = null): AutopilotStateRespon return $ret; } - public function RaftGetConfiguration(?QueryOptions $opts = null): OperatorRaftConfigurationResponse + public function RaftGetConfiguration(null|QueryOptions $opts = null): OperatorRaftConfigurationResponse { $resp = $this->_requireOK($this->_doGet('v1/operator/raft/configuration', $opts)); $ret = new OperatorRaftConfigurationResponse(); @@ -127,7 +130,7 @@ public function RaftGetConfiguration(?QueryOptions $opts = null): OperatorRaftCo return $ret; } - public function RaftRemovePeerByAddress(string $address, ?WriteOptions $opts = null): ?Error + public function RaftRemovePeerByAddress(string $address, null|WriteOptions $opts = null): null|Error { $r = $this->_newDeleteRequest('v1/operator/raft/peer', $opts); $r->applyOptions($opts); diff --git a/src/Operator/OperatorHealthReply.php b/src/Operator/OperatorHealthReply.php index a837eb7a..09caaa19 100644 --- a/src/Operator/OperatorHealthReply.php +++ b/src/Operator/OperatorHealthReply.php @@ -20,24 +20,27 @@ limitations under the License. */ -use DCarbone\PHPConsulAPI\AbstractModel; -use DCarbone\PHPConsulAPI\Transcoding; +use DCarbone\PHPConsulAPI\PHPLib\AbstractType; -class OperatorHealthReply extends AbstractModel +class OperatorHealthReply extends AbstractType { - protected const FIELDS = [ - self::FIELD_SERVERS => [ - Transcoding::FIELD_TYPE => Transcoding::ARRAY, - Transcoding::FIELD_CLASS => ServerHealth::class, - Transcoding::FIELD_ARRAY_TYPE => Transcoding::OBJECT, - ], - ]; - - private const FIELD_SERVERS = 'Servers'; - - public bool $Healthy = false; - public int $FailureTolerance = 0; - public array $Servers = []; + public bool $Healthy; + public int $FailureTolerance; + /** @var array */ + public array $Servers; + + /** + * @param array $Servers + */ + public function __construct( + bool $Healthy = false, + int $FailureTolerance = 0, + array $Servers = [], + ) { + $this->Healthy = $Healthy; + $this->FailureTolerance = $FailureTolerance; + $this->setServers(...$Servers); + } public function isHealthy(): bool { @@ -61,14 +64,42 @@ public function setFailureTolerance(int $FailureTolerance): self return $this; } + /** + * @return array + */ public function getServers(): array { return $this->Servers; } - public function setServers(array $Servers): self + public function setServers(ServerHealth ...$Servers): self { $this->Servers = $Servers; return $this; } + + public static function jsonUnserialize(\stdClass $decoded): self + { + $n = new self(); + foreach ((array)$decoded as $k => $v) { + if ('Servers' === $k) { + $n->Servers = []; + foreach ($v as $sv) { + $n->Servers[] = ServerHealth::jsonUnserialize($sv); + } + } else { + $n->{$k} = $v; + } + } + return $n; + } + + public function jsonSerialize(): \stdClass + { + $out = $this->_startJsonSerialize(); + $out->Healthy = $this->Healthy; + $out->FailureTolerance = $this->FailureTolerance; + $out->Servers = $this->Servers; + return $out; + } } diff --git a/src/Operator/OperatorHealthReplyResponse.php b/src/Operator/OperatorHealthReplyResponse.php index 1a6446cc..b8f00fe2 100644 --- a/src/Operator/OperatorHealthReplyResponse.php +++ b/src/Operator/OperatorHealthReplyResponse.php @@ -20,20 +20,20 @@ limitations under the License. */ -use DCarbone\PHPConsulAPI\AbstractValuedResponse; -use DCarbone\PHPConsulAPI\UnmarshalledResponseInterface; +use DCarbone\PHPConsulAPI\PHPLib\AbstractValuedResponse; +use DCarbone\PHPConsulAPI\PHPLib\UnmarshalledResponseInterface; class OperatorHealthReplyResponse extends AbstractValuedResponse implements UnmarshalledResponseInterface { - public ?OperatorHealthReply $OperatorHealthReply = null; + public null|OperatorHealthReply $OperatorHealthReply; - public function getValue(): mixed + public function getValue(): null|OperatorHealthReply { return $this->OperatorHealthReply; } - public function unmarshalValue(mixed $decodedData): void + public function unmarshalValue(mixed $decoded): void { - $this->OperatorHealthReply = new OperatorHealthReply((array)$decodedData); + $this->OperatorHealthReply = OperatorHealthReply::jsonUnserialize($decoded); } } diff --git a/src/Operator/OperatorRaftConfigurationResponse.php b/src/Operator/OperatorRaftConfigurationResponse.php index 114410be..9c115e47 100644 --- a/src/Operator/OperatorRaftConfigurationResponse.php +++ b/src/Operator/OperatorRaftConfigurationResponse.php @@ -20,20 +20,20 @@ limitations under the License. */ -use DCarbone\PHPConsulAPI\AbstractValuedResponse; -use DCarbone\PHPConsulAPI\UnmarshalledResponseInterface; +use DCarbone\PHPConsulAPI\PHPLib\AbstractValuedResponse; +use DCarbone\PHPConsulAPI\PHPLib\UnmarshalledResponseInterface; class OperatorRaftConfigurationResponse extends AbstractValuedResponse implements UnmarshalledResponseInterface { - public ?RaftConfiguration $RaftConfiguration = null; + public null|RaftConfiguration $RaftConfiguration; - public function getValue(): ?RaftConfiguration + public function getValue(): null|RaftConfiguration { return $this->RaftConfiguration; } - public function unmarshalValue(mixed $decodedData): void + public function unmarshalValue(mixed $decoded): void { - $this->RaftConfiguration = new RaftConfiguration($decodedData); + $this->RaftConfiguration = RaftConfiguration::jsonUnserialize($decoded); } } diff --git a/src/Operator/OperatorSerfMembersResponse.php b/src/Operator/OperatorSerfMembersResponse.php index 5c875222..3ed8849e 100644 --- a/src/Operator/OperatorSerfMembersResponse.php +++ b/src/Operator/OperatorSerfMembersResponse.php @@ -20,23 +20,27 @@ limitations under the License. */ -use DCarbone\PHPConsulAPI\AbstractValuedQueryResponse; -use DCarbone\PHPConsulAPI\UnmarshalledResponseInterface; +use DCarbone\PHPConsulAPI\PHPLib\AbstractValuedQueryResponse; +use DCarbone\PHPConsulAPI\PHPLib\UnmarshalledResponseInterface; class OperatorSerfMembersResponse extends AbstractValuedQueryResponse implements UnmarshalledResponseInterface { - public ?array $SerfMembers = null; + /** @var \DCarbone\PHPConsulAPI\Operator\SerfMember[] */ + public array $SerfMembers; - public function getValue(): ?array + /** + * @return \DCarbone\PHPConsulAPI\Operator\SerfMember[] + */ + public function getValue(): array { return $this->SerfMembers; } - public function unmarshalValue(mixed $decodedData): void + public function unmarshalValue(mixed $decoded): void { $this->SerfMembers = []; - foreach ($decodedData as $datum) { - $this->SerfMembers[] = new SerfMember($datum); + foreach ($decoded as $datum) { + $this->SerfMembers[] = SerfMember::jsonUnserialize($datum); } } } diff --git a/src/Operator/OperatorServerHealthsResponse.php b/src/Operator/OperatorServerHealthsResponse.php index c1010a68..0f3b8a71 100644 --- a/src/Operator/OperatorServerHealthsResponse.php +++ b/src/Operator/OperatorServerHealthsResponse.php @@ -20,23 +20,27 @@ limitations under the License. */ -use DCarbone\PHPConsulAPI\AbstractValuedResponse; -use DCarbone\PHPConsulAPI\UnmarshalledResponseInterface; +use DCarbone\PHPConsulAPI\PHPLib\AbstractValuedResponse; +use DCarbone\PHPConsulAPI\PHPLib\UnmarshalledResponseInterface; class OperatorServerHealthsResponse extends AbstractValuedResponse implements UnmarshalledResponseInterface { - public ?array $ServerHealths = null; + /** @var \DCarbone\PHPConsulAPI\Operator\ServerHealth[] */ + public array $ServerHealths; - public function getValue(): ?array + /** + * @return \DCarbone\PHPConsulAPI\Operator\ServerHealth[] + */ + public function getValue(): array { return $this->ServerHealths; } - public function unmarshalValue(mixed $decodedData): void + public function unmarshalValue(mixed $decoded): void { $this->ServerHealths = []; - foreach ($decodedData as $datum) { - $this->ServerHealths[] = new ServerHealth($datum); + foreach ($decoded as $datum) { + $this->ServerHealths[] = ServerHealth::jsonUnserialize($datum); } } } diff --git a/src/Operator/RaftConfiguration.php b/src/Operator/RaftConfiguration.php index 525f4e4a..76e7dd92 100644 --- a/src/Operator/RaftConfiguration.php +++ b/src/Operator/RaftConfiguration.php @@ -20,30 +20,34 @@ limitations under the License. */ -use DCarbone\PHPConsulAPI\AbstractModel; -use DCarbone\PHPConsulAPI\Transcoding; +use DCarbone\PHPConsulAPI\PHPLib\AbstractType; -class RaftConfiguration extends AbstractModel +class RaftConfiguration extends AbstractType { - protected const FIELDS = [ - self::FIELD_SERVERS => [ - Transcoding::FIELD_TYPE => Transcoding::ARRAY, - Transcoding::FIELD_CLASS => RaftServer::class, - Transcoding::FIELD_ARRAY_TYPE => Transcoding::OBJECT, - ], - ]; + /** @var array */ + public array $Servers; + public int $Index; - private const FIELD_SERVERS = 'Servers'; - - public array $Servers = []; - public int $Index = 0; + /** + * @param array $Servers + */ + public function __construct( + array $Servers = [], + int $Index = 0, + ) { + $this->setServers(...$Servers); + $this->Index = $Index; + } + /** + * @return array + */ public function getServers(): array { return $this->Servers; } - public function setServers(array $Servers): self + public function setServers(RaftServer ...$Servers): self { $this->Servers = $Servers; return $this; @@ -59,4 +63,28 @@ public function setIndex(int $Index): self $this->Index = $Index; return $this; } + + public static function jsonUnserialize(\stdClass $decoded): self + { + $n = new self(); + foreach ((array)$decoded as $k => $v) { + if ('Servers' === $k) { + $n->Servers = []; + foreach ($v as $sv) { + $n->Servers[] = RaftServer::jsonUnserialize($sv); + } + } else { + $n->{$k} = $v; + } + } + return $n; + } + + public function jsonSerialize(): \stdClass + { + $out = $this->_startJsonSerialize(); + $out->Servers = $this->Servers; + $out->Index = $this->Index; + return $out; + } } diff --git a/src/Operator/RaftServer.php b/src/Operator/RaftServer.php index 9fa59d0a..107a5c28 100644 --- a/src/Operator/RaftServer.php +++ b/src/Operator/RaftServer.php @@ -20,16 +20,32 @@ limitations under the License. */ -use DCarbone\PHPConsulAPI\AbstractModel; +use DCarbone\PHPConsulAPI\PHPLib\AbstractType; -class RaftServer extends AbstractModel +class RaftServer extends AbstractType { - public string $ID = ''; - public string $Node = ''; - public string $Address = ''; - public bool $Leader = false; - public string $ProtocolVersion = ''; - public bool $Voter = false; + public string $ID; + public string $Node; + public string $Address; + public bool $Leader; + public string $ProtocolVersion; + public bool $Voter; + + public function __construct( + string $ID = '', + string $Node = '', + string $Address = '', + bool $Leader = false, + string $ProtocolVersion = '', + bool $Voter = false, + ) { + $this->ID = $ID; + $this->Node = $Node; + $this->Address = $Address; + $this->Leader = $Leader; + $this->ProtocolVersion = $ProtocolVersion; + $this->Voter = $Voter; + } public function getID(): string { @@ -96,4 +112,25 @@ public function setVoter(bool $Voter): self $this->Voter = $Voter; return $this; } + + public static function jsonUnserialize(\stdClass $decoded): self + { + $n = new self(); + foreach ((array)$decoded as $k => $v) { + $n->{$k} = $v; + } + return $n; + } + + public function jsonSerialize(): \stdClass + { + $out = $this->_startJsonSerialize(); + $out->ID = $this->ID; + $out->Node = $this->Node; + $out->Address = $this->Address; + $out->Leader = $this->Leader; + $out->ProtocolVersion = $this->ProtocolVersion; + $out->Voter = $this->Voter; + return $out; + } } diff --git a/src/Operator/ReadableDuration.php b/src/Operator/ReadableDuration.php deleted file mode 100644 index 303c6720..00000000 --- a/src/Operator/ReadableDuration.php +++ /dev/null @@ -1,42 +0,0 @@ -{$field} = new self(\intval($value, 10)); - } - - public static function fromDuration(string $s): self - { - return new self(Time::ParseDuration($s)->Nanoseconds()); - } - - public function jsonSerialize(): string - { - return (string)$this; - } -} diff --git a/src/Operator/SerfMember.php b/src/Operator/SerfMember.php index 3c22bf53..d470fa2b 100644 --- a/src/Operator/SerfMember.php +++ b/src/Operator/SerfMember.php @@ -21,36 +21,43 @@ */ use DCarbone\Go\Time; -use DCarbone\PHPConsulAPI\AbstractModel; -use DCarbone\PHPConsulAPI\Transcoding; +use DCarbone\PHPConsulAPI\PHPLib\AbstractType; -class SerfMember extends AbstractModel +class SerfMember extends AbstractType { - protected const FIELDS = [ - self::FIELD_RTT => [ - Transcoding::FIELD_UNMARSHAL_CALLBACK => Transcoding::UNMARSHAL_DURATION, - ], - ]; - - private const FIELD_RTT = 'RTT'; - - public string $ID = ''; - public string $Name = ''; - public string $Addr = ''; - public int $Port = 0; - public string $Datacenter = ''; - public string $Role = ''; - public string $Build = ''; - public int $Protocol = 0; - public string $Status = ''; + public string $ID; + public string $Name; + public string $Addr; + public int $Port; + public string $Datacenter; + public string $Role; + public string $Build; + public int $Protocol; + public string $Status; public Time\Duration $RTT; - public function __construct(?array $data = []) - { - parent::__construct($data); - if (!isset($this->RTT)) { - $this->RTT = new Time\Duration(0); - } + public function __construct( + string $ID = '', + string $Name = '', + string $Addr = '', + int $Port = 0, + string $Datacenter = '', + string $Role = '', + string $Build = '', + int $Protocol = 0, + string $Status = '', + null|string|int|float|\DateInterval|Time\Duration $RTT = null, + ) { + $this->ID = $ID; + $this->Name = $Name; + $this->Addr = $Addr; + $this->Port = $Port; + $this->Datacenter = $Datacenter; + $this->Role = $Role; + $this->Build = $Build; + $this->Protocol = $Protocol; + $this->Status = $Status; + $this->RTT = null === $RTT ? new Time\Duration(0) : Time::Duration($RTT); } public function getID(): string @@ -157,9 +164,38 @@ public function getRTT(): Time\Duration return $this->RTT; } - public function setRTT(Time\Duration $RTT): self + public function setRTT(null|string|int|float|\DateInterval|Time\Duration $RTT): self { - $this->RTT = $RTT; + $this->RTT = Time::Duration($RTT); return $this; } + + public static function jsonUnserialize(\stdClass $decoded): self + { + $n = new self(); + foreach ((array)$decoded as $k => $v) { + if ('RTT' === $k) { + $n->RTT = Time::Duration($v); + } else { + $n->{$k} = $v; + } + } + return $n; + } + + public function jsonSerialize(): \stdClass + { + $out = $this->_startJsonSerialize(); + $out->ID = $this->ID; + $out->Name = $this->Name; + $out->Addr = $this->Addr; + $out->Port = $this->Port; + $out->Datacenter = $this->Datacenter; + $out->Role = $this->Role; + $out->Build = $this->Build; + $out->Protocol = $this->Protocol; + $out->Status = $this->Status; + $out->RTT = (string)$this->RTT; + return $out; + } } diff --git a/src/Operator/ServerHealth.php b/src/Operator/ServerHealth.php index e50af771..2cf8e3d1 100644 --- a/src/Operator/ServerHealth.php +++ b/src/Operator/ServerHealth.php @@ -21,43 +21,50 @@ */ use DCarbone\Go\Time; -use DCarbone\PHPConsulAPI\AbstractModel; -use DCarbone\PHPConsulAPI\Transcoding; +use DCarbone\PHPConsulAPI\PHPLib\AbstractType; +use function DCarbone\PHPConsulAPI\PHPLib\parse_time; -class ServerHealth extends AbstractModel +class ServerHealth extends AbstractType { - protected const FIELDS = [ - self::FIELD_LAST_CONTACT => [ - Transcoding::FIELD_UNMARSHAL_CALLBACK => [ReadableDuration::class, 'unmarshalJSON'], - Transcoding::FIELD_NULLABLE => true, - ], - self::FIELD_STABLE_SINCE => [ - Transcoding::FIELD_UNMARSHAL_CALLBACK => Transcoding::UNMARSHAL_TIME, - ], - ]; - - private const FIELD_LAST_CONTACT = 'LastContact'; - private const FIELD_STABLE_SINCE = 'StableSince'; - - public string $ID = ''; - public string $Name = ''; - public string $Address = ''; - public string $SerfStatus = ''; - public string $Version = ''; - public bool $Leader = false; - public ?ReadableDuration $LastContact = null; - public int $LastTerm = 0; - public int $LastIndex = 0; - public bool $Healthy = false; - public bool $Voter = false; + public string $ID; + public string $Name; + public string $Address; + public string $SerfStatus; + public string $Version; + public bool $Leader; + public null|Time\Duration $LastContact; + public int $LastTerm; + public int $LastIndex; + public bool $Healthy; + public bool $Voter; public Time\Time $StableSince; - public function __construct(?array $data = []) - { - parent::__construct($data); - if (!isset($this->StableSince)) { - $this->StableSince = Time::New(); - } + public function __construct( + string $ID = '', + string $Name = '', + string $Address = '', + string $SerfStatus = '', + string $Version = '', + bool $Leader = false, + null|string|int|float|\DateInterval|Time\Duration $LastContact = null, + int $LastTerm = 0, + int $LastIndex = 0, + bool $Healthy = false, + bool $Voter = false, + null|Time\Time $StableSince = null, + ) { + $this->ID = $ID; + $this->Name = $Name; + $this->Address = $Address; + $this->SerfStatus = $SerfStatus; + $this->Version = $Version; + $this->Leader = $Leader; + $this->setLastContact($LastContact); + $this->LastTerm = $LastTerm; + $this->LastIndex = $LastIndex; + $this->Healthy = $Healthy; + $this->Voter = $Voter; + $this->StableSince = $StableSince ?? Time::New(); } public function getID(): string @@ -126,14 +133,18 @@ public function setLeader(bool $Leader): self return $this; } - public function getLastContact(): ?ReadableDuration + public function getLastContact(): null|Time\Duration { return $this->LastContact; } - public function setLastContact(?ReadableDuration $LastContact): self + public function setLastContact(null|string|int|float|\DateInterval|Time\Duration $LastContact): self { - $this->LastContact = $LastContact; + if (null === $LastContact) { + $this->LastContact = null; + return $this; + } + $this->LastContact = Time::Duration($LastContact); return $this; } @@ -191,4 +202,39 @@ public function setStableSince(Time\Time $StableSince): self $this->StableSince = $StableSince; return $this; } + + public static function jsonUnserialize(\stdClass $decoded): self + { + $n = new self(); + foreach ((array)$decoded as $k => $v) { + if ('LastContact' === $k) { + $n->setLastContact($v); + } elseif ('StableSince' === $k) { + $n->StableSince = parse_time($v); + } else { + $n->{$k} = $v; + } + } + return $n; + } + + public function jsonSerialize(): \stdClass + { + $out = $this->_startJsonSerialize(); + $out->ID = $this->ID; + $out->Name = $this->Name; + $out->Address = $this->Address; + $out->SerfStatus = $this->SerfStatus; + $out->Version = $this->Version; + $out->Leader = $this->Leader; + if (null !== $this->LastContact) { + $out->LastContact = (string)$this->LastContact; + } + $out->LastTerm = $this->LastTerm; + $out->LastIndex = $this->LastIndex; + $out->Healthy = $this->Healthy; + $out->Voter = $this->Voter; + $out->StableSince = $this->StableSince; + return $out; + } } diff --git a/src/AbstractClient.php b/src/PHPLib/AbstractClient.php similarity index 72% rename from src/AbstractClient.php rename to src/PHPLib/AbstractClient.php index 0a9b322e..a86a6054 100644 --- a/src/AbstractClient.php +++ b/src/PHPLib/AbstractClient.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace DCarbone\PHPConsulAPI; +namespace DCarbone\PHPConsulAPI\PHPLib; /* Copyright 2016-2025 Daniel Carbone (daniel.p.carbone@gmail.com) @@ -22,6 +22,9 @@ use DCarbone\Go\HTTP; use DCarbone\Go\Time; +use DCarbone\PHPConsulAPI\Config; +use DCarbone\PHPConsulAPI\QueryOptions; +use DCarbone\PHPConsulAPI\WriteOptions; use GuzzleHttp\ClientInterface; use GuzzleHttp\RequestOptions as GuzzleRequestOptions; use Psr\Http\Message\ResponseInterface; @@ -41,6 +44,10 @@ public function getConfig(): Config return $this->_config; } + /** + * @param \DCarbone\PHPConsulAPI\PHPLib\Request $r + * @return array + */ protected function _buildGuzzleRequestOptions(Request $r): array { // todo: figure out better guzzle integration @@ -58,14 +65,14 @@ protected function _buildGuzzleRequestOptions(Request $r): array $opts[GuzzleRequestOptions::SSL_KEY] = $this->_config->KeyFile; } - if (null !== $r->timeout && 0 < ($ttl = \intval($r->timeout->Seconds(), 10))) { + if (null !== $r->timeout && 0 < ($ttl = intval($r->timeout->Seconds(), 10))) { $opts[GuzzleRequestOptions::TIMEOUT] = $ttl; } // todo: per-request content and accept value setting. $body = $r->getBody(); if (null !== $body) { - if (\is_scalar($body)) { + if (is_scalar($body)) { $opts[GuzzleRequestOptions::BODY] = $body; } else { $opts[GuzzleRequestOptions::JSON] = $body; @@ -75,33 +82,38 @@ protected function _buildGuzzleRequestOptions(Request $r): array return $opts; } - protected function _newRequest(string $method, string $path, mixed $body, ?RequestOptions $opts): Request + protected function _newRequest(string $method, string $path, mixed $body, null|RequestOptions $opts): Request { $r = new Request($method, $path, $this->_config, $body); $r->applyOptions($opts); return $r; } - protected function _newPostRequest(string $path, mixed $body, ?RequestOptions $opts): Request + protected function _newPostRequest(string $path, mixed $body, null|RequestOptions $opts): Request { return $this->_newRequest(HTTP\MethodPost, $path, $body, $opts); } - protected function _newPutRequest(string $path, mixed $body, ?RequestOptions $opts): Request + protected function _newPutRequest(string $path, mixed $body, null|RequestOptions $opts): Request { return $this->_newRequest(HTTP\MethodPut, $path, $body, $opts); } - protected function _newGetRequest(string $path, ?QueryOptions $opts): Request + protected function _newGetRequest(string $path, null|QueryOptions $opts): Request { return $this->_newRequest(HTTP\MethodGet, $path, null, $opts); } - protected function _newDeleteRequest(string $path, ?WriteOptions $opts): Request + protected function _newDeleteRequest(string $path, null|WriteOptions $opts): Request { return $this->_newRequest(HTTP\MethodDelete, $path, null, $opts); } + /** + * @param \DCarbone\PHPConsulAPI\PHPLib\Request $r + * @return \DCarbone\PHPConsulAPI\PHPLib\RequestResponse + * @throws \GuzzleHttp\Exception\GuzzleException + */ protected function _do(Request $r): RequestResponse { $start = microtime(true); @@ -110,7 +122,7 @@ protected function _do(Request $r): RequestResponse try { // If we actually have a client defined... - if (isset($this->_config->HttpClient) && $this->_config->HttpClient instanceof ClientInterface) { + if (isset($this->_config->HttpClient)) { $response = $this->_config->HttpClient->send( $r->toPsrRequest(), $this->_buildGuzzleRequestOptions($r) @@ -132,7 +144,7 @@ protected function _do(Request $r): RequestResponse } // calculate execution time - $dur = new Time\Duration(\intval((microtime(true) - $start) * Time::Second, 10)); + $dur = new Time\Duration(intval((microtime(true) - $start) * Time::Second, 10)); return new RequestResponse($r->meta(), $dur, $response, $err); } @@ -149,25 +161,13 @@ protected function _requireStatus(RequestResponse $r, int ...$allowed): RequestR return $r; } - // if, for whatever reason, we see an unexpected response structure... - if (!($r->Response instanceof ResponseInterface)) { - $r->Err = new Error( - sprintf( - '%s - Expected response to be instance of \\Psr\\Message\\ResponseInterface, %s seen.', - static::class, - \is_object($r->Response) ? \get_class($r->Response) : \gettype($r->Response) - ) - ); - return $r; - } - // once here, assume operable response instance // Get the response code... $actualCode = $r->Response->getStatusCode(); // If response code is in allowed list, move right along - if (\in_array($actualCode, $allowed, true)) { + if (in_array($actualCode, $allowed, true)) { return $r; } @@ -195,31 +195,37 @@ protected function _requireNotFoundOrOK(RequestResponse $r): RequestResponse return $this->_requireStatus($r, HTTP\StatusOK, HTTP\StatusNotFound); } - protected function _doGet(string $path, ?QueryOptions $opts): RequestResponse + protected function _doGet(string $path, null|QueryOptions $opts): RequestResponse { return $this->_do($this->_newGetRequest($path, $opts)); } - protected function _doPost(string $path, mixed $body, ?RequestOptions $opts): RequestResponse + protected function _doPost(string $path, mixed $body, null|RequestOptions $opts): RequestResponse { return $this->_do($this->_newPostRequest($path, $body, $opts)); } - protected function _doPut(string $path, mixed $body, ?RequestOptions $opts): RequestResponse + protected function _doPut(string $path, mixed $body, null|RequestOptions $opts): RequestResponse { return $this->_do($this->_newPutRequest($path, $body, $opts)); } - protected function _doDelete(string $path, ?WriteOptions $opts): RequestResponse + protected function _doDelete(string $path, null|WriteOptions $opts): RequestResponse { return $this->_do($this->_newDeleteRequest($path, $opts)); } protected function _decodeBody(StreamInterface $body): DecodedBody { - $data = @json_decode((string)$body, true); + $data = @json_decode( + json: (string)$body, + associative: false, + depth: $this->_config->JSONDecodeMaxDepth, + flags: $this->_config->JSONDecodeOpts, + ); - if (\JSON_ERROR_NONE === json_last_error()) { + $jsonErr = json_last_error(); + if (\JSON_ERROR_NONE === $jsonErr) { return new DecodedBody($data, null); } @@ -227,15 +233,16 @@ protected function _decodeBody(StreamInterface $body): DecodedBody null, new Error( sprintf( - '%s - Unable to parse response as JSON. Message: %s', + '%s - Unable to parse response as JSON: (%d) %s', static::class, + $jsonErr, json_last_error_msg() ) ) ); } - protected function _executePut(string $path, mixed $body, ?WriteOptions $opts): WriteResponse + protected function _executePut(string $path, mixed $body, null|WriteOptions $opts): WriteResponse { $resp = $this->_requireOK($this->_doPut($path, $body, $opts)); $ret = new WriteResponse(); @@ -243,7 +250,7 @@ protected function _executePut(string $path, mixed $body, ?WriteOptions $opts): return $ret; } - protected function _executePost(string $path, mixed $body, ?WriteOptions $opts): WriteResponse + protected function _executePost(string $path, mixed $body, null|WriteOptions $opts): WriteResponse { $resp = $this->_requireOK($this->_doPost($path, $body, $opts)); $ret = new WriteResponse(); @@ -251,7 +258,7 @@ protected function _executePost(string $path, mixed $body, ?WriteOptions $opts): return $ret; } - protected function _executeDelete(string $path, ?WriteOptions $opts): WriteResponse + protected function _executeDelete(string $path, null|WriteOptions $opts): WriteResponse { $resp = $this->_requireOK($this->_doDelete($path, $opts)); $ret = new WriteResponse(); @@ -259,7 +266,7 @@ protected function _executeDelete(string $path, ?WriteOptions $opts): WriteRespo return $ret; } - protected function _executePutValuedStr(string $path, mixed $body, ?WriteOptions $opts): ValuedWriteStringResponse + protected function _executePutValuedStr(string $path, mixed $body, null|WriteOptions $opts): ValuedWriteStringResponse { $r = $this->_newPutRequest($path, $body, $opts); $resp = $this->_requireOK($this->_do($r)); @@ -268,7 +275,7 @@ protected function _executePutValuedStr(string $path, mixed $body, ?WriteOptions return $ret; } - protected function _executeGetValuedStr(string $path, ?QueryOptions $opts): ValuedQueryStringResponse + protected function _executeGetValuedStr(string $path, null|QueryOptions $opts): ValuedQueryStringResponse { $r = $this->_newGetRequest($path, $opts); $resp = $this->_requireOK($this->_do($r)); @@ -277,7 +284,7 @@ protected function _executeGetValuedStr(string $path, ?QueryOptions $opts): Valu return $ret; } - protected function _executeGetValuedStrs(string $path, ?QueryOptions $opts): ValuedQueryStringsResponse + protected function _executeGetValuedStrs(string $path, null|QueryOptions $opts): ValuedQueryStringsResponse { $r = $this->_newGetRequest($path, $opts); $resp = $this->_requireOK($this->_do($r)); @@ -289,28 +296,22 @@ protected function _executeGetValuedStrs(string $path, ?QueryOptions $opts): Val /** * todo: move into Unmarshaller? * - * @param \DCarbone\PHPConsulAPI\RequestResponse $resp - * @param \DCarbone\PHPConsulAPI\AbstractResponse $ret + * @param \DCarbone\PHPConsulAPI\PHPLib\RequestResponse $resp + * @param \DCarbone\PHPConsulAPI\PHPLib\AbstractResponse $ret * @throws \Exception */ protected function _unmarshalResponse(RequestResponse $resp, AbstractResponse $ret): void { // determine if this response contains a *Meta field - // TODO: change to use interfaces + instanceof? - if (property_exists($ret, Transcoding::FIELD_QUERY_META)) { - $ret->QueryMeta = $resp->buildQueryMeta(); - } elseif (property_exists($ret, Transcoding::FIELD_WRITE_META)) { - $ret->WriteMeta = $resp->buildWriteMeta(); + if ($ret instanceof QueryResponseInterface) { + $ret->setQueryMeta($resp->buildQueryMeta()); + } elseif ($ret instanceof WriteResponseInterface) { + $ret->setWriteMeta($resp->buildWriteMeta()); } - // todo: can probably assume that all responses have an Err field... - $hasErrField = property_exists($ret, Transcoding::FIELD_ERR); - // if there was an error in the response, set and return if (null !== $resp->Err) { - if ($hasErrField) { - $ret->Err = $resp->Err; - } + $ret->setErr($resp->Err); return; } @@ -322,9 +323,7 @@ protected function _unmarshalResponse(RequestResponse $resp, AbstractResponse $r // attempt response decode $dec = $this->_decodeBody($resp->Response->getBody()); if (null !== $dec->Err) { - if ($hasErrField) { - $ret->Err = $dec->Err; - } + $ret->setErr($dec->Err); return; } diff --git a/src/AbstractResponse.php b/src/PHPLib/AbstractResponse.php similarity index 90% rename from src/AbstractResponse.php rename to src/PHPLib/AbstractResponse.php index 914bacd4..8af90a16 100644 --- a/src/AbstractResponse.php +++ b/src/PHPLib/AbstractResponse.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace DCarbone\PHPConsulAPI; +namespace DCarbone\PHPConsulAPI\PHPLib; /* Copyright 2016-2025 Daniel Carbone (daniel.p.carbone@gmail.com) @@ -20,8 +20,14 @@ limitations under the License. */ +/** + * @template TValue + * @implements \ArrayAccess + */ abstract class AbstractResponse implements \ArrayAccess { + use ErrorField; + public function offsetUnset(mixed $offset): void { throw new \BadMethodCallException(sprintf('Calling %s on class %s is forbidden', __METHOD__, static::class)); diff --git a/src/PHPLib/AbstractType.php b/src/PHPLib/AbstractType.php new file mode 100644 index 00000000..5104863a --- /dev/null +++ b/src/PHPLib/AbstractType.php @@ -0,0 +1,67 @@ + */ + private array $_dyn = []; + + public function __set(string $field, mixed $value): void + { + $this->_dyn[$field] = $value; + } + + public function &__get(string $field): mixed + { + if (!array_key_exists($field, $this->_dyn)) { + $this->_dyn[$field] = null; + } + return $this->_dyn[$field]; + } + + public function __unset(string $field): void + { + unset($this->_dyn[$field]); + } + + /** + * @return array + */ + public function _getDynamicFields(): array + { + return $this->_dyn; + } + + public function __toString(): string + { + return static::class; + } + + protected function _startJsonSerialize(): \stdClass + { + $out = new \stdClass(); + foreach ($this->_getDynamicFields() as $k => $v) { + $out->{$k} = $v; + } + return $out; + } +} diff --git a/src/AbstractValuedQueryResponse.php b/src/PHPLib/AbstractValuedQueryResponse.php similarity index 74% rename from src/AbstractValuedQueryResponse.php rename to src/PHPLib/AbstractValuedQueryResponse.php index c56bec8a..e3a142b9 100644 --- a/src/AbstractValuedQueryResponse.php +++ b/src/PHPLib/AbstractValuedQueryResponse.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace DCarbone\PHPConsulAPI; +namespace DCarbone\PHPConsulAPI\PHPLib; /* Copyright 2016-2025 Daniel Carbone (daniel.p.carbone@gmail.com) @@ -20,14 +20,18 @@ limitations under the License. */ -abstract class AbstractValuedQueryResponse extends AbstractResponse implements ValuedResponseInterface +use DCarbone\PHPConsulAPI\QueryMeta; + +/** + * @extends AbstractResponse + */ +abstract class AbstractValuedQueryResponse extends AbstractResponse implements QueryResponseInterface, ValuedResponseInterface { - use QueryMetaContainer; - use ErrorContainer; + use QueryMetaField; public function offsetExists(mixed $offset): bool { - return \is_int($offset) && 0 <= $offset && $offset < 3; + return is_int($offset) && 0 <= $offset && $offset < 3; } public function offsetGet(mixed $offset): mixed @@ -43,4 +47,9 @@ public function offsetGet(mixed $offset): mixed } throw $this->_newOutOfRangeException($offset); } + + public function setQueryMeta(?QueryMeta $QueryMeta): void + { + $this->QueryMeta = $QueryMeta; + } } diff --git a/src/AbstractValuedResponse.php b/src/PHPLib/AbstractValuedResponse.php similarity index 88% rename from src/AbstractValuedResponse.php rename to src/PHPLib/AbstractValuedResponse.php index 0d602a4b..bc7b7f3a 100644 --- a/src/AbstractValuedResponse.php +++ b/src/PHPLib/AbstractValuedResponse.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace DCarbone\PHPConsulAPI; +namespace DCarbone\PHPConsulAPI\PHPLib; /* Copyright 2016-2025 Daniel Carbone (daniel.p.carbone@gmail.com) @@ -20,13 +20,15 @@ limitations under the License. */ +/** + * @extends AbstractResponse + */ abstract class AbstractValuedResponse extends AbstractResponse implements ValuedResponseInterface { - use ErrorContainer; public function offsetExists(mixed $offset): bool { - return \is_int($offset) && 0 <= $offset && $offset < 2; + return is_int($offset) && 0 <= $offset && $offset < 2; } public function offsetGet(mixed $offset): mixed diff --git a/src/AbstractValuedWriteResponse.php b/src/PHPLib/AbstractValuedWriteResponse.php similarity index 82% rename from src/AbstractValuedWriteResponse.php rename to src/PHPLib/AbstractValuedWriteResponse.php index 03e5a13e..8a3b1ffe 100644 --- a/src/AbstractValuedWriteResponse.php +++ b/src/PHPLib/AbstractValuedWriteResponse.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace DCarbone\PHPConsulAPI; +namespace DCarbone\PHPConsulAPI\PHPLib; /* Copyright 2016-2025 Daniel Carbone (daniel.p.carbone@gmail.com) @@ -20,14 +20,16 @@ limitations under the License. */ -abstract class AbstractValuedWriteResponse extends AbstractResponse implements ValuedResponseInterface +/** + * @extends AbstractResponse + */ +abstract class AbstractValuedWriteResponse extends AbstractResponse implements ValuedResponseInterface, WriteResponseInterface { - use WriteMetaContainer; - use ErrorContainer; + use WriteMetaField; public function offsetExists(mixed $offset): bool { - return \is_int($offset) && 0 <= $offset && $offset < 3; + return is_int($offset) && 0 <= $offset && $offset < 3; } public function offsetGet(mixed $offset): mixed diff --git a/src/ResponseValueBoolTrait.php b/src/PHPLib/BoolValueField.php similarity index 67% rename from src/ResponseValueBoolTrait.php rename to src/PHPLib/BoolValueField.php index e4a7c401..8ef30544 100644 --- a/src/ResponseValueBoolTrait.php +++ b/src/PHPLib/BoolValueField.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace DCarbone\PHPConsulAPI; +namespace DCarbone\PHPConsulAPI\PHPLib; /* Copyright 2016-2025 Daniel Carbone (daniel.p.carbone@gmail.com) @@ -20,7 +20,7 @@ limitations under the License. */ -trait ResponseValueBoolTrait +trait BoolValueField { public bool $Value = false; @@ -29,21 +29,21 @@ public function getValue(): bool return $this->Value; } - public function unmarshalValue(mixed $decodedData): void + public function unmarshalValue(mixed $decoded): void { - if (\is_bool($decodedData)) { - $this->Value = $decodedData; + if (is_bool($decoded)) { + $this->Value = $decoded; return; } - if (\is_string($decodedData)) { - $this->Value = Transcoding::TRUE === strtolower(trim($decodedData)); + if (is_string($decoded)) { + $this->Value = 'true' === strtolower(trim($decoded)); return; } - $this->Value = (bool)$decodedData; + $this->Value = (bool)$decoded; } public function __toString(): string { - return $this->Value ? Transcoding::TRUE : Transcoding::FALSE; + return $this->Value ? 'true' : 'false'; } } diff --git a/src/DecodedBody.php b/src/PHPLib/DecodedBody.php similarity index 87% rename from src/DecodedBody.php rename to src/PHPLib/DecodedBody.php index da120b52..2b8f59e1 100644 --- a/src/DecodedBody.php +++ b/src/PHPLib/DecodedBody.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace DCarbone\PHPConsulAPI; +namespace DCarbone\PHPConsulAPI\PHPLib; /* Copyright 2016-2025 Daniel Carbone (daniel.p.carbone@gmail.com) @@ -22,11 +22,11 @@ final class DecodedBody { - use ErrorContainer; + use ErrorField; public mixed $Decoded = null; - public function __construct(mixed $decoded, ?Error $err) + public function __construct(mixed $decoded, null|Error $err) { $this->Decoded = $decoded; $this->Err = $err; diff --git a/src/Error.php b/src/PHPLib/Error.php similarity index 77% rename from src/Error.php rename to src/PHPLib/Error.php index ce2cd9d8..3d0ae73c 100644 --- a/src/Error.php +++ b/src/PHPLib/Error.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace DCarbone\PHPConsulAPI; +namespace DCarbone\PHPConsulAPI\PHPLib; /* Copyright 2016-2025 Daniel Carbone (daniel.p.carbone@gmail.com) @@ -22,35 +22,26 @@ use DCarbone\Go\Time; -/** - * TODO: Make this better... - * - * Class Error - */ class Error implements \JsonSerializable { - private const FIELD_MESSAGE = 'message'; - private const FIELD_TIMESTAMP = 'timestamp'; - private Time\Time $time; private string $message; public function __construct(string $message) { - $this->time = Time::Now(); + $this->time = Time::Now(); $this->message = $message; } public static function unexpectedResponseCodeError(RequestResponse $resp): self { - return new static( + return new self( sprintf( 'unexpected response code: %d (%s)', $resp->Response->getStatusCode(), $resp->Response->getBody()->getContents(), ) - ); } @@ -64,12 +55,12 @@ public function getMessage(): string return $this->message; } - public function jsonSerialize(): array + public function jsonSerialize(): \stdClass { - return [ - self::FIELD_MESSAGE => $this->message, - self::FIELD_TIMESTAMP => $this->time, - ]; + $out = new \stdClass(); + $out->message = $this->message; + $out->timestamp = $this->time; + return $out; } public function __toString(): string diff --git a/src/PHPLib/ErrorField.php b/src/PHPLib/ErrorField.php new file mode 100644 index 00000000..0a4e9f7b --- /dev/null +++ b/src/PHPLib/ErrorField.php @@ -0,0 +1,36 @@ +Err; + } + + public function setErr(null|Error $Err): void + { + $this->Err = $Err; + } +} diff --git a/src/PHPLib/MapResponse.php b/src/PHPLib/MapResponse.php new file mode 100644 index 00000000..3493339b --- /dev/null +++ b/src/PHPLib/MapResponse.php @@ -0,0 +1,52 @@ +|null + */ + public null|array $Map = null; + + /** + * @return array|null + */ + public function getValue(): null|array + { + return $this->Map; + } + + public function unmarshalValue(mixed $decoded): void + { + if (null === $decoded) { + $this->Map = null; + return; + } + $this->Map = []; + foreach ($decoded as $k => $v) { + $this->Map[$k] = $v; + } + } +} diff --git a/src/PHPLib/MetaField.php b/src/PHPLib/MetaField.php new file mode 100644 index 00000000..f5b018ab --- /dev/null +++ b/src/PHPLib/MetaField.php @@ -0,0 +1,59 @@ + */ + public null|array $Meta = null; + + /** + * @return array|null + */ + public function getMeta(): null|array + { + return $this->Meta; + } + + public function setMetaKey(string $k, string $v): self + { + if (null === $this->Meta) { + $this->Meta = []; + } + $this->Meta[$k] = $v; + return $this; + } + + /** + * @param null|\stdClass|array $Meta + */ + public function setMeta(null|\stdClass|array $Meta): self + { + $this->Meta = null; + if (null === $Meta) { + return $this; + } + foreach ((array)$Meta as $k => $v) { + $this->setMetaKey($k, $v); + } + return $this; + } +} diff --git a/src/PHPLib/NodeMetaField.php b/src/PHPLib/NodeMetaField.php new file mode 100644 index 00000000..918eed1f --- /dev/null +++ b/src/PHPLib/NodeMetaField.php @@ -0,0 +1,59 @@ + */ + public null|array $NodeMeta = null; + + /** + * @return null|array + */ + public function getNodeMeta(): null|array + { + return $this->NodeMeta; + } + + public function setNodeMetaKey(string $k, string $v): self + { + if (null === $this->NodeMeta) { + $this->NodeMeta = []; + } + $this->NodeMeta[$k] = $v; + return $this; + } + + /** + * @param \stdClass|array|null $NodeMeta + */ + public function setNodeMeta(null|\stdClass|array $NodeMeta): self + { + $this->NodeMeta = null; + if (null === $NodeMeta) { + return $this; + } + foreach ($NodeMeta as $k => $v) { + $this->setNodeMetaKey($k, $v); + } + return $this; + } +} diff --git a/src/Params.php b/src/PHPLib/Params.php similarity index 95% rename from src/Params.php rename to src/PHPLib/Params.php index 35f02f06..33721087 100644 --- a/src/Params.php +++ b/src/PHPLib/Params.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace DCarbone\PHPConsulAPI; +namespace DCarbone\PHPConsulAPI\PHPLib; /* Copyright 2016-2025 Daniel Carbone (daniel.p.carbone@gmail.com) diff --git a/src/QueryMetaContainer.php b/src/PHPLib/QueryMetaField.php similarity index 78% rename from src/QueryMetaContainer.php rename to src/PHPLib/QueryMetaField.php index 57bcc958..a561c05a 100644 --- a/src/QueryMetaContainer.php +++ b/src/PHPLib/QueryMetaField.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace DCarbone\PHPConsulAPI; +namespace DCarbone\PHPConsulAPI\PHPLib; /* Copyright 2016-2025 Daniel Carbone (daniel.p.carbone@gmail.com) @@ -20,11 +20,13 @@ limitations under the License. */ -trait QueryMetaContainer +use DCarbone\PHPConsulAPI\QueryMeta; + +trait QueryMetaField { - public ?QueryMeta $QueryMeta = null; + public null|QueryMeta $QueryMeta = null; - public function getQueryMeta(): ?QueryMeta + public function getQueryMeta(): null|QueryMeta { return $this->QueryMeta; } diff --git a/src/PHPLib/QueryResponseInterface.php b/src/PHPLib/QueryResponseInterface.php new file mode 100644 index 00000000..cf276104 --- /dev/null +++ b/src/PHPLib/QueryResponseInterface.php @@ -0,0 +1,30 @@ +body; } - public function applyOptions(?RequestOptions $opts): void + public function applyOptions(null|RequestOptions $opts): void { if (null === $opts) { return; @@ -112,7 +114,7 @@ public function filterQuery(string $filter): void public function getUri(): UriInterface { $uri = "{$this->scheme}://{$this->address}/{$this->path}"; - if (0 < \count($this->params)) { + if (0 < count($this->params)) { $uri .= "?{$this->params}"; } return new Uri($uri); diff --git a/src/RequestOptions.php b/src/PHPLib/RequestOptions.php similarity index 94% rename from src/RequestOptions.php rename to src/PHPLib/RequestOptions.php index 7df99f2a..05ddc2eb 100644 --- a/src/RequestOptions.php +++ b/src/PHPLib/RequestOptions.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace DCarbone\PHPConsulAPI; +namespace DCarbone\PHPConsulAPI\PHPLib; /* Copyright 2016-2025 Daniel Carbone (daniel.p.carbone@gmail.com) diff --git a/src/RequestResponse.php b/src/PHPLib/RequestResponse.php similarity index 74% rename from src/RequestResponse.php rename to src/PHPLib/RequestResponse.php index 00b3a2e3..8fb8d7cd 100644 --- a/src/RequestResponse.php +++ b/src/PHPLib/RequestResponse.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace DCarbone\PHPConsulAPI; +namespace DCarbone\PHPConsulAPI\PHPLib; /* Copyright 2016-2025 Daniel Carbone (daniel.p.carbone@gmail.com) @@ -21,19 +21,23 @@ */ use DCarbone\Go\Time; +use DCarbone\PHPConsulAPI\Consul; +use DCarbone\PHPConsulAPI\QueryMeta; +use DCarbone\PHPConsulAPI\RequestMeta; +use DCarbone\PHPConsulAPI\WriteMeta; use Psr\Http\Message\ResponseInterface; final class RequestResponse { public RequestMeta $RequestMeta; public Time\Duration $Duration; - public ?ResponseInterface $Response; - public ?Error $Err; + public null|ResponseInterface $Response = null; + public null|Error $Err; - public function __construct(RequestMeta $meta, Time\Duration $dur, ?ResponseInterface $resp, ?Error $err) + public function __construct(RequestMeta $meta, null|string|int|float|\DateInterval|Time\Duration $dur, null|ResponseInterface $resp, null|Error $err) { $this->RequestMeta = $meta; - $this->Duration = $dur; + $this->Duration = Time::Duration($dur); $this->Response = $resp; $this->Err = $err; } @@ -48,28 +52,27 @@ public function getDuration(): Time\Duration return $this->Duration; } - public function getResponse(): ?ResponseInterface + public function getResponse(): null|ResponseInterface { return $this->Response; } - public function getErr(): ?Error + public function getErr(): null|Error { return $this->Err; } public function buildQueryMeta(): QueryMeta { - // init class - $qm = new QueryMeta(); - // set some always-defined values - $qm->RequestTime = $this->Duration; - $qm->RequestUrl = (string)$this->RequestMeta->uri; + $qm = new QueryMeta( + RequestUrl: (string)$this->RequestMeta->uri, + RequestTime: $this->Duration, + ); // if there was no response, return as-is // note: should never see this in the wild. - if (!isset($this->Response)) { + if (null === $this->Response) { return $qm; } @@ -95,7 +98,7 @@ public function buildQueryMeta(): QueryMeta } if ('' !== ($h = $this->Response->getHeaderLine(Consul::_headerCache))) { - $qm->CacheAge = Time::Duration(\intval($h, 10) * Time::Second); + $qm->CacheAge = Time::Duration((int)$h * Time::Second); } return $qm; @@ -103,8 +106,6 @@ public function buildQueryMeta(): QueryMeta public function buildWriteMeta(): WriteMeta { - $wm = new WriteMeta(); - $wm->RequestTime = $this->Duration; - return $wm; + return new WriteMeta($this->Duration); } } diff --git a/src/PHPLib/ServiceMetaField.php b/src/PHPLib/ServiceMetaField.php new file mode 100644 index 00000000..46d22d08 --- /dev/null +++ b/src/PHPLib/ServiceMetaField.php @@ -0,0 +1,59 @@ + */ + public null|array $ServiceMeta = null; + + /** + * @return null|array + */ + public function getServiceMeta(): null|array + { + return $this->ServiceMeta; + } + + public function setServiceMetaValue(string $k, string $v): self + { + if (null === $this->ServiceMeta) { + $this->ServiceMeta = []; + } + $this->ServiceMeta[$k] = $v; + return $this; + } + + /** + * @param \stdClass|array|null $ServiceMeta + */ + public function setServiceMeta(null|\stdClass|array $ServiceMeta): self + { + $this->ServiceMeta = null; + if (null === $ServiceMeta) { + return $this; + } + foreach ($ServiceMeta as $k => $v) { + $this->setServiceMetaValue($k, $v); + } + return $this; + } +} diff --git a/src/PHPLib/SimpleJsonUnserializeTrait.php b/src/PHPLib/SimpleJsonUnserializeTrait.php new file mode 100644 index 00000000..bd320335 --- /dev/null +++ b/src/PHPLib/SimpleJsonUnserializeTrait.php @@ -0,0 +1,33 @@ + $v) { + $n->{$k} = $v; + } + return $n; + } +} \ No newline at end of file diff --git a/src/ResponseValueStringTrait.php b/src/PHPLib/StringValueField.php similarity index 83% rename from src/ResponseValueStringTrait.php rename to src/PHPLib/StringValueField.php index 804c3f74..909efdb6 100644 --- a/src/ResponseValueStringTrait.php +++ b/src/PHPLib/StringValueField.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace DCarbone\PHPConsulAPI; +namespace DCarbone\PHPConsulAPI\PHPLib; /* Copyright 2016-2025 Daniel Carbone (daniel.p.carbone@gmail.com) @@ -20,7 +20,7 @@ limitations under the License. */ -trait ResponseValueStringTrait +trait StringValueField { public string $Value = ''; @@ -29,9 +29,9 @@ public function getValue(): string return $this->Value; } - public function unmarshalValue(mixed $decodedData): void + public function unmarshalValue(mixed $decoded): void { - $this->Value = (string)$decodedData; + $this->Value = (string)$decoded; } public function __toString(): string diff --git a/src/ResponseValueStringsTrait.php b/src/PHPLib/StringsValueField.php similarity index 72% rename from src/ResponseValueStringsTrait.php rename to src/PHPLib/StringsValueField.php index 83e78a96..84e67d05 100644 --- a/src/ResponseValueStringsTrait.php +++ b/src/PHPLib/StringsValueField.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace DCarbone\PHPConsulAPI; +namespace DCarbone\PHPConsulAPI\PHPLib; /* Copyright 2016-2025 Daniel Carbone (daniel.p.carbone@gmail.com) @@ -20,17 +20,21 @@ limitations under the License. */ -trait ResponseValueStringsTrait +trait StringsValueField { + /** @var array */ public array $Value = []; - public function getValue(): ?array + /** + * @return null|array + */ + public function getValue(): null|array { return $this->Value; } - public function unmarshalValue(mixed $decodedData): void + public function unmarshalValue(mixed $decoded): void { - $this->Value = (array)$decodedData; + $this->Value = (array)$decoded; } } diff --git a/src/PHPLib/TaggedAddressField.php b/src/PHPLib/TaggedAddressField.php new file mode 100644 index 00000000..e51166dd --- /dev/null +++ b/src/PHPLib/TaggedAddressField.php @@ -0,0 +1,59 @@ + */ + public null|array $TaggedAddresses = null; + + /** + * @return null|array + */ + public function getTaggedAddresses(): null|array + { + return $this->TaggedAddresses; + } + + public function setTaggedAddress(string $k, string $v): self + { + if (null === $this->TaggedAddresses) { + $this->TaggedAddresses = []; + } + $this->TaggedAddresses[$k] = $v; + return $this; + } + + /** + * @param \stdClass|array|null $TaggedAddresses + */ + public function setTaggedAddresses(null|\stdClass|array $TaggedAddresses): self + { + $this->TaggedAddresses = null; + if (null === $TaggedAddresses) { + return $this; + } + foreach ($TaggedAddresses as $k => $v) { + $this->setTaggedAddress($k, $v); + } + return $this; + } +} diff --git a/src/UnmarshalledResponseInterface.php b/src/PHPLib/UnmarshalledResponseInterface.php similarity index 87% rename from src/UnmarshalledResponseInterface.php rename to src/PHPLib/UnmarshalledResponseInterface.php index 4c1e616d..972ecebd 100644 --- a/src/UnmarshalledResponseInterface.php +++ b/src/PHPLib/UnmarshalledResponseInterface.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace DCarbone\PHPConsulAPI; +namespace DCarbone\PHPConsulAPI\PHPLib; /* Copyright 2016-2025 Daniel Carbone (daniel.p.carbone@gmail.com) @@ -22,5 +22,5 @@ interface UnmarshalledResponseInterface { - public function unmarshalValue(mixed $decodedData): void; + public function unmarshalValue(mixed $decoded): void; } diff --git a/src/ValuedBoolResponse.php b/src/PHPLib/ValuedBoolResponse.php similarity index 92% rename from src/ValuedBoolResponse.php rename to src/PHPLib/ValuedBoolResponse.php index a0db756d..deea43be 100644 --- a/src/ValuedBoolResponse.php +++ b/src/PHPLib/ValuedBoolResponse.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace DCarbone\PHPConsulAPI; +namespace DCarbone\PHPConsulAPI\PHPLib; /* Copyright 2016-2025 Daniel Carbone (daniel.p.carbone@gmail.com) @@ -22,5 +22,5 @@ class ValuedBoolResponse extends AbstractValuedResponse implements UnmarshalledResponseInterface { - use ResponseValueBoolTrait; + use BoolValueField; } diff --git a/src/ValuedQueryBoolResponse.php b/src/PHPLib/ValuedQueryBoolResponse.php similarity index 92% rename from src/ValuedQueryBoolResponse.php rename to src/PHPLib/ValuedQueryBoolResponse.php index 52efc008..35f0a9e4 100644 --- a/src/ValuedQueryBoolResponse.php +++ b/src/PHPLib/ValuedQueryBoolResponse.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace DCarbone\PHPConsulAPI; +namespace DCarbone\PHPConsulAPI\PHPLib; /* Copyright 2016-2025 Daniel Carbone (daniel.p.carbone@gmail.com) @@ -22,5 +22,5 @@ class ValuedQueryBoolResponse extends AbstractValuedQueryResponse implements UnmarshalledResponseInterface { - use ResponseValueBoolTrait; + use BoolValueField; } diff --git a/src/ValuedQueryStringResponse.php b/src/PHPLib/ValuedQueryStringResponse.php similarity index 92% rename from src/ValuedQueryStringResponse.php rename to src/PHPLib/ValuedQueryStringResponse.php index e8edb1a3..6af85f87 100644 --- a/src/ValuedQueryStringResponse.php +++ b/src/PHPLib/ValuedQueryStringResponse.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace DCarbone\PHPConsulAPI; +namespace DCarbone\PHPConsulAPI\PHPLib; /* Copyright 2016-2025 Daniel Carbone (daniel.p.carbone@gmail.com) @@ -22,5 +22,5 @@ class ValuedQueryStringResponse extends AbstractValuedQueryResponse implements UnmarshalledResponseInterface { - use ResponseValueStringTrait; + use StringValueField; } diff --git a/src/ValuedQueryStringsResponse.php b/src/PHPLib/ValuedQueryStringsResponse.php similarity index 91% rename from src/ValuedQueryStringsResponse.php rename to src/PHPLib/ValuedQueryStringsResponse.php index afa3ccaf..079f9bac 100644 --- a/src/ValuedQueryStringsResponse.php +++ b/src/PHPLib/ValuedQueryStringsResponse.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace DCarbone\PHPConsulAPI; +namespace DCarbone\PHPConsulAPI\PHPLib; /* Copyright 2016-2025 Daniel Carbone (daniel.p.carbone@gmail.com) @@ -22,5 +22,5 @@ class ValuedQueryStringsResponse extends AbstractValuedQueryResponse implements UnmarshalledResponseInterface { - use ResponseValueStringsTrait; + use StringsValueField; } diff --git a/src/ValuedResponseInterface.php b/src/PHPLib/ValuedResponseInterface.php similarity index 94% rename from src/ValuedResponseInterface.php rename to src/PHPLib/ValuedResponseInterface.php index ec14dc77..76d8a7ae 100644 --- a/src/ValuedResponseInterface.php +++ b/src/PHPLib/ValuedResponseInterface.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace DCarbone\PHPConsulAPI; +namespace DCarbone\PHPConsulAPI\PHPLib; /* Copyright 2016-2025 Daniel Carbone (daniel.p.carbone@gmail.com) diff --git a/src/ValuedStringResponse.php b/src/PHPLib/ValuedStringResponse.php similarity index 91% rename from src/ValuedStringResponse.php rename to src/PHPLib/ValuedStringResponse.php index c7a680d8..f6a602eb 100644 --- a/src/ValuedStringResponse.php +++ b/src/PHPLib/ValuedStringResponse.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace DCarbone\PHPConsulAPI; +namespace DCarbone\PHPConsulAPI\PHPLib; /* Copyright 2016-2025 Daniel Carbone (daniel.p.carbone@gmail.com) @@ -22,5 +22,5 @@ class ValuedStringResponse extends AbstractValuedResponse implements UnmarshalledResponseInterface { - use ResponseValueStringTrait; + use StringValueField; } diff --git a/src/ValuedStringsResponse.php b/src/PHPLib/ValuedStringsResponse.php similarity index 91% rename from src/ValuedStringsResponse.php rename to src/PHPLib/ValuedStringsResponse.php index 9baf33d2..b635d304 100644 --- a/src/ValuedStringsResponse.php +++ b/src/PHPLib/ValuedStringsResponse.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace DCarbone\PHPConsulAPI; +namespace DCarbone\PHPConsulAPI\PHPLib; /* Copyright 2016-2025 Daniel Carbone (daniel.p.carbone@gmail.com) @@ -22,5 +22,5 @@ class ValuedStringsResponse extends AbstractValuedResponse implements UnmarshalledResponseInterface { - use ResponseValueStringsTrait; + use StringsValueField; } diff --git a/src/ValuedWriteBoolResponse.php b/src/PHPLib/ValuedWriteBoolResponse.php similarity index 92% rename from src/ValuedWriteBoolResponse.php rename to src/PHPLib/ValuedWriteBoolResponse.php index 0236ca1f..051f9dac 100644 --- a/src/ValuedWriteBoolResponse.php +++ b/src/PHPLib/ValuedWriteBoolResponse.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace DCarbone\PHPConsulAPI; +namespace DCarbone\PHPConsulAPI\PHPLib; /* Copyright 2016-2025 Daniel Carbone (daniel.p.carbone@gmail.com) @@ -22,5 +22,5 @@ class ValuedWriteBoolResponse extends AbstractValuedWriteResponse implements UnmarshalledResponseInterface { - use ResponseValueBoolTrait; + use BoolValueField; } diff --git a/src/ValuedWriteStringResponse.php b/src/PHPLib/ValuedWriteStringResponse.php similarity index 92% rename from src/ValuedWriteStringResponse.php rename to src/PHPLib/ValuedWriteStringResponse.php index d9ec5bbf..3918d8ab 100644 --- a/src/ValuedWriteStringResponse.php +++ b/src/PHPLib/ValuedWriteStringResponse.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace DCarbone\PHPConsulAPI; +namespace DCarbone\PHPConsulAPI\PHPLib; /* Copyright 2016-2025 Daniel Carbone (daniel.p.carbone@gmail.com) @@ -22,5 +22,5 @@ class ValuedWriteStringResponse extends AbstractValuedWriteResponse implements UnmarshalledResponseInterface { - use ResponseValueStringTrait; + use StringValueField; } diff --git a/src/Values.php b/src/PHPLib/Values.php similarity index 59% rename from src/Values.php rename to src/PHPLib/Values.php index e43fdc08..399283cd 100644 --- a/src/Values.php +++ b/src/PHPLib/Values.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace DCarbone\PHPConsulAPI; +namespace DCarbone\PHPConsulAPI\PHPLib; /* Copyright 2016-2025 Daniel Carbone (daniel.p.carbone@gmail.com) @@ -20,10 +20,28 @@ limitations under the License. */ -class Values implements \Iterator, \ArrayAccess, \Countable, \JsonSerializable +/** + * @implements \IteratorAggregate> + * @implements \ArrayAccess> + */ +class Values implements \IteratorAggregate, \ArrayAccess, \Countable, \JsonSerializable { + /** @var array> */ private array $values = []; + /** + * @param array> $values + * @return self + */ + public static function fromArray(array $values): self + { + $out = new self(); + foreach ($values as $hdr => $vals) { + $out->add($hdr, ...(array)$vals); + } + return $out; + } + public function get(string $key): string { if (isset($this->values[$key])) { @@ -33,6 +51,10 @@ public function get(string $key): string return ''; } + /** + * @param string $key + * @return array + */ public function getAll(string $key): array { if (isset($this->values[$key])) { @@ -63,59 +85,61 @@ public function delete(string $key): void public function count(): int { - return \count($this->values); + return count($this->values); } + /** + * @return array> + */ public function toPsr7Array(): array { return $this->values; } - public function current(): array + /** + * @return \Traversable> + */ + public function getIterator(): \Traversable { - return current($this->values); - } - - public function next(): void - { - next($this->values); - } - - public function key(): ?string - { - return key($this->values); - } - - public function valid(): bool - { - return null !== key($this->values); + if ([] === $this->values) { + return new \EmptyIterator(); + } + return new \ArrayIterator($this->values); } - public function rewind(): void - { - reset($this->values); - } public function offsetExists(mixed $offset): bool { - return isset($this->values[$offset]); + return array_key_exists($offset, $this->values); } - public function offsetGet($offset): string + /** + * @param mixed $offset + * @return array + */ + public function offsetGet(mixed $offset): array { - return $this->get($offset); + return $this->values[$offset] ?? []; } - public function offsetSet($offset, $value): void + /** + * @param string $offset + * @param array $value + * @return void + */ + public function offsetSet(mixed $offset, mixed $value): void { - $this->set($offset, $value); + $this->set($offset, ...(array)$value); } - public function offsetUnset($offset): void + public function offsetUnset(mixed $offset): void { $this->delete($offset); } + /** + * @return array> + */ public function jsonSerialize(): array { return $this->values; @@ -137,7 +161,7 @@ public function __toString(): string if ('' === $v) { $str .= $k; } else { - $str .= sprintf('%s=%s', $k, $this->encode($v)); + $str .= "{$k}={$this->encode($v)}"; } } } diff --git a/src/MapResponse.php b/src/PHPLib/WriteMetaField.php similarity index 67% rename from src/MapResponse.php rename to src/PHPLib/WriteMetaField.php index cecfec0f..33306641 100644 --- a/src/MapResponse.php +++ b/src/PHPLib/WriteMetaField.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace DCarbone\PHPConsulAPI; +namespace DCarbone\PHPConsulAPI\PHPLib; /* Copyright 2016-2025 Daniel Carbone (daniel.p.carbone@gmail.com) @@ -20,17 +20,19 @@ limitations under the License. */ -class MapResponse extends AbstractValuedResponse implements UnmarshalledResponseInterface +use DCarbone\PHPConsulAPI\WriteMeta; + +trait WriteMetaField { - public ?array $Map = null; + public null|WriteMeta $WriteMeta = null; - public function getValue(): ?array + public function getWriteMeta(): null|WriteMeta { - return $this->Map; + return $this->WriteMeta; } - public function unmarshalValue(mixed $decodedData): void + public function setWriteMeta(null|WriteMeta $WriteMeta): void { - $this->Map = $decodedData; + $this->WriteMeta = $WriteMeta; } } diff --git a/src/WriteResponse.php b/src/PHPLib/WriteResponse.php similarity index 76% rename from src/WriteResponse.php rename to src/PHPLib/WriteResponse.php index c6fa61db..86947e41 100644 --- a/src/WriteResponse.php +++ b/src/PHPLib/WriteResponse.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace DCarbone\PHPConsulAPI; +namespace DCarbone\PHPConsulAPI\PHPLib; /* Copyright 2016-2025 Daniel Carbone (daniel.p.carbone@gmail.com) @@ -20,14 +20,18 @@ limitations under the License. */ -class WriteResponse extends AbstractResponse +use DCarbone\PHPConsulAPI\WriteMeta; + +/** + * @extends AbstractResponse + */ +class WriteResponse extends AbstractResponse implements WriteResponseInterface { - use WriteMetaContainer; - use ErrorContainer; + use WriteMetaField; public function offsetExists(mixed $offset): bool { - return \is_int($offset) && 0 <= $offset && $offset < 2; + return is_int($offset) && 0 <= $offset && $offset < 2; } public function offsetGet(mixed $offset): Error|null|WriteMeta diff --git a/src/PHPLib/WriteResponseInterface.php b/src/PHPLib/WriteResponseInterface.php new file mode 100644 index 00000000..f8745b83 --- /dev/null +++ b/src/PHPLib/WriteResponseInterface.php @@ -0,0 +1,30 @@ +Nanoseconds(); + $ms = $dur->Milliseconds(); + + if (0 < $ns && 0 === (int)$ms) { + $ms = 1; + } + + return "${ms}ms"; +} + +$_zeroObject = new \stdClass(); + +function _enc_obj_if_valued(\stdClass &$out, string $field, \JsonSerializable $obj): void +{ + global $_zeroObject; + $val = $obj->jsonSerialize(); + if ($val != $_zeroObject) { + $out->{$field} = $val; + } +} diff --git a/src/Peering/Locality.php b/src/Peering/Locality.php new file mode 100644 index 00000000..e25a38d5 --- /dev/null +++ b/src/Peering/Locality.php @@ -0,0 +1,74 @@ +Region = $Region; + $this->Zone = $Zone; + } + + public function getRegion(): string + { + return $this->Region; + } + + public function setRegion(string $Region): self + { + $this->Region = $Region; + return $this; + } + + public function getZone(): string + { + return $this->Zone; + } + + public function setZone(string $Zone): self + { + $this->Zone = $Zone; + return $this; + } + + public static function jsonUnserialize(\stdClass $decoded): self + { + $n = new self(); + foreach ((array)$decoded as $k => $v) { + $n->{$k} = $v; + } + return $n; + } + + public function jsonSerialize(): \stdClass + { + $out = $this->_startJsonSerialize(); + $out->Region = $this->Region; + $out->Zone = $this->Zone; + return $out; + } +} diff --git a/src/PreparedQuery/PreparedQueryClient.php b/src/PreparedQuery/PreparedQueryClient.php index e35585c7..37af8e97 100644 --- a/src/PreparedQuery/PreparedQueryClient.php +++ b/src/PreparedQuery/PreparedQueryClient.php @@ -20,15 +20,15 @@ limitations under the License. */ -use DCarbone\PHPConsulAPI\AbstractClient; +use DCarbone\PHPConsulAPI\PHPLib\AbstractClient; +use DCarbone\PHPConsulAPI\PHPLib\ValuedWriteStringResponse; +use DCarbone\PHPConsulAPI\PHPLib\WriteResponse; use DCarbone\PHPConsulAPI\QueryOptions; -use DCarbone\PHPConsulAPI\ValuedWriteStringResponse; use DCarbone\PHPConsulAPI\WriteOptions; -use DCarbone\PHPConsulAPI\WriteResponse; class PreparedQueryClient extends AbstractClient { - public function Create(PreparedQueryDefinition $query, ?WriteOptions $opts = null): ValuedWriteStringResponse + public function Create(PreparedQueryDefinition $query, null|WriteOptions $opts = null): ValuedWriteStringResponse { $resp = $this->_requireOK($this->_doPost('v1/query', $query, $opts)); $ret = new ValuedWriteStringResponse(); @@ -36,12 +36,12 @@ public function Create(PreparedQueryDefinition $query, ?WriteOptions $opts = nul return $ret; } - public function Update(PreparedQueryDefinition $query, ?WriteOptions $opts = null): WriteResponse + public function Update(PreparedQueryDefinition $query, null|WriteOptions $opts = null): WriteResponse { return $this->_executePut('v1/query', $query, $opts); } - public function List(?QueryOptions $opts = null): PreparedQueryDefinitionsResponse + public function List(null|QueryOptions $opts = null): PreparedQueryDefinitionsResponse { $resp = $this->_doGet('v1/query', $opts); $ret = new PreparedQueryDefinitionsResponse(); @@ -49,7 +49,7 @@ public function List(?QueryOptions $opts = null): PreparedQueryDefinitionsRespon return $ret; } - public function Get(string $queryID, ?QueryOptions $opts = null): PreparedQueryDefinitionsResponse + public function Get(string $queryID, null|QueryOptions $opts = null): PreparedQueryDefinitionsResponse { $resp = $this->_doGet(sprintf('v1/query/%s', $queryID), $opts); $ret = new PreparedQueryDefinitionsResponse(); @@ -57,12 +57,12 @@ public function Get(string $queryID, ?QueryOptions $opts = null): PreparedQueryD return $ret; } - public function Delete(string $queryID, ?WriteOptions $opts = null): WriteResponse + public function Delete(string $queryID, null|WriteOptions $opts = null): WriteResponse { return $this->_executeDelete(sprintf('v1/query/%s', $queryID), $opts); } - public function Execute(string $queryIDOrName, ?QueryOptions $opts = null): PreparedQueryExecuteResponseResponse + public function Execute(string $queryIDOrName, null|QueryOptions $opts = null): PreparedQueryExecuteResponseResponse { $resp = $this->_doGet(sprintf('v1/query/%s/execute', $queryIDOrName), $opts); $ret = new PreparedQueryExecuteResponseResponse(); diff --git a/src/PreparedQuery/PreparedQueryDefinition.php b/src/PreparedQuery/PreparedQueryDefinition.php index 236b1ca1..81542ee0 100644 --- a/src/PreparedQuery/PreparedQueryDefinition.php +++ b/src/PreparedQuery/PreparedQueryDefinition.php @@ -20,50 +20,34 @@ limitations under the License. */ -use DCarbone\PHPConsulAPI\AbstractModel; -use DCarbone\PHPConsulAPI\Transcoding; +use DCarbone\PHPConsulAPI\PHPLib\AbstractType; -class PreparedQueryDefinition extends AbstractModel +class PreparedQueryDefinition extends AbstractType { - protected const FIELDS = [ - self::FIELD_SERVICE => [ - Transcoding::FIELD_TYPE => Transcoding::OBJECT, - Transcoding::FIELD_CLASS => ServiceQuery::class, - ], - self::FIELD_DNS => [ - Transcoding::FIELD_TYPE => Transcoding::OBJECT, - Transcoding::FIELD_CLASS => QueryDNSOptions::class, - ], - self::FIELD_Template => [ - Transcoding::FIELD_TYPE => Transcoding::OBJECT, - Transcoding::FIELD_CLASS => QueryTemplate::class, - ], - ]; - - private const FIELD_SERVICE = 'Service'; - private const FIELD_DNS = 'DNS'; - private const FIELD_Template = 'Template'; - - public string $ID = ''; - public string $Name = ''; - public string $Session = ''; - public string $Token = ''; + public string $ID; + public string $Name; + public string $Session; + public string $Token; public ServiceQuery $Service; public QueryDNSOptions $DNS; public QueryTemplate $Template; - public function __construct(?array $data = []) - { - parent::__construct($data); - if (!isset($this->Service)) { - $this->Service = new ServiceQuery(null); - } - if (!isset($this->DNS)) { - $this->DNS = new QueryDNSOptions(null); - } - if (!isset($this->Template)) { - $this->Template = new QueryTemplate(null); - } + public function __construct( + string $ID = '', + string $Name = '', + string $Session = '', + string $Token = '', + null|ServiceQuery $Service = null, + null|QueryDNSOptions $DNS = null, + null|QueryTemplate $Template = null, + ) { + $this->ID = $ID; + $this->Name = $Name; + $this->Session = $Session; + $this->Token = $Token; + $this->Service = $Service ?? new ServiceQuery(); + $this->DNS = $DNS ?? new QueryDNSOptions(); + $this->Template = $Template ?? new QueryTemplate(); } public function getID(): string @@ -142,4 +126,34 @@ public function setTemplate(QueryTemplate $Template): self $this->Template = $Template; return $this; } + + public static function jsonUnserialize(\stdClass $decoded): self + { + $n = new self(); + foreach ((array)$decoded as $k => $v) { + if ('Service' === $k) { + $n->Service = ServiceQuery::jsonUnserialize($v); + } elseif ('DNS' === $k) { + $n->DNS = QueryDNSOptions::jsonUnserialize($v); + } elseif ('Template' === $k) { + $n->Template = QueryTemplate::jsonUnserialize($v); + } else { + $n->{$k} = $v; + } + } + return $n; + } + + public function jsonSerialize(): \stdClass + { + $out = $this->_startJsonSerialize(); + $out->ID = $this->ID; + $out->Name = $this->Name; + $out->Session = $this->Session; + $out->Token = $this->Token; + $out->Service = $this->Service; + $out->DNS = $this->DNS; + $out->Template = $this->Template; + return $out; + } } diff --git a/src/PreparedQuery/PreparedQueryDefinitionsResponse.php b/src/PreparedQuery/PreparedQueryDefinitionsResponse.php index eb04548e..c775cfb1 100644 --- a/src/PreparedQuery/PreparedQueryDefinitionsResponse.php +++ b/src/PreparedQuery/PreparedQueryDefinitionsResponse.php @@ -20,23 +20,27 @@ namespace DCarbone\PHPConsulAPI\PreparedQuery; -use DCarbone\PHPConsulAPI\AbstractValuedQueryResponse; -use DCarbone\PHPConsulAPI\UnmarshalledResponseInterface; +use DCarbone\PHPConsulAPI\PHPLib\AbstractValuedQueryResponse; +use DCarbone\PHPConsulAPI\PHPLib\UnmarshalledResponseInterface; class PreparedQueryDefinitionsResponse extends AbstractValuedQueryResponse implements UnmarshalledResponseInterface { - public ?array $PreparedQueryDefinitions = null; + /** @var \DCarbone\PHPConsulAPI\PreparedQuery\PreparedQueryDefinition[] */ + public array $PreparedQueryDefinitions = []; - public function getValue(): ?array + /** + * @return \DCarbone\PHPConsulAPI\PreparedQuery\PreparedQueryDefinition[] + */ + public function getValue(): array { return $this->PreparedQueryDefinitions; } - public function unmarshalValue(mixed $decodedData): void + public function unmarshalValue(mixed $decoded): void { $this->PreparedQueryDefinitions = []; - foreach ($decodedData as $datum) { - $this->PreparedQueryDefinitions[] = new PreparedQueryDefinition($datum); + foreach ($decoded as $datum) { + $this->PreparedQueryDefinitions[] = PreparedQueryDefinition::jsonUnserialize($datum); } } } diff --git a/src/PreparedQuery/PreparedQueryExecuteResponse.php b/src/PreparedQuery/PreparedQueryExecuteResponse.php index 1a28093b..ac61525e 100644 --- a/src/PreparedQuery/PreparedQueryExecuteResponse.php +++ b/src/PreparedQuery/PreparedQueryExecuteResponse.php @@ -20,42 +20,36 @@ limitations under the License. */ -use DCarbone\PHPConsulAPI\AbstractModel; use DCarbone\PHPConsulAPI\Health\ServiceEntry; -use DCarbone\PHPConsulAPI\Transcoding; +use DCarbone\PHPConsulAPI\PHPLib\AbstractType; -class PreparedQueryExecuteResponse extends AbstractModel +class PreparedQueryExecuteResponse extends AbstractType { - protected const FIELDS = [ - self::FIELD_NODES => [ - Transcoding::FIELD_TYPE => Transcoding::ARRAY, - Transcoding::FIELD_CLASS => ServiceEntry::class, - Transcoding::FIELD_ARRAY_TYPE => Transcoding::OBJECT, - ], - self::FIELD_DNS => [ - Transcoding::FIELD_TYPE => Transcoding::OBJECT, - Transcoding::FIELD_CLASS => QueryDNSOptions::class, - ], - self::FIELD_NAMESPACE => Transcoding::OMITEMPTY_STRING_FIELD, - ]; - - private const FIELD_NAMESPACE = 'Namespace'; - private const FIELD_NODES = 'Nodes'; - private const FIELD_DNS = 'DNS'; - - public string $Service = ''; - public string $Namespace = ''; - public array $Nodes = []; + public string $Service; + public string $Namespace; + /** @var array */ + public array $Nodes; public QueryDNSOptions $DNS; - public string $Datacenter = ''; - public int $Failovers = 0; - - public function __construct(?array $data = []) - { - parent::__construct($data); - if (!isset($this->DNS)) { - $this->DNS = new QueryDNSOptions(null); - } + public string $Datacenter; + public int $Failovers; + + /** + * @param array $Nodes + */ + public function __construct( + string $Service = '', + string $Namespace = '', + array $Nodes = [], + null|QueryDNSOptions $DNS = null, + string $Datacenter = '', + int $Failovers = 0, + ) { + $this->Service = $Service; + $this->Namespace = $Namespace; + $this->setNodes(...$Nodes); + $this->DNS = $DNS ?? new QueryDNSOptions(); + $this->Datacenter = $Datacenter; + $this->Failovers = $Failovers; } public function getService(): string @@ -80,12 +74,15 @@ public function setNamespace(string $Namespace): self return $this; } + /** + * @return array + */ public function getNodes(): array { return $this->Nodes; } - public function setNodes(array $Nodes): self + public function setNodes(ServiceEntry ...$Nodes): self { $this->Nodes = $Nodes; return $this; @@ -123,4 +120,36 @@ public function setFailovers(int $Failovers): self $this->Failovers = $Failovers; return $this; } + + public static function jsonUnserialize(\stdClass $decoded): self + { + $n = new self(); + foreach ((array)$decoded as $k => $v) { + if ('Nodes' === $k) { + $n->Nodes = []; + foreach ($v as $nv) { + $n->Nodes[] = ServiceEntry::jsonUnserialize($nv); + } + } elseif ('DNS' === $k) { + $n->DNS = QueryDNSOptions::jsonUnserialize($v); + } else { + $n->{$k} = $v; + } + } + return $n; + } + + public function jsonSerialize(): \stdClass + { + $out = $this->_startJsonSerialize(); + $out->Service = $this->Service; + if ('' !== $this->Namespace) { + $out->Namespace = $this->Namespace; + } + $out->Nodes = $this->Nodes; + $out->DNS = $this->DNS; + $out->Datacenter = $this->Datacenter; + $out->Failovers = $this->Failovers; + return $out; + } } diff --git a/src/PreparedQuery/PreparedQueryExecuteResponseResponse.php b/src/PreparedQuery/PreparedQueryExecuteResponseResponse.php index c5f66b20..8f6b1f87 100644 --- a/src/PreparedQuery/PreparedQueryExecuteResponseResponse.php +++ b/src/PreparedQuery/PreparedQueryExecuteResponseResponse.php @@ -20,20 +20,20 @@ namespace DCarbone\PHPConsulAPI\PreparedQuery; -use DCarbone\PHPConsulAPI\AbstractValuedQueryResponse; -use DCarbone\PHPConsulAPI\UnmarshalledResponseInterface; +use DCarbone\PHPConsulAPI\PHPLib\AbstractValuedQueryResponse; +use DCarbone\PHPConsulAPI\PHPLib\UnmarshalledResponseInterface; class PreparedQueryExecuteResponseResponse extends AbstractValuedQueryResponse implements UnmarshalledResponseInterface { - public ?PreparedQueryExecuteResponse $PreparedQueryExecuteResponse = null; + public null|PreparedQueryExecuteResponse $PreparedQueryExecuteResponse = null; - public function getValue(): ?PreparedQueryExecuteResponse + public function getValue(): null|PreparedQueryExecuteResponse { return $this->PreparedQueryExecuteResponse; } - public function unmarshalValue(mixed $decodedData): void + public function unmarshalValue(mixed $decoded): void { - $this->PreparedQueryExecuteResponse = new PreparedQueryExecuteResponse((array)$decodedData); + $this->PreparedQueryExecuteResponse = PreparedQueryExecuteResponse::jsonUnserialize($decoded); } } diff --git a/src/PreparedQuery/QueryDNSOptions.php b/src/PreparedQuery/QueryDNSOptions.php index 729f29b8..6afb9552 100644 --- a/src/PreparedQuery/QueryDNSOptions.php +++ b/src/PreparedQuery/QueryDNSOptions.php @@ -20,20 +20,25 @@ limitations under the License. */ -use DCarbone\PHPConsulAPI\AbstractModel; +use DCarbone\PHPConsulAPI\PHPLib\AbstractType; -class QueryDNSOptions extends AbstractModel +class QueryDNSOptions extends AbstractType { - public string $TTL = ''; + public string $TTL; + + public function __construct(string $TTL = '') + { + $this->TTL = $TTL; + } public function getTTL(): string { return $this->TTL; } - public function setTTL(string $ttl): self + public function setTTL(string $TTL): self { - $this->TTL = $ttl; + $this->TTL = $TTL; return $this; } @@ -41,4 +46,20 @@ public function __toString(): string { return $this->TTL; } + + public static function jsonUnserialize(\stdClass $decoded): self + { + $n = new self(); + foreach ((array)$decoded as $k => $v) { + $n->{$k} = $v; + } + return $n; + } + + public function jsonSerialize(): \stdClass + { + $out = $this->_startJsonSerialize(); + $out->TTL = $this->TTL; + return $out; + } } diff --git a/src/PreparedQuery/QueryDatacenterOptions.php b/src/PreparedQuery/QueryDatacenterOptions.php index f8d67967..6fd26aff 100644 --- a/src/PreparedQuery/QueryDatacenterOptions.php +++ b/src/PreparedQuery/QueryDatacenterOptions.php @@ -20,32 +20,47 @@ limitations under the License. */ -use DCarbone\PHPConsulAPI\AbstractModel; +use DCarbone\PHPConsulAPI\PHPLib\AbstractType; -class QueryDatacenterOptions extends AbstractModel +class QueryDatacenterOptions extends AbstractType { - public int $NearestN = 0; - public array $Datacenters = []; + public int $NearestN; + /** @var array */ + public array $Datacenters; + + /** + * @param array $Datacenters + */ + public function __construct( + int $NearestN = 0, + array $Datacenters = [], + ) { + $this->NearestN = $NearestN; + $this->setDatacenters(...$Datacenters); + } public function getNearestN(): int { return $this->NearestN; } - public function setNearestN(int $nearestN): self + public function setNearestN(int $NearestN): self { - $this->NearestN = $nearestN; + $this->NearestN = $NearestN; return $this; } + /** + * @return array + */ public function getDatacenters(): array { return $this->Datacenters; } - public function setDatacenters(array $datacenters): self + public function setDatacenters(string ...$Datacenters): self { - $this->Datacenters = $datacenters; + $this->Datacenters = $Datacenters; return $this; } @@ -54,4 +69,21 @@ public function addDatacenter(string $datacenter): self $this->Datacenters[] = $datacenter; return $this; } + + public static function jsonUnserialize(\stdClass $decoded): self + { + $n = new self(); + foreach ((array)$decoded as $k => $v) { + $n->{$k} = $v; + } + return $n; + } + + public function jsonSerialize(): \stdClass + { + $out = $this->_startJsonSerialize(); + $out->NearestN = $this->NearestN; + $out->Datacenters = $this->Datacenters; + return $out; + } } diff --git a/src/PreparedQuery/QueryTemplate.php b/src/PreparedQuery/QueryTemplate.php index b6ddbada..f618c84f 100644 --- a/src/PreparedQuery/QueryTemplate.php +++ b/src/PreparedQuery/QueryTemplate.php @@ -20,12 +20,20 @@ limitations under the License. */ -use DCarbone\PHPConsulAPI\AbstractModel; +use DCarbone\PHPConsulAPI\PHPLib\AbstractType; -class QueryTemplate extends AbstractModel +class QueryTemplate extends AbstractType { - public string $Type = ''; - public string $Regexp = ''; + public string $Type; + public string $Regexp; + + public function __construct( + string $Type = '', + string $Regexp = '', + ) { + $this->Type = $Type; + $this->Regexp = $Regexp; + } public function getType(): string { @@ -48,4 +56,21 @@ public function setRegexp(string $Regexp): self $this->Regexp = $Regexp; return $this; } + + public static function jsonUnserialize(\stdClass $decoded): self + { + $n = new self(); + foreach ((array)$decoded as $k => $v) { + $n->{$k} = $v; + } + return $n; + } + + public function jsonSerialize(): \stdClass + { + $out = $this->_startJsonSerialize(); + $out->Type = $this->Type; + $out->Regexp = $this->Regexp; + return $out; + } } diff --git a/src/PreparedQuery/ServiceQuery.php b/src/PreparedQuery/ServiceQuery.php index f3c9f612..35c9a6cf 100644 --- a/src/PreparedQuery/ServiceQuery.php +++ b/src/PreparedQuery/ServiceQuery.php @@ -20,43 +20,53 @@ limitations under the License. */ -use DCarbone\PHPConsulAPI\AbstractModel; -use DCarbone\PHPConsulAPI\HasSettableStringTags; -use DCarbone\PHPConsulAPI\HasStringTags; -use DCarbone\PHPConsulAPI\Transcoding; +use DCarbone\PHPConsulAPI\PHPLib\AbstractType; -class ServiceQuery extends AbstractModel +class ServiceQuery extends AbstractType { - use HasSettableStringTags; - use HasStringTags; - - protected const FIELDS = [ - self::FIELD_NAMESPACE => Transcoding::OMITEMPTY_STRING_FIELD, - self::FIELD_FAILOVER => [ - Transcoding::FIELD_TYPE => Transcoding::OBJECT, - Transcoding::FIELD_CLASS => QueryDatacenterOptions::class, - ], - ]; - - private const FIELD_NAMESPACE = 'Namespace'; - private const FIELD_FAILOVER = 'Failover'; - - public string $Service = ''; - public string $Namespace = ''; - public string $Near = ''; - public array $IgnoreCheckIDs = []; + public string $Service; + public string $Namespace; + public string $Near; + /** @var array */ + public array $Tags; + /** @var array */ + public array $IgnoreCheckIDs; public QueryDatacenterOptions $Failover; - public bool $OnlyPassing = false; - public array $NodeMeta = []; - public array $ServiceMeta = []; - public bool $Connect = false; - - public function __construct(?array $data = []) - { - parent::__construct($data); - if (!isset($this->Failover)) { - $this->Failover = new QueryDatacenterOptions(null); - } + public bool $OnlyPassing; + /** @var array */ + public array $NodeMeta; + /** @var array */ + public array $ServiceMeta; + public bool $Connect; + + /** + * @param array $Tags + * @param array $IgnoreCheckIDs + * @param array $NodeMeta + * @param array $ServiceMeta + */ + public function __construct( + string $Service = '', + string $Namespace = '', + string $Near = '', + array $Tags = [], + array $IgnoreCheckIDs = [], + null|QueryDatacenterOptions $Failover = null, + bool $OnlyPassing = false, + array $NodeMeta = [], + array $ServiceMeta = [], + bool $Connect = false, + ) { + $this->Service = $Service; + $this->Namespace = $Namespace; + $this->Near = $Near; + $this->setTags(...$Tags); + $this->setIgnoreCheckIDs(...$IgnoreCheckIDs); + $this->Failover = $Failover ?? new QueryDatacenterOptions(); + $this->OnlyPassing = $OnlyPassing; + $this->NodeMeta = $NodeMeta; + $this->ServiceMeta = $ServiceMeta; + $this->Connect = $Connect; } public function getService(): string @@ -92,12 +102,29 @@ public function setNear(string $Near): self return $this; } + /** + * @return array + */ + public function getTags(): array + { + return $this->Tags; + } + + public function setTags(string ...$Tags): self + { + $this->Tags = $Tags; + return $this; + } + + /** + * @return array + */ public function getIgnoreCheckIDs(): array { return $this->IgnoreCheckIDs; } - public function setIgnoreCheckIDs(array $IgnoreCheckIDs): self + public function setIgnoreCheckIDs(string ...$IgnoreCheckIDs): self { $this->IgnoreCheckIDs = $IgnoreCheckIDs; return $this; @@ -125,22 +152,34 @@ public function setOnlyPassing(bool $OnlyPassing): self return $this; } + /** + * @return array + */ public function getNodeMeta(): array { return $this->NodeMeta; } + /** + * @param array $NodeMeta + */ public function setNodeMeta(array $NodeMeta): self { $this->NodeMeta = $NodeMeta; return $this; } + /** + * @return array + */ public function getServiceMeta(): array { return $this->ServiceMeta; } + /** + * @param array $ServiceMeta + */ public function setServiceMeta(array $ServiceMeta): self { $this->ServiceMeta = $ServiceMeta; @@ -157,4 +196,37 @@ public function setConnect(bool $Connect): self $this->Connect = $Connect; return $this; } + + public static function jsonUnserialize(\stdClass $decoded): self + { + $n = new self(); + foreach ((array)$decoded as $k => $v) { + if ('Failover' === $k) { + $n->Failover = QueryDatacenterOptions::jsonUnserialize($v); + } elseif ('Tags' === $k) { + $n->setTags(...$v); + } else { + $n->{$k} = $v; + } + } + return $n; + } + + public function jsonSerialize(): \stdClass + { + $out = $this->_startJsonSerialize(); + $out->Service = $this->Service; + if ('' !== $this->Namespace) { + $out->Namespace = $this->Namespace; + } + $out->Near = $this->Near; + $out->Tags = $this->Tags; + $out->IgnoreCheckIDs = $this->IgnoreCheckIDs; + $out->Failover = $this->Failover; + $out->OnlyPassing = $this->OnlyPassing; + $out->NodeMeta = $this->NodeMeta; + $out->ServiceMeta = $this->ServiceMeta; + $out->Connect = $this->Connect; + return $out; + } } diff --git a/src/QueryMeta.php b/src/QueryMeta.php index ea23adef..8102914f 100644 --- a/src/QueryMeta.php +++ b/src/QueryMeta.php @@ -24,58 +24,135 @@ class QueryMeta { - public string $RequestUrl = ''; - public int $LastIndex = 0; - public string $LastContentHash = ''; - public int $LastContact = 0; - public bool $KnownLeader = false; - public ?Time\Duration $RequestTime = null; - public bool $AddressTranslationEnabled = false; - public bool $CacheHit = false; - public ?Time\Duration $CacheAge = null; + public string $RequestUrl; + public int $LastIndex; + public string $LastContentHash; + public int $LastContact; + public bool $KnownLeader; + public Time\Duration $RequestTime; + public bool $AddressTranslationEnabled; + public bool $CacheHit; + public Time\Duration $CacheAge; + + public function __construct( + string $RequestUrl, + null|string|int|float|\DateInterval|Time\Duration $RequestTime, + int $LastIndex = 0, + string $LastContentHash = '', + int $LastContact = 0, + bool $KnownLeader = false, + bool $AddressTranslationEnabled = false, + bool $CacheHit = false, + null|string|int|float|\DateInterval|Time\Duration $CacheAge = null + ) { + $this->RequestUrl = $RequestUrl; + $this->RequestTime = Time::Duration($RequestTime); + + $this->LastIndex = $LastIndex; + $this->LastContentHash = $LastContentHash; + $this->LastContact = $LastContact; + $this->KnownLeader = $KnownLeader; + $this->AddressTranslationEnabled = $AddressTranslationEnabled; + $this->CacheHit = $CacheHit; + $this->CacheAge = Time::Duration($CacheAge); + } public function getRequestUrl(): string { return $this->RequestUrl; } + public function setRequestUrl(string $RequestUrl): self + { + $this->RequestUrl = $RequestUrl; + return $this; + } + public function getLastIndex(): int { return $this->LastIndex; } + public function setLastIndex(int $LastIndex): self + { + $this->LastIndex = $LastIndex; + return $this; + } + public function getLastContentHash(): string { return $this->LastContentHash; } + public function setLastContentHash(string $LastContentHash): self + { + $this->LastContentHash = $LastContentHash; + return $this; + } + public function getLastContact(): int { return $this->LastContact; } + public function setLastContact(int $LastContact): self + { + $this->LastContact = $LastContact; + return $this; + } + public function isKnownLeader(): bool { return $this->KnownLeader; } - public function getRequestTime(): ?Time\Duration + public function setKnownLeader(bool $KnownLeader): self + { + $this->KnownLeader = $KnownLeader; + return $this; + } + + public function getRequestTime(): Time\Duration { return $this->RequestTime; } + public function setRequestTime(null|string|int|float|\DateInterval|Time\Duration $RequestTime): self + { + $this->RequestTime = Time::Duration($RequestTime); + return $this; + } + public function isAddressTranslationEnabled(): bool { return $this->AddressTranslationEnabled; } + public function setAddressTranslationEnabled(bool $AddressTranslationEnabled): self + { + $this->AddressTranslationEnabled = $AddressTranslationEnabled; + return $this; + } + public function isCacheHit(): bool { return $this->CacheHit; } - public function getCacheAge(): ?Time\Duration + public function setCacheHit(bool $CacheHit): self + { + $this->CacheHit = $CacheHit; + return $this; + } + + public function getCacheAge(): Time\Duration { return $this->CacheAge; } + + public function setCacheAge(null|string|int|float|\DateInterval|Time\Duration $CacheAge): self + { + $this->CacheAge = Time::Duration($CacheAge); + return $this; + } } diff --git a/src/QueryOptions.php b/src/QueryOptions.php index cf6fff29..61c0681b 100644 --- a/src/QueryOptions.php +++ b/src/QueryOptions.php @@ -21,66 +21,78 @@ */ use DCarbone\Go\Time; +use DCarbone\PHPConsulAPI\PHPLib\Request; +use DCarbone\PHPConsulAPI\PHPLib\RequestOptions; +use function DCarbone\PHPConsulAPI\PHPLib\dur_to_millisecond; -class QueryOptions extends AbstractModel implements RequestOptions +class QueryOptions implements RequestOptions { - protected const FIELDS = [ - self::FIELD_MAX_AGE => [ - Transcoding::FIELD_UNMARSHAL_CALLBACK => Transcoding::UNMARSHAL_NULLABLE_DURATION, - ], - self::FIELD_STALE_IF_ERROR => [ - Transcoding::FIELD_UNMARSHAL_CALLBACK => Transcoding::UNMARSHAL_NULLABLE_DURATION, - ], - self::FIELD_WAIT_TIME => [ - Transcoding::FIELD_UNMARSHAL_CALLBACK => Transcoding::UNMARSHAL_NULLABLE_DURATION, - ], - self::FIELD_TIMEOUT => [ - Transcoding::FIELD_UNMARSHAL_CALLBACK => Transcoding::UNMARSHAL_NULLABLE_DURATION, - ], - ]; - - private const FIELD_MAX_AGE = 'MaxAge'; - private const FIELD_STALE_IF_ERROR = 'StaleIfError'; - private const FIELD_WAIT_TIME = 'WaitTime'; - private const FIELD_TIMEOUT = 'Timeout'; - - public string $Namespace = ''; - public string $Datacenter = ''; - public bool $AllowStale = false; - public bool $RequireConsistent = false; - public bool $UseCache = false; - public ?Time\Duration $MaxAge = null; - public ?Time\Duration $StaleIfError = null; - public int $WaitIndex = 0; - public string $WaitHash = ''; - public ?Time\Duration $WaitTime = null; - public string $Token = ''; - public string $Near = ''; - public string $Filter = ''; - public array $NodeMeta = []; - public int $RelayFactor = 0; - public bool $LocalOnly = false; - public bool $Connect = false; - - public ?Time\Duration $Timeout = null; - - public bool $Pretty = false; - - public function __construct(?array $data = null) - { - parent::__construct($data); - if (!($this->MaxAge instanceof Time\Duration)) { - $this->MaxAge = Time::Duration($this->MaxAge); - } - if (!($this->StaleIfError instanceof Time\Duration)) { - $this->StaleIfError = Time::Duration($this->StaleIfError); - } - if (!($this->WaitTime instanceof Time\Duration)) { - $this->WaitTime = Time::Duration($this->WaitTime); - } - if (!($this->Timeout instanceof Time\Duration)) { - $this->Timeout = Time::Duration($this->Timeout); - } + public string $Namespace; + public string $Datacenter; + public bool $AllowStale; + public bool $RequireConsistent; + public bool $UseCache; + public Time\Duration $MaxAge; + public Time\Duration $StaleIfError; + public int $WaitIndex; + public string $WaitHash; + public Time\Duration $WaitTime; + public string $Token; + public string $Near; + public string $Filter; + /** @var array */ + public array $NodeMeta; + public int $RelayFactor; + public bool $LocalOnly; + public bool $Connect; + + public Time\Duration $Timeout; + + public bool $Pretty; + + /** + * @param array $NodeMeta + */ + public function __construct( + string $Namespace = '', + string $Datacenter = '', + bool $AllowStale = false, + bool $RequireConsistent = false, + bool $UseCache = false, + null|int|float|string|\DateInterval|Time\Duration $MaxAge = null, + null|int|float|string|\DateInterval|Time\Duration $StaleIfError = null, + int $WaitIndex = 0, + string $WaitHash = '', + null|int|float|string|\DateInterval|Time\Duration $WaitTime = null, + string $Token = '', + string $Near = '', + string $Filter = '', + array $NodeMeta = [], + int $RelayFactor = 0, + bool $LocalOnly = false, + bool $Connect = false, + null|int|float|string|\DateInterval|Time\Duration $Timeout = null, + bool $Pretty = false, + ) { + $this->Namespace = $Namespace; + $this->Datacenter = $Datacenter; + $this->AllowStale = $AllowStale; + $this->RequireConsistent = $RequireConsistent; + $this->UseCache = $UseCache; + $this->MaxAge = Time::Duration($MaxAge); + $this->StaleIfError = Time::Duration($StaleIfError); + $this->WaitIndex = $WaitIndex; + $this->WaitHash = $WaitHash; + $this->WaitTime = Time::Duration($WaitTime); + $this->Token = $Token; + $this->Near = $Near; + $this->Filter = $Filter; + $this->setNodeMeta($NodeMeta); + $this->RelayFactor = $RelayFactor; + $this->LocalOnly = $LocalOnly; + $this->Connect = $Connect; + $this->Timeout = Time::Duration($Timeout); + $this->Pretty = $Pretty; } public function getNamespace(): string @@ -88,9 +100,10 @@ public function getNamespace(): string return $this->Namespace; } - public function setNamespace(string $namespace): void + public function setNamespace(string $namespace): self { $this->Namespace = $namespace; + return $this; } public function getDatacenter(): string @@ -98,9 +111,10 @@ public function getDatacenter(): string return $this->Datacenter; } - public function setDatacenter(string $datacenter): void + public function setDatacenter(string $datacenter): self { $this->Datacenter = $datacenter; + return $this; } public function isAllowStale(): bool @@ -108,9 +122,10 @@ public function isAllowStale(): bool return $this->AllowStale; } - public function setAllowStale(bool $allowStale): void + public function setAllowStale(bool $allowStale): self { $this->AllowStale = $allowStale; + return $this; } public function isRequireConsistent(): bool @@ -118,9 +133,10 @@ public function isRequireConsistent(): bool return $this->RequireConsistent; } - public function setRequireConsistent(bool $requireConsistent): void + public function setRequireConsistent(bool $requireConsistent): self { $this->RequireConsistent = $requireConsistent; + return $this; } public function isUseCache(): bool @@ -128,9 +144,10 @@ public function isUseCache(): bool return $this->UseCache; } - public function setUseCache(bool $useCache): void + public function setUseCache(bool $useCache): self { $this->UseCache = $useCache; + return $this; } public function getMaxAge(): Time\Duration @@ -138,9 +155,10 @@ public function getMaxAge(): Time\Duration return $this->MaxAge; } - public function setMaxAge(float|int|string|Time\Duration|null $maxAge): void + public function setMaxAge(null|int|float|string|\DateInterval|Time\Duration $maxAge): self { $this->MaxAge = Time::Duration($maxAge); + return $this; } public function getStaleIfError(): Time\Duration @@ -148,9 +166,10 @@ public function getStaleIfError(): Time\Duration return $this->StaleIfError; } - public function setStaleIfError(float|int|string|Time\Duration|null $staleIfError): void + public function setStaleIfError(null|int|float|string|\DateInterval|Time\Duration $staleIfError): self { $this->StaleIfError = Time::Duration($staleIfError); + return $this; } public function getWaitIndex(): int @@ -158,9 +177,10 @@ public function getWaitIndex(): int return $this->WaitIndex; } - public function setWaitIndex(int $waitIndex): void + public function setWaitIndex(int $waitIndex): self { $this->WaitIndex = $waitIndex; + return $this; } public function getWaitTime(): Time\Duration @@ -168,9 +188,10 @@ public function getWaitTime(): Time\Duration return $this->WaitTime; } - public function setWaitTime(mixed $waitTime): void + public function setWaitTime(null|int|float|string|\DateInterval|Time\Duration $waitTime): self { $this->WaitTime = Time::Duration($waitTime); + return $this; } public function getWaitHash(): string @@ -178,9 +199,10 @@ public function getWaitHash(): string return $this->WaitHash; } - public function setWaitHash(string $waitHash): void + public function setWaitHash(string $waitHash): self { $this->WaitHash = $waitHash; + return $this; } public function getToken(): string @@ -188,9 +210,10 @@ public function getToken(): string return $this->Token; } - public function setToken(string $token): void + public function setToken(string $token): self { $this->Token = $token; + return $this; } public function getNear(): string @@ -198,9 +221,10 @@ public function getNear(): string return $this->Near; } - public function setNear(string $near): void + public function setNear(string $near): self { $this->Near = $near; + return $this; } public function getFilter(): string @@ -208,19 +232,27 @@ public function getFilter(): string return $this->Filter; } - public function setFilter(string $filter): void + public function setFilter(string $filter): self { $this->Filter = $filter; + return $this; } + /** + * @return array + */ public function getNodeMeta(): array { return $this->NodeMeta; } - public function setNodeMeta(array $nodeMeta): void + /** + * @param array $nodeMeta + */ + public function setNodeMeta(array $nodeMeta): self { $this->NodeMeta = $nodeMeta; + return $this; } public function getRelayFactor(): int @@ -228,9 +260,10 @@ public function getRelayFactor(): int return $this->RelayFactor; } - public function setRelayFactor(int $relayFactor): void + public function setRelayFactor(int $relayFactor): self { $this->RelayFactor = $relayFactor; + return $this; } public function isLocalOnly(): bool @@ -238,9 +271,10 @@ public function isLocalOnly(): bool return $this->LocalOnly; } - public function setLocalOnly(bool $localOnly): void + public function setLocalOnly(bool $localOnly): self { $this->LocalOnly = $localOnly; + return $this; } public function isConnect(): bool @@ -248,19 +282,21 @@ public function isConnect(): bool return $this->Connect; } - public function setConnect(bool $connect): void + public function setConnect(bool $connect): self { $this->Connect = $connect; + return $this; } - public function getTimeout(): ?Time\Duration + public function getTimeout(): Time\Duration { return $this->Timeout; } - public function setTimeout(float|int|string|Time\Duration|null $timeout): void + public function setTimeout(null|int|float|string|\DateInterval|Time\Duration $timeout): self { $this->Timeout = Time::Duration($timeout); + return $this; } public function isPretty(): bool @@ -268,9 +304,10 @@ public function isPretty(): bool return $this->Pretty; } - public function setPretty(bool $pretty): void + public function setPretty(bool $pretty): self { $this->Pretty = $pretty; + return $this; } public function apply(Request $r): void @@ -288,9 +325,9 @@ public function apply(Request $r): void $r->params->set('consistent', ''); } if (0 !== $this->WaitIndex) { - $r->params->set('index', (string) $this->WaitIndex); + $r->params->set('index', (string)$this->WaitIndex); } - if (isset($this->WaitTime) && 0 < $this->WaitTime->Microseconds()) { + if (0 < $this->WaitTime->Microseconds()) { $r->params->set('wait', dur_to_millisecond($this->WaitTime)); } if ('' !== $this->WaitHash) { @@ -305,13 +342,13 @@ public function apply(Request $r): void if ('' !== $this->Filter) { $r->params->set('filter', $this->Filter); } - if (isset($this->NodeMeta) && [] !== $this->NodeMeta) { + if ([] !== $this->NodeMeta) { foreach ($this->NodeMeta as $k => $v) { $r->params->add('node-meta', "{$k}:{$v}"); } } if (0 !== $this->RelayFactor) { - $r->params->set('relay-factor', (string) $this->RelayFactor); + $r->params->set('relay-factor', (string)$this->RelayFactor); } if ($this->LocalOnly) { $r->params->set('local-only', 'true'); @@ -335,7 +372,7 @@ public function apply(Request $r): void } } - if (null !== $this->Timeout) { + if (0 < $this->Timeout->Nanoseconds()) { $r->timeout = $this->Timeout; } diff --git a/src/ScalarType.php b/src/ScalarType.php deleted file mode 100644 index 3dc28b72..00000000 --- a/src/ScalarType.php +++ /dev/null @@ -1,31 +0,0 @@ -ID = $ID; + $this->Namespace = $Namespace; + } public function getID(): string { return $this->ID; } - public function setID(string $id): self + public function setID(string $ID): self { - $this->ID = $id; + $this->ID = $ID; return $this; } @@ -43,9 +51,28 @@ public function getNamespace(): string return $this->Namespace; } - public function setNamespace(string $namespace): self + public function setNamespace(string $Namespace): self { - $this->Namespace = $namespace; + $this->Namespace = $Namespace; return $this; } + + public static function jsonUnserialize(\stdClass $decoded): self + { + $n = new self(); + foreach ((array)$decoded as $k => $v) { + $n->{$k} = $v; + } + return $n; + } + + public function jsonSerialize(): \stdClass + { + $out = $this->_startJsonSerialize(); + $out->ID = $this->ID; + if ('' !== $this->Namespace) { + $out->Namespace = $this->Namespace; + } + return $out; + } } diff --git a/src/Session/SessionClient.php b/src/Session/SessionClient.php index 3c997a0c..54026fa6 100644 --- a/src/Session/SessionClient.php +++ b/src/Session/SessionClient.php @@ -21,16 +21,16 @@ */ use DCarbone\Go\HTTP; -use DCarbone\PHPConsulAPI\AbstractClient; -use DCarbone\PHPConsulAPI\Error; +use DCarbone\PHPConsulAPI\PHPLib\AbstractClient; +use DCarbone\PHPConsulAPI\PHPLib\Error; +use DCarbone\PHPConsulAPI\PHPLib\ValuedWriteStringResponse; +use DCarbone\PHPConsulAPI\PHPLib\WriteResponse; use DCarbone\PHPConsulAPI\QueryOptions; -use DCarbone\PHPConsulAPI\ValuedWriteStringResponse; use DCarbone\PHPConsulAPI\WriteOptions; -use DCarbone\PHPConsulAPI\WriteResponse; class SessionClient extends AbstractClient { - public function CreateNoChecks(?SessionEntry $sessionEntry = null, ?WriteOptions $opts = null): ValuedWriteStringResponse + public function CreateNoChecks(null|SessionEntry $sessionEntry = null, null|WriteOptions $opts = null): ValuedWriteStringResponse { if (null === $sessionEntry) { $body = new SessionEntry(); @@ -45,17 +45,17 @@ public function CreateNoChecks(?SessionEntry $sessionEntry = null, ?WriteOptions return $this->_create('v1/session/create', $body, $opts); } - public function Create(?SessionEntry $sessionEntry = null, ?WriteOptions $opts = null): ValuedWriteStringResponse + public function Create(null|SessionEntry $sessionEntry = null, null|WriteOptions $opts = null): ValuedWriteStringResponse { return $this->_create('v1/session/create', $sessionEntry, $opts); } - public function Destroy(string $id, ?WriteOptions $opts = null): WriteResponse + public function Destroy(string $id, null|WriteOptions $opts = null): WriteResponse { return $this->_executePut(sprintf('v1/session/destroy/%s', $id), null, $opts); } - public function Renew(string $id, ?WriteOptions $opts = null): SessionEntriesWriteResponse + public function Renew(string $id, null|WriteOptions $opts = null): SessionEntriesWriteResponse { $ret = new SessionEntriesWriteResponse(); @@ -87,22 +87,22 @@ public function Renew(string $id, ?WriteOptions $opts = null): SessionEntriesWri return $ret; } - public function Info(string $id, ?QueryOptions $opts = null): SessionEntriesQueryResponse + public function Info(string $id, null|QueryOptions $opts = null): SessionEntriesQueryResponse { return $this->_get(sprintf('v1/session/info/%s', $id), $opts); } - public function Node(string $node, ?QueryOptions $opts = null): SessionEntriesQueryResponse + public function Node(string $node, null|QueryOptions $opts = null): SessionEntriesQueryResponse { return $this->_get(sprintf('v1/session/node/%s', $node), $opts); } - public function List(?QueryOptions $opts = null): SessionEntriesQueryResponse + public function List(null|QueryOptions $opts = null): SessionEntriesQueryResponse { return $this->_get('v1/session/list', $opts); } - private function _get(string $path, ?QueryOptions $opts): SessionEntriesQueryResponse + private function _get(string $path, null|QueryOptions $opts): SessionEntriesQueryResponse { $resp = $this->_requireOK($this->_doGet($path, $opts)); $ret = new SessionEntriesQueryResponse(); @@ -110,7 +110,7 @@ private function _get(string $path, ?QueryOptions $opts): SessionEntriesQueryRes return $ret; } - private function _create(string $path, SessionEntry $entry, ?WriteOptions $opts): ValuedWriteStringResponse + private function _create(string $path, SessionEntry $entry, null|WriteOptions $opts): ValuedWriteStringResponse { $resp = $this->_requireOK($this->_doPut($path, $entry->_toAPIPayload(), $opts)); $ret = new ValuedWriteStringResponse(); @@ -128,7 +128,7 @@ private function _create(string $path, SessionEntry $entry, ?WriteOptions $opts) return $ret; } - $ret->Value = $dec->Decoded['ID'] ?? ''; + $ret->Value = $dec->Decoded->ID ?? ''; return $ret; } } diff --git a/src/Session/SessionEntriesQueryResponse.php b/src/Session/SessionEntriesQueryResponse.php index 6ebeda8b..2c856833 100644 --- a/src/Session/SessionEntriesQueryResponse.php +++ b/src/Session/SessionEntriesQueryResponse.php @@ -20,23 +20,27 @@ limitations under the License. */ -use DCarbone\PHPConsulAPI\AbstractValuedQueryResponse; -use DCarbone\PHPConsulAPI\UnmarshalledResponseInterface; +use DCarbone\PHPConsulAPI\PHPLib\AbstractValuedQueryResponse; +use DCarbone\PHPConsulAPI\PHPLib\UnmarshalledResponseInterface; class SessionEntriesQueryResponse extends AbstractValuedQueryResponse implements UnmarshalledResponseInterface { - public ?array $SessionEntries = []; + /** @var \DCarbone\PHPConsulAPI\Session\SessionEntry[] */ + public array $SessionEntries = []; - public function getValue(): ?array + /** + * @return \DCarbone\PHPConsulAPI\Session\SessionEntry[] + */ + public function getValue(): array { return $this->SessionEntries; } - public function unmarshalValue(mixed $decodedData): void + public function unmarshalValue(mixed $decoded): void { $this->SessionEntries = []; - foreach ($decodedData as $datum) { - $this->SessionEntries[] = new SessionEntry($datum); + foreach ($decoded as $datum) { + $this->SessionEntries[] = SessionEntry::jsonUnserialize($datum); } } } diff --git a/src/Session/SessionEntriesWriteResponse.php b/src/Session/SessionEntriesWriteResponse.php index b5ce2916..5e67ab3d 100644 --- a/src/Session/SessionEntriesWriteResponse.php +++ b/src/Session/SessionEntriesWriteResponse.php @@ -20,23 +20,27 @@ limitations under the License. */ -use DCarbone\PHPConsulAPI\AbstractValuedWriteResponse; -use DCarbone\PHPConsulAPI\UnmarshalledResponseInterface; +use DCarbone\PHPConsulAPI\PHPLib\AbstractValuedWriteResponse; +use DCarbone\PHPConsulAPI\PHPLib\UnmarshalledResponseInterface; class SessionEntriesWriteResponse extends AbstractValuedWriteResponse implements UnmarshalledResponseInterface { - public ?array $SessionEntries = null; + /** @var \DCarbone\PHPConsulAPI\Session\SessionEntry[] */ + public array $SessionEntries = []; - public function getValue(): ?array + /** + * @return \DCarbone\PHPConsulAPI\Session\SessionEntry[] + */ + public function getValue(): array { return $this->SessionEntries; } - public function unmarshalValue(mixed $decodedData): void + public function unmarshalValue(mixed $decoded): void { $this->SessionEntries = []; - foreach ($decodedData as $datum) { - $this->SessionEntries[] = new SessionEntry($datum); + foreach ($decoded as $datum) { + $this->SessionEntries[] = SessionEntry::jsonUnserialize($datum); } } } diff --git a/src/Session/SessionEntry.php b/src/Session/SessionEntry.php index e269c2b1..c152a91c 100644 --- a/src/Session/SessionEntry.php +++ b/src/Session/SessionEntry.php @@ -21,53 +21,55 @@ */ use DCarbone\Go\Time; -use DCarbone\PHPConsulAPI\AbstractModel; -use DCarbone\PHPConsulAPI\Transcoding; +use DCarbone\PHPConsulAPI\PHPLib\AbstractType; +use function DCarbone\PHPConsulAPI\PHPLib\dur_to_millisecond; -use function DCarbone\PHPConsulAPI\dur_to_millisecond; - -class SessionEntry extends AbstractModel +class SessionEntry extends AbstractType { - protected const FIELDS = [ - self::FIELD_LOCK_DELAY => [ - Transcoding::FIELD_UNMARSHAL_CALLBACK => Transcoding::UNMARSHAL_DURATION, - ], - self::FIELD_SERVICE_CHECKS => [ - Transcoding::FIELD_TYPE => Transcoding::ARRAY, - Transcoding::FIELD_CLASS => ServiceCheck::class, - Transcoding::FIELD_ARRAY_TYPE => Transcoding::OBJECT, - ], - self::FIELD_NAMESPACE => Transcoding::OMITEMPTY_STRING_FIELD, - ]; - - private const FIELD_NAME = 'Name'; - private const FIELD_NODE = 'Node'; - private const FIELD_LOCK_DELAY = 'LockDelay'; - private const FIELD_CHECKS = 'Checks'; - private const FIELD_NODE_CHECKS = 'NodeChecks'; - private const FIELD_SERVICE_CHECKS = 'ServiceChecks'; - private const FIELD_BEHAVIOR = 'Behavior'; - private const FIELD_TTL = 'TTL'; - private const FIELD_NAMESPACE = 'Namespace'; - - public int $CreateIndex = 0; - public string $ID = ''; - public string $Name = ''; - public string $Node = ''; + public int $CreateIndex; + public string $ID; + public string $Name; + public string $Node; public Time\Duration $LockDelay; - public string $Behavior = ''; - public string $TTL = ''; - public string $Namespace = ''; - public array $Checks = []; - public array $NodeChecks = []; - public array $ServiceChecks = []; - - public function __construct(?array $data = null) - { - parent::__construct($data); - if (!isset($this->LockDelay)) { - $this->LockDelay = new Time\Duration(0); - } + public string $Behavior; + public string $TTL; + public string $Namespace; + /** @var array */ + public array $Checks; + /** @var array */ + public array $NodeChecks; + /** @var array */ + public array $ServiceChecks; + + /** + * @param array $Checks + * @param array $NodeChecks + * @param array $ServiceChecks + */ + public function __construct( + int $CreateIndex = 0, + string $ID = '', + string $Name = '', + string $Node = '', + null|string|int|float|\DateInterval|Time\Duration $LockDelay = null, + string $Behavior = '', + string $TTL = '', + string $Namespace = '', + array $Checks = [], + array $NodeChecks = [], + array $ServiceChecks = [], + ) { + $this->CreateIndex = $CreateIndex; + $this->ID = $ID; + $this->Name = $Name; + $this->Node = $Node; + $this->LockDelay = null === $LockDelay ? new Time\Duration(0) : Time::Duration($LockDelay); + $this->Behavior = $Behavior; + $this->TTL = $TTL; + $this->Namespace = $Namespace; + $this->Checks = $Checks; + $this->setNodeChecks(...$NodeChecks); + $this->setServiceChecks(...$ServiceChecks); } public function getCreateIndex(): int @@ -119,9 +121,9 @@ public function getLockDelay(): Time\Duration return $this->LockDelay; } - public function setLockDelay(Time\Duration $LockDelay): self + public function setLockDelay(null|string|int|float|\DateInterval|Time\Duration $LockDelay): self { - $this->LockDelay = $LockDelay; + $this->LockDelay = Time::Duration($LockDelay); return $this; } @@ -158,68 +160,119 @@ public function setNamespace(string $Namespace): self return $this; } + /** + * @return array + */ public function getChecks(): array { return $this->Checks; } - public function setChecks(array $Checks): self + public function setChecks(string ...$Checks): self { $this->Checks = $Checks; return $this; } + /** + * @return array + */ public function getNodeChecks(): array { return $this->NodeChecks; } - public function setNodeChecks(array $NodeChecks): self + public function setNodeChecks(string ...$NodeChecks): self { $this->NodeChecks = $NodeChecks; return $this; } + /** + * @return array + */ public function getServiceChecks(): array { return $this->ServiceChecks; } - public function setServiceChecks(array $ServiceChecks): self + public function setServiceChecks(ServiceCheck ...$ServiceChecks): self { $this->ServiceChecks = $ServiceChecks; return $this; } + /** + * @return array + */ public function _toAPIPayload(): array { $out = []; if ('' !== $this->Name) { - $out[self::FIELD_NAME] = $this->Name; + $out['Name'] = $this->Name; } if ('' !== $this->Node) { - $out[self::FIELD_NODE] = $this->Node; + $out['Node'] = $this->Node; } if (0 < $this->LockDelay->Nanoseconds()) { - $out[self::FIELD_LOCK_DELAY] = dur_to_millisecond($this->LockDelay); + $out['LockDelay'] = dur_to_millisecond($this->LockDelay); } if ([] !== $this->Checks) { - $out[self::FIELD_CHECKS] = $this->Checks; + $out['Checks'] = $this->Checks; } if ([] !== $this->NodeChecks) { - $out[self::FIELD_NODE_CHECKS] = $this->NodeChecks; + $out['NodeChecks'] = $this->NodeChecks; } if ([] !== $this->ServiceChecks) { - $out[self::FIELD_SERVICE_CHECKS] = $this->ServiceChecks; + $out['ServiceChecks'] = $this->ServiceChecks; } if ('' !== $this->Behavior) { - $out[self::FIELD_BEHAVIOR] = $this->Behavior; + $out['Behavior'] = $this->Behavior; } if ('' !== $this->TTL) { - $out[self::FIELD_TTL] = $this->TTL; + $out['TTL'] = $this->TTL; } return $out; } + + public static function jsonUnserialize(\stdClass $decoded): self + { + $n = new self(); + foreach ((array)$decoded as $k => $v) { + if ('LockDelay' === $k) { + $n->LockDelay = Time::Duration($v); + } elseif ('ServiceChecks' === $k) { + $n->ServiceChecks = []; + if (null !== $v) { + foreach ($v as $sc) { + $n->ServiceChecks[] = ServiceCheck::jsonUnserialize($sc); + } + } + } else { + $n->{$k} = $v; + } + } + return $n; + } + + public function jsonSerialize(): \stdClass + { + $out = $this->_startJsonSerialize(); + $out->CreateIndex = $this->CreateIndex; + $out->ID = $this->ID; + $out->Name = $this->Name; + $out->Node = $this->Node; + $out->LockDelay = (string)$this->LockDelay; + $out->Behavior = $this->Behavior; + $out->TTL = $this->TTL; + if ('' !== $this->Namespace) { + $out->Namespace = $this->Namespace; + } + $out->Checks = $this->Checks; + $out->NodeChecks = $this->NodeChecks; + $out->ServiceChecks = $this->ServiceChecks; + return $out; + } } diff --git a/src/Status/StatusClient.php b/src/Status/StatusClient.php index e66e6532..2f9ad65c 100644 --- a/src/Status/StatusClient.php +++ b/src/Status/StatusClient.php @@ -20,14 +20,14 @@ limitations under the License. */ -use DCarbone\PHPConsulAPI\AbstractClient; +use DCarbone\PHPConsulAPI\PHPLib\AbstractClient; +use DCarbone\PHPConsulAPI\PHPLib\ValuedStringResponse; +use DCarbone\PHPConsulAPI\PHPLib\ValuedStringsResponse; use DCarbone\PHPConsulAPI\QueryOptions; -use DCarbone\PHPConsulAPI\ValuedStringResponse; -use DCarbone\PHPConsulAPI\ValuedStringsResponse; class StatusClient extends AbstractClient { - public function LeaderWithQueryOptions(?QueryOptions $opts): ValuedStringResponse + public function LeaderWithQueryOptions(null|QueryOptions $opts): ValuedStringResponse { $resp = $this->_requireOK($this->_doGet('v1/status/leader', $opts)); $ret = new ValuedStringResponse(); @@ -40,7 +40,7 @@ public function Leader(): ValuedStringResponse return $this->LeaderWithQueryOptions(null); } - public function PeersWithQueryOptions(?QueryOptions $opts): ValuedStringsResponse + public function PeersWithQueryOptions(null|QueryOptions $opts): ValuedStringsResponse { $resp = $this->_requireOK($this->_doGet('v1/status/peers', $opts)); $ret = new ValuedStringsResponse(); diff --git a/src/Transcoding.php b/src/Transcoding.php deleted file mode 100644 index e19c92ac..00000000 --- a/src/Transcoding.php +++ /dev/null @@ -1,130 +0,0 @@ - self::OBJECT, self::FIELD_CLASS => FakeMap::class]; - public const DURATION_FIELD = [ - self::FIELD_TYPE => self::OBJECT, - self::FIELD_CLASS => Time\Duration::class, - ] + self::UNMARSHAL_DURATION; - - //-- common field type definitions with omitempty - - public const OMITEMPTY_FIELD = [self::FIELD_OMITEMPTY => true]; - - public const OMITEMPTY_STRING_FIELD = [self::FIELD_TYPE => self::STRING] + self::OMITEMPTY_FIELD; - public const OMITEMPTY_INTEGER_FIELD = [self::FIELD_TYPE => self::INTEGER] + self::OMITEMPTY_FIELD; - public const OMITEMPTY_DOUBLE_FIELD = [self::FIELD_TYPE => self::DOUBLE] + self::OMITEMPTY_FIELD; - public const OMITEMPTY_BOOLEAN_FIELD = [self::FIELD_TYPE => self::BOOLEAN] + self::OMITEMPTY_FIELD; - public const OMITEMPTY_STRING_ARRAY_FIELD = [ - self::FIELD_TYPE => self::ARRAY, - self::FIELD_ARRAY_TYPE => self::STRING, - ] + self::OMITEMPTY_FIELD; - public const OMITEMPTY_INTEGER_ARRAY_FIELD = [ - self::FIELD_TYPE => self::ARRAY, - self::FIELD_ARRAY_TYPE => self::INTEGER, - ] + self::OMITEMPTY_FIELD; - public const OMITEMPTY_MAP_FIELD = self::MAP_FIELD + self::OMITEMPTY_FIELD; - - public static function isScalar(string $type): bool - { - return \in_array($type, self::SCALAR, true); - } - - public static function unmarshalTime(object $instance, string $field, Time\Time|string $value): void - { - if ($value instanceof Time\Time) { - $instance->{$field} = clone $value; - return; - } - $instance->{$field} = Time\Time::createFromFormat(\DATE_RFC3339, $value); - } - - public static function unmarshalNullableTime(object $instance, string $field, Time\Time|string|null $value): void - { - if (null === $value) { - $instance->{$field} = null; - return; - } - self::unmarshalTime($instance, $field, $value); - } - - /** - * This accepts a multitude of $value types. See Time::Duration for implementation details. - * - * @param object $instance - * @param string $field - * @param mixed $value - */ - public static function unmarshalDuration(object $instance, string $field, mixed $value): void - { - $instance->{$field} = Time::Duration($value); - } - - public static function unmarshalNullableDuration(object $instance, string $field, mixed $value): void - { - if (null === $value) { - $instance->{$field} = null; - return; - } - self::unmarshalDuration($instance, $field, $value); - } -} diff --git a/src/Txn/CheckOp.php b/src/Txn/CheckOp.php new file mode 100644 index 00000000..2edcece9 --- /dev/null +++ b/src/Txn/CheckOp.php @@ -0,0 +1,33 @@ +setVerb($Verb); + if (null === $Check) { + $Check = new HealthCheck(); + } + $this->Check = $Check; + } + + public function getVerb(): CheckOp + { + return $this->Verb; + } + + public function setVerb(string|CheckOp $Verb): self + { + if (is_string($Verb)) { + $Verb = CheckOp::from($Verb); + } + $this->Verb = $Verb; + return $this; + } + + public function getCheck(): HealthCheck + { + return $this->Check; + } + + public function setCheck(HealthCheck $Check): self + { + $this->Check = $Check; + return $this; + } + + public static function jsonUnserialize(\stdClass $decoded): self + { + $n = new self(); + foreach ((array)$decoded as $k => $v) { + if ('Check' === $k) { + $n->Check = HealthCheck::jsonUnserialize($v); + } elseif ('Verb' === $k) { + $n->setVerb($v); + } else { + $n->{$k} = $v; + } + } + return $n; + } + + public function jsonSerialize(): \stdClass + { + $out = $this->_startJsonSerialize(); + $out->Verb = $this->Verb; + $out->Check = $this->Check; + return $out; + } +} diff --git a/src/Agent/TransparentProxyConfig.php b/src/Txn/KVOp.php similarity index 54% rename from src/Agent/TransparentProxyConfig.php rename to src/Txn/KVOp.php index eab35eb2..da973378 100644 --- a/src/Agent/TransparentProxyConfig.php +++ b/src/Txn/KVOp.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace DCarbone\PHPConsulAPI\Agent; +namespace DCarbone\PHPConsulAPI\Txn; /* Copyright 2016-2025 Daniel Carbone (daniel.p.carbone@gmail.com) @@ -20,21 +20,22 @@ limitations under the License. */ -use DCarbone\PHPConsulAPI\AbstractModel; - -class TransparentProxyConfig extends AbstractModel +enum KVOp: string { - public int $OutboundListenerPort = 0; - public bool $DialedDirectly = false; - - public function getOutboundListenerPort(): int - { - return $this->OutboundListenerPort; - } - - public function setOutboundListenerPort(int $OutboundListenerPort): TransparentProxyConfig - { - $this->OutboundListenerPort = $OutboundListenerPort; - return $this; - } + case KVSet = 'set'; + case KVDelete = 'delete'; + case KVDeleteCAS = 'delete-cas'; + case KVDeleteTree = 'delete-tree'; + case KVCAS = 'cas'; + case KVLock = 'lock'; + case KVUnlock = 'unlock'; + case KVGet = 'get'; + case KVGetOrEmpty = 'get-or-empty'; + case KVGetTree = 'get-tree'; + case KVCheckSession = 'check-session'; + case KVCheckIndex = 'check-index'; + case KVCheckNotExists = 'check-not-exists'; + + // Default case for when value is not set. + case UNDEFINED = ''; } diff --git a/src/KV/KVTxnAPIResponse.php b/src/Txn/KVTxnAPIResponse.php similarity index 60% rename from src/KV/KVTxnAPIResponse.php rename to src/Txn/KVTxnAPIResponse.php index d64b2515..c9cae3da 100644 --- a/src/KV/KVTxnAPIResponse.php +++ b/src/Txn/KVTxnAPIResponse.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace DCarbone\PHPConsulAPI\KV; +namespace DCarbone\PHPConsulAPI\Txn; /* Copyright 2016-2025 Daniel Carbone (daniel.p.carbone@gmail.com) @@ -20,24 +20,36 @@ limitations under the License. */ -use DCarbone\PHPConsulAPI\ErrorContainer; -use DCarbone\PHPConsulAPI\QueryMetaContainer; +use DCarbone\PHPConsulAPI\PHPLib\ErrorField; +use DCarbone\PHPConsulAPI\PHPLib\QueryMetaField; class KVTxnAPIResponse { - use QueryMetaContainer; - use ErrorContainer; + use QueryMetaField; + use ErrorField; public bool $OK = false; - public ?KVTxnResponse $KVTxnResponse = null; + public null|KVTxnResponse $KVTxnResponse = null; public function isOK(): bool { return $this->OK; } - public function getKVTxnResponse(): ?KVTxnResponse + public function setOK(bool $OK): self + { + $this->OK = $OK; + return $this; + } + + public function getKVTxnResponse(): null|KVTxnResponse { return $this->KVTxnResponse; } + + public function setKVTxnResponse(null|KVTxnResponse $KVTxnResponse): self + { + $this->KVTxnResponse = $KVTxnResponse; + return $this; + } } diff --git a/src/Txn/KVTxnOp.php b/src/Txn/KVTxnOp.php new file mode 100644 index 00000000..adc9ae32 --- /dev/null +++ b/src/Txn/KVTxnOp.php @@ -0,0 +1,186 @@ +Verb = $Verb; + $this->Key = $Key; + $this->Value = $Value; + $this->Flags = $Flags; + $this->Index = $Index; + $this->Session = $Session; + $this->Namespace = $Namespace; + $this->Partition = $Partition; + } + + public function getVerb(): KVOp + { + return $this->Verb; + } + + public function setVerb(string|KVOp $Verb): self + { + if (is_string($Verb)) { + $Verb = KVOp::from($Verb); + } + $this->Verb = $Verb; + return $this; + } + + public function getKey(): string + { + return $this->Key; + } + + public function setKey(string $Key): self + { + $this->Key = $Key; + return $this; + } + + public function getValue(): string + { + return $this->Value; + } + + public function setValue(string $Value): self + { + $this->Value = $Value; + return $this; + } + + public function getFlags(): int + { + return $this->Flags; + } + + public function setFlags(int $Flags): self + { + $this->Flags = $Flags; + return $this; + } + + public function getIndex(): int + { + return $this->Index; + } + + public function setIndex(int $Index): self + { + $this->Index = $Index; + return $this; + } + + public function getSession(): string + { + return $this->Session; + } + + public function setSession(string $Session): self + { + $this->Session = $Session; + return $this; + } + + public function getNamespace(): string + { + return $this->Namespace; + } + + public function setNamespace(string $Namespace): self + { + $this->Namespace = $Namespace; + return $this; + } + + public function getPartition(): string + { + return $this->Partition; + } + + public function setPartition(string $Partition): self + { + $this->Partition = $Partition; + return $this; + } + + public static function jsonUnserialize(\stdClass $decoded): self + { + $n = new self(); + foreach ((array)$decoded as $k => $v) { + if ('Verb' === $k) { + $n->Verb = KVOp::from($v); + } elseif ('Value' === $k) { + $val = base64_decode($v, true); + if (false === $val) { + throw new \DomainException(sprintf('Could not base64 decode value "%s"', $v)); + } + $n->Value = $val; + } else { + $n->{$k} = $v; + } + } + return $n; + } + + public function jsonSerialize(): \stdClass + { + $out = $this->_startJsonSerialize(); + $out->Verb = $this->Verb; + $out->Key = $this->Key; + $out->Value = $this->Value; + $out->Flags = $this->Flags; + $out->Index = $this->Index; + $out->Session = $this->Session; + if ('' !== $this->Namespace) { + $out->Namespace = $this->Namespace; + } + if ('' !== $this->Partition) { + $out->Partition = $this->Partition; + } + return $out; + } +} diff --git a/src/Txn/KVTxnResponse.php b/src/Txn/KVTxnResponse.php new file mode 100644 index 00000000..319dfa21 --- /dev/null +++ b/src/Txn/KVTxnResponse.php @@ -0,0 +1,100 @@ + */ + public array $Results; + /** @var array<\DCarbone\PHPConsulAPI\Txn\TxnError> */ + public array $Errors; + + /** + * @param array $Results + * @param array $Errors + */ + public function __construct( + array $Results = [], + array $Errors = [], + ) { + $this->setResults(...$Results); + $this->setErrors(...$Errors); + } + + /** + * @return array + */ + public function getResults(): array + { + return $this->Results; + } + + public function setResults(TxnResult ...$Results): self + { + $this->Results = $Results; + return $this; + } + + /** + * @return array + */ + public function getErrors(): array + { + return $this->Errors; + } + + public function setErrors(TxnError ...$Errors): self + { + $this->Errors = $Errors; + return $this; + } + + public static function jsonUnserialize(\stdClass $decoded): self + { + $n = new self(); + foreach ((array)$decoded as $k => $v) { + if ('Results' === $k) { + $n->Results = []; + foreach ($v as $vv) { + $n->Results[] = TxnResult::jsonUnserialize($vv); + } + } elseif ('Errors' === $k) { + $n->Errors = []; + foreach ($v as $vv) { + $n->Errors[] = TxnError::jsonUnserialize($vv); + } + } else { + $n->{$k} = $v; + } + } + return $n; + } + + public function jsonSerialize(): \stdClass + { + $out = $this->_startJsonSerialize(); + $out->Results = $this->Results; + $out->Errors = $this->Errors; + return $out; + } +} diff --git a/src/Txn/NodeOp.php b/src/Txn/NodeOp.php new file mode 100644 index 00000000..f97c7d98 --- /dev/null +++ b/src/Txn/NodeOp.php @@ -0,0 +1,33 @@ +setVerb($Verb); + if (null === $Node) { + $Node = new Node(); + } + $this->Node = $Node; + } + + public function getVerb(): NodeOp + { + return $this->Verb; + } + + public function setVerb(NodeOp|string $Verb): self + { + if (is_string($Verb)) { + $Verb = NodeOp::from($Verb); + } + $this->Verb = $Verb; + return $this; + } + + public function getNode(): Node + { + return $this->Node; + } + + public function setNode(Node $Node): self + { + $this->Node = $Node; + return $this; + } + + public static function jsonUnserialize(\stdClass $decoded): self + { + $n = new self(); + foreach ((array)$decoded as $k => $v) { + if ('Verb' === $k) { + $n->setVerb($v); + } elseif ('Node' === $k) { + $n->Node = Node::jsonUnserialize($v); + } else { + $n->{$k} = $v; + } + } + return $n; + } + + public function jsonSerialize(): \stdClass + { + $out = $this->_startJsonSerialize(); + $out->Verb = $this->Verb; + $out->Node = $this->Node; + return $out; + } +} diff --git a/src/Txn/ServiceOp.php b/src/Txn/ServiceOp.php new file mode 100644 index 00000000..6bc314c3 --- /dev/null +++ b/src/Txn/ServiceOp.php @@ -0,0 +1,33 @@ +setVerb($Verb); + $this->Node = $Node; + $this->Service = $Service ?? new AgentService(); + } + + public function getVerb(): ServiceOp + { + return $this->Verb; + } + + public function setVerb(string|ServiceOp $Verb): self + { + if (is_string($Verb)) { + $Verb = ServiceOp::from($Verb); + } + $this->Verb = $Verb; + return $this; + } + + public function getNode(): string + { + return $this->Node; + } + + public function setNode(string $Node): self + { + $this->Node = $Node; + return $this; + } + + public function getService(): AgentService + { + return $this->Service; + } + + public function setService(AgentService $Service): self + { + $this->Service = $Service; + return $this; + } + + public static function jsonUnserialize(\stdClass $decoded): self + { + $n = new self(); + foreach ((array)$decoded as $k => $v) { + if ('Verb' === $k) { + $n->setVerb($v); + } elseif ('Service' === $k) { + $n->Service = AgentService::jsonUnserialize($v); + } else { + $n->{$k} = $v; + } + } + return $n; + } + + public function jsonSerialize(): \stdClass + { + $out = $this->_startJsonSerialize(); + $out->Verb = $this->Verb; + $out->Node = $this->Node; + $out->Service = $this->Service; + return $out; + } +} diff --git a/src/KV/TxnError.php b/src/Txn/TxnError.php similarity index 58% rename from src/KV/TxnError.php rename to src/Txn/TxnError.php index d0add265..7c560ace 100644 --- a/src/KV/TxnError.php +++ b/src/Txn/TxnError.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace DCarbone\PHPConsulAPI\KV; +namespace DCarbone\PHPConsulAPI\Txn; /* Copyright 2016-2025 Daniel Carbone (daniel.p.carbone@gmail.com) @@ -20,12 +20,20 @@ limitations under the License. */ -use DCarbone\PHPConsulAPI\AbstractModel; +use DCarbone\PHPConsulAPI\PHPLib\AbstractType; -class TxnError extends AbstractModel +class TxnError extends AbstractType { - public int $OpIndex = 0; - public string $What = ''; + public int $OpIndex; + public string $What; + + public function __construct( + int $OpIndex = 0, + string $What = '', + ) { + $this->OpIndex = $OpIndex; + $this->What = $What; + } public function getOpIndex(): int { @@ -48,4 +56,21 @@ public function setWhat(string $What): self $this->What = $What; return $this; } + + public static function jsonUnserialize(\stdClass $decoded): self + { + $n = new self(); + foreach ((array)$decoded as $k => $v) { + $n->{$k} = $v; + } + return $n; + } + + public function jsonSerialize(): \stdClass + { + $out = $this->_startJsonSerialize(); + $out->OpIndex = $this->OpIndex; + $out->What = $this->What; + return $out; + } } diff --git a/src/Txn/TxnOp.php b/src/Txn/TxnOp.php new file mode 100644 index 00000000..6862813d --- /dev/null +++ b/src/Txn/TxnOp.php @@ -0,0 +1,124 @@ +KV = $KV; + $this->Node = $Node; + $this->Service = $Service; + $this->Check = $Check; + } + + public function getKV(): null|KVTxnOp + { + return $this->KV; + } + + public function setKV(null|KVTxnOp $KV): self + { + $this->KV = $KV; + return $this; + } + + public function getNode(): null|NodeTxnOp + { + return $this->Node; + } + + public function setNode(null|NodeTxnOp $Node): self + { + $this->Node = $Node; + return $this; + } + + public function getService(): null|ServiceTxnOp + { + return $this->Service; + } + + public function setService(null|ServiceTxnOp $Service): self + { + $this->Service = $Service; + return $this; + } + + public function getCheck(): null|CheckTxnOp + { + return $this->Check; + } + + public function setCheck(null|CheckTxnOp $Check): self + { + $this->Check = $Check; + return $this; + } + + public static function jsonUnserialize(\stdClass $decoded): self + { + $n = new self(); + foreach ((array)$decoded as $k => $v) { + if ('KV' === $k) { + $n->KV = null === $v ? null : KVTxnOp::jsonUnserialize($v); + } elseif ('Node' === $k) { + $n->Node = null === $v ? null : NodeTxnOp::jsonUnserialize($v); + } elseif ('Service' === $k) { + $n->Service = null === $v ? null : ServiceTxnOp::jsonUnserialize($v); + } elseif ('Check' === $k) { + $n->Check = null === $v ? null : CheckTxnOp::jsonUnserialize($v); + } else { + $n->{$k} = $v; + } + } + return $n; + } + + public function jsonSerialize(): \stdClass + { + $out = $this->_startJsonSerialize(); + if (null !== $this->KV) { + $out->KV = $this->KV; + } + if (null !== $this->Node) { + $out->Node = $this->Node; + } + if (null !== $this->Service) { + $out->Service = $this->Service; + } + if (null !== $this->Check) { + $out->Check = $this->Check; + } + return $out; + } +} diff --git a/src/Txn/TxnOps.php b/src/Txn/TxnOps.php new file mode 100644 index 00000000..343dafd5 --- /dev/null +++ b/src/Txn/TxnOps.php @@ -0,0 +1,106 @@ + + * @implements \IteratorAggregate + */ +class TxnOps extends AbstractType implements \Countable, \ArrayAccess, \IteratorAggregate +{ + /** @var array */ + private array $ops = []; + + /** + * @param array $ops + */ + public function __construct(array $ops = []) + { + $this->ops = $ops; + } + + public function count(): int + { + return \count($this->ops); + } + + public function offsetExists(mixed $offset): bool + { + return isset($this->ops[$offset]); + } + + public function offsetGet(mixed $offset): TxnOp + { + return $this->ops[$offset]; + } + + public function offsetSet(mixed $offset, mixed $value): void + { + if (null === $offset) { + $this->ops[] = $value; + } else { + $this->ops[$offset] = $value; + } + } + + public function offsetUnset(mixed $offset): void + { + unset($this->ops[$offset]); + } + + /** + * @return \ArrayIterator + */ + public function getIterator(): \ArrayIterator + { + return new \ArrayIterator($this->ops); + } + + /** + * @return array + */ + public function all(): array + { + return $this->ops; + } + + /** + * @param array<\stdClass> $decoded + */ + public static function jsonUnserialize(array $decoded): self + { + $n = new self(); + foreach ($decoded as $v) { + $n->ops[] = TxnOp::jsonUnserialize($v); + } + return $n; + } + + /** + * @return array + */ + public function jsonSerialize(): array + { + return $this->ops; + } +} diff --git a/src/Txn/TxnResponse.php b/src/Txn/TxnResponse.php new file mode 100644 index 00000000..354b15e2 --- /dev/null +++ b/src/Txn/TxnResponse.php @@ -0,0 +1,104 @@ + */ + public array $Results; + /** @var array */ + public array $Errors; + + /** + * @param array $Results + * @param array $Errors + */ + public function __construct( + array $Results = [], + array $Errors = [], + ) { + $this->setResults(...$Results); + $this->setErrors(...$Errors); + } + + /** + * @return array + */ + public function getResults(): array + { + return $this->Results; + } + + public function setResults(TxnResult ...$Results): self + { + $this->Results = $Results; + return $this; + } + + /** + * @return array + */ + public function getErrors(): array + { + return $this->Errors; + } + + public function setErrors(TxnError ...$Errors): self + { + $this->Errors = $Errors; + return $this; + } + + public static function jsonUnserialize(\stdClass $decoded): self + { + $n = new self(); + foreach ((array)$decoded as $k => $v) { + if ('Results' === $k) { + $n->Results = []; + if (null !== $v) { + foreach ($v as $vv) { + $n->Results[] = TxnResult::jsonUnserialize($vv); + } + } + } elseif ('Errors' === $k) { + $n->Errors = []; + if (null !== $v) { + foreach ($v as $vv) { + $n->Errors[] = TxnError::jsonUnserialize($vv); + } + } + } else { + $n->{$k} = $v; + } + } + return $n; + } + + public function jsonSerialize(): \stdClass + { + $out = $this->_startJsonSerialize(); + $out->Results = $this->Results; + $out->Errors = $this->Errors; + return $out; + } +} diff --git a/src/Txn/TxnResult.php b/src/Txn/TxnResult.php new file mode 100644 index 00000000..658fc9fe --- /dev/null +++ b/src/Txn/TxnResult.php @@ -0,0 +1,128 @@ +KV = $KV; + $this->Node = $Node; + $this->Service = $Service; + $this->Check = $Check; + } + + public function getKV(): null|KVPair + { + return $this->KV; + } + + public function setKV(null|KVPair $KV): self + { + $this->KV = $KV; + return $this; + } + + public function getNode(): null|Node + { + return $this->Node; + } + + public function setNode(null|Node $Node): self + { + $this->Node = $Node; + return $this; + } + + public function getService(): null|CatalogService + { + return $this->Service; + } + + public function setService(null|CatalogService $Service): self + { + $this->Service = $Service; + return $this; + } + + public function getCheck(): null|HealthCheck + { + return $this->Check; + } + + public function setCheck(null|HealthCheck $Check): self + { + $this->Check = $Check; + return $this; + } + + public static function jsonUnserialize(\stdClass $decoded): self + { + $n = new self(); + foreach ((array)$decoded as $k => $v) { + if ('KV' === $k) { + $n->KV = null === $v ? null : KVPair::jsonUnserialize($v); + } elseif ('Node' === $k) { + $n->Node = null === $v ? null : Node::jsonUnserialize($v); + } elseif ('Service' === $k) { + $n->Service = null === $v ? null : CatalogService::jsonUnserialize($v); + } elseif ('Check' === $k) { + $n->Check = null === $v ? null : HealthCheck::jsonUnserialize($v); + } else { + $n->{$k} = $v; + } + } + return $n; + } + + public function jsonSerialize(): \stdClass + { + $out = $this->_startJsonSerialize(); + if (null !== $this->KV) { + $out->KV = $this->KV; + } + if (null !== $this->Node) { + $out->Node = $this->Node; + } + if (null !== $this->Service) { + $out->Service = $this->Service; + } + if (null !== $this->Check) { + $out->Check = $this->Check; + } + return $out; + } +} diff --git a/src/Txn/TxnResults.php b/src/Txn/TxnResults.php new file mode 100644 index 00000000..ee9864d1 --- /dev/null +++ b/src/Txn/TxnResults.php @@ -0,0 +1,106 @@ + + * @implements \IteratorAggregate + */ +class TxnResults extends AbstractType implements \Countable, \ArrayAccess, \IteratorAggregate +{ + /** @var array */ + private array $results = []; + + /** + * @param array $results + */ + public function __construct(array $results = []) + { + $this->results = $results; + } + + public function count(): int + { + return \count($this->results); + } + + public function offsetExists(mixed $offset): bool + { + return isset($this->results[$offset]); + } + + public function offsetGet(mixed $offset): TxnResult + { + return $this->results[$offset]; + } + + public function offsetSet(mixed $offset, mixed $value): void + { + if (null === $offset) { + $this->results[] = $value; + } else { + $this->results[$offset] = $value; + } + } + + public function offsetUnset(mixed $offset): void + { + unset($this->results[$offset]); + } + + /** + * @return \ArrayIterator + */ + public function getIterator(): \ArrayIterator + { + return new \ArrayIterator($this->results); + } + + /** + * @return array + */ + public function all(): array + { + return $this->results; + } + + /** + * @param array<\stdClass> $decoded + */ + public static function jsonUnserialize(array $decoded): self + { + $n = new self(); + foreach ($decoded as $v) { + $n->results[] = TxnResult::jsonUnserialize($v); + } + return $n; + } + + /** + * @return array + */ + public function jsonSerialize(): array + { + return $this->results; + } +} diff --git a/src/Unmarshaller.php b/src/Unmarshaller.php deleted file mode 100644 index 5b55c234..00000000 --- a/src/Unmarshaller.php +++ /dev/null @@ -1,277 +0,0 @@ -unmarshalComplex($field, $value, static::FIELDS[$field]); - } elseif (!property_exists($this, $field)) { - // if the field isn't explicitly defined on the implementing class, just set it to whatever the incoming - // value is - $this->{$field} = $value; - } elseif (null !== $value) { - // at this point, value must be non-null to be operable - if (isset($this->{$field}) && is_scalar($this->{$field})) { - // if the property has a scalar default value, unmarshal it as such. - $this->unmarshalScalar($field, $value, false); - } else { - // if we fall down here, try to set the value as-is. if this barfs, it indicates we have a bug to be - // squished. - // todo: should this be an exception? - $this->{$field} = $value; - } - } - - // if the value is null at this point, ignore and move on. - // note: this is not checked prior to the property_exists call as if the field is not explicitly defined but - // is seen with a null value, we still want to define it as null on the implementing type. - } - - protected function fieldIsNullable(array $fieldDef): bool - { - // todo: make sure this key is always a bool... - return $fieldDef[Transcoding::FIELD_NULLABLE] ?? false; - } - - protected static function scalarZeroVal(string $type): float|bool|int|string|null - { - return match ($type) { - Transcoding::STRING => '', - Transcoding::INTEGER => 0, - Transcoding::DOUBLE => 0.0, - Transcoding::BOOLEAN => false, - default => null, - }; - } - - private function buildScalarValue(string $field, mixed $value, string $type, bool $nullable): float|bool|int|string|null - { - if (null === $value) { - return $nullable ? null : self::scalarZeroVal($type); - } - - return match ($type) { - Transcoding::STRING => (string)$value, - Transcoding::INTEGER => \intval($value, 10), - Transcoding::DOUBLE => (float)$value, - Transcoding::BOOLEAN => (bool)$value, - - // if we fall down to here, default to try to set the value to whatever it happens to be. - default => $value, - }; - } - - private function buildObjectValue(string $field, null|object|array $value, string $class, bool $nullable): ?object - { - // if the incoming value is null... - if (null === $value) { - return $nullable ? null : new $class([]); - } - // if the incoming value is already an instance of the class, clone it and return - if ($value instanceof $class) { - return clone $value; - } - // otherwise, attempt to cast whatever was provided as an array and construct a new instance of $class - if (KVPair::class === $class || KVTxnOp::class === $class || UserEvent::class === $class) { - // special case for KVPair and KVTxnOp - // todo: find cleaner way to do this... - return new $class((array)$value, true); - } - return new $class((array)$value); - } - - private function unmarshalScalar(string $field, mixed $value, bool $nullable): void - { - $this->{$field} = $this->buildScalarValue( - $field, - $value, - isset($this->{$field}) ? \gettype($this->{$field}) : Transcoding::MIXED, - $nullable - ); - } - - private function unmarshalComplex(string $field, mixed $value, array $def): void - { - // check if a callable has been defined - if (isset($def[Transcoding::FIELD_UNMARSHAL_CALLBACK])) { - $cb = $def[Transcoding::FIELD_UNMARSHAL_CALLBACK]; - // allow for using a "setter" method - if (\is_string($cb) && method_exists($this, $cb)) { - $this->{$cb}($value); - return; - } - // handle all other callable input - $err = \call_user_func($def[Transcoding::FIELD_UNMARSHAL_CALLBACK], $this, $field, $value); - if (false === $err) { - throw new \RuntimeException( - sprintf( - 'Error calling hydration callback "%s" for field "%s" on class "%s"', - var_export($def[Transcoding::FIELD_UNMARSHAL_CALLBACK], true), - $field, - static::class - ) - ); - } - return; - } - - // try to determine field type by first looking up the field in the definition map, then by inspecting the - // the field's default value. - // - // objects _must_ have an entry in the map, as they are either un-initialized at class instantiation time or - // set to "NULL", at which point we cannot automatically determine the value type. - - if (isset($def[Transcoding::FIELD_TYPE])) { - // if the field has a FIELD_TYPE value in the definition map - $fieldType = $def[Transcoding::FIELD_TYPE]; - } elseif (isset($this->{$field})) { - // if the field is set and non-null - $fieldType = \gettype($this->{$field}); - } else { - throw new \LogicException( - sprintf( - 'Field "%s" on type "%s" is missing a FIELD_TYPE hydration entry: %s', - $field, - static::class, - var_export($def, true) - ) - ); - } - - if (Transcoding::OBJECT === $fieldType) { - $this->unmarshalObject($field, $value, $def); - return; - } - - if (Transcoding::ARRAY === $fieldType) { - $this->unmarshalArray($field, $value, $def); - return; - } - - // at this point, assume scalar - // todo: handle non-scalar types here - $this->unmarshalScalar($field, $value, self::fieldIsNullable($def)); - } - - private function unmarshalObject(string $field, mixed $value, array $def): void - { - if (!isset($def[Transcoding::FIELD_CLASS])) { - throw new \LogicException( - sprintf( - 'Field "%s" on type "%s" is missing FIELD_CLASS hydration entry: %s', - $field, - static::class, - var_export($def, true) - ) - ); - } - - $this->{$field} = $this->buildObjectValue( - $field, - $value, - $def[Transcoding::FIELD_CLASS], - self::fieldIsNullable($def) - ); - } - - private function unmarshalArray(string $field, mixed $value, array $def): void - { - // attempt to extract the two possible keys - $type = $def[Transcoding::FIELD_ARRAY_TYPE] ?? null; - $class = $def[Transcoding::FIELD_CLASS] ?? null; - - // type is required - if (null === $type) { - throw new \DomainException( - sprintf( - 'Field "%s" on type "%s" definition is missing FIELD_ARRAY_TYPE value: %s', - $field, - static::class, - var_export($def, true) - ) - ); - } - - // is the incoming value null? - if (null === $value) { - // if this value can be null'd, allow it. - if (static::fieldIsNullable($def)) { - $this->{$field} = null; - } - return; - } - - // by the time we get here, $value must be an array - if (!\is_array($value)) { - throw new \RuntimeException( - sprintf( - 'Field "%s" on type "%s" is an array but provided value is "%s"', - $field, - static::class, - \gettype($value) - ) - ); - } - - // currently the only supported array types are scalar or objects. everything else will require - // a custom callback for hydration purposes. - - if (Transcoding::OBJECT === $type) { - if (null === $class) { - throw new \DomainException( - sprintf( - 'Field "%s" on type "%s" definition is missing FIELD_CLASS value: %s', - $field, - static::class, - var_export($def, true) - ) - ); - } - - foreach ($value as $k => $v) { - // short circuit to prevent additional func call - if (null === $v) { - $this->{$field}[$k] = null; - } else { - $this->{$field}[$k] = $this->buildObjectValue($field, $v, $class, false); - } - } - } else { - // in all other cases, just set as-is - foreach ($value as $k => $v) { - // short circuit to prevent additional func call - if (null === $v) { - $this->{$field}[$k] = null; - } else { - $this->{$field}[$k] = $this->buildScalarValue($field, $v, $type, false); - } - } - } - } -} diff --git a/src/WriteMeta.php b/src/WriteMeta.php index 326960ec..c92c3ffa 100644 --- a/src/WriteMeta.php +++ b/src/WriteMeta.php @@ -24,9 +24,14 @@ class WriteMeta { - public ?Time\Duration $RequestTime = null; + public Time\Duration $RequestTime; - public function getRequestTime(): ?Time\Duration + public function __construct(null|string|int|float|\DateInterval|Time\Duration $RequestTime) + { + $this->RequestTime = Time::Duration($RequestTime); + } + + public function getRequestTime(): Time\Duration { return $this->RequestTime; } diff --git a/src/WriteOptions.php b/src/WriteOptions.php index 6b750702..c1690d5d 100644 --- a/src/WriteOptions.php +++ b/src/WriteOptions.php @@ -21,22 +21,30 @@ */ use DCarbone\Go\Time; +use DCarbone\PHPConsulAPI\PHPLib\Request; +use DCarbone\PHPConsulAPI\PHPLib\RequestOptions; -class WriteOptions extends AbstractModel implements RequestOptions +class WriteOptions implements RequestOptions { - public string $Namespace = ''; - public string $Datacenter = ''; - public string $Token = ''; - public int $RelayFactor = 0; - - public ?Time\Duration $Timeout = null; - - public function __construct(?array $data = null) - { - parent::__construct($data); - if (!($this->Timeout instanceof Time\Duration)) { - $this->Timeout = Time::Duration($this->Timeout); - } + public string $Namespace; + public string $Datacenter; + public string $Token; + public int $RelayFactor; + + public Time\Duration $Timeout; + + public function __construct( + string $Namespace = '', + string $Datacenter = '', + string $Token = '', + int $RelayFactor = 0, + null|int|float|string|\DateInterval|Time\Duration $Timeout = null, + ) { + $this->Namespace = $Namespace; + $this->Datacenter = $Datacenter; + $this->Token = $Token; + $this->RelayFactor = $RelayFactor; + $this->Timeout = Time::Duration($Timeout); } public function getNamespace(): string @@ -44,9 +52,10 @@ public function getNamespace(): string return $this->Namespace; } - public function setNamespace(string $namespace): void + public function setNamespace(string $namespace): self { $this->Namespace = $namespace; + return $this; } public function getDatacenter(): string @@ -54,9 +63,10 @@ public function getDatacenter(): string return $this->Datacenter; } - public function setDatacenter(string $datacenter): void + public function setDatacenter(string $datacenter): self { $this->Datacenter = $datacenter; + return $this; } public function getToken(): string @@ -64,9 +74,10 @@ public function getToken(): string return $this->Token; } - public function setToken(string $token): void + public function setToken(string $token): self { $this->Token = $token; + return $this; } public function getRelayFactor(): int @@ -74,19 +85,21 @@ public function getRelayFactor(): int return $this->RelayFactor; } - public function setRelayFactor(int $relayFactor): void + public function setRelayFactor(int $relayFactor): self { $this->RelayFactor = $relayFactor; + return $this; } - public function getTimeout(): ?Time\Duration + public function getTimeout(): null|Time\Duration { return $this->Timeout; } - public function setTimeout(float|int|string|Time\Duration|null $timeout): void + public function setTimeout(null|int|float|string|\DateInterval|Time\Duration $timeout): self { $this->Timeout = Time::Duration($timeout); + return $this; } public function apply(Request $r): void @@ -101,10 +114,9 @@ public function apply(Request $r): void $r->header->set('X-Consul-Token', $this->Token); } if (0 !== $this->RelayFactor) { - $r->params->set('relay-factor', (string) $this->RelayFactor); + $r->params->set('relay-factor', (string)$this->RelayFactor); } - - if (null !== $this->Timeout) { + if (0 < $this->Timeout->Nanoseconds()) { $r->timeout = $this->Timeout; } } diff --git a/src/funcs.php b/src/funcs.php deleted file mode 100644 index 8d088c0f..00000000 --- a/src/funcs.php +++ /dev/null @@ -1,35 +0,0 @@ -Nanoseconds(); - $ms = $dur->Milliseconds(); - - if (0 < $ns && 0 === (int)$ms) { - $ms = 1; - } - - return sprintf('%dms', $ms); -} diff --git a/tests/ConsulManager.php b/tests/ConsulManager.php index f34ebb03..20f8b3ca 100644 --- a/tests/ConsulManager.php +++ b/tests/ConsulManager.php @@ -33,6 +33,9 @@ final class ConsulManager public const PID_FILE = self::TMP_DIR . '/consul.pid'; + public const CONFIG_FILE = __DIR__ . '/consul.hcl'; + public const MANAGEMENT_TOKEN = '00000000-0000-0000-0000-000000000001'; + /** * Start up single instance of Consul Agent with specified flags * @@ -40,14 +43,14 @@ final class ConsulManager */ public static function startSingle(string $flags): void { - if (\file_exists(self::PID_FILE)) { + if (file_exists(self::PID_FILE)) { self::stopSingle(); } - \shell_exec(self::START_SINGLE_CMD . " {$flags}"); + shell_exec(self::START_SINGLE_CMD . " {$flags}"); // sleep to allow consul to setup - \sleep(3); + sleep(3); } /** @@ -58,28 +61,36 @@ public static function startSingleDev(): void self::startSingle('-dev'); } + /** + * Start a single instance of a consul agent in "-dev" mode with ACL config + */ + public static function startSingleDevACL(): void + { + self::startSingle('-dev -config-file=' . self::CONFIG_FILE); + } + /** * Stop running instance */ public static function stopSingle(): void { - if (\file_exists(self::PID_FILE)) { - \shell_exec(self::STOP_SINGLE_CMD); - if (\file_exists(self::PID_FILE)) { - \unlink(self::PID_FILE); - } - \sleep(1); + if (file_exists(self::PID_FILE)) { + shell_exec(self::STOP_SINGLE_CMD); + unlink(self::PID_FILE); + sleep(1); } } /** + * @param string $Token * @return \DCarbone\PHPConsulAPI\Config */ - public static function testConfig(): Config + public static function testConfig(string $Token = ''): Config { - $conf = new Config(); - $conf->Address = '127.0.0.1:8500'; - $conf->Scheme = 'http'; - return $conf; + return new Config( + Address: '127.0.0.1:8500', + Scheme: 'http', + Token: $Token, + ); } } diff --git a/tests/Unit/ACL/ACLAuthMethodListEntryTest.php b/tests/Unit/ACL/ACLAuthMethodListEntryTest.php new file mode 100644 index 00000000..2f27b11e --- /dev/null +++ b/tests/Unit/ACL/ACLAuthMethodListEntryTest.php @@ -0,0 +1,60 @@ +getName()); + self::assertSame('', $e->getType()); + self::assertSame('', $e->getDisplayName()); + self::assertSame('', $e->getDescription()); + self::assertSame(0, $e->getMaxTokenTTL()->Nanoseconds()); + self::assertSame('', $e->getTokenLocality()); + self::assertSame(0, $e->getCreateIndex()); + self::assertSame(0, $e->getModifyIndex()); + self::assertSame('', $e->getNamespace()); + } + + public function testConstructorWithParams(): void + { + $e = new ACLAuthMethodListEntry(Name: 'auth', Type: 'jwt', DisplayName: 'JWT Auth'); + self::assertSame('auth', $e->getName()); + self::assertSame('jwt', $e->getType()); + self::assertSame('JWT Auth', $e->getDisplayName()); + } + + public function testJsonSerialize(): void + { + $e = new ACLAuthMethodListEntry(Name: 'auth', Type: 'jwt'); + $out = $e->jsonSerialize(); + self::assertSame('auth', $out->Name); + self::assertSame('jwt', $out->Type); + } + + public function testJsonUnserialize(): void + { + $d = new \stdClass(); + $d->Name = 'auth'; + $d->Type = 'kubernetes'; + $d->DisplayName = 'K8s'; + $d->Description = ''; + $d->MaxTokenTTL = '10m0s'; + $d->TokenLocality = 'local'; + $d->CreateIndex = 5; + $d->ModifyIndex = 10; + $e = ACLAuthMethodListEntry::jsonUnserialize($d); + self::assertSame('auth', $e->getName()); + self::assertSame('kubernetes', $e->getType()); + self::assertSame(5, $e->getCreateIndex()); + } +} + diff --git a/tests/Unit/ACL/ACLAuthMethodNamespaceRuleTest.php b/tests/Unit/ACL/ACLAuthMethodNamespaceRuleTest.php new file mode 100644 index 00000000..4d3985b8 --- /dev/null +++ b/tests/Unit/ACL/ACLAuthMethodNamespaceRuleTest.php @@ -0,0 +1,62 @@ +getSelector()); + self::assertSame('', $r->getBindNamespace()); + } + + public function testConstructorWithParams(): void + { + $r = new ACLAuthMethodNamespaceRule(Selector: 'sel', BindNamespace: 'ns'); + self::assertSame('sel', $r->getSelector()); + self::assertSame('ns', $r->getBindNamespace()); + } + + public function testFluentSetters(): void + { + $r = new ACLAuthMethodNamespaceRule(); + $result = $r->setSelector('s')->setBindNamespace('b'); + self::assertSame($r, $result); + self::assertSame('s', $r->getSelector()); + self::assertSame('b', $r->getBindNamespace()); + } + + public function testJsonSerializeOmitsEmptyFields(): void + { + $r = new ACLAuthMethodNamespaceRule(); + $out = $r->jsonSerialize(); + self::assertObjectNotHasProperty('Selector', $out); + self::assertObjectNotHasProperty('BindNamespace', $out); + } + + public function testJsonSerializeIncludesNonEmptyFields(): void + { + $r = new ACLAuthMethodNamespaceRule(Selector: 's', BindNamespace: 'b'); + $out = $r->jsonSerialize(); + self::assertSame('s', $out->Selector); + self::assertSame('b', $out->BindNamespace); + } + + public function testJsonUnserialize(): void + { + $d = new \stdClass(); + $d->Selector = 'sel'; + $d->BindNamespace = 'ns'; + $r = ACLAuthMethodNamespaceRule::jsonUnserialize($d); + self::assertSame('sel', $r->getSelector()); + self::assertSame('ns', $r->getBindNamespace()); + } +} + diff --git a/tests/Unit/ACL/ACLAuthMethodTest.php b/tests/Unit/ACL/ACLAuthMethodTest.php new file mode 100644 index 00000000..1e4b9fd0 --- /dev/null +++ b/tests/Unit/ACL/ACLAuthMethodTest.php @@ -0,0 +1,121 @@ +getName()); + self::assertSame('', $m->getType()); + self::assertSame('', $m->getDisplayName()); + self::assertSame('', $m->getDescription()); + self::assertSame(0, $m->getMaxTokenTTL()->Nanoseconds()); + self::assertSame('', $m->getTokenLocality()); + self::assertSame([], $m->getConfig()); + self::assertSame(0, $m->getCreateIndex()); + self::assertSame(0, $m->getModifyIndex()); + self::assertSame([], $m->getNamespaceRules()); + self::assertSame('', $m->getNamespace()); + self::assertSame('', $m->getPartition()); + } + + public function testConstructorWithParams(): void + { + $rule = new ACLAuthMethodNamespaceRule(Selector: 'sel', BindNamespace: 'ns'); + $m = new ACLAuthMethod( + Name: 'auth-1', + Type: 'kubernetes', + DisplayName: 'K8s Auth', + Description: 'desc', + MaxTokenTTL: '5m', + TokenLocality: 'local', + Config: ['Host' => 'https://k8s.example.com'], + CreateIndex: 1, + ModifyIndex: 2, + NamespaceRules: [$rule], + Namespace: 'ns', + Partition: 'pt', + ); + self::assertSame('auth-1', $m->getName()); + self::assertSame('kubernetes', $m->getType()); + self::assertSame('K8s Auth', $m->getDisplayName()); + self::assertCount(1, $m->getNamespaceRules()); + self::assertSame('ns', $m->getNamespace()); + } + + public function testFluentSetters(): void + { + $m = new ACLAuthMethod(); + $result = $m->setName('n')->setType('t')->setDisplayName('d')->setDescription('desc') + ->setMaxTokenTTL('10m')->setTokenLocality('global') + ->setConfig(['key' => 'val'])->setCreateIndex(1)->setModifyIndex(2) + ->setNamespace('ns')->setPartition('pt'); + self::assertSame($m, $result); + self::assertSame('n', $m->getName()); + self::assertSame(['key' => 'val'], $m->getConfig()); + } + + public function testAddNamespaceRule(): void + { + $m = new ACLAuthMethod(); + $rule = new ACLAuthMethodNamespaceRule(Selector: 's', BindNamespace: 'bn'); + $m->addNamespaceRule($rule); + self::assertCount(1, $m->getNamespaceRules()); + self::assertSame($rule, $m->getNamespaceRules()[0]); + } + + public function testJsonSerialize(): void + { + $m = new ACLAuthMethod(Name: 'auth', Type: 'jwt', Config: ['key' => 'val']); + $out = $m->jsonSerialize(); + self::assertSame('auth', $out->Name); + self::assertSame(['key' => 'val'], $out->Config); + } + + public function testJsonSerializeOmitsEmptyOptionalFields(): void + { + $m = new ACLAuthMethod(Name: 'auth', Type: 'jwt'); + $out = $m->jsonSerialize(); + self::assertObjectNotHasProperty('DisplayName', $out); + self::assertObjectNotHasProperty('Description', $out); + self::assertObjectNotHasProperty('MaxTokenTTL', $out); + self::assertObjectNotHasProperty('TokenLocality', $out); + self::assertObjectNotHasProperty('NamespaceRules', $out); + self::assertObjectNotHasProperty('Namespace', $out); + self::assertObjectNotHasProperty('Partition', $out); + } + + public function testJsonUnserialize(): void + { + $d = new \stdClass(); + $d->Name = 'auth-u'; + $d->Type = 'kubernetes'; + $d->DisplayName = 'display'; + $d->Description = 'desc'; + $d->MaxTokenTTL = '5m0s'; + $d->TokenLocality = 'local'; + $d->Config = new \stdClass(); + $d->Config->Host = 'https://k8s.example.com'; + $d->CreateIndex = 10; + $d->ModifyIndex = 20; + $nsRule = new \stdClass(); + $nsRule->Selector = 'sel'; + $nsRule->BindNamespace = 'bn'; + $d->NamespaceRules = [$nsRule]; + $m = ACLAuthMethod::jsonUnserialize($d); + self::assertSame('auth-u', $m->getName()); + self::assertSame('kubernetes', $m->getType()); + self::assertCount(1, $m->getNamespaceRules()); + self::assertInstanceOf(ACLAuthMethodNamespaceRule::class, $m->getNamespaceRules()[0]); + } +} + diff --git a/tests/Unit/ACL/ACLBindingRuleTest.php b/tests/Unit/ACL/ACLBindingRuleTest.php new file mode 100644 index 00000000..ef7723bf --- /dev/null +++ b/tests/Unit/ACL/ACLBindingRuleTest.php @@ -0,0 +1,120 @@ +getID()); + self::assertSame('', $b->getDescription()); + self::assertSame('', $b->getAuthMethod()); + self::assertSame('', $b->getSelector()); + self::assertSame(BindingRuleBindType::UNDEFINED, $b->getBindType()); + self::assertSame('', $b->getBindType()->value); + self::assertSame('', $b->getBindName()); + self::assertSame(0, $b->getCreateIndex()); + self::assertSame(0, $b->getModifyIndex()); + self::assertSame('', $b->getNamespace()); + } + + public function testConstructorWithParams(): void + { + $b = new ACLBindingRule( + ID: 'br-1', + Description: 'desc', + AuthMethod: 'method', + Selector: 'serviceaccount.name==web', + BindType: BindingRuleBindType::Service, + BindName: 'web', + CreateIndex: 1, + ModifyIndex: 2, + Namespace: 'ns', + ); + self::assertSame('br-1', $b->getID()); + self::assertSame(BindingRuleBindType::Service, $b->getBindType()); + self::assertSame('web', $b->getBindName()); + } + + public function testFluentSetters(): void + { + $b = new ACLBindingRule(); + $result = $b->setID('a')->setDescription('d')->setAuthMethod('m') + ->setSelector('s')->setBindType(BindingRuleBindType::Role) + ->setBindName('r')->setCreateIndex(1)->setModifyIndex(2)->setNamespace('ns'); + self::assertSame($b, $result); + self::assertSame(BindingRuleBindType::Role, $b->getBindType()); + } + + public function testJsonSerialize(): void + { + $b = new ACLBindingRule(ID: 'x', BindType: BindingRuleBindType::Service, BindName: 'web'); + $out = $b->jsonSerialize(); + self::assertSame('x', $out->ID); + self::assertSame(BindingRuleBindType::Service, $out->BindType); + self::assertSame('web', $out->BindName); + } + + public function testJsonSerializeOmitsEmptyNamespace(): void + { + $b = new ACLBindingRule(ID: 'x'); + $out = $b->jsonSerialize(); + self::assertObjectNotHasProperty('Namespace', $out); + } + + public function testJsonUnserialize(): void + { + $d = new \stdClass(); + $d->ID = 'id-1'; + $d->Description = 'desc'; + $d->AuthMethod = 'auth'; + $d->Selector = 'sel'; + $d->BindType = BindingRuleBindType::Service; + $d->BindName = 'web'; + $d->CreateIndex = 5; + $d->ModifyIndex = 10; + $b = ACLBindingRule::jsonUnserialize($d); + self::assertSame('id-1', $b->getID()); + self::assertSame('web', $b->getBindName()); + self::assertSame(BindingRuleBindType::Service, $b->getBindType()); + } + + public function testConstructorWithStringBindType(): void + { + $b = new ACLBindingRule( + ID: 'br-str', + BindType: 'service', + BindName: 'web', + ); + self::assertSame(BindingRuleBindType::Service, $b->getBindType()); + self::assertSame(BindingRuleBindType::Service, $b->BindType); + self::assertSame('web', $b->getBindName()); + } + + public function testSetBindTypeWithString(): void + { + $b = new ACLBindingRule(); + $result = $b->setBindType('role'); + self::assertSame($b, $result); + self::assertSame(BindingRuleBindType::Role, $b->getBindType()); + self::assertSame(BindingRuleBindType::Role, $b->BindType); + } + + public function testSetBindTypeWithEnum(): void + { + $b = new ACLBindingRule(); + $result = $b->setBindType(BindingRuleBindType::Node); + self::assertSame($b, $result); + self::assertSame(BindingRuleBindType::Node, $b->getBindType()); + self::assertSame(BindingRuleBindType::Node, $b->BindType); + } +} + diff --git a/tests/Unit/ACL/ACLEntryTest.php b/tests/Unit/ACL/ACLEntryTest.php new file mode 100644 index 00000000..d8bd9bc1 --- /dev/null +++ b/tests/Unit/ACL/ACLEntryTest.php @@ -0,0 +1,77 @@ +getCreateIndex()); + self::assertSame(0, $e->getModifyIndex()); + self::assertSame('', $e->getID()); + self::assertSame('', $e->getName()); + self::assertSame('', $e->getType()); + self::assertSame('', $e->getRules()); + } + + public function testConstructorWithParams(): void + { + $e = new ACLEntry(CreateIndex: 1, ModifyIndex: 2, ID: 'id-1', Name: 'test', Type: 'client', Rules: 'key "" { policy = "read" }'); + self::assertSame(1, $e->getCreateIndex()); + self::assertSame(2, $e->getModifyIndex()); + self::assertSame('id-1', $e->getID()); + self::assertSame('test', $e->getName()); + self::assertSame('client', $e->getType()); + self::assertSame('key "" { policy = "read" }', $e->getRules()); + } + + public function testFluentSetters(): void + { + $e = new ACLEntry(); + $result = $e->setCreateIndex(10)->setModifyIndex(20)->setID('abc')->setName('n')->setType('management')->setRules('r'); + self::assertSame($e, $result); + self::assertSame(10, $e->getCreateIndex()); + self::assertSame(20, $e->getModifyIndex()); + self::assertSame('abc', $e->getID()); + self::assertSame('n', $e->getName()); + self::assertSame('management', $e->getType()); + self::assertSame('r', $e->getRules()); + } + + public function testJsonSerialize(): void + { + $e = new ACLEntry(ID: 'x', Name: 'y', Type: 'client', Rules: 'r'); + $out = $e->jsonSerialize(); + self::assertInstanceOf(\stdClass::class, $out); + self::assertSame('x', $out->ID); + self::assertSame('y', $out->Name); + self::assertSame('client', $out->Type); + self::assertSame('r', $out->Rules); + } + + public function testJsonUnserialize(): void + { + $d = new \stdClass(); + $d->CreateIndex = 5; + $d->ModifyIndex = 10; + $d->ID = 'id-2'; + $d->Name = 'entry'; + $d->Type = 'management'; + $d->Rules = 'rules'; + $e = ACLEntry::jsonUnserialize($d); + self::assertSame(5, $e->getCreateIndex()); + self::assertSame(10, $e->getModifyIndex()); + self::assertSame('id-2', $e->getID()); + self::assertSame('entry', $e->getName()); + self::assertSame('management', $e->getType()); + self::assertSame('rules', $e->getRules()); + } +} + diff --git a/tests/Unit/ACL/ACLLinkTest.php b/tests/Unit/ACL/ACLLinkTest.php new file mode 100644 index 00000000..0a27789e --- /dev/null +++ b/tests/Unit/ACL/ACLLinkTest.php @@ -0,0 +1,55 @@ +getID()); + self::assertSame('', $l->getName()); + } + + public function testConstructorWithParams(): void + { + $l = new ACLLink(ID: 'link-id', Name: 'link-name'); + self::assertSame('link-id', $l->getID()); + self::assertSame('link-name', $l->getName()); + } + + public function testFluentSetters(): void + { + $l = new ACLLink(); + $result = $l->setID('a')->setName('b'); + self::assertSame($l, $result); + self::assertSame('a', $l->getID()); + self::assertSame('b', $l->getName()); + } + + public function testJsonSerialize(): void + { + $l = new ACLLink(ID: 'x', Name: 'y'); + $out = $l->jsonSerialize(); + self::assertInstanceOf(\stdClass::class, $out); + self::assertSame('x', $out->ID); + self::assertSame('y', $out->Name); + } + + public function testJsonUnserialize(): void + { + $d = new \stdClass(); + $d->ID = 'id-1'; + $d->Name = 'name-1'; + $l = ACLLink::jsonUnserialize($d); + self::assertSame('id-1', $l->getID()); + self::assertSame('name-1', $l->getName()); + } +} + diff --git a/tests/Unit/ACL/ACLLoginParamsTest.php b/tests/Unit/ACL/ACLLoginParamsTest.php new file mode 100644 index 00000000..08b9967a --- /dev/null +++ b/tests/Unit/ACL/ACLLoginParamsTest.php @@ -0,0 +1,78 @@ +getAuthMethod()); + self::assertSame('', $p->getBearerToken()); + } + + public function testConstructorWithParams(): void + { + $p = new ACLLoginParams(AuthMethod: 'k8s', BearerToken: 'token-abc'); + self::assertSame('k8s', $p->getAuthMethod()); + self::assertSame('token-abc', $p->getBearerToken()); + } + + public function testSetMetaDirectly(): void + { + $p = new ACLLoginParams(); + // Meta uses null semantics via MetaField trait. + // After setMeta, accessing $p->Meta directly returns data through __get. + $p->setMeta(['key' => 'val']); + self::assertSame('val', $p->Meta['key']); + } + + public function testSetMetaKey(): void + { + $p = new ACLLoginParams(); + $p->setMetaKey('key', 'val'); + self::assertSame('val', $p->Meta['key']); + } + + public function testConstructorDefaultMeta(): void + { + $p = new ACLLoginParams(); + self::assertNull($p->getMeta()); + } + + public function testFluentSetters(): void + { + $p = new ACLLoginParams(); + $result = $p->setAuthMethod('m')->setBearerToken('t'); + self::assertSame($p, $result); + self::assertSame('m', $p->getAuthMethod()); + self::assertSame('t', $p->getBearerToken()); + } + + public function testJsonSerialize(): void + { + $p = new ACLLoginParams(AuthMethod: 'auth', BearerToken: 'tok'); + $out = $p->jsonSerialize(); + self::assertSame('auth', $out->AuthMethod); + self::assertSame('tok', $out->BearerToken); + } + + public function testJsonUnserialize(): void + { + $d = new \stdClass(); + $d->AuthMethod = 'auth'; + $d->BearerToken = 'tok'; + $d->Meta = new \stdClass(); + $d->Meta->key = 'val'; + $p = ACLLoginParams::jsonUnserialize($d); + self::assertSame('auth', $p->getAuthMethod()); + self::assertSame('tok', $p->getBearerToken()); + } +} + diff --git a/tests/Unit/ACL/ACLNodeIdentityTest.php b/tests/Unit/ACL/ACLNodeIdentityTest.php new file mode 100644 index 00000000..500c87e0 --- /dev/null +++ b/tests/Unit/ACL/ACLNodeIdentityTest.php @@ -0,0 +1,60 @@ +getNodeName()); + self::assertSame('', $n->NodeName); + self::assertSame('', $n->getDatacenter()); + self::assertSame('', $n->Datacenter); + } + + public function testConstructorWithParams(): void + { + $n = new ACLNodeIdentity(NodeName: 'node-1', Datacenter: 'dc1'); + self::assertSame('node-1', $n->getNodeName()); + self::assertSame('node-1', $n->NodeName); + self::assertSame('dc1', $n->getDatacenter()); + self::assertSame('dc1', $n->Datacenter); + } + + public function testFluentSetters(): void + { + $n = new ACLNodeIdentity(); + $result = $n->setNodeName('node-set')->setDatacenter('dc-set'); + self::assertSame($n, $result); + self::assertSame('node-set', $n->getNodeName()); + self::assertSame('node-set', $n->NodeName); + self::assertSame('dc-set', $n->getDatacenter()); + self::assertSame('dc-set', $n->Datacenter); + } + + public function testJsonSerialize(): void + { + $n = new ACLNodeIdentity(NodeName: 'n', Datacenter: 'd'); + $out = $n->jsonSerialize(); + self::assertSame('n', $out->NodeName); + self::assertSame('d', $out->Datacenter); + } + + public function testJsonUnserialize(): void + { + $d = new \stdClass(); + $d->NodeName = 'node-2'; + $d->Datacenter = 'dc2'; + $n = ACLNodeIdentity::jsonUnserialize($d); + self::assertSame('node-2', $n->getNodeName()); + self::assertSame('dc2', $n->getDatacenter()); + } +} + diff --git a/tests/Unit/ACL/ACLOIDCAuthURLParamsTest.php b/tests/Unit/ACL/ACLOIDCAuthURLParamsTest.php new file mode 100644 index 00000000..16948990 --- /dev/null +++ b/tests/Unit/ACL/ACLOIDCAuthURLParamsTest.php @@ -0,0 +1,56 @@ +getAuthMethod()); + self::assertSame('', $p->getRedirectURI()); + self::assertSame('', $p->getClientNonce()); + } + + public function testConstructorWithParams(): void + { + $p = new ACLOIDCAuthURLParams(AuthMethod: 'oidc', RedirectURI: 'https://example.com/callback', ClientNonce: 'nonce', Meta: ['k' => 'v']); + self::assertSame('oidc', $p->getAuthMethod()); + self::assertSame('https://example.com/callback', $p->getRedirectURI()); + self::assertSame('nonce', $p->getClientNonce()); + } + + public function testFluentSetters(): void + { + $p = new ACLOIDCAuthURLParams(); + $result = $p->setAuthMethod('m')->setRedirectURI('u')->setClientNonce('n'); + self::assertSame($p, $result); + } + + public function testJsonSerialize(): void + { + $p = new ACLOIDCAuthURLParams(AuthMethod: 'oidc', RedirectURI: 'uri', ClientNonce: 'nonce'); + $out = $p->jsonSerialize(); + self::assertSame('oidc', $out->AuthMethod); + self::assertSame('uri', $out->RedirectURI); + self::assertSame('nonce', $out->ClientNonce); + } + + public function testJsonUnserialize(): void + { + $d = new \stdClass(); + $d->AuthMethod = 'oidc'; + $d->RedirectURI = 'https://example.com'; + $d->ClientNonce = 'nonce'; + $p = ACLOIDCAuthURLParams::jsonUnserialize($d); + self::assertSame('oidc', $p->getAuthMethod()); + self::assertSame('https://example.com', $p->getRedirectURI()); + } +} + diff --git a/tests/Unit/ACL/ACLOIDCCallbackParamsTest.php b/tests/Unit/ACL/ACLOIDCCallbackParamsTest.php new file mode 100644 index 00000000..c9957177 --- /dev/null +++ b/tests/Unit/ACL/ACLOIDCCallbackParamsTest.php @@ -0,0 +1,61 @@ +getAuthMethod()); + self::assertSame('', $p->getState()); + self::assertSame('', $p->getCode()); + self::assertSame('', $p->getClientNonce()); + } + + public function testConstructorWithParams(): void + { + $p = new ACLOIDCCallbackParams(AuthMethod: 'oidc', State: 's', Code: 'c', ClientNonce: 'n'); + self::assertSame('oidc', $p->getAuthMethod()); + self::assertSame('s', $p->getState()); + self::assertSame('c', $p->getCode()); + self::assertSame('n', $p->getClientNonce()); + } + + public function testFluentSetters(): void + { + $p = new ACLOIDCCallbackParams(); + $result = $p->setAuthMethod('m')->setState('st')->setCode('cd')->setClientNonce('nc'); + self::assertSame($p, $result); + self::assertSame('m', $p->getAuthMethod()); + } + + public function testJsonSerialize(): void + { + $p = new ACLOIDCCallbackParams(AuthMethod: 'a', State: 's', Code: 'c', ClientNonce: 'n'); + $out = $p->jsonSerialize(); + self::assertSame('a', $out->AuthMethod); + self::assertSame('s', $out->State); + self::assertSame('c', $out->Code); + self::assertSame('n', $out->ClientNonce); + } + + public function testJsonUnserialize(): void + { + $d = new \stdClass(); + $d->AuthMethod = 'oidc'; + $d->State = 'state'; + $d->Code = 'code'; + $d->ClientNonce = 'nonce'; + $p = ACLOIDCCallbackParams::jsonUnserialize($d); + self::assertSame('oidc', $p->getAuthMethod()); + self::assertSame('state', $p->getState()); + } +} + diff --git a/tests/Unit/ACL/ACLPolicyListEntryTest.php b/tests/Unit/ACL/ACLPolicyListEntryTest.php new file mode 100644 index 00000000..7c1d8ece --- /dev/null +++ b/tests/Unit/ACL/ACLPolicyListEntryTest.php @@ -0,0 +1,58 @@ +getID()); + self::assertSame('', $p->getName()); + self::assertSame('', $p->getDescription()); + self::assertSame([], $p->getDatacenters()); + self::assertSame('', $p->getHash()); + self::assertSame(0, $p->getCreateIndex()); + self::assertSame(0, $p->getModifyIndex()); + self::assertSame('', $p->getNamespace()); + self::assertSame('', $p->getPartition()); + } + + public function testConstructorWithParams(): void + { + $p = new ACLPolicyListEntry(ID: 'id', Name: 'n', Datacenters: ['dc1']); + self::assertSame('id', $p->getID()); + self::assertSame('n', $p->getName()); + self::assertSame(['dc1'], $p->getDatacenters()); + } + + public function testJsonSerialize(): void + { + $p = new ACLPolicyListEntry(ID: 'x', Name: 'y'); + $out = $p->jsonSerialize(); + self::assertSame('x', $out->ID); + self::assertSame('y', $out->Name); + } + + public function testJsonUnserialize(): void + { + $d = new \stdClass(); + $d->ID = 'a'; + $d->Name = 'b'; + $d->Description = 'c'; + $d->Datacenters = ['dc1']; + $d->Hash = 'h'; + $d->CreateIndex = 1; + $d->ModifyIndex = 2; + $p = ACLPolicyListEntry::jsonUnserialize($d); + self::assertSame('a', $p->getID()); + self::assertSame(['dc1'], $p->getDatacenters()); + } +} + diff --git a/tests/Unit/ACL/ACLPolicyTest.php b/tests/Unit/ACL/ACLPolicyTest.php new file mode 100644 index 00000000..c19ae4c7 --- /dev/null +++ b/tests/Unit/ACL/ACLPolicyTest.php @@ -0,0 +1,98 @@ +getID()); + self::assertSame('', $p->getName()); + self::assertSame('', $p->getDescription()); + self::assertSame('', $p->getRules()); + self::assertSame([], $p->getDatacenters()); + self::assertSame('', $p->getHash()); + self::assertSame(0, $p->getCreateIndex()); + self::assertSame(0, $p->getModifyIndex()); + self::assertSame('', $p->getNamespace()); + self::assertSame('', $p->getPartition()); + } + + public function testConstructorWithParams(): void + { + $p = new ACLPolicy( + ID: 'pol-1', + Name: 'my-policy', + Description: 'desc', + Rules: 'key "" { policy = "read" }', + Datacenters: ['dc1', 'dc2'], + Hash: 'abc', + CreateIndex: 1, + ModifyIndex: 2, + Namespace: 'ns', + Partition: 'pt', + ); + self::assertSame('pol-1', $p->getID()); + self::assertSame('my-policy', $p->getName()); + self::assertSame('desc', $p->getDescription()); + self::assertSame('key "" { policy = "read" }', $p->getRules()); + self::assertSame(['dc1', 'dc2'], $p->getDatacenters()); + self::assertSame('abc', $p->getHash()); + self::assertSame(1, $p->getCreateIndex()); + self::assertSame(2, $p->getModifyIndex()); + self::assertSame('ns', $p->getNamespace()); + self::assertSame('pt', $p->getPartition()); + } + + public function testFluentSetters(): void + { + $p = new ACLPolicy(); + $result = $p->setID('a')->setName('b')->setDescription('c')->setRules('r') + ->setDatacenters('dc1')->setHash('h')->setCreateIndex(1)->setModifyIndex(2) + ->setNamespace('ns')->setPartition('pt'); + self::assertSame($p, $result); + self::assertSame('a', $p->getID()); + self::assertSame(['dc1'], $p->getDatacenters()); + } + + public function testJsonSerializeOmitsEmptyNamespaceAndPartition(): void + { + $p = new ACLPolicy(ID: 'x', Name: 'y'); + $out = $p->jsonSerialize(); + self::assertObjectNotHasProperty('Namespace', $out); + self::assertObjectNotHasProperty('Partition', $out); + } + + public function testJsonSerializeIncludesNamespaceAndPartition(): void + { + $p = new ACLPolicy(ID: 'x', Name: 'y', Namespace: 'ns', Partition: 'pt'); + $out = $p->jsonSerialize(); + self::assertSame('ns', $out->Namespace); + self::assertSame('pt', $out->Partition); + } + + public function testJsonUnserialize(): void + { + $d = new \stdClass(); + $d->ID = 'id-1'; + $d->Name = 'pol'; + $d->Description = 'desc'; + $d->Rules = 'r'; + $d->Datacenters = ['dc1']; + $d->Hash = 'h'; + $d->CreateIndex = 3; + $d->ModifyIndex = 4; + $p = ACLPolicy::jsonUnserialize($d); + self::assertSame('id-1', $p->getID()); + self::assertSame(['dc1'], $p->getDatacenters()); + self::assertSame(3, $p->getCreateIndex()); + } +} + diff --git a/tests/Unit/ACL/ACLReplicationStatusTest.php b/tests/Unit/ACL/ACLReplicationStatusTest.php new file mode 100644 index 00000000..dc2ddb76 --- /dev/null +++ b/tests/Unit/ACL/ACLReplicationStatusTest.php @@ -0,0 +1,80 @@ +isEnabled()); + self::assertFalse($s->isRunning()); + self::assertSame('', $s->getSourceDatacenter()); + self::assertSame(0, $s->getReplicatedIndex()); + self::assertSame(0, $s->getReplicatedRoleIndex()); + self::assertSame(0, $s->getReplicatedTokenIndex()); + self::assertInstanceOf(Time\Time::class, $s->getLastSuccess()); + self::assertInstanceOf(Time\Time::class, $s->getLastError()); + } + + public function testConstructorWithParams(): void + { + $s = new ACLReplicationStatus( + Enabled: true, + Running: true, + SourceDatacenter: 'dc1', + ReplicatedIndex: 10, + ReplicatedRoleIndex: 5, + ReplicatedTokenIndex: 7, + ); + self::assertTrue($s->isEnabled()); + self::assertTrue($s->isRunning()); + self::assertSame('dc1', $s->getSourceDatacenter()); + self::assertSame(10, $s->getReplicatedIndex()); + self::assertSame(5, $s->getReplicatedRoleIndex()); + self::assertSame(7, $s->getReplicatedTokenIndex()); + } + + public function testFluentSetters(): void + { + $s = new ACLReplicationStatus(); + $result = $s->setEnabled(true)->setRunning(true)->setSourceDatacenter('dc2') + ->setReplicatedIndex(1)->setReplicatedRoleIndex(2)->setReplicatedTokenIndex(3); + self::assertSame($s, $result); + self::assertTrue($s->isEnabled()); + } + + public function testJsonSerialize(): void + { + $s = new ACLReplicationStatus(Enabled: true, Running: true, SourceDatacenter: 'dc1'); + $out = $s->jsonSerialize(); + self::assertTrue($out->Enabled); + self::assertTrue($out->Running); + self::assertSame('dc1', $out->SourceDatacenter); + } + + public function testJsonUnserialize(): void + { + $d = new \stdClass(); + $d->Enabled = true; + $d->Running = false; + $d->SourceDatacenter = 'dc1'; + $d->ReplicatedIndex = 10; + $d->ReplicatedRoleIndex = 5; + $d->ReplicatedTokenIndex = 7; + $d->LastSuccess = '2025-01-01T00:00:00Z'; + $d->LastError = '2025-01-01T00:00:00Z'; + $s = ACLReplicationStatus::jsonUnserialize($d); + self::assertTrue($s->isEnabled()); + self::assertFalse($s->isRunning()); + self::assertSame(10, $s->getReplicatedIndex()); + } +} + diff --git a/tests/Unit/ACL/ACLRolePolicyLinkTest.php b/tests/Unit/ACL/ACLRolePolicyLinkTest.php new file mode 100644 index 00000000..b66f4f28 --- /dev/null +++ b/tests/Unit/ACL/ACLRolePolicyLinkTest.php @@ -0,0 +1,64 @@ +getID()); + self::assertSame('', $l->ID); + self::assertSame('', $l->getName()); + self::assertSame('', $l->Name); + } + + public function testConstructorWithParams(): void + { + $l = new ACLRolePolicyLink(ID: 'rpl-id', Name: 'rpl-name'); + self::assertSame('rpl-id', $l->getID()); + self::assertSame('rpl-id', $l->ID); + self::assertSame('rpl-name', $l->getName()); + self::assertSame('rpl-name', $l->Name); + } + + public function testFluentSetters(): void + { + $l = new ACLRolePolicyLink(); + $result = $l->setID('a')->setName('b'); + self::assertSame($l, $result); + self::assertSame('a', $l->getID()); + self::assertSame('a', $l->ID); + self::assertSame('b', $l->getName()); + self::assertSame('b', $l->Name); + } + + public function testJsonSerialize(): void + { + $l = new ACLRolePolicyLink(ID: 'x', Name: 'y'); + $out = $l->jsonSerialize(); + self::assertInstanceOf(\stdClass::class, $out); + self::assertSame('x', $out->ID); + self::assertSame('y', $out->Name); + } + + public function testJsonUnserialize(): void + { + $d = new \stdClass(); + $d->ID = 'id-1'; + $d->Name = 'name-1'; + $l = ACLRolePolicyLink::jsonUnserialize($d); + self::assertInstanceOf(ACLRolePolicyLink::class, $l); + self::assertSame('id-1', $l->getID()); + self::assertSame('id-1', $l->ID); + self::assertSame('name-1', $l->getName()); + self::assertSame('name-1', $l->Name); + } +} + diff --git a/tests/Unit/ACL/ACLRoleTest.php b/tests/Unit/ACL/ACLRoleTest.php new file mode 100644 index 00000000..f87cc77e --- /dev/null +++ b/tests/Unit/ACL/ACLRoleTest.php @@ -0,0 +1,111 @@ +getID()); + self::assertSame('', $r->getName()); + self::assertSame('', $r->getDescription()); + self::assertSame([], $r->getPolicies()); + self::assertSame([], $r->getServiceIdentities()); + self::assertSame([], $r->getNodeIdentities()); + self::assertSame([], $r->getTemplatedPolicies()); + self::assertSame('', $r->getHash()); + self::assertSame(0, $r->getCreateIndex()); + self::assertSame(0, $r->getModifyIndex()); + self::assertSame('', $r->getNamespace()); + self::assertSame('', $r->getPartition()); + } + + public function testConstructorWithParams(): void + { + $pol = new ACLRolePolicyLink(ID: 'p1', Name: 'pol'); + $si = new ACLServiceIdentity(ServiceName: 'web'); + $ni = new ACLNodeIdentity(NodeName: 'node'); + $tp = new ACLTemplatedPolicy(TemplateName: 'tmpl'); + $r = new ACLRole( + ID: 'role-1', + Name: 'my-role', + Description: 'desc', + Policies: [$pol], + ServiceIdentities: [$si], + NodeIdentities: [$ni], + TemplatedPolicies: [$tp], + Hash: 'h', + CreateIndex: 1, + ModifyIndex: 2, + Namespace: 'ns', + Partition: 'pt', + ); + self::assertSame('role-1', $r->getID()); + self::assertCount(1, $r->getPolicies()); + self::assertCount(1, $r->getServiceIdentities()); + self::assertCount(1, $r->getNodeIdentities()); + self::assertCount(1, $r->getTemplatedPolicies()); + } + + public function testFluentSetters(): void + { + $r = new ACLRole(); + $pol = new ACLRolePolicyLink(ID: 'p1'); + $result = $r->setID('a')->setName('b')->setDescription('c') + ->setPolicies($pol)->setServiceIdentities() + ->setNodeIdentities()->setTemplatedPolicies() + ->setHash('h')->setCreateIndex(1)->setModifyIndex(2) + ->setNamespace('ns')->setPartition('pt'); + self::assertSame($r, $result); + self::assertCount(1, $r->getPolicies()); + } + + public function testJsonSerialize(): void + { + $r = new ACLRole(ID: 'x', Name: 'y'); + $out = $r->jsonSerialize(); + self::assertSame('x', $out->ID); + self::assertSame('y', $out->Name); + self::assertObjectNotHasProperty('Policies', $out); + self::assertObjectNotHasProperty('Namespace', $out); + } + + public function testJsonUnserialize(): void + { + $d = new \stdClass(); + $d->ID = 'id-1'; + $d->Name = 'role'; + $d->Description = 'desc'; + $polLink = new \stdClass(); + $polLink->ID = 'p1'; + $polLink->Name = 'pol'; + $d->Policies = [$polLink]; + $siObj = new \stdClass(); + $siObj->ServiceName = 'web'; + $siObj->Datacenters = ['dc1']; + $d->ServiceIdentities = [$siObj]; + $d->NodeIdentities = []; + $d->TemplatedPolicies = []; + $d->Hash = 'h'; + $d->CreateIndex = 5; + $d->ModifyIndex = 10; + $r = ACLRole::jsonUnserialize($d); + self::assertSame('id-1', $r->getID()); + self::assertCount(1, $r->getPolicies()); + self::assertInstanceOf(ACLRolePolicyLink::class, $r->getPolicies()[0]); + self::assertCount(1, $r->getServiceIdentities()); + self::assertInstanceOf(ACLServiceIdentity::class, $r->getServiceIdentities()[0]); + } +} + diff --git a/tests/Unit/ACL/ACLServiceIdentityTest.php b/tests/Unit/ACL/ACLServiceIdentityTest.php new file mode 100644 index 00000000..7cd6287a --- /dev/null +++ b/tests/Unit/ACL/ACLServiceIdentityTest.php @@ -0,0 +1,61 @@ +getServiceName()); + self::assertSame([], $s->getDatacenters()); + } + + public function testConstructorWithParams(): void + { + $s = new ACLServiceIdentity(ServiceName: 'web', Datacenters: ['dc1', 'dc2']); + self::assertSame('web', $s->getServiceName()); + self::assertSame(['dc1', 'dc2'], $s->getDatacenters()); + } + + public function testFluentSetters(): void + { + $s = new ACLServiceIdentity(); + $result = $s->setServiceName('api')->setDatacenters('dc1'); + self::assertSame($s, $result); + self::assertSame('api', $s->getServiceName()); + self::assertSame(['dc1'], $s->getDatacenters()); + } + + public function testJsonSerializeOmitsEmptyDatacenters(): void + { + $s = new ACLServiceIdentity(ServiceName: 'web'); + $out = $s->jsonSerialize(); + self::assertSame('web', $out->ServiceName); + self::assertObjectNotHasProperty('Datacenters', $out); + } + + public function testJsonSerializeIncludesDatacenters(): void + { + $s = new ACLServiceIdentity(ServiceName: 'web', Datacenters: ['dc1']); + $out = $s->jsonSerialize(); + self::assertSame(['dc1'], $out->Datacenters); + } + + public function testJsonUnserialize(): void + { + $d = new \stdClass(); + $d->ServiceName = 'svc'; + $d->Datacenters = ['dc1', 'dc2']; + $s = ACLServiceIdentity::jsonUnserialize($d); + self::assertSame('svc', $s->getServiceName()); + self::assertSame(['dc1', 'dc2'], $s->getDatacenters()); + } +} + diff --git a/tests/Unit/ACL/ACLTemplatedPolicyTest.php b/tests/Unit/ACL/ACLTemplatedPolicyTest.php new file mode 100644 index 00000000..f2acf9c7 --- /dev/null +++ b/tests/Unit/ACL/ACLTemplatedPolicyTest.php @@ -0,0 +1,61 @@ +getTemplateName()); + self::assertNull($t->getTemplateVariables()); + self::assertSame([], $t->getDatacenters()); + } + + public function testConstructorWithParams(): void + { + $vars = new ACLTemplatedPolicyVariables(Name: 'my-svc'); + $t = new ACLTemplatedPolicy(TemplateName: 'builtin/service', TemplateVariables: $vars, Datacenters: ['dc1']); + self::assertSame('builtin/service', $t->getTemplateName()); + self::assertSame($vars, $t->getTemplateVariables()); + self::assertSame(['dc1'], $t->getDatacenters()); + } + + public function testFluentSetters(): void + { + $t = new ACLTemplatedPolicy(); + $vars = new ACLTemplatedPolicyVariables(Name: 'v'); + $result = $t->setTemplateName('t')->setTemplateVariables($vars)->setDatacenters('dc1', 'dc2'); + self::assertSame($t, $result); + self::assertSame('t', $t->getTemplateName()); + self::assertSame($vars, $t->getTemplateVariables()); + self::assertSame(['dc1', 'dc2'], $t->getDatacenters()); + } + + public function testJsonSerializeOmitsNullAndEmpty(): void + { + $t = new ACLTemplatedPolicy(TemplateName: 'tmpl'); + $out = $t->jsonSerialize(); + self::assertSame('tmpl', $out->TemplateName); + self::assertObjectNotHasProperty('TemplateVariables', $out); + self::assertObjectNotHasProperty('Datacenters', $out); + } + + public function testJsonSerializeIncludesValues(): void + { + $vars = new ACLTemplatedPolicyVariables(Name: 'n'); + $t = new ACLTemplatedPolicy(TemplateName: 'tmpl', TemplateVariables: $vars, Datacenters: ['dc1']); + $out = $t->jsonSerialize(); + self::assertSame('tmpl', $out->TemplateName); + self::assertSame($vars, $out->TemplateVariables); + self::assertSame(['dc1'], $out->Datacenters); + } +} + diff --git a/tests/Unit/ACL/ACLTemplatedPolicyVariablesTest.php b/tests/Unit/ACL/ACLTemplatedPolicyVariablesTest.php new file mode 100644 index 00000000..89907adf --- /dev/null +++ b/tests/Unit/ACL/ACLTemplatedPolicyVariablesTest.php @@ -0,0 +1,48 @@ +getName()); + } + + public function testConstructorWithParams(): void + { + $v = new ACLTemplatedPolicyVariables(Name: 'my-svc'); + self::assertSame('my-svc', $v->getName()); + } + + public function testFluentSetters(): void + { + $v = new ACLTemplatedPolicyVariables(); + $result = $v->setName('test'); + self::assertSame($v, $result); + self::assertSame('test', $v->getName()); + } + + public function testJsonSerialize(): void + { + $v = new ACLTemplatedPolicyVariables(Name: 'n'); + $out = $v->jsonSerialize(); + self::assertSame('n', $out->Name); + } + + public function testJsonUnserialize(): void + { + $d = new \stdClass(); + $d->Name = 'test'; + $v = ACLTemplatedPolicyVariables::jsonUnserialize($d); + self::assertSame('test', $v->getName()); + } +} + diff --git a/tests/Unit/ACL/ACLTokenExpandedTest.php b/tests/Unit/ACL/ACLTokenExpandedTest.php new file mode 100644 index 00000000..de5b990f --- /dev/null +++ b/tests/Unit/ACL/ACLTokenExpandedTest.php @@ -0,0 +1,184 @@ +getExpandedPolicies()); + self::assertSame([], $t->ExpandedPolicies); + self::assertSame([], $t->getExpandedRoles()); + self::assertSame([], $t->ExpandedRoles); + self::assertSame([], $t->getNamespaceDefaultPolicyIDs()); + self::assertSame([], $t->NamespaceDefaultPolicyIDs); + self::assertSame([], $t->getNamespaceDefaultRoleIDs()); + self::assertSame([], $t->NamespaceDefaultRoleIDs); + self::assertSame('', $t->getAgentACLDefaultPolicy()); + self::assertSame('', $t->AgentACLDefaultPolicy); + self::assertSame('', $t->getAgentACLDownPolicy()); + self::assertSame('', $t->AgentACLDownPolicy); + self::assertSame('', $t->getResolvedByAgent()); + self::assertSame('', $t->ResolvedByAgent); + // inherited from ACLToken + self::assertSame(0, $t->getCreateIndex()); + self::assertSame('', $t->getAccessorID()); + self::assertSame([], $t->getPolicies()); + } + + public function testConstructorWithParams(): void + { + $pol = new ACLPolicy(ID: 'ep1', Name: 'expanded-pol'); + $role = new ACLRole(ID: 'er1', Name: 'expanded-role'); + $tokenPol = new ACLTokenPolicyLink(ID: 'tp1', Name: 'token-pol'); + $tokenRole = new ACLTokenRoleLink(ID: 'tr1', Name: 'token-role'); + + $t = new ACLTokenExpanded( + ExpandedPolicies: [$pol], + ExpandedRoles: [$role], + NamespaceDefaultPolicyIDs: ['nsp1'], + NamespaceDefaultRoleIDs: ['nsr1'], + AgentACLDefaultPolicy: 'allow', + AgentACLDownPolicy: 'deny', + ResolvedByAgent: 'agent-1', + CreateIndex: 1, + ModifyIndex: 2, + AccessorID: 'acc-1', + SecretID: 'sec-1', + Description: 'desc', + Policies: [$tokenPol], + Roles: [$tokenRole], + Local: true, + ); + + self::assertCount(1, $t->getExpandedPolicies()); + self::assertSame($pol, $t->getExpandedPolicies()[0]); + self::assertCount(1, $t->getExpandedRoles()); + self::assertSame($role, $t->getExpandedRoles()[0]); + self::assertSame(['nsp1'], $t->getNamespaceDefaultPolicyIDs()); + self::assertSame(['nsr1'], $t->getNamespaceDefaultRoleIDs()); + self::assertSame('allow', $t->getAgentACLDefaultPolicy()); + self::assertSame('allow', $t->AgentACLDefaultPolicy); + self::assertSame('deny', $t->getAgentACLDownPolicy()); + self::assertSame('agent-1', $t->getResolvedByAgent()); + self::assertSame(1, $t->getCreateIndex()); + self::assertSame('acc-1', $t->getAccessorID()); + self::assertCount(1, $t->getPolicies()); + self::assertTrue($t->isLocal()); + } + + public function testFluentSetters(): void + { + $t = new ACLTokenExpanded(); + $pol = new ACLPolicy(ID: 'ep1'); + $role = new ACLRole(ID: 'er1'); + + $result = $t->setExpandedPolicies($pol) + ->setExpandedRoles($role) + ->setNamespaceDefaultPolicyIDs('nsp1', 'nsp2') + ->setNamespaceDefaultRoleIDs('nsr1') + ->setAgentACLDefaultPolicy('allow') + ->setAgentACLDownPolicy('deny') + ->setResolvedByAgent('agent-set'); + + self::assertSame($t, $result); + self::assertCount(1, $t->getExpandedPolicies()); + self::assertSame($pol, $t->ExpandedPolicies[0]); + self::assertCount(1, $t->getExpandedRoles()); + self::assertSame($role, $t->ExpandedRoles[0]); + self::assertSame(['nsp1', 'nsp2'], $t->getNamespaceDefaultPolicyIDs()); + self::assertSame(['nsp1', 'nsp2'], $t->NamespaceDefaultPolicyIDs); + self::assertSame(['nsr1'], $t->getNamespaceDefaultRoleIDs()); + self::assertSame('allow', $t->getAgentACLDefaultPolicy()); + self::assertSame('deny', $t->getAgentACLDownPolicy()); + self::assertSame('agent-set', $t->getResolvedByAgent()); + } + + public function testJsonSerialize(): void + { + $pol = new ACLPolicy(ID: 'ep1', Name: 'pol'); + $t = new ACLTokenExpanded( + ExpandedPolicies: [$pol], + AgentACLDefaultPolicy: 'allow', + AccessorID: 'acc', + ); + $out = $t->jsonSerialize(); + self::assertInstanceOf(\stdClass::class, $out); + self::assertSame('acc', $out->AccessorID); + self::assertSame('allow', $out->AgentACLDefaultPolicy); + self::assertCount(1, $out->ExpandedPolicies); + } + + public function testJsonUnserialize(): void + { + $d = new \stdClass(); + $d->CreateIndex = 5; + $d->ModifyIndex = 10; + $d->AccessorID = 'acc-1'; + $d->SecretID = 'sec-1'; + $d->Description = 'desc'; + $d->Local = false; + $d->Hash = 'h'; + $d->Policies = []; + $d->Roles = []; + $d->ServiceIdentities = []; + $d->NodeIdentities = []; + $d->TemplatePolicies = []; + $d->AgentACLDefaultPolicy = 'allow'; + $d->AgentACLDownPolicy = 'deny'; + $d->ResolvedByAgent = 'agent-1'; + $d->NamespaceDefaultPolicyIDs = ['nsp1']; + $d->NamespaceDefaultRoleIDs = ['nsr1']; + + $epObj = new \stdClass(); + $epObj->ID = 'ep1'; + $epObj->Name = 'expanded-pol'; + $epObj->Description = ''; + $epObj->Rules = ''; + $epObj->Datacenters = []; + $epObj->Hash = ''; + $epObj->CreateIndex = 0; + $epObj->ModifyIndex = 0; + $d->ExpandedPolicies = [$epObj]; + + $erObj = new \stdClass(); + $erObj->ID = 'er1'; + $erObj->Name = 'expanded-role'; + $erObj->Description = ''; + $erObj->Policies = []; + $erObj->ServiceIdentities = []; + $erObj->NodeIdentities = []; + $erObj->TemplatedPolicies = []; + $erObj->Hash = ''; + $erObj->CreateIndex = 0; + $erObj->ModifyIndex = 0; + $d->ExpandedRoles = [$erObj]; + + $t = ACLTokenExpanded::jsonUnserialize($d); + self::assertInstanceOf(ACLTokenExpanded::class, $t); + self::assertSame('acc-1', $t->getAccessorID()); + self::assertSame('allow', $t->getAgentACLDefaultPolicy()); + self::assertSame('deny', $t->getAgentACLDownPolicy()); + self::assertSame('agent-1', $t->getResolvedByAgent()); + self::assertSame(['nsp1'], $t->getNamespaceDefaultPolicyIDs()); + self::assertSame(['nsr1'], $t->getNamespaceDefaultRoleIDs()); + self::assertCount(1, $t->getExpandedPolicies()); + self::assertInstanceOf(ACLPolicy::class, $t->getExpandedPolicies()[0]); + self::assertSame('ep1', $t->getExpandedPolicies()[0]->getID()); + self::assertCount(1, $t->getExpandedRoles()); + self::assertInstanceOf(ACLRole::class, $t->getExpandedRoles()[0]); + self::assertSame('er1', $t->getExpandedRoles()[0]->getID()); + } +} + diff --git a/tests/Unit/ACL/ACLTokenListEntryTest.php b/tests/Unit/ACL/ACLTokenListEntryTest.php new file mode 100644 index 00000000..9e0da5f3 --- /dev/null +++ b/tests/Unit/ACL/ACLTokenListEntryTest.php @@ -0,0 +1,137 @@ +getAccessorID()); + self::assertSame('', $e->getSecretID()); + self::assertSame('', $e->getDescription()); + self::assertSame([], $e->getPolicies()); + self::assertSame([], $e->getRoles()); + self::assertSame([], $e->getServiceIdentities()); + self::assertSame([], $e->getNodeIdentities()); + self::assertSame([], $e->getTemplatedPolicies()); + self::assertFalse($e->isLocal()); + self::assertSame(0, $e->getCreateIndex()); + self::assertSame(0, $e->getModifyIndex()); + self::assertFalse($e->isLegacy()); + self::assertSame('', $e->getNamespace()); + self::assertSame('', $e->getPartition()); + self::assertSame('', $e->getAuthMethodNamespace()); + } + + public function testConstructorWithParams(): void + { + $e = new ACLTokenListEntry( + AccessorID: 'acc', + SecretID: 'sec', + Description: 'desc', + Local: true, + ); + self::assertSame('acc', $e->getAccessorID()); + self::assertSame('acc', $e->AccessorID); + self::assertSame('sec', $e->getSecretID()); + self::assertSame('sec', $e->SecretID); + self::assertTrue($e->isLocal()); + self::assertTrue($e->Local); + } + + public function testFluentSetters(): void + { + $e = new ACLTokenListEntry(); + $pol = new ACLTokenPolicyLink(ID: 'p1', Name: 'pol'); + $role = new ACLTokenRoleLink(ID: 'r1', Name: 'role'); + $si = new ACLServiceIdentity(ServiceName: 'web'); + $ni = new ACLNodeIdentity(NodeName: 'node'); + $tp = new ACLTemplatedPolicy(TemplateName: 'tmpl'); + + $result = $e->setCreateIndex(10) + ->setModifyIndex(20) + ->setAccessorID('acc-set') + ->setSecretID('sec-set') + ->setDescription('desc-set') + ->setPolicies($pol) + ->setRoles($role) + ->setServiceIdentities($si) + ->setNodeIdentities($ni) + ->setTemplatedPolicies($tp) + ->setLocal(true) + ->setAuthMethod('auth-set') + ->setHash('hash-set') + ->setLegacy(true) + ->setNamespace('ns-set') + ->setPartition('pt-set') + ->setAuthMethodNamespace('amns-set'); + + self::assertSame($e, $result); + self::assertSame(10, $e->getCreateIndex()); + self::assertSame(10, $e->CreateIndex); + self::assertSame(20, $e->getModifyIndex()); + self::assertSame('acc-set', $e->getAccessorID()); + self::assertSame('acc-set', $e->AccessorID); + self::assertSame('sec-set', $e->getSecretID()); + self::assertSame('desc-set', $e->getDescription()); + self::assertCount(1, $e->getPolicies()); + self::assertCount(1, $e->getRoles()); + self::assertCount(1, $e->getServiceIdentities()); + self::assertCount(1, $e->getNodeIdentities()); + self::assertCount(1, $e->getTemplatedPolicies()); + self::assertTrue($e->isLocal()); + self::assertSame('auth-set', $e->getAuthMethod()); + self::assertSame('hash-set', $e->getHash()); + self::assertTrue($e->isLegacy()); + self::assertSame('ns-set', $e->getNamespace()); + self::assertSame('pt-set', $e->getPartition()); + self::assertSame('amns-set', $e->getAuthMethodNamespace()); + } + + public function testJsonSerialize(): void + { + $e = new ACLTokenListEntry(AccessorID: 'a', SecretID: 's'); + $out = $e->jsonSerialize(); + self::assertInstanceOf(\stdClass::class, $out); + self::assertSame('a', $out->AccessorID); + } + + public function testJsonUnserialize(): void + { + $d = new \stdClass(); + $d->CreateIndex = 5; + $d->ModifyIndex = 10; + $d->AccessorID = 'acc-1'; + $d->SecretID = 'sec-1'; + $d->Description = 'desc'; + $d->Local = true; + $d->Hash = 'h'; + $polLink = new \stdClass(); + $polLink->ID = 'p1'; + $polLink->Name = 'policy'; + $d->Policies = [$polLink]; + $d->Roles = []; + $d->ServiceIdentities = []; + $d->NodeIdentities = []; + $d->TemplatedPolicies = []; + $e = ACLTokenListEntry::jsonUnserialize($d); + self::assertSame('acc-1', $e->getAccessorID()); + self::assertSame('sec-1', $e->getSecretID()); + self::assertTrue($e->isLocal()); + self::assertCount(1, $e->getPolicies()); + self::assertInstanceOf(ACLTokenPolicyLink::class, $e->getPolicies()[0]); + } +} + diff --git a/tests/Unit/ACL/ACLTokenPolicyLinkTest.php b/tests/Unit/ACL/ACLTokenPolicyLinkTest.php new file mode 100644 index 00000000..e8e833be --- /dev/null +++ b/tests/Unit/ACL/ACLTokenPolicyLinkTest.php @@ -0,0 +1,64 @@ +getID()); + self::assertSame('', $l->ID); + self::assertSame('', $l->getName()); + self::assertSame('', $l->Name); + } + + public function testConstructorWithParams(): void + { + $l = new ACLTokenPolicyLink(ID: 'tpl-id', Name: 'tpl-name'); + self::assertSame('tpl-id', $l->getID()); + self::assertSame('tpl-id', $l->ID); + self::assertSame('tpl-name', $l->getName()); + self::assertSame('tpl-name', $l->Name); + } + + public function testFluentSetters(): void + { + $l = new ACLTokenPolicyLink(); + $result = $l->setID('a')->setName('b'); + self::assertSame($l, $result); + self::assertSame('a', $l->getID()); + self::assertSame('a', $l->ID); + self::assertSame('b', $l->getName()); + self::assertSame('b', $l->Name); + } + + public function testJsonSerialize(): void + { + $l = new ACLTokenPolicyLink(ID: 'x', Name: 'y'); + $out = $l->jsonSerialize(); + self::assertInstanceOf(\stdClass::class, $out); + self::assertSame('x', $out->ID); + self::assertSame('y', $out->Name); + } + + public function testJsonUnserialize(): void + { + $d = new \stdClass(); + $d->ID = 'id-1'; + $d->Name = 'name-1'; + $l = ACLTokenPolicyLink::jsonUnserialize($d); + self::assertInstanceOf(ACLTokenPolicyLink::class, $l); + self::assertSame('id-1', $l->getID()); + self::assertSame('id-1', $l->ID); + self::assertSame('name-1', $l->getName()); + self::assertSame('name-1', $l->Name); + } +} + diff --git a/tests/Unit/ACL/ACLTokenRoleLinkTest.php b/tests/Unit/ACL/ACLTokenRoleLinkTest.php new file mode 100644 index 00000000..04e58a54 --- /dev/null +++ b/tests/Unit/ACL/ACLTokenRoleLinkTest.php @@ -0,0 +1,56 @@ +getID()); + self::assertSame('', $l->ID); + self::assertSame('', $l->getName()); + self::assertSame('', $l->Name); + } + public function testConstructorWithParams(): void + { + $l = new ACLTokenRoleLink(ID: 'trl-id', Name: 'trl-name'); + self::assertSame('trl-id', $l->getID()); + self::assertSame('trl-id', $l->ID); + self::assertSame('trl-name', $l->getName()); + self::assertSame('trl-name', $l->Name); + } + public function testFluentSetters(): void + { + $l = new ACLTokenRoleLink(); + $result = $l->setID('a')->setName('b'); + self::assertSame($l, $result); + self::assertSame('a', $l->getID()); + self::assertSame('a', $l->ID); + self::assertSame('b', $l->getName()); + self::assertSame('b', $l->Name); + } + public function testJsonSerialize(): void + { + $l = new ACLTokenRoleLink(ID: 'x', Name: 'y'); + $out = $l->jsonSerialize(); + self::assertInstanceOf(\stdClass::class, $out); + self::assertSame('x', $out->ID); + self::assertSame('y', $out->Name); + } + public function testJsonUnserialize(): void + { + $d = new \stdClass(); + $d->ID = 'id-1'; + $d->Name = 'name-1'; + $l = ACLTokenRoleLink::jsonUnserialize($d); + self::assertInstanceOf(ACLTokenRoleLink::class, $l); + self::assertSame('id-1', $l->getID()); + self::assertSame('id-1', $l->ID); + self::assertSame('name-1', $l->getName()); + self::assertSame('name-1', $l->Name); + } +} diff --git a/tests/Unit/ACL/ACLTokenTest.php b/tests/Unit/ACL/ACLTokenTest.php new file mode 100644 index 00000000..1fc284c6 --- /dev/null +++ b/tests/Unit/ACL/ACLTokenTest.php @@ -0,0 +1,182 @@ +getCreateIndex()); + self::assertSame(0, $t->getModifyIndex()); + self::assertSame('', $t->getAccessorID()); + self::assertSame('', $t->getSecretID()); + self::assertSame('', $t->getDescription()); + self::assertSame([], $t->getPolicies()); + self::assertSame([], $t->getRoles()); + self::assertSame([], $t->getServiceIdentities()); + self::assertSame([], $t->getNodeIdentities()); + self::assertSame([], $t->getTemplatePolicies()); + self::assertFalse($t->isLocal()); + self::assertSame('', $t->getAuthMethod()); + self::assertSame('', $t->getHash()); + self::assertSame('', $t->getNamespace()); + self::assertSame('', $t->getRules()); + self::assertSame('', $t->getPartition()); + self::assertSame('', $t->getAuthMethodNamespace()); + } + + public function testConstructorWithParams(): void + { + $pol = new ACLTokenPolicyLink(ID: 'p1', Name: 'pol'); + $role = new ACLTokenRoleLink(ID: 'r1', Name: 'role'); + $t = new ACLToken( + CreateIndex: 1, + ModifyIndex: 2, + AccessorID: 'accessor-1', + SecretID: 'secret-1', + Description: 'desc', + Policies: [$pol], + Roles: [$role], + Local: true, + AuthMethod: 'auth', + Hash: 'h', + Namespace: 'ns', + Rules: 'r', + Partition: 'pt', + AuthMethodNamespace: 'amns', + ); + self::assertSame(1, $t->getCreateIndex()); + self::assertSame('accessor-1', $t->getAccessorID()); + self::assertSame('secret-1', $t->getSecretID()); + self::assertCount(1, $t->getPolicies()); + self::assertCount(1, $t->getRoles()); + self::assertTrue($t->isLocal()); + } + + public function testJsonSerialize(): void + { + $t = new ACLToken(AccessorID: 'a', SecretID: 's', Description: 'd'); + $out = $t->jsonSerialize(); + self::assertInstanceOf(\stdClass::class, $out); + self::assertSame('a', $out->AccessorID); + self::assertSame('s', $out->SecretID); + self::assertSame('d', $out->Description); + } + + public function testJsonSerializeOmitsEmptyCollections(): void + { + $t = new ACLToken(AccessorID: 'a'); + $out = $t->jsonSerialize(); + self::assertObjectNotHasProperty('Policies', $out); + self::assertObjectNotHasProperty('Roles', $out); + self::assertObjectNotHasProperty('ServiceIdentities', $out); + self::assertObjectNotHasProperty('NodeIdentities', $out); + self::assertObjectNotHasProperty('TemplatePolicies', $out); + self::assertObjectNotHasProperty('Namespace', $out); + self::assertObjectNotHasProperty('Partition', $out); + } + + public function testJsonUnserialize(): void + { + $d = new \stdClass(); + $d->CreateIndex = 5; + $d->ModifyIndex = 10; + $d->AccessorID = 'acc-1'; + $d->SecretID = 'sec-1'; + $d->Description = 'desc'; + $d->Local = true; + $d->Hash = 'h'; + $polLink = new \stdClass(); + $polLink->ID = 'p1'; + $polLink->Name = 'policy'; + $d->Policies = [$polLink]; + $d->Roles = []; + $d->ServiceIdentities = []; + $d->NodeIdentities = []; + $d->TemplatePolicies = []; + $t = ACLToken::jsonUnserialize($d); + self::assertSame('acc-1', $t->getAccessorID()); + self::assertSame('sec-1', $t->getSecretID()); + self::assertTrue($t->isLocal()); + self::assertCount(1, $t->getPolicies()); + self::assertInstanceOf(ACLTokenPolicyLink::class, $t->getPolicies()[0]); + } + + public function testFluentSetters(): void + { + $t = new ACLToken(); + $pol = new ACLTokenPolicyLink(ID: 'p1', Name: 'pol'); + $role = new ACLTokenRoleLink(ID: 'r1', Name: 'role'); + $si = new ACLServiceIdentity(ServiceName: 'web'); + $ni = new ACLNodeIdentity(NodeName: 'node'); + $tp = new ACLTemplatedPolicy(TemplateName: 'tmpl'); + + $result = $t->setCreateIndex(10) + ->setModifyIndex(20) + ->setAccessorID('acc-set') + ->setSecretID('sec-set') + ->setDescription('desc-set') + ->setPolicies($pol) + ->setRoles($role) + ->setServiceIdentities($si) + ->setNodeIdentities($ni) + ->setTemplatePolicies($tp) + ->setLocal(true) + ->setAuthMethod('auth-set') + ->setExpirationTTL('5m') + ->setHash('hash-set') + ->setNamespace('ns-set') + ->setRules('rules-set') + ->setPartition('pt-set') + ->setAuthMethodNamespace('amns-set'); + + self::assertSame($t, $result); + self::assertSame(10, $t->getCreateIndex()); + self::assertSame(10, $t->CreateIndex); + self::assertSame(20, $t->getModifyIndex()); + self::assertSame(20, $t->ModifyIndex); + self::assertSame('acc-set', $t->getAccessorID()); + self::assertSame('acc-set', $t->AccessorID); + self::assertSame('sec-set', $t->getSecretID()); + self::assertSame('sec-set', $t->SecretID); + self::assertSame('desc-set', $t->getDescription()); + self::assertSame('desc-set', $t->Description); + self::assertCount(1, $t->getPolicies()); + self::assertSame($pol, $t->getPolicies()[0]); + self::assertCount(1, $t->getRoles()); + self::assertSame($role, $t->getRoles()[0]); + self::assertCount(1, $t->getServiceIdentities()); + self::assertSame($si, $t->getServiceIdentities()[0]); + self::assertCount(1, $t->getNodeIdentities()); + self::assertSame($ni, $t->getNodeIdentities()[0]); + self::assertCount(1, $t->getTemplatePolicies()); + self::assertSame($tp, $t->getTemplatePolicies()[0]); + self::assertTrue($t->isLocal()); + self::assertTrue($t->Local); + self::assertSame('auth-set', $t->getAuthMethod()); + self::assertSame('auth-set', $t->AuthMethod); + self::assertSame('hash-set', $t->getHash()); + self::assertSame('hash-set', $t->Hash); + self::assertSame('ns-set', $t->getNamespace()); + self::assertSame('ns-set', $t->Namespace); + self::assertSame('rules-set', $t->getRules()); + self::assertSame('rules-set', $t->Rules); + self::assertSame('pt-set', $t->getPartition()); + self::assertSame('pt-set', $t->Partition); + self::assertSame('amns-set', $t->getAuthMethodNamespace()); + self::assertSame('amns-set', $t->AuthMethodNamespace); + } +} + diff --git a/tests/Unit/ACL/KubernetesAuthMethodConfigTest.php b/tests/Unit/ACL/KubernetesAuthMethodConfigTest.php new file mode 100644 index 00000000..3eddaf1e --- /dev/null +++ b/tests/Unit/ACL/KubernetesAuthMethodConfigTest.php @@ -0,0 +1,62 @@ +getHost()); + self::assertSame('', $c->getCACert()); + self::assertSame('', $c->getServiceAccountJWT()); + } + + public function testConstructorWithParams(): void + { + $c = new KubernetesAuthMethodConfig(Host: 'https://k8s', CACert: 'cert', ServiceAccountJWT: 'jwt'); + self::assertSame('https://k8s', $c->getHost()); + self::assertSame('cert', $c->getCACert()); + self::assertSame('jwt', $c->getServiceAccountJWT()); + } + + public function testFluentSetters(): void + { + $c = new KubernetesAuthMethodConfig(); + $result = $c->setHost('h')->setCACert('c')->setServiceAccountJWT('j'); + self::assertSame($c, $result); + } + + public function testRenderToConfig(): void + { + $c = new KubernetesAuthMethodConfig(Host: 'h', CACert: 'c', ServiceAccountJWT: 'j'); + $config = $c->RenderToConfig(); + self::assertSame(['Host' => 'h', 'CACert' => 'c', 'ServiceAccountJWT' => 'j'], $config); + } + + public function testJsonSerializeOmitsEmptyFields(): void + { + $c = new KubernetesAuthMethodConfig(); + $out = $c->jsonSerialize(); + self::assertObjectNotHasProperty('Host', $out); + self::assertObjectNotHasProperty('CACert', $out); + self::assertObjectNotHasProperty('ServiceAccountJWT', $out); + } + + public function testJsonUnserialize(): void + { + $d = new \stdClass(); + $d->Host = 'https://k8s'; + $d->CACert = 'cert'; + $d->ServiceAccountJWT = 'jwt'; + $c = KubernetesAuthMethodConfig::jsonUnserialize($d); + self::assertSame('https://k8s', $c->getHost()); + } +} + diff --git a/tests/Unit/ACL/OIDCAuthMethodConfigTest.php b/tests/Unit/ACL/OIDCAuthMethodConfigTest.php new file mode 100644 index 00000000..5f4fde9b --- /dev/null +++ b/tests/Unit/ACL/OIDCAuthMethodConfigTest.php @@ -0,0 +1,121 @@ +getJWTSupportedAlgs()); + self::assertSame([], $c->getBoundAudiences()); + self::assertSame([], $c->getClaimMappings()); + self::assertSame([], $c->getListClaimMappings()); + self::assertSame('', $c->getOIDCDiscoveryURL()); + self::assertSame('', $c->getOIDCDiscoveryCACert()); + self::assertSame('', $c->getOIDCClientID()); + self::assertSame('', $c->getOIDCClientSecret()); + self::assertSame([], $c->getOIDCScopes()); + self::assertSame([], $c->getOIDCACRValues()); + self::assertSame([], $c->getAllowedRedirectURIs()); + self::assertFalse($c->isVerboseOIDCLogging()); + self::assertSame('', $c->getJWKSURL()); + self::assertSame('', $c->getJWKSCACert()); + self::assertSame([], $c->getJWTValidationPubKeys()); + self::assertSame('', $c->getBoundIssuer()); + self::assertSame(0, $c->getExpirationLeeway()->Nanoseconds()); + self::assertSame(0, $c->getNotBeforeLeeway()->Nanoseconds()); + self::assertSame(0, $c->getClockSkewLeeway()->Nanoseconds()); + } + + public function testConstructorWithParams(): void + { + $c = new OIDCAuthMethodConfig( + OIDCDiscoveryURL: 'https://oidc.example.com', + OIDCClientID: 'client-id', + OIDCClientSecret: 'client-secret', + AllowedRedirectURIs: ['https://example.com/callback'], + BoundAudiences: ['aud1'], + ClaimMappings: ['sub' => 'name'], + ); + self::assertSame('https://oidc.example.com', $c->getOIDCDiscoveryURL()); + self::assertSame('client-id', $c->getOIDCClientID()); + self::assertSame(['https://example.com/callback'], $c->getAllowedRedirectURIs()); + self::assertSame(['aud1'], $c->getBoundAudiences()); + self::assertSame(['sub' => 'name'], $c->getClaimMappings()); + } + + public function testFluentSetters(): void + { + $c = new OIDCAuthMethodConfig(); + $result = $c->setJWTSupportedAlgs('RS256') + ->setBoundAudiences('aud') + ->setClaimMappings(['k' => 'v']) + ->setListClaimMappings(['k' => 'v']) + ->setOIDCDiscoveryURL('url') + ->setOIDCDiscoveryCACert('cert') + ->setOIDCClientID('id') + ->setOIDCClientSecret('secret') + ->setOIDCScopes('openid') + ->setOIDCACRValues('acr') + ->setAllowedRedirectURIs('uri') + ->setVerboseOIDCLogging(true) + ->setJWKSURL('jwks') + ->setJWKSCACert('jcert') + ->setJWTValidationPubKeys('key') + ->setBoundIssuer('issuer') + ->setExpirationLeeway('5m') + ->setNotBeforeLeeway('10m') + ->setClockSkewLeeway('1m'); + self::assertSame($c, $result); + self::assertSame(['RS256'], $c->getJWTSupportedAlgs()); + self::assertTrue($c->isVerboseOIDCLogging()); + } + + public function testSetClaimMapping(): void + { + $c = new OIDCAuthMethodConfig(); + $c->setClaimMapping('sub', 'name'); + self::assertSame(['sub' => 'name'], $c->getClaimMappings()); + } + + public function testJsonSerializeOmitsEmptyFields(): void + { + $c = new OIDCAuthMethodConfig(); + $out = $c->jsonSerialize(); + self::assertObjectNotHasProperty('JWTSupportedAlgs', $out); + self::assertObjectNotHasProperty('OIDCDiscoveryURL', $out); + self::assertObjectNotHasProperty('VerboseOIDCLogging', $out); + } + + public function testJsonUnserialize(): void + { + $d = new \stdClass(); + $d->OIDCDiscoveryURL = 'https://oidc.example.com'; + $d->OIDCClientID = 'cid'; + $d->OIDCClientSecret = 'csec'; + $d->BoundAudiences = ['aud']; + $d->AllowedRedirectURIs = ['uri']; + $d->ClaimMappings = new \stdClass(); + $d->ClaimMappings->sub = 'name'; + $d->ListClaimMappings = new \stdClass(); + $d->JWTSupportedAlgs = ['RS256']; + $d->OIDCScopes = ['openid']; + $d->OIDCACRValues = []; + $d->JWTValidationPubKeys = []; + $d->ExpirationLeeway = '5m0s'; + $d->NotBeforeLeeway = '0s'; + $d->ClockSkewLeeway = '0s'; + $c = OIDCAuthMethodConfig::jsonUnserialize($d); + self::assertSame('https://oidc.example.com', $c->getOIDCDiscoveryURL()); + self::assertSame(['aud'], $c->getBoundAudiences()); + self::assertSame(['sub' => 'name'], $c->getClaimMappings()); + } +} + diff --git a/tests/Unit/Agent/AgentCheckRegistrationTest.php b/tests/Unit/Agent/AgentCheckRegistrationTest.php new file mode 100644 index 00000000..78315bef --- /dev/null +++ b/tests/Unit/Agent/AgentCheckRegistrationTest.php @@ -0,0 +1,104 @@ +getID()); + self::assertSame('', $r->ID); + self::assertSame('', $r->getServiceID()); + self::assertSame('', $r->ServiceID); + self::assertSame('', $r->getNamespace()); + self::assertSame('', $r->Namespace); + self::assertSame('', $r->getPartition()); + self::assertSame('', $r->Partition); + // inherited from AgentServiceCheck + self::assertSame('', $r->getCheckID()); + self::assertSame('', $r->getName()); + self::assertSame([], $r->getArgs()); + } + + public function testConstructorWithParams(): void + { + $r = new AgentCheckRegistration( + ID: 'chk-1', + ServiceID: 'svc-1', + CheckID: 'chk-id', + Name: 'health', + Interval: '10s', + HTTP: 'http://localhost:8080/health', + Namespace: 'ns-1', + Partition: 'pt-1', + ); + self::assertSame('chk-1', $r->getID()); + self::assertSame('chk-1', $r->ID); + self::assertSame('svc-1', $r->getServiceID()); + self::assertSame('ns-1', $r->getNamespace()); + self::assertSame('pt-1', $r->getPartition()); + // inherited + self::assertSame('chk-id', $r->getCheckID()); + self::assertSame('health', $r->getName()); + self::assertSame('10s', $r->getInterval()); + self::assertSame('http://localhost:8080/health', $r->getHTTP()); + } + + public function testFluentSetters(): void + { + $r = new AgentCheckRegistration(); + $result = $r->setID('id-1') + ->setServiceID('svc-1') + ->setNamespace('ns') + ->setPartition('pt'); + self::assertSame($r, $result); + self::assertSame('id-1', $r->getID()); + self::assertSame('id-1', $r->ID); + self::assertSame('svc-1', $r->getServiceID()); + self::assertSame('svc-1', $r->ServiceID); + self::assertSame('ns', $r->getNamespace()); + self::assertSame('ns', $r->Namespace); + self::assertSame('pt', $r->getPartition()); + self::assertSame('pt', $r->Partition); + } + + public function testJsonSerializeOmitsDefaults(): void + { + $r = new AgentCheckRegistration(); + $out = $r->jsonSerialize(); + self::assertInstanceOf(\stdClass::class, $out); + self::assertObjectNotHasProperty('ID', $out); + self::assertObjectNotHasProperty('ServiceID', $out); + self::assertObjectNotHasProperty('Namespace', $out); + self::assertObjectNotHasProperty('Partition', $out); + } + + public function testJsonSerializeWithValues(): void + { + $r = new AgentCheckRegistration( + ID: 'chk-1', + ServiceID: 'svc-1', + CheckID: 'cid', + HTTP: 'http://localhost/health', + Interval: '5s', + Namespace: 'ns', + Partition: 'pt', + ); + $out = $r->jsonSerialize(); + self::assertSame('chk-1', $out->ID); + self::assertSame('svc-1', $out->ServiceID); + self::assertSame('ns', $out->Namespace); + self::assertSame('pt', $out->Partition); + self::assertSame('cid', $out->CheckID); + self::assertSame('http://localhost/health', $out->HTTP); + self::assertSame('5s', $out->Interval); + } +} + diff --git a/tests/Unit/Agent/AgentCheckTest.php b/tests/Unit/Agent/AgentCheckTest.php new file mode 100644 index 00000000..320dbf27 --- /dev/null +++ b/tests/Unit/Agent/AgentCheckTest.php @@ -0,0 +1,84 @@ +getNode()); + self::assertSame('', $c->getCheckID()); + self::assertSame('', $c->getName()); + self::assertSame('', $c->getStatus()); + self::assertSame('', $c->getNotes()); + self::assertSame('', $c->getOutput()); + self::assertSame('', $c->getServiceID()); + self::assertSame('', $c->getServiceName()); + self::assertSame('', $c->getType()); + self::assertInstanceOf(HealthCheckDefinition::class, $c->getDefinition()); + self::assertSame('', $c->getNamespace()); + } + + public function testConstructorWithParams(): void + { + $c = new AgentCheck(Node: 'node1', CheckID: 'chk1', Name: 'serfHealth', Status: 'passing'); + self::assertSame('node1', $c->getNode()); + self::assertSame('chk1', $c->getCheckID()); + self::assertSame('serfHealth', $c->getName()); + self::assertSame('passing', $c->getStatus()); + } + + public function testFluentSetters(): void + { + $c = new AgentCheck(); + $result = $c->setNode('n')->setCheckID('c')->setName('nm') + ->setStatus('critical')->setNotes('note')->setOutput('out') + ->setServiceID('svc')->setServiceName('svcn')->setType('http') + ->setNamespace('ns'); + self::assertSame($c, $result); + self::assertSame('n', $c->getNode()); + self::assertSame('critical', $c->getStatus()); + } + + public function testJsonSerialize(): void + { + $c = new AgentCheck(Node: 'n', CheckID: 'c'); + $out = $c->jsonSerialize(); + self::assertSame('n', $out->Node); + self::assertSame('c', $out->CheckID); + } + + public function testJsonUnserialize(): void + { + $d = new \stdClass(); + $d->Node = 'n1'; + $d->CheckID = 'chk1'; + $d->Name = 'test'; + $d->Status = 'passing'; + $d->Notes = ''; + $d->Output = ''; + $d->ServiceID = ''; + $d->ServiceName = ''; + $d->Type = ''; + $d->Definition = new \stdClass(); + $c = AgentCheck::jsonUnserialize($d); + self::assertSame('n1', $c->getNode()); + self::assertSame('chk1', $c->getCheckID()); + self::assertInstanceOf(HealthCheckDefinition::class, $c->getDefinition()); + } + + public function testToString(): void + { + $c = new AgentCheck(CheckID: 'my-check'); + self::assertSame('my-check', (string)$c); + } +} + diff --git a/tests/Unit/Agent/AgentCheckUpdateTest.php b/tests/Unit/Agent/AgentCheckUpdateTest.php new file mode 100644 index 00000000..c7d53b4d --- /dev/null +++ b/tests/Unit/Agent/AgentCheckUpdateTest.php @@ -0,0 +1,60 @@ +getStatus()); + self::assertSame('', $u->getOutput()); + } + + public function testConstructorWithParams(): void + { + $u = new AgentCheckUpdate(Status: 'passing', Output: 'ok'); + self::assertSame('passing', $u->getStatus()); + self::assertSame('ok', $u->getOutput()); + } + + public function testFluentSetters(): void + { + $u = new AgentCheckUpdate(); + $result = $u->setStatus('critical')->setOutput('err'); + self::assertSame($u, $result); + self::assertSame('critical', $u->getStatus()); + self::assertSame('err', $u->getOutput()); + } + + public function testJsonSerialize(): void + { + $u = new AgentCheckUpdate(Status: 's', Output: 'o'); + $out = $u->jsonSerialize(); + self::assertSame('s', $out->Status); + self::assertSame('o', $out->Output); + } + + public function testJsonUnserialize(): void + { + $d = new \stdClass(); + $d->Status = 'passing'; + $d->Output = 'ok'; + $u = AgentCheckUpdate::jsonUnserialize($d); + self::assertSame('passing', $u->getStatus()); + self::assertSame('ok', $u->getOutput()); + } + + public function testToString(): void + { + $u = new AgentCheckUpdate(Status: 'passing', Output: 'ok'); + self::assertSame('passing: ok', (string)$u); + } +} + diff --git a/tests/Unit/Agent/AgentChecksResponseTest.php b/tests/Unit/Agent/AgentChecksResponseTest.php new file mode 100644 index 00000000..a4a6e291 --- /dev/null +++ b/tests/Unit/Agent/AgentChecksResponseTest.php @@ -0,0 +1,55 @@ +getValue()); + self::assertSame([], $r->Checks); + self::assertNull($r->Err); + } + + public function testUnmarshalValue(): void + { + $obj = new \stdClass(); + $obj->Node = 'n1'; + $obj->CheckID = 'chk1'; + $obj->Name = 'test'; + $obj->Status = 'passing'; + $obj->Notes = ''; + $obj->Output = ''; + $obj->ServiceID = ''; + $obj->ServiceName = ''; + $obj->Type = ''; + $obj->Definition = new \stdClass(); + + $r = new AgentChecksResponse(); + $r->unmarshalValue(['chk1' => $obj]); + + $checks = $r->getValue(); + self::assertCount(1, $checks); + self::assertArrayHasKey('chk1', $checks); + self::assertInstanceOf(AgentCheck::class, $checks['chk1']); + self::assertSame('n1', $checks['chk1']->getNode()); + } + + public function testOffsetAccess(): void + { + $r = new AgentChecksResponse(); + self::assertTrue(isset($r[0])); + self::assertTrue(isset($r[1])); + self::assertSame([], $r[0]); + self::assertNull($r[1]); + } +} + diff --git a/tests/Unit/Agent/AgentHealthServiceResponseTest.php b/tests/Unit/Agent/AgentHealthServiceResponseTest.php new file mode 100644 index 00000000..35986e60 --- /dev/null +++ b/tests/Unit/Agent/AgentHealthServiceResponseTest.php @@ -0,0 +1,66 @@ +getAggregatedStatus()); + self::assertSame('passing', $r->AggregatedStatus); + self::assertNull($r->getAgentServiceChecksInfos()); + self::assertNull($r->AgentServiceChecksInfo); + self::assertNull($r->Err); + } + + public function testConstructorWithChecksInfo(): void + { + $info = new \stdClass(); + $info->AggregatedStatus = 'passing'; + $info->Service = new \stdClass(); + $info->Service->ID = 'svc-1'; + $info->Service->Service = 'web'; + $info->Service->Port = 80; + $info->Service->Address = ''; + $info->Service->Tags = []; + $info->Service->Meta = new \stdClass(); + $info->Service->Kind = ''; + $info->Service->CreateIndex = 0; + $info->Service->ModifyIndex = 0; + $info->Checks = []; + + $r = new AgentHealthServiceResponse('passing', $info, null); + self::assertSame('passing', $r->getAggregatedStatus()); + self::assertInstanceOf(AgentServiceChecksInfo::class, $r->getAgentServiceChecksInfos()); + } + + public function testConstructorWithError(): void + { + $err = new Error('something failed'); + $r = new AgentHealthServiceResponse('critical', null, $err); + self::assertSame('critical', $r->getAggregatedStatus()); + self::assertSame($err, $r->Err); + } + + public function testOffsetAccess(): void + { + $r = new AgentHealthServiceResponse('passing', null, null); + self::assertTrue(isset($r[0])); + self::assertTrue(isset($r[1])); + self::assertTrue(isset($r[2])); + self::assertFalse(isset($r[3])); + self::assertSame('passing', $r[0]); + self::assertNull($r[1]); + self::assertNull($r[2]); + } +} + diff --git a/tests/Unit/Agent/AgentHealthServicesResponseTest.php b/tests/Unit/Agent/AgentHealthServicesResponseTest.php new file mode 100644 index 00000000..4d1291d6 --- /dev/null +++ b/tests/Unit/Agent/AgentHealthServicesResponseTest.php @@ -0,0 +1,64 @@ +getAggregatedStatus()); + self::assertSame('passing', $r->AggregatedStatus); + self::assertSame([], $r->getAgentServiceChecksInfos()); + self::assertNull($r->Err); + } + + public function testConstructorWithCheckInfos(): void + { + $info = new \stdClass(); + $info->AggregatedStatus = 'passing'; + $info->Service = new \stdClass(); + $info->Service->ID = 'svc-1'; + $info->Service->Service = 'web'; + $info->Service->Port = 80; + $info->Service->Address = ''; + $info->Service->Tags = []; + $info->Service->Meta = new \stdClass(); + $info->Service->Kind = ''; + $info->Service->CreateIndex = 0; + $info->Service->ModifyIndex = 0; + $info->Checks = []; + + $r = new AgentHealthServicesResponse('passing', [$info], null); + self::assertCount(1, $r->getAgentServiceChecksInfos()); + self::assertInstanceOf(AgentServiceChecksInfo::class, $r->getAgentServiceChecksInfos()[0]); + } + + public function testConstructorWithError(): void + { + $err = new Error('fail'); + $r = new AgentHealthServicesResponse('critical', [], $err); + self::assertSame($err, $r->Err); + } + + public function testOffsetAccess(): void + { + $r = new AgentHealthServicesResponse('passing', [], null); + self::assertTrue(isset($r[0])); + self::assertTrue(isset($r[1])); + self::assertTrue(isset($r[2])); + self::assertFalse(isset($r[3])); + self::assertSame('passing', $r[0]); + self::assertSame([], $r[1]); + self::assertNull($r[2]); + } +} + diff --git a/tests/Unit/Agent/AgentMemberTest.php b/tests/Unit/Agent/AgentMemberTest.php new file mode 100644 index 00000000..145997a0 --- /dev/null +++ b/tests/Unit/Agent/AgentMemberTest.php @@ -0,0 +1,68 @@ +getName()); + self::assertSame('', $m->getAddr()); + self::assertSame(0, $m->getPort()); + self::assertSame([], $m->Tags); + self::assertSame(0, $m->getStatus()); + self::assertSame(0, $m->getProtocolMin()); + self::assertSame(0, $m->getProtocolMax()); + self::assertSame(0, $m->getProtocolCur()); + self::assertSame(0, $m->getDelegateMin()); + self::assertSame(0, $m->getDelegateMax()); + self::assertSame(0, $m->getDelegateCur()); + } + + public function testConstructorWithParams(): void + { + $m = new AgentMember(Name: 'node1', Addr: '127.0.0.1', Port: 8301, Tags: ['role' => 'consul'], Status: 1); + self::assertSame('node1', $m->getName()); + self::assertSame('127.0.0.1', $m->getAddr()); + self::assertSame(8301, $m->getPort()); + self::assertSame(['role' => 'consul'], $m->Tags); + self::assertSame(1, $m->getStatus()); + } + + public function testJsonSerialize(): void + { + $m = new AgentMember(Name: 'n', Addr: 'a', Port: 1); + $out = $m->jsonSerialize(); + self::assertSame('n', $out->Name); + self::assertSame('a', $out->Addr); + self::assertSame(1, $out->Port); + } + + public function testJsonUnserialize(): void + { + $d = new \stdClass(); + $d->Name = 'node2'; + $d->Addr = '10.0.0.1'; + $d->Port = 8301; + $d->Tags = new \stdClass(); + $d->Tags->role = 'consul'; + $d->Status = 1; + $d->ProtocolMin = 1; + $d->ProtocolMax = 5; + $d->ProtocolCur = 3; + $d->DelegateMin = 2; + $d->DelegateMax = 5; + $d->DelegateCur = 4; + $m = AgentMember::jsonUnserialize($d); + self::assertSame('node2', $m->getName()); + self::assertSame(8301, $m->getPort()); + } +} + diff --git a/tests/Unit/Agent/AgentMembersResponseTest.php b/tests/Unit/Agent/AgentMembersResponseTest.php new file mode 100644 index 00000000..a8d63f77 --- /dev/null +++ b/tests/Unit/Agent/AgentMembersResponseTest.php @@ -0,0 +1,55 @@ +getValue()); + self::assertSame([], $r->Members); + self::assertNull($r->Err); + } + + public function testUnmarshalValue(): void + { + $obj = new \stdClass(); + $obj->Name = 'node-1'; + $obj->Addr = '10.0.0.1'; + $obj->Port = 8301; + $obj->Tags = new \stdClass(); + $obj->Status = 1; + $obj->ProtocolMin = 1; + $obj->ProtocolMax = 5; + $obj->ProtocolCur = 2; + $obj->DelegateMin = 2; + $obj->DelegateMax = 5; + $obj->DelegateCur = 4; + + $r = new AgentMembersResponse(); + $r->unmarshalValue([$obj]); + + $members = $r->getValue(); + self::assertCount(1, $members); + self::assertInstanceOf(AgentMember::class, $members[0]); + self::assertSame('node-1', $members[0]->getName()); + } + + public function testOffsetAccess(): void + { + $r = new AgentMembersResponse(); + self::assertTrue(isset($r[0])); + self::assertTrue(isset($r[1])); + self::assertSame([], $r[0]); + self::assertNull($r[1]); + } +} + diff --git a/tests/Unit/Agent/AgentServiceCheckTest.php b/tests/Unit/Agent/AgentServiceCheckTest.php new file mode 100644 index 00000000..fcb08c11 --- /dev/null +++ b/tests/Unit/Agent/AgentServiceCheckTest.php @@ -0,0 +1,85 @@ +getCheckID()); + self::assertSame('', $c->getName()); + self::assertSame([], $c->getArgs()); + self::assertSame('', $c->getDockerContainerID()); + self::assertSame('', $c->getInterval()); + self::assertSame('', $c->getTimeout()); + self::assertSame('', $c->getTTL()); + self::assertSame('', $c->getHTTP()); + self::assertSame('', $c->getMethod()); + self::assertSame('', $c->getTCP()); + self::assertSame('', $c->getStatus()); + self::assertSame('', $c->getNotes()); + self::assertFalse($c->isTLSSkipVerify()); + self::assertSame('', $c->getGRPC()); + self::assertFalse($c->isGRPCUseTLS()); + self::assertSame(0, $c->getSuccessBeforePassing()); + self::assertSame(0, $c->getFailuresBeforeCritical()); + self::assertSame('', $c->getDeregisterCriticalServiceAfter()); + } + + public function testConstructorWithParams(): void + { + $c = new AgentServiceCheck( + CheckID: 'chk-1', + Name: 'http-check', + HTTP: 'http://localhost:8080/health', + Interval: '10s', + Timeout: '5s', + Status: 'critical', + ); + self::assertSame('chk-1', $c->getCheckID()); + self::assertSame('http-check', $c->getName()); + self::assertSame('http://localhost:8080/health', $c->getHTTP()); + self::assertSame('10s', $c->getInterval()); + self::assertSame('5s', $c->getTimeout()); + self::assertSame('critical', $c->getStatus()); + } + + public function testFluentSetters(): void + { + $c = new AgentServiceCheck(); + $result = $c->setCheckID('c')->setName('n')->setHTTP('http://example.com') + ->setInterval('5s')->setTimeout('2s')->setStatus('passing'); + self::assertSame($c, $result); + self::assertSame('c', $c->getCheckID()); + self::assertSame('http://example.com', $c->getHTTP()); + } + + public function testJsonSerialize(): void + { + $c = new AgentServiceCheck(CheckID: 'chk', Name: 'test', TTL: '30s'); + $out = $c->jsonSerialize(); + self::assertSame('chk', $out->CheckID); + self::assertSame('test', $out->Name); + self::assertSame('30s', $out->TTL); + } + + public function testJsonUnserialize(): void + { + $d = new \stdClass(); + $d->CheckID = 'c1'; + $d->Name = 'check'; + $d->HTTP = 'http://localhost'; + $d->Interval = '10s'; + $c = AgentServiceCheck::jsonUnserialize($d); + self::assertSame('c1', $c->getCheckID()); + self::assertSame('http://localhost', $c->getHTTP()); + } +} + diff --git a/tests/Unit/Agent/AgentServiceChecksInfoTest.php b/tests/Unit/Agent/AgentServiceChecksInfoTest.php new file mode 100644 index 00000000..713c116e --- /dev/null +++ b/tests/Unit/Agent/AgentServiceChecksInfoTest.php @@ -0,0 +1,41 @@ +getAggregatedStatus()); + self::assertNull($i->getService()); + self::assertInstanceOf(HealthChecks::class, $i->getChecks()); + } + + public function testConstructorWithParams(): void + { + $svc = new AgentService(ID: 'svc-1', Service: 'web'); + $i = new AgentServiceChecksInfo(AggregatedStatus: 'passing', Service: $svc); + self::assertSame('passing', $i->getAggregatedStatus()); + self::assertSame($svc, $i->getService()); + } + + public function testFluentSetters(): void + { + $i = new AgentServiceChecksInfo(); + $svc = new AgentService(ID: 's'); + $result = $i->setAggregatedStatus('critical')->setService($svc); + self::assertSame($i, $result); + self::assertSame('critical', $i->getAggregatedStatus()); + self::assertSame($svc, $i->getService()); + } +} + diff --git a/tests/Unit/Agent/AgentServiceChecksTest.php b/tests/Unit/Agent/AgentServiceChecksTest.php new file mode 100644 index 00000000..68dcda90 --- /dev/null +++ b/tests/Unit/Agent/AgentServiceChecksTest.php @@ -0,0 +1,128 @@ +getChecks()); + self::assertCount(0, $c); + } + + public function testConstructorWithParams(): void + { + $chk = new AgentServiceCheck(CheckID: 'c1', Name: 'test'); + $c = new AgentServiceChecks(Checks: [$chk]); + self::assertCount(1, $c); + self::assertSame($chk, $c->getChecks()[0]); + } + + public function testSetChecksVariadic(): void + { + $c = new AgentServiceChecks(); + $chk1 = new AgentServiceCheck(CheckID: 'c1'); + $chk2 = new AgentServiceCheck(CheckID: 'c2'); + $result = $c->setChecks($chk1, $chk2); + self::assertSame($c, $result); + self::assertCount(2, $c); + self::assertSame($chk1, $c->getChecks()[0]); + self::assertSame($chk2, $c->getChecks()[1]); + } + + public function testArrayAccessOffsetExists(): void + { + $chk = new AgentServiceCheck(CheckID: 'c1'); + $c = new AgentServiceChecks(Checks: [$chk]); + self::assertTrue(isset($c[0])); + self::assertFalse(isset($c[1])); + } + + public function testArrayAccessOffsetGet(): void + { + $chk = new AgentServiceCheck(CheckID: 'c1'); + $c = new AgentServiceChecks(Checks: [$chk]); + self::assertSame($chk, $c[0]); + self::assertNull($c[99]); + } + + public function testArrayAccessOffsetSet(): void + { + $c = new AgentServiceChecks(); + $chk = new AgentServiceCheck(CheckID: 'c1'); + $c->setChecks($chk); + $chk2 = new AgentServiceCheck(CheckID: 'c2'); + $c[0] = $chk2; + self::assertSame($chk2, $c[0]); + } + + public function testArrayAccessOffsetUnset(): void + { + $chk = new AgentServiceCheck(CheckID: 'c1'); + $c = new AgentServiceChecks(Checks: [$chk]); + unset($c[0]); + self::assertFalse(isset($c[0])); + } + + public function testCountable(): void + { + $c = new AgentServiceChecks(Checks: [ + new AgentServiceCheck(CheckID: 'c1'), + new AgentServiceCheck(CheckID: 'c2'), + ]); + self::assertSame(2, $c->count()); + self::assertCount(2, $c); + } + + public function testJsonSerialize(): void + { + $chk = new AgentServiceCheck(CheckID: 'c1', HTTP: 'http://localhost'); + $c = new AgentServiceChecks(Checks: [$chk]); + $out = $c->jsonSerialize(); + self::assertCount(1, $out); + self::assertInstanceOf(AgentServiceCheck::class, $out[0]); + } + + public function testJsonUnserialize(): void + { + $obj = new \stdClass(); + $obj->CheckID = 'c1'; + $obj->Name = 'test'; + $obj->Args = []; + $obj->DockerContainerID = ''; + $obj->Shell = ''; + $obj->Interval = '10s'; + $obj->Timeout = ''; + $obj->TTL = ''; + $obj->HTTP = ''; + $obj->Method = ''; + $obj->TCP = ''; + $obj->Status = ''; + $obj->Notes = ''; + $obj->TLSSkipVerify = false; + $obj->GRPC = ''; + $obj->GRPCUseTLS = false; + $obj->H2PING = ''; + $obj->H2PINGUseTLS = false; + $obj->AliasNode = ''; + $obj->AliasService = ''; + $obj->SuccessBeforePassing = 0; + $obj->FailuresBeforeCritical = 0; + $obj->DeregisterCriticalServiceAfter = ''; + + $c = AgentServiceChecks::jsonUnserialize([$obj]); + self::assertInstanceOf(AgentServiceChecks::class, $c); + self::assertCount(1, $c); + self::assertInstanceOf(AgentServiceCheck::class, $c[0]); + self::assertSame('c1', $c[0]->getCheckID()); + } +} + diff --git a/tests/Unit/Agent/AgentServiceConnectProxyConfigTest.php b/tests/Unit/Agent/AgentServiceConnectProxyConfigTest.php new file mode 100644 index 00000000..ab9956ed --- /dev/null +++ b/tests/Unit/Agent/AgentServiceConnectProxyConfigTest.php @@ -0,0 +1,55 @@ +getDestinationServiceName()); + self::assertSame('', $p->getDestinationServiceID()); + self::assertSame('', $p->getLocalServiceAddress()); + self::assertSame(0, $p->getLocalServicePort()); + self::assertSame([], $p->getEnvoyExtensions()); + self::assertSame([], $p->getUpstreams()); + } + + public function testConstructorWithParams(): void + { + $p = new AgentServiceConnectProxyConfig( + DestinationServiceName: 'web', + DestinationServiceID: 'web-1', + LocalServiceAddress: '127.0.0.1', + LocalServicePort: 8080, + ); + self::assertSame('web', $p->getDestinationServiceName()); + self::assertSame('web-1', $p->getDestinationServiceID()); + self::assertSame('127.0.0.1', $p->getLocalServiceAddress()); + self::assertSame(8080, $p->getLocalServicePort()); + } + + public function testFluentSetters(): void + { + $p = new AgentServiceConnectProxyConfig(); + $result = $p->setDestinationServiceName('svc')->setDestinationServiceID('svc-1') + ->setLocalServiceAddress('10.0.0.1')->setLocalServicePort(9090); + self::assertSame($p, $result); + self::assertSame('svc', $p->getDestinationServiceName()); + } + + public function testJsonSerialize(): void + { + $p = new AgentServiceConnectProxyConfig(DestinationServiceName: 'web', LocalServicePort: 80); + $out = $p->jsonSerialize(); + self::assertSame('web', $out->DestinationServiceName); + self::assertSame(80, $out->LocalServicePort); + } +} + diff --git a/tests/Unit/Agent/AgentServiceConnectTest.php b/tests/Unit/Agent/AgentServiceConnectTest.php new file mode 100644 index 00000000..64facb98 --- /dev/null +++ b/tests/Unit/Agent/AgentServiceConnectTest.php @@ -0,0 +1,36 @@ +isNative()); + self::assertNull($c->getSidecarService()); + } + + public function testConstructorWithParams(): void + { + $sidecar = new AgentServiceRegistration(ID: 'sidecar', Name: 'web-sidecar'); + $c = new AgentServiceConnect(Native: true, SidecarService: $sidecar); + self::assertTrue($c->isNative()); + self::assertSame($sidecar, $c->getSidecarService()); + } + + public function testJsonSerialize(): void + { + $c = new AgentServiceConnect(Native: true); + $out = $c->jsonSerialize(); + self::assertTrue($out->Native); + } +} + diff --git a/tests/Unit/Agent/AgentServiceRegistrationTest.php b/tests/Unit/Agent/AgentServiceRegistrationTest.php new file mode 100644 index 00000000..8c7bceaa --- /dev/null +++ b/tests/Unit/Agent/AgentServiceRegistrationTest.php @@ -0,0 +1,59 @@ +getKind()); + self::assertSame('', $r->getID()); + self::assertSame('', $r->getName()); + self::assertSame(0, $r->getPort()); + self::assertSame('', $r->getAddress()); + self::assertFalse($r->isEnableTagOverride()); + self::assertSame('', $r->getNamespace()); + self::assertSame('', $r->getPartition()); + } + + public function testConstructorWithParams(): void + { + $r = new AgentServiceRegistration( + Kind: ServiceKind::ConnectProxy, + ID: 'svc-1', + Name: 'web', + Port: 8080, + Address: '10.0.0.1', + Tags: ['v1', 'primary'], + ); + self::assertSame(ServiceKind::ConnectProxy, $r->getKind()); + self::assertSame('svc-1', $r->getID()); + self::assertSame('web', $r->getName()); + self::assertSame(8080, $r->getPort()); + self::assertSame(['v1', 'primary'], $r->getTags()); + } + + public function testConstructorWithStringKind(): void + { + $r = new AgentServiceRegistration(Kind: 'connect-proxy'); + self::assertSame(ServiceKind::ConnectProxy, $r->getKind()); + } + + public function testJsonSerialize(): void + { + $r = new AgentServiceRegistration(ID: 'svc', Name: 'web', Port: 80); + $out = $r->jsonSerialize(); + self::assertSame('svc', $out->ID); + self::assertSame('web', $out->Name); + self::assertSame(80, $out->Port); + } +} + diff --git a/tests/Unit/Agent/AgentServiceResponseTest.php b/tests/Unit/Agent/AgentServiceResponseTest.php new file mode 100644 index 00000000..f4e3d733 --- /dev/null +++ b/tests/Unit/Agent/AgentServiceResponseTest.php @@ -0,0 +1,61 @@ +getValue()); + self::assertNull($r->Service); + self::assertNull($r->Err); + } + + public function testUnmarshalValueNull(): void + { + $r = new AgentServiceResponse(); + $r->unmarshalValue(null); + self::assertNull($r->getValue()); + } + + public function testUnmarshalValueWithService(): void + { + $obj = new \stdClass(); + $obj->Kind = ''; + $obj->ID = 'svc-1'; + $obj->Service = 'web'; + $obj->Port = 8080; + $obj->Address = '10.0.0.1'; + $obj->Tags = []; + $obj->Meta = new \stdClass(); + $obj->CreateIndex = 1; + $obj->ModifyIndex = 2; + + $r = new AgentServiceResponse(); + $r->unmarshalValue($obj); + + $svc = $r->getValue(); + self::assertInstanceOf(AgentService::class, $svc); + self::assertSame('svc-1', $svc->getID()); + self::assertSame('web', $svc->getService()); + self::assertSame(8080, $svc->getPort()); + } + + public function testOffsetAccess(): void + { + $r = new AgentServiceResponse(); + self::assertTrue(isset($r[0])); + self::assertTrue(isset($r[1])); + self::assertNull($r[0]); + self::assertNull($r[1]); + } +} + diff --git a/tests/Unit/Agent/AgentServiceTest.php b/tests/Unit/Agent/AgentServiceTest.php new file mode 100644 index 00000000..2035b98f --- /dev/null +++ b/tests/Unit/Agent/AgentServiceTest.php @@ -0,0 +1,58 @@ +getKind()); + self::assertSame('', $s->getID()); + self::assertSame('', $s->getService()); + self::assertSame(0, $s->getPort()); + self::assertSame('', $s->getAddress()); + self::assertSame(0, $s->getCreateIndex()); + self::assertSame(0, $s->getModifyIndex()); + } + + public function testConstructorWithParams(): void + { + $s = new AgentService( + Kind: ServiceKind::ConnectProxy, + ID: 'svc-1', + Service: 'web', + Port: 8080, + Address: '10.0.0.1', + Tags: ['v1'], + ); + self::assertSame(ServiceKind::ConnectProxy, $s->getKind()); + self::assertSame('svc-1', $s->getID()); + self::assertSame('web', $s->getService()); + self::assertSame(8080, $s->getPort()); + self::assertSame(['v1'], $s->getTags()); + } + + public function testConstructorWithStringKind(): void + { + $s = new AgentService(Kind: 'connect-proxy'); + self::assertSame(ServiceKind::ConnectProxy, $s->getKind()); + } + + public function testJsonSerialize(): void + { + $s = new AgentService(ID: 'svc', Service: 'web', Port: 80); + $out = $s->jsonSerialize(); + self::assertSame('svc', $out->ID); + self::assertSame('web', $out->Service); + self::assertSame(80, $out->Port); + } +} + diff --git a/tests/Unit/Agent/AgentServicesResponseTest.php b/tests/Unit/Agent/AgentServicesResponseTest.php new file mode 100644 index 00000000..81fd83d3 --- /dev/null +++ b/tests/Unit/Agent/AgentServicesResponseTest.php @@ -0,0 +1,62 @@ +getValue()); + self::assertNull($r->Services); + self::assertNull($r->Err); + } + + public function testUnmarshalValueNull(): void + { + $r = new AgentServicesResponse(); + $r->unmarshalValue(null); + self::assertNull($r->getValue()); + } + + public function testUnmarshalValueWithServices(): void + { + $obj = new \stdClass(); + $obj->Kind = ''; + $obj->ID = 'svc-1'; + $obj->Service = 'web'; + $obj->Port = 8080; + $obj->Address = '10.0.0.1'; + $obj->Tags = []; + $obj->Meta = new \stdClass(); + $obj->CreateIndex = 1; + $obj->ModifyIndex = 2; + + $r = new AgentServicesResponse(); + $r->unmarshalValue(['web' => $obj]); + + $svcs = $r->getValue(); + self::assertIsArray($svcs); + self::assertCount(1, $svcs); + self::assertArrayHasKey('web', $svcs); + self::assertInstanceOf(AgentService::class, $svcs['web']); + self::assertSame('svc-1', $svcs['web']->getID()); + } + + public function testOffsetAccess(): void + { + $r = new AgentServicesResponse(); + self::assertTrue(isset($r[0])); + self::assertTrue(isset($r[1])); + self::assertNull($r[0]); + self::assertNull($r[1]); + } +} + diff --git a/tests/Unit/Agent/AgentTokenTest.php b/tests/Unit/Agent/AgentTokenTest.php new file mode 100644 index 00000000..0aa005ab --- /dev/null +++ b/tests/Unit/Agent/AgentTokenTest.php @@ -0,0 +1,53 @@ +getToken()); + self::assertSame('', $t->Token); + } + + public function testConstructorWithParams(): void + { + $t = new AgentToken(Token: 'tok-123'); + self::assertSame('tok-123', $t->getToken()); + self::assertSame('tok-123', $t->Token); + } + + public function testFluentSetter(): void + { + $t = new AgentToken(); + $result = $t->setToken('abc'); + self::assertSame($t, $result); + self::assertSame('abc', $t->getToken()); + self::assertSame('abc', $t->Token); + } + + public function testJsonSerialize(): void + { + $t = new AgentToken(Token: 'tok'); + $out = $t->jsonSerialize(); + self::assertInstanceOf(\stdClass::class, $out); + self::assertSame('tok', $out->Token); + } + + public function testJsonUnserialize(): void + { + $d = new \stdClass(); + $d->Token = 'tok2'; + $t = AgentToken::jsonUnserialize($d); + self::assertInstanceOf(AgentToken::class, $t); + self::assertSame('tok2', $t->getToken()); + } +} + diff --git a/tests/Unit/Agent/AgentWeightsTest.php b/tests/Unit/Agent/AgentWeightsTest.php new file mode 100644 index 00000000..d63211d6 --- /dev/null +++ b/tests/Unit/Agent/AgentWeightsTest.php @@ -0,0 +1,62 @@ +getPassing()); + self::assertSame(0, $w->Passing); + self::assertSame(0, $w->getWarning()); + self::assertSame(0, $w->Warning); + } + + public function testConstructorWithParams(): void + { + $w = new AgentWeights(Passing: 10, Warning: 1); + self::assertSame(10, $w->getPassing()); + self::assertSame(10, $w->Passing); + self::assertSame(1, $w->getWarning()); + self::assertSame(1, $w->Warning); + } + + public function testFluentSetters(): void + { + $w = new AgentWeights(); + $result = $w->setPassing(5)->setWarning(2); + self::assertSame($w, $result); + self::assertSame(5, $w->getPassing()); + self::assertSame(5, $w->Passing); + self::assertSame(2, $w->getWarning()); + self::assertSame(2, $w->Warning); + } + + public function testJsonSerialize(): void + { + $w = new AgentWeights(Passing: 5, Warning: 2); + $out = $w->jsonSerialize(); + self::assertInstanceOf(\stdClass::class, $out); + self::assertSame(5, $out->Passing); + self::assertSame(2, $out->Warning); + } + + public function testJsonUnserialize(): void + { + $d = new \stdClass(); + $d->Passing = 3; + $d->Warning = 1; + $w = AgentWeights::jsonUnserialize($d); + self::assertInstanceOf(AgentWeights::class, $w); + self::assertSame(3, $w->getPassing()); + self::assertSame(1, $w->getWarning()); + } +} + diff --git a/tests/Unit/Agent/ConnectProxyConfigTest.php b/tests/Unit/Agent/ConnectProxyConfigTest.php new file mode 100644 index 00000000..aa3f3dc2 --- /dev/null +++ b/tests/Unit/Agent/ConnectProxyConfigTest.php @@ -0,0 +1,52 @@ +getProxyServiceID()); + self::assertSame('', $c->getTargetServiceID()); + self::assertSame('', $c->getTargetServiceName()); + self::assertSame('', $c->getContentHash()); + self::assertSame([], $c->getConfig()); + self::assertSame([], $c->getUpstreams()); + } + + public function testConstructorWithParams(): void + { + $u = new Upstream(DestinationName: 'db', LocalBindPort: 5432); + $c = new ConnectProxyConfig( + ProxyServiceID: 'proxy-1', + TargetServiceID: 'web-1', + TargetServiceName: 'web', + ContentHash: 'hash', + Config: ['protocol' => 'http'], + Upstreams: [$u], + ); + self::assertSame('proxy-1', $c->getProxyServiceID()); + self::assertSame('web', $c->getTargetServiceName()); + self::assertSame(['protocol' => 'http'], $c->getConfig()); + self::assertCount(1, $c->getUpstreams()); + } + + public function testFluentSetters(): void + { + $c = new ConnectProxyConfig(); + $result = $c->setProxyServiceID('p')->setTargetServiceID('t') + ->setTargetServiceName('n')->setContentHash('h') + ->setConfig(['k' => 'v'])->setUpstreams(); + self::assertSame($c, $result); + self::assertSame('p', $c->getProxyServiceID()); + } +} + diff --git a/tests/Unit/Agent/GaugeValueTest.php b/tests/Unit/Agent/GaugeValueTest.php new file mode 100644 index 00000000..70703b4b --- /dev/null +++ b/tests/Unit/Agent/GaugeValueTest.php @@ -0,0 +1,76 @@ +getName()); + self::assertSame('', $g->Name); + self::assertSame(0.0, $g->getValue()); + self::assertSame(0.0, $g->Value); + self::assertSame([], $g->getLabels()); + self::assertSame([], $g->Labels); + } + + public function testConstructorWithParams(): void + { + $g = new GaugeValue(Name: 'cpu', Value: 99.5, Labels: ['env' => 'prod']); + self::assertSame('cpu', $g->getName()); + self::assertSame(99.5, $g->getValue()); + self::assertSame(['env' => 'prod'], $g->getLabels()); + } + + public function testFluentSetters(): void + { + $g = new GaugeValue(); + $result = $g->setName('mem')->setValue(42.0)->setLabels(['zone' => 'us']); + self::assertSame($g, $result); + self::assertSame('mem', $g->getName()); + self::assertSame('mem', $g->Name); + self::assertSame(42.0, $g->getValue()); + self::assertSame(42.0, $g->Value); + self::assertSame(['zone' => 'us'], $g->getLabels()); + } + + public function testSetLabelsNull(): void + { + $g = new GaugeValue(Name: 'cpu', Labels: ['a' => 'b']); + $g->setLabels(null); + // After setLabels(null), the property is null; getLabels returns null. + self::assertNull($g->Labels); + } + + public function testJsonSerialize(): void + { + $g = new GaugeValue(Name: 'mem', Value: 42.0, Labels: ['k' => 'v']); + $out = $g->jsonSerialize(); + self::assertInstanceOf(\stdClass::class, $out); + self::assertSame('mem', $out->Name); + self::assertSame(42.0, $out->Value); + self::assertSame(['k' => 'v'], $out->Labels); + } + + public function testJsonUnserialize(): void + { + $d = new \stdClass(); + $d->Name = 'cpu'; + $d->Value = 1.5; + $d->Labels = new \stdClass(); + $d->Labels->env = 'prod'; + $g = GaugeValue::jsonUnserialize($d); + self::assertInstanceOf(GaugeValue::class, $g); + self::assertSame('cpu', $g->getName()); + self::assertSame(1.5, $g->getValue()); + self::assertSame(['env' => 'prod'], $g->getLabels()); + } +} + diff --git a/tests/Unit/Agent/MemberACLModeTest.php b/tests/Unit/Agent/MemberACLModeTest.php new file mode 100644 index 00000000..7bfcf9a9 --- /dev/null +++ b/tests/Unit/Agent/MemberACLModeTest.php @@ -0,0 +1,44 @@ +value); + self::assertSame('1', MemberACLMode::Enabled->value); + self::assertSame('2', MemberACLMode::Legacy->value); + self::assertSame('3', MemberACLMode::Unknown->value); + } + + public function testFromString(): void + { + self::assertSame(MemberACLMode::Disabled, MemberACLMode::from('0')); + self::assertSame(MemberACLMode::Enabled, MemberACLMode::from('1')); + self::assertSame(MemberACLMode::Legacy, MemberACLMode::from('2')); + self::assertSame(MemberACLMode::Unknown, MemberACLMode::from('3')); + } + + public function testTryFromValid(): void + { + self::assertSame(MemberACLMode::Enabled, MemberACLMode::tryFrom('1')); + } + + public function testTryFromInvalid(): void + { + self::assertNull(MemberACLMode::tryFrom('99')); + } + + public function testCaseCount(): void + { + self::assertCount(4, MemberACLMode::cases()); + } +} + diff --git a/tests/Unit/Agent/MemberOptsTest.php b/tests/Unit/Agent/MemberOptsTest.php new file mode 100644 index 00000000..4f8ff5c7 --- /dev/null +++ b/tests/Unit/Agent/MemberOptsTest.php @@ -0,0 +1,77 @@ +isWAN()); + self::assertFalse($m->WAN); + self::assertSame('', $m->getSegment()); + self::assertSame('', $m->Segment); + self::assertSame('', $m->getFilter()); + self::assertSame('', $m->Filter); + } + + public function testConstructorWithParams(): void + { + $m = new MemberOpts(WAN: true, Segment: 'seg1', Filter: 'Status == "alive"'); + self::assertTrue($m->isWAN()); + self::assertTrue($m->WAN); + self::assertSame('seg1', $m->getSegment()); + self::assertSame('seg1', $m->Segment); + self::assertSame('Status == "alive"', $m->getFilter()); + self::assertSame('Status == "alive"', $m->Filter); + } + + public function testFluentSetters(): void + { + $m = new MemberOpts(); + $result = $m->setWAN(true)->setSegment('s')->setFilter('f'); + self::assertSame($m, $result); + self::assertTrue($m->isWAN()); + self::assertSame('s', $m->getSegment()); + self::assertSame('f', $m->getFilter()); + } + + public function testJsonSerializeOmitsDefaults(): void + { + $m = new MemberOpts(); + $out = $m->jsonSerialize(); + self::assertInstanceOf(\stdClass::class, $out); + self::assertObjectNotHasProperty('WAN', $out); + self::assertObjectNotHasProperty('Segment', $out); + self::assertObjectNotHasProperty('Filter', $out); + } + + public function testJsonSerializeWithValues(): void + { + $m = new MemberOpts(WAN: true, Segment: 'seg', Filter: 'f'); + $out = $m->jsonSerialize(); + self::assertTrue($out->WAN); + self::assertSame('seg', $out->Segment); + self::assertSame('f', $out->Filter); + } + + public function testJsonUnserialize(): void + { + $d = new \stdClass(); + $d->WAN = true; + $d->Segment = 'seg'; + $d->Filter = 'f'; + $m = MemberOpts::jsonUnserialize($d); + self::assertInstanceOf(MemberOpts::class, $m); + self::assertTrue($m->isWAN()); + self::assertSame('seg', $m->getSegment()); + self::assertSame('f', $m->getFilter()); + } +} + diff --git a/tests/Unit/Agent/MetricsInfoResponseTest.php b/tests/Unit/Agent/MetricsInfoResponseTest.php new file mode 100644 index 00000000..302bfc87 --- /dev/null +++ b/tests/Unit/Agent/MetricsInfoResponseTest.php @@ -0,0 +1,55 @@ +getValue()); + self::assertNull($r->MetricsInfo); + self::assertNull($r->Err); + } + + public function testUnmarshalValueNull(): void + { + $r = new MetricsInfoResponse(); + $r->unmarshalValue(null); + self::assertNull($r->getValue()); + } + + public function testUnmarshalValueWithMetrics(): void + { + $obj = new \stdClass(); + $obj->Timestamp = '2025-01-01T00:00:00Z'; + $obj->Gauges = []; + $obj->Points = []; + $obj->Counters = []; + $obj->Samples = []; + + $r = new MetricsInfoResponse(); + $r->unmarshalValue($obj); + + $info = $r->getValue(); + self::assertInstanceOf(MetricsInfo::class, $info); + self::assertSame('2025-01-01T00:00:00Z', $info->getTimestamp()); + } + + public function testOffsetAccess(): void + { + $r = new MetricsInfoResponse(); + self::assertTrue(isset($r[0])); + self::assertTrue(isset($r[1])); + self::assertNull($r[0]); + self::assertNull($r[1]); + } +} + diff --git a/tests/Unit/Agent/MetricsInfoTest.php b/tests/Unit/Agent/MetricsInfoTest.php new file mode 100644 index 00000000..a5fd47aa --- /dev/null +++ b/tests/Unit/Agent/MetricsInfoTest.php @@ -0,0 +1,115 @@ +getTimestamp()); + self::assertSame('', $m->Timestamp); + self::assertSame([], $m->getGauges()); + self::assertSame([], $m->getPoints()); + self::assertSame([], $m->getCounters()); + self::assertSame([], $m->getSamples()); + } + + public function testConstructorWithParams(): void + { + $gauge = new GaugeValue(Name: 'cpu', Value: 50.0); + $point = new PointValue(Name: 'p', Points: [1.0]); + $counter = new SampledValue(Name: 'c', Count: 1); + $sample = new SampledValue(Name: 's', Count: 2); + + $m = new MetricsInfo( + Timestamp: '2025-01-01T00:00:00Z', + Gauges: [$gauge], + Points: [$point], + Counters: [$counter], + Samples: [$sample], + ); + self::assertSame('2025-01-01T00:00:00Z', $m->getTimestamp()); + self::assertCount(1, $m->getGauges()); + self::assertSame($gauge, $m->getGauges()[0]); + self::assertCount(1, $m->getPoints()); + self::assertSame($point, $m->getPoints()[0]); + self::assertCount(1, $m->getCounters()); + self::assertSame($counter, $m->getCounters()[0]); + self::assertCount(1, $m->getSamples()); + self::assertSame($sample, $m->getSamples()[0]); + } + + public function testFluentSetters(): void + { + $m = new MetricsInfo(); + $gauge = new GaugeValue(Name: 'g'); + $result = $m->setTimestamp('ts') + ->setGauges($gauge) + ->setPoints() + ->setCounters() + ->setSamples(); + self::assertSame($m, $result); + self::assertSame('ts', $m->getTimestamp()); + self::assertCount(1, $m->getGauges()); + self::assertSame($gauge, $m->Gauges[0]); + } + + public function testJsonSerialize(): void + { + $m = new MetricsInfo(Timestamp: 'ts'); + $out = $m->jsonSerialize(); + self::assertInstanceOf(\stdClass::class, $out); + self::assertSame('ts', $out->Timestamp); + } + + public function testJsonUnserialize(): void + { + $d = new \stdClass(); + $d->Timestamp = '2025-01-01T00:00:00Z'; + + $gObj = new \stdClass(); + $gObj->Name = 'cpu'; + $gObj->Value = 1.0; + $gObj->Labels = new \stdClass(); + $d->Gauges = [$gObj]; + + $pObj = new \stdClass(); + $pObj->Name = 'pt'; + $pObj->Points = [2.0]; + $d->Points = [$pObj]; + + $cObj = new \stdClass(); + $cObj->Name = 'cnt'; + $cObj->Count = 5; + $cObj->Sum = 0.0; + $cObj->Min = 0.0; + $cObj->Max = 0.0; + $cObj->Mean = 0.0; + $cObj->Stddev = 0.0; + $cObj->Labels = new \stdClass(); + $d->Counters = [$cObj]; + $d->Samples = []; + + $m = MetricsInfo::jsonUnserialize($d); + self::assertInstanceOf(MetricsInfo::class, $m); + self::assertSame('2025-01-01T00:00:00Z', $m->getTimestamp()); + self::assertCount(1, $m->getGauges()); + self::assertInstanceOf(GaugeValue::class, $m->getGauges()[0]); + self::assertSame('cpu', $m->getGauges()[0]->getName()); + self::assertCount(1, $m->getPoints()); + self::assertInstanceOf(PointValue::class, $m->getPoints()[0]); + self::assertCount(1, $m->getCounters()); + self::assertInstanceOf(SampledValue::class, $m->getCounters()[0]); + } +} + diff --git a/tests/Unit/Agent/PointValueTest.php b/tests/Unit/Agent/PointValueTest.php new file mode 100644 index 00000000..13167fa6 --- /dev/null +++ b/tests/Unit/Agent/PointValueTest.php @@ -0,0 +1,59 @@ +getName()); + self::assertSame('', $p->Name); + self::assertSame([], $p->getPoints()); + self::assertSame([], $p->Points); + } + + public function testConstructorWithParams(): void + { + $p = new PointValue(Name: 'metric', Points: [1.0, 2.5, 3.7]); + self::assertSame('metric', $p->getName()); + self::assertSame('metric', $p->Name); + self::assertSame([1.0, 2.5, 3.7], $p->getPoints()); + } + + public function testFluentSetters(): void + { + $p = new PointValue(); + $result = $p->setName('m')->setPoints(1.0, 2.0); + self::assertSame($p, $result); + self::assertSame('m', $p->getName()); + self::assertSame([1.0, 2.0], $p->getPoints()); + } + + public function testJsonSerialize(): void + { + $p = new PointValue(Name: 'm', Points: [1.0]); + $out = $p->jsonSerialize(); + self::assertInstanceOf(\stdClass::class, $out); + self::assertSame('m', $out->Name); + self::assertSame([1.0], $out->Points); + } + + public function testJsonUnserialize(): void + { + $d = new \stdClass(); + $d->Name = 'pts'; + $d->Points = [3.0, 4.0]; + $p = PointValue::jsonUnserialize($d); + self::assertInstanceOf(PointValue::class, $p); + self::assertSame('pts', $p->getName()); + self::assertSame([3.0, 4.0], $p->getPoints()); + } +} + diff --git a/tests/Unit/Agent/SampledValueTest.php b/tests/Unit/Agent/SampledValueTest.php new file mode 100644 index 00000000..9c333d28 --- /dev/null +++ b/tests/Unit/Agent/SampledValueTest.php @@ -0,0 +1,108 @@ +getName()); + self::assertSame('', $s->Name); + self::assertSame(0, $s->getCount()); + self::assertSame(0, $s->Count); + self::assertSame(0.0, $s->getSum()); + self::assertSame(0.0, $s->getMin()); + self::assertSame(0.0, $s->getMax()); + self::assertSame(0.0, $s->getMean()); + self::assertSame(0.0, $s->getStddev()); + self::assertSame([], $s->getLabels()); + } + + public function testConstructorWithParams(): void + { + $s = new SampledValue( + Name: 'req', + Count: 10, + Sum: 100.0, + Min: 1.0, + Max: 20.0, + Mean: 10.0, + Stddev: 3.5, + Labels: ['env' => 'prod'], + ); + self::assertSame('req', $s->getName()); + self::assertSame(10, $s->getCount()); + self::assertSame(100.0, $s->getSum()); + self::assertSame(1.0, $s->getMin()); + self::assertSame(20.0, $s->getMax()); + self::assertSame(10.0, $s->getMean()); + self::assertSame(3.5, $s->getStddev()); + self::assertSame(['env' => 'prod'], $s->getLabels()); + } + + public function testFluentSetters(): void + { + $s = new SampledValue(); + $result = $s->setName('r') + ->setCount(5) + ->setSum(50.0) + ->setMin(2.0) + ->setMax(15.0) + ->setMean(10.0) + ->setStddev(2.0) + ->setLabels(['k' => 'v']); + self::assertSame($s, $result); + self::assertSame('r', $s->getName()); + self::assertSame(5, $s->getCount()); + self::assertSame(50.0, $s->getSum()); + self::assertSame(2.0, $s->getMin()); + self::assertSame(15.0, $s->getMax()); + self::assertSame(10.0, $s->getMean()); + self::assertSame(2.0, $s->getStddev()); + self::assertSame(['k' => 'v'], $s->getLabels()); + } + + public function testSetLabelsNull(): void + { + $s = new SampledValue(Labels: ['a' => 'b']); + $s->setLabels(null); + // After setLabels(null), the property is null. + self::assertNull($s->Labels); + } + + public function testJsonSerialize(): void + { + $s = new SampledValue(Name: 'req', Count: 5); + $out = $s->jsonSerialize(); + self::assertInstanceOf(\stdClass::class, $out); + self::assertSame('req', $out->Name); + self::assertSame(5, $out->Count); + } + + public function testJsonUnserialize(): void + { + $d = new \stdClass(); + $d->Name = 'latency'; + $d->Count = 3; + $d->Sum = 30.0; + $d->Min = 5.0; + $d->Max = 15.0; + $d->Mean = 10.0; + $d->Stddev = 4.0; + $d->Labels = new \stdClass(); + $d->Labels->env = 'staging'; + $s = SampledValue::jsonUnserialize($d); + self::assertInstanceOf(SampledValue::class, $s); + self::assertSame('latency', $s->getName()); + self::assertSame(3, $s->getCount()); + self::assertSame(['env' => 'staging'], $s->getLabels()); + } +} + diff --git a/tests/Unit/Agent/ServiceKindTest.php b/tests/Unit/Agent/ServiceKindTest.php new file mode 100644 index 00000000..f2d42a24 --- /dev/null +++ b/tests/Unit/Agent/ServiceKindTest.php @@ -0,0 +1,48 @@ +value); + self::assertSame('connect-proxy', ServiceKind::ConnectProxy->value); + self::assertSame('mesh-gateway', ServiceKind::MeshGateway->value); + self::assertSame('terminating-gateway', ServiceKind::TerminatingGateway->value); + self::assertSame('ingress-gateway', ServiceKind::IngressGateway->value); + self::assertSame('api-gateway', ServiceKind::APIGateway->value); + } + + public function testFromString(): void + { + self::assertSame(ServiceKind::Typical, ServiceKind::from('')); + self::assertSame(ServiceKind::ConnectProxy, ServiceKind::from('connect-proxy')); + self::assertSame(ServiceKind::MeshGateway, ServiceKind::from('mesh-gateway')); + self::assertSame(ServiceKind::TerminatingGateway, ServiceKind::from('terminating-gateway')); + self::assertSame(ServiceKind::IngressGateway, ServiceKind::from('ingress-gateway')); + self::assertSame(ServiceKind::APIGateway, ServiceKind::from('api-gateway')); + } + + public function testTryFromValid(): void + { + self::assertSame(ServiceKind::ConnectProxy, ServiceKind::tryFrom('connect-proxy')); + } + + public function testTryFromInvalid(): void + { + self::assertNull(ServiceKind::tryFrom('not-a-kind')); + } + + public function testCaseCount(): void + { + self::assertCount(6, ServiceKind::cases()); + } +} + diff --git a/tests/Unit/Agent/ServiceRegisterOptsTest.php b/tests/Unit/Agent/ServiceRegisterOptsTest.php new file mode 100644 index 00000000..611afb76 --- /dev/null +++ b/tests/Unit/Agent/ServiceRegisterOptsTest.php @@ -0,0 +1,60 @@ +isReplaceExistingChecks()); + self::assertFalse($o->ReplaceExistingChecks); + self::assertSame('', $o->getToken()); + self::assertSame('', $o->Token); + } + + public function testConstructorWithParams(): void + { + $o = new ServiceRegisterOpts(ReplaceExistingChecks: true, Token: 'tok'); + self::assertTrue($o->isReplaceExistingChecks()); + self::assertTrue($o->ReplaceExistingChecks); + self::assertSame('tok', $o->getToken()); + self::assertSame('tok', $o->Token); + } + + public function testFluentSetters(): void + { + $o = new ServiceRegisterOpts(); + $result = $o->setReplaceExistingChecks(true)->setToken('t'); + self::assertSame($o, $result); + self::assertTrue($o->isReplaceExistingChecks()); + self::assertSame('t', $o->getToken()); + } + + public function testJsonSerialize(): void + { + $o = new ServiceRegisterOpts(ReplaceExistingChecks: true, Token: 'tok'); + $out = $o->jsonSerialize(); + self::assertInstanceOf(\stdClass::class, $out); + self::assertTrue($out->ReplaceExistingChecks); + self::assertSame('tok', $out->Token); + } + + public function testJsonUnserialize(): void + { + $d = new \stdClass(); + $d->ReplaceExistingChecks = false; + $d->Token = 't2'; + $o = ServiceRegisterOpts::jsonUnserialize($d); + self::assertInstanceOf(ServiceRegisterOpts::class, $o); + self::assertFalse($o->isReplaceExistingChecks()); + self::assertSame('t2', $o->getToken()); + } +} + diff --git a/tests/Unit/Agent/UpstreamDestTypeTest.php b/tests/Unit/Agent/UpstreamDestTypeTest.php new file mode 100644 index 00000000..fa3e6e93 --- /dev/null +++ b/tests/Unit/Agent/UpstreamDestTypeTest.php @@ -0,0 +1,42 @@ +value); + self::assertSame('prepared_query', UpstreamDestType::PreparedQuery->value); + self::assertSame('', UpstreamDestType::UNDEFINED->value); + } + + public function testFromString(): void + { + self::assertSame(UpstreamDestType::Service, UpstreamDestType::from('service')); + self::assertSame(UpstreamDestType::PreparedQuery, UpstreamDestType::from('prepared_query')); + self::assertSame(UpstreamDestType::UNDEFINED, UpstreamDestType::from('')); + } + + public function testTryFromValid(): void + { + self::assertSame(UpstreamDestType::Service, UpstreamDestType::tryFrom('service')); + } + + public function testTryFromInvalid(): void + { + self::assertNull(UpstreamDestType::tryFrom('not-valid')); + } + + public function testCaseCount(): void + { + self::assertCount(3, UpstreamDestType::cases()); + } +} + diff --git a/tests/Unit/Agent/UpstreamTest.php b/tests/Unit/Agent/UpstreamTest.php new file mode 100644 index 00000000..0b89ba63 --- /dev/null +++ b/tests/Unit/Agent/UpstreamTest.php @@ -0,0 +1,65 @@ +getDestinationType()); + self::assertSame('', $u->getDestinationPartition()); + self::assertSame('', $u->getDestinationNamespace()); + self::assertSame('', $u->getDestinationPeer()); + self::assertSame('', $u->getDestinationName()); + self::assertSame('', $u->getDatacenter()); + self::assertSame('', $u->getLocalBindAddress()); + self::assertSame(0, $u->getLocalBindPort()); + self::assertFalse($u->isCentrallyConfigured()); + } + + public function testConstructorWithParams(): void + { + $u = new Upstream( + DestinationType: UpstreamDestType::Service, + DestinationName: 'db', + LocalBindAddress: '127.0.0.1', + LocalBindPort: 5432, + ); + self::assertSame(UpstreamDestType::Service, $u->getDestinationType()); + self::assertSame('db', $u->getDestinationName()); + self::assertSame(5432, $u->getLocalBindPort()); + } + + public function testConstructorWithStringDestType(): void + { + $u = new Upstream(DestinationType: 'service', DestinationName: 'db'); + self::assertSame(UpstreamDestType::Service, $u->getDestinationType()); + } + + public function testFluentSetters(): void + { + $u = new Upstream(); + $result = $u->setDestinationType(UpstreamDestType::PreparedQuery) + ->setDestinationName('query') + ->setLocalBindPort(9999); + self::assertSame($u, $result); + self::assertSame(UpstreamDestType::PreparedQuery, $u->getDestinationType()); + } + + public function testJsonSerialize(): void + { + $u = new Upstream(DestinationType: UpstreamDestType::Service, DestinationName: 'db', LocalBindPort: 5432); + $out = $u->jsonSerialize(); + self::assertSame('db', $out->DestinationName); + self::assertSame(5432, $out->LocalBindPort); + } +} + diff --git a/tests/Unit/Catalog/CatalogDeregistrationTest.php b/tests/Unit/Catalog/CatalogDeregistrationTest.php new file mode 100644 index 00000000..d6099ad6 --- /dev/null +++ b/tests/Unit/Catalog/CatalogDeregistrationTest.php @@ -0,0 +1,102 @@ +getNode()); + self::assertSame('', $d->Node); + self::assertSame('', $d->getAddress()); + self::assertSame('', $d->getDatacenter()); + self::assertSame('', $d->getServiceID()); + self::assertSame('', $d->getCheckID()); + self::assertSame('', $d->getNamespace()); + self::assertSame('', $d->getPartition()); + } + + public function testConstructorWithParams(): void + { + $d = new CatalogDeregistration( + Node: 'n', + Address: 'a', + Datacenter: 'dc', + ServiceID: 's', + CheckID: 'c', + Namespace: 'ns', + Partition: 'pt', + ); + self::assertSame('n', $d->getNode()); + self::assertSame('a', $d->getAddress()); + self::assertSame('dc', $d->getDatacenter()); + self::assertSame('s', $d->getServiceID()); + self::assertSame('c', $d->getCheckID()); + self::assertSame('ns', $d->getNamespace()); + self::assertSame('pt', $d->getPartition()); + } + + public function testFluentSetters(): void + { + $d = new CatalogDeregistration(); + $result = $d->setNode('n') + ->setAddress('a') + ->setDatacenter('dc') + ->setServiceID('s') + ->setCheckID('c') + ->setNamespace('ns') + ->setPartition('pt'); + self::assertSame($d, $result); + self::assertSame('n', $d->getNode()); + self::assertSame('n', $d->Node); + self::assertSame('a', $d->getAddress()); + self::assertSame('dc', $d->getDatacenter()); + self::assertSame('s', $d->getServiceID()); + self::assertSame('c', $d->getCheckID()); + self::assertSame('ns', $d->getNamespace()); + self::assertSame('pt', $d->getPartition()); + } + + public function testJsonSerialize(): void + { + $d = new CatalogDeregistration(Node: 'n', ServiceID: 's'); + $out = $d->jsonSerialize(); + self::assertInstanceOf(\stdClass::class, $out); + self::assertSame('n', $out->Node); + self::assertSame('s', $out->ServiceID); + } + + public function testJsonSerializeOmitsEmptyOptionalFields(): void + { + $d = new CatalogDeregistration(Node: 'n'); + $out = $d->jsonSerialize(); + self::assertObjectNotHasProperty('Address', $out); + self::assertObjectNotHasProperty('Namespace', $out); + self::assertObjectNotHasProperty('Partition', $out); + } + + public function testJsonUnserialize(): void + { + $obj = new \stdClass(); + $obj->Node = 'n1'; + $obj->Address = 'a'; + $obj->Datacenter = 'dc'; + $obj->ServiceID = 's'; + $obj->CheckID = 'c'; + $obj->Namespace = 'ns'; + $obj->Partition = 'pt'; + $d = CatalogDeregistration::jsonUnserialize($obj); + self::assertInstanceOf(CatalogDeregistration::class, $d); + self::assertSame('n1', $d->getNode()); + self::assertSame('s', $d->getServiceID()); + self::assertSame('ns', $d->getNamespace()); + } +} + diff --git a/tests/Unit/Catalog/CatalogNodeResponseTest.php b/tests/Unit/Catalog/CatalogNodeResponseTest.php new file mode 100644 index 00000000..d36be820 --- /dev/null +++ b/tests/Unit/Catalog/CatalogNodeResponseTest.php @@ -0,0 +1,59 @@ +getValue()); + self::assertNull($r->Node); + self::assertNull($r->Err); + } + + public function testUnmarshalValueNull(): void + { + $r = new CatalogNodeResponse(); + $r->unmarshalValue(null); + self::assertNull($r->getValue()); + } + + public function testUnmarshalValueWithData(): void + { + $d = new \stdClass(); + $nodeObj = new \stdClass(); + $nodeObj->ID = 'n1'; + $nodeObj->Node = 'node1'; + $nodeObj->Address = 'addr'; + $nodeObj->Datacenter = ''; + $nodeObj->TaggedAddresses = new \stdClass(); + $nodeObj->Meta = new \stdClass(); + $nodeObj->CreateIndex = 0; + $nodeObj->ModifyIndex = 0; + $d->Node = $nodeObj; + $d->Services = []; + + $r = new CatalogNodeResponse(); + $r->unmarshalValue($d); + self::assertInstanceOf(CatalogNode::class, $r->getValue()); + self::assertSame('n1', $r->getValue()->getNode()->getID()); + } + + public function testOffsetAccess(): void + { + $r = new CatalogNodeResponse(); + self::assertTrue(isset($r[0])); + self::assertTrue(isset($r[1])); + self::assertTrue(isset($r[2])); + self::assertFalse(isset($r[3])); + self::assertNull($r[0]); + } +} diff --git a/tests/Unit/Catalog/CatalogNodeServiceListTest.php b/tests/Unit/Catalog/CatalogNodeServiceListTest.php new file mode 100644 index 00000000..d2d5276f --- /dev/null +++ b/tests/Unit/Catalog/CatalogNodeServiceListTest.php @@ -0,0 +1,86 @@ +getNode()); + self::assertSame([], $l->getServices()); + } + + public function testConstructorWithParams(): void + { + $node = new Node(ID: 'n1'); + $svc = new AgentService(ID: 'svc-1', Service: 'web'); + $l = new CatalogNodeServiceList(Node: $node, Services: [$svc]); + self::assertSame($node, $l->getNode()); + self::assertSame($node, $l->Node); + self::assertCount(1, $l->getServices()); + self::assertSame($svc, $l->getServices()[0]); + } + + public function testFluentSetters(): void + { + $l = new CatalogNodeServiceList(); + $node = new Node(ID: 'n1'); + $svc = new AgentService(ID: 'svc-1'); + $result = $l->setNode($node)->setServices($svc); + self::assertSame($l, $result); + self::assertSame($node, $l->getNode()); + self::assertCount(1, $l->getServices()); + } + + public function testJsonSerialize(): void + { + $node = new Node(ID: 'n1'); + $l = new CatalogNodeServiceList(Node: $node); + $out = $l->jsonSerialize(); + self::assertInstanceOf(\stdClass::class, $out); + self::assertSame($node, $out->Node); + } + + public function testJsonUnserialize(): void + { + $d = new \stdClass(); + $nodeObj = new \stdClass(); + $nodeObj->ID = 'n1'; + $nodeObj->Node = 'node1'; + $nodeObj->Address = ''; + $nodeObj->Datacenter = ''; + $nodeObj->TaggedAddresses = new \stdClass(); + $nodeObj->Meta = new \stdClass(); + $nodeObj->CreateIndex = 0; + $nodeObj->ModifyIndex = 0; + $d->Node = $nodeObj; + + $svcObj = new \stdClass(); + $svcObj->Kind = ''; + $svcObj->ID = 'svc-1'; + $svcObj->Service = 'web'; + $svcObj->Port = 80; + $svcObj->Address = ''; + $svcObj->Tags = []; + $svcObj->Meta = new \stdClass(); + $svcObj->CreateIndex = 0; + $svcObj->ModifyIndex = 0; + $d->Services = [$svcObj]; + + $l = CatalogNodeServiceList::jsonUnserialize($d); + self::assertInstanceOf(CatalogNodeServiceList::class, $l); + self::assertInstanceOf(Node::class, $l->getNode()); + self::assertCount(1, $l->getServices()); + self::assertInstanceOf(AgentService::class, $l->getServices()[0]); + } +} + diff --git a/tests/Unit/Catalog/CatalogNodeServicesListResponseTest.php b/tests/Unit/Catalog/CatalogNodeServicesListResponseTest.php new file mode 100644 index 00000000..7d597f33 --- /dev/null +++ b/tests/Unit/Catalog/CatalogNodeServicesListResponseTest.php @@ -0,0 +1,56 @@ +getValue()); + self::assertNull($r->CatalogNodeServiceList); + self::assertNull($r->Err); + } + + public function testUnmarshalValueNull(): void + { + $r = new CatalogNodeServicesListResponse(); + $r->unmarshalValue(null); + self::assertNull($r->getValue()); + } + + public function testUnmarshalValueWithData(): void + { + $d = new \stdClass(); + $nodeObj = new \stdClass(); + $nodeObj->ID = 'n1'; + $nodeObj->Node = 'node1'; + $nodeObj->Address = ''; + $nodeObj->Datacenter = ''; + $nodeObj->TaggedAddresses = new \stdClass(); + $nodeObj->Meta = new \stdClass(); + $nodeObj->CreateIndex = 0; + $nodeObj->ModifyIndex = 0; + $d->Node = $nodeObj; + $d->Services = []; + + $r = new CatalogNodeServicesListResponse(); + $r->unmarshalValue($d); + self::assertInstanceOf(CatalogNodeServiceList::class, $r->getValue()); + } + + public function testOffsetAccess(): void + { + $r = new CatalogNodeServicesListResponse(); + self::assertTrue(isset($r[0])); + self::assertNull($r[0]); + } +} + diff --git a/tests/Unit/Catalog/CatalogNodeTest.php b/tests/Unit/Catalog/CatalogNodeTest.php new file mode 100644 index 00000000..cd278b96 --- /dev/null +++ b/tests/Unit/Catalog/CatalogNodeTest.php @@ -0,0 +1,88 @@ +getNode()); + self::assertSame([], $cn->getServices()); + } + + public function testConstructorWithParams(): void + { + $node = new Node(ID: 'n1', Node: 'node1'); + $svc = new AgentService(ID: 'svc-1', Service: 'web'); + $cn = new CatalogNode(Node: $node, Services: ['web' => $svc]); + self::assertSame($node, $cn->getNode()); + self::assertCount(1, $cn->getServices()); + self::assertArrayHasKey('web', $cn->getServices()); + self::assertSame($svc, $cn->getServices()['web']); + } + + public function testFluentSetters(): void + { + $cn = new CatalogNode(); + $node = new Node(ID: 'n1'); + $svc = new AgentService(ID: 'svc-1'); + $result = $cn->setNode($node)->setServices(['web' => $svc]); + self::assertSame($cn, $result); + self::assertSame($node, $cn->getNode()); + self::assertSame($node, $cn->Node); + self::assertCount(1, $cn->getServices()); + } + + public function testJsonSerialize(): void + { + $node = new Node(ID: 'n1'); + $cn = new CatalogNode(Node: $node); + $out = $cn->jsonSerialize(); + self::assertInstanceOf(\stdClass::class, $out); + self::assertSame($node, $out->Node); + } + + public function testJsonUnserialize(): void + { + $d = new \stdClass(); + $nodeObj = new \stdClass(); + $nodeObj->ID = 'n1'; + $nodeObj->Node = 'node1'; + $nodeObj->Address = 'addr'; + $nodeObj->Datacenter = ''; + $nodeObj->TaggedAddresses = new \stdClass(); + $nodeObj->Meta = new \stdClass(); + $nodeObj->CreateIndex = 0; + $nodeObj->ModifyIndex = 0; + $d->Node = $nodeObj; + + $svcObj = new \stdClass(); + $svcObj->Kind = ''; + $svcObj->ID = 'svc-1'; + $svcObj->Service = 'web'; + $svcObj->Port = 80; + $svcObj->Address = ''; + $svcObj->Tags = []; + $svcObj->Meta = new \stdClass(); + $svcObj->CreateIndex = 0; + $svcObj->ModifyIndex = 0; + $d->Services = ['web' => $svcObj]; + + $cn = CatalogNode::jsonUnserialize($d); + self::assertInstanceOf(CatalogNode::class, $cn); + self::assertInstanceOf(Node::class, $cn->getNode()); + self::assertSame('n1', $cn->getNode()->getID()); + self::assertCount(1, $cn->getServices()); + self::assertInstanceOf(AgentService::class, $cn->getServices()['web']); + } +} + diff --git a/tests/Unit/Catalog/CatalogRegistrationTest.php b/tests/Unit/Catalog/CatalogRegistrationTest.php new file mode 100644 index 00000000..0cb8399f --- /dev/null +++ b/tests/Unit/Catalog/CatalogRegistrationTest.php @@ -0,0 +1,111 @@ +getID()); + self::assertSame('', $r->ID); + self::assertSame('', $r->getNode()); + self::assertSame('', $r->getAddress()); + self::assertSame('', $r->getDatacenter()); + self::assertNull($r->getService()); + self::assertNull($r->getCheck()); + self::assertFalse($r->isSkipNodeUpdate()); + self::assertSame('', $r->getPartition()); + self::assertNull($r->getLocality()); + } + + public function testConstructorWithParams(): void + { + $svc = new AgentService(ID: 'svc-1'); + $chk = new AgentCheck(CheckID: 'chk-1'); + $r = new CatalogRegistration( + ID: 'id-1', + Node: 'node1', + Address: '10.0.0.1', + Datacenter: 'dc1', + Service: $svc, + Check: $chk, + SkipNodeUpdate: true, + Partition: 'pt', + ); + self::assertSame('id-1', $r->getID()); + self::assertSame('node1', $r->getNode()); + self::assertSame('10.0.0.1', $r->getAddress()); + self::assertSame('dc1', $r->getDatacenter()); + self::assertSame($svc, $r->getService()); + self::assertSame($chk, $r->getCheck()); + self::assertTrue($r->isSkipNodeUpdate()); + self::assertSame('pt', $r->getPartition()); + } + + public function testFluentSetters(): void + { + $r = new CatalogRegistration(); + $svc = new AgentService(ID: 'svc'); + $result = $r->setID('id') + ->setNode('n') + ->setAddress('a') + ->setDatacenter('dc') + ->setService($svc) + ->setSkipNodeUpdate(true) + ->setPartition('pt'); + self::assertSame($r, $result); + self::assertSame('id', $r->getID()); + self::assertSame('id', $r->ID); + self::assertSame('n', $r->getNode()); + self::assertSame($svc, $r->getService()); + self::assertTrue($r->isSkipNodeUpdate()); + } + + public function testJsonSerialize(): void + { + $r = new CatalogRegistration(ID: 'id', Node: 'n', Address: 'a'); + $out = $r->jsonSerialize(); + self::assertInstanceOf(\stdClass::class, $out); + self::assertSame('id', $out->ID); + self::assertSame('n', $out->Node); + } + + public function testJsonSerializeOmitsEmptyOptionalFields(): void + { + $r = new CatalogRegistration(ID: 'id', Node: 'n'); + $out = $r->jsonSerialize(); + self::assertObjectNotHasProperty('Partition', $out); + self::assertObjectNotHasProperty('Locality', $out); + } + + public function testJsonUnserialize(): void + { + $d = new \stdClass(); + $d->ID = 'id'; + $d->Node = 'node'; + $d->Address = 'addr'; + $d->Datacenter = 'dc'; + $d->TaggedAddresses = new \stdClass(); + $d->NodeMeta = new \stdClass(); + $d->Service = null; + $d->Check = null; + $d->Checks = null; + $d->SkipNodeUpdate = true; + $r = CatalogRegistration::jsonUnserialize($d); + self::assertInstanceOf(CatalogRegistration::class, $r); + self::assertSame('id', $r->getID()); + self::assertSame('node', $r->getNode()); + self::assertTrue($r->isSkipNodeUpdate()); + self::assertNull($r->getService()); + } +} + diff --git a/tests/Unit/Catalog/CatalogServiceTest.php b/tests/Unit/Catalog/CatalogServiceTest.php new file mode 100644 index 00000000..af51a8ce --- /dev/null +++ b/tests/Unit/Catalog/CatalogServiceTest.php @@ -0,0 +1,141 @@ +getID()); + self::assertSame('', $s->ID); + self::assertSame('', $s->getNode()); + self::assertSame('', $s->getAddress()); + self::assertSame('', $s->getDatacenter()); + self::assertSame('', $s->getServiceID()); + self::assertSame('', $s->getServiceName()); + self::assertSame('', $s->getServiceAddress()); + self::assertSame(0, $s->getServicePort()); + self::assertSame([], $s->getServiceTags()); + self::assertInstanceOf(Weights::class, $s->getServiceWeights()); + self::assertFalse($s->isServiceEnableTagOverride()); + self::assertNull($s->getServiceProxy()); + self::assertNull($s->getServiceLocality()); + self::assertSame(0, $s->getCreateIndex()); + self::assertSame(0, $s->getModifyIndex()); + self::assertInstanceOf(HealthChecks::class, $s->getChecks()); + self::assertSame('', $s->getNamespace()); + self::assertSame('', $s->getPartition()); + } + + public function testConstructorWithParams(): void + { + $s = new CatalogService( + ID: 'id', + Node: 'node1', + Address: '10.0.0.1', + Datacenter: 'dc1', + ServiceID: 'web-1', + ServiceName: 'web', + ServicePort: 8080, + ServiceTags: ['v1'], + CreateIndex: 1, + ModifyIndex: 2, + Namespace: 'ns', + Partition: 'pt', + ); + self::assertSame('id', $s->getID()); + self::assertSame('web-1', $s->getServiceID()); + self::assertSame('web', $s->getServiceName()); + self::assertSame(8080, $s->getServicePort()); + self::assertSame(['v1'], $s->getServiceTags()); + self::assertSame(1, $s->getCreateIndex()); + self::assertSame('ns', $s->getNamespace()); + } + + public function testFluentSetters(): void + { + $s = new CatalogService(); + $w = new Weights(Passing: 10); + $result = $s->setID('id') + ->setNode('n') + ->setAddress('a') + ->setDatacenter('dc') + ->setServiceID('sid') + ->setServiceName('sn') + ->setServiceAddress('sa') + ->setServicePort(80) + ->setServiceTags('v1', 'v2') + ->setServiceWeights($w) + ->setServiceEnableTagOverride(true) + ->setCreateIndex(1) + ->setModifyIndex(2) + ->setNamespace('ns') + ->setPartition('pt'); + self::assertSame($s, $result); + self::assertSame('id', $s->getID()); + self::assertSame('id', $s->ID); + self::assertSame('sid', $s->getServiceID()); + self::assertSame(['v1', 'v2'], $s->getServiceTags()); + self::assertSame($w, $s->getServiceWeights()); + self::assertTrue($s->isServiceEnableTagOverride()); + } + + public function testJsonSerialize(): void + { + $s = new CatalogService(ServiceID: 'web', ServiceName: 'web', ServicePort: 80); + $out = $s->jsonSerialize(); + self::assertInstanceOf(\stdClass::class, $out); + self::assertSame('web', $out->ServiceID); + self::assertSame(80, $out->ServicePort); + } + + public function testJsonSerializeOmitsEmptyOptionalFields(): void + { + $s = new CatalogService(ServiceID: 'web'); + $out = $s->jsonSerialize(); + self::assertObjectNotHasProperty('Namespace', $out); + self::assertObjectNotHasProperty('Partition', $out); + } + + public function testJsonUnserialize(): void + { + $d = new \stdClass(); + $d->ID = 'id'; + $d->Node = 'node'; + $d->Address = 'addr'; + $d->Datacenter = 'dc'; + $d->TaggedAddresses = new \stdClass(); + $d->NodeMeta = new \stdClass(); + $d->ServiceID = 'web-1'; + $d->ServiceName = 'web'; + $d->ServiceAddress = ''; + $d->ServiceTags = ['v1']; + $d->ServiceMeta = new \stdClass(); + $d->ServicePort = 8080; + $wObj = new \stdClass(); + $wObj->Passing = 10; + $wObj->Warning = 1; + $d->ServiceWeights = $wObj; + $d->ServiceEnableTagOverride = false; + $d->CreateIndex = 1; + $d->ModifyIndex = 2; + + $s = CatalogService::jsonUnserialize($d); + self::assertInstanceOf(CatalogService::class, $s); + self::assertSame('web-1', $s->getServiceID()); + self::assertSame('web', $s->getServiceName()); + self::assertSame(8080, $s->getServicePort()); + self::assertSame(['v1'], $s->getServiceTags()); + self::assertSame(10, $s->getServiceWeights()->getPassing()); + } +} + diff --git a/tests/Unit/Catalog/CatalogServicesResponseTest.php b/tests/Unit/Catalog/CatalogServicesResponseTest.php new file mode 100644 index 00000000..1966f2d5 --- /dev/null +++ b/tests/Unit/Catalog/CatalogServicesResponseTest.php @@ -0,0 +1,59 @@ +getValue()); + self::assertSame([], $r->Services); + self::assertNull($r->Err); + } + + public function testUnmarshalValue(): void + { + $svcObj = new \stdClass(); + $svcObj->ID = 'id'; + $svcObj->Node = 'node'; + $svcObj->Address = ''; + $svcObj->Datacenter = ''; + $svcObj->TaggedAddresses = new \stdClass(); + $svcObj->NodeMeta = new \stdClass(); + $svcObj->ServiceID = 'web-1'; + $svcObj->ServiceName = 'web'; + $svcObj->ServiceAddress = ''; + $svcObj->ServiceTags = []; + $svcObj->ServiceMeta = new \stdClass(); + $svcObj->ServicePort = 80; + $wObj = new \stdClass(); + $wObj->Passing = 0; + $wObj->Warning = 0; + $svcObj->ServiceWeights = $wObj; + $svcObj->ServiceEnableTagOverride = false; + $svcObj->CreateIndex = 0; + $svcObj->ModifyIndex = 0; + + $r = new CatalogServicesResponse(); + $r->unmarshalValue([$svcObj]); + self::assertCount(1, $r->getValue()); + self::assertInstanceOf(CatalogService::class, $r->getValue()[0]); + self::assertSame('web-1', $r->getValue()[0]->getServiceID()); + } + + public function testOffsetAccess(): void + { + $r = new CatalogServicesResponse(); + self::assertTrue(isset($r[0])); + self::assertSame([], $r[0]); + } +} + diff --git a/tests/Unit/Catalog/CompoundServiceNameTest.php b/tests/Unit/Catalog/CompoundServiceNameTest.php new file mode 100644 index 00000000..6aa9ec88 --- /dev/null +++ b/tests/Unit/Catalog/CompoundServiceNameTest.php @@ -0,0 +1,74 @@ +getName()); + self::assertSame('', $c->Name); + self::assertSame('', $c->getNamespace()); + self::assertSame('', $c->Namespace); + self::assertSame('', $c->getPartition()); + self::assertSame('', $c->Partition); + } + + public function testConstructorWithParams(): void + { + $c = new CompoundServiceName(Name: 'web', Namespace: 'ns', Partition: 'pt'); + self::assertSame('web', $c->getName()); + self::assertSame('ns', $c->getNamespace()); + self::assertSame('pt', $c->getPartition()); + } + + public function testFluentSetters(): void + { + $c = new CompoundServiceName(); + $result = $c->setName('n')->setNamespace('ns')->setPartition('pt'); + self::assertSame($c, $result); + self::assertSame('n', $c->getName()); + self::assertSame('n', $c->Name); + self::assertSame('ns', $c->getNamespace()); + self::assertSame('pt', $c->getPartition()); + } + + public function testJsonSerializeOmitsEmptyOptionalFields(): void + { + $c = new CompoundServiceName(Name: 'web'); + $out = $c->jsonSerialize(); + self::assertInstanceOf(\stdClass::class, $out); + self::assertSame('web', $out->Name); + self::assertObjectNotHasProperty('Namespace', $out); + self::assertObjectNotHasProperty('Partition', $out); + } + + public function testJsonSerializeWithOptionalFields(): void + { + $c = new CompoundServiceName(Name: 'web', Namespace: 'ns', Partition: 'pt'); + $out = $c->jsonSerialize(); + self::assertSame('ns', $out->Namespace); + self::assertSame('pt', $out->Partition); + } + + public function testJsonUnserialize(): void + { + $d = new \stdClass(); + $d->Name = 'web'; + $d->Namespace = 'ns'; + $d->Partition = 'pt'; + $c = CompoundServiceName::jsonUnserialize($d); + self::assertInstanceOf(CompoundServiceName::class, $c); + self::assertSame('web', $c->getName()); + self::assertSame('ns', $c->getNamespace()); + self::assertSame('pt', $c->getPartition()); + } +} + diff --git a/tests/Unit/Catalog/GatewayServiceTest.php b/tests/Unit/Catalog/GatewayServiceTest.php new file mode 100644 index 00000000..d5f48377 --- /dev/null +++ b/tests/Unit/Catalog/GatewayServiceTest.php @@ -0,0 +1,151 @@ +getGateway()); + self::assertInstanceOf(CompoundServiceName::class, $g->getService()); + self::assertSame(ServiceKind::Typical, $g->getGatewayKind()); + self::assertSame(0, $g->getPort()); + self::assertSame(0, $g->Port); + self::assertSame('', $g->getProtocol()); + self::assertSame([], $g->getHosts()); + self::assertSame('', $g->getCAFile()); + self::assertSame('', $g->getCertFile()); + self::assertSame('', $g->getKeyFile()); + self::assertSame('', $g->getSNI()); + self::assertSame('', $g->getFromWildCard()); + } + + public function testConstructorWithParams(): void + { + $gw = new CompoundServiceName(Name: 'gw'); + $svc = new CompoundServiceName(Name: 'web'); + $g = new GatewayService( + Gateway: $gw, + Service: $svc, + GatewayKind: ServiceKind::IngressGateway, + Port: 443, + Protocol: 'http', + Hosts: ['web.example.com'], + CAFile: '/ca.pem', + CertFile: '/cert.pem', + KeyFile: '/key.pem', + SNI: 'web.consul', + FromWildCard: 'true', + ); + self::assertSame('gw', $g->getGateway()->getName()); + self::assertSame('web', $g->getService()->getName()); + self::assertSame(ServiceKind::IngressGateway, $g->getGatewayKind()); + self::assertSame(443, $g->getPort()); + self::assertSame('http', $g->getProtocol()); + self::assertSame(['web.example.com'], $g->getHosts()); + self::assertSame('/ca.pem', $g->getCAFile()); + self::assertSame('web.consul', $g->getSNI()); + } + + public function testConstructorWithStringGatewayKind(): void + { + $g = new GatewayService(GatewayKind: 'ingress-gateway'); + self::assertSame(ServiceKind::IngressGateway, $g->getGatewayKind()); + } + + public function testFluentSetters(): void + { + $g = new GatewayService(); + $gw = new CompoundServiceName(Name: 'gw'); + $svc = new CompoundServiceName(Name: 'web'); + $result = $g->setGateway($gw) + ->setService($svc) + ->setGatewayKind(ServiceKind::MeshGateway) + ->setPort(443) + ->setProtocol('http') + ->setHosts('a.com', 'b.com') + ->setCAFile('/ca') + ->setCertFile('/cert') + ->setKeyFile('/key') + ->setSNI('sni') + ->setFromWildCard('wc'); + self::assertSame($g, $result); + self::assertSame('gw', $g->getGateway()->getName()); + self::assertSame(ServiceKind::MeshGateway, $g->getGatewayKind()); + self::assertSame(443, $g->getPort()); + self::assertSame(['a.com', 'b.com'], $g->getHosts()); + } + + public function testJsonSerialize(): void + { + $g = new GatewayService( + Gateway: new CompoundServiceName(Name: 'gw'), + Service: new CompoundServiceName(Name: 'web'), + Port: 443, + Protocol: 'http', + Hosts: ['web.example.com'], + ); + $out = $g->jsonSerialize(); + self::assertInstanceOf(\stdClass::class, $out); + self::assertSame('', $out->GatewayKind); + self::assertSame(443, $out->Port); + self::assertSame('http', $out->Protocol); + self::assertSame(['web.example.com'], $out->Hosts); + } + + public function testJsonSerializeOmitsEmptyOptionalFields(): void + { + $g = new GatewayService(); + $out = $g->jsonSerialize(); + self::assertObjectNotHasProperty('Port', $out); + self::assertObjectNotHasProperty('Protocol', $out); + self::assertObjectNotHasProperty('Hosts', $out); + self::assertObjectNotHasProperty('CAFile', $out); + self::assertObjectNotHasProperty('CertFile', $out); + self::assertObjectNotHasProperty('KeyFile', $out); + self::assertObjectNotHasProperty('SNI', $out); + self::assertObjectNotHasProperty('FromWildCard', $out); + } + + public function testJsonUnserialize(): void + { + $d = new \stdClass(); + $gwObj = new \stdClass(); + $gwObj->Name = 'gw'; + $gwObj->Namespace = ''; + $gwObj->Partition = ''; + $d->Gateway = $gwObj; + $svcObj = new \stdClass(); + $svcObj->Name = 'web'; + $svcObj->Namespace = ''; + $svcObj->Partition = ''; + $d->Service = $svcObj; + $d->GatewayKind = 'ingress-gateway'; + $d->Port = 443; + $d->Protocol = 'http'; + $d->Hosts = ['a.com']; + $d->CAFile = ''; + $d->CertFile = ''; + $d->KeyFile = ''; + $d->SNI = ''; + $d->FromWildCard = ''; + + $g = GatewayService::jsonUnserialize($d); + self::assertInstanceOf(GatewayService::class, $g); + self::assertSame('gw', $g->getGateway()->getName()); + self::assertSame('web', $g->getService()->getName()); + self::assertSame(ServiceKind::IngressGateway, $g->getGatewayKind()); + self::assertSame(443, $g->getPort()); + self::assertSame(['a.com'], $g->getHosts()); + } +} + diff --git a/tests/Unit/Catalog/GatewayServicesResponseTest.php b/tests/Unit/Catalog/GatewayServicesResponseTest.php new file mode 100644 index 00000000..77e5023a --- /dev/null +++ b/tests/Unit/Catalog/GatewayServicesResponseTest.php @@ -0,0 +1,60 @@ +getValue()); + self::assertSame([], $r->GatewayServices); + self::assertNull($r->Err); + } + + public function testUnmarshalValue(): void + { + $gwObj = new \stdClass(); + $gwObj->Name = 'gw'; + $gwObj->Namespace = ''; + $gwObj->Partition = ''; + $svcObj = new \stdClass(); + $svcObj->Name = 'web'; + $svcObj->Namespace = ''; + $svcObj->Partition = ''; + + $d = new \stdClass(); + $d->Gateway = $gwObj; + $d->Service = $svcObj; + $d->GatewayKind = ''; + $d->Port = 0; + $d->Protocol = ''; + $d->Hosts = []; + $d->CAFile = ''; + $d->CertFile = ''; + $d->KeyFile = ''; + $d->SNI = ''; + $d->FromWildCard = ''; + + $r = new GatewayServicesResponse(); + $r->unmarshalValue([$d]); + self::assertCount(1, $r->getValue()); + self::assertInstanceOf(GatewayService::class, $r->getValue()[0]); + self::assertSame('gw', $r->getValue()[0]->getGateway()->getName()); + } + + public function testOffsetAccess(): void + { + $r = new GatewayServicesResponse(); + self::assertTrue(isset($r[0])); + self::assertSame([], $r[0]); + } +} + diff --git a/tests/Unit/Catalog/NodeTest.php b/tests/Unit/Catalog/NodeTest.php new file mode 100644 index 00000000..7c3ba9c6 --- /dev/null +++ b/tests/Unit/Catalog/NodeTest.php @@ -0,0 +1,108 @@ +getID()); + self::assertSame('', $n->ID); + self::assertSame('', $n->getNode()); + self::assertSame('', $n->getAddress()); + self::assertSame('', $n->getDatacenter()); + self::assertSame(0, $n->getCreateIndex()); + self::assertSame(0, $n->getModifyIndex()); + self::assertSame('', $n->getPartition()); + self::assertSame('', $n->getPeerName()); + self::assertNull($n->getLocality()); + } + + public function testConstructorWithParams(): void + { + $n = new Node( + ID: 'id-1', + Node: 'node1', + Address: '10.0.0.1', + Datacenter: 'dc1', + CreateIndex: 1, + ModifyIndex: 2, + Partition: 'pt', + PeerName: 'peer1', + ); + self::assertSame('id-1', $n->getID()); + self::assertSame('node1', $n->getNode()); + self::assertSame('10.0.0.1', $n->getAddress()); + self::assertSame('dc1', $n->getDatacenter()); + self::assertSame(1, $n->getCreateIndex()); + self::assertSame(2, $n->getModifyIndex()); + self::assertSame('pt', $n->getPartition()); + self::assertSame('peer1', $n->getPeerName()); + } + + public function testFluentSetters(): void + { + $n = new Node(); + $result = $n->setID('id') + ->setNode('n') + ->setAddress('a') + ->setDatacenter('dc') + ->setCreateIndex(1) + ->setModifyIndex(2) + ->setPartition('pt') + ->setPeerName('p'); + self::assertSame($n, $result); + self::assertSame('id', $n->getID()); + self::assertSame('id', $n->ID); + self::assertSame('n', $n->getNode()); + self::assertSame('a', $n->getAddress()); + self::assertSame('dc', $n->getDatacenter()); + self::assertSame('pt', $n->getPartition()); + self::assertSame('p', $n->getPeerName()); + } + + public function testJsonSerialize(): void + { + $n = new Node(ID: 'x', Node: 'y', Address: 'z'); + $out = $n->jsonSerialize(); + self::assertInstanceOf(\stdClass::class, $out); + self::assertSame('x', $out->ID); + self::assertSame('y', $out->Node); + self::assertSame('z', $out->Address); + } + + public function testJsonSerializeOmitsEmptyOptionalFields(): void + { + $n = new Node(ID: 'x', Node: 'y'); + $out = $n->jsonSerialize(); + self::assertObjectNotHasProperty('Partition', $out); + self::assertObjectNotHasProperty('PeerName', $out); + self::assertObjectNotHasProperty('Locality', $out); + } + + public function testJsonUnserialize(): void + { + $d = new \stdClass(); + $d->ID = 'id'; + $d->Node = 'node'; + $d->Address = 'addr'; + $d->Datacenter = 'dc'; + $d->TaggedAddresses = new \stdClass(); + $d->Meta = new \stdClass(); + $d->CreateIndex = 5; + $d->ModifyIndex = 10; + $n = Node::jsonUnserialize($d); + self::assertInstanceOf(Node::class, $n); + self::assertSame('id', $n->getID()); + self::assertSame('node', $n->getNode()); + self::assertSame(5, $n->getCreateIndex()); + } +} + diff --git a/tests/Unit/Catalog/NodesResponseTest.php b/tests/Unit/Catalog/NodesResponseTest.php new file mode 100644 index 00000000..5d0d7cb8 --- /dev/null +++ b/tests/Unit/Catalog/NodesResponseTest.php @@ -0,0 +1,49 @@ +getValue()); + self::assertSame([], $r->Nodes); + self::assertNull($r->Err); + } + + public function testUnmarshalValue(): void + { + $nodeObj = new \stdClass(); + $nodeObj->ID = 'n1'; + $nodeObj->Node = 'node1'; + $nodeObj->Address = '10.0.0.1'; + $nodeObj->Datacenter = 'dc1'; + $nodeObj->TaggedAddresses = new \stdClass(); + $nodeObj->Meta = new \stdClass(); + $nodeObj->CreateIndex = 1; + $nodeObj->ModifyIndex = 2; + + $r = new NodesResponse(); + $r->unmarshalValue([$nodeObj]); + self::assertCount(1, $r->getValue()); + self::assertInstanceOf(Node::class, $r->getValue()[0]); + self::assertSame('n1', $r->getValue()[0]->getID()); + self::assertSame('node1', $r->getValue()[0]->getNode()); + } + + public function testOffsetAccess(): void + { + $r = new NodesResponse(); + self::assertTrue(isset($r[0])); + self::assertSame([], $r[0]); + } +} + diff --git a/tests/Unit/Catalog/ServiceAddressTest.php b/tests/Unit/Catalog/ServiceAddressTest.php new file mode 100644 index 00000000..bd514c7b --- /dev/null +++ b/tests/Unit/Catalog/ServiceAddressTest.php @@ -0,0 +1,60 @@ +getAddress()); + self::assertSame('', $sa->Address); + self::assertSame(0, $sa->getPort()); + self::assertSame(0, $sa->Port); + } + + public function testConstructorWithParams(): void + { + $sa = new ServiceAddress(Address: '10.0.0.1', Port: 8080); + self::assertSame('10.0.0.1', $sa->getAddress()); + self::assertSame(8080, $sa->getPort()); + } + + public function testFluentSetters(): void + { + $sa = new ServiceAddress(); + $result = $sa->setAddress('a')->setPort(1); + self::assertSame($sa, $result); + self::assertSame('a', $sa->getAddress()); + self::assertSame('a', $sa->Address); + self::assertSame(1, $sa->getPort()); + self::assertSame(1, $sa->Port); + } + + public function testJsonSerialize(): void + { + $sa = new ServiceAddress(Address: 'a', Port: 1); + $out = $sa->jsonSerialize(); + self::assertInstanceOf(\stdClass::class, $out); + self::assertSame('a', $out->Address); + self::assertSame(1, $out->Port); + } + + public function testJsonUnserialize(): void + { + $d = new \stdClass(); + $d->Address = 'b'; + $d->Port = 2; + $sa = ServiceAddress::jsonUnserialize($d); + self::assertInstanceOf(ServiceAddress::class, $sa); + self::assertSame('b', $sa->getAddress()); + self::assertSame(2, $sa->getPort()); + } +} + diff --git a/tests/Unit/Catalog/WeightsTest.php b/tests/Unit/Catalog/WeightsTest.php new file mode 100644 index 00000000..ccc5df8f --- /dev/null +++ b/tests/Unit/Catalog/WeightsTest.php @@ -0,0 +1,60 @@ +getPassing()); + self::assertSame(0, $w->Passing); + self::assertSame(0, $w->getWarning()); + self::assertSame(0, $w->Warning); + } + + public function testConstructorWithParams(): void + { + $w = new Weights(Passing: 10, Warning: 1); + self::assertSame(10, $w->getPassing()); + self::assertSame(1, $w->getWarning()); + } + + public function testFluentSetters(): void + { + $w = new Weights(); + $result = $w->setPassing(5)->setWarning(2); + self::assertSame($w, $result); + self::assertSame(5, $w->getPassing()); + self::assertSame(5, $w->Passing); + self::assertSame(2, $w->getWarning()); + self::assertSame(2, $w->Warning); + } + + public function testJsonSerialize(): void + { + $w = new Weights(Passing: 3, Warning: 1); + $out = $w->jsonSerialize(); + self::assertInstanceOf(\stdClass::class, $out); + self::assertSame(3, $out->Passing); + self::assertSame(1, $out->Warning); + } + + public function testJsonUnserialize(): void + { + $d = new \stdClass(); + $d->Passing = 4; + $d->Warning = 2; + $w = Weights::jsonUnserialize($d); + self::assertInstanceOf(Weights::class, $w); + self::assertSame(4, $w->getPassing()); + self::assertSame(2, $w->getWarning()); + } +} + diff --git a/tests/Unit/ConfigEntry/AccessLogsConfigTest.php b/tests/Unit/ConfigEntry/AccessLogsConfigTest.php new file mode 100644 index 00000000..ef31a3f1 --- /dev/null +++ b/tests/Unit/ConfigEntry/AccessLogsConfigTest.php @@ -0,0 +1,74 @@ +isEnabled()); + self::assertFalse($c->isDisableListenerLogs()); + self::assertSame(LogSinkType::Default, $c->getType()); + self::assertSame('', $c->getPath()); + self::assertSame('', $c->getJSONFormat()); + self::assertSame('', $c->getTextFormat()); + } + + public function testConstructorWithParams(): void + { + $c = new AccessLogsConfig( + Enabled: true, + DisableListenerLogs: true, + Type: LogSinkType::File, + Path: '/var/log/envoy.log', + JSONFormat: '{"start_time":"%START_TIME%"}', + TextFormat: '%START_TIME%', + ); + self::assertTrue($c->isEnabled()); + self::assertTrue($c->isDisableListenerLogs()); + self::assertSame(LogSinkType::File, $c->getType()); + self::assertSame('/var/log/envoy.log', $c->getPath()); + self::assertSame('{"start_time":"%START_TIME%"}', $c->getJSONFormat()); + self::assertSame('%START_TIME%', $c->getTextFormat()); + } + + public function testFluentSetters(): void + { + $c = new AccessLogsConfig(); + $result = $c->setEnabled(true) + ->setDisableListenerLogs(true) + ->setType(LogSinkType::StdErr) + ->setPath('/log') + ->setJSONFormat('json') + ->setTextFormat('text'); + self::assertSame($c, $result); + self::assertTrue($c->isEnabled()); + self::assertTrue($c->isDisableListenerLogs()); + self::assertSame(LogSinkType::StdErr, $c->getType()); + self::assertSame('/log', $c->getPath()); + self::assertSame('json', $c->getJSONFormat()); + self::assertSame('text', $c->getTextFormat()); + } + + public function testConstructorWithEnumAsString(): void + { + $c = new AccessLogsConfig(Type: 'file'); + self::assertSame(LogSinkType::File, $c->getType()); + } + + public function testSetTypeWithString(): void + { + $c = new AccessLogsConfig(); + $c->setType('stderr'); + self::assertSame(LogSinkType::StdErr, $c->getType()); + } +} diff --git a/tests/Unit/ConfigEntry/CookieConfigTest.php b/tests/Unit/ConfigEntry/CookieConfigTest.php new file mode 100644 index 00000000..8d9fcdb6 --- /dev/null +++ b/tests/Unit/ConfigEntry/CookieConfigTest.php @@ -0,0 +1,38 @@ +getSession()); + self::assertSame(0, $c->getTTL()->Nanoseconds()); + self::assertSame('', $c->getPath()); + } + + public function testConstructorWithParams(): void + { + $c = new CookieConfig(Session: true, TTL: '5m', Path: '/'); + self::assertTrue($c->getSession()); + self::assertSame('/', $c->getPath()); + } + + public function testFluentSetters(): void + { + $c = new CookieConfig(); + $result = $c->setSession(true)->setPath('/test'); + self::assertSame($c, $result); + self::assertTrue($c->getSession()); + self::assertSame('/test', $c->getPath()); + } + +} diff --git a/tests/Unit/ConfigEntry/DestinationConfigTest.php b/tests/Unit/ConfigEntry/DestinationConfigTest.php new file mode 100644 index 00000000..ee41dc0a --- /dev/null +++ b/tests/Unit/ConfigEntry/DestinationConfigTest.php @@ -0,0 +1,37 @@ +getAddresses()); + self::assertSame(0, $c->getPort()); + } + + public function testConstructorWithParams(): void + { + $c = new DestinationConfig(Addresses: ['10.0.0.1', '10.0.0.2'], Port: 443); + self::assertSame(['10.0.0.1', '10.0.0.2'], $c->getAddresses()); + self::assertSame(443, $c->getPort()); + } + + public function testFluentSetters(): void + { + $c = new DestinationConfig(); + $result = $c->setAddresses('1.2.3.4')->setPort(8080); + self::assertSame($c, $result); + self::assertSame(['1.2.3.4'], $c->getAddresses()); + self::assertSame(8080, $c->getPort()); + } + +} diff --git a/tests/Unit/ConfigEntry/EnvoyExtensionTest.php b/tests/Unit/ConfigEntry/EnvoyExtensionTest.php new file mode 100644 index 00000000..aebc3f82 --- /dev/null +++ b/tests/Unit/ConfigEntry/EnvoyExtensionTest.php @@ -0,0 +1,56 @@ +getName()); + self::assertFalse($e->isRequired()); + self::assertSame([], $e->getArguments()); + self::assertSame('', $e->getConsulVersion()); + self::assertSame('', $e->getEnvoyVersion()); + } + + public function testConstructorWithParams(): void + { + $e = new EnvoyExtension( + Name: 'lua', + Required: true, + Arguments: ['key' => 'val'], + ConsulVersion: '1.15', + EnvoyVersion: '1.25', + ); + self::assertSame('lua', $e->getName()); + self::assertTrue($e->isRequired()); + self::assertSame(['key' => 'val'], $e->getArguments()); + self::assertSame('1.15', $e->getConsulVersion()); + self::assertSame('1.25', $e->getEnvoyVersion()); + } + + public function testFluentSetters(): void + { + $e = new EnvoyExtension(); + $result = $e->setName('ext') + ->setRequired(true) + ->setArguments(['a' => 'b']) + ->setConsulVersion('1.16') + ->setEnvoyVersion('1.26'); + self::assertSame($e, $result); + self::assertSame('ext', $e->getName()); + self::assertTrue($e->isRequired()); + self::assertSame(['a' => 'b'], $e->getArguments()); + self::assertSame('1.16', $e->getConsulVersion()); + self::assertSame('1.26', $e->getEnvoyVersion()); + } + +} diff --git a/tests/Unit/ConfigEntry/ExposeConfigTest.php b/tests/Unit/ConfigEntry/ExposeConfigTest.php new file mode 100644 index 00000000..e8a829cd --- /dev/null +++ b/tests/Unit/ConfigEntry/ExposeConfigTest.php @@ -0,0 +1,40 @@ +isChecks()); + self::assertSame([], $c->getPaths()); + } + + public function testConstructorWithParams(): void + { + $path = new ExposePath(ListenerPort: 21500, Path: '/health', Protocol: 'http'); + $c = new ExposeConfig(Checks: true, Paths: [$path]); + self::assertTrue($c->isChecks()); + self::assertCount(1, $c->getPaths()); + } + + public function testFluentSetters(): void + { + $path = new ExposePath(ListenerPort: 21500); + $c = new ExposeConfig(); + $result = $c->setChecks(true)->setPaths($path); + self::assertSame($c, $result); + self::assertTrue($c->isChecks()); + self::assertCount(1, $c->getPaths()); + } + +} diff --git a/tests/Unit/ConfigEntry/ExposePathTest.php b/tests/Unit/ConfigEntry/ExposePathTest.php new file mode 100644 index 00000000..27288772 --- /dev/null +++ b/tests/Unit/ConfigEntry/ExposePathTest.php @@ -0,0 +1,56 @@ +getListenerPort()); + self::assertSame('', $p->getPath()); + self::assertSame(0, $p->getLocalPathPort()); + self::assertSame('', $p->getProtocol()); + self::assertFalse($p->isParsedFromCheck()); + } + + public function testConstructorWithParams(): void + { + $p = new ExposePath( + ListenerPort: 21500, + Path: '/health', + LocalPathPort: 8080, + Protocol: 'http', + ParsedFromCheck: true, + ); + self::assertSame(21500, $p->getListenerPort()); + self::assertSame('/health', $p->getPath()); + self::assertSame(8080, $p->getLocalPathPort()); + self::assertSame('http', $p->getProtocol()); + self::assertTrue($p->isParsedFromCheck()); + } + + public function testFluentSetters(): void + { + $p = new ExposePath(); + $result = $p->setListenerPort(21500) + ->setPath('/ready') + ->setLocalPathPort(8080) + ->setProtocol('http2') + ->setParsedFromCheck(true); + self::assertSame($p, $result); + self::assertSame(21500, $p->getListenerPort()); + self::assertSame('/ready', $p->getPath()); + self::assertSame(8080, $p->getLocalPathPort()); + self::assertSame('http2', $p->getProtocol()); + self::assertTrue($p->isParsedFromCheck()); + } + +} diff --git a/tests/Unit/ConfigEntry/GatewayServiceTLSConfigTest.php b/tests/Unit/ConfigEntry/GatewayServiceTLSConfigTest.php new file mode 100644 index 00000000..ca468dce --- /dev/null +++ b/tests/Unit/ConfigEntry/GatewayServiceTLSConfigTest.php @@ -0,0 +1,37 @@ +getSDS()); + } + + public function testConstructorWithParams(): void + { + $sds = new GatewayTLSSDSConfig(ClusterName: 'c', CertResource: 'r'); + $c = new GatewayServiceTLSConfig(SDS: $sds); + self::assertSame($sds, $c->getSDS()); + } + + public function testFluentSetters(): void + { + $sds = new GatewayTLSSDSConfig(ClusterName: 'c'); + $c = new GatewayServiceTLSConfig(); + $result = $c->setSDS($sds); + self::assertSame($c, $result); + self::assertSame($sds, $c->getSDS()); + } + +} diff --git a/tests/Unit/ConfigEntry/GatewayTLSConfigTest.php b/tests/Unit/ConfigEntry/GatewayTLSConfigTest.php new file mode 100644 index 00000000..8e7e7294 --- /dev/null +++ b/tests/Unit/ConfigEntry/GatewayTLSConfigTest.php @@ -0,0 +1,56 @@ +isEnabled()); + self::assertNull($c->getSDS()); + self::assertSame('', $c->getTLSMinVersion()); + self::assertSame('', $c->getTLSMaxVersion()); + self::assertSame([], $c->getCipherSuites()); + } + + public function testConstructorWithParams(): void + { + $sds = new GatewayTLSSDSConfig(ClusterName: 'c'); + $c = new GatewayTLSConfig( + Enabled: true, + SDS: $sds, + TLSMinVersion: 'TLSv1_2', + TLSMaxVersion: 'TLSv1_3', + CipherSuites: ['suite1'], + ); + self::assertTrue($c->isEnabled()); + self::assertSame($sds, $c->getSDS()); + self::assertSame('TLSv1_2', $c->getTLSMinVersion()); + self::assertSame('TLSv1_3', $c->getTLSMaxVersion()); + self::assertSame(['suite1'], $c->getCipherSuites()); + } + + public function testFluentSetters(): void + { + $c = new GatewayTLSConfig(); + $result = $c->setEnabled(true) + ->setTLSMinVersion('TLSv1_2') + ->setTLSMaxVersion('TLSv1_3') + ->setCipherSuites('s1', 's2'); + self::assertSame($c, $result); + self::assertTrue($c->isEnabled()); + self::assertSame('TLSv1_2', $c->getTLSMinVersion()); + self::assertSame('TLSv1_3', $c->getTLSMaxVersion()); + self::assertSame(['s1', 's2'], $c->getCipherSuites()); + } + +} diff --git a/tests/Unit/ConfigEntry/GatewayTLSSDSConfigTest.php b/tests/Unit/ConfigEntry/GatewayTLSSDSConfigTest.php new file mode 100644 index 00000000..a861ec8f --- /dev/null +++ b/tests/Unit/ConfigEntry/GatewayTLSSDSConfigTest.php @@ -0,0 +1,37 @@ +getClusterName()); + self::assertSame('', $c->getCertResource()); + } + + public function testConstructorWithParams(): void + { + $c = new GatewayTLSSDSConfig(ClusterName: 'cluster', CertResource: 'cert'); + self::assertSame('cluster', $c->getClusterName()); + self::assertSame('cert', $c->getCertResource()); + } + + public function testFluentSetters(): void + { + $c = new GatewayTLSSDSConfig(); + $result = $c->setClusterName('cl')->setCertResource('cr'); + self::assertSame($c, $result); + self::assertSame('cl', $c->getClusterName()); + self::assertSame('cr', $c->getCertResource()); + } + +} diff --git a/tests/Unit/ConfigEntry/HTTPHeaderModifiersTest.php b/tests/Unit/ConfigEntry/HTTPHeaderModifiersTest.php new file mode 100644 index 00000000..068dbd1d --- /dev/null +++ b/tests/Unit/ConfigEntry/HTTPHeaderModifiersTest.php @@ -0,0 +1,46 @@ +getAdd()); + self::assertSame([], $h->getSet()); + self::assertSame([], $h->getRemove()); + } + + public function testConstructorWithParams(): void + { + $h = new HTTPHeaderModifiers( + Add: ['X-Custom' => 'value'], + Set: ['X-Replace' => 'new-value'], + Remove: ['X-Remove'], + ); + self::assertSame(['X-Custom' => 'value'], $h->getAdd()); + self::assertSame(['X-Replace' => 'new-value'], $h->getSet()); + self::assertSame(['X-Remove'], $h->getRemove()); + } + + public function testFluentSetters(): void + { + $h = new HTTPHeaderModifiers(); + $result = $h->setAdd(['X-A' => 'a']) + ->setSet(['X-S' => 's']) + ->setRemove('X-R'); + self::assertSame($h, $result); + self::assertSame(['X-A' => 'a'], $h->getAdd()); + self::assertSame(['X-S' => 's'], $h->getSet()); + self::assertSame(['X-R'], $h->getRemove()); + } + +} diff --git a/tests/Unit/ConfigEntry/HashPolicyTest.php b/tests/Unit/ConfigEntry/HashPolicyTest.php new file mode 100644 index 00000000..9da79e15 --- /dev/null +++ b/tests/Unit/ConfigEntry/HashPolicyTest.php @@ -0,0 +1,59 @@ +getField()); + self::assertSame('', $h->getFieldValue()); + self::assertNull($h->getCookieConfig()); + self::assertFalse($h->isSourceIP()); + self::assertFalse($h->isTerminal()); + } + + public function testConstructorWithParams(): void + { + $cookie = new CookieConfig(Session: true, Path: '/'); + $h = new HashPolicy( + Field: 'header', + FieldValue: 'x-user', + CookieConfig: $cookie, + SourceIP: true, + Terminal: true, + ); + self::assertSame('header', $h->getField()); + self::assertSame('x-user', $h->getFieldValue()); + self::assertSame($cookie, $h->getCookieConfig()); + self::assertTrue($h->isSourceIP()); + self::assertTrue($h->isTerminal()); + } + + public function testFluentSetters(): void + { + $cookie = new CookieConfig(); + $h = new HashPolicy(); + $result = $h->setField('cookie') + ->setFieldValue('session') + ->setCookieConfig($cookie) + ->setSourceIP(true) + ->setTerminal(true); + self::assertSame($h, $result); + self::assertSame('cookie', $h->getField()); + self::assertSame('session', $h->getFieldValue()); + self::assertSame($cookie, $h->getCookieConfig()); + self::assertTrue($h->isSourceIP()); + self::assertTrue($h->isTerminal()); + } + +} diff --git a/tests/Unit/ConfigEntry/IngressGatewayConfigEntryTest.php b/tests/Unit/ConfigEntry/IngressGatewayConfigEntryTest.php new file mode 100644 index 00000000..cc0e007f --- /dev/null +++ b/tests/Unit/ConfigEntry/IngressGatewayConfigEntryTest.php @@ -0,0 +1,59 @@ +getKind()); + self::assertSame('', $e->getName()); + self::assertSame('', $e->getPartition()); + self::assertSame([], $e->getListeners()); + self::assertNull($e->getDefaults()); + } + + public function testConstructorWithParams(): void + { + $listener = new IngressListener(Port: 8080, Protocol: 'http'); + $defaults = new IngressServiceConfig(MaxConnections: 100); + $e = new IngressGatewayConfigEntry( + Kind: 'ingress-gateway', + Name: 'my-gateway', + Partition: 'default', + Listeners: [$listener], + Defaults: $defaults, + ); + self::assertSame('ingress-gateway', $e->getKind()); + self::assertSame('my-gateway', $e->getName()); + self::assertSame('default', $e->getPartition()); + self::assertCount(1, $e->getListeners()); + self::assertSame($defaults, $e->getDefaults()); + } + + public function testFluentSetters(): void + { + $listener = new IngressListener(Port: 443); + $e = new IngressGatewayConfigEntry(); + $result = $e->setKind('ingress-gateway') + ->setName('gw') + ->setPartition('pt') + ->setListeners($listener); + self::assertSame($e, $result); + self::assertSame('ingress-gateway', $e->getKind()); + self::assertSame('gw', $e->getName()); + self::assertSame('pt', $e->getPartition()); + self::assertCount(1, $e->getListeners()); + } + +} diff --git a/tests/Unit/ConfigEntry/IngressListenerTest.php b/tests/Unit/ConfigEntry/IngressListenerTest.php new file mode 100644 index 00000000..9929e3f2 --- /dev/null +++ b/tests/Unit/ConfigEntry/IngressListenerTest.php @@ -0,0 +1,49 @@ +getPort()); + self::assertSame('', $l->getProtocol()); + self::assertSame([], $l->getServices()); + self::assertNull($l->getTLS()); + } + + public function testConstructorWithParams(): void + { + $svc = new IngressService(Name: 'web', Hosts: ['web.example.com']); + $tls = new GatewayTLSConfig(Enabled: true); + $l = new IngressListener(Port: 8080, Protocol: 'http', Services: [$svc], TLS: $tls); + self::assertSame(8080, $l->getPort()); + self::assertSame('http', $l->getProtocol()); + self::assertCount(1, $l->getServices()); + self::assertSame($tls, $l->getTLS()); + } + + public function testFluentSetters(): void + { + $svc = new IngressService(Name: 'api'); + $l = new IngressListener(); + $result = $l->setPort(443) + ->setProtocol('tcp') + ->setServices($svc); + self::assertSame($l, $result); + self::assertSame(443, $l->getPort()); + self::assertSame('tcp', $l->getProtocol()); + self::assertCount(1, $l->getServices()); + } + +} diff --git a/tests/Unit/ConfigEntry/IngressServiceConfigTest.php b/tests/Unit/ConfigEntry/IngressServiceConfigTest.php new file mode 100644 index 00000000..ad7cc855 --- /dev/null +++ b/tests/Unit/ConfigEntry/IngressServiceConfigTest.php @@ -0,0 +1,51 @@ +getMaxConnections()); + self::assertNull($c->getMaxPendingRequests()); + self::assertNull($c->getMaxConcurrentRequests()); + self::assertNull($c->getPassiveHealthCheck()); + } + + public function testConstructorWithParams(): void + { + $phc = new PassiveHealthCheck(MaxFailures: 3); + $c = new IngressServiceConfig( + MaxConnections: 100, + MaxPendingRequests: 50, + MaxConcurrentRequests: 25, + PassiveHealthCheck: $phc, + ); + self::assertSame(100, $c->getMaxConnections()); + self::assertSame(50, $c->getMaxPendingRequests()); + self::assertSame(25, $c->getMaxConcurrentRequests()); + self::assertSame($phc, $c->getPassiveHealthCheck()); + } + + public function testFluentSetters(): void + { + $c = new IngressServiceConfig(); + $result = $c->setMaxConnections(10) + ->setMaxPendingRequests(5) + ->setMaxConcurrentRequests(3); + self::assertSame($c, $result); + self::assertSame(10, $c->getMaxConnections()); + self::assertSame(5, $c->getMaxPendingRequests()); + self::assertSame(3, $c->getMaxConcurrentRequests()); + } + +} diff --git a/tests/Unit/ConfigEntry/IngressServiceTest.php b/tests/Unit/ConfigEntry/IngressServiceTest.php new file mode 100644 index 00000000..1dbe05a4 --- /dev/null +++ b/tests/Unit/ConfigEntry/IngressServiceTest.php @@ -0,0 +1,64 @@ +getName()); + self::assertSame([], $s->getHosts()); + self::assertSame('', $s->getNamespace()); + self::assertSame('', $s->getPartition()); + self::assertNull($s->getTLS()); + self::assertNull($s->getMaxConnections()); + self::assertNull($s->getMaxPendingRequests()); + self::assertNull($s->getMaxConcurrentRequests()); + } + + public function testConstructorWithParams(): void + { + $s = new IngressService( + Name: 'web', + Hosts: ['web.example.com'], + Namespace: 'ns', + Partition: 'pt', + MaxConnections: 100, + MaxPendingRequests: 50, + MaxConcurrentRequests: 25, + ); + self::assertSame('web', $s->getName()); + self::assertSame(['web.example.com'], $s->getHosts()); + self::assertSame('ns', $s->getNamespace()); + self::assertSame('pt', $s->getPartition()); + self::assertSame(100, $s->getMaxConnections()); + self::assertSame(50, $s->getMaxPendingRequests()); + self::assertSame(25, $s->getMaxConcurrentRequests()); + } + + public function testFluentSetters(): void + { + $s = new IngressService(); + $result = $s->setName('api') + ->setHosts('api.example.com') + ->setNamespace('ns') + ->setPartition('pt') + ->setMaxConnections(200); + self::assertSame($s, $result); + self::assertSame('api', $s->getName()); + self::assertSame(['api.example.com'], $s->getHosts()); + self::assertSame('ns', $s->getNamespace()); + self::assertSame('pt', $s->getPartition()); + self::assertSame(200, $s->getMaxConnections()); + } + +} diff --git a/tests/Unit/ConfigEntry/InstanceLevelRateLimitsTest.php b/tests/Unit/ConfigEntry/InstanceLevelRateLimitsTest.php new file mode 100644 index 00000000..532690da --- /dev/null +++ b/tests/Unit/ConfigEntry/InstanceLevelRateLimitsTest.php @@ -0,0 +1,41 @@ +getRequestsPerSecond()); + self::assertSame(0, $i->getRequestsMaxBurst()); + self::assertSame([], $i->getRoutes()); + } + + public function testConstructorWithParams(): void + { + $i = new InstanceLevelRateLimits( + RequestsPerSecond: 100, + RequestsMaxBurst: 200, + ); + self::assertSame(100, $i->getRequestsPerSecond()); + self::assertSame(200, $i->getRequestsMaxBurst()); + } + + public function testFluentSetters(): void + { + $i = new InstanceLevelRateLimits(); + $result = $i->setRequestsPerSecond(50)->setRequestsMaxBurst(100); + self::assertSame($i, $result); + self::assertSame(50, $i->getRequestsPerSecond()); + self::assertSame(100, $i->getRequestsMaxBurst()); + } + +} diff --git a/tests/Unit/ConfigEntry/InstanceLevelRouteRateLimitsTest.php b/tests/Unit/ConfigEntry/InstanceLevelRouteRateLimitsTest.php new file mode 100644 index 00000000..b585a32e --- /dev/null +++ b/tests/Unit/ConfigEntry/InstanceLevelRouteRateLimitsTest.php @@ -0,0 +1,56 @@ +getPathExact()); + self::assertSame('', $r->getPathPrefix()); + self::assertSame('', $r->getPathRegex()); + self::assertSame(0, $r->getRequestsPerSecond()); + self::assertSame(0, $r->getRequestsMaxBurst()); + } + + public function testConstructorWithParams(): void + { + $r = new InstanceLevelRouteRateLimits( + PathExact: '/api/v1', + PathPrefix: '/api', + PathRegex: '/api/.*', + RequestsPerSecond: 50, + RequestsMaxBurst: 100, + ); + self::assertSame('/api/v1', $r->getPathExact()); + self::assertSame('/api', $r->getPathPrefix()); + self::assertSame('/api/.*', $r->getPathRegex()); + self::assertSame(50, $r->getRequestsPerSecond()); + self::assertSame(100, $r->getRequestsMaxBurst()); + } + + public function testFluentSetters(): void + { + $r = new InstanceLevelRouteRateLimits(); + $result = $r->setPathExact('/exact') + ->setPathPrefix('/prefix') + ->setPathRegex('/re.*') + ->setRequestsPerSecond(10) + ->setRequestsMaxBurst(20); + self::assertSame($r, $result); + self::assertSame('/exact', $r->getPathExact()); + self::assertSame('/prefix', $r->getPathPrefix()); + self::assertSame('/re.*', $r->getPathRegex()); + self::assertSame(10, $r->getRequestsPerSecond()); + self::assertSame(20, $r->getRequestsMaxBurst()); + } + +} diff --git a/tests/Unit/ConfigEntry/IntentionActionTest.php b/tests/Unit/ConfigEntry/IntentionActionTest.php new file mode 100644 index 00000000..d4e6164f --- /dev/null +++ b/tests/Unit/ConfigEntry/IntentionActionTest.php @@ -0,0 +1,49 @@ +value); + } + + public function testAllowFromString(): void + { + $e = IntentionAction::from('allow'); + self::assertSame(IntentionAction::Allow, $e); + } + + public function testDenyCase(): void + { + $e = IntentionAction::Deny; + self::assertSame('deny', $e->value); + } + + public function testDenyFromString(): void + { + $e = IntentionAction::from('deny'); + self::assertSame(IntentionAction::Deny, $e); + } + + public function testUNDEFINEDCase(): void + { + $e = IntentionAction::UNDEFINED; + self::assertSame('', $e->value); + } + + public function testUNDEFINEDFromString(): void + { + $e = IntentionAction::from(''); + self::assertSame(IntentionAction::UNDEFINED, $e); + } +} diff --git a/tests/Unit/ConfigEntry/IntentionHTTPHeaderPermissionTest.php b/tests/Unit/ConfigEntry/IntentionHTTPHeaderPermissionTest.php new file mode 100644 index 00000000..39e57180 --- /dev/null +++ b/tests/Unit/ConfigEntry/IntentionHTTPHeaderPermissionTest.php @@ -0,0 +1,62 @@ +getName()); + self::assertFalse($h->isPresent()); + self::assertSame('', $h->getExact()); + self::assertSame('', $h->getPrefix()); + self::assertSame('', $h->getSuffix()); + self::assertSame('', $h->getRegex()); + self::assertFalse($h->isInvert()); + } + + public function testConstructorWithParams(): void + { + $h = new IntentionHTTPHeaderPermission( + Name: 'x-service', + Present: true, + Exact: 'web', + Prefix: 'pre', + Suffix: 'suf', + Regex: '.*', + Invert: true, + ); + self::assertSame('x-service', $h->getName()); + self::assertTrue($h->isPresent()); + self::assertSame('web', $h->getExact()); + self::assertSame('pre', $h->getPrefix()); + self::assertSame('suf', $h->getSuffix()); + self::assertSame('.*', $h->getRegex()); + self::assertTrue($h->isInvert()); + } + + public function testFluentSetters(): void + { + $h = new IntentionHTTPHeaderPermission(); + $result = $h->setName('x-test') + ->setPresent(true) + ->setExact('val') + ->setPrefix('p') + ->setSuffix('s') + ->setRegex('r') + ->setInvert(true); + self::assertSame($h, $result); + self::assertSame('x-test', $h->getName()); + self::assertTrue($h->isPresent()); + self::assertSame('val', $h->getExact()); + } + +} diff --git a/tests/Unit/ConfigEntry/IntentionHTTPPermissionTest.php b/tests/Unit/ConfigEntry/IntentionHTTPPermissionTest.php new file mode 100644 index 00000000..51ee522a --- /dev/null +++ b/tests/Unit/ConfigEntry/IntentionHTTPPermissionTest.php @@ -0,0 +1,56 @@ +getPathExact()); + self::assertSame('', $p->getPathPrefix()); + self::assertSame('', $p->getPathRegex()); + self::assertSame([], $p->getHeader()); + self::assertSame([], $p->getMethods()); + } + + public function testConstructorWithParams(): void + { + $h = new IntentionHTTPHeaderPermission(Name: 'x-header'); + $p = new IntentionHTTPPermission( + PathExact: '/api/v1', + PathPrefix: '/api', + PathRegex: '/api/.*', + Header: [$h], + Methods: ['GET', 'POST'], + ); + self::assertSame('/api/v1', $p->getPathExact()); + self::assertSame('/api', $p->getPathPrefix()); + self::assertSame('/api/.*', $p->getPathRegex()); + self::assertCount(1, $p->getHeader()); + self::assertSame(['GET', 'POST'], $p->getMethods()); + } + + public function testFluentSetters(): void + { + $p = new IntentionHTTPPermission(); + $result = $p->setPathExact('/exact') + ->setPathPrefix('/prefix') + ->setPathRegex('/re.*') + ->setMethods('GET'); + self::assertSame($p, $result); + self::assertSame('/exact', $p->getPathExact()); + self::assertSame('/prefix', $p->getPathPrefix()); + self::assertSame('/re.*', $p->getPathRegex()); + self::assertSame(['GET'], $p->getMethods()); + } + +} diff --git a/tests/Unit/ConfigEntry/IntentionJWTClaimVerificationTest.php b/tests/Unit/ConfigEntry/IntentionJWTClaimVerificationTest.php new file mode 100644 index 00000000..744d9c08 --- /dev/null +++ b/tests/Unit/ConfigEntry/IntentionJWTClaimVerificationTest.php @@ -0,0 +1,37 @@ +getPath()); + self::assertSame('', $v->getValue()); + } + + public function testConstructorWithParams(): void + { + $v = new IntentionJWTClaimVerification(Path: ['iss'], Value: 'my-issuer'); + self::assertSame(['iss'], $v->getPath()); + self::assertSame('my-issuer', $v->getValue()); + } + + public function testFluentSetters(): void + { + $v = new IntentionJWTClaimVerification(); + $result = $v->setPath('sub')->setValue('user'); + self::assertSame($v, $result); + self::assertSame(['sub'], $v->getPath()); + self::assertSame('user', $v->getValue()); + } + +} diff --git a/tests/Unit/ConfigEntry/IntentionJWTRequirementTest.php b/tests/Unit/ConfigEntry/IntentionJWTRequirementTest.php new file mode 100644 index 00000000..72ccd725 --- /dev/null +++ b/tests/Unit/ConfigEntry/IntentionJWTRequirementTest.php @@ -0,0 +1,38 @@ +getName()); + self::assertSame([], $r->getVerifyClaims()); + } + + public function testConstructorWithParams(): void + { + $claim = new IntentionJWTClaimVerification(Path: ['iss'], Value: 'val'); + $r = new IntentionJWTRequirement(Name: 'jwt-provider', VerifyClaims: [$claim]); + self::assertSame('jwt-provider', $r->getName()); + self::assertCount(1, $r->getVerifyClaims()); + } + + public function testFluentSetters(): void + { + $r = new IntentionJWTRequirement(); + $result = $r->setName('provider'); + self::assertSame($r, $result); + self::assertSame('provider', $r->getName()); + } + +} diff --git a/tests/Unit/ConfigEntry/IntentionMatchTypeTest.php b/tests/Unit/ConfigEntry/IntentionMatchTypeTest.php new file mode 100644 index 00000000..b5386a69 --- /dev/null +++ b/tests/Unit/ConfigEntry/IntentionMatchTypeTest.php @@ -0,0 +1,49 @@ +value); + } + + public function testSourceFromString(): void + { + $e = IntentionMatchType::from('source'); + self::assertSame(IntentionMatchType::Source, $e); + } + + public function testDestinationCase(): void + { + $e = IntentionMatchType::Destination; + self::assertSame('destination', $e->value); + } + + public function testDestinationFromString(): void + { + $e = IntentionMatchType::from('destination'); + self::assertSame(IntentionMatchType::Destination, $e); + } + + public function testUNDEFINEDCase(): void + { + $e = IntentionMatchType::UNDEFINED; + self::assertSame('', $e->value); + } + + public function testUNDEFINEDFromString(): void + { + $e = IntentionMatchType::from(''); + self::assertSame(IntentionMatchType::UNDEFINED, $e); + } +} diff --git a/tests/Unit/ConfigEntry/IntentionPermissionTest.php b/tests/Unit/ConfigEntry/IntentionPermissionTest.php new file mode 100644 index 00000000..572f026b --- /dev/null +++ b/tests/Unit/ConfigEntry/IntentionPermissionTest.php @@ -0,0 +1,55 @@ +getAction()); + self::assertNull($p->getHTTP()); + self::assertNull($p->getJWT()); + } + + public function testConstructorWithParams(): void + { + $http = new IntentionHTTPPermission(PathPrefix: '/api'); + $jwt = new IntentionJWTRequirement(Name: 'jwt'); + $p = new IntentionPermission( + Action: IntentionAction::Allow, + HTTP: $http, + JWT: $jwt, + ); + self::assertSame(IntentionAction::Allow, $p->getAction()); + self::assertSame($http, $p->getHTTP()); + self::assertSame($jwt, $p->getJWT()); + } + + public function testFluentSetters(): void + { + $http = new IntentionHTTPPermission(PathPrefix: '/v1'); + $p = new IntentionPermission(); + $result = $p->setAction(IntentionAction::Deny) + ->setHTTP($http); + self::assertSame($p, $result); + self::assertSame(IntentionAction::Deny, $p->getAction()); + self::assertSame($http, $p->getHTTP()); + } + + public function testConstructorWithEnumAsString(): void + { + $p = new IntentionPermission(Action: 'allow'); + self::assertSame(IntentionAction::Allow, $p->getAction()); + } +} diff --git a/tests/Unit/ConfigEntry/IntentionSourceTypeTest.php b/tests/Unit/ConfigEntry/IntentionSourceTypeTest.php new file mode 100644 index 00000000..d75e629c --- /dev/null +++ b/tests/Unit/ConfigEntry/IntentionSourceTypeTest.php @@ -0,0 +1,37 @@ +value); + } + + public function testConsulFromString(): void + { + $e = IntentionSourceType::from('consul'); + self::assertSame(IntentionSourceType::Consul, $e); + } + + public function testUNDEFINEDCase(): void + { + $e = IntentionSourceType::UNDEFINED; + self::assertSame('', $e->value); + } + + public function testUNDEFINEDFromString(): void + { + $e = IntentionSourceType::from(''); + self::assertSame(IntentionSourceType::UNDEFINED, $e); + } +} diff --git a/tests/Unit/ConfigEntry/LeastRequestConfigTest.php b/tests/Unit/ConfigEntry/LeastRequestConfigTest.php new file mode 100644 index 00000000..74f477f1 --- /dev/null +++ b/tests/Unit/ConfigEntry/LeastRequestConfigTest.php @@ -0,0 +1,34 @@ +getChoiceCount()); + } + + public function testConstructorWithParams(): void + { + $c = new LeastRequestConfig(ChoiceCount: 5); + self::assertSame(5, $c->getChoiceCount()); + } + + public function testFluentSetters(): void + { + $c = new LeastRequestConfig(); + $result = $c->setChoiceCount(10); + self::assertSame($c, $result); + self::assertSame(10, $c->getChoiceCount()); + } + +} diff --git a/tests/Unit/ConfigEntry/LinkedServiceTest.php b/tests/Unit/ConfigEntry/LinkedServiceTest.php new file mode 100644 index 00000000..1ce9fdbf --- /dev/null +++ b/tests/Unit/ConfigEntry/LinkedServiceTest.php @@ -0,0 +1,61 @@ +getNamespace()); + self::assertSame('', $l->getName()); + self::assertSame('', $l->getCAFile()); + self::assertSame('', $l->getCertFile()); + self::assertSame('', $l->getKeyFile()); + self::assertSame('', $l->getSNI()); + } + + public function testConstructorWithParams(): void + { + $l = new LinkedService( + Namespace: 'ns', + Name: 'web', + CAFile: 'ca.pem', + CertFile: 'cert.pem', + KeyFile: 'key.pem', + SNI: 'web.consul', + ); + self::assertSame('ns', $l->getNamespace()); + self::assertSame('web', $l->getName()); + self::assertSame('ca.pem', $l->getCAFile()); + self::assertSame('cert.pem', $l->getCertFile()); + self::assertSame('key.pem', $l->getKeyFile()); + self::assertSame('web.consul', $l->getSNI()); + } + + public function testFluentSetters(): void + { + $l = new LinkedService(); + $result = $l->setNamespace('ns') + ->setName('svc') + ->setCAFile('ca') + ->setCertFile('cert') + ->setKeyFile('key') + ->setSNI('sni'); + self::assertSame($l, $result); + self::assertSame('ns', $l->getNamespace()); + self::assertSame('svc', $l->getName()); + self::assertSame('ca', $l->getCAFile()); + self::assertSame('cert', $l->getCertFile()); + self::assertSame('key', $l->getKeyFile()); + self::assertSame('sni', $l->getSNI()); + } + +} diff --git a/tests/Unit/ConfigEntry/LoadBalancerTest.php b/tests/Unit/ConfigEntry/LoadBalancerTest.php new file mode 100644 index 00000000..8c25169e --- /dev/null +++ b/tests/Unit/ConfigEntry/LoadBalancerTest.php @@ -0,0 +1,49 @@ +getPolicy()); + self::assertNull($l->getRingHashConfig()); + self::assertNull($l->getLeastRequestConfig()); + } + + public function testConstructorWithParams(): void + { + $rh = new RingHashConfig(MinimumRingSize: 1024); + $lr = new LeastRequestConfig(ChoiceCount: 5); + $l = new LoadBalancer( + Policy: 'ring_hash', + RingHashConfig: $rh, + LeastRequestConfig: $lr, + ); + self::assertSame('ring_hash', $l->getPolicy()); + self::assertSame($rh, $l->getRingHashConfig()); + self::assertSame($lr, $l->getLeastRequestConfig()); + } + + public function testFluentSetters(): void + { + $rh = new RingHashConfig(MinimumRingSize: 512); + $l = new LoadBalancer(); + $result = $l->setPolicy('ring_hash') + ->setRingHashConfig($rh); + self::assertSame($l, $result); + self::assertSame('ring_hash', $l->getPolicy()); + self::assertSame($rh, $l->getRingHashConfig()); + } + +} diff --git a/tests/Unit/ConfigEntry/LogSinkTypeTest.php b/tests/Unit/ConfigEntry/LogSinkTypeTest.php new file mode 100644 index 00000000..ef6e0356 --- /dev/null +++ b/tests/Unit/ConfigEntry/LogSinkTypeTest.php @@ -0,0 +1,61 @@ +value); + } + + public function testDefaultFromString(): void + { + $e = LogSinkType::from(''); + self::assertSame(LogSinkType::Default, $e); + } + + public function testFileCase(): void + { + $e = LogSinkType::File; + self::assertSame('file', $e->value); + } + + public function testFileFromString(): void + { + $e = LogSinkType::from('file'); + self::assertSame(LogSinkType::File, $e); + } + + public function testStdErrCase(): void + { + $e = LogSinkType::StdErr; + self::assertSame('stderr', $e->value); + } + + public function testStdErrFromString(): void + { + $e = LogSinkType::from('stderr'); + self::assertSame(LogSinkType::StdErr, $e); + } + + public function testStdOutCase(): void + { + $e = LogSinkType::StdOut; + self::assertSame('stdout', $e->value); + } + + public function testStdOutFromString(): void + { + $e = LogSinkType::from('stdout'); + self::assertSame(LogSinkType::StdOut, $e); + } +} diff --git a/tests/Unit/ConfigEntry/MeshConfigEntryTest.php b/tests/Unit/ConfigEntry/MeshConfigEntryTest.php new file mode 100644 index 00000000..03469692 --- /dev/null +++ b/tests/Unit/ConfigEntry/MeshConfigEntryTest.php @@ -0,0 +1,64 @@ +getKind()); + self::assertSame(Consul::MeshConfigMesh, $m->getName()); + self::assertSame('', $m->Partition); + self::assertInstanceOf(TransparentProxyMeshConfig::class, $m->getTransparentProxy()); + self::assertFalse($m->isAllowEnablingPermissiveMutualTLS()); + self::assertNull($m->getTLS()); + self::assertNull($m->getHTTP()); + self::assertNull($m->getPeering()); + } + + public function testConstructorWithParams(): void + { + $tp = new TransparentProxyMeshConfig(MeshDestinationsOnly: true); + $tls = new MeshTLSConfig(); + $http = new MeshHTTPConfig(SanitizeXForwardClientCert: true); + $peering = new PeeringMeshConfig(PeerThroughMeshGateways: true); + $m = new MeshConfigEntry( + Partition: 'pt', + TransparentProxy: $tp, + AllowEnablingPermissiveMutualTLS: true, + TLS: $tls, + HTTP: $http, + Peering: $peering, + ); + self::assertSame($tp, $m->getTransparentProxy()); + self::assertTrue($m->isAllowEnablingPermissiveMutualTLS()); + self::assertSame($tls, $m->getTLS()); + self::assertSame($http, $m->getHTTP()); + self::assertSame($peering, $m->getPeering()); + } + + public function testFluentSetters(): void + { + $tp = new TransparentProxyMeshConfig(MeshDestinationsOnly: true); + $m = new MeshConfigEntry(); + $result = $m->setTransparentProxy($tp) + ->setAllowEnablingPermissiveMutualTLS(true); + self::assertSame($m, $result); + self::assertSame($tp, $m->getTransparentProxy()); + self::assertTrue($m->isAllowEnablingPermissiveMutualTLS()); + } + +} diff --git a/tests/Unit/ConfigEntry/MeshDirectionalTLSConfigTest.php b/tests/Unit/ConfigEntry/MeshDirectionalTLSConfigTest.php new file mode 100644 index 00000000..a88218c4 --- /dev/null +++ b/tests/Unit/ConfigEntry/MeshDirectionalTLSConfigTest.php @@ -0,0 +1,46 @@ +getTLSMinVersion()); + self::assertSame('', $m->getTLSMaxVersion()); + self::assertSame([], $m->getCipherSuites()); + } + + public function testConstructorWithParams(): void + { + $m = new MeshDirectionalTLSConfig( + TLSMinVersion: 'TLSv1_2', + TLSMaxVersion: 'TLSv1_3', + CipherSuites: ['suite1'], + ); + self::assertSame('TLSv1_2', $m->getTLSMinVersion()); + self::assertSame('TLSv1_3', $m->getTLSMaxVersion()); + self::assertSame(['suite1'], $m->getCipherSuites()); + } + + public function testFluentSetters(): void + { + $m = new MeshDirectionalTLSConfig(); + $result = $m->setTLSMinVersion('TLSv1_2') + ->setTLSMaxVersion('TLSv1_3') + ->setCipherSuites('s1', 's2'); + self::assertSame($m, $result); + self::assertSame('TLSv1_2', $m->getTLSMinVersion()); + self::assertSame('TLSv1_3', $m->getTLSMaxVersion()); + self::assertSame(['s1', 's2'], $m->getCipherSuites()); + } + +} diff --git a/tests/Unit/ConfigEntry/MeshGatewayConfigTest.php b/tests/Unit/ConfigEntry/MeshGatewayConfigTest.php new file mode 100644 index 00000000..526531c4 --- /dev/null +++ b/tests/Unit/ConfigEntry/MeshGatewayConfigTest.php @@ -0,0 +1,47 @@ +getMode()); + } + + public function testConstructorWithParams(): void + { + $c = new MeshGatewayConfig(mode: MeshGatewayMode::Local); + self::assertSame(MeshGatewayMode::Local, $c->getMode()); + } + + public function testFluentSetters(): void + { + $c = new MeshGatewayConfig(); + $result = $c->setMode(MeshGatewayMode::Remote); + self::assertSame($c, $result); + self::assertSame(MeshGatewayMode::Remote, $c->getMode()); + } + + public function testConstructorWithEnumAsString(): void + { + $c = new MeshGatewayConfig(mode: 'local'); + self::assertSame(MeshGatewayMode::Local, $c->getMode()); + } + + public function testSetModeWithString(): void + { + $c = new MeshGatewayConfig(); + $c->setMode('remote'); + self::assertSame(MeshGatewayMode::Remote, $c->getMode()); + } +} diff --git a/tests/Unit/ConfigEntry/MeshGatewayModeTest.php b/tests/Unit/ConfigEntry/MeshGatewayModeTest.php new file mode 100644 index 00000000..455aa74f --- /dev/null +++ b/tests/Unit/ConfigEntry/MeshGatewayModeTest.php @@ -0,0 +1,61 @@ +value); + } + + public function testDefaultFromString(): void + { + $e = MeshGatewayMode::from(''); + self::assertSame(MeshGatewayMode::Default, $e); + } + + public function testNoneCase(): void + { + $e = MeshGatewayMode::None; + self::assertSame('none', $e->value); + } + + public function testNoneFromString(): void + { + $e = MeshGatewayMode::from('none'); + self::assertSame(MeshGatewayMode::None, $e); + } + + public function testLocalCase(): void + { + $e = MeshGatewayMode::Local; + self::assertSame('local', $e->value); + } + + public function testLocalFromString(): void + { + $e = MeshGatewayMode::from('local'); + self::assertSame(MeshGatewayMode::Local, $e); + } + + public function testRemoteCase(): void + { + $e = MeshGatewayMode::Remote; + self::assertSame('remote', $e->value); + } + + public function testRemoteFromString(): void + { + $e = MeshGatewayMode::from('remote'); + self::assertSame(MeshGatewayMode::Remote, $e); + } +} diff --git a/tests/Unit/ConfigEntry/MeshHTTPConfigTest.php b/tests/Unit/ConfigEntry/MeshHTTPConfigTest.php new file mode 100644 index 00000000..8d87daa6 --- /dev/null +++ b/tests/Unit/ConfigEntry/MeshHTTPConfigTest.php @@ -0,0 +1,34 @@ +isSanitizeXForwardClientCert()); + } + + public function testConstructorWithParams(): void + { + $m = new MeshHTTPConfig(SanitizeXForwardClientCert: true); + self::assertTrue($m->isSanitizeXForwardClientCert()); + } + + public function testFluentSetters(): void + { + $m = new MeshHTTPConfig(); + $result = $m->setSanitizeXForwardClientCert(true); + self::assertSame($m, $result); + self::assertTrue($m->isSanitizeXForwardClientCert()); + } + +} diff --git a/tests/Unit/ConfigEntry/MeshTLSConfigTest.php b/tests/Unit/ConfigEntry/MeshTLSConfigTest.php new file mode 100644 index 00000000..52a9723d --- /dev/null +++ b/tests/Unit/ConfigEntry/MeshTLSConfigTest.php @@ -0,0 +1,40 @@ +getIncoming()); + self::assertNull($m->getOutgoing()); + } + + public function testConstructorWithParams(): void + { + $incoming = new MeshDirectionalTLSConfig(TLSMinVersion: 'TLSv1_2'); + $outgoing = new MeshDirectionalTLSConfig(TLSMinVersion: 'TLSv1_3'); + $m = new MeshTLSConfig(Incoming: $incoming, Outgoing: $outgoing); + self::assertSame($incoming, $m->getIncoming()); + self::assertSame($outgoing, $m->getOutgoing()); + } + + public function testFluentSetters(): void + { + $incoming = new MeshDirectionalTLSConfig(TLSMinVersion: 'TLSv1_2'); + $m = new MeshTLSConfig(); + $result = $m->setIncoming($incoming); + self::assertSame($m, $result); + self::assertSame($incoming, $m->getIncoming()); + } + +} diff --git a/tests/Unit/ConfigEntry/MutualTLSModeTest.php b/tests/Unit/ConfigEntry/MutualTLSModeTest.php new file mode 100644 index 00000000..ff699d84 --- /dev/null +++ b/tests/Unit/ConfigEntry/MutualTLSModeTest.php @@ -0,0 +1,49 @@ +value); + } + + public function testDefaultFromString(): void + { + $e = MutualTLSMode::from(''); + self::assertSame(MutualTLSMode::Default, $e); + } + + public function testStrictCase(): void + { + $e = MutualTLSMode::Strict; + self::assertSame('strict', $e->value); + } + + public function testStrictFromString(): void + { + $e = MutualTLSMode::from('strict'); + self::assertSame(MutualTLSMode::Strict, $e); + } + + public function testPermissiveCase(): void + { + $e = MutualTLSMode::Permissive; + self::assertSame('permissive', $e->value); + } + + public function testPermissiveFromString(): void + { + $e = MutualTLSMode::from('permissive'); + self::assertSame(MutualTLSMode::Permissive, $e); + } +} diff --git a/tests/Unit/ConfigEntry/PassiveHealthCheckTest.php b/tests/Unit/ConfigEntry/PassiveHealthCheckTest.php new file mode 100644 index 00000000..7ccf9662 --- /dev/null +++ b/tests/Unit/ConfigEntry/PassiveHealthCheckTest.php @@ -0,0 +1,49 @@ +getInterval()->Nanoseconds()); + self::assertSame(0, $p->getMaxFailures()); + self::assertNull($p->getEnforcingConsecutive5xx()); + self::assertNull($p->getMaxEjectionPercent()); + self::assertNull($p->getBaseEjectionTime()); + } + + public function testConstructorWithParams(): void + { + $p = new PassiveHealthCheck( + Interval: '10s', + MaxFailures: 3, + EnforcingConsecutive5xx: 100, + MaxEjectionPercent: 50, + ); + self::assertSame(3, $p->getMaxFailures()); + self::assertSame(100, $p->getEnforcingConsecutive5xx()); + self::assertSame(50, $p->getMaxEjectionPercent()); + } + + public function testFluentSetters(): void + { + $p = new PassiveHealthCheck(); + $result = $p->setMaxFailures(5) + ->setEnforcingConsecutive5xx(80) + ->setMaxEjectionPercent(25); + self::assertSame($p, $result); + self::assertSame(5, $p->getMaxFailures()); + self::assertSame(80, $p->getEnforcingConsecutive5xx()); + self::assertSame(25, $p->getMaxEjectionPercent()); + } + +} diff --git a/tests/Unit/ConfigEntry/PeeringMeshConfigTest.php b/tests/Unit/ConfigEntry/PeeringMeshConfigTest.php new file mode 100644 index 00000000..e5063521 --- /dev/null +++ b/tests/Unit/ConfigEntry/PeeringMeshConfigTest.php @@ -0,0 +1,34 @@ +isPeerThroughMeshGateways()); + } + + public function testConstructorWithParams(): void + { + $c = new PeeringMeshConfig(PeerThroughMeshGateways: true); + self::assertTrue($c->isPeerThroughMeshGateways()); + } + + public function testFluentSetters(): void + { + $c = new PeeringMeshConfig(); + $result = $c->setPeerThroughMeshGateways(true); + self::assertSame($c, $result); + self::assertTrue($c->isPeerThroughMeshGateways()); + } + +} diff --git a/tests/Unit/ConfigEntry/ProxyConfigEntryTest.php b/tests/Unit/ConfigEntry/ProxyConfigEntryTest.php new file mode 100644 index 00000000..74244607 --- /dev/null +++ b/tests/Unit/ConfigEntry/ProxyConfigEntryTest.php @@ -0,0 +1,80 @@ +getKind()); + self::assertSame(Consul::ProxyConfigGlobal, $e->getName()); + self::assertSame('', $e->getPartition()); + self::assertSame(ProxyMode::Default, $e->getMode()); + self::assertNull($e->getTransparentProxy()); + self::assertSame(MutualTLSMode::Default, $e->getMutualTLSMode()); + self::assertSame([], $e->getConfig()); + self::assertNull($e->getAccessLogs()); + self::assertSame([], $e->getEnvoyExtensions()); + self::assertNull($e->getFailoverPolicy()); + self::assertNull($e->getPrioritizeByLocality()); + } + + public function testConstructorWithParams(): void + { + $tp = new TransparentProxyConfig(OutboundListenerPort: 15001); + $al = new AccessLogsConfig(Enabled: true); + $e = new ProxyConfigEntry( + Kind: 'proxy-defaults', + Name: 'global', + Partition: 'pt', + Mode: ProxyMode::Transparent, + TransparentProxy: $tp, + MutualTLSMode: MutualTLSMode::Strict, + Config: ['protocol' => 'http'], + AccessLogs: $al, + ); + self::assertSame('proxy-defaults', $e->getKind()); + self::assertSame('pt', $e->getPartition()); + self::assertSame(ProxyMode::Transparent, $e->getMode()); + self::assertSame($tp, $e->getTransparentProxy()); + self::assertSame(MutualTLSMode::Strict, $e->getMutualTLSMode()); + self::assertSame(['protocol' => 'http'], $e->getConfig()); + self::assertSame($al, $e->getAccessLogs()); + } + + public function testFluentSetters(): void + { + $e = new ProxyConfigEntry(); + $result = $e->setKind('proxy-defaults') + ->setPartition('pt') + ->setMode(ProxyMode::Direct) + ->setMutualTLSMode(MutualTLSMode::Permissive) + ->setConfig(['protocol' => 'tcp']); + self::assertSame($e, $result); + self::assertSame('proxy-defaults', $e->getKind()); + self::assertSame('pt', $e->getPartition()); + self::assertSame(ProxyMode::Direct, $e->getMode()); + self::assertSame(MutualTLSMode::Permissive, $e->getMutualTLSMode()); + self::assertSame(['protocol' => 'tcp'], $e->getConfig()); + } + + public function testConstructorWithEnumAsString(): void + { + $e = new ProxyConfigEntry(Mode: 'transparent', MutualTLSMode: 'strict'); + self::assertSame(ProxyMode::Transparent, $e->getMode()); + self::assertSame(MutualTLSMode::Strict, $e->getMutualTLSMode()); + } +} diff --git a/tests/Unit/ConfigEntry/ProxyModeTest.php b/tests/Unit/ConfigEntry/ProxyModeTest.php new file mode 100644 index 00000000..57f6dd6d --- /dev/null +++ b/tests/Unit/ConfigEntry/ProxyModeTest.php @@ -0,0 +1,49 @@ +value); + } + + public function testDefaultFromString(): void + { + $e = ProxyMode::from(''); + self::assertSame(ProxyMode::Default, $e); + } + + public function testTransparentCase(): void + { + $e = ProxyMode::Transparent; + self::assertSame('transparent', $e->value); + } + + public function testTransparentFromString(): void + { + $e = ProxyMode::from('transparent'); + self::assertSame(ProxyMode::Transparent, $e); + } + + public function testDirectCase(): void + { + $e = ProxyMode::Direct; + self::assertSame('direct', $e->value); + } + + public function testDirectFromString(): void + { + $e = ProxyMode::from('direct'); + self::assertSame(ProxyMode::Direct, $e); + } +} diff --git a/tests/Unit/ConfigEntry/RateLimitsTest.php b/tests/Unit/ConfigEntry/RateLimitsTest.php new file mode 100644 index 00000000..3b1aa9c9 --- /dev/null +++ b/tests/Unit/ConfigEntry/RateLimitsTest.php @@ -0,0 +1,37 @@ +getInstanceLevel()); + } + + public function testConstructorWithParams(): void + { + $il = new InstanceLevelRateLimits(RequestsPerSecond: 100); + $r = new RateLimits(instanceLevel: $il); + self::assertSame($il, $r->getInstanceLevel()); + } + + public function testFluentSetters(): void + { + $il = new InstanceLevelRateLimits(RequestsPerSecond: 50); + $r = new RateLimits(); + $result = $r->setInstanceLevel($il); + self::assertSame($r, $result); + self::assertSame($il, $r->getInstanceLevel()); + } + +} diff --git a/tests/Unit/ConfigEntry/RingHashConfigTest.php b/tests/Unit/ConfigEntry/RingHashConfigTest.php new file mode 100644 index 00000000..91036c7c --- /dev/null +++ b/tests/Unit/ConfigEntry/RingHashConfigTest.php @@ -0,0 +1,37 @@ +getMinimumRingSize()); + self::assertSame(0, $c->getMaximumRingSize()); + } + + public function testConstructorWithParams(): void + { + $c = new RingHashConfig(MinimumRingSize: 1024, MaximumRingSize: 8192); + self::assertSame(1024, $c->getMinimumRingSize()); + self::assertSame(8192, $c->getMaximumRingSize()); + } + + public function testFluentSetters(): void + { + $c = new RingHashConfig(); + $result = $c->setMinimumRingSize(512)->setMaximumRingSize(4096); + self::assertSame($c, $result); + self::assertSame(512, $c->getMinimumRingSize()); + self::assertSame(4096, $c->getMaximumRingSize()); + } + +} diff --git a/tests/Unit/ConfigEntry/ServiceConfigEntryTest.php b/tests/Unit/ConfigEntry/ServiceConfigEntryTest.php new file mode 100644 index 00000000..9c6e169d --- /dev/null +++ b/tests/Unit/ConfigEntry/ServiceConfigEntryTest.php @@ -0,0 +1,91 @@ +getKind()); + self::assertSame('', $e->getName()); + self::assertSame('', $e->getPartition()); + self::assertSame('', $e->getProtocol()); + self::assertSame(ProxyMode::Default, $e->getMode()); + self::assertNull($e->getTransparentProxy()); + self::assertSame(MutualTLSMode::Default, $e->getMutualTLSMode()); + self::assertSame('', $e->getExternalSNI()); + self::assertNull($e->getUpstreamConfig()); + self::assertNull($e->getDestination()); + self::assertSame(0, $e->getMaxInboundConnections()); + self::assertSame(0, $e->getLocalConnectTimeoutMs()); + self::assertSame(0, $e->getLocalRequestTimeoutMs()); + self::assertSame('', $e->getBalanceInboundConnections()); + self::assertNull($e->getRateLimits()); + self::assertSame([], $e->getEnvoyExtensions()); + } + + public function testConstructorWithParams(): void + { + $e = new ServiceConfigEntry( + Kind: 'service-defaults', + Name: 'web', + Partition: 'pt', + Protocol: 'http', + Mode: ProxyMode::Transparent, + MutualTLSMode: MutualTLSMode::Strict, + ExternalSNI: 'web.example.com', + MaxInboundConnections: 100, + ); + self::assertSame('service-defaults', $e->getKind()); + self::assertSame('web', $e->getName()); + self::assertSame('pt', $e->getPartition()); + self::assertSame('http', $e->getProtocol()); + self::assertSame(ProxyMode::Transparent, $e->getMode()); + self::assertSame(MutualTLSMode::Strict, $e->getMutualTLSMode()); + self::assertSame('web.example.com', $e->getExternalSNI()); + self::assertSame(100, $e->getMaxInboundConnections()); + } + + public function testFluentSetters(): void + { + $e = new ServiceConfigEntry(); + $result = $e->setKind('service-defaults') + ->setName('api') + ->setPartition('pt') + ->setProtocol('grpc') + ->setMode(ProxyMode::Direct) + ->setExternalSNI('api.example.com') + ->setMaxInboundConnections(50) + ->setLocalConnectTimeoutMs(5000) + ->setLocalRequestTimeoutMs(10000) + ->setBalanceInboundConnections('exact_balance'); + self::assertSame($e, $result); + self::assertSame('service-defaults', $e->getKind()); + self::assertSame('api', $e->getName()); + self::assertSame('pt', $e->getPartition()); + self::assertSame('grpc', $e->getProtocol()); + self::assertSame(ProxyMode::Direct, $e->getMode()); + self::assertSame('api.example.com', $e->getExternalSNI()); + self::assertSame(50, $e->getMaxInboundConnections()); + self::assertSame(5000, $e->getLocalConnectTimeoutMs()); + self::assertSame(10000, $e->getLocalRequestTimeoutMs()); + self::assertSame('exact_balance', $e->getBalanceInboundConnections()); + } + + public function testConstructorWithEnumAsString(): void + { + $e = new ServiceConfigEntry(Mode: 'transparent', MutualTLSMode: 'strict'); + self::assertSame(ProxyMode::Transparent, $e->getMode()); + self::assertSame(MutualTLSMode::Strict, $e->getMutualTLSMode()); + } +} diff --git a/tests/Unit/ConfigEntry/ServiceIntentionsConfigEntryTest.php b/tests/Unit/ConfigEntry/ServiceIntentionsConfigEntryTest.php new file mode 100644 index 00000000..222318e2 --- /dev/null +++ b/tests/Unit/ConfigEntry/ServiceIntentionsConfigEntryTest.php @@ -0,0 +1,64 @@ +getKind()); + self::assertSame('', $e->getName()); + self::assertSame('', $e->getPartition()); + self::assertSame('', $e->getNamespace()); + self::assertSame([], $e->getSources()); + self::assertNull($e->getJWT()); + } + + public function testConstructorWithParams(): void + { + $source = new SourceIntention(Name: 'web', Action: 'allow'); + $jwt = new IntentionJWTRequirement(Name: 'jwt'); + $e = new ServiceIntentionsConfigEntry( + Kind: 'service-intentions', + name: 'api', + Partition: 'pt', + Namespace: 'ns', + Sources: [$source], + JWT: $jwt, + ); + self::assertSame('service-intentions', $e->getKind()); + self::assertSame('api', $e->getName()); + self::assertSame('pt', $e->getPartition()); + self::assertSame('ns', $e->getNamespace()); + self::assertCount(1, $e->getSources()); + self::assertSame($jwt, $e->getJWT()); + } + + public function testFluentSetters(): void + { + $source = new SourceIntention(Name: 'web'); + $e = new ServiceIntentionsConfigEntry(); + $result = $e->setKind('service-intentions') + ->setName('api') + ->setPartition('pt') + ->setNamespace('ns') + ->setSources($source); + self::assertSame($e, $result); + self::assertSame('service-intentions', $e->getKind()); + self::assertSame('api', $e->getName()); + self::assertSame('pt', $e->getPartition()); + self::assertSame('ns', $e->getNamespace()); + self::assertCount(1, $e->getSources()); + } + +} diff --git a/tests/Unit/ConfigEntry/ServiceResolverConfigEntryTest.php b/tests/Unit/ConfigEntry/ServiceResolverConfigEntryTest.php new file mode 100644 index 00000000..42762ba7 --- /dev/null +++ b/tests/Unit/ConfigEntry/ServiceResolverConfigEntryTest.php @@ -0,0 +1,60 @@ +getKind()); + self::assertSame('', $e->getName()); + self::assertSame('', $e->getPartition()); + self::assertSame('', $e->getDefaultSubset()); + self::assertNull($e->getRedirect()); + self::assertNull($e->getLoadBalancer()); + } + + public function testConstructorWithParams(): void + { + $redirect = new ServiceResolverRedirect(Service: 'web-v2', Datacenter: 'dc2'); + $lb = new LoadBalancer(Policy: 'ring_hash'); + $e = new ServiceResolverConfigEntry( + Kind: 'service-resolver', + Name: 'web', + Partition: 'pt', + DefaultSubnet: 'v1', + Redirect: $redirect, + LoadBalancer: $lb, + ); + self::assertSame('service-resolver', $e->getKind()); + self::assertSame('web', $e->getName()); + self::assertSame('pt', $e->getPartition()); + self::assertSame($redirect, $e->getRedirect()); + self::assertSame($lb, $e->getLoadBalancer()); + } + + public function testFluentSetters(): void + { + $redirect = new ServiceResolverRedirect(Service: 'web-v2'); + $e = new ServiceResolverConfigEntry(); + $result = $e->setKind('service-resolver') + ->setName('api') + ->setPartition('pt') + ->setRedirect($redirect); + self::assertSame($e, $result); + self::assertSame('service-resolver', $e->getKind()); + self::assertSame('api', $e->getName()); + self::assertSame($redirect, $e->getRedirect()); + } + +} diff --git a/tests/Unit/ConfigEntry/ServiceResolverFailoverPolicyTest.php b/tests/Unit/ConfigEntry/ServiceResolverFailoverPolicyTest.php new file mode 100644 index 00000000..032993af --- /dev/null +++ b/tests/Unit/ConfigEntry/ServiceResolverFailoverPolicyTest.php @@ -0,0 +1,34 @@ +getMode()); + } + + public function testConstructorWithParams(): void + { + $p = new ServiceResolverFailoverPolicy(Mode: 'sequential', Regions: ['us-west-1']); + self::assertSame('sequential', $p->getMode()); + } + + public function testFluentSetters(): void + { + $p = new ServiceResolverFailoverPolicy(); + $result = $p->setMode('order-by-locality'); + self::assertSame($p, $result); + self::assertSame('order-by-locality', $p->getMode()); + } + +} diff --git a/tests/Unit/ConfigEntry/ServiceResolverFailoverTargetTest.php b/tests/Unit/ConfigEntry/ServiceResolverFailoverTargetTest.php new file mode 100644 index 00000000..14d041a2 --- /dev/null +++ b/tests/Unit/ConfigEntry/ServiceResolverFailoverTargetTest.php @@ -0,0 +1,61 @@ +getService()); + self::assertSame('', $t->getServiceSubset()); + self::assertSame('', $t->getPartition()); + self::assertSame('', $t->getNamespace()); + self::assertSame('', $t->getDatacenter()); + self::assertSame('', $t->getPeer()); + } + + public function testConstructorWithParams(): void + { + $t = new ServiceResolverFailoverTarget( + Service: 'web', + ServiceSubset: 'v1', + Partition: 'pt', + Namespace: 'ns', + Datacenter: 'dc2', + Peer: 'peer1', + ); + self::assertSame('web', $t->getService()); + self::assertSame('v1', $t->getServiceSubset()); + self::assertSame('pt', $t->getPartition()); + self::assertSame('ns', $t->getNamespace()); + self::assertSame('dc2', $t->getDatacenter()); + self::assertSame('peer1', $t->getPeer()); + } + + public function testFluentSetters(): void + { + $t = new ServiceResolverFailoverTarget(); + $result = $t->setService('web') + ->setServiceSubset('v1') + ->setPartition('pt') + ->setNamespace('ns') + ->setDatacenter('dc2') + ->setPeer('peer1'); + self::assertSame($t, $result); + self::assertSame('web', $t->getService()); + self::assertSame('v1', $t->getServiceSubset()); + self::assertSame('pt', $t->getPartition()); + self::assertSame('ns', $t->getNamespace()); + self::assertSame('dc2', $t->getDatacenter()); + self::assertSame('peer1', $t->getPeer()); + } + +} diff --git a/tests/Unit/ConfigEntry/ServiceResolverFailoverTest.php b/tests/Unit/ConfigEntry/ServiceResolverFailoverTest.php new file mode 100644 index 00000000..d62c0752 --- /dev/null +++ b/tests/Unit/ConfigEntry/ServiceResolverFailoverTest.php @@ -0,0 +1,66 @@ +getService()); + self::assertSame('', $f->getServiceSubset()); + self::assertSame('', $f->getNamespace()); + self::assertSame([], $f->getDatacenters()); + self::assertSame([], $f->getTargets()); + self::assertNull($f->getPolicy()); + self::assertSame('', $f->getSamenessGroup()); + } + + public function testConstructorWithParams(): void + { + $target = new ServiceResolverFailoverTarget(Datacenter: 'dc2'); + $policy = new ServiceResolverFailoverPolicy(Mode: 'sequential'); + $f = new ServiceResolverFailover( + Service: 'web', + ServiceSubset: 'v1', + Namespace: 'ns', + Datacenters: ['dc2'], + Targets: [$target], + Policy: $policy, + SamenessGroup: 'sg', + ); + self::assertSame('web', $f->getService()); + self::assertSame('v1', $f->getServiceSubset()); + self::assertSame('ns', $f->getNamespace()); + self::assertSame(['dc2'], $f->getDatacenters()); + self::assertCount(1, $f->getTargets()); + self::assertSame($policy, $f->getPolicy()); + self::assertSame('sg', $f->getSamenessGroup()); + } + + public function testFluentSetters(): void + { + $f = new ServiceResolverFailover(); + $result = $f->setService('web') + ->setServiceSubset('v1') + ->setNamespace('ns') + ->setDatacenters('dc1', 'dc2') + ->setSamenessGroup('sg'); + self::assertSame($f, $result); + self::assertSame('web', $f->getService()); + self::assertSame('v1', $f->getServiceSubset()); + self::assertSame('ns', $f->getNamespace()); + self::assertSame(['dc1', 'dc2'], $f->getDatacenters()); + self::assertSame('sg', $f->getSamenessGroup()); + } + +} diff --git a/tests/Unit/ConfigEntry/ServiceResolverPrioritizeByLocalityTest.php b/tests/Unit/ConfigEntry/ServiceResolverPrioritizeByLocalityTest.php new file mode 100644 index 00000000..9d1f443c --- /dev/null +++ b/tests/Unit/ConfigEntry/ServiceResolverPrioritizeByLocalityTest.php @@ -0,0 +1,34 @@ +getMode()); + } + + public function testConstructorWithParams(): void + { + $p = new ServiceResolverPrioritizeByLocality(Mode: 'failover'); + self::assertSame('failover', $p->getMode()); + } + + public function testFluentSetters(): void + { + $p = new ServiceResolverPrioritizeByLocality(); + $result = $p->setMode('none'); + self::assertSame($p, $result); + self::assertSame('none', $p->getMode()); + } + +} diff --git a/tests/Unit/ConfigEntry/ServiceResolverRedirectTest.php b/tests/Unit/ConfigEntry/ServiceResolverRedirectTest.php new file mode 100644 index 00000000..84263ce4 --- /dev/null +++ b/tests/Unit/ConfigEntry/ServiceResolverRedirectTest.php @@ -0,0 +1,66 @@ +getService()); + self::assertSame('', $r->getServiceSubset()); + self::assertSame('', $r->getNamespace()); + self::assertSame('', $r->getPartition()); + self::assertSame('', $r->getDatacenter()); + self::assertSame('', $r->getPeer()); + self::assertSame('', $r->getSamenessGroup()); + } + + public function testConstructorWithParams(): void + { + $r = new ServiceResolverRedirect( + Service: 'web-v2', + ServiceSubset: 'v2', + Namespace: 'ns', + Partition: 'pt', + Datacenter: 'dc2', + Peer: 'peer1', + SamenessGroup: 'sg', + ); + self::assertSame('web-v2', $r->getService()); + self::assertSame('v2', $r->getServiceSubset()); + self::assertSame('ns', $r->getNamespace()); + self::assertSame('pt', $r->getPartition()); + self::assertSame('dc2', $r->getDatacenter()); + self::assertSame('peer1', $r->getPeer()); + self::assertSame('sg', $r->getSamenessGroup()); + } + + public function testFluentSetters(): void + { + $r = new ServiceResolverRedirect(); + $result = $r->setService('web') + ->setServiceSubset('v1') + ->setNamespace('ns') + ->setPartition('pt') + ->setDatacenter('dc1') + ->setPeer('p1') + ->setSamenessGroup('sg'); + self::assertSame($r, $result); + self::assertSame('web', $r->getService()); + self::assertSame('v1', $r->getServiceSubset()); + self::assertSame('ns', $r->getNamespace()); + self::assertSame('pt', $r->getPartition()); + self::assertSame('dc1', $r->getDatacenter()); + self::assertSame('p1', $r->getPeer()); + self::assertSame('sg', $r->getSamenessGroup()); + } + +} diff --git a/tests/Unit/ConfigEntry/ServiceResolverSubsetTest.php b/tests/Unit/ConfigEntry/ServiceResolverSubsetTest.php new file mode 100644 index 00000000..865cbcca --- /dev/null +++ b/tests/Unit/ConfigEntry/ServiceResolverSubsetTest.php @@ -0,0 +1,38 @@ +getFilter()); + self::assertFalse($s->isOnlyPassing()); + } + + public function testConstructorWithParams(): void + { + $s = new ServiceResolverSubset(Filter: 'Service.Meta.version == v1', OnlyPassing: true); + self::assertSame('Service.Meta.version == v1', $s->getFilter()); + self::assertTrue($s->isOnlyPassing()); + } + + public function testFluentSetters(): void + { + $s = new ServiceResolverSubset(); + $result = $s->setFilter('filter') + ->setOnlyPassing(true); + self::assertSame($s, $result); + self::assertSame('filter', $s->getFilter()); + self::assertTrue($s->isOnlyPassing()); + } + +} diff --git a/tests/Unit/ConfigEntry/ServiceRouteDestinationTest.php b/tests/Unit/ConfigEntry/ServiceRouteDestinationTest.php new file mode 100644 index 00000000..83667ddf --- /dev/null +++ b/tests/Unit/ConfigEntry/ServiceRouteDestinationTest.php @@ -0,0 +1,70 @@ +getService()); + self::assertSame('', $d->getServiceSubset()); + self::assertSame('', $d->getNamespace()); + self::assertSame('', $d->getPrefixRewrite()); + self::assertSame(0, $d->getNumRetries()); + self::assertFalse($d->isRetryOnConnectFailure()); + self::assertSame([], $d->getRetryOnStatusCodes()); + self::assertSame([], $d->getRetryOn()); + } + + public function testConstructorWithParams(): void + { + $d = new ServiceRouteDestination( + Service: 'web-v2', + ServiceSubset: 'v2', + Namespace: 'ns', + PrefixRewrite: '/v2', + NumRetries: 3, + RetryOnConnectFailure: true, + RetryOnStatusCodes: [503, 504], + RetryOn: ['5xx'], + ); + self::assertSame('web-v2', $d->getService()); + self::assertSame('v2', $d->getServiceSubset()); + self::assertSame('ns', $d->getNamespace()); + self::assertSame('/v2', $d->getPrefixRewrite()); + self::assertSame(3, $d->getNumRetries()); + self::assertTrue($d->isRetryOnConnectFailure()); + self::assertSame([503, 504], $d->getRetryOnStatusCodes()); + self::assertSame(['5xx'], $d->getRetryOn()); + } + + public function testFluentSetters(): void + { + $d = new ServiceRouteDestination(); + $result = $d->setService('web') + ->setServiceSubset('v1') + ->setNamespace('ns') + ->setPrefixRewrite('/v1') + ->setNumRetries(2) + ->setRetryOnConnectFailure(true) + ->setRetryOnStatusCodes(502, 503) + ->setRetryOn('5xx'); + self::assertSame($d, $result); + self::assertSame('web', $d->getService()); + self::assertSame('v1', $d->getServiceSubset()); + self::assertSame('/v1', $d->getPrefixRewrite()); + self::assertSame(2, $d->getNumRetries()); + self::assertTrue($d->isRetryOnConnectFailure()); + self::assertSame([502, 503], $d->getRetryOnStatusCodes()); + self::assertSame(['5xx'], $d->getRetryOn()); + } + +} diff --git a/tests/Unit/ConfigEntry/ServiceRouteHTTPMatchHeaderTest.php b/tests/Unit/ConfigEntry/ServiceRouteHTTPMatchHeaderTest.php new file mode 100644 index 00000000..9f45e73e --- /dev/null +++ b/tests/Unit/ConfigEntry/ServiceRouteHTTPMatchHeaderTest.php @@ -0,0 +1,59 @@ +getName()); + self::assertFalse($h->isPresent()); + self::assertSame('', $h->getExact()); + self::assertSame('', $h->getPrefix()); + self::assertSame('', $h->getSuffix()); + self::assertSame('', $h->getRegex()); + } + + public function testConstructorWithParams(): void + { + $h = new ServiceRouteHTTPMatchHeader( + Name: 'x-version', + Present: true, + Exact: 'v2', + Prefix: 'pre', + Suffix: 'suf', + Regex: '.*', + Invert: true, + ); + self::assertSame('x-version', $h->getName()); + self::assertTrue($h->isPresent()); + self::assertSame('v2', $h->getExact()); + self::assertSame('pre', $h->getPrefix()); + self::assertSame('suf', $h->getSuffix()); + self::assertSame('.*', $h->getRegex()); + } + + public function testFluentSetters(): void + { + $h = new ServiceRouteHTTPMatchHeader(); + $result = $h->setName('x-test') + ->setPresent(true) + ->setExact('val') + ->setPrefix('p') + ->setSuffix('s') + ->setRegex('r'); + self::assertSame($h, $result); + self::assertSame('x-test', $h->getName()); + self::assertTrue($h->isPresent()); + self::assertSame('val', $h->getExact()); + } + +} diff --git a/tests/Unit/ConfigEntry/ServiceRouteHTTPMatchQueryParamTest.php b/tests/Unit/ConfigEntry/ServiceRouteHTTPMatchQueryParamTest.php new file mode 100644 index 00000000..ec364d0c --- /dev/null +++ b/tests/Unit/ConfigEntry/ServiceRouteHTTPMatchQueryParamTest.php @@ -0,0 +1,51 @@ +getName()); + self::assertFalse($q->isPresent()); + self::assertSame('', $q->getExact()); + self::assertSame('', $q->getRegex()); + } + + public function testConstructorWithParams(): void + { + $q = new ServiceRouteHTTPMatchQueryParam( + Name: 'env', + Present: true, + Exact: 'prod', + Regex: '.*', + ); + self::assertSame('env', $q->getName()); + self::assertTrue($q->isPresent()); + self::assertSame('prod', $q->getExact()); + self::assertSame('.*', $q->getRegex()); + } + + public function testFluentSetters(): void + { + $q = new ServiceRouteHTTPMatchQueryParam(); + $result = $q->setName('key') + ->setPresent(true) + ->setExact('val') + ->setRegex('r'); + self::assertSame($q, $result); + self::assertSame('key', $q->getName()); + self::assertTrue($q->isPresent()); + self::assertSame('val', $q->getExact()); + self::assertSame('r', $q->getRegex()); + } + +} diff --git a/tests/Unit/ConfigEntry/ServiceRouteHTTPMatchTest.php b/tests/Unit/ConfigEntry/ServiceRouteHTTPMatchTest.php new file mode 100644 index 00000000..614cb124 --- /dev/null +++ b/tests/Unit/ConfigEntry/ServiceRouteHTTPMatchTest.php @@ -0,0 +1,57 @@ +getPathExact()); + self::assertSame('', $h->getPathPrefix()); + self::assertSame('', $h->getPathRegex()); + self::assertSame([], $h->getHeader()); + self::assertSame([], $h->getQueryParam()); + self::assertSame([], $h->getMethods()); + } + + public function testConstructorWithParams(): void + { + $header = new ServiceRouteHTTPMatchHeader(Name: 'x-version', Exact: 'v2'); + $qp = new ServiceRouteHTTPMatchQueryParam(Name: 'env', Exact: 'prod'); + $h = new ServiceRouteHTTPMatch( + PathPrefix: '/api', + Header: [$header], + QueryParam: [$qp], + Methods: ['GET', 'POST'], + ); + self::assertSame('/api', $h->getPathPrefix()); + self::assertCount(1, $h->getHeader()); + self::assertCount(1, $h->getQueryParam()); + self::assertSame(['GET', 'POST'], $h->getMethods()); + } + + public function testFluentSetters(): void + { + $h = new ServiceRouteHTTPMatch(); + $result = $h->setPathExact('/exact') + ->setPathPrefix('/prefix') + ->setPathRegex('/re.*') + ->setMethods('GET'); + self::assertSame($h, $result); + self::assertSame('/exact', $h->getPathExact()); + self::assertSame('/prefix', $h->getPathPrefix()); + self::assertSame('/re.*', $h->getPathRegex()); + self::assertSame(['GET'], $h->getMethods()); + } + +} diff --git a/tests/Unit/ConfigEntry/ServiceRouteMatchTest.php b/tests/Unit/ConfigEntry/ServiceRouteMatchTest.php new file mode 100644 index 00000000..ce00a6bb --- /dev/null +++ b/tests/Unit/ConfigEntry/ServiceRouteMatchTest.php @@ -0,0 +1,37 @@ +getHTTP()); + } + + public function testConstructorWithParams(): void + { + $http = new ServiceRouteHTTPMatch(PathPrefix: '/api'); + $m = new ServiceRouteMatch(HTTP: $http); + self::assertSame($http, $m->getHTTP()); + } + + public function testFluentSetters(): void + { + $http = new ServiceRouteHTTPMatch(PathPrefix: '/v1'); + $m = new ServiceRouteMatch(); + $result = $m->setHTTP($http); + self::assertSame($m, $result); + self::assertSame($http, $m->getHTTP()); + } + +} diff --git a/tests/Unit/ConfigEntry/ServiceRouteTest.php b/tests/Unit/ConfigEntry/ServiceRouteTest.php new file mode 100644 index 00000000..60096b42 --- /dev/null +++ b/tests/Unit/ConfigEntry/ServiceRouteTest.php @@ -0,0 +1,43 @@ +getMatch()); + self::assertNull($r->getDestination()); + } + + public function testConstructorWithParams(): void + { + $match = new ServiceRouteMatch(); + $dest = new ServiceRouteDestination(Service: 'web-v2'); + $r = new ServiceRoute(Match: $match, Destination: $dest); + self::assertSame($match, $r->getMatch()); + self::assertSame($dest, $r->getDestination()); + } + + public function testFluentSetters(): void + { + $match = new ServiceRouteMatch(); + $dest = new ServiceRouteDestination(Service: 'api'); + $r = new ServiceRoute(); + $result = $r->setMatch($match)->setDestination($dest); + self::assertSame($r, $result); + self::assertSame($match, $r->getMatch()); + self::assertSame($dest, $r->getDestination()); + } + +} diff --git a/tests/Unit/ConfigEntry/ServiceRouterConfigEntryTest.php b/tests/Unit/ConfigEntry/ServiceRouterConfigEntryTest.php new file mode 100644 index 00000000..c5126bd2 --- /dev/null +++ b/tests/Unit/ConfigEntry/ServiceRouterConfigEntryTest.php @@ -0,0 +1,55 @@ +getKind()); + self::assertSame('', $e->getName()); + self::assertSame('', $e->getPartition()); + self::assertSame([], $e->getRoutes()); + } + + public function testConstructorWithParams(): void + { + $route = new ServiceRoute(Destination: new ServiceRouteDestination(Service: 'web')); + $e = new ServiceRouterConfigEntry( + Kind: 'service-router', + Name: 'web', + Partition: 'pt', + Routes: [$route], + ); + self::assertSame('service-router', $e->getKind()); + self::assertSame('web', $e->getName()); + self::assertSame('pt', $e->getPartition()); + self::assertCount(1, $e->getRoutes()); + } + + public function testFluentSetters(): void + { + $route = new ServiceRoute(Destination: new ServiceRouteDestination(Service: 'api')); + $e = new ServiceRouterConfigEntry(); + $result = $e->setKind('service-router') + ->setName('api') + ->setPartition('pt') + ->setRoutes($route); + self::assertSame($e, $result); + self::assertSame('service-router', $e->getKind()); + self::assertSame('api', $e->getName()); + self::assertSame('pt', $e->getPartition()); + self::assertCount(1, $e->getRoutes()); + } + +} diff --git a/tests/Unit/ConfigEntry/ServiceSplitTest.php b/tests/Unit/ConfigEntry/ServiceSplitTest.php new file mode 100644 index 00000000..d5c1ffbd --- /dev/null +++ b/tests/Unit/ConfigEntry/ServiceSplitTest.php @@ -0,0 +1,58 @@ +getWeight()); + self::assertSame('', $s->getService()); + self::assertSame('', $s->getServiceSubset()); + self::assertSame('', $s->getNamespace()); + self::assertSame('', $s->getPartition()); + self::assertNull($s->getRequestHeaders()); + self::assertNull($s->getResponseHeaders()); + } + + public function testConstructorWithParams(): void + { + $s = new ServiceSplit( + Weight: 50.0, + Service: 'web-v2', + ServiceSubset: 'v2', + Namespace: 'ns', + Partition: 'pt', + ); + self::assertSame(50.0, $s->getWeight()); + self::assertSame('web-v2', $s->getService()); + self::assertSame('v2', $s->getServiceSubset()); + self::assertSame('ns', $s->getNamespace()); + self::assertSame('pt', $s->getPartition()); + } + + public function testFluentSetters(): void + { + $s = new ServiceSplit(); + $result = $s->setWeight(75.0) + ->setService('api') + ->setServiceSubset('v1') + ->setNamespace('ns') + ->setPartition('pt'); + self::assertSame($s, $result); + self::assertSame(75.0, $s->getWeight()); + self::assertSame('api', $s->getService()); + self::assertSame('v1', $s->getServiceSubset()); + self::assertSame('ns', $s->getNamespace()); + self::assertSame('pt', $s->getPartition()); + } + +} diff --git a/tests/Unit/ConfigEntry/ServiceSplitterConfigEntryTest.php b/tests/Unit/ConfigEntry/ServiceSplitterConfigEntryTest.php new file mode 100644 index 00000000..985a3384 --- /dev/null +++ b/tests/Unit/ConfigEntry/ServiceSplitterConfigEntryTest.php @@ -0,0 +1,53 @@ +getKind()); + self::assertSame('', $e->getName()); + self::assertSame('', $e->getPartition()); + self::assertSame([], $e->getSplits()); + } + + public function testConstructorWithParams(): void + { + $split = new ServiceSplit(Weight: 100.0, Service: 'web'); + $e = new ServiceSplitterConfigEntry( + Kind: 'service-splitter', + Name: 'web', + Partition: 'pt', + Splits: [$split], + ); + self::assertSame('service-splitter', $e->getKind()); + self::assertSame('web', $e->getName()); + self::assertSame('pt', $e->getPartition()); + self::assertCount(1, $e->getSplits()); + } + + public function testFluentSetters(): void + { + $split = new ServiceSplit(Weight: 100.0, Service: 'api'); + $e = new ServiceSplitterConfigEntry(); + $result = $e->setKind('service-splitter') + ->setName('api') + ->setPartition('pt') + ->setSplits($split); + self::assertSame($e, $result); + self::assertSame('service-splitter', $e->getKind()); + self::assertSame('api', $e->getName()); + self::assertCount(1, $e->getSplits()); + } + +} diff --git a/tests/Unit/ConfigEntry/SourceIntentionTest.php b/tests/Unit/ConfigEntry/SourceIntentionTest.php new file mode 100644 index 00000000..c682aa95 --- /dev/null +++ b/tests/Unit/ConfigEntry/SourceIntentionTest.php @@ -0,0 +1,87 @@ +getName()); + self::assertSame('', $s->getPeer()); + self::assertSame('', $s->getPartition()); + self::assertSame('', $s->getNamespace()); + self::assertSame('', $s->getSamenessGroup()); + self::assertSame(IntentionAction::UNDEFINED, $s->getAction()); + self::assertSame([], $s->getPermissions()); + self::assertSame(0, $s->getPrecedence()); + self::assertSame(IntentionSourceType::UNDEFINED, $s->getType()); + self::assertSame('', $s->getDescription()); + self::assertSame('', $s->getLegacyID()); + self::assertNull($s->getLegacyMeta()); + self::assertNull($s->getLegacyCreateTime()); + self::assertNull($s->getLegacyUpdateTime()); + } + + public function testConstructorWithParams(): void + { + $s = new SourceIntention( + Name: 'web', + Peer: 'peer1', + Partition: 'pt', + Namespace: 'ns', + SamenessGroup: 'sg', + Action: IntentionAction::Allow, + Precedence: 9, + Type: IntentionSourceType::Consul, + Description: 'Allow web', + ); + self::assertSame('web', $s->getName()); + self::assertSame('peer1', $s->getPeer()); + self::assertSame('pt', $s->getPartition()); + self::assertSame('ns', $s->getNamespace()); + self::assertSame('sg', $s->getSamenessGroup()); + self::assertSame(IntentionAction::Allow, $s->getAction()); + self::assertSame(9, $s->getPrecedence()); + self::assertSame(IntentionSourceType::Consul, $s->getType()); + self::assertSame('Allow web', $s->getDescription()); + } + + public function testFluentSetters(): void + { + $s = new SourceIntention(); + $result = $s->setName('api') + ->setPeer('peer2') + ->setPartition('pt') + ->setNamespace('ns') + ->setSamenessGroup('sg') + ->setAction(IntentionAction::Deny) + ->setPrecedence(5) + ->setType(IntentionSourceType::Consul) + ->setDescription('Deny api'); + self::assertSame($s, $result); + self::assertSame('api', $s->getName()); + self::assertSame('peer2', $s->getPeer()); + self::assertSame('pt', $s->getPartition()); + self::assertSame('ns', $s->getNamespace()); + self::assertSame(IntentionAction::Deny, $s->getAction()); + self::assertSame(5, $s->getPrecedence()); + self::assertSame('Deny api', $s->getDescription()); + } + + public function testConstructorWithEnumAsString(): void + { + $s = new SourceIntention(Action: 'allow', Type: 'consul'); + self::assertSame(IntentionAction::Allow, $s->getAction()); + self::assertSame(IntentionSourceType::Consul, $s->getType()); + } +} diff --git a/tests/Unit/ConfigEntry/TerminatingGatewayConfigEntryTest.php b/tests/Unit/ConfigEntry/TerminatingGatewayConfigEntryTest.php new file mode 100644 index 00000000..cdbe57ed --- /dev/null +++ b/tests/Unit/ConfigEntry/TerminatingGatewayConfigEntryTest.php @@ -0,0 +1,49 @@ +getKind()); + self::assertSame('', $e->getName()); + self::assertSame([], $e->getServices()); + } + + public function testConstructorWithParams(): void + { + $svc = new LinkedService(Name: 'external-db'); + $e = new TerminatingGatewayConfigEntry( + Kind: 'terminating-gateway', + Name: 'tgw', + Services: [$svc], + ); + self::assertSame('terminating-gateway', $e->getKind()); + self::assertSame('tgw', $e->getName()); + self::assertCount(1, $e->getServices()); + } + + public function testFluentSetters(): void + { + $svc = new LinkedService(Name: 'ext'); + $e = new TerminatingGatewayConfigEntry(); + $result = $e->setKind('terminating-gateway') + ->setName('tgw') + ->setServices($svc); + self::assertSame($e, $result); + self::assertSame('terminating-gateway', $e->getKind()); + self::assertSame('tgw', $e->getName()); + self::assertCount(1, $e->getServices()); + } + +} diff --git a/tests/Unit/ConfigEntry/TransparentProxyConfigTest.php b/tests/Unit/ConfigEntry/TransparentProxyConfigTest.php new file mode 100644 index 00000000..10f4ddfe --- /dev/null +++ b/tests/Unit/ConfigEntry/TransparentProxyConfigTest.php @@ -0,0 +1,37 @@ +getOutboundListenerPort()); + self::assertFalse($c->isDialedDirectly()); + } + + public function testConstructorWithParams(): void + { + $c = new TransparentProxyConfig(OutboundListenerPort: 15001, DialedDirectly: true); + self::assertSame(15001, $c->getOutboundListenerPort()); + self::assertTrue($c->isDialedDirectly()); + } + + public function testFluentSetters(): void + { + $c = new TransparentProxyConfig(); + $result = $c->setOutboundListenerPort(15001)->setDialedDirectly(true); + self::assertSame($c, $result); + self::assertSame(15001, $c->getOutboundListenerPort()); + self::assertTrue($c->isDialedDirectly()); + } + +} diff --git a/tests/Unit/ConfigEntry/TransparentProxyMeshConfigTest.php b/tests/Unit/ConfigEntry/TransparentProxyMeshConfigTest.php new file mode 100644 index 00000000..dbaae96b --- /dev/null +++ b/tests/Unit/ConfigEntry/TransparentProxyMeshConfigTest.php @@ -0,0 +1,34 @@ +isMeshDestinationsOnly()); + } + + public function testConstructorWithParams(): void + { + $c = new TransparentProxyMeshConfig(MeshDestinationsOnly: true); + self::assertTrue($c->isMeshDestinationsOnly()); + } + + public function testFluentSetters(): void + { + $c = new TransparentProxyMeshConfig(); + $result = $c->setMeshDestinationsOnly(true); + self::assertSame($c, $result); + self::assertTrue($c->isMeshDestinationsOnly()); + } + +} diff --git a/tests/Unit/ConfigEntry/UpstreamConfigTest.php b/tests/Unit/ConfigEntry/UpstreamConfigTest.php new file mode 100644 index 00000000..51f8d232 --- /dev/null +++ b/tests/Unit/ConfigEntry/UpstreamConfigTest.php @@ -0,0 +1,56 @@ +getName()); + self::assertSame('', $u->getPartition()); + self::assertSame('', $u->getNamespace()); + self::assertSame('', $u->getProtocol()); + self::assertSame(0, $u->getConnectTimeoutMs()); + } + + public function testConstructorWithParams(): void + { + $u = new UpstreamConfig( + Name: 'db', + Partition: 'pt', + Namespace: 'ns', + Protocol: 'tcp', + ConnectTimeoutMs: 5000, + ); + self::assertSame('db', $u->getName()); + self::assertSame('pt', $u->getPartition()); + self::assertSame('ns', $u->getNamespace()); + self::assertSame('tcp', $u->getProtocol()); + self::assertSame(5000, $u->getConnectTimeoutMs()); + } + + public function testFluentSetters(): void + { + $u = new UpstreamConfig(); + $result = $u->setName('cache') + ->setPartition('pt') + ->setNamespace('ns') + ->setProtocol('http') + ->setConnectTimeoutMs(3000); + self::assertSame($u, $result); + self::assertSame('cache', $u->getName()); + self::assertSame('pt', $u->getPartition()); + self::assertSame('ns', $u->getNamespace()); + self::assertSame('http', $u->getProtocol()); + self::assertSame(3000, $u->getConnectTimeoutMs()); + } + +} diff --git a/tests/Unit/ConfigEntry/UpstreamConfigurationTest.php b/tests/Unit/ConfigEntry/UpstreamConfigurationTest.php new file mode 100644 index 00000000..345c1854 --- /dev/null +++ b/tests/Unit/ConfigEntry/UpstreamConfigurationTest.php @@ -0,0 +1,43 @@ +getOverrides()); + self::assertNull($uc->getDefaults()); + } + + public function testConstructorWithParams(): void + { + $defaults = new UpstreamConfig(Protocol: 'http'); + $override = new UpstreamConfig(Name: 'db', Protocol: 'tcp'); + $uc = new UpstreamConfiguration( + Overrides: [$override], + Defaults: $defaults, + ); + self::assertCount(1, $uc->getOverrides()); + self::assertSame($defaults, $uc->getDefaults()); + } + + public function testFluentSetters(): void + { + $defaults = new UpstreamConfig(Protocol: 'grpc'); + $uc = new UpstreamConfiguration(); + $result = $uc->setDefaults($defaults); + self::assertSame($uc, $result); + self::assertSame($defaults, $uc->getDefaults()); + } + +} diff --git a/tests/Unit/ConfigEntry/UpstreamLimitsTest.php b/tests/Unit/ConfigEntry/UpstreamLimitsTest.php new file mode 100644 index 00000000..7ec2330d --- /dev/null +++ b/tests/Unit/ConfigEntry/UpstreamLimitsTest.php @@ -0,0 +1,46 @@ +getMaxConnections()); + self::assertNull($u->getMaxPendingRequests()); + self::assertNull($u->getMaxConcurrentRequests()); + } + + public function testConstructorWithParams(): void + { + $u = new UpstreamLimits( + MaxConnections: 100, + MaxPendingRequests: 50, + MaxConcurrentRequests: 25, + ); + self::assertSame(100, $u->getMaxConnections()); + self::assertSame(50, $u->getMaxPendingRequests()); + self::assertSame(25, $u->getMaxConcurrentRequests()); + } + + public function testFluentSetters(): void + { + $u = new UpstreamLimits(); + $result = $u->setMaxConnections(200) + ->setMaxPendingRequests(100) + ->setMaxConcurrentRequests(50); + self::assertSame($u, $result); + self::assertSame(200, $u->getMaxConnections()); + self::assertSame(100, $u->getMaxPendingRequests()); + self::assertSame(50, $u->getMaxConcurrentRequests()); + } + +} diff --git a/tests/Unit/Coordinate/CoordinateConfigTest.php b/tests/Unit/Coordinate/CoordinateConfigTest.php new file mode 100644 index 00000000..2607aa7c --- /dev/null +++ b/tests/Unit/Coordinate/CoordinateConfigTest.php @@ -0,0 +1,121 @@ +getDimensionality()); + self::assertSame(CoordinateConfig::DefaultVivaldiErrorMax, $c->getVivaldiErrorMax()); + self::assertSame(CoordinateConfig::DefaultVivaldiCE, $c->getVivaldiCE()); + self::assertSame(CoordinateConfig::DefaultVivaldiCC, $c->getVivaldiCC()); + self::assertSame(CoordinateConfig::DefaultAdjustmentWindowSize, $c->getAdjustmentWindowSize()); + self::assertSame(CoordinateConfig::DefaultHeightMin, $c->getHeightMin()); + self::assertSame(CoordinateConfig::DefaultLatencyFilterSize, $c->getLatencyFilterSize()); + self::assertSame(CoordinateConfig::DefaultGravityRho, $c->getGravityRho()); + self::assertSame([], $c->getMetricsLabels()); + } + + public function testConstructorWithValues(): void + { + $label = new Label(Name: 'env', Value: 'test'); + $c = new CoordinateConfig( + Dimensionality: 4, + VivaldiErrorMax: 2.0, + VivaldiCE: 0.5, + VivaldiCC: 0.5, + AdjustmentWindowSize: 10, + HeightMin: 1.0e-5, + LatencyFilterSize: 5, + GravityRho: 100.0, + MetricsLabels: [$label], + ); + self::assertSame(4, $c->getDimensionality()); + self::assertSame(2.0, $c->getVivaldiErrorMax()); + self::assertSame(0.5, $c->getVivaldiCE()); + self::assertSame(0.5, $c->getVivaldiCC()); + self::assertSame(10, $c->getAdjustmentWindowSize()); + self::assertSame(1.0e-5, $c->getHeightMin()); + self::assertSame(5, $c->getLatencyFilterSize()); + self::assertSame(100.0, $c->getGravityRho()); + self::assertCount(1, $c->getMetricsLabels()); + self::assertSame('env', $c->getMetricsLabels()[0]->getName()); + } + + public function testFluentSetters(): void + { + $c = new CoordinateConfig(); + $result = $c + ->setDimensionality(3) + ->setVivaldiErrorMax(1.0) + ->setVivaldiCE(0.1) + ->setVivaldiCC(0.2) + ->setAdjustmentWindowSize(15) + ->setHeightMin(5.0e-6) + ->setLatencyFilterSize(2) + ->setGravityRho(50.0) + ->setMetricsLabels(new Label(Name: 'k', Value: 'v')); + self::assertSame($c, $result); + self::assertSame(3, $c->getDimensionality()); + self::assertCount(1, $c->getMetricsLabels()); + } + + public function testDeprecatedDefault(): void + { + $c = CoordinateConfig::Default(); + self::assertSame(CoordinateConfig::DefaultDimensionality, $c->getDimensionality()); + } + + public function testJsonSerialize(): void + { + $c = new CoordinateConfig(Dimensionality: 4); + $out = $c->jsonSerialize(); + self::assertInstanceOf(\stdClass::class, $out); + self::assertSame(4, $out->Dimensionality); + } + + public function testJsonUnserialize(): void + { + $labelObj = new \stdClass(); + $labelObj->Name = 'test'; + $labelObj->Value = 'val'; + + $decoded = new \stdClass(); + $decoded->Dimensionality = 6; + $decoded->VivaldiErrorMax = 1.0; + $decoded->VivaldiCE = 0.3; + $decoded->VivaldiCC = 0.4; + $decoded->AdjustmentWindowSize = 25; + $decoded->HeightMin = 2.0e-6; + $decoded->LatencyFilterSize = 4; + $decoded->GravityRho = 200.0; + $decoded->MetricsLabels = [$labelObj]; + + $c = CoordinateConfig::jsonUnserialize($decoded); + self::assertSame(6, $c->getDimensionality()); + self::assertSame(1.0, $c->getVivaldiErrorMax()); + self::assertCount(1, $c->getMetricsLabels()); + self::assertInstanceOf(Label::class, $c->getMetricsLabels()[0]); + self::assertSame('test', $c->getMetricsLabels()[0]->getName()); + } + + public function testJsonRoundTrip(): void + { + $original = new CoordinateConfig(Dimensionality: 5, VivaldiErrorMax: 2.5); + $restored = CoordinateConfig::jsonUnserialize($original->jsonSerialize()); + self::assertSame($original->getDimensionality(), $restored->getDimensionality()); + self::assertSame($original->getVivaldiErrorMax(), $restored->getVivaldiErrorMax()); + } +} + diff --git a/tests/Unit/Coordinate/CoordinateDatacenterMapTest.php b/tests/Unit/Coordinate/CoordinateDatacenterMapTest.php new file mode 100644 index 00000000..e299b161 --- /dev/null +++ b/tests/Unit/Coordinate/CoordinateDatacenterMapTest.php @@ -0,0 +1,91 @@ +getDatacenter()); + self::assertSame('', $m->getAreaID()); + self::assertSame([], $m->getCoordinates()); + } + + public function testConstructorWithValues(): void + { + $entry = new CoordinateEntry(Node: 'n1', Coord: new Coordinate(Vec: [1.0])); + $m = new CoordinateDatacenterMap(Datacenter: 'dc1', AreaID: 'area-1', Coordinates: [$entry]); + self::assertSame('dc1', $m->getDatacenter()); + self::assertSame('area-1', $m->getAreaID()); + self::assertCount(1, $m->getCoordinates()); + self::assertSame('n1', $m->getCoordinates()[0]->getNode()); + } + + public function testFluentSetters(): void + { + $m = new CoordinateDatacenterMap(); + $result = $m + ->setDatacenter('dc2') + ->setAreaID('a2') + ->setCoordinates(new CoordinateEntry(Node: 'n')); + self::assertSame($m, $result); + self::assertSame('dc2', $m->getDatacenter()); + self::assertSame('a2', $m->getAreaID()); + self::assertCount(1, $m->getCoordinates()); + } + + public function testJsonSerialize(): void + { + $m = new CoordinateDatacenterMap(Datacenter: 'dc1', AreaID: 'area'); + $out = $m->jsonSerialize(); + self::assertInstanceOf(\stdClass::class, $out); + self::assertSame('dc1', $out->Datacenter); + self::assertSame('area', $out->AreaID); + } + + public function testJsonUnserialize(): void + { + $coordObj = new \stdClass(); + $coordObj->Vec = [0.5]; + $coordObj->Error = 0.0; + $coordObj->Adjustment = 0.0; + $coordObj->Height = 0.0; + + $entryObj = new \stdClass(); + $entryObj->Node = 'json-n'; + $entryObj->Segment = ''; + $entryObj->Coord = $coordObj; + + $decoded = new \stdClass(); + $decoded->Datacenter = 'dc-json'; + $decoded->AreaID = 'area-json'; + $decoded->Coordinates = [$entryObj]; + + $m = CoordinateDatacenterMap::jsonUnserialize($decoded); + self::assertSame('dc-json', $m->getDatacenter()); + self::assertSame('area-json', $m->getAreaID()); + self::assertCount(1, $m->getCoordinates()); + self::assertInstanceOf(CoordinateEntry::class, $m->getCoordinates()[0]); + self::assertSame('json-n', $m->getCoordinates()[0]->getNode()); + } + + public function testJsonRoundTrip(): void + { + $original = new CoordinateDatacenterMap(Datacenter: 'dc1', AreaID: 'a1'); + $restored = CoordinateDatacenterMap::jsonUnserialize($original->jsonSerialize()); + self::assertSame($original->getDatacenter(), $restored->getDatacenter()); + self::assertSame($original->getAreaID(), $restored->getAreaID()); + } +} + diff --git a/tests/Unit/Coordinate/CoordinateEntryTest.php b/tests/Unit/Coordinate/CoordinateEntryTest.php new file mode 100644 index 00000000..2a3c41b1 --- /dev/null +++ b/tests/Unit/Coordinate/CoordinateEntryTest.php @@ -0,0 +1,98 @@ +getNode()); + self::assertSame('', $e->getSegment()); + self::assertSame('', $e->getPartition()); + self::assertNull($e->getCoord()); + } + + public function testConstructorWithValues(): void + { + $coord = new Coordinate(Vec: [1.0, 2.0], Error: 0.1); + $e = new CoordinateEntry(Node: 'node-1', Segment: 'seg', Partition: 'part', Coord: $coord); + self::assertSame('node-1', $e->getNode()); + self::assertSame('seg', $e->getSegment()); + self::assertSame('part', $e->getPartition()); + self::assertNotNull($e->getCoord()); + self::assertSame([1.0, 2.0], $e->getCoord()->getVec()); + } + + public function testFluentSetters(): void + { + $e = new CoordinateEntry(); + $coord = new Coordinate(Vec: [0.5]); + $result = $e->setNode('n')->setSegment('s')->setPartition('p')->setCoord($coord); + self::assertSame($e, $result); + self::assertSame('n', $e->getNode()); + self::assertSame('s', $e->getSegment()); + self::assertSame('p', $e->getPartition()); + self::assertNotNull($e->getCoord()); + } + + public function testJsonSerialize(): void + { + $e = new CoordinateEntry(Node: 'n1', Segment: 's1', Coord: new Coordinate(Vec: [1.0])); + $out = $e->jsonSerialize(); + self::assertInstanceOf(\stdClass::class, $out); + self::assertSame('n1', $out->Node); + self::assertSame('s1', $out->Segment); + self::assertObjectNotHasProperty('Partition', $out); + } + + public function testJsonSerializeIncludesNonEmptyPartition(): void + { + $e = new CoordinateEntry(Node: 'n1', Partition: 'p1'); + $out = $e->jsonSerialize(); + self::assertSame('p1', $out->Partition); + } + + public function testJsonUnserialize(): void + { + $coordObj = new \stdClass(); + $coordObj->Vec = [1.5, 2.5]; + $coordObj->Error = 0.3; + $coordObj->Adjustment = 0.0; + $coordObj->Height = 0.0; + + $decoded = new \stdClass(); + $decoded->Node = 'json-node'; + $decoded->Segment = 'json-seg'; + $decoded->Partition = ''; + $decoded->Coord = $coordObj; + + $e = CoordinateEntry::jsonUnserialize($decoded); + self::assertSame('json-node', $e->getNode()); + self::assertSame('json-seg', $e->getSegment()); + self::assertNotNull($e->getCoord()); + self::assertSame([1.5, 2.5], $e->getCoord()->getVec()); + } + + public function testJsonRoundTrip(): void + { + $original = new CoordinateEntry(Node: 'rt', Segment: 's', Coord: new Coordinate(Vec: [0.1, 0.2])); + $json = json_encode($original); + $decoded = json_decode($json, false); + $restored = CoordinateEntry::jsonUnserialize($decoded); + self::assertSame($original->getNode(), $restored->getNode()); + self::assertSame($original->getSegment(), $restored->getSegment()); + self::assertNotNull($restored->getCoord()); + self::assertSame($original->getCoord()->getVec(), $restored->getCoord()->getVec()); + } +} + diff --git a/tests/Unit/Coordinate/CoordinateTest.php b/tests/Unit/Coordinate/CoordinateTest.php new file mode 100644 index 00000000..2ddf142b --- /dev/null +++ b/tests/Unit/Coordinate/CoordinateTest.php @@ -0,0 +1,156 @@ +getVec()); + self::assertSame(0.0, $c->getError()); + self::assertSame(0.0, $c->getAdjustment()); + self::assertSame(0.0, $c->getHeight()); + } + + public function testConstructorWithValues(): void + { + $c = new Coordinate(Vec: [1.0, 2.0, 3.0], Error: 0.5, Adjustment: 0.1, Height: 0.01); + self::assertSame([1.0, 2.0, 3.0], $c->getVec()); + self::assertSame(0.5, $c->getError()); + self::assertSame(0.1, $c->getAdjustment()); + self::assertSame(0.01, $c->getHeight()); + } + + public function testConstructorWithConfig(): void + { + $config = new CoordinateConfig(Dimensionality: 4); + $c = new Coordinate(config: $config); + self::assertCount(4, $c->getVec()); + self::assertSame([0.0, 0.0, 0.0, 0.0], $c->getVec()); + self::assertSame($config->VivaldiErrorMax, $c->getError()); + self::assertSame(0.0, $c->getAdjustment()); + self::assertSame($config->HeightMin, $c->getHeight()); + } + + public function testFluentSetters(): void + { + $c = new Coordinate(); + $result = $c->setVec(1.0, 2.0)->setError(0.3)->setAdjustment(0.05)->setHeight(0.001); + self::assertSame($c, $result); + self::assertSame([1.0, 2.0], $c->getVec()); + self::assertSame(0.3, $c->getError()); + self::assertSame(0.05, $c->getAdjustment()); + self::assertSame(0.001, $c->getHeight()); + } + + public function testClone(): void + { + $c = new Coordinate(Vec: [1.0, 2.0], Error: 0.1); + $clone = $c->Clone(); + self::assertNotSame($c, $clone); + self::assertSame($c->getVec(), $clone->getVec()); + self::assertSame($c->getError(), $clone->getError()); + } + + public function testIsValid(): void + { + $c = new Coordinate(Vec: [1.0, 2.0], Error: 0.1, Adjustment: 0.0, Height: 0.01); + self::assertTrue($c->IsValid()); + + $invalid = new Coordinate(Vec: [NAN], Error: 0.1, Adjustment: 0.0, Height: 0.01); + self::assertFalse($invalid->IsValid()); + + $infinite = new Coordinate(Vec: [1.0], Error: INF, Adjustment: 0.0, Height: 0.01); + self::assertFalse($infinite->IsValid()); + } + + public function testIsCompatibleWith(): void + { + $a = new Coordinate(Vec: [1.0, 2.0]); + $b = new Coordinate(Vec: [3.0, 4.0]); + self::assertTrue($a->IsCompatibleWith($b)); + + $c = new Coordinate(Vec: [1.0, 2.0, 3.0]); + self::assertFalse($a->IsCompatibleWith($c)); + } + + public function testDistanceTo(): void + { + $a = new Coordinate(Vec: [0.0, 0.0], Error: 0.0, Adjustment: 0.0, Height: 0.0); + $b = new Coordinate(Vec: [3.0, 4.0], Error: 0.0, Adjustment: 0.0, Height: 0.0); + $dist = $a->DistanceTo($b); + self::assertGreaterThan(0, $dist->Nanoseconds()); + } + + public function testStaticAdd(): void + { + $result = Coordinate::_add([1.0, 2.0], [3.0, 4.0]); + self::assertSame([4.0, 6.0], $result); + } + + public function testStaticDiff(): void + { + $result = Coordinate::_diff([5.0, 7.0], [2.0, 3.0]); + self::assertSame([3.0, 4.0], $result); + } + + public function testStaticMagnitude(): void + { + $mag = Coordinate::_magnitude([3.0, 4.0]); + self::assertEqualsWithDelta(5.0, $mag, 1e-10); + } + + public function testStaticUnitVectorAt(): void + { + $result = Coordinate::_unitVectorAt([5.0, 0.0], [0.0, 0.0]); + self::assertEqualsWithDelta(1.0, $result->vec[0], 1e-10); + self::assertEqualsWithDelta(0.0, $result->vec[1], 1e-10); + self::assertEqualsWithDelta(5.0, $result->mag, 1e-10); + } + + public function testJsonSerialize(): void + { + $c = new Coordinate(Vec: [1.0, 2.0], Error: 0.5, Adjustment: 0.1, Height: 0.01); + $out = $c->jsonSerialize(); + self::assertInstanceOf(\stdClass::class, $out); + self::assertSame([1.0, 2.0], $out->Vec); + self::assertSame(0.5, $out->Error); + self::assertSame(0.1, $out->Adjustment); + self::assertSame(0.01, $out->Height); + } + + public function testJsonUnserialize(): void + { + $decoded = new \stdClass(); + $decoded->Vec = [1.5, 2.5]; + $decoded->Error = 0.3; + $decoded->Adjustment = 0.05; + $decoded->Height = 0.001; + $c = Coordinate::jsonUnserialize($decoded); + self::assertSame([1.5, 2.5], $c->getVec()); + self::assertSame(0.3, $c->getError()); + self::assertSame(0.05, $c->getAdjustment()); + self::assertSame(0.001, $c->getHeight()); + } + + public function testJsonRoundTrip(): void + { + $original = new Coordinate(Vec: [1.0, 2.0, 3.0], Error: 0.4, Adjustment: 0.02, Height: 0.003); + $restored = Coordinate::jsonUnserialize($original->jsonSerialize()); + self::assertSame($original->getVec(), $restored->getVec()); + self::assertSame($original->getError(), $restored->getError()); + self::assertSame($original->getAdjustment(), $restored->getAdjustment()); + self::assertSame($original->getHeight(), $restored->getHeight()); + } +} + diff --git a/tests/Unit/Event/UserEventTest.php b/tests/Unit/Event/UserEventTest.php new file mode 100644 index 00000000..8b510d2b --- /dev/null +++ b/tests/Unit/Event/UserEventTest.php @@ -0,0 +1,114 @@ +getID()); + self::assertSame('', $e->getName()); + self::assertSame('', $e->getPayload()); + self::assertSame('', $e->getNodeFilter()); + self::assertSame('', $e->getServiceFilter()); + self::assertSame('', $e->getTagFilter()); + self::assertSame(0, $e->getVersion()); + self::assertSame(0, $e->getLTime()); + } + + public function testConstructorWithValues(): void + { + $e = new UserEvent( + ID: 'evt-1', + Name: 'deploy', + Payload: 'data', + NodeFilter: 'web-*', + ServiceFilter: 'api', + TagFilter: 'v1', + Version: 3, + LTime: 42, + ); + self::assertSame('evt-1', $e->getID()); + self::assertSame('deploy', $e->getName()); + self::assertSame('data', $e->getPayload()); + self::assertSame('web-*', $e->getNodeFilter()); + self::assertSame('api', $e->getServiceFilter()); + self::assertSame('v1', $e->getTagFilter()); + self::assertSame(3, $e->getVersion()); + self::assertSame(42, $e->getLTime()); + } + + public function testFluentSetters(): void + { + $e = new UserEvent(); + $result = $e + ->setID('id') + ->setName('name') + ->setPayload('payload') + ->setNodeFilter('nf') + ->setServiceFilter('sf') + ->setTagFilter('tf') + ->setVersion(1) + ->setLTime(2); + self::assertSame($e, $result); + self::assertSame('id', $e->getID()); + self::assertSame('name', $e->getName()); + self::assertSame('payload', $e->getPayload()); + self::assertSame('nf', $e->getNodeFilter()); + self::assertSame('sf', $e->getServiceFilter()); + self::assertSame('tf', $e->getTagFilter()); + self::assertSame(1, $e->getVersion()); + self::assertSame(2, $e->getLTime()); + } + + public function testJsonSerialize(): void + { + $e = new UserEvent(ID: 'x', Name: 'test', Version: 5, LTime: 10); + $out = $e->jsonSerialize(); + self::assertInstanceOf(\stdClass::class, $out); + self::assertSame('x', $out->ID); + self::assertSame('test', $out->Name); + self::assertSame(5, $out->Version); + self::assertSame(10, $out->LTime); + } + + public function testJsonUnserialize(): void + { + $decoded = new \stdClass(); + $decoded->ID = 'e1'; + $decoded->Name = 'ev'; + $decoded->Payload = 'p'; + $decoded->NodeFilter = ''; + $decoded->ServiceFilter = ''; + $decoded->TagFilter = ''; + $decoded->Version = 2; + $decoded->LTime = 7; + $e = UserEvent::jsonUnserialize($decoded); + self::assertSame('e1', $e->getID()); + self::assertSame('ev', $e->getName()); + self::assertSame('p', $e->getPayload()); + self::assertSame(2, $e->getVersion()); + self::assertSame(7, $e->getLTime()); + } + + public function testJsonRoundTrip(): void + { + $original = new UserEvent(ID: 'rt', Name: 'round', Payload: 'trip', Version: 1, LTime: 3); + $restored = UserEvent::jsonUnserialize($original->jsonSerialize()); + self::assertSame($original->getID(), $restored->getID()); + self::assertSame($original->getName(), $restored->getName()); + self::assertSame($original->getPayload(), $restored->getPayload()); + self::assertSame($original->getVersion(), $restored->getVersion()); + self::assertSame($original->getLTime(), $restored->getLTime()); + } +} + diff --git a/tests/Unit/Health/HealthCheckDefinitionTest.php b/tests/Unit/Health/HealthCheckDefinitionTest.php new file mode 100644 index 00000000..872de0c2 --- /dev/null +++ b/tests/Unit/Health/HealthCheckDefinitionTest.php @@ -0,0 +1,70 @@ +getHTTP()); + self::assertSame('', $d->getMethod()); + self::assertSame('', $d->getBody()); + self::assertFalse($d->isTLSSkipVerify()); + self::assertSame('', $d->getTCP()); + self::assertFalse($d->isTCPUseTLS()); + self::assertSame('', $d->getUDP()); + self::assertSame('', $d->getGRPC()); + self::assertSame('', $d->getOSService()); + self::assertFalse($d->isGRPCUseTLS()); + } + + public function testConstructorWithValues(): void + { + $d = new HealthCheckDefinition( + HTTP: 'http://localhost:8080/health', + Method: 'GET', + TLSSkipVerify: true, + IntervalDuration: '10s', + TimeoutDuration: '5s', + ); + self::assertSame('http://localhost:8080/health', $d->getHTTP()); + self::assertSame('GET', $d->getMethod()); + self::assertTrue($d->isTLSSkipVerify()); + } + + public function testFluentSetters(): void + { + $d = new HealthCheckDefinition(); + $result = $d + ->setHTTP('http://test') + ->setMethod('POST') + ->setBody('body') + ->setTLSSkipVerify(true) + ->setTCP('localhost:8080') + ->setTCPUseTLS(true) + ->setUDP('localhost:53') + ->setGRPC('localhost:50051') + ->setOSService('svc') + ->setGRPCUseTLS(true); + self::assertSame($d, $result); + } + + public function testJsonSerialize(): void + { + $d = new HealthCheckDefinition(HTTP: 'http://test', Method: 'GET'); + $out = $d->jsonSerialize(); + self::assertInstanceOf(\stdClass::class, $out); + self::assertSame('http://test', $out->HTTP); + self::assertSame('GET', $out->Method); + } +} + diff --git a/tests/Unit/Health/HealthCheckTest.php b/tests/Unit/Health/HealthCheckTest.php new file mode 100644 index 00000000..7dc02b0e --- /dev/null +++ b/tests/Unit/Health/HealthCheckTest.php @@ -0,0 +1,133 @@ +getNode()); + self::assertSame('', $hc->getCheckID()); + self::assertSame('', $hc->getName()); + self::assertSame('', $hc->getStatus()); + self::assertSame('', $hc->getNotes()); + self::assertSame('', $hc->getOutput()); + self::assertSame('', $hc->getServiceID()); + self::assertSame('', $hc->getServiceName()); + self::assertSame([], $hc->getServiceTags()); + self::assertSame('', $hc->getType()); + self::assertSame('', $hc->getNamespace()); + self::assertSame('', $hc->getPartition()); + self::assertSame(0, $hc->getExposedPort()); + self::assertSame(0, $hc->getCreateIndex()); + self::assertSame(0, $hc->getModifyIndex()); + } + + public function testConstructorWithValues(): void + { + $hc = new HealthCheck( + Node: 'node-1', + CheckID: 'check-1', + Name: 'my-check', + Status: 'passing', + ServiceID: 'svc-1', + ServiceName: 'web', + ServiceTags: ['v1'], + CreateIndex: 5, + ModifyIndex: 10, + ); + self::assertSame('node-1', $hc->getNode()); + self::assertSame('check-1', $hc->getCheckID()); + self::assertSame('my-check', $hc->getName()); + self::assertSame('passing', $hc->getStatus()); + self::assertSame('svc-1', $hc->getServiceID()); + self::assertSame(['v1'], $hc->getServiceTags()); + } + + public function testFluentSetters(): void + { + $hc = new HealthCheck(); + $result = $hc + ->setNode('n') + ->setCheckID('c') + ->setName('name') + ->setStatus('critical') + ->setNotes('notes') + ->setOutput('output') + ->setServiceID('si') + ->setServiceName('sn') + ->setServiceTags('t1', 't2') + ->setType('tcp') + ->setNamespace('ns') + ->setPartition('pt') + ->setExposedPort(8080) + ->setCreateIndex(1) + ->setModifyIndex(2); + self::assertSame($hc, $result); + self::assertSame('n', $hc->getNode()); + self::assertSame(['t1', 't2'], $hc->getServiceTags()); + } + + public function testJsonSerialize(): void + { + $hc = new HealthCheck(Node: 'n', CheckID: 'c', Status: 'passing'); + $out = $hc->jsonSerialize(); + self::assertInstanceOf(\stdClass::class, $out); + self::assertSame('n', $out->Node); + self::assertSame('passing', $out->Status); + } + + public function testJsonUnserialize(): void + { + $defObj = new \stdClass(); + $defObj->HTTP = ''; + $defObj->Method = ''; + $defObj->Body = ''; + $defObj->TLSSkipVerify = false; + $defObj->TCP = ''; + $defObj->TCPUseTLS = false; + $defObj->UDP = ''; + $defObj->GRPC = ''; + $defObj->OSService = ''; + $defObj->GRPCUseTLS = false; + $defObj->IntervalDuration = 0; + $defObj->TimeoutDuration = 0; + $defObj->DeregisterCriticalServiceAfterDuration = 0; + + $decoded = new \stdClass(); + $decoded->Node = 'json-node'; + $decoded->CheckID = 'json-check'; + $decoded->Name = 'json-name'; + $decoded->Status = 'critical'; + $decoded->Notes = ''; + $decoded->Output = ''; + $decoded->ServiceID = ''; + $decoded->ServiceName = ''; + $decoded->ServiceTags = []; + $decoded->Type = ''; + $decoded->Namespace = ''; + $decoded->Partition = ''; + $decoded->ExposedPort = 0; + $decoded->PeerName = ''; + $decoded->Definition = $defObj; + $decoded->CreateIndex = 5; + $decoded->ModifyIndex = 10; + + $hc = HealthCheck::jsonUnserialize($decoded); + self::assertSame('json-node', $hc->getNode()); + self::assertSame('json-check', $hc->getCheckID()); + self::assertSame('critical', $hc->getStatus()); + self::assertInstanceOf(HealthCheckDefinition::class, $hc->getDefinition()); + } +} + diff --git a/tests/Unit/Health/HealthChecksTest.php b/tests/Unit/Health/HealthChecksTest.php new file mode 100644 index 00000000..dd114369 --- /dev/null +++ b/tests/Unit/Health/HealthChecksTest.php @@ -0,0 +1,99 @@ +count()); + } + + public function testIteratorAggregate(): void + { + $hcs = new HealthChecks( + new HealthCheck(Name: 'a'), + new HealthCheck(Name: 'b'), + ); + $names = []; + foreach ($hcs as $hc) { + $names[] = $hc->getName(); + } + self::assertSame(['a', 'b'], $names); + } + + public function testArrayAccess(): void + { + $hcs = new HealthChecks(new HealthCheck(Name: 'x')); + self::assertTrue(isset($hcs[0])); + self::assertFalse(isset($hcs[1])); + self::assertSame('x', $hcs[0]->getName()); + } + + public function testAggregatedStatusAllPassing(): void + { + $hcs = new HealthChecks( + new HealthCheck(Status: 'passing'), + new HealthCheck(Status: 'passing'), + ); + self::assertSame('passing', $hcs->AggregatedStatus()); + } + + public function testAggregatedStatusCritical(): void + { + $hcs = new HealthChecks( + new HealthCheck(Status: 'passing'), + new HealthCheck(Status: 'critical'), + ); + self::assertSame('critical', $hcs->AggregatedStatus()); + } + + public function testAggregatedStatusWarning(): void + { + $hcs = new HealthChecks( + new HealthCheck(Status: 'passing'), + new HealthCheck(Status: 'warning'), + ); + self::assertSame('warning', $hcs->AggregatedStatus()); + } + + public function testAggregatedStatusEmpty(): void + { + $hcs = new HealthChecks(); + self::assertSame('passing', $hcs->AggregatedStatus()); + } + + public function testJsonSerialize(): void + { + $hcs = new HealthChecks(new HealthCheck(Name: 'test')); + $out = $hcs->jsonSerialize(); + self::assertIsArray($out); + self::assertCount(1, $out); + } +} + diff --git a/tests/Unit/Health/ServiceEntryTest.php b/tests/Unit/Health/ServiceEntryTest.php new file mode 100644 index 00000000..7264d16c --- /dev/null +++ b/tests/Unit/Health/ServiceEntryTest.php @@ -0,0 +1,57 @@ +getNode()); + self::assertNull($se->getService()); + self::assertInstanceOf(HealthChecks::class, $se->getChecks()); + } + + public function testConstructorWithValues(): void + { + $node = new Node(Node: 'n1', Address: '10.0.0.1'); + $svc = new AgentService(ID: 's1', Service: 'web'); + $se = new ServiceEntry(Node: $node, Service: $svc); + self::assertNotNull($se->getNode()); + self::assertSame('n1', $se->getNode()->getNode()); + self::assertNotNull($se->getService()); + self::assertSame('s1', $se->getService()->getID()); + } + + public function testFluentSetters(): void + { + $se = new ServiceEntry(); + $result = $se + ->setNode(new Node(Node: 'x')) + ->setService(new AgentService(ID: 'y')) + ->setChecks(new HealthChecks()); + self::assertSame($se, $result); + } + + public function testJsonSerialize(): void + { + $se = new ServiceEntry( + Node: new Node(Node: 'n'), + Service: new AgentService(ID: 's'), + ); + $out = $se->jsonSerialize(); + self::assertInstanceOf(\stdClass::class, $out); + } +} + diff --git a/tests/Unit/KV/KVPairResponseTest.php b/tests/Unit/KV/KVPairResponseTest.php new file mode 100644 index 00000000..fea81237 --- /dev/null +++ b/tests/Unit/KV/KVPairResponseTest.php @@ -0,0 +1,218 @@ +KVPair); + self::assertNull($resp->getValue()); + self::assertNull($resp->Err); + } + + public function testUnmarshalValueWithNull(): void + { + $resp = new KVPairResponse(); + $resp->unmarshalValue(null); + self::assertNull($resp->KVPair); + self::assertNull($resp->getValue()); + } + + public function testUnmarshalValueWithValidData(): void + { + $decoded = new \stdClass(); + $decoded->Key = 'foo/bar'; + $decoded->Value = base64_encode('hello world'); + $decoded->CreateIndex = 10; + $decoded->ModifyIndex = 20; + $decoded->LockIndex = 0; + $decoded->Flags = 0; + $decoded->Session = ''; + + $resp = new KVPairResponse(); + $resp->unmarshalValue($decoded); + + self::assertInstanceOf(KVPair::class, $resp->KVPair); + self::assertSame('foo/bar', $resp->KVPair->getKey()); + self::assertSame('hello world', $resp->KVPair->getValue()); + self::assertSame(10, $resp->KVPair->getCreateIndex()); + self::assertSame(20, $resp->KVPair->getModifyIndex()); + } + + public function testGetValueReturnsSameAsKVPairField(): void + { + $decoded = new \stdClass(); + $decoded->Key = 'test'; + $decoded->Value = base64_encode('val'); + $decoded->CreateIndex = 0; + $decoded->ModifyIndex = 0; + $decoded->LockIndex = 0; + $decoded->Flags = 0; + $decoded->Session = ''; + + $resp = new KVPairResponse(); + $resp->unmarshalValue($decoded); + + self::assertSame($resp->KVPair, $resp->getValue()); + } + + public function testArrayAccessOffset0ReturnsValue(): void + { + $decoded = new \stdClass(); + $decoded->Key = 'k'; + $decoded->Value = base64_encode('v'); + $decoded->CreateIndex = 0; + $decoded->ModifyIndex = 0; + $decoded->LockIndex = 0; + $decoded->Flags = 0; + $decoded->Session = ''; + + $resp = new KVPairResponse(); + $resp->unmarshalValue($decoded); + + self::assertSame($resp->KVPair, $resp[0]); + } + + public function testArrayAccessOffset1ReturnsQueryMeta(): void + { + $resp = new KVPairResponse(); + $qm = new QueryMeta(RequestUrl: 'http://localhost', RequestTime: 0); + $resp->setQueryMeta($qm); + self::assertSame($qm, $resp[1]); + } + + public function testArrayAccessOffset2ReturnsErr(): void + { + $resp = new KVPairResponse(); + self::assertNull($resp[2]); + + $err = new Error('test error'); + $resp->Err = $err; + self::assertSame($err, $resp[2]); + } + + public function testArrayAccessOffsetExists(): void + { + $resp = new KVPairResponse(); + self::assertTrue(isset($resp[0])); + self::assertTrue(isset($resp[1])); + self::assertTrue(isset($resp[2])); + self::assertFalse(isset($resp[3])); + self::assertFalse(isset($resp[-1])); + } + + public function testArrayAccessOffsetGetThrowsOutOfRange(): void + { + $this->expectException(\OutOfRangeException::class); + $resp = new KVPairResponse(); + $resp[3]; + } + + public function testArrayAccessOffsetSetThrows(): void + { + $this->expectException(\BadMethodCallException::class); + $resp = new KVPairResponse(); + $resp[0] = null; + } + + public function testArrayAccessOffsetUnsetThrows(): void + { + $this->expectException(\BadMethodCallException::class); + $resp = new KVPairResponse(); + unset($resp[0]); + } + + public function testListDestructuring(): void + { + $decoded = new \stdClass(); + $decoded->Key = 'test'; + $decoded->Value = base64_encode('value'); + $decoded->CreateIndex = 5; + $decoded->ModifyIndex = 10; + $decoded->LockIndex = 0; + $decoded->Flags = 0; + $decoded->Session = ''; + + $resp = new KVPairResponse(); + $resp->unmarshalValue($decoded); + $qm = new QueryMeta(RequestUrl: 'http://localhost', RequestTime: 0); + $resp->setQueryMeta($qm); + + [$kv, $queryMeta, $err] = $resp; + self::assertInstanceOf(KVPair::class, $kv); + self::assertSame('test', $kv->getKey()); + self::assertSame($qm, $queryMeta); + self::assertNull($err); + } + + public function testListDestructuringWithError(): void + { + $resp = new KVPairResponse(); + $resp->Err = new Error('something went wrong'); + + [$kv, $queryMeta, $err] = $resp; + self::assertNull($kv); + self::assertNull($queryMeta); + self::assertInstanceOf(Error::class, $err); + self::assertSame('something went wrong', (string)$err); + } + + public function testUnmarshalOverwritesPreviousValue(): void + { + $decoded1 = new \stdClass(); + $decoded1->Key = 'first'; + $decoded1->Value = base64_encode('v1'); + $decoded1->CreateIndex = 0; + $decoded1->ModifyIndex = 0; + $decoded1->LockIndex = 0; + $decoded1->Flags = 0; + $decoded1->Session = ''; + + $decoded2 = new \stdClass(); + $decoded2->Key = 'second'; + $decoded2->Value = base64_encode('v2'); + $decoded2->CreateIndex = 0; + $decoded2->ModifyIndex = 0; + $decoded2->LockIndex = 0; + $decoded2->Flags = 0; + $decoded2->Session = ''; + + $resp = new KVPairResponse(); + $resp->unmarshalValue($decoded1); + self::assertSame('first', $resp->KVPair->getKey()); + + $resp->unmarshalValue($decoded2); + self::assertSame('second', $resp->KVPair->getKey()); + } + + public function testUnmarshalNullAfterValueClearsIt(): void + { + $decoded = new \stdClass(); + $decoded->Key = 'k'; + $decoded->Value = base64_encode('v'); + $decoded->CreateIndex = 0; + $decoded->ModifyIndex = 0; + $decoded->LockIndex = 0; + $decoded->Flags = 0; + $decoded->Session = ''; + + $resp = new KVPairResponse(); + $resp->unmarshalValue($decoded); + self::assertNotNull($resp->KVPair); + + $resp->unmarshalValue(null); + self::assertNull($resp->KVPair); + } +} + diff --git a/tests/Unit/KV/KVPairTest.php b/tests/Unit/KV/KVPairTest.php new file mode 100644 index 00000000..5d340246 --- /dev/null +++ b/tests/Unit/KV/KVPairTest.php @@ -0,0 +1,184 @@ +getKey()); + self::assertSame(0, $kvp->getCreateIndex()); + self::assertSame(0, $kvp->getModifyIndex()); + self::assertSame(0, $kvp->getLockIndex()); + self::assertSame(0, $kvp->getFlags()); + self::assertSame('', $kvp->getValue()); + self::assertSame('', $kvp->getSession()); + self::assertSame('', $kvp->getNamespace()); + self::assertSame('', $kvp->getPartition()); + } + + public function testConstructorWithNamedParams(): void + { + $kvp = new KVPair( + Key: 'test/key', + Value: 'hello', + Flags: 42, + Session: 'sess-1', + Namespace: 'ns', + Partition: 'part', + ); + self::assertSame('test/key', $kvp->getKey()); + self::assertSame('hello', $kvp->getValue()); + self::assertSame(42, $kvp->getFlags()); + self::assertSame('sess-1', $kvp->getSession()); + self::assertSame('ns', $kvp->getNamespace()); + self::assertSame('part', $kvp->getPartition()); + } + + public function testFluentSetters(): void + { + $kvp = new KVPair(); + $result = $kvp + ->setKey('k') + ->setCreateIndex(1) + ->setModifyIndex(2) + ->setLockIndex(3) + ->setFlags(4) + ->setValue('v') + ->setSession('s') + ->setNamespace('ns') + ->setPartition('pt'); + + self::assertSame($kvp, $result); + self::assertSame('k', $kvp->getKey()); + self::assertSame(1, $kvp->getCreateIndex()); + self::assertSame(2, $kvp->getModifyIndex()); + self::assertSame(3, $kvp->getLockIndex()); + self::assertSame(4, $kvp->getFlags()); + self::assertSame('v', $kvp->getValue()); + self::assertSame('s', $kvp->getSession()); + self::assertSame('ns', $kvp->getNamespace()); + self::assertSame('pt', $kvp->getPartition()); + } + + public function testJsonSerialize(): void + { + $kvp = new KVPair(Key: 'foo', Value: 'bar', Flags: 1); + $out = $kvp->jsonSerialize(); + + self::assertInstanceOf(\stdClass::class, $out); + self::assertSame('foo', $out->Key); + self::assertSame('bar', $out->Value); + self::assertSame(1, $out->Flags); + } + + public function testJsonSerializeOmitsEmptyNamespaceAndPartition(): void + { + $kvp = new KVPair(Key: 'foo'); + $out = $kvp->jsonSerialize(); + + self::assertObjectNotHasProperty('Namespace', $out); + self::assertObjectNotHasProperty('Partition', $out); + } + + public function testJsonSerializeIncludesNonEmptyNamespaceAndPartition(): void + { + $kvp = new KVPair(Key: 'foo', Namespace: 'ns1', Partition: 'pt1'); + $out = $kvp->jsonSerialize(); + + self::assertSame('ns1', $out->Namespace); + self::assertSame('pt1', $out->Partition); + } + + public function testJsonUnserializeBase64DecodesValue(): void + { + $decoded = new \stdClass(); + $decoded->Key = 'test'; + $decoded->Value = base64_encode('hello world'); + $decoded->CreateIndex = 10; + $decoded->ModifyIndex = 20; + $decoded->LockIndex = 0; + $decoded->Flags = 0; + $decoded->Session = ''; + + $kvp = KVPair::jsonUnserialize($decoded); + + self::assertSame('test', $kvp->getKey()); + self::assertSame('hello world', $kvp->getValue()); + self::assertSame(10, $kvp->getCreateIndex()); + self::assertSame(20, $kvp->getModifyIndex()); + } + + public function testJsonUnserializeThrowsOnInvalidBase64(): void + { + $this->expectException(\DomainException::class); + + $decoded = new \stdClass(); + // invalid base64 - a single "=" alone is not valid base64 + $decoded->Value = '!!!not-valid-base64!!!'; + $decoded->Key = 'k'; + + KVPair::jsonUnserialize($decoded); + } + + public function testDynamicFieldAssignment(): void + { + $kvp = new KVPair(); + $kvp->CustomField = 'custom-value'; + + self::assertSame('custom-value', $kvp->CustomField); + self::assertArrayHasKey('CustomField', $kvp->_getDynamicFields()); + } + + public function testDynamicFieldsIncludedInJsonSerialize(): void + { + $kvp = new KVPair(Key: 'k'); + $kvp->ExtraField = 'extra'; + + $out = $kvp->jsonSerialize(); + self::assertSame('extra', $out->ExtraField); + } + + public function testToString(): void + { + $kvp = new KVPair(Value: 'my-value'); + self::assertSame('my-value', (string)$kvp); + } + + public function testJsonRoundTrip(): void + { + $original = new KVPair( + Key: 'round/trip', + CreateIndex: 5, + ModifyIndex: 10, + LockIndex: 1, + Flags: 99, + Value: 'test data', + Session: 'sess-abc', + ); + + $serialized = $original->jsonSerialize(); + + // Simulate what consul returns: Value is base64 encoded + $serialized->Value = base64_encode($serialized->Value); + + $restored = KVPair::jsonUnserialize($serialized); + + self::assertSame($original->getKey(), $restored->getKey()); + self::assertSame($original->getCreateIndex(), $restored->getCreateIndex()); + self::assertSame($original->getModifyIndex(), $restored->getModifyIndex()); + self::assertSame($original->getLockIndex(), $restored->getLockIndex()); + self::assertSame($original->getFlags(), $restored->getFlags()); + self::assertSame($original->getValue(), $restored->getValue()); + self::assertSame($original->getSession(), $restored->getSession()); + } +} + diff --git a/tests/Unit/KV/KVPairsResponseTest.php b/tests/Unit/KV/KVPairsResponseTest.php new file mode 100644 index 00000000..17f57f8f --- /dev/null +++ b/tests/Unit/KV/KVPairsResponseTest.php @@ -0,0 +1,190 @@ +KVPairs); + self::assertCount(0, $resp->KVPairs); + self::assertNull($resp->Err); + } + + public function testGetValueReturnsKVPairs(): void + { + $resp = new KVPairsResponse(); + self::assertInstanceOf(KVPairs::class, $resp->getValue()); + self::assertSame($resp->KVPairs, $resp->getValue()); + } + + public function testUnmarshalValueWithNull(): void + { + // First populate, then unmarshal null to verify it resets + $obj = new \stdClass(); + $obj->Key = 'k'; + $obj->Value = base64_encode('v'); + $obj->CreateIndex = 0; + $obj->ModifyIndex = 0; + $obj->LockIndex = 0; + $obj->Flags = 0; + $obj->Session = ''; + + $resp = new KVPairsResponse(); + $resp->unmarshalValue([$obj]); + self::assertCount(1, $resp->KVPairs); + + $resp->unmarshalValue(null); + self::assertCount(0, $resp->KVPairs); + } + + public function testUnmarshalValueWithValidData(): void + { + $obj1 = new \stdClass(); + $obj1->Key = 'a/1'; + $obj1->Value = base64_encode('val1'); + $obj1->CreateIndex = 1; + $obj1->ModifyIndex = 2; + $obj1->LockIndex = 0; + $obj1->Flags = 0; + $obj1->Session = ''; + + $obj2 = new \stdClass(); + $obj2->Key = 'a/2'; + $obj2->Value = base64_encode('val2'); + $obj2->CreateIndex = 3; + $obj2->ModifyIndex = 4; + $obj2->LockIndex = 0; + $obj2->Flags = 0; + $obj2->Session = ''; + + $resp = new KVPairsResponse(); + $resp->unmarshalValue([$obj1, $obj2]); + + self::assertCount(2, $resp->KVPairs); + self::assertSame('a/1', $resp->KVPairs[0]->getKey()); + self::assertSame('val1', $resp->KVPairs[0]->getValue()); + self::assertSame('a/2', $resp->KVPairs[1]->getKey()); + self::assertSame('val2', $resp->KVPairs[1]->getValue()); + } + + public function testArrayAccessOffset0ReturnsValue(): void + { + $resp = new KVPairsResponse(); + self::assertInstanceOf(KVPairs::class, $resp[0]); + } + + public function testArrayAccessOffset1ReturnsQueryMeta(): void + { + $resp = new KVPairsResponse(); + $qm = new QueryMeta(RequestUrl: 'http://localhost', RequestTime: 0); + $resp->setQueryMeta($qm); + self::assertSame($qm, $resp[1]); + } + + public function testArrayAccessOffset2ReturnsErr(): void + { + $resp = new KVPairsResponse(); + self::assertNull($resp[2]); + + $err = new Error('test error'); + $resp->Err = $err; + self::assertSame($err, $resp[2]); + } + + public function testArrayAccessOffsetExists(): void + { + $resp = new KVPairsResponse(); + self::assertTrue(isset($resp[0])); + self::assertTrue(isset($resp[1])); + self::assertTrue(isset($resp[2])); + self::assertFalse(isset($resp[3])); + self::assertFalse(isset($resp[-1])); + } + + public function testArrayAccessOffsetGetThrowsOutOfRange(): void + { + $this->expectException(\OutOfRangeException::class); + $resp = new KVPairsResponse(); + $resp[3]; + } + + public function testListDestructuring(): void + { + $obj = new \stdClass(); + $obj->Key = 'test'; + $obj->Value = base64_encode('value'); + $obj->CreateIndex = 1; + $obj->ModifyIndex = 2; + $obj->LockIndex = 0; + $obj->Flags = 0; + $obj->Session = ''; + + $resp = new KVPairsResponse(); + $resp->unmarshalValue([$obj]); + $qm = new QueryMeta(RequestUrl: 'http://localhost', RequestTime: 0); + $resp->setQueryMeta($qm); + + [$pairs, $queryMeta, $err] = $resp; + self::assertInstanceOf(KVPairs::class, $pairs); + self::assertCount(1, $pairs); + self::assertSame($qm, $queryMeta); + self::assertNull($err); + } + + public function testListDestructuringWithError(): void + { + $resp = new KVPairsResponse(); + $resp->Err = new Error('fail'); + + [$pairs, $queryMeta, $err] = $resp; + self::assertInstanceOf(KVPairs::class, $pairs); + self::assertCount(0, $pairs); + self::assertNull($queryMeta); + self::assertInstanceOf(Error::class, $err); + } + + public function testUnmarshalValueIsIterable(): void + { + $items = []; + for ($i = 0; $i < 5; $i++) { + $obj = new \stdClass(); + $obj->Key = "prefix/key{$i}"; + $obj->Value = base64_encode("value{$i}"); + $obj->CreateIndex = $i; + $obj->ModifyIndex = $i; + $obj->LockIndex = 0; + $obj->Flags = 0; + $obj->Session = ''; + $items[] = $obj; + } + + $resp = new KVPairsResponse(); + $resp->unmarshalValue($items); + + $keys = []; + foreach ($resp->KVPairs as $pair) { + $keys[] = $pair->getKey(); + } + self::assertSame(['prefix/key0', 'prefix/key1', 'prefix/key2', 'prefix/key3', 'prefix/key4'], $keys); + } + + public function testUnmarshalEmptyArray(): void + { + $resp = new KVPairsResponse(); + $resp->unmarshalValue([]); + self::assertCount(0, $resp->KVPairs); + } +} + diff --git a/tests/Unit/KV/KVPairsTest.php b/tests/Unit/KV/KVPairsTest.php new file mode 100644 index 00000000..12eb35e3 --- /dev/null +++ b/tests/Unit/KV/KVPairsTest.php @@ -0,0 +1,192 @@ +getKVPairs(); + self::assertIsArray($arr); + self::assertCount(2, $arr); + self::assertSame('a', $arr[0]->getKey()); + self::assertSame('b', $arr[1]->getKey()); + } + + public function testGetKVPairsEmptyByDefault(): void + { + $pairs = new KVPairs(); + self::assertSame([], $pairs->getKVPairs()); + } + + public function testSetKVPairsVariadic(): void + { + $pairs = new KVPairs(); + $result = $pairs->setKVPairs(new KVPair(Key: 'x'), new KVPair(Key: 'y')); + self::assertSame($pairs, $result); + self::assertCount(2, $pairs); + self::assertSame('x', $pairs->getKVPairs()[0]->getKey()); + self::assertSame('y', $pairs->getKVPairs()[1]->getKey()); + } + + public function testSetKVPairsReplacesExisting(): void + { + $pairs = new KVPairs(new KVPair(Key: 'old')); + self::assertCount(1, $pairs); + $pairs->setKVPairs(new KVPair(Key: 'new1'), new KVPair(Key: 'new2')); + self::assertCount(2, $pairs); + self::assertSame('new1', $pairs->getKVPairs()[0]->getKey()); + } + + public function testSetKVPairsWithNoArgsClearsArray(): void + { + $pairs = new KVPairs(new KVPair(Key: 'a'), new KVPair(Key: 'b')); + self::assertCount(2, $pairs); + $pairs->setKVPairs(); + self::assertCount(0, $pairs); + self::assertSame([], $pairs->getKVPairs()); + } + + public function testCountable(): void + { + $pairs = new KVPairs(new KVPair(Key: 'x'), new KVPair(Key: 'y'), new KVPair(Key: 'z')); + self::assertSame(3, $pairs->count()); + } + + public function testIteratorAggregate(): void + { + $kv1 = new KVPair(Key: 'first'); + $kv2 = new KVPair(Key: 'second'); + $pairs = new KVPairs($kv1, $kv2); + + $keys = []; + foreach ($pairs as $pair) { + $keys[] = $pair->getKey(); + } + self::assertSame(['first', 'second'], $keys); + } + + public function testArrayAccessOffsetExists(): void + { + $pairs = new KVPairs(new KVPair(Key: 'a')); + self::assertTrue(isset($pairs[0])); + self::assertFalse(isset($pairs[1])); + } + + public function testArrayAccessOffsetGet(): void + { + $kv = new KVPair(Key: 'test'); + $pairs = new KVPairs($kv); + self::assertSame('test', $pairs[0]->getKey()); + } + + public function testArrayAccessOffsetGetThrowsOnInvalidOffset(): void + { + $this->expectException(\OutOfRangeException::class); + $pairs = new KVPairs(); + $pairs[0]; + } + + public function testArrayAccessOffsetSetAppend(): void + { + $pairs = new KVPairs(); + $pairs[] = new KVPair(Key: 'appended'); + self::assertCount(1, $pairs); + self::assertSame('appended', $pairs[0]->getKey()); + } + + public function testArrayAccessOffsetSetByIndex(): void + { + $pairs = new KVPairs(new KVPair(Key: 'old')); + $pairs[0] = new KVPair(Key: 'new'); + self::assertSame('new', $pairs[0]->getKey()); + } + + public function testArrayAccessOffsetSetThrowsOnNonKVPair(): void + { + $this->expectException(\InvalidArgumentException::class); + $pairs = new KVPairs(); + $pairs[] = 'not a KVPair'; + } + + public function testArrayAccessOffsetSetThrowsOnNonIntOffset(): void + { + $this->expectException(\InvalidArgumentException::class); + $pairs = new KVPairs(); + $pairs['key'] = new KVPair(Key: 'x'); + } + + public function testArrayAccessOffsetUnset(): void + { + $pairs = new KVPairs(new KVPair(Key: 'a'), new KVPair(Key: 'b')); + unset($pairs[0]); + self::assertFalse(isset($pairs[0])); + self::assertTrue(isset($pairs[1])); + } + + public function testJsonSerialize(): void + { + $kv1 = new KVPair(Key: 'k1', Value: 'v1'); + $kv2 = new KVPair(Key: 'k2', Value: 'v2'); + $pairs = new KVPairs($kv1, $kv2); + $out = $pairs->jsonSerialize(); + self::assertIsArray($out); + self::assertCount(2, $out); + self::assertInstanceOf(KVPair::class, $out[0]); + self::assertInstanceOf(KVPair::class, $out[1]); + } + + public function testJsonUnserialize(): void + { + $obj1 = new \stdClass(); + $obj1->Key = 'k1'; + $obj1->Value = base64_encode('v1'); + $obj1->CreateIndex = 0; + $obj1->ModifyIndex = 0; + $obj1->LockIndex = 0; + $obj1->Flags = 0; + $obj1->Session = ''; + + $obj2 = new \stdClass(); + $obj2->Key = 'k2'; + $obj2->Value = base64_encode('v2'); + $obj2->CreateIndex = 0; + $obj2->ModifyIndex = 0; + $obj2->LockIndex = 0; + $obj2->Flags = 0; + $obj2->Session = ''; + + $pairs = KVPairs::jsonUnserialize([$obj1, $obj2]); + self::assertCount(2, $pairs); + self::assertSame('k1', $pairs[0]->getKey()); + self::assertSame('v1', $pairs[0]->getValue()); + self::assertSame('k2', $pairs[1]->getKey()); + self::assertSame('v2', $pairs[1]->getValue()); + } +} + diff --git a/tests/Unit/Metrics/LabelTest.php b/tests/Unit/Metrics/LabelTest.php new file mode 100644 index 00000000..8f410bee --- /dev/null +++ b/tests/Unit/Metrics/LabelTest.php @@ -0,0 +1,65 @@ +getName()); + self::assertSame('', $l->getValue()); + } + + public function testConstructorWithValues(): void + { + $l = new Label(Name: 'env', Value: 'prod'); + self::assertSame('env', $l->getName()); + self::assertSame('prod', $l->getValue()); + } + + public function testFluentSetters(): void + { + $l = new Label(); + $result = $l->setName('host')->setValue('node-1'); + self::assertSame($l, $result); + self::assertSame('host', $l->getName()); + self::assertSame('node-1', $l->getValue()); + } + + public function testJsonSerialize(): void + { + $l = new Label(Name: 'dc', Value: 'dc1'); + $out = $l->jsonSerialize(); + self::assertInstanceOf(\stdClass::class, $out); + self::assertSame('dc', $out->Name); + self::assertSame('dc1', $out->Value); + } + + public function testJsonUnserialize(): void + { + $decoded = new \stdClass(); + $decoded->Name = 'region'; + $decoded->Value = 'us-east'; + $l = Label::jsonUnserialize($decoded); + self::assertSame('region', $l->getName()); + self::assertSame('us-east', $l->getValue()); + } + + public function testJsonRoundTrip(): void + { + $original = new Label(Name: 'service', Value: 'web'); + $restored = Label::jsonUnserialize($original->jsonSerialize()); + self::assertSame($original->getName(), $restored->getName()); + self::assertSame($original->getValue(), $restored->getValue()); + } +} + diff --git a/tests/Unit/Operator/AreaJoinResponseTest.php b/tests/Unit/Operator/AreaJoinResponseTest.php new file mode 100644 index 00000000..38a246e1 --- /dev/null +++ b/tests/Unit/Operator/AreaJoinResponseTest.php @@ -0,0 +1,92 @@ +getAddress()); + self::assertFalse($resp->isJoined()); + self::assertSame('', $resp->getError()); + } + + public function testConstructorWithValues(): void + { + $resp = new AreaJoinResponse( + Address: '10.0.0.1', + Joined: true, + Error: '', + ); + self::assertSame('10.0.0.1', $resp->getAddress()); + self::assertTrue($resp->isJoined()); + } + + public function testFluentSetters(): void + { + $resp = new AreaJoinResponse(); + $result = $resp + ->setAddress('192.168.1.1') + ->setJoined(true) + ->setError('some error'); + + self::assertSame($resp, $result); + self::assertSame('192.168.1.1', $resp->getAddress()); + self::assertTrue($resp->isJoined()); + self::assertSame('some error', $resp->getError()); + } + + public function testJsonSerialize(): void + { + $resp = new AreaJoinResponse( + Address: '10.0.0.5', + Joined: true, + Error: 'err', + ); + $out = $resp->jsonSerialize(); + + self::assertInstanceOf(\stdClass::class, $out); + self::assertSame('10.0.0.5', $out->Address); + self::assertTrue($out->Joined); + self::assertSame('err', $out->Error); + } + + public function testJsonUnserialize(): void + { + $decoded = new \stdClass(); + $decoded->Address = '172.16.0.1'; + $decoded->Joined = false; + $decoded->Error = 'connection refused'; + + $resp = AreaJoinResponse::jsonUnserialize($decoded); + + self::assertSame('172.16.0.1', $resp->getAddress()); + self::assertFalse($resp->isJoined()); + self::assertSame('connection refused', $resp->getError()); + } + + public function testJsonRoundTrip(): void + { + $original = new AreaJoinResponse( + Address: '10.1.2.3', + Joined: true, + Error: '', + ); + + $restored = AreaJoinResponse::jsonUnserialize($original->jsonSerialize()); + + self::assertSame($original->getAddress(), $restored->getAddress()); + self::assertSame($original->isJoined(), $restored->isJoined()); + self::assertSame($original->getError(), $restored->getError()); + } +} + diff --git a/tests/Unit/Operator/AreaTest.php b/tests/Unit/Operator/AreaTest.php new file mode 100644 index 00000000..74340dfd --- /dev/null +++ b/tests/Unit/Operator/AreaTest.php @@ -0,0 +1,120 @@ +getID()); + self::assertSame('', $area->getPeerDatacenter()); + self::assertSame([], $area->getRetryJoin()); + self::assertFalse($area->isUseTLS()); + } + + public function testConstructorWithValues(): void + { + $area = new Area( + ID: 'area-1', + PeerDatacenter: 'dc2', + RetryJoin: ['10.0.0.1', '10.0.0.2'], + UseTLS: true, + ); + self::assertSame('area-1', $area->getID()); + self::assertSame('dc2', $area->getPeerDatacenter()); + self::assertSame(['10.0.0.1', '10.0.0.2'], $area->getRetryJoin()); + self::assertTrue($area->isUseTLS()); + } + + public function testFluentSetters(): void + { + $area = new Area(); + $result = $area + ->setID('a') + ->setPeerDatacenter('dc') + ->setRetryJoin('1.2.3.4', '5.6.7.8') + ->setUseTLS(true); + + self::assertSame($area, $result); + self::assertSame('a', $area->getID()); + self::assertSame('dc', $area->getPeerDatacenter()); + self::assertSame(['1.2.3.4', '5.6.7.8'], $area->getRetryJoin()); + self::assertTrue($area->isUseTLS()); + } + + public function testVariadicSetRetryJoinReplacesExisting(): void + { + $area = new Area(RetryJoin: ['old-addr']); + $area->setRetryJoin('new-addr-1', 'new-addr-2'); + + self::assertSame(['new-addr-1', 'new-addr-2'], $area->getRetryJoin()); + } + + public function testVariadicSetRetryJoinWithNoArgsClears(): void + { + $area = new Area(RetryJoin: ['addr']); + $area->setRetryJoin(); + + self::assertSame([], $area->getRetryJoin()); + } + + public function testJsonSerialize(): void + { + $area = new Area( + ID: 'area-1', + PeerDatacenter: 'dc2', + RetryJoin: ['10.0.0.1'], + UseTLS: true, + ); + $out = $area->jsonSerialize(); + + self::assertInstanceOf(\stdClass::class, $out); + self::assertSame('area-1', $out->ID); + self::assertSame('dc2', $out->PeerDatacenter); + self::assertSame(['10.0.0.1'], $out->RetryJoin); + self::assertTrue($out->UseTLS); + } + + public function testJsonUnserialize(): void + { + $decoded = new \stdClass(); + $decoded->ID = 'area-x'; + $decoded->PeerDatacenter = 'dc3'; + $decoded->RetryJoin = ['a', 'b']; + $decoded->UseTLS = false; + + $area = Area::jsonUnserialize($decoded); + + self::assertSame('area-x', $area->getID()); + self::assertSame('dc3', $area->getPeerDatacenter()); + self::assertSame(['a', 'b'], $area->getRetryJoin()); + self::assertFalse($area->isUseTLS()); + } + + public function testJsonRoundTrip(): void + { + $original = new Area( + ID: 'area-rt', + PeerDatacenter: 'dc-rt', + RetryJoin: ['host-1', 'host-2'], + UseTLS: true, + ); + + $restored = Area::jsonUnserialize($original->jsonSerialize()); + + self::assertSame($original->getID(), $restored->getID()); + self::assertSame($original->getPeerDatacenter(), $restored->getPeerDatacenter()); + self::assertSame($original->getRetryJoin(), $restored->getRetryJoin()); + self::assertSame($original->isUseTLS(), $restored->isUseTLS()); + } +} + diff --git a/tests/Unit/Operator/AutopilotConfigurationTest.php b/tests/Unit/Operator/AutopilotConfigurationTest.php new file mode 100644 index 00000000..fe09d9a1 --- /dev/null +++ b/tests/Unit/Operator/AutopilotConfigurationTest.php @@ -0,0 +1,142 @@ +isCleanupDeadServers()); + self::assertNull($c->getLastContactThreshold()); + self::assertSame(0, $c->getMaxTrailingLogs()); + self::assertSame(0, $c->getMinQuorum()); + self::assertNull($c->getServerStabilizationTime()); + self::assertSame('', $c->getRedundancyZoneTag()); + self::assertFalse($c->isDisableUpgradeMigration()); + self::assertSame('', $c->getUpgradeVersionTag()); + self::assertSame(0, $c->getCreateIndex()); + self::assertSame(0, $c->getModifyIndex()); + } + + public function testConstructorWithValues(): void + { + $c = new AutopilotConfiguration( + CleanupDeadServers: true, + LastContactThreshold: '200ms', + MaxTrailingLogs: 250, + MinQuorum: 3, + ServerStabilizationTime: '10s', + RedundancyZoneTag: 'zone', + DisableUpgradeMigration: true, + UpgradeVersionTag: 'build', + CreateIndex: 5, + ModifyIndex: 10, + ); + self::assertTrue($c->isCleanupDeadServers()); + self::assertNotNull($c->getLastContactThreshold()); + self::assertSame(250, $c->getMaxTrailingLogs()); + self::assertSame(3, $c->getMinQuorum()); + self::assertNotNull($c->getServerStabilizationTime()); + self::assertSame('zone', $c->getRedundancyZoneTag()); + self::assertTrue($c->isDisableUpgradeMigration()); + self::assertSame('build', $c->getUpgradeVersionTag()); + self::assertSame(5, $c->getCreateIndex()); + self::assertSame(10, $c->getModifyIndex()); + } + + public function testFluentSetters(): void + { + $c = new AutopilotConfiguration(); + $result = $c + ->setCleanupDeadServers(true) + ->setLastContactThreshold('100ms') + ->setMaxTrailingLogs(100) + ->setMinQuorum(1) + ->setServerStabilizationTime('5s') + ->setRedundancyZoneTag('rz') + ->setDisableUpgradeMigration(true) + ->setUpgradeVersionTag('uv') + ->setCreateIndex(1) + ->setModifyIndex(2); + self::assertSame($c, $result); + } + + public function testNullDurationSetters(): void + { + $c = new AutopilotConfiguration(LastContactThreshold: '5s', ServerStabilizationTime: '10s'); + self::assertNotNull($c->getLastContactThreshold()); + self::assertNotNull($c->getServerStabilizationTime()); + $c->setLastContactThreshold(null); + $c->setServerStabilizationTime(null); + self::assertNull($c->getLastContactThreshold()); + self::assertNull($c->getServerStabilizationTime()); + } + + public function testJsonSerialize(): void + { + $c = new AutopilotConfiguration(CleanupDeadServers: true, MaxTrailingLogs: 100); + $out = $c->jsonSerialize(); + self::assertInstanceOf(\stdClass::class, $out); + self::assertTrue($out->CleanupDeadServers); + self::assertSame(100, $out->MaxTrailingLogs); + } + + public function testJsonSerializeOmitsEmptyOptionals(): void + { + $c = new AutopilotConfiguration(); + $out = $c->jsonSerialize(); + self::assertObjectNotHasProperty('RedundancyZoneTag', $out); + self::assertObjectNotHasProperty('UpgradeVersionTag', $out); + self::assertObjectNotHasProperty('LastContactThreshold', $out); + self::assertObjectNotHasProperty('ServerStabilizationTime', $out); + } + + public function testJsonUnserialize(): void + { + $decoded = new \stdClass(); + $decoded->CleanupDeadServers = true; + $decoded->LastContactThreshold = '200ms'; + $decoded->MaxTrailingLogs = 250; + $decoded->MinQuorum = 3; + $decoded->ServerStabilizationTime = '10s'; + $decoded->RedundancyZoneTag = 'zone'; + $decoded->DisableUpgradeMigration = false; + $decoded->UpgradeVersionTag = ''; + $decoded->CreateIndex = 5; + $decoded->ModifyIndex = 10; + + $c = AutopilotConfiguration::jsonUnserialize($decoded); + self::assertTrue($c->isCleanupDeadServers()); + self::assertNotNull($c->getLastContactThreshold()); + self::assertSame(250, $c->getMaxTrailingLogs()); + self::assertSame(3, $c->getMinQuorum()); + self::assertNotNull($c->getServerStabilizationTime()); + self::assertSame(5, $c->getCreateIndex()); + } + + public function testJsonRoundTrip(): void + { + $original = new AutopilotConfiguration( + CleanupDeadServers: true, + MaxTrailingLogs: 200, + CreateIndex: 7, + ModifyIndex: 14, + ); + $json = json_encode($original); + $restored = AutopilotConfiguration::jsonUnserialize(json_decode($json, false)); + self::assertSame($original->isCleanupDeadServers(), $restored->isCleanupDeadServers()); + self::assertSame($original->getMaxTrailingLogs(), $restored->getMaxTrailingLogs()); + self::assertSame($original->getCreateIndex(), $restored->getCreateIndex()); + self::assertSame($original->getModifyIndex(), $restored->getModifyIndex()); + } +} + diff --git a/tests/Unit/Operator/AutopilotServerTest.php b/tests/Unit/Operator/AutopilotServerTest.php new file mode 100644 index 00000000..4f2dd7f2 --- /dev/null +++ b/tests/Unit/Operator/AutopilotServerTest.php @@ -0,0 +1,129 @@ +getID()); + self::assertSame('', $s->getName()); + self::assertSame('', $s->getAddress()); + self::assertSame('', $s->getNodeStatus()); + self::assertSame('', $s->getVersion()); + self::assertNull($s->getLastContact()); + self::assertSame(0, $s->getLastTerm()); + self::assertSame(0, $s->getLastIndex()); + self::assertFalse($s->isHealthy()); + self::assertSame('', $s->getRedundancyZone()); + self::assertSame('', $s->getUpgradeVersion()); + self::assertFalse($s->isReadReplica()); + self::assertSame(AutopilotServerStatus::UNDEFINED, $s->getStatus()); + self::assertSame(AutopilotServerType::UNDEFINED, $s->getNodeType()); + } + + public function testConstructorWithValues(): void + { + $s = new AutopilotServer( + ID: 'srv-1', + Name: 'node-1', + Address: '10.0.0.1:8300', + NodeStatus: 'alive', + Version: '1.22.0', + LastContact: '15ms', + LastTerm: 3, + LastIndex: 100, + Healthy: true, + RedundancyZone: 'zone-a', + UpgradeVersion: '1.22.0', + readReplica: false, + status: AutopilotServerStatus::Leader, + NodeType: AutopilotServerType::Voter, + ); + self::assertSame('srv-1', $s->getID()); + self::assertTrue($s->isHealthy()); + self::assertSame(AutopilotServerStatus::Leader, $s->getStatus()); + self::assertSame(AutopilotServerType::Voter, $s->getNodeType()); + } + + public function testFluentSetters(): void + { + $s = new AutopilotServer(); + $result = $s + ->setID('i') + ->setName('n') + ->setAddress('a') + ->setNodeStatus('ns') + ->setVersion('v') + ->setLastContact('10ms') + ->setLastTerm(1) + ->setLastIndex(50) + ->setHealthy(true) + ->setRedundancyZone('z') + ->setUpgradeVersion('uv') + ->setReadReplica(true) + ->setStatus(AutopilotServerStatus::Voter) + ->setNodeType(AutopilotServerType::ReadReplica); + self::assertSame($s, $result); + self::assertSame(AutopilotServerStatus::Voter, $s->getStatus()); + self::assertSame(AutopilotServerType::ReadReplica, $s->getNodeType()); + } + + public function testSetStatusFromString(): void + { + $s = new AutopilotServer(); + $s->setStatus('leader'); + self::assertSame(AutopilotServerStatus::Leader, $s->getStatus()); + } + + public function testSetNodeTypeFromString(): void + { + $s = new AutopilotServer(); + $s->setNodeType('voter'); + self::assertSame(AutopilotServerType::Voter, $s->getNodeType()); + } + + public function testJsonSerialize(): void + { + $s = new AutopilotServer(ID: 'x', Name: 'y', Healthy: true); + $out = $s->jsonSerialize(); + self::assertInstanceOf(\stdClass::class, $out); + self::assertSame('x', $out->ID); + self::assertTrue($out->Healthy); + } + + public function testJsonUnserialize(): void + { + $decoded = new \stdClass(); + $decoded->ID = 'as1'; + $decoded->Name = 'node'; + $decoded->Address = '10.0.0.1:8300'; + $decoded->NodeStatus = 'alive'; + $decoded->Version = '1.22.0'; + $decoded->LastTerm = 3; + $decoded->LastIndex = 100; + $decoded->Healthy = true; + $decoded->StableSince = '2024-01-01T00:00:00Z'; + $decoded->ReadReplica = false; + $decoded->Status = 'voter'; + $decoded->NodeType = 'voter'; + + $s = AutopilotServer::jsonUnserialize($decoded); + self::assertSame('as1', $s->getID()); + self::assertTrue($s->isHealthy()); + self::assertSame(AutopilotServerStatus::Voter, $s->getStatus()); + self::assertSame(AutopilotServerType::Voter, $s->getNodeType()); + } +} + diff --git a/tests/Unit/Operator/AutopilotStateTest.php b/tests/Unit/Operator/AutopilotStateTest.php new file mode 100644 index 00000000..82672527 --- /dev/null +++ b/tests/Unit/Operator/AutopilotStateTest.php @@ -0,0 +1,79 @@ +isHealthy()); + self::assertSame(0, $s->getFailureTolerance()); + self::assertSame(0, $s->getOptimisticFailureTolerance()); + self::assertSame([], $s->getServers()); + self::assertSame('', $s->getLeader()); + self::assertSame([], $s->getVoters()); + self::assertSame([], $s->getReadReplicas()); + self::assertSame([], $s->getRedundancyZone()); + self::assertNull($s->getUpgrade()); + } + + public function testConstructorWithValues(): void + { + $s = new AutopilotState( + Healthy: true, + FailureTolerance: 1, + OptimisticFailureTolerance: 2, + Leader: 'leader-id', + Voters: ['v1', 'v2'], + ); + self::assertTrue($s->isHealthy()); + self::assertSame(1, $s->getFailureTolerance()); + self::assertSame('leader-id', $s->getLeader()); + self::assertSame(['v1', 'v2'], $s->getVoters()); + } + + public function testFluentSetters(): void + { + $s = new AutopilotState(); + $result = $s + ->setHealthy(true) + ->setFailureTolerance(1) + ->setOptimisticFailureTolerance(2) + ->setServers([]) + ->setLeader('l') + ->setVoters('v1') + ->setReadReplicas('r1') + ->setRedundancyZone([]) + ->setUpgrade(null); + self::assertSame($s, $result); + } + + public function testJsonSerialize(): void + { + $s = new AutopilotState(Healthy: true, FailureTolerance: 1, Leader: 'l'); + $out = $s->jsonSerialize(); + self::assertInstanceOf(\stdClass::class, $out); + self::assertTrue($out->Healthy); + self::assertSame(1, $out->FailureTolerance); + self::assertSame('l', $out->Leader); + } + + public function testJsonSerializeOmitsEmptyOptionals(): void + { + $s = new AutopilotState(); + $out = $s->jsonSerialize(); + self::assertObjectNotHasProperty('ReadReplicas', $out); + self::assertObjectNotHasProperty('RedundancyZone', $out); + self::assertObjectNotHasProperty('Upgrade', $out); + } +} + diff --git a/tests/Unit/Operator/AutopilotUpgradeTest.php b/tests/Unit/Operator/AutopilotUpgradeTest.php new file mode 100644 index 00000000..a17e764c --- /dev/null +++ b/tests/Unit/Operator/AutopilotUpgradeTest.php @@ -0,0 +1,88 @@ +getStatus()); + self::assertSame('', $u->getTargetVersion()); + self::assertSame([], $u->getTargetVersionVoters()); + self::assertSame([], $u->getTargetVersionNonVoters()); + self::assertSame([], $u->getTargetVersionReadReplicas()); + self::assertSame([], $u->getOtherVersionVoters()); + self::assertSame([], $u->getOtherVersionNonVoters()); + self::assertSame([], $u->getOtherVersionReadReplicas()); + self::assertSame([], $u->getRedundancyZones()); + } + + public function testConstructorWithValues(): void + { + $u = new AutopilotUpgrade( + Status: 'awaiting-new-voters', + TargetVersion: '1.22.0', + TargetVersionVoters: ['a'], + OtherVersionVoters: ['b'], + ); + self::assertSame('awaiting-new-voters', $u->getStatus()); + self::assertSame('1.22.0', $u->getTargetVersion()); + self::assertSame(['a'], $u->getTargetVersionVoters()); + self::assertSame(['b'], $u->getOtherVersionVoters()); + } + + public function testFluentSetters(): void + { + $u = new AutopilotUpgrade(); + $result = $u + ->setStatus('idle') + ->setTargetVersion('1.0') + ->setTargetVersionVoters('v1') + ->setTargetVersionNonVoters('nv1') + ->setTargetVersionReadReplicas('rr1') + ->setOtherVersionVoters('ov1') + ->setOtherVersionNonVoters('onv1') + ->setOtherVersionReadReplicas('orr1') + ->setRedundancyZones([]); + self::assertSame($u, $result); + } + + public function testJsonSerialize(): void + { + $u = new AutopilotUpgrade(Status: 'idle', TargetVersion: '1.0', TargetVersionVoters: ['a']); + $out = $u->jsonSerialize(); + self::assertInstanceOf(\stdClass::class, $out); + self::assertSame('idle', $out->Status); + self::assertSame('1.0', $out->TargetVersion); + self::assertSame(['a'], $out->TargetVersionVoters); + } + + public function testJsonSerializeOmitsEmpty(): void + { + $u = new AutopilotUpgrade(Status: 'idle'); + $out = $u->jsonSerialize(); + self::assertObjectNotHasProperty('TargetVersion', $out); + self::assertObjectNotHasProperty('TargetVersionVoters', $out); + } + + public function testJsonUnserialize(): void + { + $decoded = new \stdClass(); + $decoded->Status = 'idle'; + $decoded->TargetVersion = '1.22.0'; + $decoded->TargetVersionVoters = ['x']; + $u = AutopilotUpgrade::jsonUnserialize($decoded); + self::assertSame('idle', $u->getStatus()); + self::assertSame('1.22.0', $u->getTargetVersion()); + } +} + diff --git a/tests/Unit/Operator/AutopilotZoneTest.php b/tests/Unit/Operator/AutopilotZoneTest.php new file mode 100644 index 00000000..2d4e1b8f --- /dev/null +++ b/tests/Unit/Operator/AutopilotZoneTest.php @@ -0,0 +1,121 @@ +getServers()); + self::assertSame([], $zone->getVoters()); + self::assertSame(0, $zone->getFailureTolerance()); + } + + public function testConstructorWithValues(): void + { + $zone = new AutopilotZone( + Servers: ['srv-1', 'srv-2'], + Voters: ['v-1'], + FailureTolerance: 2, + ); + self::assertSame(['srv-1', 'srv-2'], $zone->getServers()); + self::assertSame(['v-1'], $zone->getVoters()); + self::assertSame(2, $zone->getFailureTolerance()); + } + + public function testVariadicSetServers(): void + { + $zone = new AutopilotZone(); + $result = $zone->setServers('a', 'b', 'c'); + + self::assertSame($zone, $result); + self::assertSame(['a', 'b', 'c'], $zone->getServers()); + } + + public function testVariadicSetVoters(): void + { + $zone = new AutopilotZone(); + $result = $zone->setVoters('x', 'y'); + + self::assertSame($zone, $result); + self::assertSame(['x', 'y'], $zone->getVoters()); + } + + public function testVariadicSettersReplaceExisting(): void + { + $zone = new AutopilotZone(Servers: ['old'], Voters: ['old-v']); + + $zone->setServers('new-1'); + $zone->setVoters('new-v-1', 'new-v-2'); + + self::assertSame(['new-1'], $zone->getServers()); + self::assertSame(['new-v-1', 'new-v-2'], $zone->getVoters()); + } + + public function testFluentSetters(): void + { + $zone = new AutopilotZone(); + $result = $zone + ->setServers('s1') + ->setVoters('v1') + ->setFailureTolerance(3); + + self::assertSame($zone, $result); + self::assertSame(3, $zone->getFailureTolerance()); + } + + public function testJsonSerialize(): void + { + $zone = new AutopilotZone( + Servers: ['srv-a'], + Voters: ['vtr-a'], + FailureTolerance: 1, + ); + + $out = $zone->jsonSerialize(); + + self::assertInstanceOf(\stdClass::class, $out); + self::assertSame(['srv-a'], $out->Servers); + self::assertSame(['vtr-a'], $out->Voters); + self::assertSame(1, $out->FailureTolerance); + } + + public function testJsonUnserialize(): void + { + $decoded = new \stdClass(); + $decoded->Servers = ['s1', 's2']; + $decoded->Voters = ['v1']; + $decoded->FailureTolerance = 5; + + $zone = AutopilotZone::jsonUnserialize($decoded); + + self::assertSame(['s1', 's2'], $zone->getServers()); + self::assertSame(['v1'], $zone->getVoters()); + self::assertSame(5, $zone->getFailureTolerance()); + } + + public function testJsonRoundTrip(): void + { + $original = new AutopilotZone( + Servers: ['srv-1', 'srv-2'], + Voters: ['v-1'], + FailureTolerance: 2, + ); + + $restored = AutopilotZone::jsonUnserialize($original->jsonSerialize()); + + self::assertSame($original->getServers(), $restored->getServers()); + self::assertSame($original->getVoters(), $restored->getVoters()); + self::assertSame($original->getFailureTolerance(), $restored->getFailureTolerance()); + } +} + diff --git a/tests/Unit/Operator/AutopilotZoneUpgradeVersionsTest.php b/tests/Unit/Operator/AutopilotZoneUpgradeVersionsTest.php new file mode 100644 index 00000000..6673aa82 --- /dev/null +++ b/tests/Unit/Operator/AutopilotZoneUpgradeVersionsTest.php @@ -0,0 +1,84 @@ +getTargetVersionVoters()); + self::assertSame([], $z->getTargetVersionNonVoters()); + self::assertSame([], $z->getOtherVersionVoters()); + self::assertSame([], $z->getOtherVersionNonVoters()); + } + + public function testConstructorWithValues(): void + { + $z = new AutopilotZoneUpgradeVersions( + TargetVersionVoters: ['a', 'b'], + TargetVersionNonVoters: ['c'], + OtherVersionVoters: ['d'], + OtherVersionNonVoters: ['e', 'f'], + ); + self::assertSame(['a', 'b'], $z->getTargetVersionVoters()); + self::assertSame(['c'], $z->getTargetVersionNonVoters()); + self::assertSame(['d'], $z->getOtherVersionVoters()); + self::assertSame(['e', 'f'], $z->getOtherVersionNonVoters()); + } + + public function testFluentSetters(): void + { + $z = new AutopilotZoneUpgradeVersions(); + $result = $z + ->setTargetVersionVoters('x') + ->setTargetVersionNonVoters('y') + ->setOtherVersionVoters('z') + ->setOtherVersionNonVoters('w'); + self::assertSame($z, $result); + self::assertSame(['x'], $z->getTargetVersionVoters()); + } + + public function testJsonSerializeOmitsEmptyArrays(): void + { + $z = new AutopilotZoneUpgradeVersions(); + $out = $z->jsonSerialize(); + self::assertInstanceOf(\stdClass::class, $out); + self::assertObjectNotHasProperty('TargetVersionVoters', $out); + } + + public function testJsonSerializeIncludesNonEmpty(): void + { + $z = new AutopilotZoneUpgradeVersions(TargetVersionVoters: ['a']); + $out = $z->jsonSerialize(); + self::assertSame(['a'], $out->TargetVersionVoters); + } + + public function testJsonUnserialize(): void + { + $decoded = new \stdClass(); + $decoded->TargetVersionVoters = ['a', 'b']; + $decoded->TargetVersionNonVoters = ['c']; + $decoded->OtherVersionVoters = []; + $decoded->OtherVersionNonVoters = []; + $z = AutopilotZoneUpgradeVersions::jsonUnserialize($decoded); + self::assertSame(['a', 'b'], $z->getTargetVersionVoters()); + } + + public function testJsonRoundTrip(): void + { + $original = new AutopilotZoneUpgradeVersions(TargetVersionVoters: ['v1']); + $json = json_encode($original); + $restored = AutopilotZoneUpgradeVersions::jsonUnserialize(json_decode($json, false)); + self::assertSame(['v1'], $restored->getTargetVersionVoters()); + } +} + diff --git a/tests/Unit/Operator/OperatorHealthReplyTest.php b/tests/Unit/Operator/OperatorHealthReplyTest.php new file mode 100644 index 00000000..f349b766 --- /dev/null +++ b/tests/Unit/Operator/OperatorHealthReplyTest.php @@ -0,0 +1,81 @@ +isHealthy()); + self::assertSame(0, $r->getFailureTolerance()); + self::assertSame([], $r->getServers()); + } + + public function testConstructorWithValues(): void + { + $sh = new ServerHealth(ID: 'srv-1', Healthy: true); + $r = new OperatorHealthReply(Healthy: true, FailureTolerance: 1, Servers: [$sh]); + self::assertTrue($r->isHealthy()); + self::assertSame(1, $r->getFailureTolerance()); + self::assertCount(1, $r->getServers()); + self::assertSame('srv-1', $r->getServers()[0]->getID()); + } + + public function testFluentSetters(): void + { + $r = new OperatorHealthReply(); + $result = $r + ->setHealthy(true) + ->setFailureTolerance(2) + ->setServers(new ServerHealth(ID: 'a'), new ServerHealth(ID: 'b')); + self::assertSame($r, $result); + self::assertCount(2, $r->getServers()); + } + + public function testJsonSerialize(): void + { + $r = new OperatorHealthReply(Healthy: true, FailureTolerance: 1); + $out = $r->jsonSerialize(); + self::assertInstanceOf(\stdClass::class, $out); + self::assertTrue($out->Healthy); + self::assertSame(1, $out->FailureTolerance); + } + + public function testJsonUnserialize(): void + { + $shObj = new \stdClass(); + $shObj->ID = 'sh1'; + $shObj->Name = 'node'; + $shObj->Address = ''; + $shObj->SerfStatus = ''; + $shObj->Version = ''; + $shObj->Leader = false; + $shObj->LastTerm = 0; + $shObj->LastIndex = 0; + $shObj->Healthy = true; + $shObj->Voter = true; + $shObj->StableSince = '2024-01-01T00:00:00Z'; + + $decoded = new \stdClass(); + $decoded->Healthy = true; + $decoded->FailureTolerance = 1; + $decoded->Servers = [$shObj]; + + $r = OperatorHealthReply::jsonUnserialize($decoded); + self::assertTrue($r->isHealthy()); + self::assertSame(1, $r->getFailureTolerance()); + self::assertCount(1, $r->getServers()); + self::assertInstanceOf(ServerHealth::class, $r->getServers()[0]); + } +} + diff --git a/tests/Unit/Operator/RaftConfigurationTest.php b/tests/Unit/Operator/RaftConfigurationTest.php new file mode 100644 index 00000000..7fcb8640 --- /dev/null +++ b/tests/Unit/Operator/RaftConfigurationTest.php @@ -0,0 +1,134 @@ +getServers()); + self::assertSame(0, $rc->getIndex()); + } + + public function testConstructorWithServers(): void + { + $s1 = new RaftServer(ID: 'srv-1', Node: 'node-1'); + $s2 = new RaftServer(ID: 'srv-2', Node: 'node-2'); + + $rc = new RaftConfiguration(Servers: [$s1, $s2], Index: 5); + + self::assertCount(2, $rc->getServers()); + self::assertSame('srv-1', $rc->getServers()[0]->getID()); + self::assertSame('srv-2', $rc->getServers()[1]->getID()); + self::assertSame(5, $rc->getIndex()); + } + + public function testVariadicSetServersReplacesExisting(): void + { + $rc = new RaftConfiguration(Servers: [new RaftServer(ID: 'old')]); + $rc->setServers(new RaftServer(ID: 'new-1'), new RaftServer(ID: 'new-2')); + + self::assertCount(2, $rc->getServers()); + self::assertSame('new-1', $rc->getServers()[0]->getID()); + self::assertSame('new-2', $rc->getServers()[1]->getID()); + } + + public function testVariadicSetServersWithNoArgsClearsArray(): void + { + $rc = new RaftConfiguration(Servers: [new RaftServer(ID: 'x')]); + $rc->setServers(); + + self::assertSame([], $rc->getServers()); + } + + public function testFluentSetters(): void + { + $rc = new RaftConfiguration(); + $result = $rc + ->setServers(new RaftServer(ID: 'a')) + ->setIndex(42); + + self::assertSame($rc, $result); + self::assertSame(42, $rc->getIndex()); + self::assertCount(1, $rc->getServers()); + } + + public function testJsonSerialize(): void + { + $rc = new RaftConfiguration( + Servers: [new RaftServer(ID: 'srv-a', Node: 'n-a', Leader: true, Voter: true)], + Index: 7, + ); + + $out = $rc->jsonSerialize(); + + self::assertInstanceOf(\stdClass::class, $out); + self::assertSame(7, $out->Index); + self::assertIsArray($out->Servers); + self::assertCount(1, $out->Servers); + } + + public function testJsonUnserialize(): void + { + $serverObj = new \stdClass(); + $serverObj->ID = 'srv-z'; + $serverObj->Node = 'node-z'; + $serverObj->Address = '10.0.0.1:8300'; + $serverObj->Leader = true; + $serverObj->ProtocolVersion = '3'; + $serverObj->Voter = true; + + $decoded = new \stdClass(); + $decoded->Servers = [$serverObj]; + $decoded->Index = 15; + + $rc = RaftConfiguration::jsonUnserialize($decoded); + + self::assertSame(15, $rc->getIndex()); + self::assertCount(1, $rc->getServers()); + + $server = $rc->getServers()[0]; + self::assertInstanceOf(RaftServer::class, $server); + self::assertSame('srv-z', $server->getID()); + self::assertSame('node-z', $server->getNode()); + self::assertTrue($server->isLeader()); + self::assertTrue($server->isVoter()); + } + + public function testJsonRoundTrip(): void + { + $original = new RaftConfiguration( + Servers: [ + new RaftServer(ID: 'a', Node: 'n-a', Leader: true, Voter: true), + new RaftServer(ID: 'b', Node: 'n-b', Leader: false, Voter: true), + ], + Index: 42, + ); + + $serialized = $original->jsonSerialize(); + + // Simulate JSON encode/decode cycle + $json = json_encode($serialized); + self::assertIsString($json); + $decoded = json_decode($json); + self::assertInstanceOf(\stdClass::class, $decoded); + + $restored = RaftConfiguration::jsonUnserialize($decoded); + + self::assertSame($original->getIndex(), $restored->getIndex()); + self::assertCount(count($original->getServers()), $restored->getServers()); + self::assertSame($original->getServers()[0]->getID(), $restored->getServers()[0]->getID()); + self::assertSame($original->getServers()[1]->getID(), $restored->getServers()[1]->getID()); + } +} + diff --git a/tests/Unit/Operator/RaftServerTest.php b/tests/Unit/Operator/RaftServerTest.php new file mode 100644 index 00000000..47503c89 --- /dev/null +++ b/tests/Unit/Operator/RaftServerTest.php @@ -0,0 +1,90 @@ +getID()); + self::assertSame('', $r->getNode()); + self::assertSame('', $r->getAddress()); + self::assertFalse($r->isLeader()); + self::assertSame('', $r->getProtocolVersion()); + self::assertFalse($r->isVoter()); + } + + public function testConstructorWithValues(): void + { + $r = new RaftServer( + ID: 'id-1', + Node: 'node-1', + Address: '10.0.0.1:8300', + Leader: true, + ProtocolVersion: '3', + Voter: true, + ); + self::assertSame('id-1', $r->getID()); + self::assertSame('node-1', $r->getNode()); + self::assertSame('10.0.0.1:8300', $r->getAddress()); + self::assertTrue($r->isLeader()); + self::assertSame('3', $r->getProtocolVersion()); + self::assertTrue($r->isVoter()); + } + + public function testFluentSetters(): void + { + $r = new RaftServer(); + $result = $r + ->setID('i') + ->setNode('n') + ->setAddress('a') + ->setLeader(true) + ->setProtocolVersion('2') + ->setVoter(true); + self::assertSame($r, $result); + } + + public function testJsonSerialize(): void + { + $r = new RaftServer(ID: 'x', Node: 'y', Leader: true); + $out = $r->jsonSerialize(); + self::assertInstanceOf(\stdClass::class, $out); + self::assertSame('x', $out->ID); + self::assertTrue($out->Leader); + } + + public function testJsonUnserialize(): void + { + $decoded = new \stdClass(); + $decoded->ID = 'r1'; + $decoded->Node = 'n1'; + $decoded->Address = '10.0.0.1:8300'; + $decoded->Leader = false; + $decoded->ProtocolVersion = '3'; + $decoded->Voter = true; + $r = RaftServer::jsonUnserialize($decoded); + self::assertSame('r1', $r->getID()); + self::assertSame('n1', $r->getNode()); + self::assertTrue($r->isVoter()); + } + + public function testJsonRoundTrip(): void + { + $original = new RaftServer(ID: 'rt', Node: 'n', Address: 'a', Leader: true, Voter: true); + $restored = RaftServer::jsonUnserialize($original->jsonSerialize()); + self::assertSame($original->getID(), $restored->getID()); + self::assertSame($original->getNode(), $restored->getNode()); + self::assertSame($original->isLeader(), $restored->isLeader()); + } +} + diff --git a/tests/Unit/Operator/SerfMemberTest.php b/tests/Unit/Operator/SerfMemberTest.php new file mode 100644 index 00000000..12d1684d --- /dev/null +++ b/tests/Unit/Operator/SerfMemberTest.php @@ -0,0 +1,109 @@ +getID()); + self::assertSame('', $m->getName()); + self::assertSame('', $m->getAddr()); + self::assertSame(0, $m->getPort()); + self::assertSame('', $m->getDatacenter()); + self::assertSame('', $m->getRole()); + self::assertSame('', $m->getBuild()); + self::assertSame(0, $m->getProtocol()); + self::assertSame('', $m->getStatus()); + self::assertSame(0.0, $m->getRTT()->Seconds()); + } + + public function testConstructorWithValues(): void + { + $m = new SerfMember( + ID: 'member-1', + Name: 'node-1', + Addr: '10.0.0.1', + Port: 8301, + Datacenter: 'dc1', + Role: 'consul', + Build: '1.22.0', + Protocol: 2, + Status: 'alive', + RTT: '5ms', + ); + self::assertSame('member-1', $m->getID()); + self::assertSame('node-1', $m->getName()); + self::assertSame('10.0.0.1', $m->getAddr()); + self::assertSame(8301, $m->getPort()); + self::assertSame('dc1', $m->getDatacenter()); + self::assertSame('consul', $m->getRole()); + } + + public function testFluentSetters(): void + { + $m = new SerfMember(); + $result = $m + ->setID('i') + ->setName('n') + ->setAddr('a') + ->setPort(1234) + ->setDatacenter('dc') + ->setRole('r') + ->setBuild('b') + ->setProtocol(2) + ->setStatus('s') + ->setRTT('10ms'); + self::assertSame($m, $result); + } + + public function testJsonSerialize(): void + { + $m = new SerfMember(ID: 'x', Name: 'y', Port: 8301); + $out = $m->jsonSerialize(); + self::assertInstanceOf(\stdClass::class, $out); + self::assertSame('x', $out->ID); + self::assertSame('y', $out->Name); + self::assertSame(8301, $out->Port); + } + + public function testJsonUnserialize(): void + { + $decoded = new \stdClass(); + $decoded->ID = 'sm1'; + $decoded->Name = 'node'; + $decoded->Addr = '10.0.0.1'; + $decoded->Port = 8301; + $decoded->Datacenter = 'dc1'; + $decoded->Role = 'consul'; + $decoded->Build = '1.22.0'; + $decoded->Protocol = 2; + $decoded->Status = 'alive'; + $decoded->RTT = 5000000; // 5ms in nanoseconds + + $m = SerfMember::jsonUnserialize($decoded); + self::assertSame('sm1', $m->getID()); + self::assertSame('node', $m->getName()); + self::assertSame(8301, $m->getPort()); + } + + public function testJsonRoundTrip(): void + { + $original = new SerfMember(ID: 'rt', Name: 'n', Port: 1234); + $json = json_encode($original); + $restored = SerfMember::jsonUnserialize(json_decode($json, false)); + self::assertSame($original->getID(), $restored->getID()); + self::assertSame($original->getName(), $restored->getName()); + self::assertSame($original->getPort(), $restored->getPort()); + } +} + diff --git a/tests/Unit/Operator/ServerHealthTest.php b/tests/Unit/Operator/ServerHealthTest.php new file mode 100644 index 00000000..f984ada6 --- /dev/null +++ b/tests/Unit/Operator/ServerHealthTest.php @@ -0,0 +1,113 @@ +getID()); + self::assertSame('', $s->getName()); + self::assertSame('', $s->getAddress()); + self::assertSame('', $s->getSerfStatus()); + self::assertSame('', $s->getVersion()); + self::assertFalse($s->isLeader()); + self::assertNull($s->getLastContact()); + self::assertSame(0, $s->getLastTerm()); + self::assertSame(0, $s->getLastIndex()); + self::assertFalse($s->isHealthy()); + self::assertFalse($s->isVoter()); + } + + public function testConstructorWithValues(): void + { + $s = new ServerHealth( + ID: 'srv-1', + Name: 'node-1', + Address: '10.0.0.1:8300', + SerfStatus: 'alive', + Version: '1.22.0', + Leader: true, + LastContact: '15ms', + LastTerm: 3, + LastIndex: 100, + Healthy: true, + Voter: true, + ); + self::assertSame('srv-1', $s->getID()); + self::assertSame('node-1', $s->getName()); + self::assertTrue($s->isLeader()); + self::assertNotNull($s->getLastContact()); + self::assertSame(3, $s->getLastTerm()); + self::assertSame(100, $s->getLastIndex()); + self::assertTrue($s->isHealthy()); + self::assertTrue($s->isVoter()); + } + + public function testFluentSetters(): void + { + $s = new ServerHealth(); + $result = $s + ->setID('i') + ->setName('n') + ->setAddress('a') + ->setSerfStatus('alive') + ->setVersion('v') + ->setLeader(true) + ->setLastContact('10ms') + ->setLastTerm(1) + ->setLastIndex(50) + ->setHealthy(true) + ->setVoter(true); + self::assertSame($s, $result); + } + + public function testNullLastContact(): void + { + $s = new ServerHealth(LastContact: '5s'); + self::assertNotNull($s->getLastContact()); + $s->setLastContact(null); + self::assertNull($s->getLastContact()); + } + + public function testJsonSerialize(): void + { + $s = new ServerHealth(ID: 'x', Name: 'y', Healthy: true); + $out = $s->jsonSerialize(); + self::assertInstanceOf(\stdClass::class, $out); + self::assertSame('x', $out->ID); + self::assertTrue($out->Healthy); + } + + public function testJsonUnserialize(): void + { + $decoded = new \stdClass(); + $decoded->ID = 'sh1'; + $decoded->Name = 'node'; + $decoded->Address = '10.0.0.1:8300'; + $decoded->SerfStatus = 'alive'; + $decoded->Version = '1.22.0'; + $decoded->Leader = true; + $decoded->LastContact = '15ms'; + $decoded->LastTerm = 3; + $decoded->LastIndex = 100; + $decoded->Healthy = true; + $decoded->Voter = true; + $decoded->StableSince = '2024-01-01T00:00:00.000000Z'; + + $s = ServerHealth::jsonUnserialize($decoded); + self::assertSame('sh1', $s->getID()); + self::assertTrue($s->isLeader()); + self::assertTrue($s->isHealthy()); + } +} + diff --git a/tests/Unit/Peering/LocalityTest.php b/tests/Unit/Peering/LocalityTest.php new file mode 100644 index 00000000..f83b7ae1 --- /dev/null +++ b/tests/Unit/Peering/LocalityTest.php @@ -0,0 +1,65 @@ +getRegion()); + self::assertSame('', $l->getZone()); + } + + public function testConstructorWithValues(): void + { + $l = new Locality(Region: 'us-east-1', Zone: 'us-east-1a'); + self::assertSame('us-east-1', $l->getRegion()); + self::assertSame('us-east-1a', $l->getZone()); + } + + public function testFluentSetters(): void + { + $l = new Locality(); + $result = $l->setRegion('eu-west-1')->setZone('eu-west-1b'); + self::assertSame($l, $result); + self::assertSame('eu-west-1', $l->getRegion()); + self::assertSame('eu-west-1b', $l->getZone()); + } + + public function testJsonSerialize(): void + { + $l = new Locality(Region: 'us-west-2', Zone: 'us-west-2c'); + $out = $l->jsonSerialize(); + self::assertInstanceOf(\stdClass::class, $out); + self::assertSame('us-west-2', $out->Region); + self::assertSame('us-west-2c', $out->Zone); + } + + public function testJsonUnserialize(): void + { + $decoded = new \stdClass(); + $decoded->Region = 'ap-south-1'; + $decoded->Zone = 'ap-south-1a'; + $l = Locality::jsonUnserialize($decoded); + self::assertSame('ap-south-1', $l->getRegion()); + self::assertSame('ap-south-1a', $l->getZone()); + } + + public function testJsonRoundTrip(): void + { + $original = new Locality(Region: 'us-east-1', Zone: 'us-east-1b'); + $restored = Locality::jsonUnserialize($original->jsonSerialize()); + self::assertSame($original->getRegion(), $restored->getRegion()); + self::assertSame($original->getZone(), $restored->getZone()); + } +} + diff --git a/tests/Unit/PreparedQuery/PreparedQueryDefinitionTest.php b/tests/Unit/PreparedQuery/PreparedQueryDefinitionTest.php new file mode 100644 index 00000000..c98dbea3 --- /dev/null +++ b/tests/Unit/PreparedQuery/PreparedQueryDefinitionTest.php @@ -0,0 +1,68 @@ +getID()); + self::assertSame('', $d->getName()); + self::assertSame('', $d->getSession()); + self::assertSame('', $d->getToken()); + self::assertInstanceOf(ServiceQuery::class, $d->getService()); + self::assertInstanceOf(QueryDNSOptions::class, $d->getDNS()); + self::assertInstanceOf(QueryTemplate::class, $d->getTemplate()); + } + + public function testConstructorWithValues(): void + { + $d = new PreparedQueryDefinition( + ID: 'pq-1', + Name: 'my-query', + Session: 'sess-1', + Token: 'tok-1', + ); + self::assertSame('pq-1', $d->getID()); + self::assertSame('my-query', $d->getName()); + self::assertSame('sess-1', $d->getSession()); + self::assertSame('tok-1', $d->getToken()); + } + + public function testFluentSetters(): void + { + $d = new PreparedQueryDefinition(); + $result = $d + ->setID('i') + ->setName('n') + ->setSession('s') + ->setToken('t') + ->setService(new ServiceQuery(Service: 'web')) + ->setDNS(new QueryDNSOptions(TTL: '5s')) + ->setTemplate(new QueryTemplate(Type: 'tmpl')); + self::assertSame($d, $result); + self::assertSame('web', $d->getService()->getService()); + } + + public function testJsonSerialize(): void + { + $d = new PreparedQueryDefinition(ID: 'x', Name: 'y'); + $out = $d->jsonSerialize(); + self::assertInstanceOf(\stdClass::class, $out); + self::assertSame('x', $out->ID); + self::assertSame('y', $out->Name); + } +} + diff --git a/tests/Unit/PreparedQuery/PreparedQueryExecuteResponseTest.php b/tests/Unit/PreparedQuery/PreparedQueryExecuteResponseTest.php new file mode 100644 index 00000000..bda39da7 --- /dev/null +++ b/tests/Unit/PreparedQuery/PreparedQueryExecuteResponseTest.php @@ -0,0 +1,61 @@ +getService()); + self::assertSame('', $r->getNamespace()); + self::assertSame([], $r->getNodes()); + self::assertSame('', $r->getDatacenter()); + self::assertSame(0, $r->getFailovers()); + } + + public function testConstructorWithValues(): void + { + $r = new PreparedQueryExecuteResponse( + Service: 'web', + Namespace: 'ns', + Datacenter: 'dc1', + Failovers: 2, + ); + self::assertSame('web', $r->getService()); + self::assertSame('ns', $r->getNamespace()); + self::assertSame('dc1', $r->getDatacenter()); + self::assertSame(2, $r->getFailovers()); + } + + public function testFluentSetters(): void + { + $r = new PreparedQueryExecuteResponse(); + $result = $r + ->setService('svc') + ->setNamespace('ns') + ->setDatacenter('dc') + ->setFailovers(1) + ->setDNS(new QueryDNSOptions(TTL: '5s')); + self::assertSame($r, $result); + } + + public function testJsonSerialize(): void + { + $r = new PreparedQueryExecuteResponse(Service: 'web', Datacenter: 'dc1'); + $out = $r->jsonSerialize(); + self::assertInstanceOf(\stdClass::class, $out); + self::assertSame('web', $out->Service); + self::assertSame('dc1', $out->Datacenter); + } +} + diff --git a/tests/Unit/PreparedQuery/QueryDNSOptionsTest.php b/tests/Unit/PreparedQuery/QueryDNSOptionsTest.php new file mode 100644 index 00000000..5417c2b5 --- /dev/null +++ b/tests/Unit/PreparedQuery/QueryDNSOptionsTest.php @@ -0,0 +1,58 @@ +getTTL()); + } + + public function testConstructorWithValues(): void + { + $d = new QueryDNSOptions(TTL: '10s'); + self::assertSame('10s', $d->getTTL()); + } + + public function testFluentSetters(): void + { + $d = new QueryDNSOptions(); + $result = $d->setTTL('30s'); + self::assertSame($d, $result); + self::assertSame('30s', $d->getTTL()); + } + + public function testJsonSerialize(): void + { + $d = new QueryDNSOptions(TTL: '5s'); + $out = $d->jsonSerialize(); + self::assertInstanceOf(\stdClass::class, $out); + self::assertSame('5s', $out->TTL); + } + + public function testJsonUnserialize(): void + { + $decoded = new \stdClass(); + $decoded->TTL = '15s'; + $d = QueryDNSOptions::jsonUnserialize($decoded); + self::assertSame('15s', $d->getTTL()); + } + + public function testJsonRoundTrip(): void + { + $original = new QueryDNSOptions(TTL: '60s'); + $restored = QueryDNSOptions::jsonUnserialize($original->jsonSerialize()); + self::assertSame($original->getTTL(), $restored->getTTL()); + } +} + diff --git a/tests/Unit/PreparedQuery/QueryDatacenterOptionsTest.php b/tests/Unit/PreparedQuery/QueryDatacenterOptionsTest.php new file mode 100644 index 00000000..53e51f87 --- /dev/null +++ b/tests/Unit/PreparedQuery/QueryDatacenterOptionsTest.php @@ -0,0 +1,108 @@ +getNearestN()); + self::assertSame([], $opts->getDatacenters()); + } + + public function testConstructorWithValues(): void + { + $opts = new QueryDatacenterOptions( + NearestN: 3, + Datacenters: ['dc1', 'dc2', 'dc3'], + ); + self::assertSame(3, $opts->getNearestN()); + self::assertSame(['dc1', 'dc2', 'dc3'], $opts->getDatacenters()); + } + + public function testFluentSetters(): void + { + $opts = new QueryDatacenterOptions(); + $result = $opts + ->setNearestN(5) + ->setDatacenters('us-east', 'us-west'); + + self::assertSame($opts, $result); + self::assertSame(5, $opts->getNearestN()); + self::assertSame(['us-east', 'us-west'], $opts->getDatacenters()); + } + + public function testVariadicSetDatacentersReplacesExisting(): void + { + $opts = new QueryDatacenterOptions(Datacenters: ['old-dc']); + $opts->setDatacenters('new-dc-1', 'new-dc-2'); + + self::assertSame(['new-dc-1', 'new-dc-2'], $opts->getDatacenters()); + } + + public function testVariadicSetDatacentersWithNoArgsClearsArray(): void + { + $opts = new QueryDatacenterOptions(Datacenters: ['dc1']); + $opts->setDatacenters(); + + self::assertSame([], $opts->getDatacenters()); + } + + public function testAddDatacenter(): void + { + $opts = new QueryDatacenterOptions(Datacenters: ['dc1']); + $result = $opts->addDatacenter('dc2'); + + self::assertSame($opts, $result); + self::assertSame(['dc1', 'dc2'], $opts->getDatacenters()); + } + + public function testJsonSerialize(): void + { + $opts = new QueryDatacenterOptions( + NearestN: 2, + Datacenters: ['dc-a', 'dc-b'], + ); + + $out = $opts->jsonSerialize(); + + self::assertInstanceOf(\stdClass::class, $out); + self::assertSame(2, $out->NearestN); + self::assertSame(['dc-a', 'dc-b'], $out->Datacenters); + } + + public function testJsonUnserialize(): void + { + $decoded = new \stdClass(); + $decoded->NearestN = 4; + $decoded->Datacenters = ['x', 'y']; + + $opts = QueryDatacenterOptions::jsonUnserialize($decoded); + + self::assertSame(4, $opts->getNearestN()); + self::assertSame(['x', 'y'], $opts->getDatacenters()); + } + + public function testJsonRoundTrip(): void + { + $original = new QueryDatacenterOptions( + NearestN: 3, + Datacenters: ['dc1', 'dc2'], + ); + + $restored = QueryDatacenterOptions::jsonUnserialize($original->jsonSerialize()); + + self::assertSame($original->getNearestN(), $restored->getNearestN()); + self::assertSame($original->getDatacenters(), $restored->getDatacenters()); + } +} + diff --git a/tests/Unit/PreparedQuery/QueryTemplateTest.php b/tests/Unit/PreparedQuery/QueryTemplateTest.php new file mode 100644 index 00000000..b9fc7d91 --- /dev/null +++ b/tests/Unit/PreparedQuery/QueryTemplateTest.php @@ -0,0 +1,62 @@ +getType()); + self::assertSame('', $t->getRegexp()); + } + + public function testConstructorWithValues(): void + { + $t = new QueryTemplate(Type: 'name_prefix_match', Regexp: '^geo-(.+?)$'); + self::assertSame('name_prefix_match', $t->getType()); + self::assertSame('^geo-(.+?)$', $t->getRegexp()); + } + + public function testFluentSetters(): void + { + $t = new QueryTemplate(); + $result = $t->setType('t')->setRegexp('r'); + self::assertSame($t, $result); + } + + public function testJsonSerialize(): void + { + $t = new QueryTemplate(Type: 'test'); + $out = $t->jsonSerialize(); + self::assertInstanceOf(\stdClass::class, $out); + self::assertSame('test', $out->Type); + } + + public function testJsonUnserialize(): void + { + $decoded = new \stdClass(); + $decoded->Type = 'name_prefix_match'; + $decoded->Regexp = '^test-(.+)$'; + $t = QueryTemplate::jsonUnserialize($decoded); + self::assertSame('name_prefix_match', $t->getType()); + self::assertSame('^test-(.+)$', $t->getRegexp()); + } + + public function testJsonRoundTrip(): void + { + $original = new QueryTemplate(Type: 'x', Regexp: 'y'); + $restored = QueryTemplate::jsonUnserialize($original->jsonSerialize()); + self::assertSame($original->getType(), $restored->getType()); + self::assertSame($original->getRegexp(), $restored->getRegexp()); + } +} + diff --git a/tests/Unit/PreparedQuery/ServiceQueryTest.php b/tests/Unit/PreparedQuery/ServiceQueryTest.php new file mode 100644 index 00000000..ab267c96 --- /dev/null +++ b/tests/Unit/PreparedQuery/ServiceQueryTest.php @@ -0,0 +1,91 @@ +getService()); + self::assertSame('', $s->getNamespace()); + self::assertSame('', $s->getNear()); + self::assertSame([], $s->getTags()); + self::assertSame([], $s->getIgnoreCheckIDs()); + self::assertFalse($s->isOnlyPassing()); + self::assertFalse($s->isConnect()); + } + + public function testConstructorWithValues(): void + { + $s = new ServiceQuery( + Service: 'web', + Namespace: 'ns', + Near: '_agent', + Tags: ['v1'], + OnlyPassing: true, + Connect: true, + ); + self::assertSame('web', $s->getService()); + self::assertSame('ns', $s->getNamespace()); + self::assertSame('_agent', $s->getNear()); + self::assertSame(['v1'], $s->getTags()); + self::assertTrue($s->isOnlyPassing()); + self::assertTrue($s->isConnect()); + } + + public function testFluentSetters(): void + { + $s = new ServiceQuery(); + $result = $s + ->setService('svc') + ->setNamespace('ns') + ->setNear('near') + ->setTags('t1', 't2') + ->setIgnoreCheckIDs('c1') + ->setOnlyPassing(true) + ->setConnect(true); + self::assertSame($s, $result); + self::assertSame(['t1', 't2'], $s->getTags()); + } + + public function testJsonSerialize(): void + { + $s = new ServiceQuery(Service: 'web'); + $out = $s->jsonSerialize(); + self::assertInstanceOf(\stdClass::class, $out); + self::assertSame('web', $out->Service); + } + + public function testJsonUnserialize(): void + { + $decoded = new \stdClass(); + $decoded->Service = 'api'; + $decoded->Namespace = ''; + $decoded->Near = ''; + $decoded->Tags = ['v2']; + $decoded->IgnoreCheckIDs = []; + $decoded->OnlyPassing = true; + $decoded->Connect = false; + + $failover = new \stdClass(); + $failover->NearestN = 0; + $failover->Datacenters = []; + $decoded->Failover = $failover; + + $s = ServiceQuery::jsonUnserialize($decoded); + self::assertSame('api', $s->getService()); + self::assertSame(['v2'], $s->getTags()); + self::assertTrue($s->isOnlyPassing()); + } +} + diff --git a/tests/Unit/QueryOptionsTest.php b/tests/Unit/QueryOptionsTest.php new file mode 100644 index 00000000..e20270ee --- /dev/null +++ b/tests/Unit/QueryOptionsTest.php @@ -0,0 +1,143 @@ +getNamespace()); + self::assertSame('', $qo->getDatacenter()); + self::assertFalse($qo->isAllowStale()); + self::assertFalse($qo->isRequireConsistent()); + self::assertFalse($qo->isUseCache()); + self::assertSame(0.0, $qo->getMaxAge()->Seconds()); + self::assertSame(0.0, $qo->getStaleIfError()->Seconds()); + self::assertSame(0, $qo->getWaitIndex()); + self::assertSame('', $qo->getWaitHash()); + self::assertSame(0.0, $qo->getWaitTime()->Seconds()); + self::assertSame('', $qo->getToken()); + self::assertSame('', $qo->getNear()); + self::assertSame('', $qo->getFilter()); + self::assertSame([], $qo->getNodeMeta()); + self::assertSame(0, $qo->getRelayFactor()); + self::assertFalse($qo->isLocalOnly()); + self::assertFalse($qo->isConnect()); + self::assertSame(0.0, $qo->getTimeout()->Seconds()); + self::assertFalse($qo->isPretty()); + } + + public function testConstructorWithValues(): void + { + $qo = new QueryOptions( + Namespace: 'ns', + Datacenter: 'dc1', + AllowStale: true, + Token: 'tok', + Near: '_agent', + Filter: 'Service.Tags contains "web"', + NodeMeta: ['env' => 'prod'], + RelayFactor: 3, + Pretty: true, + ); + self::assertSame('ns', $qo->getNamespace()); + self::assertSame('dc1', $qo->getDatacenter()); + self::assertTrue($qo->isAllowStale()); + self::assertSame('tok', $qo->getToken()); + self::assertSame('_agent', $qo->getNear()); + self::assertSame('Service.Tags contains "web"', $qo->getFilter()); + self::assertSame(['env' => 'prod'], $qo->getNodeMeta()); + self::assertSame(3, $qo->getRelayFactor()); + self::assertTrue($qo->isPretty()); + } + + public function testFluentSetters(): void + { + $qo = new QueryOptions(); + $result = $qo + ->setNamespace('ns') + ->setDatacenter('dc') + ->setAllowStale(true) + ->setRequireConsistent(true) + ->setUseCache(true) + ->setMaxAge('30s') + ->setStaleIfError('60s') + ->setWaitIndex(100) + ->setWaitHash('abc') + ->setWaitTime('5s') + ->setToken('my-token') + ->setNear('_agent') + ->setFilter('f') + ->setNodeMeta(['k' => 'v']) + ->setRelayFactor(2) + ->setLocalOnly(true) + ->setConnect(true) + ->setTimeout('15s') + ->setPretty(true); + + self::assertSame($qo, $result); + self::assertSame('ns', $qo->getNamespace()); + self::assertSame('dc', $qo->getDatacenter()); + self::assertTrue($qo->isAllowStale()); + self::assertTrue($qo->isRequireConsistent()); + self::assertTrue($qo->isUseCache()); + self::assertSame(30.0, $qo->getMaxAge()->Seconds()); + self::assertSame(60.0, $qo->getStaleIfError()->Seconds()); + self::assertSame(100, $qo->getWaitIndex()); + self::assertSame('abc', $qo->getWaitHash()); + self::assertSame(5.0, $qo->getWaitTime()->Seconds()); + self::assertSame('my-token', $qo->getToken()); + self::assertSame('_agent', $qo->getNear()); + self::assertSame('f', $qo->getFilter()); + self::assertSame(['k' => 'v'], $qo->getNodeMeta()); + self::assertSame(2, $qo->getRelayFactor()); + self::assertTrue($qo->isLocalOnly()); + self::assertTrue($qo->isConnect()); + self::assertSame(15.0, $qo->getTimeout()->Seconds()); + self::assertTrue($qo->isPretty()); + } + + public function testNodeMetaIsKeyedMap(): void + { + $qo = new QueryOptions(NodeMeta: ['env' => 'staging', 'region' => 'us-east']); + $meta = $qo->getNodeMeta(); + + self::assertArrayHasKey('env', $meta); + self::assertArrayHasKey('region', $meta); + self::assertSame('staging', $meta['env']); + self::assertSame('us-east', $meta['region']); + } + + public function testSetNodeMetaReplacesExisting(): void + { + $qo = new QueryOptions(NodeMeta: ['old' => 'val']); + $qo->setNodeMeta(['new' => 'val2']); + + self::assertSame(['new' => 'val2'], $qo->getNodeMeta()); + } + + public function testDurationCoercionFromString(): void + { + $qo = new QueryOptions(MaxAge: '1m', StaleIfError: '2m', WaitTime: '30s', Timeout: '10s'); + self::assertSame(60.0, $qo->getMaxAge()->Seconds()); + self::assertSame(120.0, $qo->getStaleIfError()->Seconds()); + self::assertSame(30.0, $qo->getWaitTime()->Seconds()); + self::assertSame(10.0, $qo->getTimeout()->Seconds()); + } + + public function testDurationCoercionFromNanoseconds(): void + { + $qo = new QueryOptions(MaxAge: 5000000000); // 5s in nanoseconds + self::assertSame(5.0, $qo->getMaxAge()->Seconds()); + } +} + diff --git a/tests/Unit/Session/ServiceCheckTest.php b/tests/Unit/Session/ServiceCheckTest.php new file mode 100644 index 00000000..57a11fb4 --- /dev/null +++ b/tests/Unit/Session/ServiceCheckTest.php @@ -0,0 +1,72 @@ +getID()); + self::assertSame('', $sc->getNamespace()); + } + + public function testConstructorWithValues(): void + { + $sc = new ServiceCheck(ID: 'check-1', Namespace: 'ns-1'); + self::assertSame('check-1', $sc->getID()); + self::assertSame('ns-1', $sc->getNamespace()); + } + + public function testFluentSetters(): void + { + $sc = new ServiceCheck(); + $result = $sc->setID('id')->setNamespace('ns'); + self::assertSame($sc, $result); + self::assertSame('id', $sc->getID()); + self::assertSame('ns', $sc->getNamespace()); + } + + public function testJsonSerialize(): void + { + $sc = new ServiceCheck(ID: 'sc-1', Namespace: 'default'); + $out = $sc->jsonSerialize(); + self::assertInstanceOf(\stdClass::class, $out); + self::assertSame('sc-1', $out->ID); + self::assertSame('default', $out->Namespace); + } + + public function testJsonSerializeOmitsEmptyNamespace(): void + { + $sc = new ServiceCheck(ID: 'sc-1'); + $out = $sc->jsonSerialize(); + self::assertObjectNotHasProperty('Namespace', $out); + } + + public function testJsonUnserialize(): void + { + $decoded = new \stdClass(); + $decoded->ID = 'sc-from-json'; + $decoded->Namespace = 'my-ns'; + $sc = ServiceCheck::jsonUnserialize($decoded); + self::assertSame('sc-from-json', $sc->getID()); + self::assertSame('my-ns', $sc->getNamespace()); + } + + public function testJsonRoundTrip(): void + { + $original = new ServiceCheck(ID: 'rt', Namespace: 'ns'); + $restored = ServiceCheck::jsonUnserialize($original->jsonSerialize()); + self::assertSame($original->getID(), $restored->getID()); + self::assertSame($original->getNamespace(), $restored->getNamespace()); + } +} + diff --git a/tests/Unit/Session/SessionEntryTest.php b/tests/Unit/Session/SessionEntryTest.php new file mode 100644 index 00000000..e6401e3a --- /dev/null +++ b/tests/Unit/Session/SessionEntryTest.php @@ -0,0 +1,228 @@ +getCreateIndex()); + self::assertSame('', $se->getID()); + self::assertSame('', $se->getName()); + self::assertSame('', $se->getNode()); + self::assertSame('', $se->getBehavior()); + self::assertSame('', $se->getTTL()); + self::assertSame('', $se->getNamespace()); + self::assertSame([], $se->getChecks()); + self::assertSame([], $se->getNodeChecks()); + self::assertSame([], $se->getServiceChecks()); + } + + public function testConstructorWithValues(): void + { + $sc = new ServiceCheck(ID: 'svc-check-1', Namespace: 'ns'); + $se = new SessionEntry( + CreateIndex: 10, + ID: 'sess-1', + Name: 'my-session', + Node: 'node-1', + Behavior: 'release', + TTL: '30s', + Namespace: 'default', + Checks: ['serfHealth'], + NodeChecks: ['node-check-1'], + ServiceChecks: [$sc], + ); + + self::assertSame(10, $se->getCreateIndex()); + self::assertSame('sess-1', $se->getID()); + self::assertSame('my-session', $se->getName()); + self::assertSame('node-1', $se->getNode()); + self::assertSame('release', $se->getBehavior()); + self::assertSame('30s', $se->getTTL()); + self::assertSame('default', $se->getNamespace()); + self::assertSame(['serfHealth'], $se->getChecks()); + self::assertSame(['node-check-1'], $se->getNodeChecks()); + self::assertCount(1, $se->getServiceChecks()); + self::assertSame('svc-check-1', $se->getServiceChecks()[0]->getID()); + } + + public function testVariadicSetChecks(): void + { + $se = new SessionEntry(); + $result = $se->setChecks('check-a', 'check-b'); + + self::assertSame($se, $result); + self::assertSame(['check-a', 'check-b'], $se->getChecks()); + } + + public function testVariadicSetNodeChecks(): void + { + $se = new SessionEntry(); + $result = $se->setNodeChecks('nc-1', 'nc-2', 'nc-3'); + + self::assertSame($se, $result); + self::assertSame(['nc-1', 'nc-2', 'nc-3'], $se->getNodeChecks()); + } + + public function testVariadicSetServiceChecks(): void + { + $sc1 = new ServiceCheck(ID: 'sc-1'); + $sc2 = new ServiceCheck(ID: 'sc-2'); + + $se = new SessionEntry(); + $result = $se->setServiceChecks($sc1, $sc2); + + self::assertSame($se, $result); + self::assertCount(2, $se->getServiceChecks()); + self::assertSame('sc-1', $se->getServiceChecks()[0]->getID()); + self::assertSame('sc-2', $se->getServiceChecks()[1]->getID()); + } + + public function testVariadicSettersReplaceExisting(): void + { + $se = new SessionEntry( + Checks: ['old'], + NodeChecks: ['old-nc'], + ServiceChecks: [new ServiceCheck(ID: 'old-sc')], + ); + + $se->setChecks('new'); + $se->setNodeChecks('new-nc'); + $se->setServiceChecks(new ServiceCheck(ID: 'new-sc')); + + self::assertSame(['new'], $se->getChecks()); + self::assertSame(['new-nc'], $se->getNodeChecks()); + self::assertCount(1, $se->getServiceChecks()); + self::assertSame('new-sc', $se->getServiceChecks()[0]->getID()); + } + + public function testFluentSetters(): void + { + $se = new SessionEntry(); + $result = $se + ->setCreateIndex(1) + ->setID('id') + ->setName('name') + ->setNode('node') + ->setBehavior('delete') + ->setTTL('60s') + ->setNamespace('ns') + ->setChecks('c1') + ->setNodeChecks('nc1') + ->setServiceChecks(new ServiceCheck(ID: 'sc1')); + + self::assertSame($se, $result); + } + + public function testJsonSerialize(): void + { + $se = new SessionEntry( + CreateIndex: 5, + ID: 'sess-x', + Name: 'test', + Node: 'n1', + Behavior: 'release', + TTL: '15s', + Checks: ['serfHealth'], + NodeChecks: ['nc1'], + ServiceChecks: [new ServiceCheck(ID: 'sc1', Namespace: 'ns')], + ); + + $out = $se->jsonSerialize(); + + self::assertInstanceOf(\stdClass::class, $out); + self::assertSame(5, $out->CreateIndex); + self::assertSame('sess-x', $out->ID); + self::assertSame('test', $out->Name); + self::assertSame('release', $out->Behavior); + self::assertSame(['serfHealth'], $out->Checks); + self::assertSame(['nc1'], $out->NodeChecks); + self::assertIsArray($out->ServiceChecks); + self::assertCount(1, $out->ServiceChecks); + } + + public function testJsonSerializeOmitsEmptyNamespace(): void + { + $se = new SessionEntry(); + $out = $se->jsonSerialize(); + + self::assertObjectNotHasProperty('Namespace', $out); + } + + public function testJsonSerializeIncludesNonEmptyNamespace(): void + { + $se = new SessionEntry(Namespace: 'my-ns'); + $out = $se->jsonSerialize(); + + self::assertSame('my-ns', $out->Namespace); + } + + public function testJsonUnserialize(): void + { + $scObj = new \stdClass(); + $scObj->ID = 'sc-unserialized'; + $scObj->Namespace = 'ns'; + + $decoded = new \stdClass(); + $decoded->CreateIndex = 20; + $decoded->ID = 'sess-from-json'; + $decoded->Name = 'json-session'; + $decoded->Node = 'json-node'; + $decoded->LockDelay = 15000000000; // 15 seconds in nanoseconds + $decoded->Behavior = 'release'; + $decoded->TTL = '30s'; + $decoded->Checks = ['serfHealth']; + $decoded->NodeChecks = ['nc1']; + $decoded->ServiceChecks = [$scObj]; + + $se = SessionEntry::jsonUnserialize($decoded); + + self::assertSame(20, $se->getCreateIndex()); + self::assertSame('sess-from-json', $se->getID()); + self::assertSame('json-session', $se->getName()); + self::assertSame('json-node', $se->getNode()); + self::assertSame('release', $se->getBehavior()); + self::assertSame('30s', $se->getTTL()); + self::assertSame(['serfHealth'], $se->getChecks()); + self::assertSame(['nc1'], $se->getNodeChecks()); + self::assertCount(1, $se->getServiceChecks()); + self::assertInstanceOf(ServiceCheck::class, $se->getServiceChecks()[0]); + self::assertSame('sc-unserialized', $se->getServiceChecks()[0]->getID()); + } + + public function testLockDelayDurationHandling(): void + { + // Integer nanoseconds + $se = new SessionEntry(LockDelay: 5000000000); + self::assertSame(5.0, $se->getLockDelay()->Seconds()); + + // String duration + $se2 = new SessionEntry(LockDelay: '10s'); + self::assertSame(10.0, $se2->getLockDelay()->Seconds()); + + // Null defaults to zero + $se3 = new SessionEntry(); + self::assertSame(0.0, $se3->getLockDelay()->Seconds()); + } + + public function testSetLockDelay(): void + { + $se = new SessionEntry(); + $result = $se->setLockDelay('5s'); + + self::assertSame($se, $result); + self::assertSame(5.0, $se->getLockDelay()->Seconds()); + } +} + diff --git a/tests/Unit/Txn/CheckTxnOpTest.php b/tests/Unit/Txn/CheckTxnOpTest.php new file mode 100644 index 00000000..9b4ed91c --- /dev/null +++ b/tests/Unit/Txn/CheckTxnOpTest.php @@ -0,0 +1,46 @@ +getCheck()); + } + + public function testConstructorWithValues(): void + { + $check = new HealthCheck(Node: 'node-1', Name: 'my-check'); + $op = new CheckTxnOp(Check: $check); + self::assertSame('node-1', $op->getCheck()->getNode()); + self::assertSame('my-check', $op->getCheck()->getName()); + } + + public function testFluentSetters(): void + { + $op = new CheckTxnOp(); + $check = new HealthCheck(Name: 'test'); + $result = $op->setCheck($check); + self::assertSame($op, $result); + self::assertSame('test', $op->getCheck()->getName()); + } + + public function testJsonSerialize(): void + { + $op = new CheckTxnOp(Check: new HealthCheck(Name: 'hc')); + $out = $op->jsonSerialize(); + self::assertInstanceOf(\stdClass::class, $out); + } +} + diff --git a/tests/Unit/Txn/KVTxnOpTest.php b/tests/Unit/Txn/KVTxnOpTest.php new file mode 100644 index 00000000..1a336b20 --- /dev/null +++ b/tests/Unit/Txn/KVTxnOpTest.php @@ -0,0 +1,127 @@ +getVerb()); + self::assertSame('', $op->getKey()); + self::assertSame('', $op->getValue()); + self::assertSame(0, $op->getFlags()); + self::assertSame(0, $op->getIndex()); + self::assertSame('', $op->getSession()); + self::assertSame('', $op->getNamespace()); + self::assertSame('', $op->getPartition()); + } + + public function testConstructorWithEnumVerb(): void + { + $op = new KVTxnOp(Verb: KVOp::KVSet, Key: 'test/key', Value: 'val'); + self::assertSame(KVOp::KVSet, $op->getVerb()); + self::assertSame('test/key', $op->getKey()); + } + + public function testConstructorWithStringVerb(): void + { + $op = new KVTxnOp(Verb: 'get', Key: 'foo'); + self::assertSame(KVOp::KVGet, $op->getVerb()); + } + + public function testSetVerbWithString(): void + { + $op = new KVTxnOp(); + $result = $op->setVerb('set'); + self::assertSame($op, $result); + self::assertSame(KVOp::KVSet, $op->getVerb()); + } + + public function testSetVerbWithEnum(): void + { + $op = new KVTxnOp(); + $op->setVerb(KVOp::KVDelete); + self::assertSame(KVOp::KVDelete, $op->getVerb()); + } + + public function testFluentSetters(): void + { + $op = new KVTxnOp(); + $result = $op + ->setVerb(KVOp::KVSet) + ->setKey('my/key') + ->setValue('my-value') + ->setFlags(5) + ->setIndex(10) + ->setSession('sess-1') + ->setNamespace('ns') + ->setPartition('pt'); + + self::assertSame($op, $result); + self::assertSame('my/key', $op->getKey()); + self::assertSame('my-value', $op->getValue()); + self::assertSame(5, $op->getFlags()); + self::assertSame(10, $op->getIndex()); + self::assertSame('sess-1', $op->getSession()); + self::assertSame('ns', $op->getNamespace()); + self::assertSame('pt', $op->getPartition()); + } + + public function testJsonSerializeOmitsEmptyNamespaceAndPartition(): void + { + $op = new KVTxnOp(Verb: KVOp::KVGet, Key: 'k'); + $out = $op->jsonSerialize(); + self::assertObjectNotHasProperty('Namespace', $out); + self::assertObjectNotHasProperty('Partition', $out); + } + + public function testJsonSerializeIncludesNonEmptyNamespaceAndPartition(): void + { + $op = new KVTxnOp(Verb: KVOp::KVGet, Key: 'k', Namespace: 'ns', Partition: 'pt'); + $out = $op->jsonSerialize(); + self::assertSame('ns', $out->Namespace); + self::assertSame('pt', $out->Partition); + } + + public function testJsonUnserializeBase64DecodesValue(): void + { + $decoded = new \stdClass(); + $decoded->Verb = 'set'; + $decoded->Key = 'test'; + $decoded->Value = base64_encode('hello'); + $decoded->Flags = 0; + $decoded->Index = 0; + $decoded->Session = ''; + + $op = KVTxnOp::jsonUnserialize($decoded); + self::assertSame(KVOp::KVSet, $op->getVerb()); + self::assertSame('hello', $op->getValue()); + } + + public function testJsonUnserializeThrowsOnInvalidBase64(): void + { + $this->expectException(\DomainException::class); + $decoded = new \stdClass(); + $decoded->Verb = 'get'; + $decoded->Key = 'k'; + $decoded->Value = '!!!invalid!!!'; + KVTxnOp::jsonUnserialize($decoded); + } + + public function testConstructorWithInvalidStringVerbThrows(): void + { + $this->expectException(\ValueError::class); + new KVTxnOp(Verb: 'not-a-valid-verb'); + } +} + diff --git a/tests/Unit/Txn/KVTxnResponseTest.php b/tests/Unit/Txn/KVTxnResponseTest.php new file mode 100644 index 00000000..96ef3cdb --- /dev/null +++ b/tests/Unit/Txn/KVTxnResponseTest.php @@ -0,0 +1,72 @@ +getResults()); + self::assertSame([], $r->getErrors()); + } + + public function testConstructorWithValues(): void + { + $result = new TxnResult(); + $error = new TxnError(OpIndex: 0, What: 'err'); + $r = new KVTxnResponse(Results: [$result], Errors: [$error]); + self::assertCount(1, $r->getResults()); + self::assertCount(1, $r->getErrors()); + self::assertSame('err', $r->getErrors()[0]->getWhat()); + } + + public function testFluentSetters(): void + { + $r = new KVTxnResponse(); + $result = $r + ->setResults(new TxnResult(), new TxnResult()) + ->setErrors(new TxnError(OpIndex: 1, What: 'x')); + self::assertSame($r, $result); + self::assertCount(2, $r->getResults()); + self::assertCount(1, $r->getErrors()); + } + + public function testJsonSerialize(): void + { + $r = new KVTxnResponse(Results: [new TxnResult()], Errors: [new TxnError(OpIndex: 0, What: 'e')]); + $out = $r->jsonSerialize(); + self::assertInstanceOf(\stdClass::class, $out); + self::assertIsArray($out->Results); + self::assertIsArray($out->Errors); + } + + public function testJsonUnserialize(): void + { + $resultObj = new \stdClass(); + $errorObj = new \stdClass(); + $errorObj->OpIndex = 2; + $errorObj->What = 'failed'; + + $decoded = new \stdClass(); + $decoded->Results = [$resultObj]; + $decoded->Errors = [$errorObj]; + + $r = KVTxnResponse::jsonUnserialize($decoded); + self::assertCount(1, $r->getResults()); + self::assertInstanceOf(TxnResult::class, $r->getResults()[0]); + self::assertCount(1, $r->getErrors()); + self::assertSame('failed', $r->getErrors()[0]->getWhat()); + } +} + diff --git a/tests/Unit/Txn/NodeTxnOpTest.php b/tests/Unit/Txn/NodeTxnOpTest.php new file mode 100644 index 00000000..b4fca7cf --- /dev/null +++ b/tests/Unit/Txn/NodeTxnOpTest.php @@ -0,0 +1,46 @@ +getNode()); + } + + public function testConstructorWithValues(): void + { + $node = new Node(Node: 'node-1', Address: '10.0.0.1'); + $op = new NodeTxnOp(Node: $node); + self::assertSame('node-1', $op->getNode()->getNode()); + self::assertSame('10.0.0.1', $op->getNode()->getAddress()); + } + + public function testFluentSetters(): void + { + $op = new NodeTxnOp(); + $node = new Node(Node: 'n'); + $result = $op->setNode($node); + self::assertSame($op, $result); + self::assertSame('n', $op->getNode()->getNode()); + } + + public function testJsonSerialize(): void + { + $op = new NodeTxnOp(Node: new Node(Node: 'x')); + $out = $op->jsonSerialize(); + self::assertInstanceOf(\stdClass::class, $out); + } +} + diff --git a/tests/Unit/Txn/ServiceTxnOpTest.php b/tests/Unit/Txn/ServiceTxnOpTest.php new file mode 100644 index 00000000..06d487b6 --- /dev/null +++ b/tests/Unit/Txn/ServiceTxnOpTest.php @@ -0,0 +1,47 @@ +getNode()); + self::assertInstanceOf(AgentService::class, $op->getService()); + } + + public function testConstructorWithValues(): void + { + $svc = new AgentService(ID: 'svc-1', Service: 'web'); + $op = new ServiceTxnOp(Node: 'node-1', Service: $svc); + self::assertSame('node-1', $op->getNode()); + self::assertSame('svc-1', $op->getService()->getID()); + } + + public function testFluentSetters(): void + { + $op = new ServiceTxnOp(); + $svc = new AgentService(ID: 'x'); + $result = $op->setNode('n')->setService($svc); + self::assertSame($op, $result); + self::assertSame('n', $op->getNode()); + } + + public function testJsonSerialize(): void + { + $op = new ServiceTxnOp(Node: 'n', Service: new AgentService(ID: 's')); + $out = $op->jsonSerialize(); + self::assertInstanceOf(\stdClass::class, $out); + } +} + diff --git a/tests/Unit/Txn/TxnErrorTest.php b/tests/Unit/Txn/TxnErrorTest.php new file mode 100644 index 00000000..3f509fb5 --- /dev/null +++ b/tests/Unit/Txn/TxnErrorTest.php @@ -0,0 +1,73 @@ +getOpIndex()); + self::assertSame('', $err->getWhat()); + } + + public function testConstructorWithValues(): void + { + $err = new TxnError(OpIndex: 5, What: 'permission denied'); + self::assertSame(5, $err->getOpIndex()); + self::assertSame('permission denied', $err->getWhat()); + } + + public function testFluentSetters(): void + { + $err = new TxnError(); + $result = $err + ->setOpIndex(3) + ->setWhat('timeout'); + + self::assertSame($err, $result); + self::assertSame(3, $err->getOpIndex()); + self::assertSame('timeout', $err->getWhat()); + } + + public function testJsonSerialize(): void + { + $err = new TxnError(OpIndex: 7, What: 'key not found'); + $out = $err->jsonSerialize(); + + self::assertInstanceOf(\stdClass::class, $out); + self::assertSame(7, $out->OpIndex); + self::assertSame('key not found', $out->What); + } + + public function testJsonUnserialize(): void + { + $decoded = new \stdClass(); + $decoded->OpIndex = 4; + $decoded->What = 'cas mismatch'; + + $err = TxnError::jsonUnserialize($decoded); + + self::assertSame(4, $err->getOpIndex()); + self::assertSame('cas mismatch', $err->getWhat()); + } + + public function testJsonRoundTrip(): void + { + $original = new TxnError(OpIndex: 9, What: 'round trip error'); + + $restored = TxnError::jsonUnserialize($original->jsonSerialize()); + + self::assertSame($original->getOpIndex(), $restored->getOpIndex()); + self::assertSame($original->getWhat(), $restored->getWhat()); + } +} + diff --git a/tests/Unit/Txn/TxnOpTest.php b/tests/Unit/Txn/TxnOpTest.php new file mode 100644 index 00000000..22efcc2f --- /dev/null +++ b/tests/Unit/Txn/TxnOpTest.php @@ -0,0 +1,56 @@ +getKV()); + self::assertNull($op->getNode()); + self::assertNull($op->getService()); + self::assertNull($op->getCheck()); + } + + public function testConstructorWithKV(): void + { + $kvOp = new KVTxnOp(Key: 'test'); + $op = new TxnOp(KV: $kvOp); + self::assertNotNull($op->getKV()); + self::assertSame('test', $op->getKV()->getKey()); + } + + public function testFluentSetters(): void + { + $op = new TxnOp(); + $result = $op->setKV(null)->setNode(null)->setService(null)->setCheck(null); + self::assertSame($op, $result); + } + + public function testJsonSerializeOmitsNulls(): void + { + $op = new TxnOp(); + $out = $op->jsonSerialize(); + self::assertInstanceOf(\stdClass::class, $out); + self::assertObjectNotHasProperty('KV', $out); + self::assertObjectNotHasProperty('Node', $out); + } + + public function testJsonSerializeIncludesNonNull(): void + { + $op = new TxnOp(KV: new KVTxnOp(Key: 'k')); + $out = $op->jsonSerialize(); + self::assertObjectHasProperty('KV', $out); + } +} + diff --git a/tests/Unit/Txn/TxnOpsTest.php b/tests/Unit/Txn/TxnOpsTest.php new file mode 100644 index 00000000..d7bb1f82 --- /dev/null +++ b/tests/Unit/Txn/TxnOpsTest.php @@ -0,0 +1,98 @@ +count()); + } + + public function testArrayAccessExists(): void + { + $ops = new TxnOps([new TxnOp()]); + self::assertTrue(isset($ops[0])); + self::assertFalse(isset($ops[1])); + } + + public function testArrayAccessGet(): void + { + $op = new TxnOp(); + $ops = new TxnOps([$op]); + self::assertSame($op, $ops[0]); + } + + public function testArrayAccessAppend(): void + { + $ops = new TxnOps(); + $ops[] = new TxnOp(); + self::assertCount(1, $ops); + } + + public function testArrayAccessSet(): void + { + $ops = new TxnOps([new TxnOp()]); + $newOp = new TxnOp(); + $ops[0] = $newOp; + self::assertSame($newOp, $ops[0]); + } + + public function testArrayAccessUnset(): void + { + $ops = new TxnOps([new TxnOp()]); + unset($ops[0]); + self::assertFalse(isset($ops[0])); + } + + public function testIteratorAggregate(): void + { + $op1 = new TxnOp(); + $op2 = new TxnOp(); + $ops = new TxnOps([$op1, $op2]); + $items = []; + foreach ($ops as $op) { + $items[] = $op; + } + self::assertCount(2, $items); + self::assertSame($op1, $items[0]); + } + + public function testAll(): void + { + $op = new TxnOp(); + $ops = new TxnOps([$op]); + self::assertSame([$op], $ops->all()); + } + + public function testJsonSerialize(): void + { + $ops = new TxnOps([new TxnOp()]); + $out = $ops->jsonSerialize(); + self::assertIsArray($out); + self::assertCount(1, $out); + } +} + diff --git a/tests/Unit/Txn/TxnResponseTest.php b/tests/Unit/Txn/TxnResponseTest.php new file mode 100644 index 00000000..aa4fe5da --- /dev/null +++ b/tests/Unit/Txn/TxnResponseTest.php @@ -0,0 +1,122 @@ +getResults()); + self::assertSame([], $resp->getErrors()); + } + + public function testConstructorWithValues(): void + { + $r1 = new TxnResult(); + $e1 = new TxnError(OpIndex: 0, What: 'fail'); + + $resp = new TxnResponse(Results: [$r1], Errors: [$e1]); + + self::assertCount(1, $resp->getResults()); + self::assertCount(1, $resp->getErrors()); + self::assertSame('fail', $resp->getErrors()[0]->getWhat()); + } + + public function testVariadicSetResults(): void + { + $resp = new TxnResponse(); + $r1 = new TxnResult(); + $r2 = new TxnResult(); + $result = $resp->setResults($r1, $r2); + + self::assertSame($resp, $result); + self::assertCount(2, $resp->getResults()); + } + + public function testVariadicSetErrors(): void + { + $resp = new TxnResponse(); + $e1 = new TxnError(OpIndex: 0, What: 'a'); + $e2 = new TxnError(OpIndex: 1, What: 'b'); + $result = $resp->setErrors($e1, $e2); + + self::assertSame($resp, $result); + self::assertCount(2, $resp->getErrors()); + self::assertSame('a', $resp->getErrors()[0]->getWhat()); + self::assertSame('b', $resp->getErrors()[1]->getWhat()); + } + + public function testVariadicSettersReplaceExisting(): void + { + $resp = new TxnResponse( + Results: [new TxnResult()], + Errors: [new TxnError(OpIndex: 0, What: 'old')], + ); + + $resp->setResults(); + $resp->setErrors(); + + self::assertSame([], $resp->getResults()); + self::assertSame([], $resp->getErrors()); + } + + public function testJsonSerialize(): void + { + $resp = new TxnResponse( + Errors: [new TxnError(OpIndex: 3, What: 'err')], + ); + + $out = $resp->jsonSerialize(); + + self::assertInstanceOf(\stdClass::class, $out); + self::assertSame([], $out->Results); + self::assertIsArray($out->Errors); + self::assertCount(1, $out->Errors); + } + + public function testJsonUnserialize(): void + { + $errObj = new \stdClass(); + $errObj->OpIndex = 2; + $errObj->What = 'something failed'; + + $resultObj = new \stdClass(); + + $decoded = new \stdClass(); + $decoded->Results = [$resultObj]; + $decoded->Errors = [$errObj]; + + $resp = TxnResponse::jsonUnserialize($decoded); + + self::assertCount(1, $resp->getResults()); + self::assertInstanceOf(TxnResult::class, $resp->getResults()[0]); + self::assertCount(1, $resp->getErrors()); + self::assertInstanceOf(TxnError::class, $resp->getErrors()[0]); + self::assertSame(2, $resp->getErrors()[0]->getOpIndex()); + self::assertSame('something failed', $resp->getErrors()[0]->getWhat()); + } + + public function testJsonUnserializeHandlesNullArrays(): void + { + $decoded = new \stdClass(); + $decoded->Results = null; + $decoded->Errors = null; + + $resp = TxnResponse::jsonUnserialize($decoded); + + self::assertSame([], $resp->getResults()); + self::assertSame([], $resp->getErrors()); + } +} + diff --git a/tests/Unit/Txn/TxnResultTest.php b/tests/Unit/Txn/TxnResultTest.php new file mode 100644 index 00000000..8f647c68 --- /dev/null +++ b/tests/Unit/Txn/TxnResultTest.php @@ -0,0 +1,62 @@ +getKV()); + self::assertNull($r->getNode()); + self::assertNull($r->getService()); + self::assertNull($r->getCheck()); + } + + public function testConstructorWithValues(): void + { + $kv = new KVPair(Key: 'test'); + $r = new TxnResult(KV: $kv); + self::assertNotNull($r->getKV()); + self::assertSame('test', $r->getKV()->getKey()); + self::assertNull($r->getNode()); + } + + public function testFluentSetters(): void + { + $r = new TxnResult(); + $kv = new KVPair(Key: 'k'); + $result = $r->setKV($kv)->setNode(null)->setService(null)->setCheck(null); + self::assertSame($r, $result); + self::assertNotNull($r->getKV()); + } + + public function testJsonSerialize(): void + { + $r = new TxnResult(KV: new KVPair(Key: 'foo')); + $out = $r->jsonSerialize(); + self::assertInstanceOf(\stdClass::class, $out); + self::assertObjectHasProperty('KV', $out); + self::assertObjectNotHasProperty('Node', $out); + } + + public function testJsonSerializeOmitsNulls(): void + { + $r = new TxnResult(); + $out = $r->jsonSerialize(); + self::assertObjectNotHasProperty('KV', $out); + self::assertObjectNotHasProperty('Node', $out); + self::assertObjectNotHasProperty('Service', $out); + self::assertObjectNotHasProperty('Check', $out); + } +} + diff --git a/tests/Unit/Txn/TxnResultsTest.php b/tests/Unit/Txn/TxnResultsTest.php new file mode 100644 index 00000000..9c9e359a --- /dev/null +++ b/tests/Unit/Txn/TxnResultsTest.php @@ -0,0 +1,71 @@ +count()); + } + + public function testArrayAccess(): void + { + $result = new TxnResult(); + $r = new TxnResults([$result]); + self::assertTrue(isset($r[0])); + self::assertSame($result, $r[0]); + $r[] = new TxnResult(); + self::assertCount(2, $r); + unset($r[0]); + self::assertFalse(isset($r[0])); + } + + public function testIteratorAggregate(): void + { + $r = new TxnResults([new TxnResult(), new TxnResult()]); + $items = []; + foreach ($r as $result) { + $items[] = $result; + } + self::assertCount(2, $items); + } + + public function testAll(): void + { + $result = new TxnResult(); + $r = new TxnResults([$result]); + self::assertSame([$result], $r->all()); + } + + public function testJsonSerialize(): void + { + $r = new TxnResults([new TxnResult()]); + $out = $r->jsonSerialize(); + self::assertIsArray($out); + self::assertCount(1, $out); + } +} + diff --git a/tests/Unit/WriteOptionsTest.php b/tests/Unit/WriteOptionsTest.php new file mode 100644 index 00000000..0a3d1324 --- /dev/null +++ b/tests/Unit/WriteOptionsTest.php @@ -0,0 +1,75 @@ +getNamespace()); + self::assertSame('', $wo->getDatacenter()); + self::assertSame('', $wo->getToken()); + self::assertSame(0, $wo->getRelayFactor()); + self::assertSame(0.0, $wo->getTimeout()->Seconds()); + } + + public function testConstructorWithValues(): void + { + $wo = new WriteOptions( + Namespace: 'ns1', + Datacenter: 'dc1', + Token: 'tok-123', + RelayFactor: 2, + Timeout: '5s', + ); + self::assertSame('ns1', $wo->getNamespace()); + self::assertSame('dc1', $wo->getDatacenter()); + self::assertSame('tok-123', $wo->getToken()); + self::assertSame(2, $wo->getRelayFactor()); + self::assertSame(5.0, $wo->getTimeout()->Seconds()); + } + + public function testFluentSetters(): void + { + $wo = new WriteOptions(); + $result = $wo + ->setNamespace('ns') + ->setDatacenter('dc') + ->setToken('t') + ->setRelayFactor(1) + ->setTimeout('10s'); + + self::assertSame($wo, $result); + self::assertSame('ns', $wo->getNamespace()); + self::assertSame('dc', $wo->getDatacenter()); + self::assertSame('t', $wo->getToken()); + self::assertSame(1, $wo->getRelayFactor()); + self::assertSame(10.0, $wo->getTimeout()->Seconds()); + } + + public function testSetTimeoutWithNullResetsToZero(): void + { + $wo = new WriteOptions(Timeout: '30s'); + self::assertSame(30.0, $wo->getTimeout()->Seconds()); + + $wo->setTimeout(null); + self::assertSame(0.0, $wo->getTimeout()->Seconds()); + } + + public function testSetTimeoutWithIntNanoseconds(): void + { + $wo = new WriteOptions(); + $wo->setTimeout(2000000000); // 2 seconds in nanoseconds + self::assertSame(2.0, $wo->getTimeout()->Seconds()); + } +} + diff --git a/tests/Usage/ACL/ACLClientTest.php b/tests/Usage/ACL/ACLClientTest.php index f16501ea..af6d04b8 100644 --- a/tests/Usage/ACL/ACLClientTest.php +++ b/tests/Usage/ACL/ACLClientTest.php @@ -3,7 +3,7 @@ namespace DCarbone\PHPConsulAPITests\Usage\ACL; /* - Copyright 2016-2021 Daniel Carbone (daniel.p.carbone@gmail.com) + Copyright 2016-2025 Daniel Carbone (daniel.p.carbone@gmail.com) Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -19,50 +19,157 @@ */ use DCarbone\PHPConsulAPI\ACL\ACLClient; +use DCarbone\PHPConsulAPI\ACL\ACLPolicy; +use DCarbone\PHPConsulAPI\ACL\ACLToken; +use DCarbone\PHPConsulAPI\ACL\ACLTokenPolicyLink; use DCarbone\PHPConsulAPI\QueryMeta; use DCarbone\PHPConsulAPI\WriteMeta; use DCarbone\PHPConsulAPITests\ConsulManager; use DCarbone\PHPConsulAPITests\Usage\AbstractUsageTests; /** - * Class ACLClientTest - * * @internal */ final class ACLClientTest extends AbstractUsageTests { - /** @var string */ - protected $bootstrappedACL; + protected static bool $singlePerClass = false; + + public static function setUpBeforeClass(): void + { + ConsulManager::startSingleDevACL(); + } + + private static function managementClient(): ACLClient + { + return new ACLClient(ConsulManager::testConfig(ConsulManager::MANAGEMENT_TOKEN)); + } + + public function testTokenReadSelf(): void + { + $client = self::managementClient(); + + [$token, $qm, $err] = $client->TokenReadSelf(); + self::assertNull($err, 'TokenReadSelf() returned error: ' . $err); + self::assertInstanceOf(QueryMeta::class, $qm); + self::assertInstanceOf(ACLToken::class, $token); + self::assertNotEmpty($token->AccessorID); + self::assertNotEmpty($token->SecretID); + } /** - * @return string + * @return string The policy ID */ - public function testCanBootstrapACL() + public function testPolicyCreate(): string { - ConsulManager::startSingleDev('-bind="127.0.0.1"'); + $client = self::managementClient(); - $client = new ACLClient(ConsulManager::testConfig()); + $policy = new ACLPolicy( + Name: 'php-consul-api-test-policy', + Description: 'Test policy created by php-consul-api', + Rules: 'key_prefix "test/" { policy = "read" }', + ); - [$aclID, $wm, $err] = $client->Bootstrap(); - self::assertNull($err, 'ACL::bootstrap() returned error: ' . $err); + [$created, $wm, $err] = $client->PolicyCreate($policy); + self::assertNull($err, 'PolicyCreate() returned error: ' . $err); self::assertInstanceOf(WriteMeta::class, $wm); - self::assertIsString($aclID); + self::assertInstanceOf(ACLPolicy::class, $created); + self::assertNotEmpty($created->ID); + self::assertSame('php-consul-api-test-policy', $created->Name); + + return $created->ID; + } + + /** + * @depends testPolicyCreate + * @return array{0: string, 1: string} [accessorID, policyID] + */ + public function testTokenCreate(string $policyID): array + { + $client = self::managementClient(); + + $token = new ACLToken( + Description: 'php-consul-api-test-token', + Policies: [new ACLTokenPolicyLink(ID: $policyID)], + ); + + [$created, $wm, $err] = $client->TokenCreate($token); + self::assertNull($err, 'TokenCreate() returned error: ' . $err); + self::assertInstanceOf(WriteMeta::class, $wm); + self::assertInstanceOf(ACLToken::class, $created); + self::assertNotEmpty($created->AccessorID); + self::assertNotEmpty($created->SecretID); + self::assertSame('php-consul-api-test-token', $created->Description); + + return [$created->AccessorID, $policyID]; + } + + /** + * @depends testTokenCreate + * @param array{0: string, 1: string} $ids + * @return array{0: string, 1: string} [accessorID, policyID] + */ + public function testTokenRead(array $ids): array + { + [$accessorID] = $ids; + + $client = self::managementClient(); + + [$token, $qm, $err] = $client->TokenRead($accessorID); + self::assertNull($err, 'TokenRead() returned error: ' . $err); + self::assertInstanceOf(QueryMeta::class, $qm); + self::assertInstanceOf(ACLToken::class, $token); + self::assertSame($accessorID, $token->AccessorID); + self::assertSame('php-consul-api-test-token', $token->Description); - return $aclID; + return $ids; } /** - * @depends testCanBootstrapACL - * @param string $aclID + * @depends testTokenRead + * @param array{0: string, 1: string} $ids + * @return array{0: string, 1: string} [accessorID, policyID] */ - public function testCanGetBootstrappedACL(string $aclID): void + public function testTokenList(array $ids): array { - $client = new ACLClient(ConsulManager::testConfig()); + $client = self::managementClient(); - [$acls, $qm, $err] = $client->Info($aclID); - self::assertNull($err, 'ACL::info() return error: ' . $err); + [$entries, $qm, $err] = $client->TokenList(); + self::assertNull($err, 'TokenList() returned error: ' . $err); self::assertInstanceOf(QueryMeta::class, $qm); - self::assertIsArray($acls); - \var_dump($acls); + self::assertIsArray($entries); + // At minimum: the management token + the anonymous token + our created token + self::assertGreaterThanOrEqual(2, count($entries)); + + return $ids; + } + + /** + * @depends testTokenList + * @param array{0: string, 1: string} $ids + * @return string The policyID + */ + public function testTokenDelete(array $ids): string + { + [$accessorID, $policyID] = $ids; + + $client = self::managementClient(); + + [$wm, $err] = $client->TokenDelete($accessorID); + self::assertNull($err, 'TokenDelete() returned error: ' . $err); + self::assertInstanceOf(WriteMeta::class, $wm); + + return $policyID; + } + + /** + * @depends testTokenDelete + */ + public function testPolicyDelete(string $policyID): void + { + $client = self::managementClient(); + + [$wm, $err] = $client->PolicyDelete($policyID); + self::assertNull($err, 'PolicyDelete() returned error: ' . $err); + self::assertInstanceOf(WriteMeta::class, $wm); } } diff --git a/tests/Usage/Agent/AgentClientTest.php b/tests/Usage/Agent/AgentClientTest.php index 40c8ce03..dd7fa486 100644 --- a/tests/Usage/Agent/AgentClientTest.php +++ b/tests/Usage/Agent/AgentClientTest.php @@ -56,9 +56,9 @@ public function testCanGetSelf(): void self::assertNull($err); self::assertIsArray( $self, - \sprintf( + sprintf( 'Expected AgentClient::self to return array, saw "%s"', - \gettype($self) + gettype($self) ) ); } @@ -70,7 +70,7 @@ public function testCanReloadSelf(): void { $client = new AgentClient(ConsulManager::testConfig()); $err = $client->Reload(); - self::assertNull($err, \sprintf('AgentClient::reload returned error: %s', $err)); + self::assertNull($err, sprintf('AgentClient::reload returned error: %s', $err)); } /** @@ -81,10 +81,10 @@ public function testCanGetNodeName(): void $client = new AgentClient(ConsulManager::testConfig()); [$nodeName, $err] = $client->NodeName(); - self::assertNull($err, \sprintf('Unable to get agent node name: %s', $err)); + self::assertNull($err, sprintf('Unable to get agent node name: %s', $err)); self::assertIsString( $nodeName, - \sprintf('node name expected to be string, %s seen', \gettype($nodeName)) + sprintf('node name expected to be string, %s seen', gettype($nodeName)) ); self::assertNotEmpty($nodeName, 'NodeName was empty!'); } @@ -97,7 +97,7 @@ public function testCanGeMembers(): void $client = new AgentClient(ConsulManager::testConfig()); [$members, $err] = $client->Members(); - self::assertNull($err, \sprintf('AgentClient::members returned error: %s', $err)); + self::assertNull($err, sprintf('AgentClient::members returned error: %s', $err)); self::assertIsArray($members); self::assertContainsOnlyInstancesOf(AgentMember::class, $members); self::assertCount(1, $members); @@ -117,7 +117,7 @@ public function testCanRegisterServiceNoChecks(): void ->setPort(1234); $err = $client->ServiceRegister($svc); - self::assertNull($err, \sprintf('AgentClient::serviceRegister returned error: %s', $err)); + self::assertNull($err, sprintf('AgentClient::serviceRegister returned error: %s', $err)); } /** @@ -132,12 +132,12 @@ public function testCanRegisterServiceWithOneCheck(): void ->setName(self::Service2Name) ->setAddress('127.0.0.1') ->setPort(4321) - ->setCheck(new AgentServiceCheck([ - 'TTL' => '5s', - ])); + ->setCheck(new AgentServiceCheck( + TTL: '5s', + )); $err = $client->ServiceRegister($svc); - self::assertNull($err, \sprintf('AgentClient::serviceRegister returned error: %s', $err)); + self::assertNull($err, sprintf('AgentClient::serviceRegister returned error: %s', $err)); } /** @@ -152,7 +152,7 @@ public function testCanGetServiceList(): void [$svcs, $err] = $client->Services(); try { - self::assertNull($err, \sprintf('AgentClient::services return error: %s', $err)); + self::assertNull($err, sprintf('AgentClient::services return error: %s', $err)); self::assertIsArray($svcs); self::assertContainsOnlyInstancesOf(AgentService::class, $svcs); @@ -160,7 +160,7 @@ public function testCanGetServiceList(): void self::assertCount(2, $svcs); } catch (AssertionFailedError $e) { echo "\nservices list:\n"; - \var_dump($svcs); + var_dump($svcs); echo "\n"; throw $e; @@ -175,18 +175,18 @@ public function testCanDeregisterService(): void $client = new AgentClient(ConsulManager::testConfig()); $err = $client->ServiceDeregister(self::Service1Name); - self::assertNull($err, \sprintf('AgentClient::serviceDeregister returned error: %s', $err)); + self::assertNull($err, sprintf('AgentClient::serviceDeregister returned error: %s', $err)); [$svcs, $err] = $client->Services(); try { - self::assertNull($err, \sprintf('AgentClient::services returned error: %s', $err)); + self::assertNull($err, sprintf('AgentClient::services returned error: %s', $err)); self::assertIsArray($svcs); self::assertContainsOnlyInstancesOf(AgentService::class, $svcs); self::assertCount(1, $svcs); } catch (AssertionFailedError $e) { echo "\nservices list:\n"; - \var_dump($svcs); + var_dump($svcs); echo "\n"; throw $e; @@ -205,32 +205,32 @@ public function testCanRegisterServiceWithCheck(): void ->setName(self::Service1Name) ->setPort(1234) ->setAddress('127.0.0.1') - ->setCheck(new AgentServiceCheck([ - 'TCP' => '127.0.0.1', - 'Interval' => '30s', - ])); + ->setCheck(Check: new AgentServiceCheck( + Interval: '30s', + TCP: '127.0.0.1', + )); $err = $client->ServiceRegister($svc); - self::assertNull($err, \sprintf('Error registering service with check: %s', $err)); + self::assertNull($err, sprintf('Error registering service with check: %s', $err)); - \sleep(2); + sleep(2); [$svcs, $err] = $client->Services(); try { - self::assertNull($err, \sprintf('AgentClient::services returned error: %s', $err)); + self::assertNull($err, sprintf('AgentClient::services returned error: %s', $err)); self::assertIsArray($svcs); self::assertContainsOnlyInstancesOf(AgentService::class, $svcs); self::assertCount(2, $svcs); } catch (AssertionFailedError $e) { echo "\nservices list:\n"; - \var_dump($svcs); + var_dump($svcs); echo "\n"; throw $e; } $err = $client->ServiceDeregister(self::Service1Name); - self::assertNull($err, \sprintf('Error deregistering service: %s', $err)); + self::assertNull($err, sprintf('Error deregistering service: %s', $err)); } } diff --git a/tests/Usage/Agent/AgentServiceConnectProxyConfigTest.php b/tests/Usage/Agent/AgentServiceConnectProxyConfigTest.php index e0d5fea7..2ac0f2e7 100644 --- a/tests/Usage/Agent/AgentServiceConnectProxyConfigTest.php +++ b/tests/Usage/Agent/AgentServiceConnectProxyConfigTest.php @@ -20,29 +20,28 @@ */ use DCarbone\PHPConsulAPI\Agent\AgentServiceConnectProxyConfig; -use DCarbone\PHPConsulAPI\FakeMap; use DCarbone\PHPConsulAPITests\Usage\AbstractUsageTests; class AgentServiceConnectProxyConfigTest extends AbstractUsageTests { - public function test_construct_givenConfig_willUnmarshalConfigValuesSuccessfully() + public function test_construct_givenConfig_willUnmarshalConfigValuesSuccessfully(): void { - $config = new AgentServiceConnectProxyConfig([ - 'Config' => [ + $config = new AgentServiceConnectProxyConfig( + Config: [ 'envoy_prometheus_bind_addr' => '0.0.0.0:12345', 'handshake_timeout_ms' => 10000, 'local_connect_timeout_ms' => 1000, 'local_request_timeout_ms' => 0, 'protocol' => 'http', ], - ]); + ); - $this->assertEquals(new FakeMap([ + $this->assertEquals([ 'envoy_prometheus_bind_addr' => '0.0.0.0:12345', 'handshake_timeout_ms' => 10000, 'local_connect_timeout_ms' => 1000, 'local_request_timeout_ms' => 0, 'protocol' => 'http', - ]), $config->Config); + ], $config->Config); } } \ No newline at end of file diff --git a/tests/Usage/Catalog/CatalogClientTest.php b/tests/Usage/Catalog/CatalogClientTest.php index e0111b9a..d1292c3a 100644 --- a/tests/Usage/Catalog/CatalogClientTest.php +++ b/tests/Usage/Catalog/CatalogClientTest.php @@ -61,16 +61,16 @@ public function testCanRegisterService(): void { $client = new CatalogClient(ConsulManager::testConfig()); - $registration = new CatalogRegistration([ - 'Node' => 'dc1', - 'Address' => self::ServiceAddress, - 'Service' => new AgentService([ - 'ID' => self::ServiceID1, - 'Service' => self::ServiceName, - 'Port' => self::ServicePort, - 'Address' => self::ServiceAddress, - ]), - ]); + $registration = new CatalogRegistration( + Node: 'dc1', + Address: self::ServiceAddress, + Service:new AgentService( + ID: self::ServiceID1, + Service: self::ServiceName, + Port:self::ServicePort, + Address: self::ServiceAddress, + ), + ); [$wm, $err] = $client->Register($registration); self::assertNull($err, 'CatalogClient::register returned error: ' . $err); @@ -89,7 +89,7 @@ public function testCanGetService(): void self::assertInstanceOf(QueryMeta::class, $qm); self::assertIsArray($service); self::assertCount(1, $service); - self::assertInstanceOf(CatalogService::class, \reset($service)); + self::assertInstanceOf(CatalogService::class, reset($service)); } /** @@ -99,16 +99,16 @@ public function testCanRegisterSecondServiceWithSameName(): void { $client = new CatalogClient(ConsulManager::testConfig()); - [$wm, $err] = $client->Register(new CatalogRegistration([ - 'Node' => 'dc1', - 'Address' => self::ServiceAddress, - 'Service' => new AgentService([ - 'ID' => self::ServiceID2, - 'Service' => self::ServiceName, - 'Port' => self::ServicePort, - 'Address' => self::ServiceAddress, - ]), - ])); + [$wm, $err] = $client->Register(new CatalogRegistration( + Node: 'dc1', + Address: self::ServiceAddress, + Service: new AgentService( + ID: self::ServiceID2, + Service: self::ServiceName, + Port: self::ServicePort, + Address: self::ServiceAddress, + ), + )); self::assertNull($err, 'CatalogClient::register failed to register second service: ' . $err); self::assertInstanceOf(WriteMeta::class, $wm); @@ -132,7 +132,7 @@ public function testCanGetListOfService(): void self::assertInstanceOf(CatalogService::class, $s); } } catch (AssertionFailedError $e) { - \var_dump($service); + var_dump($service); throw $e; } } @@ -153,7 +153,7 @@ public function testCanGetListOfServices(): void self::assertCount(2, $services); self::assertContainsOnly('array', $services); } catch (AssertionFailedError $e) { - \var_dump($services); + var_dump($services); throw $e; } } @@ -165,10 +165,10 @@ public function testCanDeregisterService(): void { $client = new CatalogClient(ConsulManager::testConfig()); - [$wm, $err] = $client->Deregister(new CatalogDeregistration([ - 'Node' => 'dc1', - 'ServiceID' => self::ServiceID1, - ])); + [$wm, $err] = $client->Deregister(new CatalogDeregistration( + Node: 'dc1', + ServiceID: self::ServiceID1, + )); self::assertNull($err, 'CatalogClient::deregister returned error: ' . $err); self::assertInstanceOf(WriteMeta::class, $wm); @@ -176,7 +176,7 @@ public function testCanDeregisterService(): void self::assertNull($err, 'CatalogClient::service returned error: ' . $err); self::assertInstanceOf(QueryMeta::class, $qm); self::assertCount(1, $service); - self::assertInstanceOf(CatalogService::class, \reset($service)); + self::assertInstanceOf(CatalogService::class, reset($service)); } /** @@ -196,7 +196,7 @@ public function testCanGetDatacenters(): void self::assertCount(1, $dcs); self::assertSame('dc1', $dcs[0]); } catch (AssertionFailedError $e) { - \var_dump($dcs); + var_dump($dcs); throw $e; } } @@ -217,7 +217,7 @@ public function testCanGetListOfNodes(): void self::assertCount(2, $nodes); self::assertContainsOnlyInstancesOf(Node::class, $nodes); } catch (AssertionFailedError $e) { - \var_dump($nodes); + var_dump($nodes); throw $e; } } @@ -245,7 +245,7 @@ public function testCanGetNode(): void self::assertNotNull($id, 'Unable to get node with ID'); } catch (AssertionFailedError $e) { - \var_dump($nodes); + var_dump($nodes); throw $e; } @@ -255,7 +255,7 @@ public function testCanGetNode(): void self::assertInstanceOf(QueryMeta::class, $qm); self::assertInstanceOf(CatalogNode::class, $node); } catch (AssertionFailedError $e) { - \var_dump($node); + var_dump($node); throw $e; } } diff --git a/tests/Usage/Coordinate/CoordinateClientTest.php b/tests/Usage/Coordinate/CoordinateClientTest.php index 1d615539..2440e5fa 100644 --- a/tests/Usage/Coordinate/CoordinateClientTest.php +++ b/tests/Usage/Coordinate/CoordinateClientTest.php @@ -47,9 +47,9 @@ public function testDatacenters(): void $client = new CoordinateClient(ConsulManager::testConfig()); [$dcs, $err] = $client->Datacenters(); - self::assertNull($err, \sprintf('CoordinateClient::datacenters() - %s', $err)); + self::assertNull($err, sprintf('CoordinateClient::datacenters() - %s', $err)); self::assertIsArray($dcs); - self::assertGreaterThan(0, \count($dcs), 'Expected at least 1 datacenter'); + self::assertGreaterThan(0, count($dcs), 'Expected at least 1 datacenter'); } /** @@ -60,7 +60,7 @@ public function testNodes(): void $client = new CoordinateClient(ConsulManager::testConfig()); [$nodes, $qm, $err] = $client->Nodes(); - self::assertNull($err, \sprintf('CoordinateClient::nodes() - %s', $err)); + self::assertNull($err, sprintf('CoordinateClient::nodes() - %s', $err)); self::assertInstanceOf(QueryMeta::class, $qm); self::assertIsArray($nodes); } diff --git a/tests/Usage/Coordinate/CoordinateUsageTest.php b/tests/Usage/Coordinate/CoordinateUsageTest.php index 0ed2b1a5..0bbb6438 100644 --- a/tests/Usage/Coordinate/CoordinateUsageTest.php +++ b/tests/Usage/Coordinate/CoordinateUsageTest.php @@ -8,11 +8,6 @@ use DCarbone\PHPConsulAPITests\Usage\AbstractUsageTests; use PHPUnit\Framework\AssertionFailedError; -use function DCarbone\PHPConsulAPI\Coordinate\add; -use function DCarbone\PHPConsulAPI\Coordinate\diff; -use function DCarbone\PHPConsulAPI\Coordinate\magnitude; -use function DCarbone\PHPConsulAPI\Coordinate\unitVectorAt; - /** * These tests were largely pulled from https://github.com/hashicorp/serf/blob/master/coordinate/coordinate_test.go * @@ -28,23 +23,23 @@ public function testAdd(): void { $vec1 = [1.0, -3.0, 3.0]; $vec2 = [-4.0, 5.0, 6.0]; - $this->verifyEqualVectors(add($vec1, $vec2), [-3.0, 2.0, 9.0]); + $this->verifyEqualVectors(Coordinate::_add($vec1, $vec2), [-3.0, 2.0, 9.0]); } public function testDiff(): void { $vec1 = [1.0, -3.0, 3.0]; $vec2 = [-4.0, 5.0, 6.0]; - $this->verifyEqualVectors(diff($vec1, $vec2), [5.0, -8.0, -3.0]); + $this->verifyEqualVectors(Coordinate::_diff($vec1, $vec2), [5.0, -8.0, -3.0]); } public function testMagnitude(): void { $zero = [0.0, 0.0, 0.0]; - $this->verifyEqualFloats(magnitude($zero), 0.0); + $this->verifyEqualFloats(Coordinate::_magnitude($zero), 0.0); $vec = [1.0, -2.0, 3.0]; - $this->verifyEqualFloats(magnitude($vec), 3.7416573867739413); + $this->verifyEqualFloats(Coordinate::_magnitude($vec), 3.7416573867739413); } public function testUnitVectorAt(): void @@ -52,13 +47,13 @@ public function testUnitVectorAt(): void $vec1 = [1.0, 2.0, 3.0]; $vec2 = [0.5, 0.6, 0.7]; - [$u, $mag] = unitVectorAt($vec1, $vec2); + [$u, $mag] = Coordinate::_unitVectorAt($vec1, $vec2); $this->verifyEqualVectors($u, [0.18257418583505536, 0.511207720338155, 0.8398412548412546]); - $this->verifyEqualFloats(magnitude($u), 1.0); - $this->verifyEqualFloats($mag, magnitude(diff($vec1, $vec2))); + $this->verifyEqualFloats(Coordinate::_magnitude($u), 1.0); + $this->verifyEqualFloats($mag, Coordinate::_magnitude(Coordinate::_diff($vec1, $vec2))); - [$u, $mag] = unitVectorAt($vec1, $vec1); - $this->verifyEqualFloats(magnitude($u), 1.0); + [$u, $mag] = Coordinate::_unitVectorAt($vec1, $vec1); + $this->verifyEqualFloats(Coordinate::_magnitude($u), 1.0); $this->verifyEqualFloats($mag, 0.0); } @@ -78,9 +73,7 @@ public function testCanConstructCoordinateWithDefaultConfig(): void public function testCanConstructCoordinateWithArrayOfValues(): void { $coord = new Coordinate( - [ - 'Vec' => [0.1, 0.2], - ] + Vec: [0.1, 0.2], ); self::assertInstanceOf(Coordinate::class, $coord); self::assertIsArray($coord->Vec); @@ -178,7 +171,7 @@ public function testApplyForce(): void $this->verifyEqualFloats($c->Height, $config->HeightMin); $bad = clone $c; - $bad->Vec = \array_fill(0, \count($c->Vec) + 1, 0.0); + $bad->Vec = array_fill(0, count($c->Vec) + 1, 0.0); $c->ApplyForce($config, 1.0, $bad); } @@ -212,7 +205,7 @@ public function testDistanceTo(): void $this->verifyEqualFloats($c1->DistanceTo($c2)->Seconds(), 4.104875150354758 + 0.3 + 0.8); $bad = clone $c1; - $bad->Vec = \array_fill(0, \count($c1->Vec) + 1, 0.0); + $bad->Vec = array_fill(0, count($c1->Vec) + 1, 0.0); $c1->DistanceTo($bad); } @@ -224,8 +217,8 @@ protected function verifyEqualFloats(float $f1, float $f2): void { self::assertLessThanOrEqual( self::ZeroThreshold, - \abs($f1 - $f2), - \sprintf('equal assertion fail, %.6f != %.6f', $f1, $f2) + abs($f1 - $f2), + sprintf('equal assertion fail, %.6f != %.6f', $f1, $f2) ); } @@ -241,7 +234,7 @@ protected function verifyEqualVectors(array $vec1, array $vec2): void $this->verifyEqualFloats($v, $vec2[$k]); } } catch (AssertionFailedError $e) { - \var_dump($vec1, $vec2); + var_dump($vec1, $vec2); throw $e; } } diff --git a/tests/Usage/KV/KVCRUDTest.php b/tests/Usage/KV/KVCRUDTest.php index ae1cebd9..cbfc01e0 100644 --- a/tests/Usage/KV/KVCRUDTest.php +++ b/tests/Usage/KV/KVCRUDTest.php @@ -1,11 +1,9 @@ Put(new KVPair(Key: 'test/put', Value: 'hello')); + self::assertNull($err, sprintf('KV::Put returned error: %s', (string)$err)); + self::assertInstanceOf(WriteMeta::class, $wm); + } - public function testCanPutKey(): void + /** + * Mirrors Go TestAPI_ClientPut with flags set. + */ + public function testPutWithFlags(): void { $client = new KVClient(ConsulManager::testConfig()); - [$wm, $err] = $client->Put(new KVPair(['Key' => self::KVKey1, 'Value' => self::KVValue1])); - self::assertNull($err, \sprintf('Unable to set kvp: %s', (string)$err)); + [$wm, $err] = $client->Put(new KVPair(Key: 'test/flags', Value: 'flagged', Flags: 42)); + self::assertNull($err, sprintf('KV::Put returned error: %s', (string)$err)); self::assertInstanceOf(WriteMeta::class, $wm); + + [$kv, , $err] = $client->Get('test/flags'); + self::assertNull($err, sprintf('KV::Get returned error: %s', (string)$err)); + self::assertInstanceOf(KVPair::class, $kv); + self::assertSame(42, $kv->Flags); + self::assertSame('flagged', $kv->Value); } + // --------------------------------------------------------------- + // GET + // --------------------------------------------------------------- + /** - * @depends testCanPutKey + * Mirrors Go TestAPI_ClientGet: put then get, verify value matches. */ - public function testCanGetKey(): void + public function testGet(): void { $client = new KVClient(ConsulManager::testConfig()); - $client->Put(new KVPair(['Key' => self::KVKey1, 'Value' => self::KVValue1])); - [$kv, $qm, $err] = $client->Get(self::KVKey1); - self::assertNull($err, \sprintf('KV::get returned error: %s', (string)$err)); - self::assertInstanceOf(QueryMeta::class, $qm); + $key = 'test/get'; + $value = 'bar'; + + [$_, $err] = $client->Put(new KVPair(Key: $key, Value: $value)); + self::assertNull($err, sprintf('KV::Put returned error: %s', (string)$err)); + + [$kv, $qm, $err] = $client->Get($key); + self::assertNull($err, sprintf('KV::Get returned error: %s', (string)$err)); self::assertInstanceOf(KVPair::class, $kv); - self::assertSame(self::KVKey1, $kv->Key); - self::assertSame(self::KVValue1, $kv->Value); + self::assertInstanceOf(QueryMeta::class, $qm); + self::assertSame($key, $kv->Key); + self::assertSame($value, $kv->Value); + self::assertGreaterThan(0, $kv->CreateIndex); + self::assertGreaterThan(0, $kv->ModifyIndex); + self::assertSame(0, $kv->LockIndex); + self::assertSame(0, $kv->Flags); + self::assertSame('', $kv->Session); + self::assertGreaterThan(0, $qm->LastIndex); } /** - * @depends testCanPutKey + * Mirrors Go TestAPI_ClientGet for a non-existent key: returns nil KVPair, no error. */ - public function testCanDeleteKey(): void + public function testGetNotExist(): void { $client = new KVClient(ConsulManager::testConfig()); - $client->Put(new KVPair(['Key' => self::KVKey1, 'Value' => self::KVValue1])); - - [$wm, $err] = $client->Delete(self::KVKey1); - self::assertNull($err, \sprintf('KV::delete returned error: %s', $err)); - self::assertInstanceOf( - WriteMeta::class, - $wm, - \sprintf( - 'expected "%s", saw "%s"', - WriteMeta::class, - \is_object($wm) ? \get_class($wm) : \gettype($wm) - ) - ); + + [$kv, $qm, $err] = $client->Get('nonexistent/key'); + self::assertNull($err, sprintf('KV::Get returned error: %s', (string)$err)); + self::assertNull($kv, 'Expected null KVPair for non-existent key'); + self::assertInstanceOf(QueryMeta::class, $qm); } - public function testListReturnsErrorWithInvalidPrefix(): void + // --------------------------------------------------------------- + // LIST + // --------------------------------------------------------------- + + /** + * Mirrors Go TestAPI_ClientList: put multiple keys under a prefix, list them. + */ + public function testList(): void { - $client = new KVClient(ConsulManager::testConfig()); - [$_, $_, $err] = $client->List(12345); - self::assertInstanceOf( - Error::class, - $err, - \sprintf( - 'Expected $err to be instanceof "%s", saw "%s"', - Error::class, - \is_object($err) ? \get_class($err) : \gettype($err) - ) - ); + $client = new KVClient(ConsulManager::testConfig()); + + $prefix = 'test/list'; + $keys = [ + "{$prefix}/foo" => 'foo-value', + "{$prefix}/bar" => 'bar-value', + "{$prefix}/baz" => 'baz-value', + ]; + + foreach ($keys as $k => $v) { + [$_, $err] = $client->Put(new KVPair(Key: $k, Value: $v)); + self::assertNull($err, sprintf('KV::Put(%s) returned error: %s', $k, (string)$err)); + } + + [$list, $qm, $err] = $client->List($prefix); + self::assertNull($err, sprintf('KV::List returned error: %s', (string)$err)); + self::assertInstanceOf(KVPairs::class, $list); + self::assertInstanceOf(QueryMeta::class, $qm); + self::assertCount(3, $list); + + $found = []; + foreach ($list as $pair) { + self::assertInstanceOf(KVPair::class, $pair); + $found[$pair->Key] = $pair->Value; + } + + foreach ($keys as $k => $v) { + self::assertArrayHasKey($k, $found, "Key {$k} not found in list"); + self::assertSame($v, $found[$k], "Value mismatch for key {$k}"); + } } /** - * @depends testCanPutKey + * Mirrors Go TestAPI_ClientList with no prefix: list all keys in the store. */ - public function testCanGetNoPrefixList(): void + public function testListNoPrefix(): void { - /** @var \DCarbone\PHPConsulAPI\KV\KVPair[] $list */ - /** @var \DCarbone\PHPConsulAPI\QueryMeta $qm */ - /** @var \DCarbone\PHPConsulAPI\Error $err */ $client = new KVClient(ConsulManager::testConfig()); - $client->Put(new KVPair(['Key' => self::KVKey1, 'Value' => self::KVValue1])); - $client->Put(new KVPair(['Key' => self::KVKey2, 'Value' => self::KVValue2])); - $client->Put(new KVPair(['Key' => self::KVKey3, 'Value' => self::KVValue3])); - /** @noinspection PhpUnhandledExceptionInspection */ + [$_, $err] = $client->Put(new KVPair(Key: 'alpha', Value: 'a')); + self::assertNull($err); + [$_, $err] = $client->Put(new KVPair(Key: 'beta', Value: 'b')); + self::assertNull($err); + [$list, $qm, $err] = $client->List(); - self::assertNull($err, \sprintf('KV::valueList returned error: %s', $err)); - - try { - self::assertInstanceOf(KVPairs::class, $list); - self::assertInstanceOf(QueryMeta::class, $qm); - self::assertCount(3, $list); - - $key1found = false; - $key2found = false; - $key3found = false; - - foreach ($list as $kv) { - if (self::KVValue1 === $kv->Value) { - $key1found = true; - } elseif (self::KVValue2 === $kv->Value) { - $key2found = true; - } elseif (self::KVValue3 === $kv->Value) { - $key3found = true; - } - } - - self::assertTrue($key1found, 'Key1 not found in list!'); - self::assertTrue($key2found, 'Key2 not found in list!'); - self::assertTrue($key3found, 'Key3 not found in list!'); - } catch (AssertionFailedError $e) { - echo "\nno prefix \$list value:\n"; - \var_dump($list); - echo "\n"; - - throw $e; - } + self::assertNull($err, sprintf('KV::List returned error: %s', (string)$err)); + self::assertInstanceOf(KVPairs::class, $list); + self::assertInstanceOf(QueryMeta::class, $qm); + self::assertGreaterThanOrEqual(2, count($list)); } + // --------------------------------------------------------------- + // KEYS + // --------------------------------------------------------------- + /** - * @depends testCanPutKey + * Mirrors Go TestAPI_ClientKeys: put multiple keys, get keys list. */ - public function testCanGetPrefixList(): void + public function testKeys(): void { - /** @var \DCarbone\PHPConsulAPI\KV\KVPair[] $list */ - /** @var \DCarbone\PHPConsulAPI\QueryMeta $qm */ - /** @var \DCarbone\PHPConsulAPI\Error $err */ $client = new KVClient(ConsulManager::testConfig()); - $client->Put(new KVPair(['Key' => self::KVPrefix . '/' . self::KVKey1, 'Value' => self::KVValue1])); - $client->Put(new KVPair(['Key' => self::KVPrefix . '/' . self::KVKey2, 'Value' => self::KVValue2])); - $client->Put(new KVPair(['Key' => self::KVPrefix . '/' . self::KVKey3, 'Value' => self::KVValue3])); - [$list, $qm, $err] = $client->List(self::KVPrefix); - self::assertNull($err, \sprintf('KV::valueList returned error: %s', $err)); + $prefix = 'test/keys'; + $keyNames = ["{$prefix}/a", "{$prefix}/b", "{$prefix}/c"]; + + foreach ($keyNames as $k) { + [$_, $err] = $client->Put(new KVPair(Key: $k, Value: 'v')); + self::assertNull($err, sprintf('KV::Put(%s) returned error: %s', $k, (string)$err)); + } + + [$keys, $qm, $err] = $client->Keys($prefix); + self::assertNull($err, sprintf('KV::Keys returned error: %s', (string)$err)); self::assertInstanceOf(QueryMeta::class, $qm); + self::assertIsArray($keys); + self::assertCount(3, $keys); + self::assertContainsOnly('string', $keys, true); - try { - self::assertInstanceOf(KVPairs::class, $list); - self::assertCount(3, $list); - self::assertContainsOnlyInstancesOf(KVPair::class, $list); - - $key1found = false; - $key2found = false; - $key3found = false; - - foreach ($list as $kv) { - if (self::KVValue1 === $kv->Value) { - $key1found = true; - } elseif (self::KVValue2 === $kv->Value) { - $key2found = true; - } elseif (self::KVValue3 === $kv->Value) { - $key3found = true; - } - } - - self::assertTrue($key1found, 'Key1 not found in list!'); - self::assertTrue($key2found, 'Key2 not found in list!'); - self::assertTrue($key3found, 'Key3 not found in list!'); - } catch (AssertionFailedError $e) { - echo "\nprefix \$list value:\n"; - \var_dump($list); - echo "\n"; - - throw $e; + foreach ($keyNames as $expected) { + self::assertContains($expected, $keys, "Expected key {$expected} not found"); } } - public function testKeysReturnsErrorWithInvalidPrefix(): void + /** + * Mirrors Go TestAPI_ClientKeys with no prefix: returns all keys. + */ + public function testKeysNoPrefix(): void { - $client = new KVClient(ConsulManager::testConfig()); - [$_, $_, $err] = $client->Keys(12345); - self::assertInstanceOf( - Error::class, - $err, - \sprintf( - 'Expected $err to be "%s", saw "%s"', - Error::class, - \is_object($err) ? \get_class($err) : \gettype($err) - ) - ); + $client = new KVClient(ConsulManager::testConfig()); + + [$_, $err] = $client->Put(new KVPair(Key: 'keytest1', Value: 'v')); + self::assertNull($err); + [$_, $err] = $client->Put(new KVPair(Key: 'keytest2', Value: 'v')); + self::assertNull($err); + + [$keys, $qm, $err] = $client->Keys(); + self::assertNull($err, sprintf('KV::Keys returned error: %s', (string)$err)); + self::assertInstanceOf(QueryMeta::class, $qm); + self::assertIsArray($keys); + self::assertGreaterThanOrEqual(2, count($keys)); + self::assertContains('keytest1', $keys); + self::assertContains('keytest2', $keys); } + // --------------------------------------------------------------- + // DELETE + // --------------------------------------------------------------- + /** - * @depends testCanPutKey + * Mirrors Go TestAPI_ClientDelete: put, delete, verify gone. */ - public function testCanGetNoPrefixKeys(): void + public function testDelete(): void { - /** @var string[] $list */ - /** @var \DCarbone\PHPConsulAPI\QueryMeta $qm */ - /** @var \DCarbone\PHPConsulAPI\Error $err */ $client = new KVClient(ConsulManager::testConfig()); - $client->Put(new KVPair(['Key' => self::KVKey1, 'Value' => self::KVValue1])); - $client->Put(new KVPair(['Key' => self::KVKey2, 'Value' => self::KVValue2])); - $client->Put(new KVPair(['Key' => self::KVKey3, 'Value' => self::KVValue3])); - [$list, $qm, $err] = $client->Keys(); - self::assertNull($err, \sprintf('KV::keys returned error: %s', $err)); - self::assertInstanceOf(QueryMeta::class, $qm); + $key = 'test/delete'; - try { - self::assertIsArray($list); - self::assertCount(3, $list); - self::assertContainsOnly('string', $list, true); - - $key1found = false; - $key2found = false; - $key3found = false; - - foreach ($list as $key) { - if (self::KVKey1 === $key) { - $key1found = true; - } elseif (self::KVKey2 === $key) { - $key2found = true; - } elseif (self::KVKey3 === $key) { - $key3found = true; - } - } - - self::assertTrue($key1found, 'Key1 not found in list!'); - self::assertTrue($key2found, 'Key2 not found in list!'); - self::assertTrue($key3found, 'Key3 not found in list!'); - } catch (AssertionFailedError $e) { - echo "\nprefix \$list value:\n"; - \var_dump($list); - echo "\n"; - - throw $e; + [$_, $err] = $client->Put(new KVPair(Key: $key, Value: 'removeme')); + self::assertNull($err, sprintf('KV::Put returned error: %s', (string)$err)); + + // Verify it exists + [$kv, , $err] = $client->Get($key); + self::assertNull($err); + self::assertInstanceOf(KVPair::class, $kv); + + // Delete + [$wm, $err] = $client->Delete($key); + self::assertNull($err, sprintf('KV::Delete returned error: %s', (string)$err)); + self::assertInstanceOf(WriteMeta::class, $wm); + + // Verify it's gone + [$kv, , $err] = $client->Get($key); + self::assertNull($err, sprintf('KV::Get after delete returned error: %s', (string)$err)); + self::assertNull($kv, 'Expected null after deletion'); + } + + /** + * Mirrors Go TestAPI_ClientDeleteTree: put a tree, delete tree, verify gone. + */ + public function testDeleteTree(): void + { + $client = new KVClient(ConsulManager::testConfig()); + + $prefix = 'test/deltree'; + $keys = ["{$prefix}/1", "{$prefix}/2", "{$prefix}/sub/3"]; + + foreach ($keys as $k) { + [$_, $err] = $client->Put(new KVPair(Key: $k, Value: 'v')); + self::assertNull($err, sprintf('KV::Put(%s) returned error: %s', $k, (string)$err)); } + + // Verify they exist + [$list, , $err] = $client->List($prefix); + self::assertNull($err); + self::assertCount(3, $list); + + // Delete tree + [$wm, $err] = $client->DeleteTree($prefix); + self::assertNull($err, sprintf('KV::DeleteTree returned error: %s', (string)$err)); + self::assertInstanceOf(WriteMeta::class, $wm); + + // Verify all gone - should return empty list + [$list, , $err] = $client->List($prefix); + self::assertNull($err, sprintf('KV::List after delete tree returned error: %s', (string)$err)); + self::assertCount(0, $list); + } + + // --------------------------------------------------------------- + // Combined read-after-write patterns + // --------------------------------------------------------------- + + /** + * Put a key, update it, verify the value and ModifyIndex changed. + */ + public function testPutOverwrite(): void + { + $client = new KVClient(ConsulManager::testConfig()); + + $key = 'test/overwrite'; + + [$_, $err] = $client->Put(new KVPair(Key: $key, Value: 'original')); + self::assertNull($err); + + [$kv1, , $err] = $client->Get($key); + self::assertNull($err); + self::assertSame('original', $kv1->Value); + + [$_, $err] = $client->Put(new KVPair(Key: $key, Value: 'updated')); + self::assertNull($err); + + [$kv2, , $err] = $client->Get($key); + self::assertNull($err); + self::assertSame('updated', $kv2->Value); + self::assertGreaterThan($kv1->ModifyIndex, $kv2->ModifyIndex); + } + + /** + * Put empty value, verify it round-trips correctly. + */ + public function testPutEmptyValue(): void + { + $client = new KVClient(ConsulManager::testConfig()); + + $key = 'test/empty'; + + [$_, $err] = $client->Put(new KVPair(Key: $key, Value: '')); + self::assertNull($err, sprintf('KV::Put returned error: %s', (string)$err)); + + [$kv, , $err] = $client->Get($key); + self::assertNull($err, sprintf('KV::Get returned error: %s', (string)$err)); + self::assertInstanceOf(KVPair::class, $kv); + self::assertSame('', $kv->Value); + } + + /** + * Delete a key that doesn't exist - should succeed without error. + */ + public function testDeleteNonExistent(): void + { + $client = new KVClient(ConsulManager::testConfig()); + + [$wm, $err] = $client->Delete('nonexistent/delete'); + self::assertNull($err, sprintf('KV::Delete returned error: %s', (string)$err)); + self::assertInstanceOf(WriteMeta::class, $wm); } } diff --git a/tests/Usage/KV/KVClientCASTest.php b/tests/Usage/KV/KVClientCASTest.php index d212e6c2..95a3ea80 100644 --- a/tests/Usage/KV/KVClientCASTest.php +++ b/tests/Usage/KV/KVClientCASTest.php @@ -2,66 +2,227 @@ namespace DCarbone\PHPConsulAPITests\Usage\KV; +/* + Copyright 2016-2025 Daniel Carbone (daniel.p.carbone@gmail.com) + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + use DCarbone\PHPConsulAPI\KV\KVClient; use DCarbone\PHPConsulAPI\KV\KVPair; +use DCarbone\PHPConsulAPI\WriteMeta; use DCarbone\PHPConsulAPITests\ConsulManager; use DCarbone\PHPConsulAPITests\Usage\AbstractUsageTests; /** - * Class KVClientCASTest + * Replicates the upstream Go TestAPI_ClientCAS and TestAPI_ClientDeleteCAS tests. * * @internal */ final class KVClientCASTest extends AbstractUsageTests { - public const KVKey1 = 'testcaskey'; - public const KVOriginalValue = 'originalvalue'; - public const KVUpdatedValue = 'updatedvalue'; - public const KVUpdatedValue2 = 'updatedvalue2'; - - /** @var bool */ protected static bool $singlePerClass = true; - public function testKVWithCAS(): void + /** + * Mirrors Go TestAPI_ClientCAS: put, get, CAS with correct index succeeds, + * CAS with stale index fails. + */ + public function testCASSuccess(): void + { + $client = new KVClient(ConsulManager::testConfig()); + + // Create initial key + [$_, $err] = $client->Put(new KVPair(Key: 'test/cas', Value: 'original')); + self::assertNull($err, sprintf('KV::Put returned error: %s', (string)$err)); + + // Fetch to get ModifyIndex + [$kv, , $err] = $client->Get('test/cas'); + self::assertNull($err, sprintf('KV::Get returned error: %s', (string)$err)); + self::assertInstanceOf(KVPair::class, $kv); + self::assertSame('original', $kv->Value); + + // CAS with correct ModifyIndex should succeed + $kv->Value = 'updated'; + [$ok, $wm, $err] = $client->CAS($kv); + self::assertNull($err, sprintf('KV::CAS returned error: %s', (string)$err)); + self::assertTrue($ok, 'CAS with correct ModifyIndex should succeed'); + self::assertInstanceOf(WriteMeta::class, $wm); + } + + /** + * CAS with stale ModifyIndex should fail (return false). + */ + public function testCASFailsWithStaleIndex(): void { - /** @var \DCarbone\PHPConsulAPI\KV\KVPair $kv */ - /** @var \DCarbone\PHPConsulAPI\Error $err */ $client = new KVClient(ConsulManager::testConfig()); - [$_, $err] = $client->Put(new KVPair(['Key' => self::KVKey1, 'Value' => self::KVOriginalValue])); - self::assertNull($err, \sprintf('Unable to put KV: %s', $err)); + [$_, $err] = $client->Put(new KVPair(Key: 'test/cas-stale', Value: 'v1')); + self::assertNull($err); - [$kv, $_, $err] = $client->Get(self::KVKey1); - self::assertNull($err, \sprintf('Unable to get KV: %s', $err)); + [$kv, , $err] = $client->Get('test/cas-stale'); + self::assertNull($err); self::assertInstanceOf(KVPair::class, $kv); - self::assertSame(self::KVOriginalValue, $kv->Value); - $omi = $kv->ModifyIndex; + $staleIndex = $kv->ModifyIndex; + + // Update the key via regular Put to bump ModifyIndex + [$_, $err] = $client->Put(new KVPair(Key: 'test/cas-stale', Value: 'v2')); + self::assertNull($err); - $kv->Value = self::KVUpdatedValue; + // Attempt CAS with the old (stale) ModifyIndex + $kv->Value = 'v3'; + $kv->ModifyIndex = $staleIndex; + [$ok, , $err] = $client->CAS($kv); + self::assertNull($err, sprintf('KV::CAS returned error: %s', (string)$err)); + self::assertFalse($ok, 'CAS with stale ModifyIndex should fail'); + + // Verify value was NOT changed + [$kv, , $err] = $client->Get('test/cas-stale'); + self::assertNull($err); + self::assertSame('v2', $kv->Value, 'Value should remain v2 after failed CAS'); + } + + /** + * CAS with flags should persist flags on success. + */ + public function testCASWithFlags(): void + { + $client = new KVClient(ConsulManager::testConfig()); - [$ok, $_, $err] = $client->CAS($kv); - self::assertNull($err, \sprintf('Unable to update kv value: %s', $err)); + [$_, $err] = $client->Put(new KVPair(Key: 'test/cas-flags', Value: 'v1')); + self::assertNull($err); + + [$kv, , $err] = $client->Get('test/cas-flags'); + self::assertNull($err); + self::assertInstanceOf(KVPair::class, $kv); + + $kv->Value = 'v2'; + $kv->Flags = 99; + [$ok, , $err] = $client->CAS($kv); + self::assertNull($err); self::assertTrue($ok); - $kv->Value = self::KVUpdatedValue2; + [$kv2, , $err] = $client->Get('test/cas-flags'); + self::assertNull($err); + self::assertSame('v2', $kv2->Value); + self::assertSame(99, $kv2->Flags); + } + + /** + * Mirrors Go TestAPI_ClientDeleteCAS: delete with correct and stale index. + */ + public function testDeleteCASSuccess(): void + { + $client = new KVClient(ConsulManager::testConfig()); + + [$_, $err] = $client->Put(new KVPair(Key: 'test/delcas', Value: 'v1')); + self::assertNull($err); + + [$kv, , $err] = $client->Get('test/delcas'); + self::assertNull($err); + self::assertInstanceOf(KVPair::class, $kv); + + // DeleteCAS with correct index should succeed + [$ok, , $err] = $client->DeleteCAS($kv); + self::assertNull($err, sprintf('KV::DeleteCAS returned error: %s', (string)$err)); + self::assertTrue($ok, 'DeleteCAS with correct ModifyIndex should succeed'); + + // Verify it's gone + [$kv, , $err] = $client->Get('test/delcas'); + self::assertNull($err); + self::assertNull($kv, 'Expected null after DeleteCAS'); + } + + /** + * DeleteCAS with stale index should fail. + */ + public function testDeleteCASFailsWithStaleIndex(): void + { + $client = new KVClient(ConsulManager::testConfig()); + + [$_, $err] = $client->Put(new KVPair(Key: 'test/delcas-stale', Value: 'v1')); + self::assertNull($err); + + [$kv, , $err] = $client->Get('test/delcas-stale'); + self::assertNull($err); + self::assertInstanceOf(KVPair::class, $kv); + + $staleIndex = $kv->ModifyIndex; + + // Bump the ModifyIndex + [$_, $err] = $client->Put(new KVPair(Key: 'test/delcas-stale', Value: 'v2')); + self::assertNull($err); + + // Attempt DeleteCAS with stale index + $kv->ModifyIndex = $staleIndex; + [$ok, , $err] = $client->DeleteCAS($kv); + self::assertNull($err, sprintf('KV::DeleteCAS returned error: %s', (string)$err)); + self::assertFalse($ok, 'DeleteCAS with stale index should fail'); + + // Verify key still exists + [$kv2, , $err] = $client->Get('test/delcas-stale'); + self::assertNull($err); + self::assertInstanceOf(KVPair::class, $kv2); + self::assertSame('v2', $kv2->Value); + } + + /** + * Full CAS lifecycle: put → get → CAS update → CAS stale → DeleteCAS stale → get → DeleteCAS current. + * Mirrors the original combined test. + */ + public function testCASFullLifecycle(): void + { + $client = new KVClient(ConsulManager::testConfig()); + + $key = 'test/cas-lifecycle'; + + // 1. Put initial value + [$_, $err] = $client->Put(new KVPair(Key: $key, Value: 'original')); + self::assertNull($err); + + // 2. Get to capture ModifyIndex + [$kv, , $err] = $client->Get($key); + self::assertNull($err); + self::assertSame('original', $kv->Value); + $originalModifyIndex = $kv->ModifyIndex; + + // 3. CAS with correct index → success + $kv->Value = 'updated'; + [$ok, , $err] = $client->CAS($kv); + self::assertNull($err); + self::assertTrue($ok); - [$ok, $_, $err] = $client->CAS($kv); - self::assertNull($err, \sprintf('Error updating kv with old cas: %s', $err)); - self::assertFalse($ok, 'Expected false when trying to update key with old cas'); + // 4. CAS with stale index → failure + $kv->Value = 'should-not-be-set'; + [$ok, , $err] = $client->CAS($kv); + self::assertNull($err); + self::assertFalse($ok, 'CAS with old ModifyIndex should fail'); - [$ok, $_, $err] = $client->DeleteCAS($kv); - self::assertNull($err, \sprintf('Error deleting kv with old cas: %s', $err)); - self::assertFalse($ok, 'Expected false when trying to delete key with old cas'); + // 5. DeleteCAS with stale index → failure + [$ok, , $err] = $client->DeleteCAS($kv); + self::assertNull($err); + self::assertFalse($ok, 'DeleteCAS with old ModifyIndex should fail'); - [$kv, $_, $err] = $client->Get(self::KVKey1); - self::assertNull($err, \sprintf('Error retrieving updated key: %s', $err)); + // 6. Verify value is the successful update + [$kv, , $err] = $client->Get($key); + self::assertNull($err); self::assertInstanceOf(KVPair::class, $kv); - self::assertNotSame($omi, $kv->ModifyIndex, 'Expected ModifyIndex to be different'); - self::assertSame(self::KVUpdatedValue, $kv->Value, 'KV Value was not actually updated'); + self::assertNotSame($originalModifyIndex, $kv->ModifyIndex); + self::assertSame('updated', $kv->Value); - [$ok, $_, $err] = $client->DeleteCAS($kv); - self::assertNull($err, \sprintf('Error deleting key: %s', $err)); - self::assertTrue($ok, 'Expected true when deleting key with updated cas'); + // 7. DeleteCAS with current index → success + [$ok, , $err] = $client->DeleteCAS($kv); + self::assertNull($err); + self::assertTrue($ok, 'DeleteCAS with current ModifyIndex should succeed'); } } diff --git a/tests/Usage/KV/KVClientLockTest.php b/tests/Usage/KV/KVClientLockTest.php index 615455d2..79acdf2b 100644 --- a/tests/Usage/KV/KVClientLockTest.php +++ b/tests/Usage/KV/KVClientLockTest.php @@ -2,6 +2,22 @@ namespace DCarbone\PHPConsulAPITests\Usage\KV; +/* + Copyright 2016-2025 Daniel Carbone (daniel.p.carbone@gmail.com) + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + use DCarbone\Go\Time; use DCarbone\PHPConsulAPI\Consul; use DCarbone\PHPConsulAPI\KV\KVClient; @@ -13,45 +29,148 @@ use DCarbone\PHPConsulAPITests\Usage\AbstractUsageTests; /** - * Class KVClientLockTest + * Replicates the upstream Go TestAPI_ClientAcquireRelease test. * * @internal */ final class KVClientLockTest extends AbstractUsageTests { - /** @var bool */ protected static bool $singlePerClass = true; + /** + * Mirrors Go TestAPI_ClientAcquireRelease: create a session, acquire a lock, + * verify the key is locked, release the lock, verify unlocked. + */ public function testAcquireAndRelease(): void { - static $name = 'lockme'; - static $key = 'lockable'; - $conf = ConsulManager::testConfig(); $kvClient = new KVClient($conf); $sessionClient = new SessionClient($conf); + // Create session with no checks and short TTL [$id, $_, $err] = $sessionClient->CreateNoChecks( new SessionEntry( - [ - 'Name' => $name, - 'TTL' => '10s', - 'LockDelay' => new Time\Duration(0), - 'Behavior' => Consul::SessionBehaviorDelete, - ] + Name: 'lock-test', + TTL: '10s', + LockDelay: new Time\Duration(0), + Behavior: Consul::SessionBehaviorDelete, ) ); - self::assertNull($err, \sprintf('Error creating session: %s', $err)); + self::assertNull($err, sprintf('Error creating session: %s', (string)$err)); + self::assertNotEmpty($id, 'Expected non-empty session ID'); - $kv = new KVPair(['Key' => $key, 'Value' => 'whatever', 'Session' => $id]); + $key = 'test/lockable'; + + // Acquire lock + $kv = new KVPair(Key: $key, Value: 'locked-value', Session: $id); [$wm, $err] = $kvClient->Acquire($kv); - self::assertNull($err, \sprintf('Error acquiring lock: %s', $err)); + self::assertNull($err, sprintf('Error acquiring lock: %s', (string)$err)); + self::assertInstanceOf(WriteMeta::class, $wm); + + // Verify the key is locked with the correct session + [$kv, , $err] = $kvClient->Get($key); + self::assertNull($err, sprintf('Error getting key after acquire: %s', (string)$err)); + self::assertInstanceOf(KVPair::class, $kv); + self::assertSame($id, $kv->Session, 'Session ID should match after acquire'); + self::assertSame('locked-value', $kv->Value); + self::assertGreaterThan(0, $kv->LockIndex, 'LockIndex should be > 0 after acquire'); + + // Release lock + $kv->Session = $id; + [$wm, $err] = $kvClient->Release($kv); + self::assertNull($err, sprintf('Error releasing lock: %s', (string)$err)); self::assertInstanceOf(WriteMeta::class, $wm); - [$kv, $_, $err] = $kvClient->Get($key); - self::assertNull($err, \sprintf('Error retrieving key: %s', $err)); + // Verify the key is unlocked + [$kv, , $err] = $kvClient->Get($key); + self::assertNull($err, sprintf('Error getting key after release: %s', (string)$err)); + self::assertInstanceOf(KVPair::class, $kv); + self::assertSame('', $kv->Session, 'Session should be empty after release'); + self::assertSame('locked-value', $kv->Value, 'Value should be preserved after release'); + } + + /** + * Acquire lock, then attempt to acquire same key with a different session - should fail. + */ + public function testAcquireConflict(): void + { + $conf = ConsulManager::testConfig(); + $kvClient = new KVClient($conf); + $sessionClient = new SessionClient($conf); + + // Create two sessions + [$session1, , $err] = $sessionClient->CreateNoChecks( + new SessionEntry( + Name: 'lock-conflict-1', + TTL: '10s', + LockDelay: new Time\Duration(0), + Behavior: Consul::SessionBehaviorRelease, + ) + ); + self::assertNull($err); + + [$session2, , $err] = $sessionClient->CreateNoChecks( + new SessionEntry( + Name: 'lock-conflict-2', + TTL: '10s', + LockDelay: new Time\Duration(0), + Behavior: Consul::SessionBehaviorRelease, + ) + ); + self::assertNull($err); + + $key = 'test/lock-conflict'; + + // Session 1 acquires lock + $kv = new KVPair(Key: $key, Value: 'session1', Session: $session1); + [$wm, $err] = $kvClient->Acquire($kv); + self::assertNull($err); + self::assertInstanceOf(WriteMeta::class, $wm); + + // Verify session 1 holds the lock + [$kv, , $err] = $kvClient->Get($key); + self::assertNull($err); + self::assertSame($session1, $kv->Session); + + // Session 2 attempts to acquire the same lock - the key should still be held by session 1 + $kv2 = new KVPair(Key: $key, Value: 'session2', Session: $session2); + [$_, $err] = $kvClient->Acquire($kv2); + self::assertNull($err); + + // Verify session 1 still holds the lock + [$kv, , $err] = $kvClient->Get($key); + self::assertNull($err); + self::assertSame($session1, $kv->Session, 'Session 1 should still hold the lock'); + } + + /** + * Acquire with flags should persist. + */ + public function testAcquireWithFlags(): void + { + $conf = ConsulManager::testConfig(); + $kvClient = new KVClient($conf); + $sessionClient = new SessionClient($conf); + + [$id, , $err] = $sessionClient->CreateNoChecks( + new SessionEntry( + Name: 'lock-flags', + TTL: '10s', + LockDelay: new Time\Duration(0), + Behavior: Consul::SessionBehaviorRelease, + ) + ); + self::assertNull($err); + + $key = 'test/lock-flags'; + $kv = new KVPair(Key: $key, Value: 'flagged', Session: $id, Flags: 77); + [$_, $err] = $kvClient->Acquire($kv); + self::assertNull($err); + + [$kv, , $err] = $kvClient->Get($key); + self::assertNull($err); self::assertInstanceOf(KVPair::class, $kv); + self::assertSame(77, $kv->Flags); self::assertSame($id, $kv->Session); - self::assertSame('whatever', $kv->Value); } } diff --git a/tests/Usage/KV/KVClientTest.php b/tests/Usage/KV/KVClientTest.php index 49e1d357..3529d21f 100644 --- a/tests/Usage/KV/KVClientTest.php +++ b/tests/Usage/KV/KVClientTest.php @@ -3,7 +3,7 @@ namespace DCarbone\PHPConsulAPITests\Usage\KV; /* - Copyright 2016-2021 Daniel Carbone (daniel.p.carbone@gmail.com) + Copyright 2016-2025 Daniel Carbone (daniel.p.carbone@gmail.com) Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -18,12 +18,13 @@ limitations under the License. */ +use DCarbone\PHPConsulAPI\Consul; use DCarbone\PHPConsulAPI\KV\KVClient; use DCarbone\PHPConsulAPITests\ConsulManager; use PHPUnit\Framework\TestCase; /** - * Class KVClientTest + * Basic client instantiation tests. * * @internal */ @@ -34,4 +35,11 @@ public function testCanConstructClient(): void $kv = new KVClient(ConsulManager::testConfig()); self::assertInstanceOf(KVClient::class, $kv); } + + public function testCanConstructViaConsul(): void + { + $consul = new Consul(ConsulManager::testConfig()); + self::assertInstanceOf(KVClient::class, $consul->KV); + self::assertInstanceOf(KVClient::class, $consul->KV()); + } } diff --git a/tests/Usage/KV/KVClientTxnTest.php b/tests/Usage/KV/KVClientTxnTest.php new file mode 100644 index 00000000..86b05199 --- /dev/null +++ b/tests/Usage/KV/KVClientTxnTest.php @@ -0,0 +1,364 @@ +Txn([ + new TxnOp( + KV: new KVTxnOp( + Verb: KVOp::KVSet, + Key: $key, + Value: $value, + ), + ), + ]); + + self::assertNull($txnResp->Err, sprintf('KV::Txn set returned error: %s', (string)$txnResp->Err)); + self::assertTrue($txnResp->OK, 'Txn should be OK'); + self::assertNotNull($txnResp->KVTxnResponse); + self::assertEmpty($txnResp->KVTxnResponse->Errors, 'Txn set should have no errors'); + self::assertNotEmpty($txnResp->KVTxnResponse->Results, 'Txn set should have results'); + + // Verify the result KV pair + $result = $txnResp->KVTxnResponse->Results[0]; + self::assertNotNull($result->KV); + self::assertSame($key, $result->KV->Key); + + // Verify via regular Get + [$kv, , $err] = $client->Get($key); + self::assertNull($err, sprintf('KV::Get returned error: %s', (string)$err)); + self::assertInstanceOf(KVPair::class, $kv); + self::assertSame($value, $kv->Value); + } + + /** + * Get key via transaction. + */ + public function testTxnGet(): void + { + $client = new KVClient(ConsulManager::testConfig()); + + $key = 'test/txn/get'; + $value = 'txn-get-value'; + + // Put the key first + [$_, $err] = $client->Put(new KVPair(Key: $key, Value: $value)); + self::assertNull($err); + + // Get via Txn + $txnResp = $client->Txn([ + new TxnOp( + KV: new KVTxnOp( + Verb: KVOp::KVGet, + Key: $key, + ), + ), + ]); + + self::assertNull($txnResp->Err, sprintf('KV::Txn get returned error: %s', (string)$txnResp->Err)); + self::assertTrue($txnResp->OK); + self::assertNotNull($txnResp->KVTxnResponse); + self::assertEmpty($txnResp->KVTxnResponse->Errors); + self::assertCount(1, $txnResp->KVTxnResponse->Results); + + $result = $txnResp->KVTxnResponse->Results[0]; + self::assertNotNull($result->KV); + self::assertSame($key, $result->KV->Key); + self::assertSame($value, $result->KV->Value); + } + + /** + * Multiple operations in a single transaction. + */ + public function testTxnMultipleOps(): void + { + $client = new KVClient(ConsulManager::testConfig()); + + $txnResp = $client->Txn([ + new TxnOp( + KV: new KVTxnOp( + Verb: KVOp::KVSet, + Key: 'test/txn/multi/a', + Value: 'val-a', + ), + ), + new TxnOp( + KV: new KVTxnOp( + Verb: KVOp::KVSet, + Key: 'test/txn/multi/b', + Value: 'val-b', + ), + ), + new TxnOp( + KV: new KVTxnOp( + Verb: KVOp::KVSet, + Key: 'test/txn/multi/c', + Value: 'val-c', + ), + ), + ]); + + self::assertNull($txnResp->Err, sprintf('KV::Txn returned error: %s', (string)$txnResp->Err)); + self::assertTrue($txnResp->OK); + self::assertNotNull($txnResp->KVTxnResponse); + self::assertEmpty($txnResp->KVTxnResponse->Errors); + self::assertCount(3, $txnResp->KVTxnResponse->Results); + + // Verify via Get + [$kv, , $err] = $client->Get('test/txn/multi/a'); + self::assertNull($err); + self::assertSame('val-a', $kv->Value); + + [$kv, , $err] = $client->Get('test/txn/multi/b'); + self::assertNull($err); + self::assertSame('val-b', $kv->Value); + + [$kv, , $err] = $client->Get('test/txn/multi/c'); + self::assertNull($err); + self::assertSame('val-c', $kv->Value); + } + + /** + * Delete via transaction. + */ + public function testTxnDelete(): void + { + $client = new KVClient(ConsulManager::testConfig()); + + $key = 'test/txn/delete'; + + // Put key first + [$_, $err] = $client->Put(new KVPair(Key: $key, Value: 'to-delete')); + self::assertNull($err); + + // Delete via Txn + $txnResp = $client->Txn([ + new TxnOp( + KV: new KVTxnOp( + Verb: KVOp::KVDelete, + Key: $key, + ), + ), + ]); + + self::assertNull($txnResp->Err, sprintf('KV::Txn delete returned error: %s', (string)$txnResp->Err)); + self::assertTrue($txnResp->OK); + + // Verify deleted + [$kv, , $err] = $client->Get($key); + self::assertNull($err); + self::assertNull($kv, 'Expected null after Txn delete'); + } + + /** + * CAS via transaction: set with ModifyIndex check. + */ + public function testTxnCAS(): void + { + $client = new KVClient(ConsulManager::testConfig()); + + $key = 'test/txn/cas'; + + // Put initial value + [$_, $err] = $client->Put(new KVPair(Key: $key, Value: 'v1')); + self::assertNull($err); + + // Get ModifyIndex + [$kv, , $err] = $client->Get($key); + self::assertNull($err); + self::assertInstanceOf(KVPair::class, $kv); + + // CAS via Txn with correct index + $txnResp = $client->Txn([ + new TxnOp( + KV: new KVTxnOp( + Verb: KVOp::KVCAS, + Key: $key, + Value: 'v2', + Index: $kv->ModifyIndex, + ), + ), + ]); + + self::assertNull($txnResp->Err); + self::assertTrue($txnResp->OK); + + // Verify updated + [$kv, , $err] = $client->Get($key); + self::assertNull($err); + self::assertSame('v2', $kv->Value); + } + + /** + * DeleteTree via transaction. + */ + public function testTxnDeleteTree(): void + { + $client = new KVClient(ConsulManager::testConfig()); + + $prefix = 'test/txn/tree'; + + // Put several keys under the prefix + [$_, $err] = $client->Put(new KVPair(Key: "{$prefix}/a", Value: 'va')); + self::assertNull($err); + [$_, $err] = $client->Put(new KVPair(Key: "{$prefix}/b", Value: 'vb')); + self::assertNull($err); + + // Delete tree via Txn + $txnResp = $client->Txn([ + new TxnOp( + KV: new KVTxnOp( + Verb: KVOp::KVDeleteTree, + Key: $prefix, + ), + ), + ]); + + self::assertNull($txnResp->Err, sprintf('KV::Txn delete-tree returned error: %s', (string)$txnResp->Err)); + self::assertTrue($txnResp->OK); + + // Verify tree is gone + [$list, , $err] = $client->List($prefix); + self::assertNull($err); + self::assertCount(0, $list); + } + + /** + * Check-not-exists via transaction. + */ + public function testTxnCheckNotExists(): void + { + $client = new KVClient(ConsulManager::testConfig()); + + $key = 'test/txn/check-not-exists'; + + // Ensure key doesn't exist + [$_, $err] = $client->Delete($key); + self::assertNull($err); + + // check-not-exists should succeed when key doesn't exist + $txnResp = $client->Txn([ + new TxnOp( + KV: new KVTxnOp( + Verb: KVOp::KVCheckNotExists, + Key: $key, + ), + ), + ]); + + self::assertNull($txnResp->Err, sprintf('KV::Txn returned error: %s', (string)$txnResp->Err)); + self::assertTrue($txnResp->OK); + } + + /** + * Set and get in the same transaction. + */ + public function testTxnSetAndGet(): void + { + $client = new KVClient(ConsulManager::testConfig()); + + $key = 'test/txn/set-get'; + + // Set then get in same txn + $txnResp = $client->Txn([ + new TxnOp( + KV: new KVTxnOp( + Verb: KVOp::KVSet, + Key: $key, + Value: 'set-value', + ), + ), + new TxnOp( + KV: new KVTxnOp( + Verb: KVOp::KVGet, + Key: $key, + ), + ), + ]); + + self::assertNull($txnResp->Err, sprintf('KV::Txn returned error: %s', (string)$txnResp->Err)); + self::assertTrue($txnResp->OK); + self::assertNotNull($txnResp->KVTxnResponse); + self::assertEmpty($txnResp->KVTxnResponse->Errors); + self::assertCount(2, $txnResp->KVTxnResponse->Results); + + // Second result should be the get with the value + $getResult = $txnResp->KVTxnResponse->Results[1]; + self::assertNotNull($getResult->KV); + self::assertSame($key, $getResult->KV->Key); + self::assertSame('set-value', $getResult->KV->Value); + } + + /** + * Set with flags via transaction. + */ + public function testTxnSetWithFlags(): void + { + $client = new KVClient(ConsulManager::testConfig()); + + $key = 'test/txn/flags'; + + $txnResp = $client->Txn([ + new TxnOp( + KV: new KVTxnOp( + Verb: KVOp::KVSet, + Key: $key, + Value: 'flagged', + Flags: 123, + ), + ), + ]); + + self::assertNull($txnResp->Err); + self::assertTrue($txnResp->OK); + + [$kv, , $err] = $client->Get($key); + self::assertNull($err); + self::assertInstanceOf(KVPair::class, $kv); + self::assertSame('flagged', $kv->Value); + self::assertSame(123, $kv->Flags); + } +} + diff --git a/tests/Usage/Operator/OperatorAutopilotTest.php b/tests/Usage/Operator/OperatorAutopilotTest.php index e77a82fb..6fd456ac 100644 --- a/tests/Usage/Operator/OperatorAutopilotTest.php +++ b/tests/Usage/Operator/OperatorAutopilotTest.php @@ -39,11 +39,11 @@ public function testCanGetAutopilotConfiguration(): void $client = new OperatorClient(ConsulManager::testConfig()); [$conf, $err] = $client->AutopilotGetConfiguration(); - self::assertNull($err, \sprintf('Unable to list autopilot configuration: %s', $err)); + self::assertNull($err, sprintf('Unable to list autopilot configuration: %s', $err)); self::assertInstanceOf( AutopilotConfiguration::class, $conf, - \sprintf('Expected instance of %s, saw: %s', AutopilotConfiguration::class, \json_encode($conf)) + sprintf('Expected instance of %s, saw: %s', AutopilotConfiguration::class, json_encode($conf)) ); } diff --git a/tests/Usage/Operator/ReadableDurationTest.php b/tests/Usage/Operator/ReadableDurationTest.php index 53db8ae9..6a55d0e5 100644 --- a/tests/Usage/Operator/ReadableDurationTest.php +++ b/tests/Usage/Operator/ReadableDurationTest.php @@ -18,8 +18,6 @@ limitations under the License. */ -use DCarbone\Go\Time; -use DCarbone\PHPConsulAPI\Operator\ReadableDuration; use PHPUnit\Framework\TestCase; /** @@ -31,7 +29,6 @@ final class ReadableDurationTest extends TestCase { public function testReadableJsonEncoding(): void { - $rd = new ReadableDuration(\time() * Time::Second); - self::assertSame('"' . (string)$rd . '"', \json_encode($rd)); + self::markTestSkipped('ReadableDuration class was removed during modernization'); } } diff --git a/tests/Usage/Random/RandomWhateverTest.php b/tests/Usage/Random/RandomWhateverTest.php index 965022be..13acd86d 100644 --- a/tests/Usage/Random/RandomWhateverTest.php +++ b/tests/Usage/Random/RandomWhateverTest.php @@ -39,7 +39,7 @@ public function testDynamicFieldAssignment(): void $this->assertIsObject($dec); - $kvp = new KVPair((array)$dec, false); + $kvp = KVPair::jsonUnserialize($dec); self::assertEquals($v, $kvp->{$k}); } diff --git a/tests/Usage/RequestUsageTest.php b/tests/Usage/RequestUsageTest.php index 2e0bc48a..33acc956 100644 --- a/tests/Usage/RequestUsageTest.php +++ b/tests/Usage/RequestUsageTest.php @@ -20,7 +20,7 @@ use DCarbone\PHPConsulAPI\KV\KVPair; use DCarbone\PHPConsulAPI\QueryOptions; -use DCarbone\PHPConsulAPI\Request; +use DCarbone\PHPConsulAPI\PHPLib\Request; use DCarbone\PHPConsulAPI\WriteOptions; use DCarbone\PHPConsulAPITests\ConsulManager; use PHPUnit\Framework\TestCase; @@ -79,7 +79,7 @@ public function testCanCreatePsr7Request(): void public function testCanSetQueryOptions(): void { $r = new Request('GET', 'kv', ConsulManager::testConfig(), null); - $r->applyOptions(new QueryOptions(['Pretty' => true])); + $r->applyOptions(new QueryOptions(Pretty: true)); $psr7 = $r->toPsrRequest(); $uri = $psr7->getUri(); @@ -92,7 +92,7 @@ public function testCanSetQueryOptions(): void public function testCanSetWriteOptions(): void { $r = new Request('GET', 'kv', ConsulManager::testConfig(), null); - $r->applyOptions(new WriteOptions(['Datacenter' => 'dc1'])); + $r->applyOptions(new WriteOptions(Datacenter: 'dc1')); $psr7 = $r->toPsrRequest(); $uri = $psr7->getUri(); diff --git a/tests/Usage/Session/SessionClientUsageTest.php b/tests/Usage/Session/SessionClientUsageTest.php index 47cdeca3..93669827 100644 --- a/tests/Usage/Session/SessionClientUsageTest.php +++ b/tests/Usage/Session/SessionClientUsageTest.php @@ -31,17 +31,17 @@ public function testNoChecksLifecycle(): void /** @var \DCarbone\PHPConsulAPI\Error $err */ $client = new SessionClient(ConsulManager::testConfig()); - [$id, $wm, $err] = $client->CreateNoChecks(new SessionEntry([ - 'Name' => $name, - 'Behavior' => Consul::SessionBehaviorDelete, - 'TTL' => $ttl, - ])); - self::assertNull($err, \sprintf('Error creating session: %s', $err)); + [$id, $wm, $err] = $client->CreateNoChecks(new SessionEntry( + Name: $name, + Behavior: Consul::SessionBehaviorDelete, + TTL: $ttl, + )); + self::assertNull($err, sprintf('Error creating session: %s', $err)); self::assertInstanceOf(WriteMeta::class, $wm); self::assertIsString($id, 'Expected ID to be string'); [$sessions, $qm, $err] = $client->Info($id); - self::assertNull($err, \sprintf('Error getting %s info: %s', $id, $err)); + self::assertNull($err, sprintf('Error getting %s info: %s', $id, $err)); self::assertInstanceOf(QueryMeta::class, $qm); self::assertIsArray($sessions); self::assertCount(1, $sessions); @@ -58,17 +58,17 @@ public function testNoChecksLifecycle(): void self::assertSame(15 * Time::Second, $session->LockDelay->Nanoseconds()); [$sessions, $wm, $err] = $client->Renew($id); - self::assertNull($err, \sprintf('Error renewing session: %s', $err)); + self::assertNull($err, sprintf('Error renewing session: %s', $err)); self::assertInstanceOf(WriteMeta::class, $wm); self::assertIsArray($sessions); self::assertCount(1, $sessions); self::assertContainsOnlyInstancesOf(SessionEntry::class, $sessions); [$_, $err] = $client->Destroy($id); - self::assertNull($err, \sprintf('Error destroying session: %s', $err)); + self::assertNull($err, sprintf('Error destroying session: %s', $err)); [$sessions, $_, $err] = $client->Info($id); - self::assertNull($err, \sprintf('Error getting list after expected expiration: %s', $err)); + self::assertNull($err, sprintf('Error getting list after expected expiration: %s', $err)); self::assertIsArray($sessions, 'Expected $sessions to be an array'); self::assertCount(0, $sessions, 'Expected $sessions to be empty'); } diff --git a/tests/Usage/ValuesUsageTest.php b/tests/Usage/ValuesUsageTest.php index 291e4a54..8055cd96 100644 --- a/tests/Usage/ValuesUsageTest.php +++ b/tests/Usage/ValuesUsageTest.php @@ -18,7 +18,7 @@ limitations under the License. */ -use DCarbone\PHPConsulAPI\Values; +use DCarbone\PHPConsulAPI\PHPLib\Values; use PHPUnit\Framework\TestCase; /** diff --git a/tests/consul.hcl b/tests/consul.hcl new file mode 100644 index 00000000..f799b27b --- /dev/null +++ b/tests/consul.hcl @@ -0,0 +1,7 @@ +acl { + enabled = true + default_policy = "allow" + tokens { + initial_management = "00000000-0000-0000-0000-000000000001" + } +} \ No newline at end of file diff --git a/tests/funcs.php b/tests/funcs.php index a7102800..83429fff 100644 --- a/tests/funcs.php +++ b/tests/funcs.php @@ -50,7 +50,7 @@ function determine_param_hint(Compound $compoundHint): array $others[] = $hint; } } - if (1 === \count($others)) { + if (1 === count($others)) { $out[1] = $others[0]; } return $out; diff --git a/tests/run_consul.sh b/tests/run_consul.sh index 45704659..c5e6b071 100755 --- a/tests/run_consul.sh +++ b/tests/run_consul.sh @@ -1,10 +1,8 @@ -#!/usr/bin/env bash +#!/bin/sh -DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" -TMPDIR=${DIR}/../tmp +DIR="$(cd "$(dirname "$0")" && pwd)" +TMPDIR="${DIR}/../tmp" -consul_args=("$@") +echo "Starting Single consul instance with flags \"$*\"" -echo Starting Single consul instance with flags \""${consul_args[*]}"\" - -/usr/bin/env consul agent "${consul_args[@]}" >> "${TMPDIR}"/consul.log 2>&1 & echo $! > "${TMPDIR}"/consul.pid +/usr/bin/env consul agent "$@" >> "${TMPDIR}/consul.log" 2>&1 & echo $! > "${TMPDIR}/consul.pid" diff --git a/tests/stop_consul.sh b/tests/stop_consul.sh index 4b3e1e97..5a4c6c08 100755 --- a/tests/stop_consul.sh +++ b/tests/stop_consul.sh @@ -1,8 +1,8 @@ -#!/usr/bin/env bash +#!/bin/sh -DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" -TMPDIR=${DIR}/../tmp +DIR="$(cd "$(dirname "$0")" && pwd)" +TMPDIR="${DIR}/../tmp" -if [ -e "${TMPDIR}"/consul.pid ]; then - kill -SIGINT "$(cat "${TMPDIR}"/consul.pid)" +if [ -e "${TMPDIR}/consul.pid" ]; then + kill -INT "$(cat "${TMPDIR}/consul.pid")" fi diff --git a/tools/php-cs-fixer/composer.lock b/tools/php-cs-fixer/composer.lock index 3df88f8b..fc8b95ef 100644 --- a/tools/php-cs-fixer/composer.lock +++ b/tools/php-cs-fixer/composer.lock @@ -196,16 +196,16 @@ }, { "name": "composer/semver", - "version": "3.4.3", + "version": "3.4.4", "source": { "type": "git", "url": "https://github.com/composer/semver.git", - "reference": "4313d26ada5e0c4edfbd1dc481a92ff7bff91f12" + "reference": "198166618906cb2de69b95d7d47e5fa8aa1b2b95" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/semver/zipball/4313d26ada5e0c4edfbd1dc481a92ff7bff91f12", - "reference": "4313d26ada5e0c4edfbd1dc481a92ff7bff91f12", + "url": "https://api.github.com/repos/composer/semver/zipball/198166618906cb2de69b95d7d47e5fa8aa1b2b95", + "reference": "198166618906cb2de69b95d7d47e5fa8aa1b2b95", "shasum": "" }, "require": { @@ -257,7 +257,7 @@ "support": { "irc": "ircs://irc.libera.chat:6697/composer", "issues": "https://github.com/composer/semver/issues", - "source": "https://github.com/composer/semver/tree/3.4.3" + "source": "https://github.com/composer/semver/tree/3.4.4" }, "funding": [ { @@ -267,13 +267,9 @@ { "url": "https://github.com/composer", "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/composer/composer", - "type": "tidelift" } ], - "time": "2024-09-19T14:15:21+00:00" + "time": "2025-08-20T19:15:30+00:00" }, { "name": "composer/xdebug-handler", @@ -390,16 +386,16 @@ }, { "name": "fidry/cpu-core-counter", - "version": "1.2.0", + "version": "1.3.0", "source": { "type": "git", "url": "https://github.com/theofidry/cpu-core-counter.git", - "reference": "8520451a140d3f46ac33042715115e290cf5785f" + "reference": "db9508f7b1474469d9d3c53b86f817e344732678" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/theofidry/cpu-core-counter/zipball/8520451a140d3f46ac33042715115e290cf5785f", - "reference": "8520451a140d3f46ac33042715115e290cf5785f", + "url": "https://api.github.com/repos/theofidry/cpu-core-counter/zipball/db9508f7b1474469d9d3c53b86f817e344732678", + "reference": "db9508f7b1474469d9d3c53b86f817e344732678", "shasum": "" }, "require": { @@ -409,10 +405,10 @@ "fidry/makefile": "^0.2.0", "fidry/php-cs-fixer-config": "^1.1.2", "phpstan/extension-installer": "^1.2.0", - "phpstan/phpstan": "^1.9.2", - "phpstan/phpstan-deprecation-rules": "^1.0.0", - "phpstan/phpstan-phpunit": "^1.2.2", - "phpstan/phpstan-strict-rules": "^1.4.4", + "phpstan/phpstan": "^2.0", + "phpstan/phpstan-deprecation-rules": "^2.0.0", + "phpstan/phpstan-phpunit": "^2.0", + "phpstan/phpstan-strict-rules": "^2.0", "phpunit/phpunit": "^8.5.31 || ^9.5.26", "webmozarts/strict-phpunit": "^7.5" }, @@ -439,7 +435,7 @@ ], "support": { "issues": "https://github.com/theofidry/cpu-core-counter/issues", - "source": "https://github.com/theofidry/cpu-core-counter/tree/1.2.0" + "source": "https://github.com/theofidry/cpu-core-counter/tree/1.3.0" }, "funding": [ { @@ -447,20 +443,20 @@ "type": "github" } ], - "time": "2024-08-06T10:04:20+00:00" + "time": "2025-08-14T07:29:31+00:00" }, { "name": "friendsofphp/php-cs-fixer", - "version": "v3.74.0", + "version": "v3.75.0", "source": { "type": "git", "url": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer.git", - "reference": "6b7cb12a6cf592fd9a2b46a2d5d4c3b44003973d" + "reference": "399a128ff2fdaf4281e4e79b755693286cdf325c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/6b7cb12a6cf592fd9a2b46a2d5d4c3b44003973d", - "reference": "6b7cb12a6cf592fd9a2b46a2d5d4c3b44003973d", + "url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/399a128ff2fdaf4281e4e79b755693286cdf325c", + "reference": "399a128ff2fdaf4281e4e79b755693286cdf325c", "shasum": "" }, "require": { @@ -543,7 +539,7 @@ ], "support": { "issues": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/issues", - "source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.74.0" + "source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.75.0" }, "funding": [ { @@ -551,7 +547,7 @@ "type": "github" } ], - "time": "2025-03-27T22:31:30+00:00" + "time": "2025-03-31T18:40:42+00:00" }, { "name": "psr/container", @@ -1003,23 +999,23 @@ }, { "name": "react/promise", - "version": "v3.2.0", + "version": "v3.3.0", "source": { "type": "git", "url": "https://github.com/reactphp/promise.git", - "reference": "8a164643313c71354582dc850b42b33fa12a4b63" + "reference": "23444f53a813a3296c1368bb104793ce8d88f04a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/reactphp/promise/zipball/8a164643313c71354582dc850b42b33fa12a4b63", - "reference": "8a164643313c71354582dc850b42b33fa12a4b63", + "url": "https://api.github.com/repos/reactphp/promise/zipball/23444f53a813a3296c1368bb104793ce8d88f04a", + "reference": "23444f53a813a3296c1368bb104793ce8d88f04a", "shasum": "" }, "require": { "php": ">=7.1.0" }, "require-dev": { - "phpstan/phpstan": "1.10.39 || 1.4.10", + "phpstan/phpstan": "1.12.28 || 1.4.10", "phpunit/phpunit": "^9.6 || ^7.5" }, "type": "library", @@ -1064,7 +1060,7 @@ ], "support": { "issues": "https://github.com/reactphp/promise/issues", - "source": "https://github.com/reactphp/promise/tree/v3.2.0" + "source": "https://github.com/reactphp/promise/tree/v3.3.0" }, "funding": [ { @@ -1072,7 +1068,7 @@ "type": "open_collective" } ], - "time": "2024-05-24T10:39:05+00:00" + "time": "2025-08-19T18:57:03+00:00" }, { "name": "react/socket", @@ -1234,29 +1230,29 @@ }, { "name": "sebastian/diff", - "version": "7.0.0", + "version": "5.1.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/diff.git", - "reference": "7ab1ea946c012266ca32390913653d844ecd085f" + "reference": "c41e007b4b62af48218231d6c2275e4c9b975b2e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/7ab1ea946c012266ca32390913653d844ecd085f", - "reference": "7ab1ea946c012266ca32390913653d844ecd085f", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/c41e007b4b62af48218231d6c2275e4c9b975b2e", + "reference": "c41e007b4b62af48218231d6c2275e4c9b975b2e", "shasum": "" }, "require": { - "php": ">=8.3" + "php": ">=8.1" }, "require-dev": { - "phpunit/phpunit": "^12.0", - "symfony/process": "^7.2" + "phpunit/phpunit": "^10.0", + "symfony/process": "^6.4" }, "type": "library", "extra": { "branch-alias": { - "dev-main": "7.0-dev" + "dev-main": "5.1-dev" } }, "autoload": { @@ -1289,7 +1285,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/diff/issues", "security": "https://github.com/sebastianbergmann/diff/security/policy", - "source": "https://github.com/sebastianbergmann/diff/tree/7.0.0" + "source": "https://github.com/sebastianbergmann/diff/tree/5.1.1" }, "funding": [ { @@ -1297,50 +1293,51 @@ "type": "github" } ], - "time": "2025-02-07T04:55:46+00:00" + "time": "2024-03-02T07:15:17+00:00" }, { "name": "symfony/console", - "version": "v7.2.1", + "version": "v6.4.26", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "fefcc18c0f5d0efe3ab3152f15857298868dc2c3" + "reference": "492de6dfd93910d7d7a729c5a04ddcd2b9e99c4f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/fefcc18c0f5d0efe3ab3152f15857298868dc2c3", - "reference": "fefcc18c0f5d0efe3ab3152f15857298868dc2c3", + "url": "https://api.github.com/repos/symfony/console/zipball/492de6dfd93910d7d7a729c5a04ddcd2b9e99c4f", + "reference": "492de6dfd93910d7d7a729c5a04ddcd2b9e99c4f", "shasum": "" }, "require": { - "php": ">=8.2", + "php": ">=8.1", + "symfony/deprecation-contracts": "^2.5|^3", "symfony/polyfill-mbstring": "~1.0", "symfony/service-contracts": "^2.5|^3", - "symfony/string": "^6.4|^7.0" + "symfony/string": "^5.4|^6.0|^7.0" }, "conflict": { - "symfony/dependency-injection": "<6.4", - "symfony/dotenv": "<6.4", - "symfony/event-dispatcher": "<6.4", - "symfony/lock": "<6.4", - "symfony/process": "<6.4" + "symfony/dependency-injection": "<5.4", + "symfony/dotenv": "<5.4", + "symfony/event-dispatcher": "<5.4", + "symfony/lock": "<5.4", + "symfony/process": "<5.4" }, "provide": { "psr/log-implementation": "1.0|2.0|3.0" }, "require-dev": { "psr/log": "^1|^2|^3", - "symfony/config": "^6.4|^7.0", - "symfony/dependency-injection": "^6.4|^7.0", - "symfony/event-dispatcher": "^6.4|^7.0", + "symfony/config": "^5.4|^6.0|^7.0", + "symfony/dependency-injection": "^5.4|^6.0|^7.0", + "symfony/event-dispatcher": "^5.4|^6.0|^7.0", "symfony/http-foundation": "^6.4|^7.0", "symfony/http-kernel": "^6.4|^7.0", - "symfony/lock": "^6.4|^7.0", - "symfony/messenger": "^6.4|^7.0", - "symfony/process": "^6.4|^7.0", - "symfony/stopwatch": "^6.4|^7.0", - "symfony/var-dumper": "^6.4|^7.0" + "symfony/lock": "^5.4|^6.0|^7.0", + "symfony/messenger": "^5.4|^6.0|^7.0", + "symfony/process": "^5.4|^6.0|^7.0", + "symfony/stopwatch": "^5.4|^6.0|^7.0", + "symfony/var-dumper": "^5.4|^6.0|^7.0" }, "type": "library", "autoload": { @@ -1374,7 +1371,7 @@ "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v7.2.1" + "source": "https://github.com/symfony/console/tree/v6.4.26" }, "funding": [ { @@ -1385,25 +1382,29 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2024-12-11T03:49:26+00:00" + "time": "2025-09-26T12:13:46+00:00" }, { "name": "symfony/deprecation-contracts", - "version": "v3.5.1", + "version": "v3.6.0", "source": { "type": "git", "url": "https://github.com/symfony/deprecation-contracts.git", - "reference": "74c71c939a79f7d5bf3c1ce9f5ea37ba0114c6f6" + "reference": "63afe740e99a13ba87ec199bb07bbdee937a5b62" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/74c71c939a79f7d5bf3c1ce9f5ea37ba0114c6f6", - "reference": "74c71c939a79f7d5bf3c1ce9f5ea37ba0114c6f6", + "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/63afe740e99a13ba87ec199bb07bbdee937a5b62", + "reference": "63afe740e99a13ba87ec199bb07bbdee937a5b62", "shasum": "" }, "require": { @@ -1416,7 +1417,7 @@ "name": "symfony/contracts" }, "branch-alias": { - "dev-main": "3.5-dev" + "dev-main": "3.6-dev" } }, "autoload": { @@ -1441,7 +1442,7 @@ "description": "A generic function and convention to trigger deprecation notices", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/deprecation-contracts/tree/v3.5.1" + "source": "https://github.com/symfony/deprecation-contracts/tree/v3.6.0" }, "funding": [ { @@ -1457,28 +1458,28 @@ "type": "tidelift" } ], - "time": "2024-09-25T14:20:29+00:00" + "time": "2024-09-25T14:21:43+00:00" }, { "name": "symfony/event-dispatcher", - "version": "v7.2.0", + "version": "v6.4.25", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher.git", - "reference": "910c5db85a5356d0fea57680defec4e99eb9c8c1" + "reference": "b0cf3162020603587363f0551cd3be43958611ff" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/910c5db85a5356d0fea57680defec4e99eb9c8c1", - "reference": "910c5db85a5356d0fea57680defec4e99eb9c8c1", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/b0cf3162020603587363f0551cd3be43958611ff", + "reference": "b0cf3162020603587363f0551cd3be43958611ff", "shasum": "" }, "require": { - "php": ">=8.2", + "php": ">=8.1", "symfony/event-dispatcher-contracts": "^2.5|^3" }, "conflict": { - "symfony/dependency-injection": "<6.4", + "symfony/dependency-injection": "<5.4", "symfony/service-contracts": "<2.5" }, "provide": { @@ -1487,13 +1488,13 @@ }, "require-dev": { "psr/log": "^1|^2|^3", - "symfony/config": "^6.4|^7.0", - "symfony/dependency-injection": "^6.4|^7.0", - "symfony/error-handler": "^6.4|^7.0", - "symfony/expression-language": "^6.4|^7.0", - "symfony/http-foundation": "^6.4|^7.0", + "symfony/config": "^5.4|^6.0|^7.0", + "symfony/dependency-injection": "^5.4|^6.0|^7.0", + "symfony/error-handler": "^5.4|^6.0|^7.0", + "symfony/expression-language": "^5.4|^6.0|^7.0", + "symfony/http-foundation": "^5.4|^6.0|^7.0", "symfony/service-contracts": "^2.5|^3", - "symfony/stopwatch": "^6.4|^7.0" + "symfony/stopwatch": "^5.4|^6.0|^7.0" }, "type": "library", "autoload": { @@ -1521,7 +1522,7 @@ "description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/event-dispatcher/tree/v7.2.0" + "source": "https://github.com/symfony/event-dispatcher/tree/v6.4.25" }, "funding": [ { @@ -1532,25 +1533,29 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2024-09-25T14:21:43+00:00" + "time": "2025-08-13T09:41:44+00:00" }, { "name": "symfony/event-dispatcher-contracts", - "version": "v3.5.1", + "version": "v3.6.0", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher-contracts.git", - "reference": "7642f5e970b672283b7823222ae8ef8bbc160b9f" + "reference": "59eb412e93815df44f05f342958efa9f46b1e586" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/7642f5e970b672283b7823222ae8ef8bbc160b9f", - "reference": "7642f5e970b672283b7823222ae8ef8bbc160b9f", + "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/59eb412e93815df44f05f342958efa9f46b1e586", + "reference": "59eb412e93815df44f05f342958efa9f46b1e586", "shasum": "" }, "require": { @@ -1564,7 +1569,7 @@ "name": "symfony/contracts" }, "branch-alias": { - "dev-main": "3.5-dev" + "dev-main": "3.6-dev" } }, "autoload": { @@ -1597,7 +1602,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v3.5.1" + "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v3.6.0" }, "funding": [ { @@ -1613,29 +1618,29 @@ "type": "tidelift" } ], - "time": "2024-09-25T14:20:29+00:00" + "time": "2024-09-25T14:21:43+00:00" }, { "name": "symfony/filesystem", - "version": "v7.2.0", + "version": "v6.4.24", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", - "reference": "b8dce482de9d7c9fe2891155035a7248ab5c7fdb" + "reference": "75ae2edb7cdcc0c53766c30b0a2512b8df574bd8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/b8dce482de9d7c9fe2891155035a7248ab5c7fdb", - "reference": "b8dce482de9d7c9fe2891155035a7248ab5c7fdb", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/75ae2edb7cdcc0c53766c30b0a2512b8df574bd8", + "reference": "75ae2edb7cdcc0c53766c30b0a2512b8df574bd8", "shasum": "" }, "require": { - "php": ">=8.2", + "php": ">=8.1", "symfony/polyfill-ctype": "~1.8", "symfony/polyfill-mbstring": "~1.8" }, "require-dev": { - "symfony/process": "^6.4|^7.0" + "symfony/process": "^5.4|^6.4|^7.0" }, "type": "library", "autoload": { @@ -1663,7 +1668,7 @@ "description": "Provides basic utilities for the filesystem", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/filesystem/tree/v7.2.0" + "source": "https://github.com/symfony/filesystem/tree/v6.4.24" }, "funding": [ { @@ -1674,32 +1679,36 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2024-10-25T15:15:23+00:00" + "time": "2025-07-10T08:14:14+00:00" }, { "name": "symfony/finder", - "version": "v7.2.2", + "version": "v6.4.24", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "87a71856f2f56e4100373e92529eed3171695cfb" + "reference": "73089124388c8510efb8d2d1689285d285937b08" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/87a71856f2f56e4100373e92529eed3171695cfb", - "reference": "87a71856f2f56e4100373e92529eed3171695cfb", + "url": "https://api.github.com/repos/symfony/finder/zipball/73089124388c8510efb8d2d1689285d285937b08", + "reference": "73089124388c8510efb8d2d1689285d285937b08", "shasum": "" }, "require": { - "php": ">=8.2" + "php": ">=8.1" }, "require-dev": { - "symfony/filesystem": "^6.4|^7.0" + "symfony/filesystem": "^6.0|^7.0" }, "type": "library", "autoload": { @@ -1727,7 +1736,7 @@ "description": "Finds files and directories via an intuitive fluent interface", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/finder/tree/v7.2.2" + "source": "https://github.com/symfony/finder/tree/v6.4.24" }, "funding": [ { @@ -1738,29 +1747,33 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2024-12-30T19:00:17+00:00" + "time": "2025-07-15T12:02:45+00:00" }, { "name": "symfony/options-resolver", - "version": "v7.2.0", + "version": "v6.4.25", "source": { "type": "git", "url": "https://github.com/symfony/options-resolver.git", - "reference": "7da8fbac9dcfef75ffc212235d76b2754ce0cf50" + "reference": "d28e7e2db8a73e9511df892d36445f61314bbebe" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/options-resolver/zipball/7da8fbac9dcfef75ffc212235d76b2754ce0cf50", - "reference": "7da8fbac9dcfef75ffc212235d76b2754ce0cf50", + "url": "https://api.github.com/repos/symfony/options-resolver/zipball/d28e7e2db8a73e9511df892d36445f61314bbebe", + "reference": "d28e7e2db8a73e9511df892d36445f61314bbebe", "shasum": "" }, "require": { - "php": ">=8.2", + "php": ">=8.1", "symfony/deprecation-contracts": "^2.5|^3" }, "type": "library", @@ -1794,7 +1807,7 @@ "options" ], "support": { - "source": "https://github.com/symfony/options-resolver/tree/v7.2.0" + "source": "https://github.com/symfony/options-resolver/tree/v6.4.25" }, "funding": [ { @@ -1805,16 +1818,20 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2024-11-20T11:17:29+00:00" + "time": "2025-08-04T17:06:28+00:00" }, { "name": "symfony/polyfill-ctype", - "version": "v1.31.0", + "version": "v1.33.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-ctype.git", @@ -1873,7 +1890,7 @@ "portable" ], "support": { - "source": "https://github.com/symfony/polyfill-ctype/tree/v1.31.0" + "source": "https://github.com/symfony/polyfill-ctype/tree/v1.33.0" }, "funding": [ { @@ -1884,6 +1901,10 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" @@ -1893,16 +1914,16 @@ }, { "name": "symfony/polyfill-intl-grapheme", - "version": "v1.31.0", + "version": "v1.33.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-grapheme.git", - "reference": "b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe" + "reference": "380872130d3a5dd3ace2f4010d95125fde5d5c70" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe", - "reference": "b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe", + "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/380872130d3a5dd3ace2f4010d95125fde5d5c70", + "reference": "380872130d3a5dd3ace2f4010d95125fde5d5c70", "shasum": "" }, "require": { @@ -1951,7 +1972,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.31.0" + "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.33.0" }, "funding": [ { @@ -1962,16 +1983,20 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2024-09-09T11:45:10+00:00" + "time": "2025-06-27T09:58:17+00:00" }, { "name": "symfony/polyfill-intl-normalizer", - "version": "v1.31.0", + "version": "v1.33.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-normalizer.git", @@ -2032,7 +2057,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.31.0" + "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.33.0" }, "funding": [ { @@ -2043,6 +2068,10 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" @@ -2132,16 +2161,16 @@ }, { "name": "symfony/polyfill-php80", - "version": "v1.31.0", + "version": "v1.33.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php80.git", - "reference": "60328e362d4c2c802a54fcbf04f9d3fb892b4cf8" + "reference": "0cc9dd0f17f61d8131e7df6b84bd344899fe2608" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/60328e362d4c2c802a54fcbf04f9d3fb892b4cf8", - "reference": "60328e362d4c2c802a54fcbf04f9d3fb892b4cf8", + "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/0cc9dd0f17f61d8131e7df6b84bd344899fe2608", + "reference": "0cc9dd0f17f61d8131e7df6b84bd344899fe2608", "shasum": "" }, "require": { @@ -2192,7 +2221,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php80/tree/v1.31.0" + "source": "https://github.com/symfony/polyfill-php80/tree/v1.33.0" }, "funding": [ { @@ -2203,16 +2232,20 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2024-09-09T11:45:10+00:00" + "time": "2025-01-02T08:10:11+00:00" }, { "name": "symfony/polyfill-php81", - "version": "v1.31.0", + "version": "v1.33.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php81.git", @@ -2268,7 +2301,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php81/tree/v1.31.0" + "source": "https://github.com/symfony/polyfill-php81/tree/v1.33.0" }, "funding": [ { @@ -2279,6 +2312,10 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" @@ -2288,20 +2325,20 @@ }, { "name": "symfony/process", - "version": "v7.2.4", + "version": "v6.4.26", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "d8f411ff3c7ddc4ae9166fb388d1190a2df5b5cf" + "reference": "48bad913268c8cafabbf7034b39c8bb24fbc5ab8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/d8f411ff3c7ddc4ae9166fb388d1190a2df5b5cf", - "reference": "d8f411ff3c7ddc4ae9166fb388d1190a2df5b5cf", + "url": "https://api.github.com/repos/symfony/process/zipball/48bad913268c8cafabbf7034b39c8bb24fbc5ab8", + "reference": "48bad913268c8cafabbf7034b39c8bb24fbc5ab8", "shasum": "" }, "require": { - "php": ">=8.2" + "php": ">=8.1" }, "type": "library", "autoload": { @@ -2329,7 +2366,7 @@ "description": "Executes commands in sub-processes", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/process/tree/v7.2.4" + "source": "https://github.com/symfony/process/tree/v6.4.26" }, "funding": [ { @@ -2340,25 +2377,29 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2025-02-05T08:33:46+00:00" + "time": "2025-09-11T09:57:09+00:00" }, { "name": "symfony/service-contracts", - "version": "v3.5.1", + "version": "v3.6.0", "source": { "type": "git", "url": "https://github.com/symfony/service-contracts.git", - "reference": "e53260aabf78fb3d63f8d79d69ece59f80d5eda0" + "reference": "f021b05a130d35510bd6b25fe9053c2a8a15d5d4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/service-contracts/zipball/e53260aabf78fb3d63f8d79d69ece59f80d5eda0", - "reference": "e53260aabf78fb3d63f8d79d69ece59f80d5eda0", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/f021b05a130d35510bd6b25fe9053c2a8a15d5d4", + "reference": "f021b05a130d35510bd6b25fe9053c2a8a15d5d4", "shasum": "" }, "require": { @@ -2376,7 +2417,7 @@ "name": "symfony/contracts" }, "branch-alias": { - "dev-main": "3.5-dev" + "dev-main": "3.6-dev" } }, "autoload": { @@ -2412,7 +2453,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/service-contracts/tree/v3.5.1" + "source": "https://github.com/symfony/service-contracts/tree/v3.6.0" }, "funding": [ { @@ -2428,24 +2469,24 @@ "type": "tidelift" } ], - "time": "2024-09-25T14:20:29+00:00" + "time": "2025-04-25T09:37:31+00:00" }, { "name": "symfony/stopwatch", - "version": "v7.2.4", + "version": "v6.4.24", "source": { "type": "git", "url": "https://github.com/symfony/stopwatch.git", - "reference": "5a49289e2b308214c8b9c2fda4ea454d8b8ad7cd" + "reference": "b67e94e06a05d9572c2fa354483b3e13e3cb1898" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/stopwatch/zipball/5a49289e2b308214c8b9c2fda4ea454d8b8ad7cd", - "reference": "5a49289e2b308214c8b9c2fda4ea454d8b8ad7cd", + "url": "https://api.github.com/repos/symfony/stopwatch/zipball/b67e94e06a05d9572c2fa354483b3e13e3cb1898", + "reference": "b67e94e06a05d9572c2fa354483b3e13e3cb1898", "shasum": "" }, "require": { - "php": ">=8.2", + "php": ">=8.1", "symfony/service-contracts": "^2.5|^3" }, "type": "library", @@ -2474,7 +2515,7 @@ "description": "Provides a way to profile code", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/stopwatch/tree/v7.2.4" + "source": "https://github.com/symfony/stopwatch/tree/v6.4.24" }, "funding": [ { @@ -2485,29 +2526,33 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2025-02-24T10:49:57+00:00" + "time": "2025-07-10T08:14:14+00:00" }, { "name": "symfony/string", - "version": "v7.2.0", + "version": "v6.4.26", "source": { "type": "git", "url": "https://github.com/symfony/string.git", - "reference": "446e0d146f991dde3e73f45f2c97a9faad773c82" + "reference": "5621f039a71a11c87c106c1c598bdcd04a19aeea" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/446e0d146f991dde3e73f45f2c97a9faad773c82", - "reference": "446e0d146f991dde3e73f45f2c97a9faad773c82", + "url": "https://api.github.com/repos/symfony/string/zipball/5621f039a71a11c87c106c1c598bdcd04a19aeea", + "reference": "5621f039a71a11c87c106c1c598bdcd04a19aeea", "shasum": "" }, "require": { - "php": ">=8.2", + "php": ">=8.1", "symfony/polyfill-ctype": "~1.8", "symfony/polyfill-intl-grapheme": "~1.0", "symfony/polyfill-intl-normalizer": "~1.0", @@ -2517,12 +2562,10 @@ "symfony/translation-contracts": "<2.5" }, "require-dev": { - "symfony/emoji": "^7.1", - "symfony/error-handler": "^6.4|^7.0", - "symfony/http-client": "^6.4|^7.0", - "symfony/intl": "^6.4|^7.0", + "symfony/http-client": "^5.4|^6.0|^7.0", + "symfony/intl": "^6.2|^7.0", "symfony/translation-contracts": "^2.5|^3.0", - "symfony/var-exporter": "^6.4|^7.0" + "symfony/var-exporter": "^5.4|^6.0|^7.0" }, "type": "library", "autoload": { @@ -2561,7 +2604,7 @@ "utf8" ], "support": { - "source": "https://github.com/symfony/string/tree/v7.2.0" + "source": "https://github.com/symfony/string/tree/v6.4.26" }, "funding": [ { @@ -2572,12 +2615,16 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2024-11-13T13:31:26+00:00" + "time": "2025-09-11T14:32:46+00:00" } ], "packages-dev": [], diff --git a/tools/php-cs-fixer/php-consul-api-rules.php_cs b/tools/php-cs-fixer/php-consul-api-rules.php_cs index 1db0153f..854b38db 100644 --- a/tools/php-cs-fixer/php-consul-api-rules.php_cs +++ b/tools/php-cs-fixer/php-consul-api-rules.php_cs @@ -1,17 +1,17 @@ -setUsingCache(false) - ->setRiskyAllowed(true) +// ->setRiskyAllowed(true) ->setLineEnding("\n") ->setIndent(' ') ->registerCustomFixers( @@ -20,9 +20,10 @@ $config ] ) ->setRules( - (new PSR12Set())->getRules() + - (new PSR12RiskySet())->getRules() + [ + '@PSR12' => true, +// 'PSR12Risky', + // custom rules 'AdamWojs/phpdoc_force_fqcn_fixer' => true,