Skip to content

Commit 66435a6

Browse files
authored
feat(Local evaluation): Use the new context-based engine (#109)
* Introduce context values evaluation data model * Update engine test data * Get ready for engine tests * Introduce new engine * Lint ✨ * Make priority clearer * Update EvaluationResult spec Contributes to Flagsmith/flagsmith#6121 * yay * Fix identity traits data type * WIP: First pass at using the new engine * Update engine test data branch * Let's talk, environment document * Fix the toolbox * Fix identity as an optional context * Improve API * Fix the talking * Fix local evaluation setting * Fix cloning contexts * Make it easier to test private members * Delete outdated code * Make sure getEnvironmentFlags now works as expected * Make code reusable * Apples will never be bananas * Found the key * Connect all the dots * Please run tests * Stop wasting cycles * Revert API changes in the offline handler * Revert "Stop wasting cycles" This reverts commit a52c914. * Prevent us from deleting code we don't understand * Fix casting * Improve clarity * Track TODO with an issue #110 * Improve type handling in the IN operator * Make MODULO check less prone to error * Fix obtaining a context value * Update comment to latest reality * Delete skippable code * Update test cases * Fix tests * Carry segment metadata around * Please run tests (cherry picked from commit 2913611) * Map segment metadata from the environment context * Comply with latest test data * Ensure variants are selected consistently * To each their responsibilities * Update tests * Respect historical variant priority (UUID-based) * Improve architecture with feature metadata * Fix virtual segments bleeding to the client
1 parent 4cb3481 commit 66435a6

File tree

17 files changed

+655
-123
lines changed

17 files changed

+655
-123
lines changed

.gitmodules

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
[submodule "tests/Engine/EngineTests/EngineTestData"]
22
path = tests/Engine/EngineTests/EngineTestData
33
url = git@github.com:Flagsmith/engine-test-data.git
4-
tag = v2.4.0
4+
tag = v2.5.0

src/Engine/Engine.php

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ public static function getEvaluationResult($context): EvaluationResult
5757
$segmentResult = new SegmentResult();
5858
$segmentResult->key = $segment->key;
5959
$segmentResult->name = $segment->name;
60-
$segmentResult->metadata = $segment->metadata ?? null;
60+
$segmentResult->metadata = $segment->metadata;
6161
$evaluatedSegments[] = $segmentResult;
6262

6363
foreach ($segment->overrides as $overrideFeature) {
@@ -152,6 +152,7 @@ private static function getFlagResultFromFeatureContext($feature, $splitKey)
152152
$flag->enabled = $feature->enabled;
153153
$flag->value = $variant->value;
154154
$flag->reason = "SPLIT; weight={$variant->weight}";
155+
$flag->metadata = $feature->metadata;
155156
return $flag;
156157
}
157158
$startPercentage = $limit;
@@ -164,6 +165,7 @@ private static function getFlagResultFromFeatureContext($feature, $splitKey)
164165
$flag->enabled = $feature->enabled;
165166
$flag->value = $feature->value;
166167
$flag->reason = 'DEFAULT';
168+
$flag->metadata = $feature->metadata;
167169
return $flag;
168170
}
169171

@@ -180,6 +182,7 @@ private static function getFlagResultFromSegmentContext($feature, $segment)
180182
$flag->enabled = $feature->enabled;
181183
$flag->value = $feature->value;
182184
$flag->reason = "TARGETING_MATCH; segment={$segment->name}";
185+
$flag->metadata = $feature->metadata;
183186
return $flag;
184187
}
185188

src/Engine/Features/FeatureStateModel.php

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ class FeatureStateModel
1717

1818
public FeatureModel $feature;
1919
public bool $enabled;
20-
private $_value;
20+
public mixed $feature_state_value;
2121
public string $featurestate_uuid;
2222
public MultivariateFeatureStateValueModelList $multivariate_feature_state_values;
2323
public ?int $django_id = null;
@@ -157,7 +157,7 @@ public function getValue($identityId = null)
157157
if ($identityId && count($this->multivariate_feature_state_values) > 0) {
158158
return $this->getMultivariateValue($identityId);
159159
}
160-
return $this->_value;
160+
return $this->feature_state_value;
161161
}
162162

163163
/**
@@ -207,7 +207,7 @@ function (
207207
$startPercentage = $limit;
208208
}
209209

210-
return $this->_value;
210+
return $this->feature_state_value;
211211
}
212212

213213
/**
@@ -217,7 +217,7 @@ function (
217217
*/
218218
public function setValue($value)
219219
{
220-
$this->_value = $value;
220+
$this->feature_state_value = $value;
221221
}
222222

223223

