From 263286e6a00b8e02a41ee7ff4641525a7925f875 Mon Sep 17 00:00:00 2001 From: Kim Gustyr Date: Wed, 27 Mar 2024 16:56:37 +0000 Subject: [PATCH 1/2] feat: Identity overrides in local evaluation mode --- src/Engine/Environments/EnvironmentModel.php | 12 +++------ src/Engine/Utils/Collections/IdentityList.php | 18 +++++++++++++ src/Flagsmith.php | 20 +++++++++------ tests/Data/environment.json | 25 +++++++++++++++++++ tests/FlagsmithClientTest.php | 15 +++++++++++ 5 files changed, 75 insertions(+), 15 deletions(-) create mode 100644 src/Engine/Utils/Collections/IdentityList.php diff --git a/src/Engine/Environments/EnvironmentModel.php b/src/Engine/Environments/EnvironmentModel.php index 5bc17d7..37e1752 100644 --- a/src/Engine/Environments/EnvironmentModel.php +++ b/src/Engine/Environments/EnvironmentModel.php @@ -6,7 +6,9 @@ use Flagsmith\Concerns\JsonSerializer; use Flagsmith\Engine\Environments\Integrations\IntegrationModel; use Flagsmith\Engine\Projects\ProjectModel; +use Flagsmith\Engine\Identities\IdentityModel; use Flagsmith\Engine\Utils\Collections\FeatureStateModelList; +use Flagsmith\Engine\Utils\Collections\IdentityList; #[\AllowDynamicProperties] class EnvironmentModel @@ -16,17 +18,11 @@ class EnvironmentModel public int $id; public string $api_key; public FeatureStateModelList $feature_states; - public IntegrationModel $segment_config; - public IntegrationModel $heap_config; - public IntegrationModel $mixpanel_config; - public IntegrationModel $amplitude_config; + public IdentityList $identity_overrides; public ProjectModel $project; private array $keys = [ + 'identity_overrides' => 'Flagsmith\Engine\Utils\Collections\IdentityList', 'feature_states' => 'Flagsmith\Engine\Utils\Collections\FeatureStateModelList', - 'segment_config' => 'Flagsmith\Engine\Environments\Integrations\IntegrationModel', - 'heap_config' => 'Flagsmith\Engine\Environments\Integrations\IntegrationModel', - 'mixpanel_config' => 'Flagsmith\Engine\Environments\Integrations\IntegrationModel', - 'amplitude_config' => 'Flagsmith\Engine\Environments\Integrations\IntegrationModel', 'project' => 'Flagsmith\Engine\Projects\ProjectModel', ]; diff --git a/src/Engine/Utils/Collections/IdentityList.php b/src/Engine/Utils/Collections/IdentityList.php new file mode 100644 index 0000000..0fb92bd --- /dev/null +++ b/src/Engine/Utils/Collections/IdentityList.php @@ -0,0 +1,18 @@ +identifier, $value); + } +} diff --git a/src/Flagsmith.php b/src/Flagsmith.php index 08b3dbd..2e7d2a1 100644 --- a/src/Flagsmith.php +++ b/src/Flagsmith.php @@ -327,7 +327,7 @@ public function getIdentitySegments(string $identifier, ?object $traits = null): } $traits = $traits ?? (object)[]; - $identityModel = $this->buildIdentityModel($identifier, $traits); + $identityModel = $this->getIdentityModel($identifier, $traits); $segmentModels = SegmentEvaluator::getIdentitySegments($this->environment, $identityModel); return array_map(fn ($segment) => (new Segment()) @@ -384,7 +384,7 @@ private function getEnvironmentFlagsFromDocument(): Flags */ private function getIdentityFlagsFromDocument(string $identifier, object $traits): Flags { - $identityModel = $this->buildIdentityModel($identifier, $traits); + $identityModel = $this->getIdentityModel($identifier, $traits); $featureStates = Engine::getIdentityFeatureStates($this->environment, $identityModel); return Flags::fromFeatureStateModels( @@ -461,7 +461,7 @@ private function getIdentityFlagsFromApi(string $identifier, ?object $traits): F * * @throws FlagsmithClientError */ - private function buildIdentityModel(string $identifier, ?object $traits): IdentityModel + private function getIdentityModel(string $identifier, ?object $traits): IdentityModel { if (empty($this->environment)) { throw new FlagsmithClientError('Unable to build identity model when no local environment present.'); @@ -474,10 +474,16 @@ private function buildIdentityModel(string $identifier, ?object $traits): Identi ->withTraitValue($value); } - return (new IdentityModel()) - ->withIdentifier($identifier) - ->withEnvironmentApiKey($this->apiKey) - ->withIdentityTraits(new IdentityTraitList($traitModels)); + $identityModel = isset($this->environment->identity_overrides) ? $this->environment->identity_overrides[$identifier] ?? null : null; + + if (is_null($identityModel)) { + return (new IdentityModel()) + ->withIdentifier($identifier) + ->withEnvironmentApiKey($this->apiKey) + ->withIdentityTraits(new IdentityTraitList($traitModels)); + } + + return $identityModel->withIdentityTraits(new IdentityTraitList($traitModels)); } /** diff --git a/tests/Data/environment.json b/tests/Data/environment.json index aa0e060..00ca0b0 100644 --- a/tests/Data/environment.json +++ b/tests/Data/environment.json @@ -52,5 +52,30 @@ "segment_id": null, "enabled": true } + ], + "identity_overrides": [ + { + "identifier": "overridden-id", + "identity_uuid": "0f21cde8-63c5-4e50-baca-87897fa6cd01", + "created_date": "2019-08-27T14:53:45.698555Z", + "updated_at": "2023-07-14 16:12:00.000000", + "environment_api_key": "B62qaMZNwfiqT76p38ggrQ", + "identity_features": [ + { + "id": 1, + "feature": { + "id": 1, + "name": "some_feature", + "type": "STANDARD" + }, + "featurestate_uuid": "1bddb9a5-7e59-42c6-9be9-625fa369749f", + "feature_state_value": "some-overridden-value", + "enabled": false, + "environment": 1, + "identity": null, + "feature_segment": null + } + ] + } ] } \ No newline at end of file diff --git a/tests/FlagsmithClientTest.php b/tests/FlagsmithClientTest.php index 24900ad..5b61683 100644 --- a/tests/FlagsmithClientTest.php +++ b/tests/FlagsmithClientTest.php @@ -279,4 +279,19 @@ public function testGetIdentitySegmentsWithValidTrait() $this->assertEquals($segments[0]->getName(), 'Test segment'); } } + + public function testLocalEvaluationGetIdentityOverride() + { + foreach (ClientFixtures::localEvalFlagsmith() as $flagsmith) { + $identifier = 'overridden-id'; + $featureName = 'some_feature'; + + $identityFlags = $flagsmith->getIdentityFlags($identifier); + + $flag = $identityFlags->getFlag($featureName); + + $this->assertEquals($flag->enabled, false); + $this->assertEquals($flag->value, 'some-overridden-value'); + } + } } From 094ad9531d3f71ffe9301ce88c46c1acdd456a22 Mon Sep 17 00:00:00 2001 From: Kim Gustyr Date: Wed, 27 Mar 2024 16:58:41 +0000 Subject: [PATCH 2/2] formatting --- src/Engine/Utils/Collections/IdentityList.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Engine/Utils/Collections/IdentityList.php b/src/Engine/Utils/Collections/IdentityList.php index 0fb92bd..d2e4e45 100644 --- a/src/Engine/Utils/Collections/IdentityList.php +++ b/src/Engine/Utils/Collections/IdentityList.php @@ -12,7 +12,8 @@ class IdentityList extends \ArrayObject implements \JsonSerializable * @param IdentityModel $value * @return void */ - public function offsetSet($offset, $value): void { + public function offsetSet($offset, $value): void + { parent::offsetSet($value->identifier, $value); } }