Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .gitmodules
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
[submodule "tests/Engine/EngineTests/EngineTestData"]
path = tests/Engine/EngineTests/EngineTestData
url = git@github.com:Flagsmith/engine-test-data.git
tag = v2.5.0
tag = v3.2.1
Binary file added composer.phar
Binary file not shown.
36 changes: 23 additions & 13 deletions src/Engine/Engine.php
Original file line number Diff line number Diff line change
Expand Up @@ -44,25 +44,26 @@ public static function getEvaluationResult($context): EvaluationResult
$evaluatedFeatures = [];

/** @var array<string, SegmentContext> */
$matchedSegmentsByFeatureKey = [];
$matchedSegmentsByFeatureName = [];

/** @var array<string, FlagResult> */
$evaluatedFlags = [];

self::enrichContext($context);

foreach ($context->segments as $segment) {
if (!self::isContextInSegment($context, $segment)) {
continue;
}

$segmentResult = new SegmentResult();
$segmentResult->key = $segment->key;
$segmentResult->name = $segment->name;
$segmentResult->metadata = $segment->metadata;
$evaluatedSegments[] = $segmentResult;

foreach ($segment->overrides as $overrideFeature) {
$featureKey = $overrideFeature->feature_key;
$evaluatedFeature = $evaluatedFeatures[$featureKey] ?? null;
$featureName = $overrideFeature->name;
$evaluatedFeature = $evaluatedFeatures[$featureName] ?? null;
if ($evaluatedFeature) {
$overrideWinsPriority =
($overrideFeature->priority ?? self::WEAKEST_PRIORITY) <
Expand All @@ -72,19 +73,18 @@ public static function getEvaluationResult($context): EvaluationResult
}
}

$evaluatedFeatures[$featureKey] = $overrideFeature;
$matchedSegmentsByFeatureKey[$featureKey] = $segment;
$evaluatedFeatures[$featureName] = $overrideFeature;
$matchedSegmentsByFeatureName[$featureName] = $segment;
}
}

foreach ($context->features as $feature) {
$featureKey = $feature->feature_key;
$featureName = $feature->name;
$evaluatedFeature = $evaluatedFeatures[$featureKey] ?? null;
$evaluatedFeature = $evaluatedFeatures[$featureName] ?? null;
if ($evaluatedFeature) {
$evaluatedFlags[$featureName] = self::getFlagResultFromSegmentContext(
$evaluatedFeature,
$matchedSegmentsByFeatureKey[$featureKey],
$matchedSegmentsByFeatureName[$featureName],
);
continue;
}
Expand All @@ -101,6 +101,19 @@ public static function getEvaluationResult($context): EvaluationResult
return $result;
}

/**
* Enrich the evaluation context with derived values:
* - `$.identity.key` if missing
* @param EvaluationContext $context
* @return void
*/
private static function enrichContext(EvaluationContext $context): void
{
if ($context->identity !== null && $context->identity->key === null) {
$context->identity->key = "{$context->environment->key}_{$context->identity->identifier}";
}
}

/**
* @param EvaluationContext $context
* @param SegmentContext $segment
Expand Down Expand Up @@ -147,7 +160,6 @@ private static function getFlagResultFromFeatureContext($feature, $splitKey)
$percentageValue < $limit
) {
$flag = new FlagResult();
$flag->feature_key = $feature->feature_key;
$flag->name = $feature->name;
$flag->enabled = $feature->enabled;
$flag->value = $variant->value;
Expand All @@ -160,7 +172,6 @@ private static function getFlagResultFromFeatureContext($feature, $splitKey)
}

$flag = new FlagResult();
$flag->feature_key = $feature->feature_key;
$flag->name = $feature->name;
$flag->enabled = $feature->enabled;
$flag->value = $feature->value;
Expand All @@ -177,7 +188,6 @@ private static function getFlagResultFromFeatureContext($feature, $splitKey)
private static function getFlagResultFromSegmentContext($feature, $segment)
{
$flag = new FlagResult();
$flag->feature_key = $feature->feature_key;
$flag->name = $feature->name;
$flag->enabled = $feature->enabled;
$flag->value = $feature->value;
Expand Down Expand Up @@ -259,7 +269,7 @@ private static function _contextMatchesCondition(

switch ($condition->operator) {
case SegmentConditionOperator::IN:
if ($contextValue === null) {
if ($contextValue === null || gettype($contextValue) === 'boolean') {
Comment thread
khvn26 marked this conversation as resolved.
return false;
}
if (is_array($condition->value)) {
Expand Down
1 change: 0 additions & 1 deletion src/Engine/Utils/Types/Context/EvaluationContext.php
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,6 @@ private static function _convertFeatures($jsonFeatures): array
foreach ($jsonFeatures as $jsonFeature) {
$feature = new FeatureContext();
$feature->key = $jsonFeature->key;
$feature->feature_key = (string) $jsonFeature->feature_key;
$feature->name = $jsonFeature->name;
$feature->enabled = $jsonFeature->enabled;
$feature->value = $jsonFeature->value;
Expand Down
3 changes: 0 additions & 3 deletions src/Engine/Utils/Types/Context/FeatureContext.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,6 @@ class FeatureContext
/** @var string */
public $key;

/** @var string */
public $feature_key;

/** @var string */
public $name;

Expand Down
3 changes: 0 additions & 3 deletions src/Engine/Utils/Types/Result/FlagResult.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,6 @@