@@ -232,7 +232,7 @@ protected function setValues($values)
232232
unset($values->feature_state_value);
233233
$this->setValuesSerializer($values);
234234
if (!empty($featureStateValue)) {
235-
$this->_value = $featureStateValue;
235+
$this->feature_state_value = $featureStateValue;
236236
}
237237
}
238238

src/Engine/Utils/Types/Context/EvaluationContext.php

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ public static function fromJsonObject($jsonContext)
3636
}
3737

3838
$context->segments = [];
39-
foreach ($jsonContext->segments as $jsonSegment) {
39+
foreach (($jsonContext->segments ?? []) as $jsonSegment) {
4040
$segment = new SegmentContext();
4141
$segment->key = $jsonSegment->key;
4242
$segment->name = $jsonSegment->name;
@@ -51,6 +51,15 @@ public static function fromJsonObject($jsonContext)
5151
return $context;
5252
}
5353

54+
/**
55+
* Deep clone the EvaluationContext
56+
* @return EvaluationContext
57+
*/
58+
public function deepClone(): self
59+
{
60+
return EvaluationContext::fromJsonObject($this);
61+
}
62+
5463
/**
5564
* @param array<object> $jsonRules
5665
* @return array<SegmentRule>
@@ -60,15 +69,17 @@ private static function _convertRules($jsonRules)
6069
$rules = [];
6170
foreach ($jsonRules as $jsonRule) {
6271
$rule = new SegmentRule();
63-
$rule->type = SegmentRuleType::from($jsonRule->type);
72+
$rule->type = $jsonRule->type instanceof SegmentRuleType
73+
? $jsonRule->type
74+
: SegmentRuleType::from($jsonRule->type);
6475

6576
$rule->conditions = [];
6677
foreach ($jsonRule->conditions ?? [] as $jsonCondition) {
6778
$condition = new SegmentCondition();
6879
$condition->property = $jsonCondition->property;
69-
$condition->operator = SegmentConditionOperator::from(
70-
$jsonCondition->operator,
71-
);
80+
$condition->operator = $jsonCondition->operator instanceof SegmentConditionOperator
81+
? $jsonCondition->operator
82+
: SegmentConditionOperator::from($jsonCondition->operator);
7283
$condition->value = $jsonCondition->value;
7384
$rule->conditions[] = $condition;
7485
}
@@ -93,11 +104,12 @@ private static function _convertFeatures($jsonFeatures): array
93104
foreach ($jsonFeatures as $jsonFeature) {
94105
$feature = new FeatureContext();
95106
$feature->key = $jsonFeature->key;
96-
$feature->feature_key = $jsonFeature->feature_key;
107+
$feature->feature_key = (string) $jsonFeature->feature_key;
97108
$feature->name = $jsonFeature->name;
98109
$feature->enabled = $jsonFeature->enabled;
99110
$feature->value = $jsonFeature->value;
100111
$feature->priority = $jsonFeature->priority ?? null;
112+
$feature->metadata = (array) ($jsonFeature->metadata ?? []);
101113
$feature->variants = [];
102114
foreach ($jsonFeature->variants ?? [] as $jsonVariant) {
103115
$variant = new FeatureValue();

src/Engine/Utils/Types/Context/FeatureContext.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,4 +24,7 @@ class FeatureContext
2424

2525
/** @var array<FeatureValue> */
2626
public $variants;
27+
28+
/** @var ?array<string,mixed> */
29+
public $metadata;
2730
}

src/Engine/Utils/Types/Result/FlagResult.php

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
namespace Flagsmith\Engine\Utils\Types\Result;
44

5-
class FlagResult
5+
class FlagResult implements \JsonSerializable
66
{
77
/** @var string */
88
public $feature_key;
@@ -18,4 +18,19 @@ class FlagResult
1818

1919
/** @var ?string */
2020
public $reason;
21+
22+
/** @var ?array<string,mixed> */
23+
public $metadata;
24+
25+
public function jsonSerialize(): array
26+
{
27+
$data = get_object_vars($this);
28+
29+
// 'metadata' is only added if there is any
30+
if (empty($this->metadata)) {
31+
unset($data['metadata']);
32+
}
33+
34+
return $data;
35+
}
2136
}

src/Engine/Utils/Types/Result/SegmentResult.php

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,11 @@ class SegmentResult implements \JsonSerializable
1515

1616
public function jsonSerialize(): array
1717
{
18-
$data = [
19-
'key' => $this->key,
20-
'name' => $this->name,
21-
];
18+
$data = get_object_vars($this);
2219

2320
// 'metadata' is only added if there is any
24-
if (!empty($this->metadata)) {
25-
$data['metadata'] = $this->metadata;
21+
if (empty($this->metadata)) {
22+
unset($data['metadata']);
2623
}
2724

2825
return $data;

0 commit comments

Comments
 (0)