From 146a236e1b217b00712f10bb29d1713376e6db10 Mon Sep 17 00:00:00 2001 From: Peter Csajtai Date: Wed, 15 Mar 2023 02:29:52 +0100 Subject: [PATCH] Bump to PHP 8.1 (#30) * Move to PHP 8.1 * Add getAllValueDetails() --- .github/workflows/php-ci.yml | 4 +- .github/workflows/snyk.yml | 2 +- .phpunit.result.cache | 1 + README.md | 5 + composer.json | 17 ++-- src/Attributes/Config.php | 4 +- src/Attributes/PercentageAttributes.php | 6 +- src/Attributes/Preferences.php | 4 +- src/Attributes/RolloutAttributes.php | 10 +- src/Attributes/SettingAttributes.php | 10 +- src/Cache/ArrayCache.php | 7 +- src/Cache/CacheItem.php | 16 ++-- src/Cache/ConfigCache.php | 5 +- src/Cache/LaravelCache.php | 8 +- src/Cache/Psr16Cache.php | 8 +- src/Cache/Psr6Cache.php | 7 +- src/ClientInterface.php | 40 +++++--- src/ClientOptions.php | 24 ++--- src/ConfigCatClient.php | 118 ++++++++++++++---------- src/ConfigCatClientException.php | 1 - src/ConfigFetcher.php | 45 ++++----- src/DataGovernance.php | 4 +- src/EvaluationDetails.php | 58 +++--------- src/EvaluationLogCollector.php | 7 +- src/EvaluationResult.php | 17 ++-- src/FetchResponse.php | 40 +++----- src/Hooks.php | 21 ++--- src/Log/InternalLogger.php | 41 ++------ src/Log/LogLevel.php | 18 ++-- src/Override/ArrayDataSource.php | 10 +- src/Override/FlagOverrides.php | 10 +- src/Override/LocalFileDataSource.php | 11 +-- src/Override/OverrideBehaviour.php | 10 +- src/Override/OverrideDataSource.php | 7 +- src/Pair.php | 12 +-- src/RefreshResult.php | 9 +- src/RolloutEvaluator.php | 16 ++-- src/SettingsResult.php | 9 +- src/User.php | 14 +-- src/Utils.php | 6 +- tests/ConfigCatClientTest.php | 13 +++ tests/ConfigFetcherTest.php | 6 +- 42 files changed, 297 insertions(+), 384 deletions(-) create mode 100644 .phpunit.result.cache diff --git a/.github/workflows/php-ci.yml b/.github/workflows/php-ci.yml index 13244a2..94cbe2f 100644 --- a/.github/workflows/php-ci.yml +++ b/.github/workflows/php-ci.yml @@ -15,7 +15,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - php-versions: [ '7.1', '7.2', '7.3', '7.4', '8.0', '8.1' ] + php-versions: [ '8.1', '8.2' ] steps: - uses: actions/checkout@v3 @@ -53,7 +53,7 @@ jobs: - name: Setup PHP uses: shivammathur/setup-php@v2 with: - php-version: '7.4' + php-version: '8.1' extensions: xdebug - name: Validate composer.json and composer.lock diff --git a/.github/workflows/snyk.yml b/.github/workflows/snyk.yml index 61ce6d7..9e3e31c 100644 --- a/.github/workflows/snyk.yml +++ b/.github/workflows/snyk.yml @@ -17,7 +17,7 @@ jobs: - name: Setup PHP uses: shivammathur/setup-php@v2 with: - php-version: '7.4' + php-version: '8.1' - name: Validate composer.json and composer.lock run: composer validate --strict diff --git a/.phpunit.result.cache b/.phpunit.result.cache new file mode 100644 index 0000000..927f8da --- /dev/null +++ b/.phpunit.result.cache @@ -0,0 +1 @@ +{"version":1,"defects":{"ConfigCat\\Tests\\ConfigCatClientTest::testConstructLoggerOption":6,"ConfigCat\\Tests\\ConfigCatClientTest::testConstructCacheOption":6,"ConfigCat\\Tests\\ConfigCatClientTest::testConstructCacheRefreshIntervalOption":6,"ConfigCat\\Tests\\ConfigCatClientTest::testGetValueFailedFetch":4,"ConfigCat\\Tests\\ConfigCatClientTest::testGetAllKeysFailedFetch":4,"ConfigCat\\Tests\\ConfigCatClientTest::testForceRefresh":4,"ConfigCat\\Tests\\ConfigCatClientTest::testKeyNotExist":4,"ConfigCat\\Tests\\ConfigCatClientTest::testGetVariationId":4,"ConfigCat\\Tests\\ConfigCatClientTest::testGetVariationIdDefault":4,"ConfigCat\\Tests\\ConfigCatClientTest::testGetAllVariationIds":4,"ConfigCat\\Tests\\ConfigCatClientTest::testGetAllVariationIdsEmpty":4,"ConfigCat\\Tests\\ConfigCatClientTest::testGetKeyAndValue":4,"ConfigCat\\Tests\\ConfigCatClientTest::testGetKeyAndValueNull":4,"ConfigCat\\Tests\\ConfigCatClientTest::testGetAllValues":4,"ConfigCat\\Tests\\ConfigCatClientTest::testDefaultUser":4,"ConfigCat\\Tests\\ConfigCatClientTest::testInitDefaultUser":4,"ConfigCat\\Tests\\ConfigCatClientTest::testDefaultUserVariationId":4,"ConfigCat\\Tests\\ConfigCatClientTest::testOfflineOnline":4,"ConfigCat\\Tests\\ConfigCatClientTest::testInitOfflineOnline":4,"ConfigCat\\Tests\\ConfigCatClientTest::testHooks":4,"ConfigCat\\Tests\\ConfigCatClientTest::testEvalDetails":4,"ConfigCat\\Tests\\ConfigCatClientTest::testEvalDetailsHook":4,"ConfigCat\\Tests\\ConfigCatClientTest::testTimeout":4,"ConfigCat\\Tests\\ConfigCatClientTest::testHttpException":4,"ConfigCat\\Tests\\ConfigCatClientTest::testGeneralException":4,"ConfigCat\\Tests\\DataGovernanceTest::testShouldStayOnServer":6,"ConfigCat\\Tests\\DataGovernanceTest::testShouldStayOnSameUrlWithRedirect":6,"ConfigCat\\Tests\\DataGovernanceTest::testShouldStayOnSameUrlEvenWhenForced":6,"ConfigCat\\Tests\\DataGovernanceTest::testShouldRedirectToAnotherServer":6,"ConfigCat\\Tests\\DataGovernanceTest::testShouldRedirectToAnotherServerWhenForced":6,"ConfigCat\\Tests\\DataGovernanceTest::testShouldRedirectToAnotherServerWhenWrongIsCached":6,"ConfigCat\\Tests\\DataGovernanceTest::testShouldBreakRedirectLoop":6,"ConfigCat\\Tests\\DataGovernanceTest::testShouldBreakRedirectLoopWhenForced":6,"ConfigCat\\Tests\\DataGovernanceTest::testShouldRespectCustomUrlWhenNotForced":6,"ConfigCat\\Tests\\DataGovernanceTest::testShouldNotRespectCustomUrlWhenForced":6,"ConfigCat\\Tests\\LocalSourceTest::testWithFile":4,"ConfigCat\\Tests\\LocalSourceTest::testWithFile_Rules":4,"ConfigCat\\Tests\\LocalSourceTest::testWithSimpleFile":4,"ConfigCat\\Tests\\LocalSourceTest::testWithArraySource":4,"ConfigCat\\Tests\\LocalSourceTest::testLocalOverRemote":4,"ConfigCat\\Tests\\LocalSourceTest::testRemoteOverLocal":4,"ConfigCat\\Tests\\LocalSourceTest::testLocalOnlyIgnoresFetched":4,"ConfigCat\\Tests\\LoggerTest::testClientNoLog":4,"ConfigCat\\Tests\\RolloutIntegrationsTest::testRolloutIntegration with data set #0":4,"ConfigCat\\Tests\\RolloutIntegrationsTest::testRolloutIntegration with data set #1":4,"ConfigCat\\Tests\\RolloutIntegrationsTest::testRolloutIntegration with data set #2":4,"ConfigCat\\Tests\\RolloutIntegrationsTest::testRolloutIntegration with data set #3":4,"ConfigCat\\Tests\\RolloutIntegrationsTest::testRolloutIntegration with data set #4":4,"ConfigCat\\Tests\\RolloutIntegrationsTest::testRolloutIntegration with data set #5":4},"times":{"ConfigCat\\Tests\\ConfigCatClientTest::testConstructEmptySdkKey":0.003,"ConfigCat\\Tests\\ConfigCatClientTest::testConstructDefaults":0.009,"ConfigCat\\Tests\\ConfigCatClientTest::testConstructLoggerOption":0.001,"ConfigCat\\Tests\\ConfigCatClientTest::testConstructCacheOption":0,"ConfigCat\\Tests\\ConfigCatClientTest::testConstructCacheRefreshIntervalOption":0,"ConfigCat\\Tests\\ConfigCatClientTest::testGetValueFailedFetch":0.006,"ConfigCat\\Tests\\ConfigCatClientTest::testGetAllKeysFailedFetch":0.001,"ConfigCat\\Tests\\ConfigCatClientTest::testForceRefresh":0.097,"ConfigCat\\Tests\\ConfigCatClientTest::testKeyNotExist":0.08,"ConfigCat\\Tests\\ConfigCatClientTest::testGetVariationId":0.001,"ConfigCat\\Tests\\ConfigCatClientTest::testGetVariationIdDefault":0,"ConfigCat\\Tests\\ConfigCatClientTest::testGetAllVariationIds":0,"ConfigCat\\Tests\\ConfigCatClientTest::testGetAllVariationIdsEmpty":0,"ConfigCat\\Tests\\ConfigCatClientTest::testGetKeyAndValue":0.001,"ConfigCat\\Tests\\ConfigCatClientTest::testGetKeyAndValueNull":0,"ConfigCat\\Tests\\ConfigCatClientTest::testGetAllValues":0,"ConfigCat\\Tests\\ConfigCatClientTest::testDefaultUser":0.001,"ConfigCat\\Tests\\ConfigCatClientTest::testInitDefaultUser":0,"ConfigCat\\Tests\\ConfigCatClientTest::testDefaultUserVariationId":0,"ConfigCat\\Tests\\ConfigCatClientTest::testOfflineOnline":0.001,"ConfigCat\\Tests\\ConfigCatClientTest::testInitOfflineOnline":0,"ConfigCat\\Tests\\ConfigCatClientTest::testHooks":0.001,"ConfigCat\\Tests\\ConfigCatClientTest::testEvalDetails":0,"ConfigCat\\Tests\\ConfigCatClientTest::testEvalDetailsHook":0,"ConfigCat\\Tests\\ConfigCatClientTest::testTimeout":0.001,"ConfigCat\\Tests\\ConfigCatClientTest::testHttpException":0.001,"ConfigCat\\Tests\\ConfigCatClientTest::testGeneralException":0,"ConfigCat\\Tests\\ConfigFetcherTest::testFetchOk":0,"ConfigCat\\Tests\\ConfigFetcherTest::testFetchNotModified":0,"ConfigCat\\Tests\\ConfigFetcherTest::testFetchFailed":0.001,"ConfigCat\\Tests\\ConfigFetcherTest::testFetchInvalidJson":0,"ConfigCat\\Tests\\ConfigFetcherTest::testConstructEmptySdkKey":0,"ConfigCat\\Tests\\ConfigFetcherTest::testConstructDefaults":0,"ConfigCat\\Tests\\ConfigFetcherTest::testConstructConnectTimeoutOption":0,"ConfigCat\\Tests\\ConfigFetcherTest::testConstructRequestTimeoutOption":0,"ConfigCat\\Tests\\ConfigFetcherTest::testTimeoutException":0,"ConfigCat\\Tests\\ConfigFetcherTest::testIntegration":0.108,"ConfigCat\\Tests\\DataGovernanceTest::testShouldStayOnServer":0.001,"ConfigCat\\Tests\\DataGovernanceTest::testShouldStayOnSameUrlWithRedirect":0,"ConfigCat\\Tests\\DataGovernanceTest::testShouldStayOnSameUrlEvenWhenForced":0,"ConfigCat\\Tests\\DataGovernanceTest::testShouldRedirectToAnotherServer":0.001,"ConfigCat\\Tests\\DataGovernanceTest::testShouldRedirectToAnotherServerWhenForced":0.001,"ConfigCat\\Tests\\DataGovernanceTest::testShouldRedirectToAnotherServerWhenWrongIsCached":0.001,"ConfigCat\\Tests\\DataGovernanceTest::testShouldBreakRedirectLoop":0.001,"ConfigCat\\Tests\\DataGovernanceTest::testShouldBreakRedirectLoopWhenForced":0.001,"ConfigCat\\Tests\\DataGovernanceTest::testShouldRespectCustomUrlWhenNotForced":0,"ConfigCat\\Tests\\DataGovernanceTest::testShouldNotRespectCustomUrlWhenForced":0.001,"ConfigCat\\Tests\\LocalSourceTest::testWithNonExistingFile":0.001,"ConfigCat\\Tests\\LocalSourceTest::testWithInvalidBehavior":0,"ConfigCat\\Tests\\LocalSourceTest::testWithFile":0,"ConfigCat\\Tests\\LocalSourceTest::testWithFile_Rules":0,"ConfigCat\\Tests\\LocalSourceTest::testWithSimpleFile":0,"ConfigCat\\Tests\\LocalSourceTest::testWithArraySource":0,"ConfigCat\\Tests\\LocalSourceTest::testLocalOverRemote":0,"ConfigCat\\Tests\\LocalSourceTest::testRemoteOverLocal":0,"ConfigCat\\Tests\\LocalSourceTest::testLocalOnlyIgnoresFetched":0,"ConfigCat\\Tests\\LoggerTest::testLoggerBypassesInternalLogicWhenGlobalLevelIsZero":0.001,"ConfigCat\\Tests\\LoggerTest::testLoggerLogOnlyHigherLevelThanDebug":0.001,"ConfigCat\\Tests\\LoggerTest::testLoggerLogOnlyHigherLevelThanInfo":0.001,"ConfigCat\\Tests\\LoggerTest::testLoggerLogOnlyHigherLevelThanNotice":0,"ConfigCat\\Tests\\LoggerTest::testLoggerLogOnlyHigherLevelThanWarning":0,"ConfigCat\\Tests\\LoggerTest::testLoggerLogOnlyHigherLevelThanError":0,"ConfigCat\\Tests\\LoggerTest::testLoggerLogOnlyHigherLevelThanCritical":0,"ConfigCat\\Tests\\LoggerTest::testLoggerLogOnlyHigherLevelThanAlert":0,"ConfigCat\\Tests\\LoggerTest::testLoggerNoLog":0,"ConfigCat\\Tests\\LoggerTest::testClientNoLog":0.064,"ConfigCat\\Tests\\LoggerTest::testLoggerBypassesLogWhenExceptionIsIgnored":0.001,"ConfigCat\\Tests\\RolloutIntegrationsTest::testRolloutIntegration with data set #0":0.722,"ConfigCat\\Tests\\RolloutIntegrationsTest::testRolloutIntegration with data set #1":0.112,"ConfigCat\\Tests\\RolloutIntegrationsTest::testRolloutIntegration with data set #2":0.078,"ConfigCat\\Tests\\RolloutIntegrationsTest::testRolloutIntegration with data set #3":0.172,"ConfigCat\\Tests\\RolloutIntegrationsTest::testRolloutIntegration with data set #4":0.074,"ConfigCat\\Tests\\RolloutIntegrationsTest::testRolloutIntegration with data set #5":0.075,"ConfigCat\\Tests\\UserTest::testConstructEmptyIdentifier":0,"ConfigCat\\Tests\\UserTest::testGetAttributeEmptyKey":0}} \ No newline at end of file diff --git a/README.md b/README.md index bf24fb9..dd4f3c5 100644 --- a/README.md +++ b/README.md @@ -13,6 +13,11 @@ ConfigCat is a hosted feature fl [![Total Downloads](https://poser.pugx.org/configcat/configcat-client/downloads)](https://packagist.org/packages/configcat/configcat-client) [![Latest Unstable Version](https://poser.pugx.org/configcat/configcat-client/v/unstable)](https://packagist.org/packages/configcat/configcat-client) +## Requirements +- PHP >= 8.1 + +ConfigCat SDK for PHP >= 7.1 is available [here](https://github.com/configcat/php7-sdk). + ## Getting started ### 1. Install the package with [Composer](https://getcomposer.org/) diff --git a/composer.json b/composer.json index 4f2727e..fb6154d 100644 --- a/composer.json +++ b/composer.json @@ -13,19 +13,19 @@ } ], "require": { - "php": ">=7.1", + "php": ">=8.1", "guzzlehttp/guzzle": "^6.3|^7.0", - "psr/log": "^1.1", + "psr/log": "^2.0|^3.0", "ext-json": "*", - "monolog/monolog": "^1.6|^2.0", + "monolog/monolog": "2.0|^3.0", "z4kn4fein/php-semver": "^2.0" }, "require-dev": { "phpunit/phpunit": "~7.0|^8", - "illuminate/cache": "^5.0", - "psr/simple-cache": "^1.0", + "illuminate/cache": "^9.0", + "psr/simple-cache": "^3.0", "psr/cache": "^1.0", - "squizlabs/php_codesniffer": "3.5.1" + "squizlabs/php_codesniffer": "^3.7" }, "autoload": { "psr-4": { @@ -41,5 +41,10 @@ "psr/cache": "When using any PSR6 Cache implementation, a pre-built cache adapter \\ConfigCat\\Psr6Cache can be used as the main cache of the library.", "psr/simple-cache": "When using any PSR16 SimpleCache implementation, a pre-built cache adapter \\ConfigCat\\Psr16Cache can be used as the main cache of the library.", "laravel/framework": "When using laravel, a pre-built cache adapter \\ConfigCat\\LaravelCache can be used as the main cache of the library." + }, + "config": { + "allow-plugins": { + "kylekatarnls/update-helper": false + } } } diff --git a/src/Attributes/Config.php b/src/Attributes/Config.php index 6c3db47..752cf9b 100644 --- a/src/Attributes/Config.php +++ b/src/Attributes/Config.php @@ -8,6 +8,6 @@ */ class Config { - const PREFERENCES = "p"; - const ENTRIES = "f"; + public const PREFERENCES = "p"; + public const ENTRIES = "f"; } diff --git a/src/Attributes/PercentageAttributes.php b/src/Attributes/PercentageAttributes.php index 59aa4cd..d6712f4 100644 --- a/src/Attributes/PercentageAttributes.php +++ b/src/Attributes/PercentageAttributes.php @@ -8,7 +8,7 @@ */ class PercentageAttributes { - const VALUE = "v"; - const PERCENTAGE = "p"; - const VARIATION_ID = "i"; + public const VALUE = "v"; + public const PERCENTAGE = "p"; + public const VARIATION_ID = "i"; } diff --git a/src/Attributes/Preferences.php b/src/Attributes/Preferences.php index 6b6e5cf..cdf2b88 100644 --- a/src/Attributes/Preferences.php +++ b/src/Attributes/Preferences.php @@ -8,6 +8,6 @@ */ class Preferences { - const BASE_URL = "u"; - const REDIRECT = "r"; + public const BASE_URL = "u"; + public const REDIRECT = "r"; } diff --git a/src/Attributes/RolloutAttributes.php b/src/Attributes/RolloutAttributes.php index 3b6b721..cebb06f 100644 --- a/src/Attributes/RolloutAttributes.php +++ b/src/Attributes/RolloutAttributes.php @@ -8,9 +8,9 @@ */ class RolloutAttributes { - const VALUE = "v"; - const COMPARISON_ATTRIBUTE = "a"; - const COMPARATOR = "t"; - const COMPARISON_VALUE = "c"; - const VARIATION_ID = "i"; + public const VALUE = "v"; + public const COMPARISON_ATTRIBUTE = "a"; + public const COMPARATOR = "t"; + public const COMPARISON_VALUE = "c"; + public const VARIATION_ID = "i"; } diff --git a/src/Attributes/SettingAttributes.php b/src/Attributes/SettingAttributes.php index 74470e2..8bcfbba 100644 --- a/src/Attributes/SettingAttributes.php +++ b/src/Attributes/SettingAttributes.php @@ -8,9 +8,9 @@ */ class SettingAttributes { - const VALUE = "v"; - const TYPE = "t"; - const ROLLOUT_PERCENTAGE_ITEMS = "p"; - const ROLLOUT_RULES = "r"; - const VARIATION_ID = "i"; + public const VALUE = "v"; + public const TYPE = "t"; + public const ROLLOUT_PERCENTAGE_ITEMS = "p"; + public const ROLLOUT_RULES = "r"; + public const VARIATION_ID = "i"; } diff --git a/src/Cache/ArrayCache.php b/src/Cache/ArrayCache.php index 982a62b..917fc17 100644 --- a/src/Cache/ArrayCache.php +++ b/src/Cache/ArrayCache.php @@ -8,18 +8,17 @@ */ final class ArrayCache extends ConfigCache { - /** @var array */ - private static $arrayCache = []; + private static array $arrayCache = []; /** * Reads the value identified by the given $key from the underlying cache. * * @param string $key Identifier for the cached value. - * @return string|null Cached value for the given key, or null if it's missing. + * @return ?string Cached value for the given key, or null if it's missing. */ protected function get(string $key): ?string { - return array_key_exists($key, self::$arrayCache) ? self::$arrayCache[$key] : null; + return self::$arrayCache[$key] ?? null; } /** diff --git a/src/Cache/CacheItem.php b/src/Cache/CacheItem.php index 2051233..f495b2a 100644 --- a/src/Cache/CacheItem.php +++ b/src/Cache/CacheItem.php @@ -8,12 +8,12 @@ */ class CacheItem { - /** @var int The time the cached entry refreshed. */ - public $lastRefreshed = 0; - /** @var string The ETag. */ - public $etag; - /** @var array The cached JSON configuration. */ - public $config; - /** @var string The url pointing to the proper cdn server. */ - public $url; + /** The time the cached entry refreshed. */ + public int $lastRefreshed = 0; + /** The ETag. */ + public ?string $etag = null; + /** The cached JSON configuration. */ + public array $config; + /** The url pointing to the proper cdn server. */ + public ?string $url = null; } diff --git a/src/Cache/ConfigCache.php b/src/Cache/ConfigCache.php index 1e1b18a..375fcbe 100644 --- a/src/Cache/ConfigCache.php +++ b/src/Cache/ConfigCache.php @@ -13,8 +13,7 @@ */ abstract class ConfigCache implements LoggerAwareInterface { - /** @var LoggerInterface */ - private $logger; + private LoggerInterface $logger; /** * Reads the value identified by the given $key from the underlying cache. @@ -58,7 +57,7 @@ public function store(string $key, CacheItem $value): void * Reads the value identified by the given $key from the underlying cache. * * @param string $key Identifier for the cached value. - * @return CacheItem|null Cached value for the given key, or null if it's missing. + * @return ?CacheItem Cached value for the given key, or null if it's missing. * * @throws InvalidArgumentException * If the $key is not a legal value. diff --git a/src/Cache/LaravelCache.php b/src/Cache/LaravelCache.php index 2af9a1d..e9223ea 100644 --- a/src/Cache/LaravelCache.php +++ b/src/Cache/LaravelCache.php @@ -7,19 +7,15 @@ class LaravelCache extends ConfigCache { - /** @var Repository */ - private $cache; - - public function __construct(Repository $cache) + public function __construct(private readonly Repository $cache) { - $this->cache = $cache; } /** * Reads the value identified by the given $key from the underlying cache. * * @param string $key Identifier for the cached value. - * @return string|null Cached value for the given key, or null if it's missing. + * @return ?string Cached value for the given key, or null if it's missing. * * @throws InvalidArgumentException If the $key is not a legal value. */ diff --git a/src/Cache/Psr16Cache.php b/src/Cache/Psr16Cache.php index 1de859a..dd6c50a 100644 --- a/src/Cache/Psr16Cache.php +++ b/src/Cache/Psr16Cache.php @@ -7,19 +7,15 @@ class Psr16Cache extends ConfigCache { - /** @var CacheInterface */ - private $cache; - - public function __construct(CacheInterface $cache) + public function __construct(private readonly CacheInterface $cache) { - $this->cache = $cache; } /** * Reads the value identified by the given $key from the underlying cache. * * @param string $key Identifier for the cached value. - * @return string|null Cached value for the given key, or null if it's missing. + * @return ?string Cached value for the given key, or null if it's missing. * * @throws InvalidArgumentException If the $key is not a legal value. */ diff --git a/src/Cache/Psr6Cache.php b/src/Cache/Psr6Cache.php index 939229e..fb7213d 100644 --- a/src/Cache/Psr6Cache.php +++ b/src/Cache/Psr6Cache.php @@ -7,19 +7,16 @@ class Psr6Cache extends ConfigCache { - /** @var CacheItemPoolInterface */ - private $cachePool; - public function __construct(CacheItemPoolInterface $cachePool) + public function __construct(private readonly CacheItemPoolInterface $cachePool) { - $this->cachePool = $cachePool; } /** * Reads the value identified by the given $key from the underlying cache. * * @param string $key Identifier for the cached value. - * @return string|null Cached value for the given key, or null if it's missing. + * @return ?string Cached value for the given key, or null if it's missing. * * @throws InvalidArgumentException If the $key is not a legal value. */ diff --git a/src/ClientInterface.php b/src/ClientInterface.php index c893705..129898c 100644 --- a/src/ClientInterface.php +++ b/src/ClientInterface.php @@ -13,61 +13,75 @@ interface ClientInterface * * @param string $key The identifier of the configuration value. * @param mixed $defaultValue In case of any failure, this value will be returned. - * @param User|null $user The user object to identify the caller. + * @param ?User $user The user object to identify the caller. * @return mixed The configuration value identified by the given key. */ - public function getValue(string $key, $defaultValue, User $user = null); + public function getValue(string $key, mixed $defaultValue, ?User $user = null): mixed; /** * Gets the value and evaluation details of a feature flag or setting identified by the given key. * * @param string $key The identifier of the configuration value. * @param mixed $defaultValue In case of any failure, this value will be returned. - * @param User|null $user The user object to identify the caller. + * @param ?User $user The user object to identify the caller. * @return mixed The configuration value identified by the given key. */ - public function getValueDetails(string $key, $defaultValue, User $user = null): EvaluationDetails; + public function getValueDetails(string $key, mixed $defaultValue, ?User $user = null): EvaluationDetails; /** * Gets the Variation ID (analytics) of a feature flag or setting by the given key. * * @param string $key The identifier of the configuration value. * @param mixed $defaultVariationId In case of any failure, this value will be returned. - * @param User|null $user The user object to identify the caller. - * @return mixed The Variation ID identified by the given key. + * @param ?User $user The user object to identify the caller. + * @return ?string The Variation ID identified by the given key. + * + * @deprecated This method is obsolete and will be removed in a future major version. + * Please use getValueDetails() instead. */ - public function getVariationId(string $key, $defaultVariationId, User $user = null); + public function getVariationId(string $key, ?string $defaultVariationId, ?User $user = null): ?string; /** * Gets the Variation IDs (analytics) of all feature flags or settings. * - * @param User|null $user The user object to identify the caller. + * @param ?User $user The user object to identify the caller. * @return array of all Variation IDs. + * + * @deprecated This method is obsolete and will be removed in a future major version. + * Please use getAllValueDetails() instead. */ - public function getAllVariationIds(User $user = null): array; + public function getAllVariationIds(?User $user = null): array; /** * Gets the key of a setting and its value identified by the given Variation ID (analytics). * * @param string $variationId The Variation ID. - * @return Pair|null of the key and value of a setting. + * @return ?Pair of the key and value of a setting. */ public function getKeyAndValue(string $variationId): ?Pair; /** * Gets a collection of all setting keys. * - * @return array of keys. + * @return string[] of keys. */ public function getAllKeys(): array; /** * Gets the values of all feature flags or settings. * - * @param User|null $user The user object to identify the caller. + * @param ?User $user The user object to identify the caller. * @return array of values. */ - public function getAllValues(User $user = null): array; + public function getAllValues(?User $user = null): array; + + /** + * Gets the values along with evaluation details of all feature flags and settings. + * + * @param ?User $user The user object to identify the caller. + * @return EvaluationDetails[] of evaluation details of all feature flags and settings. + */ + public function getAllValueDetails(?User $user = null): array; /** * Initiates a force refresh on the cached configuration. diff --git a/src/ClientOptions.php b/src/ClientOptions.php index 1acd9d6..c39d36b 100644 --- a/src/ClientOptions.php +++ b/src/ClientOptions.php @@ -10,64 +10,64 @@ final class ClientOptions /** * The base ConfigCat CDN url. */ - const BASE_URL = "base-url"; + public const BASE_URL = "base-url"; /** * A \Psr\Log\LoggerInterface implementation used for logging. */ - const LOGGER = "logger"; + public const LOGGER = "logger"; /** * Default: Warning. Sets the internal log level. */ - const LOG_LEVEL = "log-level"; + public const LOG_LEVEL = "log-level"; /** * A \ConfigCat\ConfigCache implementation used for caching. */ - const CACHE = "cache"; + public const CACHE = "cache"; /** * Array of exception classes that should be ignored from logs. */ - const EXCEPTIONS_TO_IGNORE = "exceptions-to-ignore"; + public const EXCEPTIONS_TO_IGNORE = "exceptions-to-ignore"; /** * Sets how frequent the cached configuration should be refreshed. */ - const CACHE_REFRESH_INTERVAL = "cache-refresh-interval"; + public const CACHE_REFRESH_INTERVAL = "cache-refresh-interval"; /** * Additional options for Guzzle http requests. * https://docs.guzzlephp.org/en/stable/request-options.html */ - const REQUEST_OPTIONS = "request-options"; + public const REQUEST_OPTIONS = "request-options"; /** * A custom callable Guzzle http handler. */ - const CUSTOM_HANDLER = "custom-handler"; + public const CUSTOM_HANDLER = "custom-handler"; /** * Default: Global. Set this parameter to be in sync with the Data Governance * preference on the Dashboard: https://app.configcat.com/organization/data-governance * (Only Organization Admins can access) */ - const DATA_GOVERNANCE = "data-governance"; + public const DATA_GOVERNANCE = "data-governance"; /** * A \ConfigCat\Override\OverrideDataSource implementation used to override * feature flags & settings. */ - const FLAG_OVERRIDES = "flag-overrides"; + public const FLAG_OVERRIDES = "flag-overrides"; /** * A \ConfigCat\User as default user. */ - const DEFAULT_USER = "default-user"; + public const DEFAULT_USER = "default-user"; /** * Default: false. Indicates whether the SDK should be initialized in offline mode or not. */ - const OFFLINE = "offline"; + public const OFFLINE = "offline"; } diff --git a/src/ConfigCatClient.php b/src/ConfigCatClient.php index 3c6d92a..366fd6c 100644 --- a/src/ConfigCatClient.php +++ b/src/ConfigCatClient.php @@ -26,29 +26,18 @@ */ final class ConfigCatClient implements ClientInterface { - /** @var string */ - const SDK_VERSION = "6.2.0"; - - /** @var LoggerInterface */ - private $logger; - /** @var ConfigCache */ - private $cache; - /** @var ConfigFetcher */ - private $fetcher; - /** @var int */ - private $cacheRefreshInterval = 60; - /** @var string */ - private $cacheKey; - /** @var RolloutEvaluator */ - private $evaluator; - /** @var FlagOverrides */ - private $overrides; - /** @var User */ - private $defaultUser; - /** @var Hooks */ - private $hooks; - /** @var bool */ - private $offline = false; + public const SDK_VERSION = '6.2.0'; + + private LoggerInterface $logger; + private ConfigCache $cache; + private ConfigFetcher $fetcher; + private int $cacheRefreshInterval = 60; + private string $cacheKey; + private RolloutEvaluator $evaluator; + private ?FlagOverrides $overrides; + private ?User $defaultUser; + private Hooks $hooks; + private bool $offline = false; /** * Creates a new ConfigCatClient. @@ -121,9 +110,7 @@ public function __construct(string $sdkKey, array $options = []) $this->cacheRefreshInterval = $options[ClientOptions::CACHE_REFRESH_INTERVAL]; } - if (!is_null($this->overrides)) { - $this->overrides->setLogger($this->logger); - } + $this->overrides?->setLogger($this->logger); if (isset($options[ClientOptions::OFFLINE]) && $options[ClientOptions::OFFLINE] === true) { $this->offline = true; @@ -139,10 +126,10 @@ public function __construct(string $sdkKey, array $options = []) * * @param string $key The identifier of the configuration value. * @param mixed $defaultValue In case of any failure, this value will be returned. - * @param User|null $user The user object to identify the caller. + * @param ?User $user The user object to identify the caller. * @return mixed The configuration value identified by the given key. */ - public function getValue(string $key, $defaultValue, User $user = null) + public function getValue(string $key, mixed $defaultValue, ?User $user = null): mixed { try { $settingsResult = $this->getSettings(); @@ -184,10 +171,10 @@ public function getValue(string $key, $defaultValue, User $user = null) * * @param string $key The identifier of the configuration value. * @param mixed $defaultValue In case of any failure, this value will be returned. - * @param User|null $user The user object to identify the caller. + * @param ?User $user The user object to identify the caller. * @return mixed The configuration value identified by the given key. */ - public function getValueDetails(string $key, $defaultValue, User $user = null): EvaluationDetails + public function getValueDetails(string $key, mixed $defaultValue, ?User $user = null): EvaluationDetails { try { $settingsResult = $this->getSettings(); @@ -227,10 +214,13 @@ public function getValueDetails(string $key, $defaultValue, User $user = null): * * @param string $key The identifier of the configuration value. * @param mixed $defaultVariationId In case of any failure, this value will be returned. - * @param User|null $user The user object to identify the caller. - * @return mixed The Variation ID identified by the given key. + * @param ?User $user The user object to identify the caller. + * @return ?string The Variation ID identified by the given key. + * + * @deprecated This method is obsolete and will be removed in a future major version. + * Please use getValueDetails() instead. */ - public function getVariationId(string $key, $defaultVariationId, User $user = null) + public function getVariationId(string $key, ?string $defaultVariationId, ?User $user = null): ?string { try { $settingsResult = $this->getSettings(); @@ -264,14 +254,17 @@ public function getVariationId(string $key, $defaultVariationId, User $user = nu /** * Gets the Variation IDs (analytics) of all feature flags or settings. * - * @param User|null $user The user object to identify the caller. + * @param ?User $user The user object to identify the caller. * @return array of all Variation IDs. + * + * @deprecated This method is obsolete and will be removed in a future major version. + * Please use getAllValueDetails() instead. */ - public function getAllVariationIds(User $user = null): array + public function getAllVariationIds(?User $user = null): array { try { $settingsResult = $this->getSettings(); - return is_null($settingsResult->settings) ? [] : $this->parseVariationIds($settingsResult, $user); + return empty($settingsResult->settings) ? [] : $this->parseVariationIds($settingsResult, $user); } catch (Exception $exception) { $this->logger->error("An error occurred during getting all the variation ids. Returning empty array. " . $exception->getMessage(), ['exception' => $exception]); @@ -283,13 +276,13 @@ public function getAllVariationIds(User $user = null): array * Gets the key of a setting and its value identified by the given Variation ID (analytics). * * @param string $variationId The Variation ID. - * @return Pair|null of the key and value of a setting. + * @return ?Pair of the key and value of a setting. */ public function getKeyAndValue(string $variationId): ?Pair { try { $settingsResult = $this->getSettings(); - return is_null($settingsResult->settings) + return empty($settingsResult->settings) ? null : $this->parseKeyAndValue($settingsResult->settings, $variationId); } catch (Exception $exception) { @@ -308,7 +301,7 @@ public function getAllKeys(): array { try { $settingsResult = $this->getSettings(); - return is_null($settingsResult->settings) ? [] : array_keys($settingsResult->settings); + return empty($settingsResult->settings) ? [] : array_keys($settingsResult->settings); } catch (Exception $exception) { $this->logger->error("An error occurred during the deserialization. Returning empty array. " . $exception->getMessage(), ['exception' => $exception]); @@ -319,14 +312,14 @@ public function getAllKeys(): array /** * Gets the values of all feature flags or settings. * - * @param User|null $user The user object to identify the caller. + * @param ?User $user The user object to identify the caller. * @return array of values. */ - public function getAllValues(User $user = null): array + public function getAllValues(?User $user = null): array { try { $settingsResult = $this->getSettings(); - return is_null($settingsResult->settings) ? [] : $this->parseValues($settingsResult, $user); + return empty($settingsResult->settings) ? [] : $this->parseValues($settingsResult, $user); } catch (Exception $exception) { $this->logger->error("An error occurred during getting all values. Returning empty array. " . $exception->getMessage(), ['exception' => $exception]); @@ -334,12 +327,43 @@ public function getAllValues(User $user = null): array } } + /** + * Gets the values along with evaluation details of all feature flags and settings. + * + * @param ?User $user The user object to identify the caller. + * @return EvaluationDetails[] of evaluation details of all feature flags and settings. + */ + public function getAllValueDetails(?User $user = null): array + { + try { + $settingsResult = $this->getSettings(); + if (empty($settingsResult->settings)) { + return []; + } + $keys = array_keys($settingsResult->settings); + $result = []; + foreach ($keys as $key) { + $result[$key] = $this->evaluate( + $key, + $settingsResult->settings[$key], + $user, + $settingsResult->fetchTime + ); + } + return $result; + } catch (Exception $exception) { + $this->logger->error("An error occurred during getting all value details. Returning empty array. " + . $exception->getMessage(), ['exception' => $exception]); + return []; + } + } + /** * Initiates a force refresh on the cached configuration. */ public function forceRefresh(): RefreshResult { - if (!is_null($this->overrides) && $this->overrides->getBehaviour() == OverrideBehaviour::LOCAL_ONLY) { + if ($this->overrides !== null && OverrideBehaviour::LOCAL_ONLY == $this->overrides->getBehaviour()) { return new RefreshResult( false, "The ConfigCat SDK is in local-only mode. Calling .forceRefresh() has no effect." @@ -353,7 +377,7 @@ public function forceRefresh(): RefreshResult } $cacheItem = $this->cache->load($this->cacheKey); - if (is_null($cacheItem)) { + if ($cacheItem === null) { $cacheItem = new CacheItem(); } @@ -447,7 +471,7 @@ private function parseVariationIds(SettingsResult $settingsResult, User $user = private function evaluate(string $key, array $setting, ?User $user, int $fetchTime): EvaluationDetails { - $actualUser = is_null($user) ? $this->defaultUser : $user; + $actualUser = $user === null ? $this->defaultUser : $user; $collector = new EvaluationLogCollector(); $collector->add("Evaluating " . $key . "."); $result = $this->evaluator->evaluate($key, $setting, $collector, $actualUser); @@ -499,7 +523,7 @@ private function parseKeyAndValue(array $json, $variationId): ?Pair */ private function getSettings(): SettingsResult { - if (!is_null($this->overrides)) { + if ($this->overrides !== null) { switch ($this->overrides->getBehaviour()) { case OverrideBehaviour::LOCAL_ONLY: return new SettingsResult($this->overrides->getDataSource()->getOverrides(), 0); @@ -525,7 +549,7 @@ private function getSettings(): SettingsResult private function getRemoteSettings(): SettingsResult { $cacheItem = $this->cache->load($this->cacheKey); - if (is_null($cacheItem)) { + if ($cacheItem === null) { $cacheItem = new CacheItem(); } diff --git a/src/ConfigCatClientException.php b/src/ConfigCatClientException.php index 2160226..8ff0ab1 100644 --- a/src/ConfigCatClientException.php +++ b/src/ConfigCatClientException.php @@ -4,5 +4,4 @@ class ConfigCatClientException extends \Exception { - } diff --git a/src/ConfigFetcher.php b/src/ConfigFetcher.php index adb133f..3a5064f 100644 --- a/src/ConfigFetcher.php +++ b/src/ConfigFetcher.php @@ -19,30 +19,23 @@ */ final class ConfigFetcher { - const ETAG_HEADER = "ETag"; - const CONFIG_JSON_NAME = "config_v5"; - - const GLOBAL_URL = "https://cdn-global.configcat.com"; - const EU_ONLY_URL = "https://cdn-eu.configcat.com"; - - const NO_REDIRECT = 0; - const SHOULD_REDIRECT = 1; - const FORCE_REDIRECT = 2; - - /** @var LoggerInterface */ - private $logger; - /** @var array */ - private $requestOptions; - /** @var array */ - private $clientOptions; - /** @var string */ - private $urlPath; - /** @var string */ - private $baseUrl; - /** @var bool */ - private $urlIsCustom = false; - /** @var Client */ - private $client; + public const ETAG_HEADER = "ETag"; + public const CONFIG_JSON_NAME = "config_v5"; + + public const GLOBAL_URL = "https://cdn-global.configcat.com"; + public const EU_ONLY_URL = "https://cdn-eu.configcat.com"; + + public const NO_REDIRECT = 0; + public const SHOULD_REDIRECT = 1; + public const FORCE_REDIRECT = 2; + + private LoggerInterface $logger; + private array $requestOptions; + private array $clientOptions; + private string $urlPath; + private string $baseUrl; + private bool $urlIsCustom = false; + private Client $client; /** * ConfigFetcher constructor. @@ -110,8 +103,8 @@ public function __construct(string $sdkKey, LoggerInterface $logger, array $opti /** * Gets the latest configuration from the network. * - * @param string|null $etag The ETag. - * @param string|null $cachedUrl The cached cdn url. + * @param ?string $etag The ETag. + * @param ?string $cachedUrl The cached cdn url. * * @return FetchResponse An object describing the result of the fetch. */ diff --git a/src/DataGovernance.php b/src/DataGovernance.php index ecb7509..0a8e832 100644 --- a/src/DataGovernance.php +++ b/src/DataGovernance.php @@ -9,9 +9,9 @@ final class DataGovernance { /** @var int Select this if your feature flags are published to all global CDN nodes. */ - const GLOBAL_ = 0; + public const GLOBAL_ = 0; /** @var int Select this if your feature flags are published to CDN nodes only in the EU. */ - const EU_ONLY = 1; + public const EU_ONLY = 1; public static function isValid($value): bool { diff --git a/src/EvaluationDetails.php b/src/EvaluationDetails.php index 0546e82..ce5e22a 100644 --- a/src/EvaluationDetails.php +++ b/src/EvaluationDetails.php @@ -4,48 +4,20 @@ class EvaluationDetails { - /** @var string */ - private $key; - /** @var string|null */ - private $variationId; - /** @var mixed */ - private $value; - /** @var User|null */ - private $user; - /** @var bool */ - private $isDefaultValue; - /** @var string */ - private $error; - /** @var int */ - private $fetchTimeUnixSeconds; - /** @var array|null */ - private $matchedEvaluationRule; - /** @var array|null */ - private $matchedEvaluationPercentageRule; - /** * @internal */ public function __construct( - string $key, - ?string $variationId, - $value, - ?User $user, - bool $isDefaultValue, - ?string $error, - int $fetchTimeUnixSeconds, - ?array $matchedEvaluationRule, - ?array $matchedEvaluationPercentageRule + private readonly string $key, + private readonly ?string $variationId, + private readonly mixed $value, + private readonly ?User $user, + private readonly bool $isDefaultValue, + private readonly ?string $error, + private readonly int $fetchTimeUnixSeconds, + private readonly ?array $matchedEvaluationRule, + private readonly ?array $matchedEvaluationPercentageRule ) { - $this->key = $key; - $this->variationId = $variationId; - $this->value = $value; - $this->user = $user; - $this->isDefaultValue = $isDefaultValue; - $this->error = $error; - $this->fetchTimeUnixSeconds = $fetchTimeUnixSeconds; - $this->matchedEvaluationRule = $matchedEvaluationRule; - $this->matchedEvaluationPercentageRule = $matchedEvaluationPercentageRule; } /** @@ -75,7 +47,7 @@ public function getKey(): string } /** - * @return string the variation ID (analytics) + * @return ?string the variation ID (analytics) */ public function getVariationId(): ?string { @@ -85,13 +57,13 @@ public function getVariationId(): ?string /** * @return mixed the evaluated value of the feature flag or setting. */ - public function getValue() + public function getValue(): mixed { return $this->value; } /** - * @return User the user object that was used for evaluation. + * @return ?User the user object that was used for evaluation. */ public function getUser(): ?User { @@ -107,7 +79,7 @@ public function isDefaultValue(): bool } /** - * @return string in case of an error, the error message. + * @return ?string in case of an error, the error message. */ public function getError(): ?string { @@ -123,7 +95,7 @@ public function getFetchTimeUnixSeconds(): int } /** - * @return array the targeting rule the evaluation was based on. + * @return ?array the targeting rule the evaluation was based on. */ public function getMatchedEvaluationRule(): ?array { @@ -131,7 +103,7 @@ public function getMatchedEvaluationRule(): ?array } /** - * @return array the percentage rule the evaluation was based on. + * @return ?array the percentage rule the evaluation was based on. */ public function getMatchedEvaluationPercentageRule(): ?array { diff --git a/src/EvaluationLogCollector.php b/src/EvaluationLogCollector.php index c236b9a..fcd99ea 100644 --- a/src/EvaluationLogCollector.php +++ b/src/EvaluationLogCollector.php @@ -7,16 +7,15 @@ */ class EvaluationLogCollector { - /** @var array */ - private $entries = []; + private array $entries = []; - public function add($entry): void + public function add(string $entry): void { $this->entries[] = $entry; } public function __toString(): string { - return join(PHP_EOL, $this->entries); + return implode(PHP_EOL, $this->entries); } } diff --git a/src/EvaluationResult.php b/src/EvaluationResult.php index 5138f72..b7994c2 100644 --- a/src/EvaluationResult.php +++ b/src/EvaluationResult.php @@ -7,16 +7,11 @@ */ final class EvaluationResult { - public $value; - public $variationId; - public $targetingRule; - public $percentageRule; - - public function __construct($value, string $variationId, ?array $targetingRule, ?array $percentageRule) - { - $this->value = $value; - $this->variationId = $variationId; - $this->targetingRule = $targetingRule; - $this->percentageRule = $percentageRule; + public function __construct( + public mixed $value, + public string $variationId, + public ?array $targetingRule, + public ?array $percentageRule + ) { } } diff --git a/src/FetchResponse.php b/src/FetchResponse.php index 2ae4ac3..1e76276 100644 --- a/src/FetchResponse.php +++ b/src/FetchResponse.php @@ -10,35 +10,19 @@ final class FetchResponse { /** @var int */ - const FETCHED = 0; + public const FETCHED = 0; /** @var int */ - const NOT_MODIFIED = 1; + public const NOT_MODIFIED = 1; /** @var int */ - const FAILED = 3; - - /** @var array|null */ - private $body; - /** @var int */ - private $status; - /** @var string|null */ - private $etag; - /** @var string */ - private $url; - /** @var string|null */ - private $error; + public const FAILED = 3; private function __construct( - int $status, - ?string $etag = null, - ?array $body = null, - ?string $url = null, - ?string $error = null + private readonly int $status, + private readonly ?string $etag = null, + private readonly ?array $body = null, + private readonly ?string $url = null, + private readonly ?string $error = null ) { - $this->status = $status; - $this->body = $body; - $this->etag = $etag; - $this->url = $url; - $this->error = $error; } /** @@ -108,7 +92,7 @@ public function isFailed(): bool /** * Returns the response body. * - * @return array|null The fetched response body. + * @return ?array The fetched response body. */ public function getBody(): ?array { @@ -118,7 +102,7 @@ public function getBody(): ?array /** * Returns the ETag. * - * @return string|null The received ETag. + * @return ?string The received ETag. */ public function getETag(): ?string { @@ -128,7 +112,7 @@ public function getETag(): ?string /** * Returns the proper cdn url. * - * @return string|null The cdn url. + * @return ?string The cdn url. */ public function getUrl(): ?string { @@ -138,7 +122,7 @@ public function getUrl(): ?string /** * Returns the error if the fetch failed. * - * @return string|null The error. + * @return ?string The error. */ public function getError(): ?string { diff --git a/src/Hooks.php b/src/Hooks.php index b37dd08..0f46524 100644 --- a/src/Hooks.php +++ b/src/Hooks.php @@ -8,18 +8,15 @@ */ final class Hooks { - /** @var array */ - private $onConfigChanged = []; - /** @var array */ - private $onFlagEvaluated = []; - /** @var array */ - private $onError = []; + private array $onConfigChanged = []; + private array $onFlagEvaluated = []; + private array $onError = []; /** * This event is sent when the SDK loads a valid config.json into memory from cache, * and each subsequent time when the loaded config.json changes via HTTP. */ - public function addOnConfigChanged(callable $callback) + public function addOnConfigChanged(callable $callback): void { $this->onConfigChanged[] = $callback; } @@ -28,7 +25,7 @@ public function addOnConfigChanged(callable $callback) * This event is sent each time when the SDK evaluates a feature flag or setting. The event sends * the same evaluation details that you would get from [ConfigCatClient.getValueDetails]. */ - public function addOnFlagEvaluated(callable $callback) + public function addOnFlagEvaluated(callable $callback): void { $this->onFlagEvaluated[] = $callback; } @@ -36,7 +33,7 @@ public function addOnFlagEvaluated(callable $callback) /** * This event is sent when an error occurs within the SDK. */ - public function addOnError(callable $callback) + public function addOnError(callable $callback): void { $this->onError[] = $callback; } @@ -44,7 +41,7 @@ public function addOnError(callable $callback) /** * @internal */ - public function fireOnConfigChanged(array $settings) + public function fireOnConfigChanged(array $settings): void { foreach ($this->onConfigChanged as $callback) { call_user_func($callback, $settings); @@ -54,7 +51,7 @@ public function fireOnConfigChanged(array $settings) /** * @internal */ - public function fireOnFlagEvaluated(EvaluationDetails $details) + public function fireOnFlagEvaluated(EvaluationDetails $details): void { foreach ($this->onFlagEvaluated as $callback) { call_user_func($callback, $details); @@ -64,7 +61,7 @@ public function fireOnFlagEvaluated(EvaluationDetails $details) /** * @internal */ - public function fireOnError(string $error) + public function fireOnError(string $error): void { foreach ($this->onError as $callback) { call_user_func($callback, $error); diff --git a/src/Log/InternalLogger.php b/src/Log/InternalLogger.php index e5cfffe..ef50f85 100644 --- a/src/Log/InternalLogger.php +++ b/src/Log/InternalLogger.php @@ -13,29 +13,12 @@ */ class InternalLogger implements LoggerInterface { - /** - * @var LoggerInterface - */ - private $logger; - /** - * @var int - */ - private $globalLevel; - /** - * @var array - */ - private $exceptionsToIgnore; - /** - * @var Hooks - */ - private $hooks; - - public function __construct(LoggerInterface $logger, $globalLevel, array $exceptionsToIgnore, Hooks $hooks) - { - $this->logger = $logger; - $this->globalLevel = $globalLevel; - $this->exceptionsToIgnore = $exceptionsToIgnore; - $this->hooks = $hooks; + public function __construct( + private readonly LoggerInterface $logger, + private readonly int $globalLevel, + private readonly array $exceptionsToIgnore, + private readonly Hooks $hooks + ) { } public function emergency($message, array $context = []): void @@ -105,11 +88,7 @@ public function log($level, $message, array $context = []): void private function shouldLog($currentLevel, array $context): bool { - if ($currentLevel >= $this->globalLevel && !$this->hasAnythingToIgnore($context)) { - return true; - } - - return false; + return $currentLevel >= $this->globalLevel && !$this->hasAnythingToIgnore($context); } private function hasAnythingToIgnore(array $context): bool @@ -120,10 +99,6 @@ private function hasAnythingToIgnore(array $context): bool return false; } - if (in_array(get_class($context['exception']), $this->exceptionsToIgnore)) { - return true; - } - - return false; + return in_array(get_class($context['exception']), $this->exceptionsToIgnore); } } diff --git a/src/Log/LogLevel.php b/src/Log/LogLevel.php index 0a02293..c4a1b38 100644 --- a/src/Log/LogLevel.php +++ b/src/Log/LogLevel.php @@ -8,15 +8,15 @@ */ class LogLevel { - const DEBUG = 10; - const INFO = 20; - const NOTICE = 30; - const WARNING = 40; - const ERROR = 50; - const CRITICAL = 60; - const ALERT = 70; - const EMERGENCY = 80; - const NO_LOG = 90; + public const DEBUG = 10; + public const INFO = 20; + public const NOTICE = 30; + public const WARNING = 40; + public const ERROR = 50; + public const CRITICAL = 60; + public const ALERT = 70; + public const EMERGENCY = 80; + public const NO_LOG = 90; public static function isValid($level): bool { diff --git a/src/Override/ArrayDataSource.php b/src/Override/ArrayDataSource.php index 61fb967..f542219 100644 --- a/src/Override/ArrayDataSource.php +++ b/src/Override/ArrayDataSource.php @@ -11,20 +11,12 @@ */ class ArrayDataSource extends OverrideDataSource { - /** @var array */ - private $overrides; - /** * Constructs an array data source. * @param $overrides array The array that contains the overrides. */ - public function __construct(array $overrides) + public function __construct(private readonly array $overrides) { - if (!is_array($overrides)) { - throw new InvalidArgumentException("The overrides is not a valid array."); - } - - $this->overrides = $overrides; } /** diff --git a/src/Override/FlagOverrides.php b/src/Override/FlagOverrides.php index 957ba08..9c8a7ab 100644 --- a/src/Override/FlagOverrides.php +++ b/src/Override/FlagOverrides.php @@ -11,11 +11,6 @@ */ class FlagOverrides implements LoggerAwareInterface { - /** @var int */ - private $behaviour; - /** @var OverrideDataSource */ - private $dataSource; - /** * Constructs the feature flag overrides. * @param $dataSource OverrideDataSource The data source of the feature flag overrides. @@ -23,14 +18,11 @@ class FlagOverrides implements LoggerAwareInterface * override the remote values, or use local values only when a remote value doesn't exist, * or use it for local only mode. */ - public function __construct(OverrideDataSource $dataSource, int $behaviour) + public function __construct(private readonly OverrideDataSource $dataSource, private readonly int $behaviour) { if (!OverrideBehaviour::isValid($behaviour)) { throw new InvalidArgumentException("The behaviour argument is not valid."); } - - $this->behaviour = $behaviour; - $this->dataSource = $dataSource; } /** diff --git a/src/Override/LocalFileDataSource.php b/src/Override/LocalFileDataSource.php index 5bf86d3..1b36e40 100644 --- a/src/Override/LocalFileDataSource.php +++ b/src/Override/LocalFileDataSource.php @@ -12,25 +12,20 @@ */ class LocalFileDataSource extends OverrideDataSource { - /** @var string */ - private $filePath; - /** * Constructs a local file data source. * @param $filePath string The path to the file. */ - public function __construct(string $filePath) + public function __construct(private readonly string $filePath) { if (!file_exists($filePath)) { throw new InvalidArgumentException("The file '" . $filePath . "' doesn't exist."); } - - $this->filePath = $filePath; } /** * Gets the overrides. - * @return array The overrides. + * @return ?array The overrides. */ public function getOverrides(): ?array { @@ -44,7 +39,7 @@ public function getOverrides(): ?array if ($json == null) { $this->logger->error("Could not decode json from file " . $this->filePath . ". JSON error: - " . json_last_error_msg() . ""); + " . json_last_error_msg()); return null; } diff --git a/src/Override/OverrideBehaviour.php b/src/Override/OverrideBehaviour.php index 0ec9972..a3d6ec7 100644 --- a/src/Override/OverrideBehaviour.php +++ b/src/Override/OverrideBehaviour.php @@ -12,19 +12,19 @@ class OverrideBehaviour * When evaluating values, the SDK will not use feature flags & settings from the ConfigCat CDN, but it will use * all feature flags & settings that are loaded from local-override sources. */ - const LOCAL_ONLY = 10; + public const LOCAL_ONLY = 10; /** * When evaluating values, the SDK will use all feature flags & settings that are downloaded from the ConfigCat CDN, * plus all feature flags & settings that are loaded from local-override sources. If a feature flag or a setting is * defined both in the fetched and the local-override source then the local-override version will take precedence. */ - const LOCAL_OVER_REMOTE = 20; + public const LOCAL_OVER_REMOTE = 20; /** * When evaluating values, the SDK will use all feature flags & settings that are downloaded from the ConfigCat CDN, * plus all feature flags & settings that are loaded from local-override sources. If a feature flag or a setting is * defined both in the fetched and the local-override source then the fetched version will take precedence. */ - const REMOTE_OVER_LOCAL = 30; + public const REMOTE_OVER_LOCAL = 30; /** * Checks whether a given value is a valid behaviour. @@ -33,10 +33,6 @@ class OverrideBehaviour */ public static function isValid(int $behaviour): bool { - if (!is_int($behaviour)) { - return false; - } - return $behaviour == self::LOCAL_ONLY || $behaviour == self::LOCAL_OVER_REMOTE || $behaviour == self::REMOTE_OVER_LOCAL; diff --git a/src/Override/OverrideDataSource.php b/src/Override/OverrideDataSource.php index 361a0ca..d305e56 100644 --- a/src/Override/OverrideDataSource.php +++ b/src/Override/OverrideDataSource.php @@ -11,12 +11,11 @@ */ abstract class OverrideDataSource implements LoggerAwareInterface { - /** @var LoggerInterface */ - protected $logger; + protected LoggerInterface $logger; /** * Gets the overrides. - * @return array The overrides. + * @return ?array The overrides. */ abstract public function getOverrides(): ?array; @@ -24,7 +23,7 @@ abstract public function getOverrides(): ?array; * Sets the logger. * @param LoggerInterface $logger The logger. */ - public function setLogger(LoggerInterface $logger) + public function setLogger(LoggerInterface $logger): void { $this->logger = $logger; } diff --git a/src/Pair.php b/src/Pair.php index b04330a..2da39ec 100644 --- a/src/Pair.php +++ b/src/Pair.php @@ -8,22 +8,14 @@ */ class Pair { - /** @var string The key. */ - private $key; - - /** @var mixed The value. */ - private $value; - /** * Creates a new Pair. * * @param string $key The key. * @param mixed $value The value: */ - public function __construct(string $key, $value) + public function __construct(private readonly string $key, private readonly mixed $value) { - $this->key = $key; - $this->value = $value; } /** @@ -41,7 +33,7 @@ public function getKey(): string * * @return mixed */ - public function getValue() + public function getValue(): mixed { return $this->value; } diff --git a/src/RefreshResult.php b/src/RefreshResult.php index 927f59e..4f8bbd7 100644 --- a/src/RefreshResult.php +++ b/src/RefreshResult.php @@ -7,20 +7,13 @@ */ class RefreshResult { - /** @var bool */ - private $isSuccess; - /** @var string|null */ - private $error; - /** * @param bool $isSuccess * @param string|null $error * @internal */ - public function __construct(bool $isSuccess, ?string $error) + public function __construct(private readonly bool $isSuccess, private readonly ?string $error) { - $this->isSuccess = $isSuccess; - $this->error = $error; } /** diff --git a/src/RolloutEvaluator.php b/src/RolloutEvaluator.php index a96012c..16344f3 100644 --- a/src/RolloutEvaluator.php +++ b/src/RolloutEvaluator.php @@ -17,10 +17,7 @@ */ final class RolloutEvaluator { - /** @var LoggerInterface */ - private $logger; - - private $comparatorTexts = [ + private array $comparatorTexts = [ "IS ONE OF", "IS NOT ONE OF", "CONTAINS", @@ -46,9 +43,8 @@ final class RolloutEvaluator * * @param LoggerInterface $logger The logger instance. */ - public function __construct(LoggerInterface $logger) + public function __construct(private readonly LoggerInterface $logger) { - $this->logger = $logger; } /** @@ -57,16 +53,16 @@ public function __construct(LoggerInterface $logger) * @param string $key The key of the desired value. * @param array $json The decoded JSON configuration. * @param EvaluationLogCollector $logCollector The evaluation log collector. - * @param User|null $user Optional. The user to identify the caller. + * @param ?User $user Optional. The user to identify the caller. * @return EvaluationResult The evaluation result. */ public function evaluate( string $key, array $json, EvaluationLogCollector $logCollector, - User $user = null + ?User $user = null ): EvaluationResult { - if (is_null($user)) { + if ($user === null) { if (isset($json[SettingAttributes::ROLLOUT_RULES]) && !empty($json[SettingAttributes::ROLLOUT_RULES]) || isset($json[SettingAttributes::ROLLOUT_PERCENTAGE_ITEMS]) && @@ -177,7 +173,7 @@ public function evaluate( )); return new EvaluationResult($value, $variationId, $rule, null); } - } catch (SemverException $exception) { + } catch (SemverException) { $logCollector->add($this->logMatch( $comparisonAttribute, $userValue, diff --git a/src/SettingsResult.php b/src/SettingsResult.php index 13e7f56..bfbf267 100644 --- a/src/SettingsResult.php +++ b/src/SettingsResult.php @@ -7,14 +7,7 @@ */ class SettingsResult { - /** @var array */ - public $settings; - /** @var int */ - public $fetchTime; - - public function __construct(array $settings, int $fetchTime) + public function __construct(public array $settings, public int $fetchTime) { - $this->settings = $settings; - $this->fetchTime = $fetchTime; } } diff --git a/src/User.php b/src/User.php index 8a07ea2..ed5af90 100644 --- a/src/User.php +++ b/src/User.php @@ -8,10 +8,8 @@ */ final class User { - /** @var array */ - private $attributes = []; - /** @var string */ - private $identifier; + private string $identifier; + private array $attributes = []; /** * User constructor. @@ -21,8 +19,12 @@ final class User * @param string $country Optional. The country attribute of the user. * @param array $custom Custom user attributes. */ - public function __construct(string $identifier, string $email = "", string $country = "", array $custom = []) - { + public function __construct( + string $identifier, + string $email = "", + string $country = "", + array $custom = [] + ) { $this->identifier = $this->attributes['Identifier'] = $identifier; if (!empty($email)) { diff --git a/src/Utils.php b/src/Utils.php index 15a3c89..ee83f96 100644 --- a/src/Utils.php +++ b/src/Utils.php @@ -10,7 +10,7 @@ final class Utils { /** - * Determines that a string contains an other. + * Determines that a string contains another string. * * @param string $haystack The string in we search for the other. * @param string $needle The string we search. @@ -18,7 +18,7 @@ final class Utils */ public static function strContains(string $haystack, string $needle): bool { - return strpos($haystack, $needle) !== false; + return str_contains($haystack, $needle); } /** @@ -39,7 +39,7 @@ public static function splitTrim(string $text, string $delimiter = ','): array * @param mixed $value The value. * @return string The result string. */ - public static function getStringRepresentation($value): string + public static function getStringRepresentation(mixed $value): string { if (is_bool($value) === true) { return $value ? "true" : "false"; diff --git a/tests/ConfigCatClientTest.php b/tests/ConfigCatClientTest.php index 8d80759..433c5b2 100644 --- a/tests/ConfigCatClientTest.php +++ b/tests/ConfigCatClientTest.php @@ -207,6 +207,19 @@ public function testGetAllValues() $this->assertEquals(["first" => false, "second" => true], $value); } + public function testGetAllValueDetails() + { + $client = new ConfigCatClient("testGetAllValueDetails", [ + ClientOptions::CUSTOM_HANDLER => new MockHandler( + [new Response(200, [], self::TEST_JSON)] + ), + ]); + $value = $client->getAllValueDetails(); + + $this->assertFalse($value["first"]->getValue()); + $this->assertTrue($value["second"]->getValue()); + } + public function testDefaultUser() { $client = new ConfigCatClient("testDefaultUser", [ClientOptions::CUSTOM_HANDLER => new MockHandler([ diff --git a/tests/ConfigFetcherTest.php b/tests/ConfigFetcherTest.php index 69d07ce..b06f941 100644 --- a/tests/ConfigFetcherTest.php +++ b/tests/ConfigFetcherTest.php @@ -16,9 +16,9 @@ class ConfigFetcherTest extends TestCase { - private $mockSdkKey = "testSdkKey"; - private $mockEtag = "testEtag"; - private $mockBody = "{\"key\": \"value\"}"; + private string $mockSdkKey = "testSdkKey"; + private string $mockEtag = "testEtag"; + private string $mockBody = "{\"key\": \"value\"}"; public function testFetchOk() {