Skip to content

Commit 42c1ff2

Browse files
authored
Merge pull request #28 from launchdarkly/eb/ch12124/client-side-filter
add ability to filter for client-side flags only
2 parents c1ac079 + fd08375 commit 42c1ff2

File tree

3 files changed

+55
-3
lines changed

3 files changed

+55
-3
lines changed

src/LaunchDarkly/FeatureFlag.php

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,9 @@ class FeatureFlag
3131
protected $_trackEvents = false;
3232
/** @var int | null */
3333
protected $_debugEventsUntilDate = null;
34+
/** @var bool */
35+
protected $_clientSide = false;
36+
3437
// Note, trackEvents and debugEventsUntilDate are not used in EventProcessor, because
3538
// the PHP client doesn't do summary events. However, we need to capture them in case
3639
// they want to pass the flag data to the front end with allFlagsState().
@@ -47,7 +50,8 @@ protected function __construct($key,
4750
array $variations,
4851
$deleted,
4952
$trackEvents,
50-
$debugEventsUntilDate)
53+
$debugEventsUntilDate,
54+
$clientSide)
5155
{
5256
$this->_key = $key;
5357
$this->_version = $version;
@@ -62,6 +66,7 @@ protected function __construct($key,
6266
$this->_deleted = $deleted;
6367
$this->_trackEvents = $trackEvents;
6468
$this->_debugEventsUntilDate = $debugEventsUntilDate;
69+
$this->_clientSide = $clientSide;
6570
}
6671

6772
public static function getDecoder()
@@ -80,7 +85,8 @@ public static function getDecoder()
8085
$v['variations'] ?: [],
8186
$v['deleted'],
8287
isset($v['trackEvents']) && $v['trackEvents'],
83-
isset($v['debugEventsUntilDate']) ? $v['debugEventsUntilDate'] : null
88+
isset($v['debugEventsUntilDate']) ? $v['debugEventsUntilDate'] : null,
89+
isset($v['clientSide']) && $v['clientSide']
8490
);
8591
};
8692
}
@@ -252,4 +258,12 @@ public function getDebugEventsUntilDate()
252258
{
253259
return $this->_debugEventsUntilDate;
254260
}
261+
262+
/**
263+
* @return boolean
264+
*/
265+
public function isClientSide()
266+
{
267+
return $this->_clientSide;
268+
}
255269
}

src/LaunchDarkly/LDClient.php

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -282,9 +282,12 @@ public function allFlags($user)
282282
* The most common use case for this method is to bootstrap a set of client-side feature flags from a back-end service.
283283
* To convert the state object into a JSON data structure, call its toJson() method.
284284
* @param $user LDUser the end user requesting the feature flags
285+
* @param $options array optional properties affecting how the state is computed; set
286+
* <code>'clientSideOnly' => true</code> to specify that only flags marked for client-side use
287+
* should be included (by default, all flags are included)
285288
* @return FeatureFlagsState a FeatureFlagsState object (will never be null; see FeatureFlagsState.isValid())
286289
*/
287-
public function allFlagsState($user)
290+
public function allFlagsState($user, $options = array())
288291
{
289292
if (is_null($user) || is_null($user->getKey())) {
290293
$this->_logger->warn("allFlagsState called with null user or null/empty user key! Returning empty state");
@@ -304,7 +307,11 @@ public function allFlagsState($user)
304307
}
305308

306309
$state = new FeatureFlagsState(true);
310+
$clientOnly = isset($options['clientSideOnly']) && $options['clientSideOnly'];
307311
foreach ($flags as $key => $flag) {
312+
if ($clientOnly && !$flag->isClientSide()) {
313+
continue;
314+
}
308315
$result = $flag->evaluate($user, $this->_featureRequester);
309316
$state->addFlag($flag, $result);
310317
}

tests/LDClientTest.php

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,37 @@ public function testAllFlagsStateReturnsState()
164164
$this->assertEquals($expectedState, $state->jsonSerialize());
165165
}
166166

167+
public function testAllFlagsStateCanFilterForClientSideFlags()
168+
{
169+
$flagJson = array('key' => 'server-side-1', 'version' => 1, 'on' => false, 'salt' => '', 'deleted' => false,
170+
'targets' => array(), 'rules' => array(), 'prerequisites' => array(), 'fallthrough' => array(),
171+
'offVariation' => 0, 'variations' => array('a'), 'clientSide' => false);
172+
$flag1 = FeatureFlag::decode($flagJson);
173+
$flagJson['key'] = 'server-side-2';
174+
$flag2 = FeatureFlag::decode($flagJson);
175+
$flagJson['key'] = 'client-side-1';
176+
$flagJson['clientSide'] = true;
177+
$flagJson['variations'] = array('value1');
178+
$flag3 = FeatureFlag::decode($flagJson);
179+
$flagJson['key'] = 'client-side-2';
180+
$flagJson['variations'] = array('value2');
181+
$flag4 = FeatureFlag::decode($flagJson);
182+
MockFeatureRequester::$flags = array(
183+
$flag1->getKey() => $flag1, $flag2->getKey() => $flag2, $flag3->getKey() => $flag3, $flag4->getKey() => $flag4
184+
);
185+
$client = new LDClient("someKey", array(
186+
'feature_requester_class' => MockFeatureRequester::class,
187+
'events' => false
188+
));
189+
190+
$builder = new LDUserBuilder(3);
191+
$user = $builder->build();
192+
$state = $client->allFlagsState($user, array('clientSideOnly' => true));
193+
194+
$this->assertTrue($state->isValid());
195+
$this->assertEquals(array('client-side-1' => 'value1', 'client-side-2' => 'value2'), $state->toValuesMap());
196+
}
197+
167198
public function testOnlyValidFeatureRequester()
168199
{
169200
$this->setExpectedException(InvalidArgumentException::class);

0 commit comments

Comments
 (0)