class FlagResult implements \JsonSerializable
{
/** @var string */
public $feature_key;

/** @var string */
public $name;

Expand Down
3 changes: 0 additions & 3 deletions src/Engine/Utils/Types/Result/SegmentResult.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,6 @@

class SegmentResult implements \JsonSerializable
{
/** @var string */
public $key;

/** @var string */
public $name;

Expand Down
3 changes: 0 additions & 3 deletions src/Utils/Mappers.php
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,6 @@ public static function mapContextAndIdentityToContext($context, $identifier, $tr
{
$identity = new IdentityContext();
$identity->identifier = $identifier;
$identity->key = "{$context->environment->key}_{$identifier}";
$identity->traits = (array) $traits;

$context = $context->deepClone();
Expand Down Expand Up @@ -112,7 +111,6 @@ private static function _mapEnvironmentDocumentFeatureStatesToFeatureContexts($f
foreach ($featureStates as $featureState) {
$feature = new FeatureContext();
$feature->key = (string) ($featureState->django_id ?? $featureState->featurestate_uuid);
$feature->feature_key = (string) $featureState->feature->id;
$feature->name = $featureState->feature->name;
$feature->enabled = $featureState->enabled;
$feature->value = $featureState->feature_state_value;
Expand Down Expand Up @@ -190,7 +188,6 @@ private static function _mapIdentityOverridesToSegments($identityOverrides)
[$featureId, $featureName, $enabled, $value] = $overrideKey;
$feature = new FeatureContext();
$feature->key = ''; // Not used in identity overrides
$feature->feature_key = (string) $featureId;
$feature->name = $featureName;
$feature->enabled = $enabled;
$feature->value = $value;
Expand Down
2 changes: 1 addition & 1 deletion tests/Engine/EngineTests/EngineTestData
Submodule EngineTestData updated 158 files
32 changes: 0 additions & 32 deletions tests/Utils/MappersTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,6 @@ public function testMapEnvironmentDocumentToContextProducesEvaluationContext():
$this->assertEquals(['overridden-id'], $context->segments[$overrideKey]->rules[0]->conditions[0]->value);

$this->assertEquals('', $context->segments[$overrideKey]->overrides[0]->key);
$this->assertEquals(1, $context->segments[$overrideKey]->overrides[0]->feature_key);
$this->assertEquals('some_feature', $context->segments[$overrideKey]->overrides[0]->name);
$this->assertFalse($context->segments[$overrideKey]->overrides[0]->enabled);
$this->assertEquals('some-overridden-value', $context->segments[$overrideKey]->overrides[0]->value);
Expand All @@ -74,7 +73,6 @@ public function testMapEnvironmentDocumentToContextProducesEvaluationContext():
$this->assertCount(3, $context->features);
$this->assertArrayHasKey('some_feature', $context->features);
$this->assertEquals('00000000-0000-0000-0000-000000000000', $context->features['some_feature']->key);
$this->assertEquals('1', $context->features['some_feature']->feature_key);
$this->assertEquals('some_feature', $context->features['some_feature']->name);
$this->assertTrue($context->features['some_feature']->enabled);
$this->assertEquals('some-value', $context->features['some_feature']->value);
Expand All @@ -86,7 +84,6 @@ public function testMapEnvironmentDocumentToContextProducesEvaluationContext():
$this->assertArrayHasKey('mv_feature_with_ids', $context->features);
$mvFeatureWithIds = $context->features['mv_feature_with_ids'];
$this->assertEquals('2', $mvFeatureWithIds->key);
$this->assertEquals('2', $mvFeatureWithIds->feature_key);
$this->assertEquals('mv_feature_with_ids', $mvFeatureWithIds->name);
$this->assertTrue($mvFeatureWithIds->enabled);
$this->assertEquals('default_value', $mvFeatureWithIds->value);
Expand All @@ -108,7 +105,6 @@ public function testMapEnvironmentDocumentToContextProducesEvaluationContext():
$this->assertArrayHasKey('mv_feature_without_ids', $context->features);
$mvFeatureWithoutIds = $context->features['mv_feature_without_ids'];
$this->assertEquals('3', $mvFeatureWithoutIds->key);
$this->assertEquals('3', $mvFeatureWithoutIds->feature_key);
$this->assertEquals('mv_feature_without_ids', $mvFeatureWithoutIds->name);
$this->assertFalse($mvFeatureWithoutIds->enabled);
$this->assertEquals('fallback_value', $mvFeatureWithoutIds->value);
Expand All @@ -127,32 +123,4 @@ public function testMapEnvironmentDocumentToContextProducesEvaluationContext():
$this->assertEquals(25.0, $mvFeatureWithoutIds->variants[2]->weight);
$this->assertEquals(2, $mvFeatureWithoutIds->variants[2]->priority); // Third
}

public function testMapContextAndIdentityToContextProducesEvaluationContextWithIdentity(): void
{
// Given
$originalContext = new EvaluationContext();
$originalContext->environment = new EnvironmentContext();
$originalContext->environment->key = 'public-env-key';

// When
$context = Mappers::mapContextAndIdentityToContext(
context: $originalContext,
identifier: 'neo',
traits: (object) [
'chosen-pill' => 'red',
'has-met-the-oracle' => true,
],
);

// Then
$this->assertInstanceOf(EvaluationContext::class, $context);
$this->assertNotSame($originalContext, $context);
$this->assertEquals('public-env-key', $context->environment->key);
$this->assertEquals('neo', $context->identity->identifier);
$this->assertEquals('public-env-key_neo', $context->identity->key);
$this->assertCount(2, $context->identity->traits);
$this->assertEquals('red', $context->identity->traits['chosen-pill']);
$this->assertTrue($context->identity->traits['has-met-the-oracle']);
}
}