diff --git a/.envrc b/.envrc new file mode 100644 index 0000000..8392d15 --- /dev/null +++ b/.envrc @@ -0,0 +1 @@ +use flake \ No newline at end of file diff --git a/.github/workflows/pullrequest.yml b/.github/workflows/pullrequest.yml index 3dae50e..d83bcf6 100644 --- a/.github/workflows/pullrequest.yml +++ b/.github/workflows/pullrequest.yml @@ -20,7 +20,7 @@ jobs: strategy: matrix: operating-system: [ubuntu-latest] - php-version: ['8.0', '8.1', '8.2'] + php-version: ['8.1', '8.2', '8.3'] steps: - uses: actions/checkout@v4 diff --git a/.gitignore b/.gitignore index 0199447..bea6a4d 100644 --- a/.gitignore +++ b/.gitignore @@ -8,4 +8,4 @@ /features/*.feature -/.devenv* \ No newline at end of file +/.direnv \ No newline at end of file diff --git a/.tool-versions b/.tool-versions index 89eae35..19a822a 100644 --- a/.tool-versions +++ b/.tool-versions @@ -1,3 +1,3 @@ -php 8.2.12 +php 8.3.0 +# php 8.2.12 # php 8.1.11 -# php 8.0.24 \ No newline at end of file diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 91dccbe..af5e9b6 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -4,11 +4,11 @@ ### System Requirements -PHP 8+ is required. +PHP 8.1+ is required. ### Compilation target(s) -We target compatibility with PHP versions 8.0, 8.1, and 8.2. +We target compatibility with supported versions of PHP. Currently, this includes PHP versions 8.1, 8.2, and 8.3. ### Installation and Dependencies diff --git a/README.md b/README.md index bfdf31e..a29335d 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ [![Specification](https://img.shields.io/static/v1?label=Specification&message=v0.5.1&color=yellow)](https://github.com/open-feature/spec/tree/v0.5.1) [![Latest Stable Version](http://poser.pugx.org/open-feature/sdk/v)](https://packagist.org/packages/open-feature/sdk) [![Total Downloads](http://poser.pugx.org/open-feature/sdk/downloads)](https://packagist.org/packages/open-feature/sdk) -![PHP 8.0+](https://img.shields.io/badge/php->=8.0-blue.svg) +![PHP 8.1+](https://img.shields.io/badge/php->=8.0-blue.svg) [![License](http://poser.pugx.org/open-feature/sdk/license)](https://packagist.org/packages/open-feature/sdk) [![OpenSSF Best Practices](https://bestpractices.coreinfrastructure.org/projects/6853/badge)](https://bestpractices.coreinfrastructure.org/projects/6853) @@ -108,7 +108,17 @@ The OpenFeature project maintains the [open-feature/php-sdk-contrib](https://git This library targets PHP version 8.0 and newer. As long as you have any compatible version of PHP on your system you should be able to utilize the OpenFeature SDK. -This package also has a `.tool-versions` file for use with PHP version managers like `asdf`. +#### asdf + +This package has a `.tool-versions` file for use with PHP version managers like `asdf`. + +#### Nix + +This package includes a `flake.nix` file which defines reproducible development shells powered by [Nix](https://nixos.org/). You can manually drop into a shell with `nix develop`, or provide a specific PHP minor version target with `nix develop .#php82`. + +#### direnv + +This package includes a `.envrc` file which automatically infers the usage of the default shell for the project, which is set to the minimum supported version of PHP. ### Installation and Dependencies diff --git a/composer.json b/composer.json index 2ef5a88..f6f1a4c 100644 --- a/composer.json +++ b/composer.json @@ -15,7 +15,7 @@ } ], "require": { - "php": "^8", + "php": "^8.1", "myclabs/php-enum": "^1.8", "psr/log": "^2.0 || ^3.0" }, @@ -56,10 +56,10 @@ }, "config": { "allow-plugins": { - "phpstan/extension-installer": true, + "captainhook/plugin-composer": true, "dealerdirect/phpcodesniffer-composer-installer": true, "ergebnis/composer-normalize": true, - "captainhook/plugin-composer": true, + "phpstan/extension-installer": true, "ramsey/composer-repl": true }, "sort-packages": true diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000..52633e0 --- /dev/null +++ b/flake.lock @@ -0,0 +1,26 @@ +{ + "nodes": { + "nixpkgs": { + "locked": { + "lastModified": 1701315746, + "narHash": "sha256-4HUEjLTe/DV2nT8Kj47v8aRNxSnQHwxXGZj5iZMTZCY=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "e94cea6132d50ff4bb73845da902b8950d8620f5", + "type": "github" + }, + "original": { + "owner": "NixOS", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "nixpkgs": "nixpkgs" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..fadcf88 --- /dev/null +++ b/flake.nix @@ -0,0 +1,94 @@ +{ + description = "OpenFeature PHP SDK Nix flake dev shells"; + + # Flake inputs + inputs.nixpkgs.url = "github:NixOS/nixpkgs"; + + # Flake outputs + outputs = { self, nixpkgs }: + let + # Systems supported + allSystems = [ + "x86_64-linux" # 64-bit Intel/ARM Linux + "aarch64-linux" # 64-bit AMD Linux + "x86_64-darwin" # 64-bit Intel/ARM macOS + "aarch64-darwin" # 64-bit Apple Silicon + ]; + + # Helper to provide system-specific attributes + nameValuePair = name: value: { inherit name value; }; + genAttrs = names: f: builtins.listToAttrs (map (n: nameValuePair n (f n)) names); + forAllSystems = f: genAttrs allSystems (system: f { + pkgs = import nixpkgs { + inherit system; + }; + }); + in + { + # Development environment output + devShells = forAllSystems ({ pkgs }: + let + coreShellPackages = [ + pkgs.zsh + ]; + coreDevPackages = [ + pkgs.git + ]; + corePhpPackages = [ + pkgs.libpng + ]; + php81Packages = [ + pkgs.php81 + pkgs.php81.packages.composer + ]; + php82Packages = [ + pkgs.php82 + pkgs.php82.packages.composer + ]; + php83Packages = [ + pkgs.php83 + pkgs.php83.packages.composer + ]; + emptyStr = ""; + shellHookCommandFactory = { git ? true, php ? false, node ? false, yarn ? false, pnpm ? false, python ? false, bun ? false }: '' + echo $ Started devenv shell for OpenFeature PHP-SDK with $PHP_VERSION + echo + ${if git then ''git --version'' else emptyStr} + ${if php then ''php --version'' else emptyStr} + echo + ''; + phpShellHookCommand = shellHookCommandFactory { php = true; }; + in rec + { + php81 = pkgs.mkShell { + packages = coreShellPackages ++ coreDevPackages ++ corePhpPackages ++ php81Packages; + + PHP_VERSION = "PHP81"; + + shellHook = phpShellHookCommand; + }; + + php82 = pkgs.mkShell { + packages = coreShellPackages ++ coreDevPackages ++ corePhpPackages ++ php82Packages; + + PHP_VERSION = "PHP82"; + + shellHook = phpShellHookCommand; + }; + + php83 = pkgs.mkShell { + packages = coreShellPackages ++ coreDevPackages ++ corePhpPackages ++ php83Packages; + + PHP_VERSION = "PHP83"; + + shellHook = phpShellHookCommand; + }; + + # Default aliases, uses minimum supported PHP version + php = php81; + + default = php; + } + ); + }; +} \ No newline at end of file diff --git a/integration/composer.json b/integration/composer.json index 906f60d..b39c551 100644 --- a/integration/composer.json +++ b/integration/composer.json @@ -15,7 +15,7 @@ } ], "require": { - "php": "^8", + "php": "^8.1", "open-feature/sdk": "^2.0.0", "open-feature/flagd-provider": "^0.7.0", "guzzlehttp/guzzle": "^7.5", diff --git a/integration/features/bootstrap/FeatureContext.php b/integration/features/bootstrap/FeatureContext.php index 78040bf..570f9a2 100644 --- a/integration/features/bootstrap/FeatureContext.php +++ b/integration/features/bootstrap/FeatureContext.php @@ -82,7 +82,7 @@ public function aProviderIsRegisteredWithCacheDisabled() */ public function aBooleanFlagWithKeyIsEvaluatedWithDefaultValue(string $flagKey, bool $defaultValue) { - $this->flagType = FlagValueType::BOOLEAN; + $this->flagType = FlagValueType::Boolean; $this->inputFlagKey = $flagKey; $this->inputFlagDefaultValue = $defaultValue; } @@ -103,7 +103,7 @@ public function theResolvedBooleanValueShouldBe(bool $resolvedValue) */ public function aStringFlagWithKeyIsEvaluatedWithDefaultValue(string $flagKey, string $defaultValue) { - $this->flagType = FlagValueType::STRING; + $this->flagType = FlagValueType::String; $this->inputFlagKey = $flagKey; $this->inputFlagDefaultValue = $defaultValue; } @@ -124,7 +124,7 @@ public function theResolvedStringValueShouldBe(string $resolvedValue) */ public function anIntegerFlagWithKeyIsEvaluatedWithDefaultValue(string $flagKey, int $defaultValue) { - $this->flagType = FlagValueType::INTEGER; + $this->flagType = FlagValueType::Integer; $this->inputFlagKey = $flagKey; $this->inputFlagDefaultValue = $defaultValue; print_r("Setting integer...\n"); @@ -146,7 +146,7 @@ public function theResolvedIntegerValueShouldBe(int $resolvedValue) */ public function aFloatFlagWithKeyIsEvaluatedWithDefaultValue(string $flagKey, float $defaultValue) { - $this->flagType = FlagValueType::FLOAT; + $this->flagType = FlagValueType::Float; $this->inputFlagKey = $flagKey; $this->inputFlagDefaultValue = $defaultValue; } @@ -167,7 +167,7 @@ public function theResolvedFloatValueShouldBe(float $resolvedValue) */ public function anObjectFlagWithKeyIsEvaluatedWithANullDefaultValue(string $flagKey, mixed $defaultValue) { - $this->flagType = FlagValueType::OBJECT; + $this->flagType = FlagValueType::Object; $this->inputFlagKey = $flagKey; $this->inputFlagDefaultValue = $defaultValue; } @@ -192,7 +192,7 @@ public function theResolvedObjectValueShouldBeContainFieldsAndWithValuesAndRespe */ public function aBooleanFlagWithKeyIsEvaluatedWithDetailsAndDefaultValue(string $flagKey, bool $defaultValue) { - $this->flagType = FlagValueType::BOOLEAN; + $this->flagType = FlagValueType::Boolean; $this->inputFlagKey = $flagKey; $this->inputFlagDefaultValue = $defaultValue; } @@ -214,7 +214,7 @@ public function theResolvedBooleanDetailsValueShouldBeTheVariantShouldBeAndTheRe */ public function aStringFlagWithKeyIsEvaluatedWithDetailsAndDefaultValue(string $flagKey, string $defaultValue) { - $this->flagType = FlagValueType::STRING; + $this->flagType = FlagValueType::String; $this->inputFlagKey = $flagKey; $this->inputFlagDefaultValue = $defaultValue; } @@ -236,7 +236,7 @@ public function theResolvedStringDetailsValueShouldBeTheVariantShouldBeAndTheRea */ public function anIntegerFlagWithKeyIsEvaluatedWithDetailsAndDefaultValue(string $flagKey, int $defaultValue) { - $this->flagType = FlagValueType::INTEGER; + $this->flagType = FlagValueType::Integer; $this->inputFlagKey = $flagKey; $this->inputFlagDefaultValue = $defaultValue; } @@ -258,7 +258,7 @@ public function theResolvedIntegerDetailsValueShouldBeTheVariantShouldBeAndTheRe */ public function aFloatFlagWithKeyIsEvaluatedWithDetailsAndDefaultValue(string $flagKey, float $defaultValue) { - $this->flagType = FlagValueType::FLOAT; + $this->flagType = FlagValueType::Float; $this->inputFlagKey = $flagKey; $this->inputFlagDefaultValue = $defaultValue; } @@ -280,7 +280,7 @@ public function theResolvedFloatDetailsValueShouldBeTheVariantShouldBeAndTheReas */ public function anObjectFlagWithKeyIsEvaluatedWithDetailsAndANullDefaultValue(string $flagKey, mixed $defaultValue) { - $this->flagType = FlagValueType::OBJECT; + $this->flagType = FlagValueType::Object; $this->inputFlagKey = $flagKey; $this->inputFlagDefaultValue = $defaultValue; } @@ -409,7 +409,7 @@ public function theReasonShouldIndicateAnErrorAndTheErrorCodeShouldIndicateAMiss */ public function aStringFlagWithKeyIsEvaluatedAsAnIntegerWithDetailsAndADefaultValue(string $flagKey, int $defaultValue) { - $this->flagType = FlagValueType::INTEGER; + $this->flagType = FlagValueType::Integer; $this->inputFlagKey = $flagKey; $this->inputFlagDefaultValue = $defaultValue; } @@ -447,23 +447,23 @@ private function calculateValue() { $value = null; switch ($this->flagType) { - case FlagValueType::BOOLEAN: + case FlagValueType::Boolean: $value = $this->client->getBooleanValue($this->inputFlagKey, $this->inputFlagDefaultValue, $this->inputContext, $this->inputOptions); break; - case FlagValueType::FLOAT: + case FlagValueType::Float: $value = $this->client->getFloatValue($this->inputFlagKey, $this->inputFlagDefaultValue, $this->inputContext, $this->inputOptions); break; - case FlagValueType::INTEGER: + case FlagValueType::Integer: $value = $this->client->getIntegerValue($this->inputFlagKey, $this->inputFlagDefaultValue, $this->inputContext, $this->inputOptions); break; - case FlagValueType::OBJECT: + case FlagValueType::Object: $value = $this->client->getObjectValue($this->inputFlagKey, $this->inputFlagDefaultValue, $this->inputContext, $this->inputOptions); break; - case FlagValueType::STRING: + case FlagValueType::String: $value = $this->client->getStringValue($this->inputFlagKey, $this->inputFlagDefaultValue, $this->inputContext, $this->inputOptions); break; @@ -479,23 +479,23 @@ private function calculateDetails(): EvaluationDetails { $details = null; switch ($this->flagType) { - case FlagValueType::BOOLEAN: + case FlagValueType::Boolean: $details = $this->client->getBooleanDetails($this->inputFlagKey, $this->inputFlagDefaultValue, $this->inputContext, $this->inputOptions); break; - case FlagValueType::FLOAT: + case FlagValueType::Float: $details = $this->client->getFloatDetails($this->inputFlagKey, $this->inputFlagDefaultValue, $this->inputContext, $this->inputOptions); break; - case FlagValueType::INTEGER: + case FlagValueType::Integer: $details = $this->client->getIntegerDetails($this->inputFlagKey, $this->inputFlagDefaultValue, $this->inputContext, $this->inputOptions); break; - case FlagValueType::OBJECT: + case FlagValueType::Object: $details = $this->client->getObjectDetails($this->inputFlagKey, $this->inputFlagDefaultValue, $this->inputContext, $this->inputOptions); break; - case FlagValueType::STRING: + case FlagValueType::String: $details = $this->client->getStringDetails($this->inputFlagKey, $this->inputFlagDefaultValue, $this->inputContext, $this->inputOptions); break; @@ -518,23 +518,23 @@ private function setFlagTypeIfNullByValue(mixed $value): void private function getFlagTypeOf(mixed $value): ?string { if (is_string($value)) { - return FlagValueType::STRING; + return FlagValueType::String; } if (is_array($value)) { - return FlagValueType::OBJECT; + return FlagValueType::Object; } if (is_float($value)) { - return FlagValueType::FLOAT; + return FlagValueType::Float; } if (is_int($value)) { - return FlagValueType::INTEGER; + return FlagValueType::Integer; } if (is_bool($value)) { - return FlagValueType::BOOLEAN; + return FlagValueType::Boolean; } } diff --git a/src/OpenFeatureAPI.php b/src/OpenFeatureAPI.php index 8971509..cca9c34 100644 --- a/src/OpenFeatureAPI.php +++ b/src/OpenFeatureAPI.php @@ -16,7 +16,6 @@ use Psr\Log\LoggerAwareInterface; use Throwable; -use function array_merge; use function is_null; final class OpenFeatureAPI implements API, LoggerAwareInterface @@ -130,7 +129,7 @@ public function getHooks(): array */ public function addHooks(Hook ...$hooks): void { - $this->hooks = array_merge($this->hooks, $hooks); + $this->hooks = [...$this->hooks, ...$hooks]; } public function clearHooks(): void diff --git a/src/OpenFeatureClient.php b/src/OpenFeatureClient.php index 4181a60..929eb5b 100644 --- a/src/OpenFeatureClient.php +++ b/src/OpenFeatureClient.php @@ -4,10 +4,8 @@ namespace OpenFeature; -use DateTime; use OpenFeature\implementation\common\Metadata; use OpenFeature\implementation\common\ValueTypeValidator; -use OpenFeature\implementation\errors\FlagValueTypeError; use OpenFeature\implementation\errors\InvalidResolutionValueError; use OpenFeature\implementation\flags\EvaluationContext; use OpenFeature\implementation\flags\EvaluationDetailsBuilder; @@ -17,7 +15,6 @@ use OpenFeature\implementation\hooks\HookContextFactory; use OpenFeature\implementation\hooks\HookExecutor; use OpenFeature\implementation\hooks\HookHints; -use OpenFeature\implementation\provider\Reason; use OpenFeature\implementation\provider\ResolutionError; use OpenFeature\interfaces\common\LoggerAwareTrait; use OpenFeature\interfaces\common\Metadata as MetadataInterface; @@ -31,12 +28,12 @@ use OpenFeature\interfaces\hooks\HooksAwareTrait; use OpenFeature\interfaces\provider\ErrorCode; use OpenFeature\interfaces\provider\Provider; +use OpenFeature\interfaces\provider\Reason; use OpenFeature\interfaces\provider\ResolutionDetails; use OpenFeature\interfaces\provider\ThrowableWithResolutionError; use Psr\Log\LoggerAwareInterface; use Throwable; -use function array_merge; use function array_reverse; use function sprintf; @@ -45,9 +42,6 @@ class OpenFeatureClient implements Client, LoggerAwareInterface use HooksAwareTrait; use LoggerAwareTrait; - private API $api; - private string $name; - private string $version; private ?EvaluationContextInterface $evaluationContext = null; /** @@ -57,11 +51,11 @@ class OpenFeatureClient implements Client, LoggerAwareInterface * @param string $name Name of the client (used by observability tools). * @param string $version Version of the client (used by observability tools). */ - public function __construct(API $api, string $name, string $version) - { - $this->api = $api; - $this->name = $name; - $this->version = $version; + public function __construct( + private readonly API $api, + private readonly string $name, + private readonly string $version, + ) { $this->hooks = []; } @@ -102,7 +96,7 @@ public function setEvaluationContext(EvaluationContextInterface $context): void */ public function addHooks(Hook ...$hooks): void { - $this->hooks = array_merge($this->hooks, $hooks); + $this->hooks = [...$this->hooks, ...$hooks]; } /** @@ -146,7 +140,7 @@ public function getBooleanValue(string $flagKey, bool $defaultValue, ?Evaluation */ public function getBooleanDetails(string $flagKey, bool $defaultValue, ?EvaluationContextInterface $context = null, ?EvaluationOptionsInterface $options = null): EvaluationDetailsInterface { - return $this->evaluateFlag(FlagValueType::BOOLEAN, $flagKey, $defaultValue, $context, $options); + return $this->evaluateFlag(FlagValueType::Boolean, $flagKey, $defaultValue, $context, $options); } /** @@ -175,7 +169,7 @@ public function getStringValue(string $flagKey, string $defaultValue, ?Evaluatio */ public function getStringDetails(string $flagKey, string $defaultValue, ?EvaluationContextInterface $context = null, ?EvaluationOptionsInterface $options = null): EvaluationDetailsInterface { - return $this->evaluateFlag(FlagValueType::STRING, $flagKey, $defaultValue, $context, $options); + return $this->evaluateFlag(FlagValueType::String, $flagKey, $defaultValue, $context, $options); } /** @@ -209,7 +203,7 @@ public function getIntegerValue(string $flagKey, int $defaultValue, ?EvaluationC */ public function getIntegerDetails(string $flagKey, int $defaultValue, ?EvaluationContextInterface $context = null, ?EvaluationOptionsInterface $options = null): EvaluationDetailsInterface { - return $this->evaluateFlag(FlagValueType::INTEGER, $flagKey, $defaultValue, $context, $options); + return $this->evaluateFlag(FlagValueType::Integer, $flagKey, $defaultValue, $context, $options); } /** @@ -243,7 +237,7 @@ public function getFloatValue(string $flagKey, float $defaultValue, ?EvaluationC */ public function getFloatDetails(string $flagKey, float $defaultValue, ?EvaluationContextInterface $context = null, ?EvaluationOptionsInterface $options = null): EvaluationDetailsInterface { - return $this->evaluateFlag(FlagValueType::FLOAT, $flagKey, $defaultValue, $context, $options); + return $this->evaluateFlag(FlagValueType::Float, $flagKey, $defaultValue, $context, $options); } /** @@ -278,7 +272,7 @@ public function getObjectValue(string $flagKey, $defaultValue, ?EvaluationContex */ public function getObjectDetails(string $flagKey, $defaultValue, ?EvaluationContextInterface $context = null, ?EvaluationOptionsInterface $options = null): EvaluationDetailsInterface { - return $this->evaluateFlag(FlagValueType::OBJECT, $flagKey, $defaultValue, $context, $options); + return $this->evaluateFlag(FlagValueType::Object, $flagKey, $defaultValue, $context, $options); } /** @@ -287,12 +281,12 @@ public function getObjectDetails(string $flagKey, $defaultValue, ?EvaluationCont * ----------------- * Methods, functions, or operations on the client MUST NOT throw exceptions, or otherwise abnormally terminate. Flag evaluation calls must always return the default value in the event of abnormal execution. Exceptions include functions or methods for the purposes for configuration or setup. * - * @param bool|string|int|float|DateTime|mixed[]|null $defaultValue + * @param bool|string|int|float|mixed[]|null $defaultValue */ private function evaluateFlag( - string $flagValueType, + FlagValueType $flagValueType, string $flagKey, - bool | string | int | float | DateTime | array | null $defaultValue, + bool | string | int | float | array | null $defaultValue, ?EvaluationContextInterface $invocationContext = null, ?EvaluationOptionsInterface $options = null, ): EvaluationDetailsInterface { @@ -326,14 +320,14 @@ private function evaluateFlag( // after: Provider, Invocation, Client, API // error (if applicable): Provider, Invocation, Client, API // finally: Provider, Invocation, Client, API - $mergedBeforeHooks = array_merge( - $api->getHooks(), - $this->getHooks(), - $options->getHooks(), - $provider->getHooks(), - ); + $mergedBeforeHooks = [ + ...$api->getHooks(), + ...$this->getHooks(), + ...$options->getHooks(), + ...$provider->getHooks(), + ]; - $mergedRemainingHooks = array_reverse(array_merge([], $mergedBeforeHooks)); + $mergedRemainingHooks = array_reverse([...$mergedBeforeHooks]); try { $contextFromBeforeHook = $hookExecutor->beforeHooks($flagValueType, $hookContext, $mergedBeforeHooks, $hookHints); @@ -357,7 +351,7 @@ private function evaluateFlag( ); if (!$resolutionDetails->getError() && !ValueTypeValidator::is($flagValueType, $resolutionDetails->getValue())) { - throw new InvalidResolutionValueError($flagValueType); + throw new InvalidResolutionValueError($flagValueType->value); } $details = EvaluationDetailsFactory::fromResolution($flagKey, $resolutionDetails); @@ -388,41 +382,42 @@ private function evaluateFlag( return $details; } + /** + * @param bool|string|int|float|mixed[]|null $defaultValue + */ private function createProviderEvaluation( - string $type, + FlagValueType $type, string $key, - mixed $defaultValue, + bool | string | int | float | array | null $defaultValue, Provider $provider, EvaluationContextInterface $context, ): ResolutionDetails { - switch ($type) { - case FlagValueType::BOOLEAN: - /** @var bool $defaultValue */ + switch ($type->value) { + case FlagValueType::Boolean->value: + /** @var bool $defaultValue */; $defaultValue = $defaultValue; return $provider->resolveBooleanValue($key, $defaultValue, $context); - case FlagValueType::STRING: - /** @var string $defaultValue */ + case FlagValueType::String->value: + /** @var string $defaultValue */; $defaultValue = $defaultValue; return $provider->resolveStringValue($key, $defaultValue, $context); - case FlagValueType::INTEGER: - /** @var int $defaultValue */ + case FlagValueType::Integer->value: + /** @var int $defaultValue */; $defaultValue = $defaultValue; return $provider->resolveIntegerValue($key, $defaultValue, $context); - case FlagValueType::FLOAT: - /** @var float $defaultValue */ + case FlagValueType::Float->value: + /** @var float $defaultValue */; $defaultValue = $defaultValue; return $provider->resolveFloatValue($key, $defaultValue, $context); - case FlagValueType::OBJECT: - /** @var mixed[] $defaultValue */ + case FlagValueType::Object->value: + /** @var mixed[] $defaultValue */; $defaultValue = $defaultValue; return $provider->resolveObjectValue($key, $defaultValue, $context); - default: - throw new FlagValueTypeError($type); } } } diff --git a/src/implementation/common/Metadata.php b/src/implementation/common/Metadata.php index 6759b3a..139ee1d 100644 --- a/src/implementation/common/Metadata.php +++ b/src/implementation/common/Metadata.php @@ -8,11 +8,8 @@ class Metadata implements MetadataInterface { - private string $name; - - public function __construct(string $name) + public function __construct(private string $name) { - $this->name = $name; } public function getName(): string diff --git a/src/implementation/common/ValueTypeValidator.php b/src/implementation/common/ValueTypeValidator.php index 955f468..3fd12e7 100644 --- a/src/implementation/common/ValueTypeValidator.php +++ b/src/implementation/common/ValueTypeValidator.php @@ -74,21 +74,14 @@ public static function isDateTime(mixed $value): bool /** * Validates whether the value is valid for the given type */ - public static function is(string $type, mixed $value): bool + public static function is(FlagValueType $type, mixed $value): bool { - switch ($type) { - case FlagValueType::BOOLEAN: - return self::isBoolean($value); - case FlagValueType::FLOAT: - return self::isFloat($value); - case FlagValueType::INTEGER: - return self::isInteger($value); - case FlagValueType::STRING: - return self::isString($value); - case FlagValueType::OBJECT: - return self::isStructure($value) || self::isArray($value); - default: - return false; - } + return match ($type) { + FlagValueType::Boolean => self::isBoolean($value), + FlagValueType::Float => self::isFloat($value), + FlagValueType::Integer => self::isInteger($value), + FlagValueType::String => self::isString($value), + FlagValueType::Object => self::isStructure($value) || self::isArray($value), + }; } } diff --git a/src/implementation/flags/Attributes.php b/src/implementation/flags/Attributes.php index 9676c4e..886bfd7 100644 --- a/src/implementation/flags/Attributes.php +++ b/src/implementation/flags/Attributes.php @@ -8,8 +8,6 @@ use OpenFeature\implementation\common\ArrayHelper; use OpenFeature\interfaces\flags\Attributes as AttributesInterface; -use function array_merge; - class Attributes implements AttributesInterface { /** @var Array $attributesMap */ @@ -50,6 +48,6 @@ public function get(string $key): bool | string | int | float | DateTime | array */ public function toArray(): array { - return array_merge([], $this->attributesMap); + return [...$this->attributesMap]; } } diff --git a/src/implementation/flags/EvaluationContext.php b/src/implementation/flags/EvaluationContext.php index 5af458f..20eaaee 100644 --- a/src/implementation/flags/EvaluationContext.php +++ b/src/implementation/flags/EvaluationContext.php @@ -11,13 +11,10 @@ class EvaluationContext implements EvaluationContextInterface { use EvaluationContextMerger; - private ?string $targetingKey; - protected AttributesInterface $attributes; - - public function __construct(?string $targetingKey = null, ?AttributesInterface $attributes = null) - { - $this->targetingKey = $targetingKey; - $this->attributes = $attributes ?? new Attributes(); + public function __construct( + private ?string $targetingKey = null, + protected readonly AttributesInterface $attributes = new Attributes(), + ) { } public function getTargetingKey(): ?string diff --git a/src/implementation/flags/EvaluationDetails.php b/src/implementation/flags/EvaluationDetails.php index d96c46b..31e66eb 100644 --- a/src/implementation/flags/EvaluationDetails.php +++ b/src/implementation/flags/EvaluationDetails.php @@ -4,7 +4,6 @@ namespace OpenFeature\implementation\flags; -use DateTime; use OpenFeature\interfaces\flags\EvaluationDetails as EvaluationDetailsInterface; use OpenFeature\interfaces\provider\ResolutionError; @@ -12,15 +11,14 @@ class EvaluationDetails implements EvaluationDetailsInterface { private string $flagKey = ''; - /** @var bool|string|int|float|DateTime|mixed[]|null $value */ - private bool | string | int | float | DateTime | array | null $value = null; + /** @var bool|string|int|float|mixed[]|null $value */ + private bool | string | int | float | array | null $value = null; private ?ResolutionError $error = null; private ?string $reason = null; private ?string $variant = null; public function __construct() { - $this->value = null; } public function getFlagKey(): string @@ -39,17 +37,17 @@ public function setFlagKey(string $flagKey): void * ----------------- * The evaluation details structure's value field MUST contain the evaluated flag value. * - * @return bool|string|int|float|DateTime|mixed[]|null + * @return bool|string|int|float|mixed[]|null */ - public function getValue(): bool | string | int | float | DateTime | array | null + public function getValue(): bool | string | int | float | array | null { return $this->value; } /** - * @param bool|string|int|float|DateTime|mixed[]|null $value + * @param bool|string|int|float|mixed[]|null $value */ - public function setValue(bool | string | int | float | DateTime | array | null $value): void + public function setValue(bool | string | int | float | array | null $value): void { $this->value = $value; } diff --git a/src/implementation/flags/EvaluationDetailsBuilder.php b/src/implementation/flags/EvaluationDetailsBuilder.php index 7cb4dc6..61e8cf6 100644 --- a/src/implementation/flags/EvaluationDetailsBuilder.php +++ b/src/implementation/flags/EvaluationDetailsBuilder.php @@ -4,7 +4,6 @@ namespace OpenFeature\implementation\flags; -use DateTime; use OpenFeature\interfaces\flags\EvaluationDetails as EvaluationDetailsInterface; use OpenFeature\interfaces\provider\ResolutionError; @@ -25,9 +24,9 @@ public function withFlagKey(string $flagKey): EvaluationDetailsBuilder } /** - * @param bool|string|int|float|DateTime|mixed[]|null $value + * @param bool|string|int|float|mixed[]|null $value */ - public function withValue(bool | string | int | float | DateTime | array | null $value): EvaluationDetailsBuilder + public function withValue(bool | string | int | float | array | null $value): EvaluationDetailsBuilder { $this->details->setValue($value); diff --git a/src/implementation/flags/EvaluationDetailsFactory.php b/src/implementation/flags/EvaluationDetailsFactory.php index 6115799..b491a15 100644 --- a/src/implementation/flags/EvaluationDetailsFactory.php +++ b/src/implementation/flags/EvaluationDetailsFactory.php @@ -4,7 +4,6 @@ namespace OpenFeature\implementation\flags; -use DateTime; use OpenFeature\interfaces\flags\EvaluationDetails; use OpenFeature\interfaces\provider\ResolutionDetails; @@ -13,9 +12,9 @@ class EvaluationDetailsFactory /** * Provides a simple method for building EvaluationDetails from a given value\ * - * @param bool|string|int|float|DateTime|mixed[]|null $value + * @param bool|string|int|float|mixed[]|null $value */ - public static function from(string $flagKey, bool | string | int | float | DateTime | array | null $value): EvaluationDetails + public static function from(string $flagKey, bool | string | int | float | array | null $value): EvaluationDetails { return (new EvaluationDetailsBuilder()) ->withFlagKey($flagKey) diff --git a/src/implementation/flags/EvaluationOptions.php b/src/implementation/flags/EvaluationOptions.php index 72a8c89..965b345 100644 --- a/src/implementation/flags/EvaluationOptions.php +++ b/src/implementation/flags/EvaluationOptions.php @@ -13,12 +13,10 @@ class EvaluationOptions implements EvaluationOptionsInterface { use HooksAwareTrait; - private ?HookHints $hookHints; - /** * @param Hook[] $hooks */ - public function __construct(array $hooks = [], ?HookHints $hookHints = null) + public function __construct(array $hooks = [], private ?HookHints $hookHints = null) { $this->setHooks($hooks); $this->hookHints = $hookHints; diff --git a/src/implementation/flags/NoOpClient.php b/src/implementation/flags/NoOpClient.php index 792e262..c35fb44 100644 --- a/src/implementation/flags/NoOpClient.php +++ b/src/implementation/flags/NoOpClient.php @@ -4,7 +4,6 @@ namespace OpenFeature\implementation\flags; -use DateTime; use OpenFeature\implementation\common\Metadata; use OpenFeature\interfaces\flags\Client; use OpenFeature\interfaces\flags\EvaluationContext as EvaluationContextInterface; @@ -69,7 +68,7 @@ public function getObjectValue( return $defaultValue; } - public function getObjectDetails(string $flagKey, bool | string | int | float | DateTime | array | null $defaultValue, ?EvaluationContextInterface $context = null, ?EvaluationOptions $options = null): EvaluationDetails + public function getObjectDetails(string $flagKey, bool | string | int | float | array | null $defaultValue, ?EvaluationContextInterface $context = null, ?EvaluationOptions $options = null): EvaluationDetails { return EvaluationDetailsFactory::from($flagKey, $defaultValue); } diff --git a/src/implementation/hooks/AbstractHook.php b/src/implementation/hooks/AbstractHook.php index 4303d9c..ead670d 100644 --- a/src/implementation/hooks/AbstractHook.php +++ b/src/implementation/hooks/AbstractHook.php @@ -5,6 +5,7 @@ namespace OpenFeature\implementation\hooks; use OpenFeature\interfaces\flags\EvaluationContext; +use OpenFeature\interfaces\flags\FlagValueType; use OpenFeature\interfaces\hooks\Hook; use OpenFeature\interfaces\hooks\HookContext; use OpenFeature\interfaces\hooks\HookHints; @@ -21,5 +22,5 @@ abstract public function error(HookContext $context, Throwable $error, HookHints abstract public function finally(HookContext $context, HookHints $hints): void; - abstract public function supportsFlagValueType(string $flagValueType): bool; + abstract public function supportsFlagValueType(FlagValueType $flagValueType): bool; } diff --git a/src/implementation/hooks/AbstractHookContext.php b/src/implementation/hooks/AbstractHookContext.php index 39fbeba..678238c 100644 --- a/src/implementation/hooks/AbstractHookContext.php +++ b/src/implementation/hooks/AbstractHookContext.php @@ -4,11 +4,12 @@ namespace OpenFeature\implementation\hooks; -use DateTime; +use Exception; use OpenFeature\implementation\common\Metadata; use OpenFeature\implementation\flags\EvaluationContext; use OpenFeature\interfaces\common\Metadata as MetadataInterface; use OpenFeature\interfaces\flags\EvaluationContext as EvaluationContextInterface; +use OpenFeature\interfaces\flags\FlagValueType; use OpenFeature\interfaces\hooks\HookContext; use function is_array; @@ -16,13 +17,15 @@ abstract class AbstractHookContext { protected string $flagKey = ''; - protected string $type = ''; - /** @var bool|string|int|float|DateTime|mixed[]|null $defaultValue */ - protected bool | string | int | float | DateTime | array | null $defaultValue = null; + protected FlagValueType $type = FlagValueType::Boolean; + /** @var bool|string|int|float|mixed[]|null $defaultValue */ + protected bool | string | int | float | array | null $defaultValue = null; protected EvaluationContextInterface $evaluationContext; protected MetadataInterface $clientMetadata; protected MetadataInterface $providerMetadata; + private const REQUIRED_PROPERTIES = ['flagKey', 'type']; + /** * @param HookContext|mixed[]|null $hookContext */ @@ -43,6 +46,12 @@ public function __construct(HookContext | array | null $hookContext = null) $this->clientMetadata = $hookContext->getClientMetadata(); $this->providerMetadata = $hookContext->getProviderMetadata(); } elseif (is_array($hookContext)) { + foreach (self::REQUIRED_PROPERTIES as $requiredProperty) { + if (!isset($hookContext[$requiredProperty])) { + throw new Exception('Required property missing from hook context'); + } + } + /** @var string $property */ /** @var mixed $value */ foreach ($hookContext as $property => $value) { diff --git a/src/implementation/hooks/BooleanHook.php b/src/implementation/hooks/BooleanHook.php index 500c176..45c931e 100644 --- a/src/implementation/hooks/BooleanHook.php +++ b/src/implementation/hooks/BooleanHook.php @@ -8,8 +8,8 @@ abstract class BooleanHook extends AbstractHook { - public function supportsFlagValueType(string $flagValueType): bool + public function supportsFlagValueType(FlagValueType $flagValueType): bool { - return $flagValueType === FlagValueType::BOOLEAN; + return $flagValueType === FlagValueType::Boolean; } } diff --git a/src/implementation/hooks/FloatHook.php b/src/implementation/hooks/FloatHook.php index 5e80e5b..f7e49e4 100644 --- a/src/implementation/hooks/FloatHook.php +++ b/src/implementation/hooks/FloatHook.php @@ -8,8 +8,8 @@ abstract class FloatHook extends AbstractHook { - public function supportsFlagValueType(string $flagValueType): bool + public function supportsFlagValueType(FlagValueType $flagValueType): bool { - return $flagValueType === FlagValueType::FLOAT; + return $flagValueType === FlagValueType::Float; } } diff --git a/src/implementation/hooks/HookContextBuilder.php b/src/implementation/hooks/HookContextBuilder.php index 5e94f37..88805dd 100644 --- a/src/implementation/hooks/HookContextBuilder.php +++ b/src/implementation/hooks/HookContextBuilder.php @@ -4,9 +4,9 @@ namespace OpenFeature\implementation\hooks; -use DateTime; use OpenFeature\interfaces\common\Metadata; use OpenFeature\interfaces\flags\EvaluationContext; +use OpenFeature\interfaces\flags\FlagValueType; use OpenFeature\interfaces\hooks\HookContext as HookContextInterface; class HookContextBuilder @@ -26,7 +26,7 @@ public function withFlagKey(string $flagKey): self return $this; } - public function withType(string $type): self + public function withType(FlagValueType $type): self { $this->hookContext->setType($type); @@ -34,9 +34,9 @@ public function withType(string $type): self } /** - * @param bool|string|int|float|DateTime|mixed[]|null $defaultValue + * @param bool|string|int|float|mixed[]|null $defaultValue */ - public function withDefaultValue(bool | string | int | float | DateTime | array | null $defaultValue): self + public function withDefaultValue(bool | string | int | float | array | null $defaultValue): self { $this->hookContext->setDefaultValue($defaultValue); diff --git a/src/implementation/hooks/HookContextFactory.php b/src/implementation/hooks/HookContextFactory.php index 1d22e69..d633661 100644 --- a/src/implementation/hooks/HookContextFactory.php +++ b/src/implementation/hooks/HookContextFactory.php @@ -4,21 +4,21 @@ namespace OpenFeature\implementation\hooks; -use DateTime; use OpenFeature\implementation\flags\EvaluationContext; use OpenFeature\interfaces\common\Metadata; use OpenFeature\interfaces\flags\EvaluationContext as EvaluationContextInterface; +use OpenFeature\interfaces\flags\FlagValueType; use OpenFeature\interfaces\hooks\HookContext; class HookContextFactory { /** - * @param bool|string|int|float|DateTime|mixed[]|null $defaultValue + * @param bool|string|int|float|mixed[]|null $defaultValue */ public static function from( string $flagKey, - string $type, - bool | string | int | float | DateTime | array | null $defaultValue, + FlagValueType $type, + bool | string | int | float | array | null $defaultValue, ?EvaluationContextInterface $evaluationContext, Metadata $clientMetadata, Metadata $providerMetadata, diff --git a/src/implementation/hooks/HookExecutor.php b/src/implementation/hooks/HookExecutor.php index b92374c..b218340 100644 --- a/src/implementation/hooks/HookExecutor.php +++ b/src/implementation/hooks/HookExecutor.php @@ -8,6 +8,7 @@ use OpenFeature\implementation\flags\MutableEvaluationContext; use OpenFeature\interfaces\common\LoggerAwareTrait; use OpenFeature\interfaces\flags\EvaluationContext; +use OpenFeature\interfaces\flags\FlagValueType; use OpenFeature\interfaces\hooks\Hook; use OpenFeature\interfaces\hooks\HookContext; use OpenFeature\interfaces\hooks\HookHints as HookHintsInterface; @@ -35,7 +36,7 @@ public function __construct(?LoggerInterface $logger = null) * * @param Hook[] $mergedHooks */ - public function beforeHooks(string $type, HookContext $hookContext, array $mergedHooks, HookHintsInterface $hints): ?EvaluationContext + public function beforeHooks(FlagValueType $type, HookContext $hookContext, array $mergedHooks, HookHintsInterface $hints): ?EvaluationContext { $additionalContext = new MutableEvaluationContext(); @@ -54,7 +55,7 @@ public function beforeHooks(string $type, HookContext $hookContext, array $merge /** * @param Hook[] $mergedHooks */ - public function afterHooks(string $type, HookContext $hookContext, ResolutionDetails $details, array $mergedHooks, HookHintsInterface $hints): void + public function afterHooks(FlagValueType $type, HookContext $hookContext, ResolutionDetails $details, array $mergedHooks, HookHintsInterface $hints): void { foreach ($mergedHooks as $hook) { if ($hook->supportsFlagValueType($type)) { @@ -66,7 +67,7 @@ public function afterHooks(string $type, HookContext $hookContext, ResolutionDet /** * @param Hook[] $mergedHooks */ - public function errorHooks(string $type, HookContext $hookContext, Throwable $err, array $mergedHooks, HookHintsInterface $hints): void + public function errorHooks(FlagValueType $type, HookContext $hookContext, Throwable $err, array $mergedHooks, HookHintsInterface $hints): void { foreach ($mergedHooks as $hook) { if ($hook->supportsFlagValueType($type)) { @@ -78,7 +79,7 @@ public function errorHooks(string $type, HookContext $hookContext, Throwable $er /** * @param Hook[] $mergedHooks */ - public function finallyHooks(string $type, HookContext $hookContext, array $mergedHooks, HookHintsInterface $hints): void + public function finallyHooks(FlagValueType $type, HookContext $hookContext, array $mergedHooks, HookHintsInterface $hints): void { foreach ($mergedHooks as $hook) { if ($hook->supportsFlagValueType($type)) { diff --git a/src/implementation/hooks/HookHints.php b/src/implementation/hooks/HookHints.php index 2385d57..a237777 100644 --- a/src/implementation/hooks/HookHints.php +++ b/src/implementation/hooks/HookHints.php @@ -12,8 +12,12 @@ class HookHints implements HookHintsInterface { - /** @var Array $hints */ - private array $hints = []; + /** + * @param Array $hints + */ + public function __construct(private readonly array $hints = []) + { + } /** * @return bool|string|int|float|DateTime|mixed[]|null @@ -34,12 +38,4 @@ public function keys(): array { return array_keys($this->hints); } - - /** - * @param Array $hints - */ - public function __construct(array $hints = []) - { - $this->hints = $hints; - } } diff --git a/src/implementation/hooks/ImmutableHookContext.php b/src/implementation/hooks/ImmutableHookContext.php index e0ed360..2cb6756 100644 --- a/src/implementation/hooks/ImmutableHookContext.php +++ b/src/implementation/hooks/ImmutableHookContext.php @@ -4,9 +4,9 @@ namespace OpenFeature\implementation\hooks; -use DateTime; use OpenFeature\interfaces\common\Metadata; use OpenFeature\interfaces\flags\EvaluationContext; +use OpenFeature\interfaces\flags\FlagValueType; use OpenFeature\interfaces\hooks\HookContext as HookContextInterface; class ImmutableHookContext extends AbstractHookContext implements HookContextInterface @@ -16,15 +16,15 @@ public function getFlagKey(): string return $this->flagKey; } - public function getType(): string + public function getType(): FlagValueType { return $this->type; } /** - * @return bool|string|int|float|DateTime|mixed[]|null + * @return bool|string|int|float|mixed[]|null */ - public function getDefaultValue(): bool | string | int | float | DateTime | array | null + public function getDefaultValue(): bool | string | int | float | array | null { return $this->defaultValue; } diff --git a/src/implementation/hooks/IntegerHook.php b/src/implementation/hooks/IntegerHook.php index 86eebf3..4c9d730 100644 --- a/src/implementation/hooks/IntegerHook.php +++ b/src/implementation/hooks/IntegerHook.php @@ -8,8 +8,8 @@ abstract class IntegerHook extends AbstractHook { - public function supportsFlagValueType(string $flagValueType): bool + public function supportsFlagValueType(FlagValueType $flagValueType): bool { - return $flagValueType === FlagValueType::INTEGER; + return $flagValueType === FlagValueType::Integer; } } diff --git a/src/implementation/hooks/MutableHookContext.php b/src/implementation/hooks/MutableHookContext.php index a8a1b77..348e0b5 100644 --- a/src/implementation/hooks/MutableHookContext.php +++ b/src/implementation/hooks/MutableHookContext.php @@ -4,9 +4,9 @@ namespace OpenFeature\implementation\hooks; -use DateTime; use OpenFeature\interfaces\common\Metadata; use OpenFeature\interfaces\flags\EvaluationContext; +use OpenFeature\interfaces\flags\FlagValueType; use OpenFeature\interfaces\hooks\HookContext as HookContextInterface; use OpenFeature\interfaces\hooks\MutableHookContext as MutableHookContextInterface; @@ -17,12 +17,12 @@ public function setFlagKey(string $flagKey): void $this->flagKey = $flagKey; } - public function setType(string $type): void + public function setType(FlagValueType $type): void { $this->type = $type; } - public function setDefaultValue(bool | string | int | float | DateTime | array | null $defaultValue): void + public function setDefaultValue(bool | string | int | float | array | null $defaultValue): void { $this->defaultValue = $defaultValue; } diff --git a/src/implementation/hooks/ObjectHook.php b/src/implementation/hooks/ObjectHook.php index 45dcfc7..7fd0b5d 100644 --- a/src/implementation/hooks/ObjectHook.php +++ b/src/implementation/hooks/ObjectHook.php @@ -8,8 +8,8 @@ abstract class ObjectHook extends AbstractHook { - public function supportsFlagValueType(string $flagValueType): bool + public function supportsFlagValueType(FlagValueType $flagValueType): bool { - return $flagValueType === FlagValueType::OBJECT; + return $flagValueType === FlagValueType::Object; } } diff --git a/src/implementation/hooks/StringHook.php b/src/implementation/hooks/StringHook.php index 3f8e2cd..04d8974 100644 --- a/src/implementation/hooks/StringHook.php +++ b/src/implementation/hooks/StringHook.php @@ -8,8 +8,8 @@ abstract class StringHook extends AbstractHook { - public function supportsFlagValueType(string $flagValueType): bool + public function supportsFlagValueType(FlagValueType $flagValueType): bool { - return $flagValueType === FlagValueType::STRING; + return $flagValueType === FlagValueType::String; } } diff --git a/src/implementation/provider/AbstractProvider.php b/src/implementation/provider/AbstractProvider.php index 3598d3f..ec8cc2b 100644 --- a/src/implementation/provider/AbstractProvider.php +++ b/src/implementation/provider/AbstractProvider.php @@ -7,20 +7,19 @@ use OpenFeature\implementation\common\Metadata; use OpenFeature\interfaces\common\Metadata as MetadataInterface; use OpenFeature\interfaces\flags\EvaluationContext; -use OpenFeature\interfaces\hooks\Hook; +use OpenFeature\interfaces\hooks\HooksAware; +use OpenFeature\interfaces\hooks\HooksAwareTrait; use OpenFeature\interfaces\provider\Provider; use OpenFeature\interfaces\provider\ResolutionDetails as ResolutionDetailsInterface; use Psr\Log\LoggerAwareTrait; -abstract class AbstractProvider implements Provider +abstract class AbstractProvider implements HooksAware, Provider { + use HooksAwareTrait; use LoggerAwareTrait; protected static string $NAME = 'AbstractProvider'; - /** @var Hook[] $hooks */ - private array $hooks = []; - public function getMetadata(): MetadataInterface { return new Metadata(self::$NAME); @@ -38,20 +37,4 @@ abstract public function resolveFloatValue(string $flagKey, float $defaultValue, * @param mixed[] $defaultValue */ abstract public function resolveObjectValue(string $flagKey, array $defaultValue, ?EvaluationContext $context = null): ResolutionDetailsInterface; - - /** - * @return Hook[] - */ - public function getHooks(): array - { - return $this->hooks; - } - - /** - * @param Hook[] $hooks - */ - public function setHooks(array $hooks): void - { - $this->hooks = $hooks; - } } diff --git a/src/implementation/provider/Reason.php b/src/implementation/provider/Reason.php deleted file mode 100644 index a867e7b..0000000 --- a/src/implementation/provider/Reason.php +++ /dev/null @@ -1,16 +0,0 @@ -value; } /** - * @param bool|string|int|float|DateTime|mixed[]|null $value + * @param bool|string|int|float|mixed[]|null $value */ - public function setValue(bool | string | int | float | DateTime | array | null $value): void + public function setValue(bool | string | int | float | array | null $value): void { $this->value = $value; } diff --git a/src/implementation/provider/ResolutionDetailsBuilder.php b/src/implementation/provider/ResolutionDetailsBuilder.php index 73ae2c7..4028f6b 100644 --- a/src/implementation/provider/ResolutionDetailsBuilder.php +++ b/src/implementation/provider/ResolutionDetailsBuilder.php @@ -4,7 +4,6 @@ namespace OpenFeature\implementation\provider; -use DateTime; use OpenFeature\interfaces\provider\ResolutionDetails as ResolutionDetailsInterface; use OpenFeature\interfaces\provider\ResolutionError; @@ -18,9 +17,9 @@ public function __construct() } /** - * @param bool|string|int|float|DateTime|mixed[]|null $value + * @param bool|string|int|float|mixed[]|null $value */ - public function withValue(bool | string | int | float | DateTime | array | null $value): ResolutionDetailsBuilder + public function withValue(bool | string | int | float | array | null $value): ResolutionDetailsBuilder { $this->details->setValue($value); diff --git a/src/implementation/provider/ResolutionDetailsFactory.php b/src/implementation/provider/ResolutionDetailsFactory.php index 79d2e1b..42289ea 100644 --- a/src/implementation/provider/ResolutionDetailsFactory.php +++ b/src/implementation/provider/ResolutionDetailsFactory.php @@ -4,15 +4,14 @@ namespace OpenFeature\implementation\provider; -use DateTime; use OpenFeature\interfaces\provider\ResolutionDetails as ResolutionDetailsInterface; class ResolutionDetailsFactory { /** - * @param bool|string|int|float|DateTime|mixed[]|null $value + * @param bool|string|int|float|mixed[]|null $value */ - public static function fromSuccess(bool | string | int | float | DateTime | array | null $value): ResolutionDetailsInterface + public static function fromSuccess(bool | string | int | float | array | null $value): ResolutionDetailsInterface { return (new ResolutionDetailsBuilder()) ->withValue($value) diff --git a/src/interfaces/common/TypeValuePair.php b/src/interfaces/common/TypeValuePair.php deleted file mode 100644 index 767ac57..0000000 --- a/src/interfaces/common/TypeValuePair.php +++ /dev/null @@ -1,17 +0,0 @@ -expectException(Throwable::class); + + new MutableHookContext(['flagKey' => 'test-key']); + } + public function testAsMutable(): void { - $expectedValue = new MutableHookContext(['flagKey' => 'test-key']); + $expectedValue = new MutableHookContext(['flagKey' => 'test-key', 'type' => FlagValueType::Boolean]); $actualValue = (new HookContextBuilder())->withFlagKey('test-key')->asMutable()->build(); @@ -24,9 +33,9 @@ public function testAsMutable(): void public function testAsImmutable(): void { - $expectedValue = new ImmutableHookContext(['flagKey' => 'test-key']); + $expectedValue = new ImmutableHookContext(['flagKey' => 'test-key', 'type' => FlagValueType::Boolean]); - $actualValue = (new HookContextBuilder())->withFlagKey('test-key')->asImmutable()->build(); + $actualValue = (new HookContextBuilder())->withFlagKey('test-key')->withType(FlagValueType::Boolean)->asImmutable()->build(); $this->assertInstanceOf(HookContext::class, $actualValue); $this->assertEqualsCanonicalizing($expectedValue, $actualValue); diff --git a/tests/unit/HooksTest.php b/tests/unit/HooksTest.php index 51c7370..56e3e86 100644 --- a/tests/unit/HooksTest.php +++ b/tests/unit/HooksTest.php @@ -38,7 +38,7 @@ class HooksTest extends TestCase public function testHookContextMustProvideArguments(): void { $flagKey = 'test-key'; - $flagValueType = FlagValueType::BOOLEAN; + $flagValueType = FlagValueType::Boolean; $evaluationContext = new EvaluationContext(); $defaultValue = false; @@ -60,7 +60,7 @@ public function testHookContextShouldProvideAccessToMetadataFields(): void $clientMetadata = new Metadata('client'); $providerMetadata = new Metadata('provider'); - $hookContext = HookContextFactory::from('key', FlagValueType::BOOLEAN, false, new EvaluationContext(), $clientMetadata, $providerMetadata); + $hookContext = HookContextFactory::from('key', FlagValueType::Boolean, false, new EvaluationContext(), $clientMetadata, $providerMetadata); $this->assertEquals($clientMetadata, $hookContext->getClientMetadata()); $this->assertEquals($providerMetadata, $hookContext->getProviderMetadata()); @@ -73,7 +73,7 @@ public function testHookContextShouldProvideAccessToMetadataFields(): void */ public function testValuePropertiesMustBeImmutable(): void { - $expectedHookContext = HookContextFactory::from('key', FlagValueType::BOOLEAN, false, new EvaluationContext(), new Metadata('client'), new Metadata('provider')); + $expectedHookContext = HookContextFactory::from('key', FlagValueType::Boolean, false, new EvaluationContext(), new Metadata('client'), new Metadata('provider')); $testRunner = $this; $hook = $this->mockery(TestHook::class)->makePartial(); @@ -83,7 +83,7 @@ public function testValuePropertiesMustBeImmutable(): void $testRunner->assertEquals($expectedHookContext, $context); }); - (new HookExecutor(null))->beforeHooks(FlagValueType::BOOLEAN, $expectedHookContext, [$hook], new HookHints()); + (new HookExecutor(null))->beforeHooks(FlagValueType::Boolean, $expectedHookContext, [$hook], new HookHints()); } /** @@ -106,8 +106,8 @@ public function testEvaluationContextIsMutableWithinBeforeHook(): void $additionalEvaluationContext = (new HookExecutor()) ->beforeHooks( - FlagValueType::BOOLEAN, - HookContextFactory::from('flagKey', FlagValueType::BOOLEAN, false, new EvaluationContext(), new Metadata('client'), new Metadata('provider')), + FlagValueType::Boolean, + HookContextFactory::from('flagKey', FlagValueType::Boolean, false, new EvaluationContext(), new Metadata('client'), new Metadata('provider')), [$mutationHook], new HookHints(), ); @@ -137,8 +137,8 @@ public function testEvaluationContextIsImmutableInAfterHooks(): void // @phpstan-ignore-next-line $additionalEvaluationContext = (new HookExecutor()) ->afterHooks( - FlagValueType::BOOLEAN, - HookContextFactory::from('flagKey', FlagValueType::BOOLEAN, false, new EvaluationContext(), new Metadata('client'), new Metadata('provider')), + FlagValueType::Boolean, + HookContextFactory::from('flagKey', FlagValueType::Boolean, false, new EvaluationContext(), new Metadata('client'), new Metadata('provider')), ResolutionDetailsFactory::fromSuccess(true), [$mutationHook], new HookHints(), @@ -168,8 +168,8 @@ public function testEvaluationContextIsImmutableInErrorHooks(): void //@phpstan-ignore-next-line $additionalEvaluationContext = (new HookExecutor()) ->errorHooks( - FlagValueType::BOOLEAN, - HookContextFactory::from('flagKey', FlagValueType::BOOLEAN, false, new EvaluationContext(), new Metadata('client'), new Metadata('provider')), + FlagValueType::Boolean, + HookContextFactory::from('flagKey', FlagValueType::Boolean, false, new EvaluationContext(), new Metadata('client'), new Metadata('provider')), new Exception('Error'), [$mutationHook], new HookHints(), @@ -200,8 +200,8 @@ public function testEvaluationContextIsImmutableInFinallyHooks(): void // @phpstan-ignore-next-line $additionalEvaluationContext = (new HookExecutor()) ->finallyHooks( - FlagValueType::BOOLEAN, - HookContextFactory::from('flagKey', FlagValueType::BOOLEAN, false, new EvaluationContext(), new Metadata('client'), new Metadata('provider')), + FlagValueType::Boolean, + HookContextFactory::from('flagKey', FlagValueType::Boolean, false, new EvaluationContext(), new Metadata('client'), new Metadata('provider')), [$mutationHook], new HookHints(), ); @@ -289,7 +289,7 @@ public function testClientMetadataInHookContextIsImmutable(): void $hookContext = (new HookContextBuilder())->withClientMetadata($clientMetadata)->build(); - (new HookExecutor())->beforeHooks(FlagValueType::BOOLEAN, $hookContext, [], new HookHints()); + (new HookExecutor())->beforeHooks(FlagValueType::Boolean, $hookContext, [], new HookHints()); $this->assertEquals($originalName, $hookContext->getClientMetadata()->getName()); } @@ -326,7 +326,7 @@ public function testProviderMetadataInHookContextIsImmutable(): void $hookContext = (new HookContextBuilder())->withProviderMetadata($providerMetadata)->build(); - (new HookExecutor())->beforeHooks(FlagValueType::BOOLEAN, $hookContext, [], new HookHints()); + (new HookExecutor())->beforeHooks(FlagValueType::Boolean, $hookContext, [], new HookHints()); $this->assertEquals($originalName, $hookContext->getProviderMetadata()->getName()); } @@ -436,7 +436,7 @@ public function testHooksMustNotAlterHookHints(): void $hookContext = new ImmutableHookContext(); - (new HookExecutor())->beforeHooks(FlagValueType::BOOLEAN, $hookContext, [], $expectedHookHints); + (new HookExecutor())->beforeHooks(FlagValueType::Boolean, $hookContext, [], $expectedHookHints); $this->assertEquals('value', $expectedHookHints->get('key')); } diff --git a/tests/unit/NoOpClientTest.php b/tests/unit/NoOpClientTest.php index 093bb77..82b0bce 100644 --- a/tests/unit/NoOpClientTest.php +++ b/tests/unit/NoOpClientTest.php @@ -9,6 +9,7 @@ use OpenFeature\implementation\flags\EvaluationContext; use OpenFeature\implementation\flags\EvaluationDetailsBuilder; use OpenFeature\implementation\flags\NoOpClient; +use OpenFeature\interfaces\flags\FlagValueType; use OpenFeature\interfaces\hooks\Hook; use OpenFeature\interfaces\hooks\HookContext; use OpenFeature\interfaces\hooks\HookHints; @@ -198,7 +199,7 @@ public function finally(HookContext $context, HookHints $hints): void // no-op } - public function supportsFlagValueType(string $flagValueType): bool + public function supportsFlagValueType(FlagValueType $flagValueType): bool { return true; }