Skip to content

Commit 54676f1

Browse files
Fix segment priorities (#24)
* Fix segment priorities * Formatting * Remove unnecessary includes * Slight simplification * fix typo
1 parent 1df2563 commit 54676f1

File tree

5 files changed

+117
-1
lines changed

5 files changed

+117
-1
lines changed

src/Engine/Engine.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,12 @@ private static function _getIdentityFeatureStatesDict(
139139

140140
foreach ($identitySegments as $is) {
141141
foreach ($is->getFeatureStates() as $fs) {
142+
$feature = $fs->getFeature();
143+
$existing = $featureStates[$feature->getName()];
144+
if ($existing != null && $existing->isHigherPriority($fs)) {
145+
continue;
146+
}
147+
142148
$featureStates[$fs->getFeature()->getName()] = $fs;
143149
}
144150
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
<?php
2+
3+
namespace Flagsmith\Engine\Features;
4+
5+
use Flagsmith\Concerns\HasWith;
6+
use Flagsmith\Concerns\JsonSerializer;
7+
8+
class FeatureSegmentModel
9+
{
10+
use HasWith;
11+
use JsonSerializer;
12+
13+
public int $priority;
14+
15+
/**
16+
* Get priority.
17+
* @return int
18+
*/
19+
public function getPriority(): int
20+
{
21+
return $this->priority;
22+
}
23+
24+
/**
25+
* Build with priority.
26+
* @param int $priority
27+
* @return FeatureSegmentModel
28+
*/
29+
public function withPriority(int $priority): self
30+
{
31+
return $this->with('priority', $priority);
32+
}
33+
}

src/Engine/Features/FeatureStateModel.php

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,12 @@ class FeatureStateModel
2020
public string $featurestate_uuid;
2121
public MultivariateFeatureStateValueModelList $multivariate_feature_state_values;
2222
public ?int $django_id = null;
23+
public ?FeatureSegmentModel $feature_segment = null;
2324

2425
private array $keys = [
2526
'feature' => 'Flagsmith\Engine\Features\FeatureModel',
2627
'multivariate_feature_state_values' => 'Flagsmith\Engine\Utils\Collections\MultivariateFeatureStateValueModelList',
28+
'feature_segment' => 'Flagsmith\Engine\Features\FeatureSegmentModel',
2729
];
2830

2931
public function __construct()
@@ -127,6 +129,25 @@ public function withFeaturestateUuid(string $featurestateUuid): self
127129
return $this->with('featurestate_uuid', $featurestateUuid);
128130
}
129131

132+
/**
133+
* get the feature ssegment.
134+
* @return FeatureSegmentModel
135+
*/
136+
public function getFeatureSegment(): ?FeatureSegmentModel
137+
{
138+
return $this->feature_segment;
139+
}
140+
141+
/**
142+
* build with a feature segment model.
143+
* @param FeatureSegmentModel $featureSegment
144+
* @return FeatureStateModel
145+
*/
146+
public function withFeatureSegment(?FeatureSegmentModel $featureSegment): self
147+
{
148+
return $this->with('feature_segment', $featureSegment);
149+
}
150+
130151
/**
131152
* get the value.
132153
*/
@@ -213,4 +234,22 @@ protected function setValues($values)
213234
$this->_value = $featureStateValue;
214235
}
215236
}
237+
238+
/**
239+
* Another FeatureStateModel is deemed to be higher priority if and only if
240+
* it has a FeatureSegment and either this.FeatureSegment is null or the
241+
* value of other.FeatureSegment.priority is lower than that of
242+
* this.FeatureSegment.priority.
243+
*
244+
* @param FeatureStateModel $other - the other FeatureStateModel to compare priority with
245+
* @return bool - true if `this` is higher priority than `other`
246+
*/
247+
public function isHigherPriority(FeatureStateModel $other): bool
248+
{
249+
if ($this->getFeatureSegment() == null || $other->getFeatureSegment() == null) {
250+
return ($this->getFeatureSegment() != null && $other->getFeatureSegment() == null);
251+
}
252+
253+
return $this->getFeatureSegment()->getPriority() < $other->getFeatureSegment()->getPriority();
254+
}
216255
}

tests/Engine/Unit/Features/FeatureModelsTest.php

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
<?php
22

33
use Flagsmith\Engine\Features\FeatureModel;
4+
use Flagsmith\Engine\Features\FeatureSegmentModel;
45
use Flagsmith\Engine\Features\FeatureStateModel;
56
use Flagsmith\Engine\Features\FeatureTypes;
67
use Flagsmith\Engine\Features\MultivariateFeatureOptionModel;
@@ -146,4 +147,41 @@ public function testGetValueUsesFeatuestateUuidForMultivariateValueCalculationIf
146147
// validation in with()
147148
$this->assertTrue(true);
148149
}
150+
151+
public function testIsHigherPriorityReturnsFalseForTwoNullFeatureSegments()
152+
{
153+
// Given
154+
$featureState1 = (new FeatureStateModel())
155+
->withFeatureSegment(null);
156+
$featureState2 = (new FeatureStateModel())
157+
->withFeatureSegment(null);
158+
159+
// Then
160+
$this->assertFalse($featureState1->isHigherPriority($featureState2));
161+
$this->assertFalse($featureState2->isHigherPriority($featureState1));
162+
}
163+
164+
public function testIsHigherPriorityReturnsTrueWhenOtherFeatureStateHasNullFeatureSegment()
165+
{
166+
// Given
167+
$featureState1 = (new FeatureStateModel())
168+
->withFeatureSegment((new FeatureSegmentModel())->withPriority(0));
169+
$featureState2 = (new FeatureStateModel())
170+
->withFeatureSegment(null);
171+
172+
// Then
173+
$this->assertTrue($featureState1->isHigherPriority($featureState2));
174+
}
175+
176+
public function testIsHigherPriorityReturnsTrueWhenOtherFeatureStateHasLowerPriorityFeatureSegment()
177+
{
178+
// Given
179+
$featureState1 = (new FeatureStateModel())
180+
->withFeatureSegment((new FeatureSegmentModel())->withPriority(0));
181+
$featureState2 = (new FeatureStateModel())
182+
->withFeatureSegment((new FeatureSegmentModel())->withPriority(1));
183+
184+
// Then
185+
$this->assertTrue($featureState1->isHigherPriority($featureState2));
186+
}
149187
}

0 commit comments

Comments
 (0)