From 584bce0eae395ea83b27fac530cbc67e0042e251 Mon Sep 17 00:00:00 2001 From: Jarred Stelfox Date: Mon, 15 Jul 2024 15:22:57 -0700 Subject: [PATCH] Forced Features: Implement it This exists in the JS SDK, but not in the PHP sdk. It's useful for cases like QA overrides during testing of features --- src/Growthbook.php | 37 ++++++++++++++++++++++++++++++++++++- tests/GrowthbookTest.php | 14 ++++++++++++++ 2 files changed, 50 insertions(+), 1 deletion(-) diff --git a/src/Growthbook.php b/src/Growthbook.php index 862bf1b..24f6fb8 100644 --- a/src/Growthbook.php +++ b/src/Growthbook.php @@ -21,6 +21,8 @@ class Growthbook implements LoggerAwareInterface private $attributes = []; /** @var Feature[] */ private $features = []; + /** @var array> */ + private $forcedFeatures = []; /** @var array */ private $forcedVariations = []; /** @var bool */ @@ -63,7 +65,7 @@ public static function create(): Growthbook } /** - * @param array{enabled?:bool,logger?:\Psr\Log\LoggerInterface,url?:string,attributes?:array,features?:array,forcedVariations?:array,qaMode?:bool,trackingCallback?:callable,cache?:\Psr\SimpleCache\CacheInterface,httpClient?:\Psr\Http\Client\ClientInterface,requestFactory?:\Psr\Http\Message\RequestFactoryInterface,decryptionKey?:string} $options + * @param array{enabled?:bool,logger?:\Psr\Log\LoggerInterface,url?:string,attributes?:array,features?:array,forcedVariations?:array,qaMode?:bool,trackingCallback?:callable,cache?:\Psr\SimpleCache\CacheInterface,httpClient?:\Psr\Http\Client\ClientInterface,requestFactory?:\Psr\Http\Message\RequestFactoryInterface,decryptionKey?:string,forcedFeatures?:array>} $options */ public function __construct(array $options = []) { @@ -75,6 +77,7 @@ public function __construct(array $options = []) "attributes", "features", "forcedVariations", + "forcedFeatures", "qaMode", "trackingCallback", "cache", @@ -104,6 +107,10 @@ public function __construct(array $options = []) // Ignore errors from discovery } + if(array_key_exists("forcedFeatures", $options)) { + $this->withForcedFeatures($options['forcedFeatures']); + } + if (array_key_exists("features", $options)) { $this->withFeatures(($options["features"])); } @@ -155,6 +162,16 @@ public function withForcedVariations(array $forcedVariations): Growthbook $this->forcedVariations = $forcedVariations; return $this; } + + /** + * @param array> $forcedFeatures + * @return Growthbook + */ + public function withForcedFeatures(array $forcedFeatures) + { + $this->forcedFeatures = $forcedFeatures; + return $this; + } /** * @param string $url * @return Growthbook @@ -211,6 +228,13 @@ public function getForcedVariations(): array { return $this->forcedVariations; } + /** + * @return array> + */ + public function getForcedFeatured() + { + return $this->forcedFeatures; + } /** * @return string */ @@ -267,6 +291,17 @@ public function getFeature(string $key): FeatureResult } $this->log(LogLevel::DEBUG, "Evaluating feature - $key"); $feature = $this->features[$key]; + + // Check if the feature is forced + if (array_key_exists($key, $this->forcedFeatures)) { + $this->log(LogLevel::DEBUG, "Feature Forced - $key", [ + "feature" => $key, + "result" => $this->forcedFeatures[$key], + ]); + + return $this->forcedFeatures[$key]; + } + if ($feature->rules) { foreach ($feature->rules as $rule) { if ($rule->condition) { diff --git a/tests/GrowthbookTest.php b/tests/GrowthbookTest.php index 22ed89c..8c17b76 100644 --- a/tests/GrowthbookTest.php +++ b/tests/GrowthbookTest.php @@ -3,6 +3,7 @@ require_once __DIR__ . '/../vendor/autoload.php'; use Growthbook\Condition; +use Growthbook\FeatureResult; use Growthbook\Growthbook; use Growthbook\InlineExperiment; use PHPUnit\Framework\TestCase; @@ -330,6 +331,19 @@ public function testFluentInterface(): void ); } + public function testForcedFeatures(): void + { + $gb = Growthbook::create() + ->withFeatures([ + 'feature-1'=>['defaultValue' => false, 'rules' => []] + ]) + ->withForcedFeatures([ + 'feature-1' => new FeatureResult(true, 'forcedFeature') + ]); + + $this->assertSame(true, $gb->getFeature('feature-1')->value); + } + public function testInlineExperiment(): void { $condition = ['country'=>'US'];