├── hooks ├── .gitkeep ├── DDTrace │ ├── .gitignore │ ├── examples │ │ ├── .gitignore │ │ └── AutoloadDDTrace │ │ │ ├── README.md │ │ │ ├── composer.json │ │ │ └── src │ │ │ └── main.php │ ├── psalm-baseline.xml │ ├── src │ │ ├── _autoload.php │ │ └── DDTraceHook.php │ ├── phpstan.neon.dist │ ├── psalm.xml │ ├── tests │ │ ├── unit │ │ │ └── DDTraceHookTest.php │ │ ├── TestCase.php │ │ └── integration │ │ │ └── DDTraceHookTest.php │ ├── phpunit.xml.dist │ ├── phpcs.xml.dist │ ├── CHANGELOG.md │ └── README.md ├── OpenTelemetry │ ├── .gitignore │ ├── examples │ │ ├── .gitignore │ │ ├── AutoloadOTelSDK │ │ │ ├── README.md │ │ │ ├── composer.json │ │ │ └── src │ │ │ │ └── main.php │ │ └── OTelManualInstrumentation │ │ │ ├── README.md │ │ │ └── composer.json │ ├── psalm-baseline.xml │ ├── src │ │ ├── _autoload.php │ │ ├── TracerHelper.php │ │ └── OpenTelemetryHook.php │ ├── phpstan.neon.dist │ ├── psalm.xml │ ├── tests │ │ ├── unit │ │ │ └── OpenTelemetryHookTest.php │ │ ├── TestCase.php │ │ └── integration │ │ │ └── OpenTelemetryHookTest.php │ ├── CHANGELOG.md │ ├── phpunit.xml.dist │ ├── phpcs.xml.dist │ └── README.md └── Validators │ ├── .gitignore │ ├── examples │ ├── .gitignore │ └── ExampleRegexpValidators │ │ ├── README.md │ │ ├── composer.json │ │ └── src │ │ └── main.php │ ├── psalm-baseline.xml │ ├── phpstan.neon.dist │ ├── src │ ├── Exceptions │ │ └── ValidationException.php │ └── Regexp │ │ ├── InvalidRegularExpressionException.php │ │ └── RegexpValidatorHook.php │ ├── tests │ ├── integration │ │ └── RegexpValidatorHookTest.php │ ├── TestCase.php │ └── unit │ │ └── RegexpValidatorHookTest.php │ ├── psalm.xml │ ├── phpunit.xml.dist │ ├── CHANGELOG.md │ ├── phpcs.xml.dist │ ├── README.md │ └── composer.json ├── providers ├── .gitkeep ├── Flagd │ ├── .gitignore │ ├── examples │ │ ├── .gitignore │ │ └── Http │ │ │ ├── README.md │ │ │ ├── composer.json │ │ │ └── src │ │ │ └── main.php │ ├── proto │ │ ├── README.md │ │ └── php │ │ │ ├── GPBMetadata │ │ │ └── Schema │ │ │ │ └── V1 │ │ │ │ └── Schema.php │ │ │ └── Schema │ │ │ └── V1 │ │ │ ├── ResolveIntRequest.php │ │ │ ├── ResolveFloatRequest.php │ │ │ ├── ResolveObjectRequest.php │ │ │ ├── ResolveStringRequest.php │ │ │ ├── ResolveBooleanRequest.php │ │ │ ├── ServiceClient.php │ │ │ ├── EventStreamResponse.php │ │ │ ├── ResolveIntResponse.php │ │ │ ├── ResolveFloatResponse.php │ │ │ ├── ResolveBooleanResponse.php │ │ │ └── ResolveStringResponse.php │ ├── psalm-baseline.xml │ ├── src │ │ ├── errors │ │ │ ├── InvalidConfigException.php │ │ │ ├── InvalidTypeException.php │ │ │ └── RequestBuildException.php │ │ ├── config │ │ │ ├── Protocols.php │ │ │ ├── Defaults.php │ │ │ ├── IConfig.php │ │ │ ├── IHttpConfig.php │ │ │ ├── ConfigFactory.php │ │ │ ├── HttpConfig.php │ │ │ ├── Config.php │ │ │ └── Validator.php │ │ ├── service │ │ │ ├── ServiceFactory.php │ │ │ └── ServiceInterface.php │ │ ├── http │ │ │ ├── GrpcWebEndpoint.php │ │ │ ├── Method.php │ │ │ ├── FlagdResponseValidator.php │ │ │ └── FlagdResponseResolutionDetailsAdapter.php │ │ ├── common │ │ │ ├── SafeArrayAccessor.php │ │ │ ├── EvaluationContextArrayFactory.php │ │ │ └── ResponseCodeErrorCodeMap.php │ │ └── FlagdProvider.php │ ├── phpstan.neon.dist │ ├── psalm.xml │ ├── phpunit.xml.dist │ ├── phpcs.xml.dist │ ├── tests │ │ └── TestCase.php │ ├── CHANGELOG.md │ └── README.md ├── Split │ ├── .gitignore │ ├── examples │ │ ├── .gitignore │ │ └── SplitSDK │ │ │ ├── README.md │ │ │ ├── composer.json │ │ │ └── src │ │ │ └── main.php │ ├── psalm-baseline.xml │ ├── phpstan.neon.dist │ ├── tests │ │ ├── integration │ │ │ └── files │ │ │ │ └── splits.yml │ │ ├── TestCase.php │ │ └── unit │ │ │ └── SplitProviderTest.php │ ├── src │ │ ├── errors │ │ │ ├── SplitFactoryCreationException.php │ │ │ ├── InvalidTreatmentTypeException.php │ │ │ └── TargetingKeyMissingException.php │ │ └── treatments │ │ │ ├── TreatmentParser.php │ │ │ └── TreatmentValidator.php │ ├── psalm.xml │ ├── phpunit.xml.dist │ ├── phpcs.xml.dist │ ├── CHANGELOG.md │ ├── README.md │ └── composer.json └── CloudBees │ ├── .gitignore │ ├── examples │ ├── .gitignore │ └── CloudBees │ │ ├── README.md │ │ ├── composer.json │ │ └── src │ │ └── main.php │ ├── psalm-baseline.xml │ ├── phpstan.neon.dist │ ├── src │ ├── transformers │ │ ├── IdentityTransformer.php │ │ └── JsonTransformer.php │ ├── errors │ │ ├── InvalidJsonTypeException.php │ │ └── JsonParseException.php │ ├── context │ │ └── ContextAdapter.php │ └── CloudBeesProvider.php │ ├── scripts │ └── seed-data.json │ ├── psalm.xml │ ├── CHANGELOG.md │ ├── phpunit.xml.dist │ ├── tests │ ├── unit │ │ └── JsonTransformerTest.php │ ├── TestCase.php │ └── integration │ │ └── CloudBeesProviderTest.php │ ├── phpcs.xml.dist │ ├── README.md │ └── composer.json ├── .tool-versions ├── .pre-commit-config.yaml ├── .gitmodules ├── renovate.json ├── devenv.yaml ├── .release-please-manifest.json ├── release-please-config.json ├── .gitsplit.yml ├── composer.json ├── devenv.nix ├── README.md └── devenv.lock /hooks/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /providers/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.tool-versions: -------------------------------------------------------------------------------- 1 | php 8.0.24 2 | # php 8.1.11 3 | # php 8.2.1 4 | -------------------------------------------------------------------------------- /hooks/DDTrace/.gitignore: -------------------------------------------------------------------------------- 1 | /composer.lock 2 | /vendor 3 | /build -------------------------------------------------------------------------------- /hooks/DDTrace/examples/.gitignore: -------------------------------------------------------------------------------- 1 | /*/vendor 2 | /*/composer.lock -------------------------------------------------------------------------------- /providers/Flagd/.gitignore: -------------------------------------------------------------------------------- 1 | /composer.lock 2 | /vendor 3 | /build -------------------------------------------------------------------------------- /providers/Split/.gitignore: -------------------------------------------------------------------------------- 1 | /composer.lock 2 | /vendor 3 | /build -------------------------------------------------------------------------------- /hooks/OpenTelemetry/.gitignore: -------------------------------------------------------------------------------- 1 | /composer.lock 2 | /vendor 3 | /build -------------------------------------------------------------------------------- /hooks/Validators/.gitignore: -------------------------------------------------------------------------------- 1 | /composer.lock 2 | /vendor 3 | /build -------------------------------------------------------------------------------- /hooks/Validators/examples/.gitignore: -------------------------------------------------------------------------------- 1 | /*/vendor 2 | /*/composer.lock -------------------------------------------------------------------------------- /providers/CloudBees/.gitignore: -------------------------------------------------------------------------------- 1 | /composer.lock 2 | /vendor 3 | /build -------------------------------------------------------------------------------- /providers/Flagd/examples/.gitignore: -------------------------------------------------------------------------------- 1 | /*/vendor 2 | /*/composer.lock -------------------------------------------------------------------------------- /providers/Split/examples/.gitignore: -------------------------------------------------------------------------------- 1 | /*/vendor 2 | /*/composer.lock -------------------------------------------------------------------------------- /hooks/OpenTelemetry/examples/.gitignore: -------------------------------------------------------------------------------- 1 | /*/vendor 2 | /*/composer.lock -------------------------------------------------------------------------------- /providers/CloudBees/examples/.gitignore: -------------------------------------------------------------------------------- 1 | /*/vendor 2 | /*/composer.lock -------------------------------------------------------------------------------- /providers/Flagd/examples/Http/README.md: -------------------------------------------------------------------------------- 1 | # OpenFeature flagd HTTP example -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | /nix/store/kjn5c8afbhm6xjdaz5z4z2ldwpknw0z9-pre-commit-config.json -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "schemas"] 2 | path = providers/Flagd/schemas 3 | url = https://github.com/tcarrio/schemas/ 4 | -------------------------------------------------------------------------------- /providers/Flagd/proto/README.md: -------------------------------------------------------------------------------- 1 | # proto 2 | 3 | **⚠️ This folder is entirely generated code. Do not modify it by hand!** -------------------------------------------------------------------------------- /hooks/DDTrace/psalm-baseline.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /providers/Flagd/psalm-baseline.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /providers/Split/psalm-baseline.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://docs.renovatebot.com/renovate-schema.json", 3 | "extends": [ 4 | "config:base" 5 | ] 6 | } 7 | -------------------------------------------------------------------------------- /hooks/OpenTelemetry/psalm-baseline.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /hooks/Validators/psalm-baseline.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /providers/CloudBees/psalm-baseline.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /devenv.yaml: -------------------------------------------------------------------------------- 1 | inputs: 2 | nixpkgs: 3 | url: github:NixOS/nixpkgs/nixpkgs-unstable 4 | pre-commit-hooks: 5 | url: github:cachix/pre-commit-hooks.nix -------------------------------------------------------------------------------- /providers/Flagd/proto/php/GPBMetadata/Schema/V1/Schema.php: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/infomaniak/php-sdk-contrib/main/providers/Flagd/proto/php/GPBMetadata/Schema/V1/Schema.php -------------------------------------------------------------------------------- /providers/Split/examples/SplitSDK/README.md: -------------------------------------------------------------------------------- 1 | # OpenFeature Split SDK example 2 | 3 | This example provides an example of bootstrapping and using the OpenFeature Split provider. 4 | -------------------------------------------------------------------------------- /hooks/Validators/examples/ExampleRegexpValidators/README.md: -------------------------------------------------------------------------------- 1 | # OpenFeature Validators Hook example 2 | 3 | This example provides an example of using the validators hooks for OpenFeature. 4 | -------------------------------------------------------------------------------- /providers/CloudBees/examples/CloudBees/README.md: -------------------------------------------------------------------------------- 1 | # OpenFeature CloudBees SDK example 2 | 3 | This example provides an example of bootstrapping and using the OpenFeature CloudBees provider. 4 | -------------------------------------------------------------------------------- /hooks/DDTrace/src/_autoload.php: -------------------------------------------------------------------------------- 1 | getProtocol()) { 15 | default: 16 | return HttpService::fromConfig($config); 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /providers/Flagd/src/http/GrpcWebEndpoint.php: -------------------------------------------------------------------------------- 1 | assertInstanceOf(Hook::class, $hook); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /providers/Flagd/examples/Http/composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "open-feature/flagd-http-example", 3 | "description": "An example of using OpenFeature with the Flagd provider over HTTP", 4 | "type": "project", 5 | "license": "Apache-2.0", 6 | "autoload": { 7 | "psr-4": { 8 | "OpenFeature\\Providers\\Examples\\FlagdHttpExample\\": "src/" 9 | } 10 | }, 11 | "authors": [ 12 | { 13 | "name": "Tom Carrio", 14 | "email": "tom@carrio.dev" 15 | } 16 | ], 17 | "require": { 18 | "open-feature/sdk": "^1.2.0" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /providers/Flagd/src/http/FlagdResponseValidator.php: -------------------------------------------------------------------------------- 1 | getClient('dev.openfeature.contrib.php.demo', '1.0.0'); 13 | 14 | $version = $client->getStringValue('dev.openfeature.contrib.php.version-value', 'unknown'); 15 | 16 | echo 'Version is ' . $version; -------------------------------------------------------------------------------- /hooks/DDTrace/psalm.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /providers/Flagd/psalm.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /providers/Split/psalm.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /hooks/OpenTelemetry/psalm.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /hooks/Validators/psalm.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /providers/CloudBees/psalm.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /providers/Flagd/src/config/IHttpConfig.php: -------------------------------------------------------------------------------- 1 | assertNotEmpty($api->getHooks()); 24 | $this->assertInstanceOf(Hook::class, $api->getHooks()[0]); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /hooks/OpenTelemetry/tests/unit/OpenTelemetryHookTest.php: -------------------------------------------------------------------------------- 1 | assertNotEmpty($api->getHooks()); 24 | $this->assertInstanceOf(Hook::class, $api->getHooks()[0]); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /providers/Flagd/examples/Http/src/main.php: -------------------------------------------------------------------------------- 1 | 'localhost', 19 | 'port' => 8013, 20 | 'secure' => false, 21 | 'protocol' => 'http' 22 | ]); 23 | 24 | $api->setProvider($provider); 25 | 26 | // retrieve an OpenFeatureClient 27 | $client = $api->getClient('http-example', '1.0'); 28 | 29 | $flagValue = $client->getBooleanDetails('dev.openfeature.example_flag', true, null, null); 30 | -------------------------------------------------------------------------------- /hooks/OpenTelemetry/examples/OTelManualInstrumentation/composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "open-feature/otel-manual-instrumentation-example", 3 | "description": "An example of using the OpenTelemetry hook for OpenFeature with manual instrumentation", 4 | "type": "project", 5 | "license": "Apache-2.0", 6 | "authors": [ 7 | { 8 | "name": "Tom Carrio", 9 | "email": "tom@carrio.dev" 10 | } 11 | ], 12 | "require": { 13 | "guzzlehttp/guzzle": "*", 14 | "php-http/guzzle7-adapter": "*", 15 | "slim/slim": "~4", 16 | "php-di/php-di": "^6.3", 17 | "php-di/slim-bridge": "^3.2", 18 | "open-telemetry/api": "0.0.17", 19 | "open-telemetry/sdk": "0.0.17", 20 | "open-feature/sdk": "^1.2.0" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /providers/Flagd/phpunit.xml.dist: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 10 | 11 | ./tests/unit 12 | 13 | 14 | 15 | 16 | 17 | ./src 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /hooks/Validators/examples/ExampleRegexpValidators/composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "open-feature/validators-hook-example", 3 | "description": "An example of using the validator hooks for OpenFeature", 4 | "type": "project", 5 | "license": "Apache-2.0", 6 | "authors": [ 7 | { 8 | "name": "Tom Carrio", 9 | "email": "tom@carrio.dev" 10 | } 11 | ], 12 | "require": { 13 | "open-feature/sdk": "^1.2.0", 14 | "open-feature/validators-hook": "dev-main" 15 | }, 16 | "repositories": [ 17 | { 18 | "type": "path", 19 | "url": "../../", 20 | "options": { 21 | "versions": { 22 | "open-feature/validators-hook": "dev-main" 23 | } 24 | } 25 | } 26 | ] 27 | } 28 | -------------------------------------------------------------------------------- /hooks/OpenTelemetry/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## 0.2.0 (2023-01-09) 4 | 5 | 6 | ### ⚠ BREAKING CHANGES 7 | 8 | * reset release-please ([#39](https://github.com/open-feature/php-sdk-contrib/issues/39)) 9 | 10 | ### Features 11 | 12 | * otel hook ([#22](https://github.com/open-feature/php-sdk-contrib/issues/22)) ([be3f1e9](https://github.com/open-feature/php-sdk-contrib/commit/be3f1e9ed37dee4bbce8e3701e4693c1b949c398)) 13 | * **otel-hook:** autoload registration of otel hook ([#25](https://github.com/open-feature/php-sdk-contrib/issues/25)) ([789a95c](https://github.com/open-feature/php-sdk-contrib/commit/789a95c47bc278b333bf8b241b0e342baa27acc5)) 14 | 15 | 16 | ### Miscellaneous Chores 17 | 18 | * reset release-please ([#39](https://github.com/open-feature/php-sdk-contrib/issues/39)) ([b452080](https://github.com/open-feature/php-sdk-contrib/commit/b452080443d837c66b554b1bb1a07cadba5a152a)) 19 | -------------------------------------------------------------------------------- /providers/CloudBees/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## 0.3.0 (2023-01-09) 4 | 5 | 6 | ### ⚠ BREAKING CHANGES 7 | 8 | * reset release-please ([#39](https://github.com/open-feature/php-sdk-contrib/issues/39)) 9 | 10 | ### Features 11 | 12 | * otel hook ([#22](https://github.com/open-feature/php-sdk-contrib/issues/22)) ([be3f1e9](https://github.com/open-feature/php-sdk-contrib/commit/be3f1e9ed37dee4bbce8e3701e4693c1b949c398)) 13 | * **otel-hook:** autoload registration of otel hook ([#25](https://github.com/open-feature/php-sdk-contrib/issues/25)) ([789a95c](https://github.com/open-feature/php-sdk-contrib/commit/789a95c47bc278b333bf8b241b0e342baa27acc5)) 14 | 15 | 16 | ### Miscellaneous Chores 17 | 18 | * reset release-please ([#39](https://github.com/open-feature/php-sdk-contrib/issues/39)) ([b452080](https://github.com/open-feature/php-sdk-contrib/commit/b452080443d837c66b554b1bb1a07cadba5a152a)) 19 | -------------------------------------------------------------------------------- /providers/CloudBees/src/transformers/JsonTransformer.php: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 10 | 11 | ./tests/unit 12 | 13 | 14 | ./tests/integration 15 | 16 | 17 | 18 | 19 | 20 | ./src 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /providers/Split/phpunit.xml.dist: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 10 | 11 | ./tests/unit 12 | 13 | 14 | ./tests/integration 15 | 16 | 17 | 18 | 19 | 20 | ./src 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /hooks/OpenTelemetry/phpunit.xml.dist: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 10 | 11 | ./tests/unit 12 | 13 | 14 | ./tests/integration 15 | 16 | 17 | 18 | 19 | 20 | ./src 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /hooks/Validators/phpunit.xml.dist: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 10 | 11 | ./tests/unit 12 | 13 | 14 | ./tests/integration 15 | 16 | 17 | 18 | 19 | 20 | ./src 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /providers/CloudBees/phpunit.xml.dist: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 10 | 11 | ./tests/unit 12 | 13 | 14 | ./tests/integration 15 | 16 | 17 | 18 | 19 | 20 | ./src 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /hooks/Validators/examples/ExampleRegexpValidators/src/main.php: -------------------------------------------------------------------------------- 1 | getClient('split-example', '1.0'); 18 | 19 | // create some example hook validators 20 | 21 | $alphanumericValidator = new RegexpValidatorHook('/^[A-Za-z0-9]+$/'); 22 | $hexadecimalValidator = new RegexpValidatorHook('/^[0-9a-f]+$/'); 23 | $asciiValidator = new RegexpValidatorHook('/^[ -~]$/'); 24 | 25 | $client->setHooks([ 26 | $alphanumericValidator, 27 | $hexadecimalValidator, 28 | $asciiValidator 29 | ]); 30 | 31 | $flagValue = $client->getBooleanDetails('dev.openfeature.example_flag', true, null, null); 32 | -------------------------------------------------------------------------------- /providers/CloudBees/src/errors/InvalidJsonTypeException.php: -------------------------------------------------------------------------------- 1 | resolutionError = new ResolutionErrorImpl(ErrorCode::PARSE_ERROR(), 'An error occurred while parsing the JSON'); 21 | } 22 | 23 | public function getResolutionError(): ResolutionError 24 | { 25 | return $this->resolutionError; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /providers/CloudBees/src/errors/JsonParseException.php: -------------------------------------------------------------------------------- 1 | resolutionError = new ResolutionErrorImpl(ErrorCode::PARSE_ERROR(), 'An error occurred while parsing the JSON'); 21 | } 22 | 23 | public function getResolutionError(): ResolutionError 24 | { 25 | return $this->resolutionError; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /providers/CloudBees/tests/unit/JsonTransformerTest.php: -------------------------------------------------------------------------------- 1 | assertNotNull($decodedValue); 26 | $this->assertIsArray($decodedValue); 27 | $this->assertEquals($decodedValue['name'], $name); 28 | $this->assertEquals($decodedValue['version'], $version); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /providers/Flagd/src/common/SafeArrayAccessor.php: -------------------------------------------------------------------------------- 1 | arr = $arr; 18 | } 19 | 20 | /** 21 | * @param mixed[] $arr 22 | */ 23 | public static function with(array $arr): SafeArrayAccessor 24 | { 25 | return new SafeArrayAccessor($arr); 26 | } 27 | 28 | /** 29 | * @param mixed[] $arr 30 | * 31 | * @return mixed 32 | */ 33 | public static function getKeyFromArray(array $arr, string $key) 34 | { 35 | return $arr[$key] ?? null; 36 | } 37 | 38 | /** 39 | * @return mixed 40 | */ 41 | public function get(string $key) 42 | { 43 | return self::getKeyFromArray($this->arr, $key); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /hooks/OpenTelemetry/examples/AutoloadOTelSDK/src/main.php: -------------------------------------------------------------------------------- 1 | getClient('dev.openfeature.contrib.php.demo', '1.0.0'); 22 | 23 | $version = $client->getStringValue('dev.openfeature.contrib.php.version-value', 'unknown'); 24 | 25 | echo 'Version is ' . $version; -------------------------------------------------------------------------------- /providers/Split/src/errors/InvalidTreatmentTypeException.php: -------------------------------------------------------------------------------- 1 | resolutionError = new ProviderResolutionError(ErrorCode::TYPE_MISMATCH(), 'Treatment value does not match the expected type'); 21 | } 22 | 23 | public function getResolutionError(): ResolutionError 24 | { 25 | return $this->resolutionError; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /providers/Split/src/errors/TargetingKeyMissingException.php: -------------------------------------------------------------------------------- 1 | resolutionError = new ProviderResolutionError(ErrorCode::TARGETING_KEY_MISSING(), 'The targeting key is required for Split'); 21 | } 22 | 23 | public function getResolutionError(): ResolutionError 24 | { 25 | return $this->resolutionError; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /providers/Flagd/src/common/EvaluationContextArrayFactory.php: -------------------------------------------------------------------------------- 1 | getAttributes()->toArray(), 27 | $context->getTargetingKey() ? ['targetingKey' => $context->getTargetingKey()] : [], 28 | ); 29 | 30 | if (sizeof($contextArray) === 0) { 31 | return new stdClass(); 32 | } 33 | } 34 | 35 | return $contextArray; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /providers/CloudBees/src/context/ContextAdapter.php: -------------------------------------------------------------------------------- 1 | getAttributes()->toArray(), 25 | ['targetingKey' => $context->getTargetingKey()], 26 | ), 27 | /** 28 | * @param mixed $value 29 | */ 30 | fn ($value) => !is_null($value), 31 | ), 32 | ); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /release-please-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "bootstrap-sha": "91dbcca98f4a56ec37ce1b03bc0f39aeaba6dbd3", 3 | "separate-pull-requests": true, 4 | "prerelease": false, 5 | "bump-minor-pre-major": true, 6 | "bump-patch-for-minor-pre-major": true, 7 | "include-v-in-tag": false, 8 | "packages": { 9 | "hooks/DDTrace": { 10 | "package-name": "open-feature/dd-trace-hook", 11 | "release-as": "0.2.0" 12 | }, 13 | "hooks/OpenTelemetry": { 14 | "package-name": "open-feature/otel-hook", 15 | "release-as": "0.2.0" 16 | }, 17 | "hooks/Validators": { 18 | "package-name": "open-feature/validators-hook", 19 | "release-as": "0.2.0" 20 | }, 21 | "providers/CloudBees": { 22 | "package-name": "open-feature/cloudbees-provider", 23 | "release-as": "0.3.0" 24 | }, 25 | "providers/Flagd": { 26 | "package-name": "open-feature/flagd-provider", 27 | "release-as": "0.4.0" 28 | }, 29 | "providers/Split": { 30 | "package-name": "open-feature/split-provider", 31 | "release-as": "0.3.0" 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /hooks/Validators/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## [0.2.0](https://github.com/open-feature/php-sdk-contrib/compare/open-feature/validators-hook-0.2.0...open-feature/validators-hook-0.2.0) (2023-02-12) 4 | 5 | 6 | ### Features 7 | 8 | * deprecate php 7 ([#59](https://github.com/open-feature/php-sdk-contrib/issues/59)) ([d028e6d](https://github.com/open-feature/php-sdk-contrib/commit/d028e6d7741d07b7edef21b43b249fdb2d18d8f2)) 9 | 10 | ## 0.2.0 (2023-01-09) 11 | 12 | 13 | ### ⚠ BREAKING CHANGES 14 | 15 | * reset release-please ([#39](https://github.com/open-feature/php-sdk-contrib/issues/39)) 16 | 17 | ### Features 18 | 19 | * **validators-hook:** created new package with validation offering ([#30](https://github.com/open-feature/php-sdk-contrib/issues/30)) ([a2501e6](https://github.com/open-feature/php-sdk-contrib/commit/a2501e6440e8f25ce3231fffd225f5cf13ab5fe4)) 20 | 21 | 22 | ### Miscellaneous Chores 23 | 24 | * reset release-please ([#39](https://github.com/open-feature/php-sdk-contrib/issues/39)) ([b452080](https://github.com/open-feature/php-sdk-contrib/commit/b452080443d837c66b554b1bb1a07cadba5a152a)) 25 | -------------------------------------------------------------------------------- /hooks/DDTrace/phpcs.xml.dist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | ./src 9 | ./tests 10 | 11 | */tests/fixtures/* 12 | */tests/*/fixtures/* 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /hooks/DDTrace/tests/TestCase.php: -------------------------------------------------------------------------------- 1 | $class 25 | * @param mixed ...$arguments 26 | * 27 | * @return T & MockInterface 28 | * 29 | * @template T 30 | * 31 | * phpcs:disable SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint 32 | */ 33 | public function mockery(string $class, ...$arguments) 34 | { 35 | /** @var T & MockInterface $mock */ 36 | $mock = Mockery::mock($class, ...$arguments); 37 | 38 | return $mock; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /hooks/OpenTelemetry/phpcs.xml.dist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | ./src 9 | ./tests 10 | 11 | */tests/fixtures/* 12 | */tests/*/fixtures/* 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /hooks/Validators/phpcs.xml.dist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | ./src 9 | ./tests 10 | 11 | */tests/fixtures/* 12 | */tests/*/fixtures/* 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /providers/CloudBees/phpcs.xml.dist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | ./src 9 | ./tests 10 | 11 | */tests/fixtures/* 12 | */tests/*/fixtures/* 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /providers/Flagd/phpcs.xml.dist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | ./src 9 | ./tests 10 | 11 | */tests/fixtures/* 12 | */tests/*/fixtures/* 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /providers/Split/phpcs.xml.dist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | ./src 9 | ./tests 10 | 11 | */tests/fixtures/* 12 | */tests/*/fixtures/* 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /providers/Flagd/tests/TestCase.php: -------------------------------------------------------------------------------- 1 | $class 25 | * @param mixed ...$arguments 26 | * 27 | * @return T & MockInterface 28 | * 29 | * @template T 30 | * 31 | * phpcs:disable SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint 32 | */ 33 | public function mockery(string $class, ...$arguments) 34 | { 35 | /** @var T & MockInterface $mock */ 36 | $mock = Mockery::mock($class, ...$arguments); 37 | 38 | return $mock; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /providers/Split/tests/TestCase.php: -------------------------------------------------------------------------------- 1 | $class 25 | * @param mixed ...$arguments 26 | * 27 | * @return T & MockInterface 28 | * 29 | * @template T 30 | * 31 | * phpcs:disable SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint 32 | */ 33 | public function mockery(string $class, ...$arguments) 34 | { 35 | /** @var T & MockInterface $mock */ 36 | $mock = Mockery::mock($class, ...$arguments); 37 | 38 | return $mock; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /hooks/Validators/tests/TestCase.php: -------------------------------------------------------------------------------- 1 | $class 25 | * @param mixed ...$arguments 26 | * 27 | * @return T & MockInterface 28 | * 29 | * @template T 30 | * 31 | * phpcs:disable SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint 32 | */ 33 | public function mockery(string $class, ...$arguments) 34 | { 35 | /** @var T & MockInterface $mock */ 36 | $mock = Mockery::mock($class, ...$arguments); 37 | 38 | return $mock; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /hooks/OpenTelemetry/tests/TestCase.php: -------------------------------------------------------------------------------- 1 | $class 25 | * @param mixed ...$arguments 26 | * 27 | * @return T & MockInterface 28 | * 29 | * @template T 30 | * 31 | * phpcs:disable SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint 32 | */ 33 | public function mockery(string $class, ...$arguments) 34 | { 35 | /** @var T & MockInterface $mock */ 36 | $mock = Mockery::mock($class, ...$arguments); 37 | 38 | return $mock; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /providers/CloudBees/tests/TestCase.php: -------------------------------------------------------------------------------- 1 | $class 25 | * @param mixed ...$arguments 26 | * 27 | * @return T & MockInterface 28 | * 29 | * @template T 30 | * 31 | * phpcs:disable SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint 32 | */ 33 | public function mockery(string $class, ...$arguments) 34 | { 35 | /** @var T & MockInterface $mock */ 36 | $mock = Mockery::mock($class, ...$arguments); 37 | 38 | return $mock; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /providers/Split/examples/SplitSDK/src/main.php: -------------------------------------------------------------------------------- 1 | 'tcp', 19 | 'host' => getenv('REDIS_HOST'), 20 | 'port' => getenv('REDIS_PORT'), 21 | 'timeout' => 881, 22 | ]; 23 | 24 | $options = ['prefix' => '']; 25 | 26 | $splitConfig = [ 27 | 'cache' => [ 28 | 'adapter' => 'predis', 29 | 'parameters' => $parameters, 30 | 'options' => $options, 31 | ], 32 | ]; 33 | 34 | $splitApiKey = getenv('SPLIT_API_KEY'); 35 | 36 | $provider = new SplitProvider($splitApiKey, $splitConfig); 37 | 38 | $api->setProvider($provider); 39 | 40 | // retrieve an OpenFeatureClient 41 | $client = $api->getClient('split-example', '1.0'); 42 | 43 | $flagValue = $client->getBooleanDetails('dev.openfeature.example_flag', true, null, null); 44 | -------------------------------------------------------------------------------- /providers/Split/tests/unit/SplitProviderTest.php: -------------------------------------------------------------------------------- 1 | getPathToValidSplitFile(); 18 | 19 | $apiKey = 'localhost'; 20 | $config = [ 21 | 'splitFile' => $splitFile, 22 | ]; 23 | 24 | // When 25 | $instance = new SplitProvider($apiKey, $config); 26 | 27 | // Then 28 | $this->assertNotNull($instance); 29 | $this->assertInstanceOf(Provider::class, $instance); 30 | } 31 | 32 | private function getPathToValidSplitFile(): string 33 | { 34 | $splitFs = vfsStream::setup('root', 0777, [ 35 | '.split' => '', 36 | ]); 37 | 38 | return $splitFs->getChild('.split')->url(); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /providers/Flagd/src/common/ResponseCodeErrorCodeMap.php: -------------------------------------------------------------------------------- 1 | ErrorCode::FLAG_NOT_FOUND(), 38 | 'invalid_argument' => ErrorCode::TYPE_MISMATCH(), 39 | ]; 40 | 41 | self::$initialized = true; 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /providers/Flagd/src/config/HttpConfig.php: -------------------------------------------------------------------------------- 1 | client = $client; 20 | $this->requestFactory = $requestFactory; 21 | $this->streamFactory = $streamFactory; 22 | } 23 | 24 | public function getClient(): ClientInterface 25 | { 26 | return $this->client; 27 | } 28 | 29 | public function getRequestFactory(): RequestFactoryInterface 30 | { 31 | return $this->requestFactory; 32 | } 33 | 34 | public function getStreamFactory(): StreamFactoryInterface 35 | { 36 | return $this->streamFactory; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /.gitsplit.yml: -------------------------------------------------------------------------------- 1 | # Path to a cache directory Used to speed up the split over time by reusing git's objects 2 | cache_url: "/cache/gitsplit" 3 | 4 | # Path to the repository to split (default = current path) 5 | project_url: "https://github.com/open-feature/php-sdk-contrib.git" 6 | 7 | # List of splits. 8 | splits: 9 | - prefix: "hooks/OpenTelemetry" 10 | target: "https://${GH_TOKEN}@github.com/open-feature-php/otel-hook.git" 11 | - prefix: "hooks/DDTrace" 12 | target: "https://${GH_TOKEN}@github.com/open-feature-php/dd-trace-hook.git" 13 | - prefix: "hooks/Validators" 14 | target: "https://${GH_TOKEN}@github.com/open-feature-php/validators-hook.git" 15 | - prefix: "providers/Flagd" 16 | target: "https://${GH_TOKEN}@github.com/open-feature-php/flagd-provider.git" 17 | - prefix: "providers/Split" 18 | target: "https://${GH_TOKEN}@github.com/open-feature-php/split-provider.git" 19 | - prefix: "providers/CloudBees" 20 | target: "https://${GH_TOKEN}@github.com/open-feature-php/cloudbees-provider.git" 21 | 22 | # List of references to split (defined as regexp) 23 | origins: 24 | - ^main$ 25 | - ^test$ 26 | - ^split$ 27 | - ^v\d+\.\d+\.\d+$ 28 | - ^\d+\.\d+\.\d+$ 29 | -------------------------------------------------------------------------------- /hooks/DDTrace/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## [0.2.0](https://github.com/open-feature/php-sdk-contrib/compare/open-feature/dd-trace-hook-0.2.0...open-feature/dd-trace-hook-0.2.0) (2023-02-12) 4 | 5 | 6 | ### Features 7 | 8 | * deprecate php 7 ([#59](https://github.com/open-feature/php-sdk-contrib/issues/59)) ([d028e6d](https://github.com/open-feature/php-sdk-contrib/commit/d028e6d7741d07b7edef21b43b249fdb2d18d8f2)) 9 | 10 | ## 0.2.0 (2023-01-09) 11 | 12 | 13 | ### ⚠ BREAKING CHANGES 14 | 15 | * fix release-please config ([#38](https://github.com/open-feature/php-sdk-contrib/issues/38)) 16 | * fix release-please config 17 | 18 | ### Features 19 | 20 | * dd-trace hook ([#26](https://github.com/open-feature/php-sdk-contrib/issues/26)) ([d2b1a04](https://github.com/open-feature/php-sdk-contrib/commit/d2b1a0440bbb0d1fa557b3aefd32eee6267f2823)) 21 | 22 | 23 | ### Miscellaneous Chores 24 | 25 | * fix release-please config ([0210952](https://github.com/open-feature/php-sdk-contrib/commit/0210952af1d6774744c633507a9bec73f3cf7251)) 26 | * fix release-please config ([#38](https://github.com/open-feature/php-sdk-contrib/issues/38)) ([8ee9fe3](https://github.com/open-feature/php-sdk-contrib/commit/8ee9fe37584ad6754272ad3ac016902e6ebd48d8)) 27 | -------------------------------------------------------------------------------- /providers/Flagd/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## [0.4.0](https://github.com/open-feature/php-sdk-contrib/compare/open-feature/flagd-provider-0.4.0...open-feature/flagd-provider-0.4.0) (2023-02-12) 4 | 5 | 6 | ### Features 7 | 8 | * deprecate php 7 ([#59](https://github.com/open-feature/php-sdk-contrib/issues/59)) ([d028e6d](https://github.com/open-feature/php-sdk-contrib/commit/d028e6d7741d07b7edef21b43b249fdb2d18d8f2)) 9 | 10 | ## 0.4.0 (2023-01-09) 11 | 12 | 13 | ### ⚠ BREAKING CHANGES 14 | 15 | * reset release-please ([#39](https://github.com/open-feature/php-sdk-contrib/issues/39)) 16 | 17 | ### Features 18 | 19 | * otel hook ([#22](https://github.com/open-feature/php-sdk-contrib/issues/22)) ([be3f1e9](https://github.com/open-feature/php-sdk-contrib/commit/be3f1e9ed37dee4bbce8e3701e4693c1b949c398)) 20 | * **otel-hook:** autoload registration of otel hook ([#25](https://github.com/open-feature/php-sdk-contrib/issues/25)) ([789a95c](https://github.com/open-feature/php-sdk-contrib/commit/789a95c47bc278b333bf8b241b0e342baa27acc5)) 21 | 22 | 23 | ### Miscellaneous Chores 24 | 25 | * reset release-please ([#39](https://github.com/open-feature/php-sdk-contrib/issues/39)) ([b452080](https://github.com/open-feature/php-sdk-contrib/commit/b452080443d837c66b554b1bb1a07cadba5a152a)) 26 | -------------------------------------------------------------------------------- /hooks/DDTrace/tests/integration/DDTraceHookTest.php: -------------------------------------------------------------------------------- 1 | clearHooks(); 19 | 20 | // When 21 | $this->simulateAutoload(); 22 | 23 | // Then 24 | 25 | $this->assertCount(1, $api->getHooks()); 26 | $this->assertInstanceOf(Hook::class, $api->getHooks()[0]); 27 | } 28 | 29 | public function testCanBeRegistered(): void 30 | { 31 | // Given 32 | $api = OpenFeatureAPI::getInstance(); 33 | $api->clearHooks(); 34 | 35 | // When 36 | DDTraceHook::register(); 37 | 38 | // Then 39 | $this->assertCount(1, $api->getHooks()); 40 | $this->assertInstanceOf(Hook::class, $api->getHooks()[0]); 41 | } 42 | 43 | private function simulateAutoload(): void 44 | { 45 | require __DIR__ . '/../../src/_autoload.php'; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /hooks/OpenTelemetry/tests/integration/OpenTelemetryHookTest.php: -------------------------------------------------------------------------------- 1 | clearHooks(); 19 | 20 | // When 21 | $this->simulateAutoload(); 22 | 23 | // Then 24 | 25 | $this->assertCount(1, $api->getHooks()); 26 | $this->assertInstanceOf(Hook::class, $api->getHooks()[0]); 27 | } 28 | 29 | public function testCanBeRegistered(): void 30 | { 31 | // Given 32 | $api = OpenFeatureAPI::getInstance(); 33 | $api->clearHooks(); 34 | 35 | // When 36 | OpenTelemetryHook::register(); 37 | 38 | // Then 39 | $this->assertCount(1, $api->getHooks()); 40 | $this->assertInstanceOf(Hook::class, $api->getHooks()[0]); 41 | } 42 | 43 | private function simulateAutoload(): void 44 | { 45 | require __DIR__ . '/../../src/_autoload.php'; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /providers/Flagd/src/config/Config.php: -------------------------------------------------------------------------------- 1 | host = $host ?? Defaults::DEFAULT_HOST; 18 | $this->port = $port ?? Defaults::DEFAULT_PORT; 19 | $this->protocol = $protocol ?? Defaults::DEFAULT_PROTOCOL; 20 | $this->secure = $secure ?? Defaults::DEFAULT_SECURE; 21 | $this->httpConfig = $httpConfig ?? null; 22 | } 23 | 24 | public function getHost(): string 25 | { 26 | return $this->host; 27 | } 28 | 29 | public function getPort(): int 30 | { 31 | return $this->port; 32 | } 33 | 34 | public function getProtocol(): string 35 | { 36 | return $this->protocol; 37 | } 38 | 39 | public function isSecure(): bool 40 | { 41 | return $this->secure; 42 | } 43 | 44 | public function getHttpConfig(): ?IHttpConfig 45 | { 46 | return $this->httpConfig; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /providers/Split/src/treatments/TreatmentParser.php: -------------------------------------------------------------------------------- 1 | has(TracerInterface::class)) { 27 | /** @var TracerInterface|null $maybeTracer */ 28 | $maybeTracer = $container->get(TracerInterface::class); 29 | 30 | if ($maybeTracer instanceof TracerInterface) { 31 | return $maybeTracer; 32 | } 33 | } 34 | } 35 | 36 | return Globals::tracerProvider()->getTracer('open-feature/otel-hook', '0.0.1'); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /devenv.nix: -------------------------------------------------------------------------------- 1 | { pkgs, ... }: 2 | 3 | { 4 | 5 | # https://devenv.sh/packages/ 6 | packages = [ pkgs.git ]; 7 | 8 | # https://devenv.sh/languages/ 9 | languages.nix.enable = true; 10 | languages.php.enable = true; 11 | languages.php.package = pkgs.php80; 12 | 13 | # https://devenv.sh/basics/ 14 | env.PROJECT_NAME = "openfeature-php-sdk"; 15 | 16 | # https://devenv.sh/scripts/ 17 | scripts.hello.exec = "echo $ Started devenv shell in $PROJECT_NAME"; 18 | 19 | enterShell = '' 20 | hello 21 | echo 22 | git --version 23 | php --version 24 | echo 25 | 26 | # optimization step -- files and directories that match entries 27 | # in the .gitignore will still be traversed, and the .devenv 28 | # directory contains over 5000 files and 121MB. 29 | if ! grep -E "excludesfile.+\.gitignore" .git/config &>/dev/null 30 | then 31 | git config --local core.excludesfile .gitignore 32 | fi 33 | ''; 34 | 35 | ## https://devenv.sh/pre-commit-hooks/ 36 | pre-commit.hooks = { 37 | # # general formatting 38 | # prettier.enable = true; 39 | # github actions 40 | actionlint.enable = true; 41 | # nix 42 | deadnix.enable = true; 43 | nixfmt.enable = true; 44 | # php 45 | # phpcbf.enable = true; 46 | # # ensure Markdown code is executable 47 | # mdsh.enable = true; 48 | }; 49 | 50 | # https://devenv.sh/processes/ 51 | # processes.ping.exec = "ping example.com"; 52 | } 53 | -------------------------------------------------------------------------------- /providers/Split/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## [0.3.0](https://github.com/open-feature/php-sdk-contrib/compare/open-feature/split-provider-0.3.0...open-feature/split-provider-0.3.0) (2023-02-12) 4 | 5 | 6 | ### Features 7 | 8 | * deprecate php 7 ([#59](https://github.com/open-feature/php-sdk-contrib/issues/59)) ([d028e6d](https://github.com/open-feature/php-sdk-contrib/commit/d028e6d7741d07b7edef21b43b249fdb2d18d8f2)) 9 | 10 | ## 0.3.0 (2023-01-09) 11 | 12 | 13 | ### ⚠ BREAKING CHANGES 14 | 15 | * reset release-please config ([#40](https://github.com/open-feature/php-sdk-contrib/issues/40)) 16 | * reset release-please ([#39](https://github.com/open-feature/php-sdk-contrib/issues/39)) 17 | 18 | ### Features 19 | 20 | * otel hook ([#22](https://github.com/open-feature/php-sdk-contrib/issues/22)) ([be3f1e9](https://github.com/open-feature/php-sdk-contrib/commit/be3f1e9ed37dee4bbce8e3701e4693c1b949c398)) 21 | * **otel-hook:** autoload registration of otel hook ([#25](https://github.com/open-feature/php-sdk-contrib/issues/25)) ([789a95c](https://github.com/open-feature/php-sdk-contrib/commit/789a95c47bc278b333bf8b241b0e342baa27acc5)) 22 | 23 | 24 | ### Miscellaneous Chores 25 | 26 | * reset release-please ([#39](https://github.com/open-feature/php-sdk-contrib/issues/39)) ([b452080](https://github.com/open-feature/php-sdk-contrib/commit/b452080443d837c66b554b1bb1a07cadba5a152a)) 27 | * reset release-please config ([#40](https://github.com/open-feature/php-sdk-contrib/issues/40)) ([b9a3b7e](https://github.com/open-feature/php-sdk-contrib/commit/b9a3b7e1017dc56ddfdd767fb8dab2d01b641699)) 28 | -------------------------------------------------------------------------------- /providers/Split/src/treatments/TreatmentValidator.php: -------------------------------------------------------------------------------- 1 | =8.0-blue.svg) 6 | ![License](https://img.shields.io/github/license/open-feature/php-sdk-contrib) 7 | ![Experimental](https://img.shields.io/badge/Status-Experimental-yellow) 8 | 9 | ## Overview 10 | 11 | The `php-contrib-sdk` repository is a monorepository containing various providers and hooks for OpenFeature's PHP SDK. Packages include: 12 | 13 | - Providers 14 | - [Flagd](./providers/Flagd/README.md) 15 | - [Split](./providers/Split/README.md) 16 | - [CloudBees](./providers/CloudBees/README.md) 17 | - Hooks 18 | - [OpenTelemetry](./hooks/OpenTelemetry/README.md) 19 | - [Datadog](./hooks/DDTrace/README.md) 20 | - [Validators](./hooks/Validators/README.md) 21 | 22 | ### Status 23 | 24 | This repository is marked as **experimental** since the repository structure itself could change. However, each the packages within the repository maintains its own release status. 25 | 26 | ## Development 27 | 28 | ### PHP Versioning 29 | 30 | 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. 31 | 32 | This package also has a `.tool-versions` file for use with PHP version managers like `asdf`. 33 | 34 | ### Installation and Dependencies 35 | 36 | Install dependencies with `composer install`. `composer install` will update the `composer.lock` with the most recent compatible versions. 37 | 38 | We value having as few runtime dependencies as possible. The addition of any dependencies requires careful consideration and review. 39 | 40 | ### Testing 41 | 42 | Each package implements its own test suite. 43 | 44 | Run tests with `composer run test` in the package's directory. 45 | -------------------------------------------------------------------------------- /hooks/Validators/src/Regexp/RegexpValidatorHook.php: -------------------------------------------------------------------------------- 1 | regexp = self::validateRegexp($regexp); 26 | } 27 | 28 | public function before(HookContext $context, HookHints $hints): ?EvaluationContext 29 | { 30 | return null; 31 | } 32 | 33 | public function after(HookContext $context, ResolutionDetails $details, HookHints $hints): void 34 | { 35 | /** @var string $resolvedValue */ 36 | $resolvedValue = $details->getValue(); 37 | 38 | if ($this->testResolvedValue($resolvedValue)) { 39 | return; 40 | } 41 | 42 | throw new ValidationException(); 43 | } 44 | 45 | public function error(HookContext $context, Throwable $error, HookHints $hints): void 46 | { 47 | // no-op 48 | } 49 | 50 | public function finally(HookContext $context, HookHints $hints): void 51 | { 52 | // no-op 53 | } 54 | 55 | public function supportsFlagValueType(string $flagValueType): bool 56 | { 57 | return $flagValueType === FlagValueType::STRING; 58 | } 59 | 60 | private function testResolvedValue(string $resolvedValue): bool 61 | { 62 | return preg_match($this->regexp, $resolvedValue) === 1; 63 | } 64 | 65 | private static function validateRegexp(string $regexp): string 66 | { 67 | if (self::isValidRegexp($regexp)) { 68 | return $regexp; 69 | } 70 | 71 | throw new InvalidRegularExpressionException($regexp); 72 | } 73 | 74 | private static function isValidRegexp(string $regexp): bool 75 | { 76 | return is_int(@preg_match($regexp, '')); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /providers/Flagd/src/FlagdProvider.php: -------------------------------------------------------------------------------- 1 | config = Validator::validate($config); 28 | 29 | $this->service = ServiceFactory::fromConfig($this->config); 30 | } 31 | 32 | public function resolveBooleanValue(string $flagKey, bool $defaultValue, ?EvaluationContext $context = null): ResolutionDetails 33 | { 34 | return $this->service->resolveValue($flagKey, FlagValueType::BOOLEAN, $defaultValue, $context); 35 | } 36 | 37 | public function resolveStringValue(string $flagKey, string $defaultValue, ?EvaluationContext $context = null): ResolutionDetails 38 | { 39 | return $this->service->resolveValue($flagKey, FlagValueType::STRING, $defaultValue, $context); 40 | } 41 | 42 | public function resolveIntegerValue(string $flagKey, int $defaultValue, ?EvaluationContext $context = null): ResolutionDetails 43 | { 44 | return $this->service->resolveValue($flagKey, FlagValueType::INTEGER, $defaultValue, $context); 45 | } 46 | 47 | public function resolveFloatValue(string $flagKey, float $defaultValue, ?EvaluationContext $context = null): ResolutionDetails 48 | { 49 | return $this->service->resolveValue($flagKey, FlagValueType::FLOAT, $defaultValue, $context); 50 | } 51 | 52 | public function resolveObjectValue(string $flagKey, mixed $defaultValue, ?EvaluationContext $context = null): ResolutionDetails 53 | { 54 | return $this->service->resolveValue($flagKey, FlagValueType::OBJECT, $defaultValue, $context); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /hooks/Validators/README.md: -------------------------------------------------------------------------------- 1 | # OpenFeature Validator Hooks 2 | 3 | [![a](https://img.shields.io/badge/slack-%40cncf%2Fopenfeature-brightgreen?style=flat&logo=slack)](https://cloud-native.slack.com/archives/C0344AANLA1) 4 | [![Latest Stable Version](http://poser.pugx.org/open-feature/validators-hook/v)](https://packagist.org/packages/open-feature/validators-hook) 5 | [![Total Downloads](http://poser.pugx.org/open-feature/validators-hook/downloads)](https://packagist.org/packages/open-feature/validators-hook) 6 | ![PHP 8.0+](https://img.shields.io/badge/php->=8.0-blue.svg) 7 | [![License](http://poser.pugx.org/open-feature/validators-hook/license)](https://packagist.org/packages/open-feature/validators-hook) 8 | 9 | ## Overview 10 | 11 | Validator Hook constructs that provide means to execute validation against resolved feature flag values. 12 | 13 | This package also builds on various PSRs (PHP Standards Recommendations) such as the Logger interfaces (PSR-3) and the Basic and Extended Coding Standards (PSR-1 and PSR-12). 14 | 15 | ## Installation 16 | 17 | ```sh 18 | composer require open-feature/validators-hook 19 | ``` 20 | 21 | ## Usage 22 | 23 | The following validator hook constructs are available, but more are being worked on over time: 24 | 25 | - `RegexpValidatorHook` 26 | 27 | 28 | ```php 29 | use OpenFeature\Hooks\Validators\RegexpValidatorHook; 30 | 31 | $alphanumericValidator = new RegexpValidatorHook('/^[A-Za-z0-9]+$/'); 32 | $hexadecimalValidator = new RegexpValidatorHook('/^[0-9a-f]+$/'); 33 | $asciiValidator = new RegexpValidatorHook('/^[ -~]$/'); 34 | 35 | // this specific invocation will use this validator 36 | $client->resolveStringValue('test-flag', 'deadbeef', null, new EvaluationOptions([$hexadecimalValidator])); 37 | ``` 38 | 39 | For more examples, see the [examples](./examples/). 40 | 41 | ## Development 42 | 43 | ### PHP Versioning 44 | 45 | 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. 46 | 47 | This package also has a `.tool-versions` file for use with PHP version managers like `asdf`. 48 | 49 | ### Installation and Dependencies 50 | 51 | Install dependencies with `composer install`. `composer install` will update the `composer.lock` with the most recent compatible versions. 52 | 53 | We value having as few runtime dependencies as possible. The addition of any dependencies requires careful consideration and review. 54 | 55 | ### Testing 56 | 57 | Run tests with `composer run test`. 58 | -------------------------------------------------------------------------------- /providers/Flagd/src/http/FlagdResponseResolutionDetailsAdapter.php: -------------------------------------------------------------------------------- 1 | withValue($defaultValue) 23 | ->withError(new ResolutionError(ErrorCode::TYPE_MISMATCH())) 24 | ->build(); 25 | } 26 | 27 | /** 28 | * @param string[] $response 29 | * @param mixed[]|bool|DateTime|float|int|string|null $defaultValue 30 | */ 31 | public static function forError(array $response, mixed $defaultValue): ResolutionDetails 32 | { 33 | $responseCode = $response['code']; 34 | if ($responseCode && ResponseCodeErrorCodeMap::has($responseCode)) { 35 | /** 36 | * @var ErrorCode $responseErrorCode 37 | */ 38 | $responseErrorCode = ResponseCodeErrorCodeMap::get($responseCode); 39 | 40 | $resolutionError = new ResolutionError( 41 | $responseErrorCode, 42 | $response['message'] ?? (string) ErrorCode::GENERAL(), 43 | ); 44 | } else { 45 | $resolutionError = new ResolutionError(ErrorCode::GENERAL(), (string) ErrorCode::GENERAL()); 46 | } 47 | 48 | return (new ResolutionDetailsBuilder()) 49 | ->withValue($defaultValue) 50 | ->withError($resolutionError) 51 | ->build(); 52 | } 53 | 54 | /** 55 | * @param array{value: mixed[]|bool|DateTime|float|int|string|null, variant: ?string, reason: ?string} $response 56 | */ 57 | public static function forSuccess(array $response): ResolutionDetails 58 | { 59 | $builder = new ResolutionDetailsBuilder(); 60 | 61 | $builder->withValue($response['value']); 62 | 63 | if (isset($response['variant'])) { 64 | $builder->withVariant($response['variant']); 65 | } 66 | 67 | if (isset($response['reason'])) { 68 | $builder->withReason($response['reason']); 69 | } 70 | 71 | return $builder->build(); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /providers/CloudBees/examples/CloudBees/src/main.php: -------------------------------------------------------------------------------- 1 | setDevModeKey($devModeKey); 52 | 53 | if (isEnabled('ROLLOUT_LOGGING')) { 54 | $logFile = join(DIRECTORY_SEPARATOR, [ 55 | sys_get_temp_dir(), 56 | 'rollout', 57 | 'logs', 58 | 'demo.log' 59 | ]); 60 | 61 | LoggerFactory::setup((new MonologLoggerFactory()) 62 | ->setDefaultHandlers([ 63 | new StreamHandler($logFile, Logger::DEBUG) 64 | ])); 65 | } 66 | 67 | if (isEnabled('ROLLOUT_CACHE')) { 68 | $roxOptionsBuilder 69 | ->setCacheStorage(new DoctrineCacheStorage( 70 | new ChainCache([ 71 | new ArrayCache(), 72 | new FilesystemCache('/tmp/rollout/cache'), 73 | ]) 74 | )) 75 | ->setLogCacheHitsAndMisses(true) 76 | ->setConfigFetchIntervalInSeconds(30); 77 | } 78 | 79 | $provider = CloudBeesProvider::setup($apiKey, new RoxOptions($roxOptionsBuilder)); 80 | 81 | $api->setProvider($provider); 82 | 83 | // retrieve an OpenFeatureClient 84 | $client = $api->getClient('cloudbees-example', '1.0'); 85 | 86 | $flagValue = $client->getBooleanDetails('dev.openfeature.example_flag', true, null, null); 87 | 88 | // make sure to shutdown the CloudBees provider 89 | CloudBeesProvider::shutdown(); 90 | -------------------------------------------------------------------------------- /hooks/OpenTelemetry/README.md: -------------------------------------------------------------------------------- 1 | # OpenFeature OpenTelemetry Hook 2 | 3 | [![a](https://img.shields.io/badge/slack-%40cncf%2Fopenfeature-brightgreen?style=flat&logo=slack)](https://cloud-native.slack.com/archives/C0344AANLA1) 4 | [![Latest Stable Version](http://poser.pugx.org/open-feature/otel-hook/v)](https://packagist.org/packages/open-feature/otel-hook) 5 | [![Total Downloads](http://poser.pugx.org/open-feature/otel-hook/downloads)](https://packagist.org/packages/open-feature/otel-hook) 6 | ![PHP 8.0+](https://img.shields.io/badge/php->=8.0-blue.svg) 7 | [![License](http://poser.pugx.org/open-feature/otel-hook/license)](https://packagist.org/packages/open-feature/otel-hook) 8 | 9 | ## Overview 10 | 11 | OpenTelemetry is an open specification for distributed tracing, metrics, and logging. It defines a semantic convention for feature flagging which is utilized in this hook to report flag evaluations. 12 | 13 | This package also builds on various PSRs (PHP Standards Recommendations) such as the Logger interfaces (PSR-3) and the Basic and Extended Coding Standards (PSR-1 and PSR-12). 14 | 15 | ### Autoloading 16 | 17 | This package supports Composer autoloading. Thus, simply installing the package is all you need in order to immediately get started with OpenTracing for OpenFeature! Examples are provided that showcase the simple setup as well. Check out the Usage section for more info. 18 | 19 | ### OpenTelemetry Package Status 20 | 21 | The OpenTelemetry package for PHP is still in beta, so there could be changes required. However, it exposes global primitives for span retrieval that should not require any configuration upfront for the provider to just work. 22 | 23 | ## Installation 24 | 25 | ```sh 26 | composer require open-feature/otel-hook 27 | ``` 28 | 29 | ## Usage 30 | 31 | The `OpenTelemetryHook` should be registered to the OpenFeatureAPI globally for use across all evaluations. 32 | 33 | It makes use of the `open-telemetry/api` packages `Globals` utility for current span retrieval, thus has 34 | no dependency on configuration or injection of tracers. 35 | 36 | ```php 37 | use OpenFeature\Hooks\OpenTelemetry\OpenTelemetryHook; 38 | 39 | OpenTelemetryHook::register(); 40 | ``` 41 | 42 | For more information on OpenTelemetry, check out [their documentation](https://opentelemetry.io/docs/instrumentation/php/). 43 | 44 | For more examples, see the [examples](./examples/). 45 | 46 | ## Development 47 | 48 | ### PHP Versioning 49 | 50 | 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. 51 | 52 | This package also has a `.tool-versions` file for use with PHP version managers like `asdf`. 53 | 54 | ### Installation and Dependencies 55 | 56 | Install dependencies with `composer install`. `composer install` will update the `composer.lock` with the most recent compatible versions. 57 | 58 | We value having as few runtime dependencies as possible. The addition of any dependencies requires careful consideration and review. 59 | 60 | ### Testing 61 | 62 | Run tests with `composer run test`. 63 | -------------------------------------------------------------------------------- /hooks/DDTrace/README.md: -------------------------------------------------------------------------------- 1 | # OpenFeature DDTrace Hook 2 | 3 | [![a](https://img.shields.io/badge/slack-%40cncf%2Fopenfeature-brightgreen?style=flat&logo=slack)](https://cloud-native.slack.com/archives/C0344AANLA1) 4 | [![Latest Stable Version](http://poser.pugx.org/open-feature/dd-trace-hook/v)](https://packagist.org/packages/open-feature/dd-trace-hook) 5 | [![Total Downloads](http://poser.pugx.org/open-feature/dd-trace-hook/downloads)](https://packagist.org/packages/open-feature/dd-trace-hook) 6 | ![PHP 8.0+](https://img.shields.io/badge/php->=8.0-blue.svg) 7 | [![License](http://poser.pugx.org/open-feature/dd-trace-hook/license)](https://packagist.org/packages/open-feature/dd-trace-hook) 8 | 9 | ## Overview 10 | 11 | `dd-trace` is the Datadog tracing library for PHP. It is built on the OpenTracing specification. 12 | 13 | This package also builds on various PSRs (PHP Standards Recommendations) such as the Logger interfaces (PSR-3) and the Basic and Extended Coding Standards (PSR-1 and PSR-12). 14 | 15 | ### Design 16 | 17 | OpenTracing is now an archived project of the CNCF, with suggestions to move towards OpenTelemetry. Feel free to check out our [OpenTelemetry hook for OpenFeature](../OpenTelemetry/README.md) as well. OpenTelemetry defines a semantic convention for feature flagging which is utilized in this hook to report flag evaluations, which is the basis for the log events being performed in this library for `dd-trace`. 18 | 19 | ### Autoloading 20 | 21 | This package supports Composer autoloading. Thus, simply installing the package is all you need in order to immediately get started with Datadog's DDTrace for OpenFeature! Examples are provided that showcase the simple setup as well. Check out the **Usage** section for more info. 22 | 23 | ## Installation 24 | 25 | ```sh 26 | composer require open-feature/dd-trace-hook 27 | ``` 28 | 29 | ## Usage 30 | 31 | The `DDTraceHook` should be registered to the OpenFeatureAPI globally for use across all evaluations. 32 | 33 | It makes use of the `dd-trace` packages `Globals` utility for current span retrieval, thus has 34 | no dependency on configuration or injection of tracers. 35 | 36 | ```php 37 | use OpenFeature\Hooks\DDTrace\DDTraceHook; 38 | 39 | DDTraceHook::register(); 40 | ``` 41 | 42 | For more information on DDTrace, check out [their documentation](https://docs.datadoghq.com/tracing/trace_collection/dd_libraries/php?tab=containers). 43 | 44 | For more examples, see the [examples](./examples/). 45 | 46 | ## Development 47 | 48 | ### PHP Versioning 49 | 50 | 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. 51 | 52 | This package also has a `.tool-versions` file for use with PHP version managers like `asdf`. 53 | 54 | ### Installation and Dependencies 55 | 56 | Install dependencies with `composer install`. `composer install` will update the `composer.lock` with the most recent compatible versions. 57 | 58 | We value having as few runtime dependencies as possible. The addition of any dependencies requires careful consideration and review. 59 | 60 | ### Testing 61 | 62 | Run tests with `composer run test`. 63 | -------------------------------------------------------------------------------- /hooks/Validators/tests/unit/RegexpValidatorHookTest.php: -------------------------------------------------------------------------------- 1 | assertInstanceOf(Hook::class, $hook); 25 | } 26 | 27 | public function testCannotCreateInvalidRegexpForHook(): void 28 | { 29 | $this->expectException(InvalidRegularExpressionException::class); 30 | 31 | new RegexpValidatorHook('/[\\]/'); 32 | } 33 | 34 | public function testAlphanumericRegexpHookPasses(): void 35 | { 36 | $hook = new RegexpValidatorHook('/^[A-Za-z0-9]+$/'); 37 | 38 | $this->assertInstanceOf(Hook::class, $hook); 39 | 40 | $this->executeHook($hook, 'Abc123'); 41 | } 42 | 43 | public function testAlphanumericRegexpHookFails(): void 44 | { 45 | $hook = new RegexpValidatorHook('/^[A-Za-z0-9]+$/'); 46 | 47 | $this->assertInstanceOf(Hook::class, $hook); 48 | 49 | $this->expectException(ValidationException::class); 50 | 51 | $this->executeHook($hook, 'This, a sentence, has other invalid characters.'); 52 | } 53 | 54 | public function testHexadecimalRegexpHookPasses(): void 55 | { 56 | $hook = new RegexpValidatorHook('/^[0-9a-f]+$/'); 57 | 58 | $this->assertInstanceOf(Hook::class, $hook); 59 | 60 | $this->executeHook($hook, 'deadbeef007'); 61 | } 62 | 63 | public function testHexadecimalRegexpHookFails(): void 64 | { 65 | $hook = new RegexpValidatorHook('/^[0-9a-f]+$/'); 66 | 67 | $this->assertInstanceOf(Hook::class, $hook); 68 | 69 | $this->expectException(ValidationException::class); 70 | 71 | $this->executeHook($hook, '0123456789abcdefg'); 72 | } 73 | 74 | public function testAsciiRegexpHookPasses(): void 75 | { 76 | $hook = new RegexpValidatorHook('/^[ -~]+$/'); 77 | 78 | $this->assertInstanceOf(Hook::class, $hook); 79 | 80 | $this->executeHook($hook, 'Only ASCII characters get used here: See?'); 81 | } 82 | 83 | public function testAsciiRegexpHookFails(): void 84 | { 85 | $hook = new RegexpValidatorHook('/^[ -~]+$/'); 86 | 87 | $this->assertInstanceOf(Hook::class, $hook); 88 | 89 | $this->expectException(ValidationException::class); 90 | 91 | $this->executeHook($hook, '死'); 92 | } 93 | 94 | private function executeHook(Hook $hook, string $resolvedValue): void 95 | { 96 | $ctx = HookContextFactory::from( 97 | 'any-key', 98 | FlagValueType::STRING, 99 | 'default-value', 100 | null, 101 | new Metadata('client'), 102 | new Metadata('provider'), 103 | ); 104 | 105 | $details = ResolutionDetailsFactory::fromSuccess($resolvedValue); 106 | 107 | $nullHints = new HookHints(); 108 | 109 | $hook->after($ctx, $details, $nullHints); 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /providers/Flagd/proto/php/Schema/V1/ResolveIntRequest.php: -------------------------------------------------------------------------------- 1 | schema.v1.ResolveIntRequest 15 | */ 16 | class ResolveIntRequest extends \Google\Protobuf\Internal\Message 17 | { 18 | /** 19 | * Flag key of the requested flag. 20 | * 21 | * Generated from protobuf field string flag_key = 1 [json_name = "flagKey"]; 22 | */ 23 | protected $flag_key = ''; 24 | /** 25 | * Object structure describing the EvaluationContext used in the flag evaluation, see https://openfeature.dev/docs/reference/concepts/evaluation-context 26 | * 27 | * Generated from protobuf field .google.protobuf.Struct context = 2 [json_name = "context"]; 28 | */ 29 | protected $context = null; 30 | 31 | /** 32 | * Constructor. 33 | * 34 | * @param array $data { 35 | * Optional. Data for populating the Message object. 36 | * 37 | * @type string $flag_key 38 | * Flag key of the requested flag. 39 | * @type \Google\Protobuf\Struct $context 40 | * Object structure describing the EvaluationContext used in the flag evaluation, see https://openfeature.dev/docs/reference/concepts/evaluation-context 41 | * } 42 | */ 43 | public function __construct($data = NULL) { 44 | \GPBMetadata\Schema\V1\Schema::initOnce(); 45 | parent::__construct($data); 46 | } 47 | 48 | /** 49 | * Flag key of the requested flag. 50 | * 51 | * Generated from protobuf field string flag_key = 1 [json_name = "flagKey"]; 52 | * @return string 53 | */ 54 | public function getFlagKey() 55 | { 56 | return $this->flag_key; 57 | } 58 | 59 | /** 60 | * Flag key of the requested flag. 61 | * 62 | * Generated from protobuf field string flag_key = 1 [json_name = "flagKey"]; 63 | * @param string $var 64 | * @return $this 65 | */ 66 | public function setFlagKey($var) 67 | { 68 | GPBUtil::checkString($var, True); 69 | $this->flag_key = $var; 70 | 71 | return $this; 72 | } 73 | 74 | /** 75 | * Object structure describing the EvaluationContext used in the flag evaluation, see https://openfeature.dev/docs/reference/concepts/evaluation-context 76 | * 77 | * Generated from protobuf field .google.protobuf.Struct context = 2 [json_name = "context"]; 78 | * @return \Google\Protobuf\Struct|null 79 | */ 80 | public function getContext() 81 | { 82 | return $this->context; 83 | } 84 | 85 | public function hasContext() 86 | { 87 | return isset($this->context); 88 | } 89 | 90 | public function clearContext() 91 | { 92 | unset($this->context); 93 | } 94 | 95 | /** 96 | * Object structure describing the EvaluationContext used in the flag evaluation, see https://openfeature.dev/docs/reference/concepts/evaluation-context 97 | * 98 | * Generated from protobuf field .google.protobuf.Struct context = 2 [json_name = "context"]; 99 | * @param \Google\Protobuf\Struct $var 100 | * @return $this 101 | */ 102 | public function setContext($var) 103 | { 104 | GPBUtil::checkMessage($var, \Google\Protobuf\Struct::class); 105 | $this->context = $var; 106 | 107 | return $this; 108 | } 109 | 110 | } 111 | 112 | -------------------------------------------------------------------------------- /providers/Flagd/proto/php/Schema/V1/ResolveFloatRequest.php: -------------------------------------------------------------------------------- 1 | schema.v1.ResolveFloatRequest 15 | */ 16 | class ResolveFloatRequest extends \Google\Protobuf\Internal\Message 17 | { 18 | /** 19 | * Flag key of the requested flag. 20 | * 21 | * Generated from protobuf field string flag_key = 1 [json_name = "flagKey"]; 22 | */ 23 | protected $flag_key = ''; 24 | /** 25 | * Object structure describing the EvaluationContext used in the flag evaluation, see https://openfeature.dev/docs/reference/concepts/evaluation-context 26 | * 27 | * Generated from protobuf field .google.protobuf.Struct context = 2 [json_name = "context"]; 28 | */ 29 | protected $context = null; 30 | 31 | /** 32 | * Constructor. 33 | * 34 | * @param array $data { 35 | * Optional. Data for populating the Message object. 36 | * 37 | * @type string $flag_key 38 | * Flag key of the requested flag. 39 | * @type \Google\Protobuf\Struct $context 40 | * Object structure describing the EvaluationContext used in the flag evaluation, see https://openfeature.dev/docs/reference/concepts/evaluation-context 41 | * } 42 | */ 43 | public function __construct($data = NULL) { 44 | \GPBMetadata\Schema\V1\Schema::initOnce(); 45 | parent::__construct($data); 46 | } 47 | 48 | /** 49 | * Flag key of the requested flag. 50 | * 51 | * Generated from protobuf field string flag_key = 1 [json_name = "flagKey"]; 52 | * @return string 53 | */ 54 | public function getFlagKey() 55 | { 56 | return $this->flag_key; 57 | } 58 | 59 | /** 60 | * Flag key of the requested flag. 61 | * 62 | * Generated from protobuf field string flag_key = 1 [json_name = "flagKey"]; 63 | * @param string $var 64 | * @return $this 65 | */ 66 | public function setFlagKey($var) 67 | { 68 | GPBUtil::checkString($var, True); 69 | $this->flag_key = $var; 70 | 71 | return $this; 72 | } 73 | 74 | /** 75 | * Object structure describing the EvaluationContext used in the flag evaluation, see https://openfeature.dev/docs/reference/concepts/evaluation-context 76 | * 77 | * Generated from protobuf field .google.protobuf.Struct context = 2 [json_name = "context"]; 78 | * @return \Google\Protobuf\Struct|null 79 | */ 80 | public function getContext() 81 | { 82 | return $this->context; 83 | } 84 | 85 | public function hasContext() 86 | { 87 | return isset($this->context); 88 | } 89 | 90 | public function clearContext() 91 | { 92 | unset($this->context); 93 | } 94 | 95 | /** 96 | * Object structure describing the EvaluationContext used in the flag evaluation, see https://openfeature.dev/docs/reference/concepts/evaluation-context 97 | * 98 | * Generated from protobuf field .google.protobuf.Struct context = 2 [json_name = "context"]; 99 | * @param \Google\Protobuf\Struct $var 100 | * @return $this 101 | */ 102 | public function setContext($var) 103 | { 104 | GPBUtil::checkMessage($var, \Google\Protobuf\Struct::class); 105 | $this->context = $var; 106 | 107 | return $this; 108 | } 109 | 110 | } 111 | 112 | -------------------------------------------------------------------------------- /providers/Flagd/proto/php/Schema/V1/ResolveObjectRequest.php: -------------------------------------------------------------------------------- 1 | schema.v1.ResolveObjectRequest 15 | */ 16 | class ResolveObjectRequest extends \Google\Protobuf\Internal\Message 17 | { 18 | /** 19 | * Flag key of the requested flag. 20 | * 21 | * Generated from protobuf field string flag_key = 1 [json_name = "flagKey"]; 22 | */ 23 | protected $flag_key = ''; 24 | /** 25 | * Object structure describing the EvaluationContext used in the flag evaluation, see https://openfeature.dev/docs/reference/concepts/evaluation-context 26 | * 27 | * Generated from protobuf field .google.protobuf.Struct context = 2 [json_name = "context"]; 28 | */ 29 | protected $context = null; 30 | 31 | /** 32 | * Constructor. 33 | * 34 | * @param array $data { 35 | * Optional. Data for populating the Message object. 36 | * 37 | * @type string $flag_key 38 | * Flag key of the requested flag. 39 | * @type \Google\Protobuf\Struct $context 40 | * Object structure describing the EvaluationContext used in the flag evaluation, see https://openfeature.dev/docs/reference/concepts/evaluation-context 41 | * } 42 | */ 43 | public function __construct($data = NULL) { 44 | \GPBMetadata\Schema\V1\Schema::initOnce(); 45 | parent::__construct($data); 46 | } 47 | 48 | /** 49 | * Flag key of the requested flag. 50 | * 51 | * Generated from protobuf field string flag_key = 1 [json_name = "flagKey"]; 52 | * @return string 53 | */ 54 | public function getFlagKey() 55 | { 56 | return $this->flag_key; 57 | } 58 | 59 | /** 60 | * Flag key of the requested flag. 61 | * 62 | * Generated from protobuf field string flag_key = 1 [json_name = "flagKey"]; 63 | * @param string $var 64 | * @return $this 65 | */ 66 | public function setFlagKey($var) 67 | { 68 | GPBUtil::checkString($var, True); 69 | $this->flag_key = $var; 70 | 71 | return $this; 72 | } 73 | 74 | /** 75 | * Object structure describing the EvaluationContext used in the flag evaluation, see https://openfeature.dev/docs/reference/concepts/evaluation-context 76 | * 77 | * Generated from protobuf field .google.protobuf.Struct context = 2 [json_name = "context"]; 78 | * @return \Google\Protobuf\Struct|null 79 | */ 80 | public function getContext() 81 | { 82 | return $this->context; 83 | } 84 | 85 | public function hasContext() 86 | { 87 | return isset($this->context); 88 | } 89 | 90 | public function clearContext() 91 | { 92 | unset($this->context); 93 | } 94 | 95 | /** 96 | * Object structure describing the EvaluationContext used in the flag evaluation, see https://openfeature.dev/docs/reference/concepts/evaluation-context 97 | * 98 | * Generated from protobuf field .google.protobuf.Struct context = 2 [json_name = "context"]; 99 | * @param \Google\Protobuf\Struct $var 100 | * @return $this 101 | */ 102 | public function setContext($var) 103 | { 104 | GPBUtil::checkMessage($var, \Google\Protobuf\Struct::class); 105 | $this->context = $var; 106 | 107 | return $this; 108 | } 109 | 110 | } 111 | 112 | -------------------------------------------------------------------------------- /providers/Flagd/proto/php/Schema/V1/ResolveStringRequest.php: -------------------------------------------------------------------------------- 1 | schema.v1.ResolveStringRequest 15 | */ 16 | class ResolveStringRequest extends \Google\Protobuf\Internal\Message 17 | { 18 | /** 19 | * Flag key of the requested flag. 20 | * 21 | * Generated from protobuf field string flag_key = 1 [json_name = "flagKey"]; 22 | */ 23 | protected $flag_key = ''; 24 | /** 25 | * Object structure describing the EvaluationContext used in the flag evaluation, see https://openfeature.dev/docs/reference/concepts/evaluation-context 26 | * 27 | * Generated from protobuf field .google.protobuf.Struct context = 2 [json_name = "context"]; 28 | */ 29 | protected $context = null; 30 | 31 | /** 32 | * Constructor. 33 | * 34 | * @param array $data { 35 | * Optional. Data for populating the Message object. 36 | * 37 | * @type string $flag_key 38 | * Flag key of the requested flag. 39 | * @type \Google\Protobuf\Struct $context 40 | * Object structure describing the EvaluationContext used in the flag evaluation, see https://openfeature.dev/docs/reference/concepts/evaluation-context 41 | * } 42 | */ 43 | public function __construct($data = NULL) { 44 | \GPBMetadata\Schema\V1\Schema::initOnce(); 45 | parent::__construct($data); 46 | } 47 | 48 | /** 49 | * Flag key of the requested flag. 50 | * 51 | * Generated from protobuf field string flag_key = 1 [json_name = "flagKey"]; 52 | * @return string 53 | */ 54 | public function getFlagKey() 55 | { 56 | return $this->flag_key; 57 | } 58 | 59 | /** 60 | * Flag key of the requested flag. 61 | * 62 | * Generated from protobuf field string flag_key = 1 [json_name = "flagKey"]; 63 | * @param string $var 64 | * @return $this 65 | */ 66 | public function setFlagKey($var) 67 | { 68 | GPBUtil::checkString($var, True); 69 | $this->flag_key = $var; 70 | 71 | return $this; 72 | } 73 | 74 | /** 75 | * Object structure describing the EvaluationContext used in the flag evaluation, see https://openfeature.dev/docs/reference/concepts/evaluation-context 76 | * 77 | * Generated from protobuf field .google.protobuf.Struct context = 2 [json_name = "context"]; 78 | * @return \Google\Protobuf\Struct|null 79 | */ 80 | public function getContext() 81 | { 82 | return $this->context; 83 | } 84 | 85 | public function hasContext() 86 | { 87 | return isset($this->context); 88 | } 89 | 90 | public function clearContext() 91 | { 92 | unset($this->context); 93 | } 94 | 95 | /** 96 | * Object structure describing the EvaluationContext used in the flag evaluation, see https://openfeature.dev/docs/reference/concepts/evaluation-context 97 | * 98 | * Generated from protobuf field .google.protobuf.Struct context = 2 [json_name = "context"]; 99 | * @param \Google\Protobuf\Struct $var 100 | * @return $this 101 | */ 102 | public function setContext($var) 103 | { 104 | GPBUtil::checkMessage($var, \Google\Protobuf\Struct::class); 105 | $this->context = $var; 106 | 107 | return $this; 108 | } 109 | 110 | } 111 | 112 | -------------------------------------------------------------------------------- /providers/Flagd/proto/php/Schema/V1/ResolveBooleanRequest.php: -------------------------------------------------------------------------------- 1 | schema.v1.ResolveBooleanRequest 15 | */ 16 | class ResolveBooleanRequest extends \Google\Protobuf\Internal\Message 17 | { 18 | /** 19 | * Flag key of the requested flag. 20 | * 21 | * Generated from protobuf field string flag_key = 1 [json_name = "flagKey"]; 22 | */ 23 | protected $flag_key = ''; 24 | /** 25 | * Object structure describing the EvaluationContext used in the flag evaluation, see https://openfeature.dev/docs/reference/concepts/evaluation-context 26 | * 27 | * Generated from protobuf field .google.protobuf.Struct context = 2 [json_name = "context"]; 28 | */ 29 | protected $context = null; 30 | 31 | /** 32 | * Constructor. 33 | * 34 | * @param array $data { 35 | * Optional. Data for populating the Message object. 36 | * 37 | * @type string $flag_key 38 | * Flag key of the requested flag. 39 | * @type \Google\Protobuf\Struct $context 40 | * Object structure describing the EvaluationContext used in the flag evaluation, see https://openfeature.dev/docs/reference/concepts/evaluation-context 41 | * } 42 | */ 43 | public function __construct($data = NULL) { 44 | \GPBMetadata\Schema\V1\Schema::initOnce(); 45 | parent::__construct($data); 46 | } 47 | 48 | /** 49 | * Flag key of the requested flag. 50 | * 51 | * Generated from protobuf field string flag_key = 1 [json_name = "flagKey"]; 52 | * @return string 53 | */ 54 | public function getFlagKey() 55 | { 56 | return $this->flag_key; 57 | } 58 | 59 | /** 60 | * Flag key of the requested flag. 61 | * 62 | * Generated from protobuf field string flag_key = 1 [json_name = "flagKey"]; 63 | * @param string $var 64 | * @return $this 65 | */ 66 | public function setFlagKey($var) 67 | { 68 | GPBUtil::checkString($var, True); 69 | $this->flag_key = $var; 70 | 71 | return $this; 72 | } 73 | 74 | /** 75 | * Object structure describing the EvaluationContext used in the flag evaluation, see https://openfeature.dev/docs/reference/concepts/evaluation-context 76 | * 77 | * Generated from protobuf field .google.protobuf.Struct context = 2 [json_name = "context"]; 78 | * @return \Google\Protobuf\Struct|null 79 | */ 80 | public function getContext() 81 | { 82 | return $this->context; 83 | } 84 | 85 | public function hasContext() 86 | { 87 | return isset($this->context); 88 | } 89 | 90 | public function clearContext() 91 | { 92 | unset($this->context); 93 | } 94 | 95 | /** 96 | * Object structure describing the EvaluationContext used in the flag evaluation, see https://openfeature.dev/docs/reference/concepts/evaluation-context 97 | * 98 | * Generated from protobuf field .google.protobuf.Struct context = 2 [json_name = "context"]; 99 | * @param \Google\Protobuf\Struct $var 100 | * @return $this 101 | */ 102 | public function setContext($var) 103 | { 104 | GPBUtil::checkMessage($var, \Google\Protobuf\Struct::class); 105 | $this->context = $var; 106 | 107 | return $this; 108 | } 109 | 110 | } 111 | 112 | -------------------------------------------------------------------------------- /providers/CloudBees/README.md: -------------------------------------------------------------------------------- 1 | # OpenFeature CloudBees Provider for PHP 2 | 3 | [![a](https://img.shields.io/badge/slack-%40cncf%2Fopenfeature-brightgreen?style=flat&logo=slack)](https://cloud-native.slack.com/archives/C0344AANLA1) 4 | [![Latest Stable Version](http://poser.pugx.org/open-feature/cloudbees-provider/v)](https://packagist.org/packages/open-feature/cloudbees-provider) 5 | [![Total Downloads](http://poser.pugx.org/open-feature/cloudbees-provider/downloads)](https://packagist.org/packages/open-feature/cloudbees-provider) 6 | ![PHP 8.0+](https://img.shields.io/badge/php->=8.0-blue.svg) 7 | [![License](http://poser.pugx.org/open-feature/cloudbees-provider/license)](https://packagist.org/packages/open-feature/cloudbees-provider) 8 | 9 | ## Overview 10 | 11 | CloudBees Feature Management is designed to release, control, and measure features at scale. This repository and package provides the client side code for interacting with it via the OpenFeature PHP SDK. 12 | 13 | This package also builds on various PSRs (PHP Standards Recommendations) such as the Logger interfaces (PSR-3) and the Basic and Extended Coding Standards (PSR-1 and PSR-12). 14 | 15 | ### Limitations 16 | 17 | There is [an open issue](https://github.com/rollout/rox-php/issues/37) with object deserialization in the upstream library used for Rollout, CloudBees Feature Management SDK for PHP. Objects are also not first-class citizens of the feature management system, as in there is no direct "object" retrieval. Instead the OpenFeature provider builds upon the string retrieval with JSON as the expected format. This doesn't _really_ work though, due to the open issue above. Once that is resolved, JSON objects saved in CloudBees Feature Management system will simply be accessible. 18 | 19 | ## Installation 20 | 21 | ```sh 22 | composer require open-feature/cloudbees-provider 23 | ``` 24 | 25 | ## Usage 26 | 27 | The `CloudBeesProvider` can be created with the static `setup` method. This works in much the same way as the `Rox::setup` method, so you can refer to the Rollout documentation for PHP [here](https://docs.cloudbees.com/docs/cloudbees-feature-management/latest/getting-started/php-sdk) for more information. 28 | 29 | ```php 30 | // retrieve the OpenFeatureAPI instance 31 | $api = OpenFeatureAPI::getInstance(); 32 | 33 | // setup the CloudBeesProvider with the default settings 34 | $provider = CloudBeesProvider::setup($apiKey); 35 | 36 | // set the OpenFeature provider 37 | $api->setProvider($provider); 38 | 39 | // retrieve an OpenFeatureClient 40 | $client = $api->getClient('cloudbees-example', '1.0'); 41 | 42 | $flagValue = $client->getBooleanDetails('dev.openfeature.example_flag', true, null, null); 43 | 44 | // ... do work with the $flagValue 45 | 46 | // IMPORTANT! make sure to shutdown the CloudBees provider 47 | CloudBeesProvider::shutdown(); 48 | 49 | ``` 50 | 51 | ## Development 52 | 53 | ### PHP Versioning 54 | 55 | 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. 56 | 57 | This package also has a `.tool-versions` file for use with PHP version managers like `asdf`. 58 | 59 | ### Installation and Dependencies 60 | 61 | Install dependencies with `composer install`. `composer install` will update the `composer.lock` with the most recent compatible versions. 62 | 63 | We value having as few runtime dependencies as possible. The addition of any dependencies requires careful consideration and review. 64 | 65 | ### Testing 66 | 67 | Run tests with `composer run test`. 68 | 69 | #### Integration tests 70 | 71 | The integration test suite utilizes a locally available mock server for Rollout called Roxy. 72 | 73 | The docker image is published under `rollout/roxy`. 74 | 75 | For more information on Roxy, see [the documentation](https://docs.cloudbees.com/docs/cloudbees-feature-management/latest/debugging/microservices-automated-testing-and-local-development#_running_roxy). 76 | -------------------------------------------------------------------------------- /providers/Flagd/README.md: -------------------------------------------------------------------------------- 1 | # OpenFeature Flagd Provider for PHP 2 | 3 | [![a](https://img.shields.io/badge/slack-%40cncf%2Fopenfeature-brightgreen?style=flat&logo=slack)](https://cloud-native.slack.com/archives/C0344AANLA1) 4 | [![Latest Stable Version](http://poser.pugx.org/open-feature/flagd-provider/v)](https://packagist.org/packages/open-feature/flagd-provider) 5 | [![Total Downloads](http://poser.pugx.org/open-feature/flagd-provider/downloads)](https://packagist.org/packages/open-feature/flagd-provider) 6 | ![PHP 8.0+](https://img.shields.io/badge/php->=8.0-blue.svg) 7 | [![License](http://poser.pugx.org/open-feature/flagd-provider/license)](https://packagist.org/packages/open-feature/flagd-provider) 8 | 9 | ## Overview 10 | 11 | Flagd is a simple command line tool for fetching and presenting feature flags to services. It is designed to conform to OpenFeature schema for flag definitions. This repository and package provides the client side code for interacting with it via the OpenFeature PHP SDK. 12 | 13 | This package also builds on various PSRs (PHP Standards Recommendations) such as the Logger interfaces (PSR-3) and the Basic and Extended Coding Standards (PSR-1 and PSR-12). 14 | 15 | ## Installation 16 | 17 | ```sh 18 | composer require open-feature/flagd-provider 19 | ``` 20 | 21 | ## Usage 22 | 23 | The `FlagdProvider` client constructor takes a single optional argument with 3 fields, their default values correspond to the default arguments supplied to the flagd server: 24 | 25 | ```php 26 | /** @var \Psr\Http\Client\ClientInterface $client */ 27 | $client; 28 | 29 | /** @var Psr\Http\Message\RequestFactoryInterface $requestFactory */ 30 | $requestFactory; 31 | 32 | /** @var Psr\Http\Message\StreamFactoryInterface $streamFactory */ 33 | $streamFactory; 34 | 35 | OpenFeatureAPI::setProvider(new FlagdProvider([ 36 | 'protocol' => 'http', 37 | 'host' => 'localhost', 38 | 'port' => 8013, 39 | 'secure' => true, 40 | 'httpConfig' => [ 41 | 'client' => $client, 42 | 'requestFactory' => $requestFactory, 43 | 'streamFactory' => $streamFactory, 44 | ], 45 | ])); 46 | ``` 47 | 48 | - **protocol**: "http" _(defaults to http)_ 49 | - **host**: string _(defaults to "localhost")_ 50 | - **port**: number _(defaults to 8013)_ 51 | - **secure**: true | false _(defaults to false)_ 52 | - **httpConfig**: An array or `HttpConfig` object, providing implementations for PSR interfaces 53 | - **client**: a `ClientInterface` implementation 54 | - **requestFactory**: a `RequestFactoryInterface` implementation 55 | - **streamFactory**: a `StreamFactoryInterface` implementation 56 | 57 | ### gRPC vs HTTP 58 | 59 | The Flagd server is gRPC but offers gRPC Web endpoints that can be accessed over HTTP. The latter is used by the current implementation of the Flagd provider, with future development planned to implement a gRPC native provider option. There are certain flexibilities around HTTP with PHP available, whereas gRPC is an opinionated code-generation strategy, but they are both useful and gRPC native may provide better performance over certain sync/async scenarios. An additional goal will be to provide benchmarking of the Flagd provider's protocol for various scenarios so this decision can be made more easily by consumers of the provider. 60 | 61 | ## Development 62 | 63 | ### PHP Versioning 64 | 65 | This library targets PHP version and newer. As long as you have any compatible version of PHP on your system you should be able to utilize the OpenFeature SDK. 66 | 67 | This package also has a `.tool-versions` file for use with PHP version managers like `asdf`. 68 | 69 | ### Installation and Dependencies 70 | 71 | Install dependencies with `composer install`. `composer install` will update the `composer.lock` with the most recent compatible versions. 72 | 73 | We value having as few runtime dependencies as possible. The addition of any dependencies requires careful consideration and review. 74 | 75 | ### Testing 76 | 77 | Run tests with `composer run test`. 78 | -------------------------------------------------------------------------------- /providers/Flagd/proto/php/Schema/V1/ServiceClient.php: -------------------------------------------------------------------------------- 1 | _simpleRequest('/schema.v1.Service/ResolveBoolean', 29 | $argument, 30 | ['\Schema\V1\ResolveBooleanResponse', 'decode'], 31 | $metadata, $options); 32 | } 33 | 34 | /** 35 | * @param \Schema\V1\ResolveStringRequest $argument input argument 36 | * @param array $metadata metadata 37 | * @param array $options call options 38 | * @return \Grpc\UnaryCall 39 | */ 40 | public function ResolveString(\Schema\V1\ResolveStringRequest $argument, 41 | $metadata = [], $options = []) { 42 | return $this->_simpleRequest('/schema.v1.Service/ResolveString', 43 | $argument, 44 | ['\Schema\V1\ResolveStringResponse', 'decode'], 45 | $metadata, $options); 46 | } 47 | 48 | /** 49 | * @param \Schema\V1\ResolveFloatRequest $argument input argument 50 | * @param array $metadata metadata 51 | * @param array $options call options 52 | * @return \Grpc\UnaryCall 53 | */ 54 | public function ResolveFloat(\Schema\V1\ResolveFloatRequest $argument, 55 | $metadata = [], $options = []) { 56 | return $this->_simpleRequest('/schema.v1.Service/ResolveFloat', 57 | $argument, 58 | ['\Schema\V1\ResolveFloatResponse', 'decode'], 59 | $metadata, $options); 60 | } 61 | 62 | /** 63 | * @param \Schema\V1\ResolveIntRequest $argument input argument 64 | * @param array $metadata metadata 65 | * @param array $options call options 66 | * @return \Grpc\UnaryCall 67 | */ 68 | public function ResolveInt(\Schema\V1\ResolveIntRequest $argument, 69 | $metadata = [], $options = []) { 70 | return $this->_simpleRequest('/schema.v1.Service/ResolveInt', 71 | $argument, 72 | ['\Schema\V1\ResolveIntResponse', 'decode'], 73 | $metadata, $options); 74 | } 75 | 76 | /** 77 | * @param \Schema\V1\ResolveObjectRequest $argument input argument 78 | * @param array $metadata metadata 79 | * @param array $options call options 80 | * @return \Grpc\UnaryCall 81 | */ 82 | public function ResolveObject(\Schema\V1\ResolveObjectRequest $argument, 83 | $metadata = [], $options = []) { 84 | return $this->_simpleRequest('/schema.v1.Service/ResolveObject', 85 | $argument, 86 | ['\Schema\V1\ResolveObjectResponse', 'decode'], 87 | $metadata, $options); 88 | } 89 | 90 | /** 91 | * @param \Google\Protobuf\GPBEmpty $argument input argument 92 | * @param array $metadata metadata 93 | * @param array $options call options 94 | * @return \Grpc\ServerStreamingCall 95 | */ 96 | public function EventStream(\Google\Protobuf\GPBEmpty $argument, 97 | $metadata = [], $options = []) { 98 | return $this->_serverStreamRequest('/schema.v1.Service/EventStream', 99 | $argument, 100 | ['\Schema\V1\EventStreamResponse', 'decode'], 101 | $metadata, $options); 102 | } 103 | 104 | } 105 | -------------------------------------------------------------------------------- /hooks/OpenTelemetry/src/OpenTelemetryHook.php: -------------------------------------------------------------------------------- 1 | addHooks(self::$instance); 50 | self::$registeredHook = true; 51 | } 52 | 53 | private static ?OpenTelemetryHook $instance = null; 54 | private static bool $registeredHook = false; 55 | 56 | public function before(HookContext $context, HookHints $hints): ?EvaluationContext 57 | { 58 | return null; 59 | } 60 | 61 | public function after(HookContext $context, ResolutionDetails $details, HookHints $hints): void 62 | { 63 | $span = Span::getCurrent(); 64 | 65 | $span->addEvent(self::EVENT_NAME, [ 66 | self::FLAG_KEY => $context->getFlagKey(), 67 | self::FLAG_PROVIDER_NAME => OpenFeatureAPI::getInstance()->getProvider()->getMetadata()->getName(), 68 | self::FLAG_VARIANT => $details->getVariant(), 69 | ]); 70 | } 71 | 72 | public function error(HookContext $context, Throwable $error, HookHints $hints): void 73 | { 74 | $span = Span::getCurrent(); 75 | 76 | $span->recordException($error, [ 77 | self::FLAG_KEY => $context->getFlagKey(), 78 | self::FLAG_PROVIDER_NAME => OpenFeatureAPI::getInstance()->getProvider()->getMetadata()->getName(), 79 | ]); 80 | } 81 | 82 | public function finally(HookContext $context, HookHints $hints): void 83 | { 84 | // no-op 85 | } 86 | 87 | public function supportsFlagValueType(string $flagValueType): bool 88 | { 89 | return true; 90 | } 91 | 92 | /** 93 | * Hooks can be cleared by other means so we can't simply memoize whether a registration has occurred 94 | * 95 | * However if no registration has yet happened then we can absolutely determine that the hook will 96 | * not be registered yet. 97 | */ 98 | private static function isRegisteredInHooks(): bool 99 | { 100 | foreach (OpenFeatureAPI::getInstance()->getHooks() as $hook) { 101 | if ($hook instanceof OpenTelemetryHook) { 102 | return true; 103 | } 104 | } 105 | 106 | return false; 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /providers/Flagd/proto/php/Schema/V1/EventStreamResponse.php: -------------------------------------------------------------------------------- 1 | schema.v1.EventStreamResponse 15 | */ 16 | class EventStreamResponse extends \Google\Protobuf\Internal\Message 17 | { 18 | /** 19 | * String key indicating the type of event that is being received, e.g. provider_ready or configuration_change 20 | * 21 | * Generated from protobuf field string type = 1 [json_name = "type"]; 22 | */ 23 | protected $type = ''; 24 | /** 25 | * Object structure for use when sending relevant metadata to provide context to the event. 26 | * Can be left unset when it is not required. 27 | * 28 | * Generated from protobuf field .google.protobuf.Struct data = 2 [json_name = "data"]; 29 | */ 30 | protected $data = null; 31 | 32 | /** 33 | * Constructor. 34 | * 35 | * @param array $data { 36 | * Optional. Data for populating the Message object. 37 | * 38 | * @type string $type 39 | * String key indicating the type of event that is being received, e.g. provider_ready or configuration_change 40 | * @type \Google\Protobuf\Struct $data 41 | * Object structure for use when sending relevant metadata to provide context to the event. 42 | * Can be left unset when it is not required. 43 | * } 44 | */ 45 | public function __construct($data = NULL) { 46 | \GPBMetadata\Schema\V1\Schema::initOnce(); 47 | parent::__construct($data); 48 | } 49 | 50 | /** 51 | * String key indicating the type of event that is being received, e.g. provider_ready or configuration_change 52 | * 53 | * Generated from protobuf field string type = 1 [json_name = "type"]; 54 | * @return string 55 | */ 56 | public function getType() 57 | { 58 | return $this->type; 59 | } 60 | 61 | /** 62 | * String key indicating the type of event that is being received, e.g. provider_ready or configuration_change 63 | * 64 | * Generated from protobuf field string type = 1 [json_name = "type"]; 65 | * @param string $var 66 | * @return $this 67 | */ 68 | public function setType($var) 69 | { 70 | GPBUtil::checkString($var, True); 71 | $this->type = $var; 72 | 73 | return $this; 74 | } 75 | 76 | /** 77 | * Object structure for use when sending relevant metadata to provide context to the event. 78 | * Can be left unset when it is not required. 79 | * 80 | * Generated from protobuf field .google.protobuf.Struct data = 2 [json_name = "data"]; 81 | * @return \Google\Protobuf\Struct|null 82 | */ 83 | public function getData() 84 | { 85 | return $this->data; 86 | } 87 | 88 | public function hasData() 89 | { 90 | return isset($this->data); 91 | } 92 | 93 | public function clearData() 94 | { 95 | unset($this->data); 96 | } 97 | 98 | /** 99 | * Object structure for use when sending relevant metadata to provide context to the event. 100 | * Can be left unset when it is not required. 101 | * 102 | * Generated from protobuf field .google.protobuf.Struct data = 2 [json_name = "data"]; 103 | * @param \Google\Protobuf\Struct $var 104 | * @return $this 105 | */ 106 | public function setData($var) 107 | { 108 | GPBUtil::checkMessage($var, \Google\Protobuf\Struct::class); 109 | $this->data = $var; 110 | 111 | return $this; 112 | } 113 | 114 | } 115 | 116 | -------------------------------------------------------------------------------- /providers/CloudBees/tests/integration/CloudBeesProviderTest.php: -------------------------------------------------------------------------------- 1 | setRoxyURL('http://localhost:4444/')), 31 | ); 32 | 33 | $this->instance = $instance; 34 | } 35 | 36 | public function testCanBeInstantiated(): void 37 | { 38 | // Given 39 | $instance = $this->instance; 40 | 41 | // Then 42 | $this->assertNotNull($instance); 43 | $this->assertInstanceOf(CloudBeesProvider::class, $instance); 44 | $this->assertInstanceOf(Provider::class, $instance); 45 | } 46 | 47 | public function testCanResolveBool(): void 48 | { 49 | // Given 50 | $flagName = 'dev.openfeature.bool_flag'; 51 | $defaultValue = false; 52 | $expectedValue = true; 53 | 54 | // When 55 | $details = $this->instance->resolveBooleanValue($flagName, $defaultValue); 56 | $value = $details->getValue(); 57 | 58 | // Then 59 | $this->assertNotEquals($value, $defaultValue); 60 | $this->assertEquals($value, $expectedValue); 61 | } 62 | 63 | public function testCanResolveInt(): void 64 | { 65 | // Given 66 | $flagName = 'dev.openfeature.int_flag'; 67 | $defaultValue = 0; 68 | $expectedValue = 42; 69 | 70 | // When 71 | $details = $this->instance->resolveIntegerValue($flagName, $defaultValue); 72 | $value = $details->getValue(); 73 | 74 | // Then 75 | $this->assertNotEquals($value, $defaultValue); 76 | $this->assertEquals($value, $expectedValue); 77 | } 78 | 79 | public function testCanResolveFloat(): void 80 | { 81 | // Given 82 | $flagName = 'dev.openfeature.float_flag'; 83 | $defaultValue = 0.0; 84 | $expectedValue = 3.14; 85 | 86 | // When 87 | $details = $this->instance->resolveFloatValue($flagName, $defaultValue); 88 | $value = $details->getValue(); 89 | 90 | // Then 91 | $this->assertNotEquals($value, $defaultValue); 92 | $this->assertEquals($value, $expectedValue); 93 | } 94 | 95 | public function testCanResolveString(): void 96 | { 97 | // Given 98 | $flagName = 'dev.openfeature.string_flag'; 99 | $defaultValue = 'default'; 100 | $expectedValue = 'string-value'; 101 | 102 | // When 103 | $details = $this->instance->resolveStringValue($flagName, $defaultValue); 104 | $value = $details->getValue(); 105 | 106 | // Then 107 | $this->assertNotEquals($value, $defaultValue); 108 | $this->assertEquals($value, $expectedValue); 109 | } 110 | 111 | public function testCanResolveObject(): void 112 | { 113 | // Given 114 | $flagName = 'dev.openfeature.object_flag'; 115 | $defaultValue = ['anything' => 'at all']; 116 | $expectedValue = []; 117 | 118 | // When 119 | $details = $this->instance->resolveObjectValue($flagName, $defaultValue); 120 | $value = $details->getValue(); 121 | 122 | // Then 123 | $this->assertNotEquals($value, $defaultValue); 124 | $this->assertEquals($value, $expectedValue); 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /providers/Split/README.md: -------------------------------------------------------------------------------- 1 | # OpenFeature SplitIO Provider for PHP 2 | 3 | [![a](https://img.shields.io/badge/slack-%40cncf%2Fopenfeature-brightgreen?style=flat&logo=slack)](https://cloud-native.slack.com/archives/C0344AANLA1) 4 | [![Latest Stable Version](http://poser.pugx.org/open-feature/split-provider/v)](https://packagist.org/packages/open-feature/split-provider) 5 | [![Total Downloads](http://poser.pugx.org/open-feature/split-provider/downloads)](https://packagist.org/packages/open-feature/split-provider) 6 | ![PHP 8.0+](https://img.shields.io/badge/php->=8.0-blue.svg) 7 | [![License](http://poser.pugx.org/open-feature/split-provider/license)](https://packagist.org/packages/open-feature/split-provider) 8 | 9 | ## Overview 10 | 11 | Split is a feature delivery platform that powers feature flag management, software experimentation, and continuous delivery. This repository and package provides the client side code for interacting with it via the OpenFeature PHP SDK. 12 | 13 | This package also builds on various PSRs (PHP Standards Recommendations) such as the Logger interfaces (PSR-3) and the Basic and Extended Coding Standards (PSR-1 and PSR-12). 14 | 15 | ## Installation 16 | 17 | ```sh 18 | composer require open-feature/split-provider 19 | ``` 20 | 21 | ## Usage 22 | 23 | The `SplitProvider` client constructor takes a single optional argument with 3 fields, their default values correspond to the default arguments supplied to the flagd server: 24 | 25 | ```php 26 | $splitConfig = [ 27 | 'cache' => [ 28 | 'adapter' => 'predis', 29 | 'parameters' => [ 30 | 'scheme' => 'tcp', 31 | 'host' => getenv('REDIS_HOST'), 32 | 'port' => getenv('REDIS_PORT'), 33 | 'timeout' => 881, 34 | ], 35 | 'options' => [ 36 | 'prefix' => '', 37 | ], 38 | ], 39 | ]; 40 | 41 | $splitApiKey = getenv('SPLIT_API_KEY'); 42 | 43 | $provider = new SplitProvider($splitApiKey, $splitConfig); 44 | ``` 45 | 46 | For more information on the configuration options, please see the Split PHP SDK documentation on [Configuration](https://help.split.io/hc/en-us/articles/360020350372-PHP-SDK#configuration). 47 | 48 | Resolving values requires the use of the `EvaluationContext, where you can provide the `targetingKey` for the evaluation (the identifier which represents the user/account/etc.) 49 | 50 | ```php 51 | $client = $api->getClient('split-example', '1.0.0'); 52 | 53 | $featureEnabled = $client->getBooleanDetails('dev.openfeature.example_flag', false, new EvaluationContext('user-id'), null); 54 | 55 | if ($featureEnabled) { 56 | // do new logic here 57 | } else { 58 | // do old logic here 59 | } 60 | ``` 61 | 62 | You can provide more elaborate attributes to resolve values, but the values must conform to the requirements of the Split SDK. Information on what attributes are allowed can be found in the [Attributes section](https://help.split.io/hc/en-us/articles/360020350372-PHP-SDK#attribute-syntax) of the PHP SDK documentation. 63 | 64 | ```php 65 | $client = $api->getClient('split-example', '1.0.0'); 66 | 67 | $featureEnabled = $client->getBooleanDetails('dev.openfeature.example_flag', false, new EvaluationContext('user-id', [ 68 | 'plan_type' => 'growth', 69 | 'registered_date' => (new DateTime('now', new DateTimeZone('UTC')))->getTimestamp(), 70 | 'deal_size' => 10000, 71 | 'paying_customer' => True, 72 | 'permissions' => ['gold','silver','platinum'], 73 | ]), null); 74 | 75 | if ($featureEnabled) { 76 | // do new logic here 77 | } else { 78 | // do old logic here 79 | } 80 | ``` 81 | 82 | ## Development 83 | 84 | ### PHP Versioning 85 | 86 | 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. 87 | 88 | This package also has a `.tool-versions` file for use with PHP version managers like `asdf`. 89 | 90 | ### Installation and Dependencies 91 | 92 | Install dependencies with `composer install`. `composer install` will update the `composer.lock` with the most recent compatible versions. 93 | 94 | We value having as few runtime dependencies as possible. The addition of any dependencies requires careful consideration and review. 95 | 96 | ### Testing 97 | 98 | Run tests with `composer run test`. 99 | -------------------------------------------------------------------------------- /providers/Flagd/src/config/Validator.php: -------------------------------------------------------------------------------- 1 | getHost()); 55 | $port = self::validatePort($config->getPort()); 56 | $protocol = self::validateProtocol($config->getProtocol()); 57 | $secure = self::validateSecure($config->isSecure()); 58 | $httpConfig = self::validateHttpConfig($config->getHttpConfig()); 59 | 60 | return new Config($host, $port, $protocol, $secure, $httpConfig); 61 | } 62 | 63 | private static function validateSecure(mixed $secure): bool 64 | { 65 | if (is_bool($secure)) { 66 | return $secure; 67 | } 68 | 69 | return Defaults::DEFAULT_SECURE; 70 | } 71 | 72 | private static function validateHost(mixed $host): string 73 | { 74 | if (is_string($host) && preg_match(self::VALID_HOST_REGEXP, $host)) { 75 | return $host; 76 | } 77 | 78 | return Defaults::DEFAULT_HOST; 79 | } 80 | 81 | private static function validatePort(mixed $port): int 82 | { 83 | [$minPort, $maxPort] = self::VALID_PORT_RANGE; 84 | 85 | if (is_int($port) && $port >= $minPort && $port <= $maxPort) { 86 | return $port; 87 | } 88 | 89 | return Defaults::DEFAULT_PORT; 90 | } 91 | 92 | private static function validateProtocol(mixed $protocol): string 93 | { 94 | if (is_string($protocol) && in_array($protocol, self::VALID_PROTOCOLS)) { 95 | return $protocol; 96 | } 97 | 98 | return Defaults::DEFAULT_PROTOCOL; 99 | } 100 | 101 | private static function validateHttpConfig(mixed $httpConfig): ?IHttpConfig 102 | { 103 | if (is_null($httpConfig)) { 104 | return null; 105 | } 106 | 107 | if (is_array($httpConfig)) { 108 | /** @var ClientInterface|mixed $client */ 109 | $client = $httpConfig['client']; 110 | /** @var RequestFactoryInterface|mixed $requestFactory */ 111 | $requestFactory = $httpConfig['requestFactory']; 112 | /** @var StreamFactoryInterface|mixed $streamFactory */ 113 | $streamFactory = $httpConfig['streamFactory']; 114 | 115 | if ( 116 | $client instanceof ClientInterface 117 | && $requestFactory instanceof RequestFactoryInterface 118 | && $streamFactory instanceof StreamFactoryInterface 119 | ) { 120 | return new HttpConfig($client, $requestFactory, $streamFactory); 121 | } 122 | } 123 | 124 | if ($httpConfig instanceof IHttpConfig) { 125 | return $httpConfig; 126 | } 127 | 128 | return null; 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /providers/Flagd/proto/php/Schema/V1/ResolveIntResponse.php: -------------------------------------------------------------------------------- 1 | schema.v1.ResolveIntResponse 15 | */ 16 | class ResolveIntResponse extends \Google\Protobuf\Internal\Message 17 | { 18 | /** 19 | * The response value of the int flag evaluation, will be unset in the case of error. 20 | * 21 | * Generated from protobuf field int64 value = 1 [json_name = "value"]; 22 | */ 23 | protected $value = 0; 24 | /** 25 | * The reason for the given return value, see https://openfeature.dev/docs/specification/types#resolution-details 26 | * 27 | * Generated from protobuf field string reason = 2 [json_name = "reason"]; 28 | */ 29 | protected $reason = ''; 30 | /** 31 | * The variant name of the returned flag value. 32 | * 33 | * Generated from protobuf field string variant = 3 [json_name = "variant"]; 34 | */ 35 | protected $variant = ''; 36 | 37 | /** 38 | * Constructor. 39 | * 40 | * @param array $data { 41 | * Optional. Data for populating the Message object. 42 | * 43 | * @type int|string $value 44 | * The response value of the int flag evaluation, will be unset in the case of error. 45 | * @type string $reason 46 | * The reason for the given return value, see https://openfeature.dev/docs/specification/types#resolution-details 47 | * @type string $variant 48 | * The variant name of the returned flag value. 49 | * } 50 | */ 51 | public function __construct($data = NULL) { 52 | \GPBMetadata\Schema\V1\Schema::initOnce(); 53 | parent::__construct($data); 54 | } 55 | 56 | /** 57 | * The response value of the int flag evaluation, will be unset in the case of error. 58 | * 59 | * Generated from protobuf field int64 value = 1 [json_name = "value"]; 60 | * @return int|string 61 | */ 62 | public function getValue() 63 | { 64 | return $this->value; 65 | } 66 | 67 | /** 68 | * The response value of the int flag evaluation, will be unset in the case of error. 69 | * 70 | * Generated from protobuf field int64 value = 1 [json_name = "value"]; 71 | * @param int|string $var 72 | * @return $this 73 | */ 74 | public function setValue($var) 75 | { 76 | GPBUtil::checkInt64($var); 77 | $this->value = $var; 78 | 79 | return $this; 80 | } 81 | 82 | /** 83 | * The reason for the given return value, see https://openfeature.dev/docs/specification/types#resolution-details 84 | * 85 | * Generated from protobuf field string reason = 2 [json_name = "reason"]; 86 | * @return string 87 | */ 88 | public function getReason() 89 | { 90 | return $this->reason; 91 | } 92 | 93 | /** 94 | * The reason for the given return value, see https://openfeature.dev/docs/specification/types#resolution-details 95 | * 96 | * Generated from protobuf field string reason = 2 [json_name = "reason"]; 97 | * @param string $var 98 | * @return $this 99 | */ 100 | public function setReason($var) 101 | { 102 | GPBUtil::checkString($var, True); 103 | $this->reason = $var; 104 | 105 | return $this; 106 | } 107 | 108 | /** 109 | * The variant name of the returned flag value. 110 | * 111 | * Generated from protobuf field string variant = 3 [json_name = "variant"]; 112 | * @return string 113 | */ 114 | public function getVariant() 115 | { 116 | return $this->variant; 117 | } 118 | 119 | /** 120 | * The variant name of the returned flag value. 121 | * 122 | * Generated from protobuf field string variant = 3 [json_name = "variant"]; 123 | * @param string $var 124 | * @return $this 125 | */ 126 | public function setVariant($var) 127 | { 128 | GPBUtil::checkString($var, True); 129 | $this->variant = $var; 130 | 131 | return $this; 132 | } 133 | 134 | } 135 | 136 | -------------------------------------------------------------------------------- /providers/Flagd/proto/php/Schema/V1/ResolveFloatResponse.php: -------------------------------------------------------------------------------- 1 | schema.v1.ResolveFloatResponse 15 | */ 16 | class ResolveFloatResponse extends \Google\Protobuf\Internal\Message 17 | { 18 | /** 19 | * The response value of the float flag evaluation, will be empty in the case of error. 20 | * 21 | * Generated from protobuf field double value = 1 [json_name = "value"]; 22 | */ 23 | protected $value = 0.0; 24 | /** 25 | * The reason for the given return value, see https://openfeature.dev/docs/specification/types#resolution-details 26 | * 27 | * Generated from protobuf field string reason = 2 [json_name = "reason"]; 28 | */ 29 | protected $reason = ''; 30 | /** 31 | * The variant name of the returned flag value. 32 | * 33 | * Generated from protobuf field string variant = 3 [json_name = "variant"]; 34 | */ 35 | protected $variant = ''; 36 | 37 | /** 38 | * Constructor. 39 | * 40 | * @param array $data { 41 | * Optional. Data for populating the Message object. 42 | * 43 | * @type float $value 44 | * The response value of the float flag evaluation, will be empty in the case of error. 45 | * @type string $reason 46 | * The reason for the given return value, see https://openfeature.dev/docs/specification/types#resolution-details 47 | * @type string $variant 48 | * The variant name of the returned flag value. 49 | * } 50 | */ 51 | public function __construct($data = NULL) { 52 | \GPBMetadata\Schema\V1\Schema::initOnce(); 53 | parent::__construct($data); 54 | } 55 | 56 | /** 57 | * The response value of the float flag evaluation, will be empty in the case of error. 58 | * 59 | * Generated from protobuf field double value = 1 [json_name = "value"]; 60 | * @return float 61 | */ 62 | public function getValue() 63 | { 64 | return $this->value; 65 | } 66 | 67 | /** 68 | * The response value of the float flag evaluation, will be empty in the case of error. 69 | * 70 | * Generated from protobuf field double value = 1 [json_name = "value"]; 71 | * @param float $var 72 | * @return $this 73 | */ 74 | public function setValue($var) 75 | { 76 | GPBUtil::checkDouble($var); 77 | $this->value = $var; 78 | 79 | return $this; 80 | } 81 | 82 | /** 83 | * The reason for the given return value, see https://openfeature.dev/docs/specification/types#resolution-details 84 | * 85 | * Generated from protobuf field string reason = 2 [json_name = "reason"]; 86 | * @return string 87 | */ 88 | public function getReason() 89 | { 90 | return $this->reason; 91 | } 92 | 93 | /** 94 | * The reason for the given return value, see https://openfeature.dev/docs/specification/types#resolution-details 95 | * 96 | * Generated from protobuf field string reason = 2 [json_name = "reason"]; 97 | * @param string $var 98 | * @return $this 99 | */ 100 | public function setReason($var) 101 | { 102 | GPBUtil::checkString($var, True); 103 | $this->reason = $var; 104 | 105 | return $this; 106 | } 107 | 108 | /** 109 | * The variant name of the returned flag value. 110 | * 111 | * Generated from protobuf field string variant = 3 [json_name = "variant"]; 112 | * @return string 113 | */ 114 | public function getVariant() 115 | { 116 | return $this->variant; 117 | } 118 | 119 | /** 120 | * The variant name of the returned flag value. 121 | * 122 | * Generated from protobuf field string variant = 3 [json_name = "variant"]; 123 | * @param string $var 124 | * @return $this 125 | */ 126 | public function setVariant($var) 127 | { 128 | GPBUtil::checkString($var, True); 129 | $this->variant = $var; 130 | 131 | return $this; 132 | } 133 | 134 | } 135 | 136 | -------------------------------------------------------------------------------- /providers/Flagd/proto/php/Schema/V1/ResolveBooleanResponse.php: -------------------------------------------------------------------------------- 1 | schema.v1.ResolveBooleanResponse 15 | */ 16 | class ResolveBooleanResponse extends \Google\Protobuf\Internal\Message 17 | { 18 | /** 19 | * The response value of the boolean flag evaluation, will be unset in the case of error. 20 | * 21 | * Generated from protobuf field bool value = 1 [json_name = "value"]; 22 | */ 23 | protected $value = false; 24 | /** 25 | * The reason for the given return value, see https://openfeature.dev/docs/specification/types#resolution-details 26 | * 27 | * Generated from protobuf field string reason = 2 [json_name = "reason"]; 28 | */ 29 | protected $reason = ''; 30 | /** 31 | * The variant name of the returned flag value. 32 | * 33 | * Generated from protobuf field string variant = 3 [json_name = "variant"]; 34 | */ 35 | protected $variant = ''; 36 | 37 | /** 38 | * Constructor. 39 | * 40 | * @param array $data { 41 | * Optional. Data for populating the Message object. 42 | * 43 | * @type bool $value 44 | * The response value of the boolean flag evaluation, will be unset in the case of error. 45 | * @type string $reason 46 | * The reason for the given return value, see https://openfeature.dev/docs/specification/types#resolution-details 47 | * @type string $variant 48 | * The variant name of the returned flag value. 49 | * } 50 | */ 51 | public function __construct($data = NULL) { 52 | \GPBMetadata\Schema\V1\Schema::initOnce(); 53 | parent::__construct($data); 54 | } 55 | 56 | /** 57 | * The response value of the boolean flag evaluation, will be unset in the case of error. 58 | * 59 | * Generated from protobuf field bool value = 1 [json_name = "value"]; 60 | * @return bool 61 | */ 62 | public function getValue() 63 | { 64 | return $this->value; 65 | } 66 | 67 | /** 68 | * The response value of the boolean flag evaluation, will be unset in the case of error. 69 | * 70 | * Generated from protobuf field bool value = 1 [json_name = "value"]; 71 | * @param bool $var 72 | * @return $this 73 | */ 74 | public function setValue($var) 75 | { 76 | GPBUtil::checkBool($var); 77 | $this->value = $var; 78 | 79 | return $this; 80 | } 81 | 82 | /** 83 | * The reason for the given return value, see https://openfeature.dev/docs/specification/types#resolution-details 84 | * 85 | * Generated from protobuf field string reason = 2 [json_name = "reason"]; 86 | * @return string 87 | */ 88 | public function getReason() 89 | { 90 | return $this->reason; 91 | } 92 | 93 | /** 94 | * The reason for the given return value, see https://openfeature.dev/docs/specification/types#resolution-details 95 | * 96 | * Generated from protobuf field string reason = 2 [json_name = "reason"]; 97 | * @param string $var 98 | * @return $this 99 | */ 100 | public function setReason($var) 101 | { 102 | GPBUtil::checkString($var, True); 103 | $this->reason = $var; 104 | 105 | return $this; 106 | } 107 | 108 | /** 109 | * The variant name of the returned flag value. 110 | * 111 | * Generated from protobuf field string variant = 3 [json_name = "variant"]; 112 | * @return string 113 | */ 114 | public function getVariant() 115 | { 116 | return $this->variant; 117 | } 118 | 119 | /** 120 | * The variant name of the returned flag value. 121 | * 122 | * Generated from protobuf field string variant = 3 [json_name = "variant"]; 123 | * @param string $var 124 | * @return $this 125 | */ 126 | public function setVariant($var) 127 | { 128 | GPBUtil::checkString($var, True); 129 | $this->variant = $var; 130 | 131 | return $this; 132 | } 133 | 134 | } 135 | 136 | -------------------------------------------------------------------------------- /providers/Flagd/proto/php/Schema/V1/ResolveStringResponse.php: -------------------------------------------------------------------------------- 1 | schema.v1.ResolveStringResponse 15 | */ 16 | class ResolveStringResponse extends \Google\Protobuf\Internal\Message 17 | { 18 | /** 19 | * The response value of the string flag evaluation, will be unset in the case of error. 20 | * 21 | * Generated from protobuf field string value = 1 [json_name = "value"]; 22 | */ 23 | protected $value = ''; 24 | /** 25 | * The reason for the given return value, see https://openfeature.dev/docs/specification/types#resolution-details 26 | * 27 | * Generated from protobuf field string reason = 2 [json_name = "reason"]; 28 | */ 29 | protected $reason = ''; 30 | /** 31 | * The variant name of the returned flag value. 32 | * 33 | * Generated from protobuf field string variant = 3 [json_name = "variant"]; 34 | */ 35 | protected $variant = ''; 36 | 37 | /** 38 | * Constructor. 39 | * 40 | * @param array $data { 41 | * Optional. Data for populating the Message object. 42 | * 43 | * @type string $value 44 | * The response value of the string flag evaluation, will be unset in the case of error. 45 | * @type string $reason 46 | * The reason for the given return value, see https://openfeature.dev/docs/specification/types#resolution-details 47 | * @type string $variant 48 | * The variant name of the returned flag value. 49 | * } 50 | */ 51 | public function __construct($data = NULL) { 52 | \GPBMetadata\Schema\V1\Schema::initOnce(); 53 | parent::__construct($data); 54 | } 55 | 56 | /** 57 | * The response value of the string flag evaluation, will be unset in the case of error. 58 | * 59 | * Generated from protobuf field string value = 1 [json_name = "value"]; 60 | * @return string 61 | */ 62 | public function getValue() 63 | { 64 | return $this->value; 65 | } 66 | 67 | /** 68 | * The response value of the string flag evaluation, will be unset in the case of error. 69 | * 70 | * Generated from protobuf field string value = 1 [json_name = "value"]; 71 | * @param string $var 72 | * @return $this 73 | */ 74 | public function setValue($var) 75 | { 76 | GPBUtil::checkString($var, True); 77 | $this->value = $var; 78 | 79 | return $this; 80 | } 81 | 82 | /** 83 | * The reason for the given return value, see https://openfeature.dev/docs/specification/types#resolution-details 84 | * 85 | * Generated from protobuf field string reason = 2 [json_name = "reason"]; 86 | * @return string 87 | */ 88 | public function getReason() 89 | { 90 | return $this->reason; 91 | } 92 | 93 | /** 94 | * The reason for the given return value, see https://openfeature.dev/docs/specification/types#resolution-details 95 | * 96 | * Generated from protobuf field string reason = 2 [json_name = "reason"]; 97 | * @param string $var 98 | * @return $this 99 | */ 100 | public function setReason($var) 101 | { 102 | GPBUtil::checkString($var, True); 103 | $this->reason = $var; 104 | 105 | return $this; 106 | } 107 | 108 | /** 109 | * The variant name of the returned flag value. 110 | * 111 | * Generated from protobuf field string variant = 3 [json_name = "variant"]; 112 | * @return string 113 | */ 114 | public function getVariant() 115 | { 116 | return $this->variant; 117 | } 118 | 119 | /** 120 | * The variant name of the returned flag value. 121 | * 122 | * Generated from protobuf field string variant = 3 [json_name = "variant"]; 123 | * @param string $var 124 | * @return $this 125 | */ 126 | public function setVariant($var) 127 | { 128 | GPBUtil::checkString($var, True); 129 | $this->variant = $var; 130 | 131 | return $this; 132 | } 133 | 134 | } 135 | 136 | -------------------------------------------------------------------------------- /hooks/DDTrace/src/DDTraceHook.php: -------------------------------------------------------------------------------- 1 | addHooks(self::$instance); 55 | self::$registeredHook = true; 56 | } 57 | 58 | private static ?DDTraceHook $instance = null; 59 | private static bool $registeredHook = false; 60 | 61 | public function before(HookContext $context, HookHints $hints): ?EvaluationContext 62 | { 63 | return null; 64 | } 65 | 66 | public function after(HookContext $context, ResolutionDetails $details, HookHints $hints): void 67 | { 68 | $span = self::getCurrentSpan(); 69 | if (!$span) { 70 | return; 71 | } 72 | 73 | $span->log([ 74 | Tag::LOG_MESSAGE => [ 75 | self::FLAG_KEY => $context->getFlagKey(), 76 | self::FLAG_PROVIDER_NAME => OpenFeatureAPI::getInstance()->getProvider()->getMetadata()->getName(), 77 | self::FLAG_VARIANT => $details->getVariant(), 78 | ], 79 | ], new DateTimeImmutable('now')); 80 | } 81 | 82 | public function error(HookContext $context, Throwable $error, HookHints $hints): void 83 | { 84 | $span = self::getCurrentSpan(); 85 | if (!$span) { 86 | return; 87 | } 88 | 89 | $span->log([ 90 | Tag::LOG_ERROR_OBJECT => [ 91 | self::FLAG_KEY => $context->getFlagKey(), 92 | self::FLAG_PROVIDER_NAME => OpenFeatureAPI::getInstance()->getProvider()->getMetadata()->getName(), 93 | ], 94 | ], new DateTimeImmutable('now')); 95 | } 96 | 97 | public function finally(HookContext $context, HookHints $hints): void 98 | { 99 | // no-op 100 | } 101 | 102 | public function supportsFlagValueType(string $flagValueType): bool 103 | { 104 | return true; 105 | } 106 | 107 | /** 108 | * Hooks can be cleared by other means so we can't simply memoize whether a registration has occurred 109 | * 110 | * However if no registration has yet happened then we can absolutely determine that the hook will 111 | * not be registered yet. 112 | */ 113 | private static function isRegisteredInHooks(): bool 114 | { 115 | foreach (OpenFeatureAPI::getInstance()->getHooks() as $hook) { 116 | if ($hook instanceof DDTraceHook) { 117 | return true; 118 | } 119 | } 120 | 121 | return false; 122 | } 123 | 124 | private static function getCurrentSpan(): ?Span 125 | { 126 | if (!class_exists(GlobalTracer::class)) { 127 | return null; 128 | } 129 | 130 | return GlobalTracer::get()->getActiveSpan(); 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /devenv.lock: -------------------------------------------------------------------------------- 1 | { 2 | "nodes": { 3 | "devenv": { 4 | "locked": { 5 | "dir": "src/modules", 6 | "lastModified": 1675875772, 7 | "narHash": "sha256-sYXHPZ4tsjdG+UXK0mYnABhiS/RuzHiV9uGOU9YakwE=", 8 | "owner": "cachix", 9 | "repo": "devenv", 10 | "rev": "eac5eb12eb42765f5f252972dc876d1f96b03dfe", 11 | "type": "github" 12 | }, 13 | "original": { 14 | "dir": "src/modules", 15 | "owner": "cachix", 16 | "repo": "devenv", 17 | "type": "github" 18 | } 19 | }, 20 | "flake-compat": { 21 | "flake": false, 22 | "locked": { 23 | "lastModified": 1673956053, 24 | "narHash": "sha256-4gtG9iQuiKITOjNQQeQIpoIB6b16fm+504Ch3sNKLd8=", 25 | "owner": "edolstra", 26 | "repo": "flake-compat", 27 | "rev": "35bb57c0c8d8b62bbfd284272c928ceb64ddbde9", 28 | "type": "github" 29 | }, 30 | "original": { 31 | "owner": "edolstra", 32 | "repo": "flake-compat", 33 | "type": "github" 34 | } 35 | }, 36 | "flake-utils": { 37 | "locked": { 38 | "lastModified": 1667395993, 39 | "narHash": "sha256-nuEHfE/LcWyuSWnS8t12N1wc105Qtau+/OdUAjtQ0rA=", 40 | "owner": "numtide", 41 | "repo": "flake-utils", 42 | "rev": "5aed5285a952e0b949eb3ba02c12fa4fcfef535f", 43 | "type": "github" 44 | }, 45 | "original": { 46 | "owner": "numtide", 47 | "repo": "flake-utils", 48 | "type": "github" 49 | } 50 | }, 51 | "gitignore": { 52 | "inputs": { 53 | "nixpkgs": [ 54 | "pre-commit-hooks", 55 | "nixpkgs" 56 | ] 57 | }, 58 | "locked": { 59 | "lastModified": 1660459072, 60 | "narHash": "sha256-8DFJjXG8zqoONA1vXtgeKXy68KdJL5UaXR8NtVMUbx8=", 61 | "owner": "hercules-ci", 62 | "repo": "gitignore.nix", 63 | "rev": "a20de23b925fd8264fd7fad6454652e142fd7f73", 64 | "type": "github" 65 | }, 66 | "original": { 67 | "owner": "hercules-ci", 68 | "repo": "gitignore.nix", 69 | "type": "github" 70 | } 71 | }, 72 | "nixpkgs": { 73 | "locked": { 74 | "lastModified": 1675758091, 75 | "narHash": "sha256-7gFSQbSVAFUHtGCNHPF7mPc5CcqDk9M2+inlVPZSneg=", 76 | "owner": "NixOS", 77 | "repo": "nixpkgs", 78 | "rev": "747927516efcb5e31ba03b7ff32f61f6d47e7d87", 79 | "type": "github" 80 | }, 81 | "original": { 82 | "owner": "NixOS", 83 | "ref": "nixpkgs-unstable", 84 | "repo": "nixpkgs", 85 | "type": "github" 86 | } 87 | }, 88 | "nixpkgs-stable": { 89 | "locked": { 90 | "lastModified": 1673800717, 91 | "narHash": "sha256-SFHraUqLSu5cC6IxTprex/nTsI81ZQAtDvlBvGDWfnA=", 92 | "owner": "NixOS", 93 | "repo": "nixpkgs", 94 | "rev": "2f9fd351ec37f5d479556cd48be4ca340da59b8f", 95 | "type": "github" 96 | }, 97 | "original": { 98 | "owner": "NixOS", 99 | "ref": "nixos-22.11", 100 | "repo": "nixpkgs", 101 | "type": "github" 102 | } 103 | }, 104 | "nixpkgs_2": { 105 | "locked": { 106 | "lastModified": 1671271357, 107 | "narHash": "sha256-xRJdLbWK4v2SewmSStYrcLa0YGJpleufl44A19XSW8k=", 108 | "owner": "NixOS", 109 | "repo": "nixpkgs", 110 | "rev": "40f79f003b6377bd2f4ed4027dde1f8f922995dd", 111 | "type": "github" 112 | }, 113 | "original": { 114 | "owner": "NixOS", 115 | "ref": "nixos-unstable", 116 | "repo": "nixpkgs", 117 | "type": "github" 118 | } 119 | }, 120 | "pre-commit-hooks": { 121 | "inputs": { 122 | "flake-compat": "flake-compat", 123 | "flake-utils": "flake-utils", 124 | "gitignore": "gitignore", 125 | "nixpkgs": "nixpkgs_2", 126 | "nixpkgs-stable": "nixpkgs-stable" 127 | }, 128 | "locked": { 129 | "lastModified": 1675688762, 130 | "narHash": "sha256-oit/SxMk0B380ASuztBGQLe8TttO1GJiXF8aZY9AYEc=", 131 | "owner": "cachix", 132 | "repo": "pre-commit-hooks.nix", 133 | "rev": "ab608394886fb04b8a5df3cb0bab2598400e3634", 134 | "type": "github" 135 | }, 136 | "original": { 137 | "owner": "cachix", 138 | "repo": "pre-commit-hooks.nix", 139 | "type": "github" 140 | } 141 | }, 142 | "root": { 143 | "inputs": { 144 | "devenv": "devenv", 145 | "nixpkgs": "nixpkgs", 146 | "pre-commit-hooks": "pre-commit-hooks" 147 | } 148 | } 149 | }, 150 | "root": "root", 151 | "version": 7 152 | } 153 | -------------------------------------------------------------------------------- /providers/CloudBees/src/CloudBeesProvider.php: -------------------------------------------------------------------------------- 1 | resolve( 67 | $defaultValue, 68 | fn () => Rox::dynamicApi()->isEnabled($flagKey, $defaultValue, ContextAdapter::adapt($context)), 69 | ); 70 | } 71 | 72 | public function resolveStringValue(string $flagKey, string $defaultValue, ?EvaluationContext $context = null): ResolutionDetails 73 | { 74 | return $this->resolve( 75 | $defaultValue, 76 | fn () => Rox::dynamicApi()->getValue($flagKey, $defaultValue, [/* TODO: Variations */], ContextAdapter::adapt($context)), 77 | ); 78 | } 79 | 80 | public function resolveIntegerValue(string $flagKey, int $defaultValue, ?EvaluationContext $context = null): ResolutionDetails 81 | { 82 | return $this->resolve( 83 | $defaultValue, 84 | fn () => Rox::dynamicApi()->getInt($flagKey, $defaultValue, [/* TODO: Variations */], ContextAdapter::adapt($context)), 85 | ); 86 | } 87 | 88 | public function resolveFloatValue(string $flagKey, float $defaultValue, ?EvaluationContext $context = null): ResolutionDetails 89 | { 90 | return $this->resolve( 91 | $defaultValue, 92 | fn () => Rox::dynamicApi()->getDouble($flagKey, $defaultValue, [/* TODO: Variations */], ContextAdapter::adapt($context)), 93 | ); 94 | } 95 | 96 | /** 97 | * @param mixed[] $defaultValue 98 | */ 99 | public function resolveObjectValue(string $flagKey, array $defaultValue, ?EvaluationContext $context = null): ResolutionDetails 100 | { 101 | return $this->resolve( 102 | $defaultValue, 103 | fn () => Rox::dynamicApi()->getValue($flagKey, 'anything', [/* TODO: Variations */], ContextAdapter::adapt($context)), 104 | new JsonTransformer(), 105 | ); 106 | } 107 | 108 | /** 109 | * @param bool|string|int|float|mixed[] $defaultValue 110 | */ 111 | private function resolve(mixed $defaultValue, callable $fn, ?callable $transformer = null): ResolutionDetails 112 | { 113 | if (is_null($transformer)) { 114 | $transformer = new IdentityTransformer(); 115 | } 116 | 117 | try { 118 | /** 119 | * @var bool|string|int|float $value 120 | */ 121 | $value = call_user_func($fn); 122 | 123 | /** 124 | * @var bool|string|int|float|mixed[] $transformed 125 | */ 126 | $transformed = call_user_func($transformer, $value); 127 | 128 | return (new ResolutionDetailsBuilder()) 129 | ->withValue($transformed) 130 | ->build(); 131 | } catch (Throwable $err) { 132 | $detailsBuilder = new ResolutionDetailsBuilder(); 133 | 134 | $detailsBuilder->withValue($defaultValue); 135 | 136 | if ($err instanceof ThrowableWithResolutionError) { 137 | $detailsBuilder->withError($err->getResolutionError()); 138 | } else { 139 | $detailsBuilder->withError(new ResolutionError(ErrorCode::GENERAL(), $err->getMessage())); 140 | } 141 | 142 | return $detailsBuilder->build(); 143 | } 144 | } 145 | } 146 | -------------------------------------------------------------------------------- /hooks/Validators/composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "open-feature/validators-hook", 3 | "description": "A validator hooks package for OpenFeature", 4 | "license": "Apache-2.0", 5 | "type": "library", 6 | "keywords": [ 7 | "featureflags", 8 | "featureflagging", 9 | "openfeature", 10 | "validator", 11 | "hook" 12 | ], 13 | "authors": [ 14 | { 15 | "name": "OpenFeature PHP Maintainers", 16 | "homepage": "https://github.com/orgs/open-feature/teams/php-maintainer" 17 | }, 18 | { 19 | "name": "open-feature/php-sdk-contrib Contributors", 20 | "homepage": "https://github.com/open-feature/php-sdk-contrib/graphs/contributors" 21 | } 22 | ], 23 | "require": { 24 | "php": "^8", 25 | "open-feature/sdk": "^2.0" 26 | }, 27 | "require-dev": { 28 | "ergebnis/composer-normalize": "^2.25", 29 | "friendsofphp/php-cs-fixer": "^3.13", 30 | "hamcrest/hamcrest-php": "^2.0", 31 | "mdwheele/zalgo": "^0.3.1", 32 | "mikey179/vfsstream": "v1.6.11", 33 | "mockery/mockery": "^1.5", 34 | "phan/phan": "^5.4", 35 | "php-parallel-lint/php-console-highlighter": "^1.0", 36 | "php-parallel-lint/php-parallel-lint": "^1.3", 37 | "phpstan/extension-installer": "^1.1", 38 | "phpstan/phpstan": "~1.10.0", 39 | "phpstan/phpstan-mockery": "^1.0", 40 | "phpstan/phpstan-phpunit": "^1.1", 41 | "psalm/plugin-mockery": "^0.9.1", 42 | "psalm/plugin-phpunit": "^0.18.0", 43 | "ramsey/coding-standard": "^2.0.3", 44 | "ramsey/composer-repl": "^1.4", 45 | "ramsey/conventional-commits": "^1.3", 46 | "roave/security-advisories": "dev-latest", 47 | "spatie/phpunit-snapshot-assertions": "^4.2", 48 | "vimeo/psalm": "~4.30.0" 49 | }, 50 | "minimum-stability": "dev", 51 | "prefer-stable": true, 52 | "autoload": { 53 | "psr-4": { 54 | "OpenFeature\\Hooks\\Validators\\": "src" 55 | } 56 | }, 57 | "autoload-dev": { 58 | "psr-4": { 59 | "OpenFeature\\Hooks\\Validators\\Test\\": "tests" 60 | } 61 | }, 62 | "config": { 63 | "allow-plugins": { 64 | "phpstan/extension-installer": true, 65 | "dealerdirect/phpcodesniffer-composer-installer": true, 66 | "ergebnis/composer-normalize": true, 67 | "captainhook/plugin-composer": true, 68 | "ramsey/composer-repl": true 69 | }, 70 | "sort-packages": true 71 | }, 72 | "extra": { 73 | "captainhook": { 74 | "force-install": false 75 | } 76 | }, 77 | "scripts": { 78 | "dev:analyze": [ 79 | "@dev:analyze:phpstan", 80 | "@dev:analyze:psalm" 81 | ], 82 | "dev:analyze:phpstan": "phpstan analyse --ansi --debug --memory-limit=512M", 83 | "dev:analyze:psalm": "psalm", 84 | "dev:build:clean": "git clean -fX build/", 85 | "dev:lint": [ 86 | "@dev:lint:syntax", 87 | "@dev:lint:style" 88 | ], 89 | "dev:lint:fix": "phpcbf", 90 | "dev:lint:style": "phpcs --colors", 91 | "dev:lint:syntax": "parallel-lint --colors src/ tests/", 92 | "dev:test": [ 93 | "@dev:lint", 94 | "@dev:analyze", 95 | "@dev:test:unit", 96 | "@dev:test:integration" 97 | ], 98 | "dev:test:coverage:ci": "phpunit --colors=always --coverage-text --coverage-clover build/coverage/clover.xml --coverage-cobertura build/coverage/cobertura.xml --coverage-crap4j build/coverage/crap4j.xml --coverage-xml build/coverage/coverage-xml --log-junit build/junit.xml", 99 | "dev:test:coverage:html": "phpunit --colors=always --coverage-html build/coverage/coverage-html/", 100 | "dev:test:unit": [ 101 | "@dev:test:unit:setup", 102 | "phpunit --colors=always --testdox --testsuite=unit", 103 | "@dev:test:unit:teardown" 104 | ], 105 | "dev:test:unit:debug": "phpunit --colors=always --testdox -d xdebug.profiler_enable=on", 106 | "dev:test:unit:setup": "echo 'Setup for unit tests...'", 107 | "dev:test:unit:teardown": "echo 'Tore down for unit tests...'", 108 | "dev:test:integration": [ 109 | "@dev:test:integration:setup", 110 | "phpunit --colors=always --testdox --testsuite=integration", 111 | "@dev:test:integration:teardown" 112 | ], 113 | "dev:test:integration:debug": "phpunit --colors=always --testdox -d xdebug.profiler_enable=on", 114 | "dev:test:integration:setup": "echo 'Setup for integration tests...'", 115 | "dev:test:integration:teardown": "echo 'Tore down integration tests...'", 116 | "test": "@dev:test" 117 | }, 118 | "scripts-descriptions": { 119 | "dev:analyze": "Runs all static analysis checks.", 120 | "dev:analyze:phpstan": "Runs the PHPStan static analyzer.", 121 | "dev:analyze:psalm": "Runs the Psalm static analyzer.", 122 | "dev:build:clean": "Cleans the build/ directory.", 123 | "dev:lint": "Runs all linting checks.", 124 | "dev:lint:fix": "Auto-fixes coding standards issues, if possible.", 125 | "dev:lint:style": "Checks for coding standards issues.", 126 | "dev:lint:syntax": "Checks for syntax errors.", 127 | "dev:test": "Runs linting, static analysis, and unit tests.", 128 | "dev:test:coverage:ci": "Runs unit tests and generates CI coverage reports.", 129 | "dev:test:coverage:html": "Runs unit tests and generates HTML coverage report.", 130 | "dev:test:unit": "Runs unit tests.", 131 | "test": "Runs linting, static analysis, and unit tests." 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /providers/CloudBees/composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "open-feature/cloudbees-provider", 3 | "description": "The CloudBees provider package for OpenFeature", 4 | "license": "Apache-2.0", 5 | "type": "library", 6 | "keywords": [ 7 | "featureflags", 8 | "featureflagging", 9 | "openfeature", 10 | "cloudbees", 11 | "rox", 12 | "rollout", 13 | "provider" 14 | ], 15 | "authors": [ 16 | { 17 | "name": "OpenFeature PHP Maintainers", 18 | "homepage": "https://github.com/orgs/open-feature/teams/php-maintainer" 19 | }, 20 | { 21 | "name": "open-feature/php-sdk-contrib Contributors", 22 | "homepage": "https://github.com/open-feature/php-sdk-contrib/graphs/contributors" 23 | } 24 | ], 25 | "require": { 26 | "php": "^8", 27 | "open-feature/sdk": "^2.0", 28 | "rollout/rox": "^5.0" 29 | }, 30 | "require-dev": { 31 | "ergebnis/composer-normalize": "^2.25", 32 | "friendsofphp/php-cs-fixer": "^3.13", 33 | "hamcrest/hamcrest-php": "^2.0", 34 | "mdwheele/zalgo": "^0.3.1", 35 | "mockery/mockery": "^1.5", 36 | "phan/phan": "^5.4", 37 | "php-parallel-lint/php-console-highlighter": "^1.0", 38 | "php-parallel-lint/php-parallel-lint": "^1.3", 39 | "phpstan/extension-installer": "^1.1", 40 | "phpstan/phpstan": "~1.10.0", 41 | "phpstan/phpstan-mockery": "^1.0", 42 | "phpstan/phpstan-phpunit": "^1.1", 43 | "psalm/plugin-mockery": "^0.11.0", 44 | "psalm/plugin-phpunit": "^0.18.0", 45 | "ramsey/coding-standard": "^2.0.3", 46 | "ramsey/composer-repl": "^1.4", 47 | "ramsey/conventional-commits": "^1.3", 48 | "roave/security-advisories": "dev-latest", 49 | "spatie/phpunit-snapshot-assertions": "^4.2", 50 | "vimeo/psalm": "~4.30.0" 51 | }, 52 | "minimum-stability": "dev", 53 | "prefer-stable": true, 54 | "autoload": { 55 | "psr-4": { 56 | "OpenFeature\\Providers\\CloudBees\\": "src/" 57 | } 58 | }, 59 | "autoload-dev": { 60 | "psr-4": { 61 | "OpenFeature\\Providers\\CloudBees\\Test\\": "tests/" 62 | } 63 | }, 64 | "config": { 65 | "allow-plugins": { 66 | "phpstan/extension-installer": true, 67 | "dealerdirect/phpcodesniffer-composer-installer": true, 68 | "ergebnis/composer-normalize": true, 69 | "captainhook/plugin-composer": true, 70 | "ramsey/composer-repl": true 71 | }, 72 | "sort-packages": true 73 | }, 74 | "extra": { 75 | "captainhook": { 76 | "force-install": false 77 | } 78 | }, 79 | "scripts": { 80 | "dev:analyze": [ 81 | "@dev:analyze:phpstan", 82 | "@dev:analyze:psalm" 83 | ], 84 | "dev:analyze:phpstan": "phpstan analyse --ansi --debug --memory-limit=512M", 85 | "dev:analyze:psalm": "psalm", 86 | "dev:build:clean": "git clean -fX build/", 87 | "dev:lint": [ 88 | "@dev:lint:syntax", 89 | "@dev:lint:style" 90 | ], 91 | "dev:lint:fix": "phpcbf", 92 | "dev:lint:style": "phpcs --colors", 93 | "dev:lint:syntax": "parallel-lint --colors src/ tests/", 94 | "dev:test": [ 95 | "@dev:lint", 96 | "@dev:analyze", 97 | "@dev:test:unit", 98 | "@dev:test:integration" 99 | ], 100 | "dev:test:coverage:ci": "phpunit --colors=always --coverage-text --coverage-clover build/coverage/clover.xml --coverage-cobertura build/coverage/cobertura.xml --coverage-crap4j build/coverage/crap4j.xml --coverage-xml build/coverage/coverage-xml --log-junit build/junit.xml", 101 | "dev:test:coverage:html": "phpunit --colors=always --coverage-html build/coverage/coverage-html/", 102 | "dev:test:unit": "phpunit --colors=always --testdox tests/unit", 103 | "dev:test:unit:debug": "phpunit --colors=always --testdox -d xdebug.profiler_enable=on tests/unit", 104 | "dev:test:unit:setup": "echo 'Setup for unit tests...'", 105 | "dev:test:unit:teardown": "echo 'Tore down unit tests...'", 106 | "dev:test:integration": [ 107 | "@dev:test:integration:teardown", 108 | "@dev:test:integration:setup", 109 | "phpunit --colors=always --testdox tests/integration", 110 | "@dev:test:integration:teardown" 111 | ], 112 | "dev:test:integration:debug": "phpunit --colors=always --testdox -d xdebug.profiler_enable=on tests/integration", 113 | "dev:test:integration:setup": "python3 scripts/scaffold-integration-tests.py", 114 | "dev:test:integration:teardown": "python3 scripts/scaffold-integration-tests.py stop", 115 | "test": "@dev:test" 116 | }, 117 | "scripts-descriptions": { 118 | "dev:analyze": "Runs all static analysis checks.", 119 | "dev:analyze:phpstan": "Runs the PHPStan static analyzer.", 120 | "dev:analyze:psalm": "Runs the Psalm static analyzer.", 121 | "dev:build:clean": "Cleans the build/ directory.", 122 | "dev:lint": "Runs all linting checks.", 123 | "dev:lint:fix": "Auto-fixes coding standards issues, if possible.", 124 | "dev:lint:style": "Checks for coding standards issues.", 125 | "dev:lint:syntax": "Checks for syntax errors.", 126 | "dev:test": "Runs linting, static analysis, and unit tests.", 127 | "dev:test:coverage:ci": "Runs unit tests and generates CI coverage reports.", 128 | "dev:test:coverage:html": "Runs unit tests and generates HTML coverage report.", 129 | "dev:test:unit": "Runs unit tests.", 130 | "test": "Runs linting, static analysis, and unit tests." 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /providers/Split/composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "open-feature/split-provider", 3 | "description": "The Split provider package for OpenFeature", 4 | "license": "Apache-2.0", 5 | "type": "library", 6 | "keywords": [ 7 | "featureflags", 8 | "featureflagging", 9 | "openfeature", 10 | "split", 11 | "splitio", 12 | "provider" 13 | ], 14 | "authors": [ 15 | { 16 | "name": "OpenFeature PHP Maintainers", 17 | "homepage": "https://github.com/orgs/open-feature/teams/php-maintainer" 18 | }, 19 | { 20 | "name": "open-feature/php-sdk-contrib Contributors", 21 | "homepage": "https://github.com/open-feature/php-sdk-contrib/graphs/contributors" 22 | } 23 | ], 24 | "require": { 25 | "php": "^8", 26 | "open-feature/sdk": "^2.0", 27 | "splitsoftware/split-sdk-php": "^7.1" 28 | }, 29 | "require-dev": { 30 | "ergebnis/composer-normalize": "^2.25", 31 | "friendsofphp/php-cs-fixer": "^3.13", 32 | "hamcrest/hamcrest-php": "^2.0", 33 | "mdwheele/zalgo": "^0.3.1", 34 | "mikey179/vfsstream": "v1.6.11", 35 | "mockery/mockery": "^1.5", 36 | "phan/phan": "^5.4", 37 | "php-parallel-lint/php-console-highlighter": "^1.0", 38 | "php-parallel-lint/php-parallel-lint": "^1.3", 39 | "phpstan/extension-installer": "^1.1", 40 | "phpstan/phpstan": "~1.10.0", 41 | "phpstan/phpstan-mockery": "^1.0", 42 | "phpstan/phpstan-phpunit": "^1.1", 43 | "psalm/plugin-mockery": "^0.11.0", 44 | "psalm/plugin-phpunit": "^0.18.0", 45 | "ramsey/coding-standard": "^2.0.3", 46 | "ramsey/composer-repl": "^1.4", 47 | "ramsey/conventional-commits": "^1.3", 48 | "roave/security-advisories": "dev-latest", 49 | "spatie/phpunit-snapshot-assertions": "^4.2", 50 | "vimeo/psalm": "~4.30.0" 51 | }, 52 | "minimum-stability": "dev", 53 | "prefer-stable": true, 54 | "autoload": { 55 | "psr-4": { 56 | "OpenFeature\\Providers\\Split\\": "src/" 57 | } 58 | }, 59 | "autoload-dev": { 60 | "psr-4": { 61 | "OpenFeature\\Providers\\Split\\Test\\": "tests/" 62 | } 63 | }, 64 | "config": { 65 | "allow-plugins": { 66 | "phpstan/extension-installer": true, 67 | "dealerdirect/phpcodesniffer-composer-installer": true, 68 | "ergebnis/composer-normalize": true, 69 | "captainhook/plugin-composer": true, 70 | "ramsey/composer-repl": true 71 | }, 72 | "sort-packages": true 73 | }, 74 | "extra": { 75 | "captainhook": { 76 | "force-install": false 77 | } 78 | }, 79 | "scripts": { 80 | "dev:analyze": [ 81 | "@dev:analyze:phpstan", 82 | "@dev:analyze:psalm" 83 | ], 84 | "dev:analyze:phpstan": "phpstan analyse --ansi --debug --memory-limit=512M", 85 | "dev:analyze:psalm": "psalm", 86 | "dev:build:clean": "git clean -fX build/", 87 | "dev:lint": [ 88 | "@dev:lint:syntax", 89 | "@dev:lint:style" 90 | ], 91 | "dev:lint:fix": "phpcbf", 92 | "dev:lint:style": "phpcs --colors", 93 | "dev:lint:syntax": "parallel-lint --colors src/ tests/", 94 | "dev:test": [ 95 | "@dev:lint", 96 | "@dev:analyze", 97 | "@dev:test:unit", 98 | "@dev:test:integration" 99 | ], 100 | "dev:test:coverage:ci": "phpunit --colors=always --coverage-text --coverage-clover build/coverage/clover.xml --coverage-cobertura build/coverage/cobertura.xml --coverage-crap4j build/coverage/crap4j.xml --coverage-xml build/coverage/coverage-xml --log-junit build/junit.xml", 101 | "dev:test:coverage:html": "phpunit --colors=always --coverage-html build/coverage/coverage-html/", 102 | "dev:test:unit": [ 103 | "@dev:test:unit:setup", 104 | "phpunit --colors=always --testdox --testsuite=unit", 105 | "@dev:test:unit:teardown" 106 | ], 107 | "dev:test:unit:debug": "phpunit --colors=always --testdox -d xdebug.profiler_enable=on", 108 | "dev:test:unit:setup": "echo 'Setup for unit tests...'", 109 | "dev:test:unit:teardown": "echo 'Tore down for unit tests...'", 110 | "dev:test:integration": [ 111 | "@dev:test:integration:setup", 112 | "phpunit --colors=always --testdox --testsuite=integration", 113 | "@dev:test:integration:teardown" 114 | ], 115 | "dev:test:integration:debug": "phpunit --colors=always --testdox -d xdebug.profiler_enable=on", 116 | "dev:test:integration:setup": "echo 'Setup for integration tests...'", 117 | "dev:test:integration:teardown": "echo 'Tore down integration tests...'", 118 | "test": "@dev:test" 119 | }, 120 | "scripts-descriptions": { 121 | "dev:analyze": "Runs all static analysis checks.", 122 | "dev:analyze:phpstan": "Runs the PHPStan static analyzer.", 123 | "dev:analyze:psalm": "Runs the Psalm static analyzer.", 124 | "dev:build:clean": "Cleans the build/ directory.", 125 | "dev:lint": "Runs all linting checks.", 126 | "dev:lint:fix": "Auto-fixes coding standards issues, if possible.", 127 | "dev:lint:style": "Checks for coding standards issues.", 128 | "dev:lint:syntax": "Checks for syntax errors.", 129 | "dev:test": "Runs linting, static analysis, and unit tests.", 130 | "dev:test:coverage:ci": "Runs unit tests and generates CI coverage reports.", 131 | "dev:test:coverage:html": "Runs unit tests and generates HTML coverage report.", 132 | "dev:test:unit": "Runs unit tests.", 133 | "test": "Runs linting, static analysis, and unit tests." 134 | } 135 | } 136 | --------------------------------------------------------------------------------