Skip to content

Commit d1571bd

Browse files
authored
feat: Support transient identities and traits (#78)
* feat: Support transient identities and traits
1 parent 956eb0b commit d1571bd

4 files changed

Lines changed: 66 additions & 19 deletions

File tree

.github/workflows/pull-requests.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ jobs:
3333

3434
- name: Get composer cache directory
3535
id: composer-cache
36-
run: echo "::set-output name=dir::$(composer config cache-files-dir)"
36+
run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT
3737

3838
- name: Cache dependencies
3939
uses: actions/cache@v2

src/Flagsmith.php

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -292,22 +292,28 @@ public function getEnvironmentFlags(): Flags
292292

293293
/**
294294
* Get all the flags for the current environment for a given identity. Will also
295-
* upsert all traits to the Flagsmith API for future evaluations. Providing a
296-
* trait with a value of None will remove the trait from the identity if it exists.
295+
* upsert all traits to the Flagsmith API for future evaluations.
296+
*
297+
* Providing a trait with a value of None will remove the trait from the identity if it exists.
298+
*
299+
* To send a transient trait, use an object as value:
300+
*
301+
* `$flagsmith->getIdentityFlags($identifier, (object)['transient' => ['value' => 'no-persist', 'transient' => true]])->allFlags();`
302+
*
297303
* @param string $identifier
298304
* @param object|null $traits
299305
* @return Flags
300306
*
301307
* @throws FlagsmithThrowable
302308
*/
303-
public function getIdentityFlags(string $identifier, ?object $traits = null): Flags
309+
public function getIdentityFlags(string $identifier, ?object $traits = null, ?bool $transient = false): Flags
304310
{
305-
$traits = $traits ?? (object) [];
311+
$traits = $traits ?? (object)[];
306312
if ($this->environment) {
307313
return $this->getIdentityFlagsFromDocument($identifier, $traits);
308314
}
309315

310-
return $this->getIdentityFlagsFromApi($identifier, $traits);
316+
return $this->getIdentityFlagsFromApi($identifier, $traits, $transient);
311317
}
312318

313319
/**
@@ -426,11 +432,11 @@ private function getEnvironmentFlagsFromApi(): Flags
426432
*
427433
* @throws FlagsmithAPIError
428434
*/
429-
private function getIdentityFlagsFromApi(string $identifier, ?object $traits): Flags
435+
private function getIdentityFlagsFromApi(string $identifier, ?object $traits, ?bool $transient): Flags
430436
{
431437
try {
432-
$data = IdentitiesGenerator::generateIdentitiesData($identifier, $traits);
433-
$cacheKey = IdentitiesGenerator::generateIdentitiesCacheKey($identifier, $traits);
438+
$data = IdentitiesGenerator::generateIdentitiesData($identifier, $traits, $transient);
439+
$cacheKey = IdentitiesGenerator::generateIdentitiesCacheKey($identifier, $traits, $transient);
434440
$apiFlags = $this->cachedCall(
435441
$cacheKey,
436442
'POST',

src/Utils/IdentitiesGenerator.php

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,26 +4,39 @@
44

55
class IdentitiesGenerator
66
{
7-
public static function generateIdentitiesData(string $identifier, ?object $traits)
7+
public static function generateIdentitiesData(string $identifier, ?object $traits, ?bool $transient)
88
{
9-
$identities = [
9+
$identityData = [
1010
'identifier' => $identifier,
1111
'traits' => [],
1212
];
1313

14+
if ($transient) {
15+
$identityData['transient'] = true;
16+
}
17+
1418
if (!empty($traits)) {
1519
foreach ($traits as $key => $value) {
16-
$identities['traits'][] = ['trait_key' => $key, 'trait_value' => $value];
20+
$traitData = ['trait_key' => $key];
21+
if (is_object($value)) {
22+
$traitData['trait_value'] = $value->value;
23+
if ($value->transient) {
24+
$traitData['transient'] = true;
25+
}
26+
} else {
27+
$traitData['trait_value'] = $value;
28+
}
29+
$identityData['traits'][] = $traitData;
1730
}
1831
}
1932

20-
return $identities;
33+
return $identityData;
2134
}
2235

23-
public static function generateIdentitiesCacheKey(string $identifier, ?object $traits)
36+
public static function generateIdentitiesCacheKey(string $identifier, ?object $traits, ?bool $transient)
2437
{
2538
$hashedTraits = $traits !== null ? '.'.sha1(serialize($traits)) : '';
2639
$hashedIdentifier = sha1($identifier);
27-
return 'Identity.'.$hashedIdentifier.$hashedTraits;
40+
return 'Identity.'.$transient ? 'Transient' : ''.$hashedIdentifier.$hashedTraits;
2841
}
2942
}

tests/FlagsmithClientTest.php

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -73,13 +73,17 @@ public function testGetIdentityFlagsCallsApiWhenNoLocalEnvironmentWithTraits()
7373
->withStreamFactory($streamMock);
7474

7575
$identifier = 'identifer';
76-
$traits = (object) ['some_trait' => 'some-value'];
77-
78-
$requestBody = IdentitiesGenerator::generateIdentitiesData($identifier, $traits);
76+
$traits = (object)['some_trait' => 'some-value', 'transient_trait' => (object)['transient' => true, 'value' => 'some-transient-value']];
7977

8078
$streamMock->expects($this->once())
8179
->method('createStream')
82-
->with($this->equalTo(json_encode($requestBody)));
80+
->with($this->equalTo(json_encode([
81+
'identifier' => $identifier,
82+
'traits' => [
83+
['trait_key' => 'some_trait', 'trait_value' => 'some-value'],
84+
['trait_key' => 'transient_trait', 'trait_value' => 'some-transient-value', 'transient' => true],
85+
],
86+
])));
8387

8488
$identityFlags = $flagsmith->getIdentityFlags($identifier, $traits)->allFlags();
8589

@@ -88,6 +92,30 @@ public function testGetIdentityFlagsCallsApiWhenNoLocalEnvironmentWithTraits()
8892
$this->assertEquals($identityFlags[0]->feature_name, 'some_feature');
8993
}
9094

95+
public function testGetIdentityFlagsCallsApiWhenNoLocalEnvironmentTransient()
96+
{
97+
$streamMock = $this->createMock(StreamFactoryInterface::class);
98+
99+
$flagsmith = (new Flagsmith('api_key'))
100+
->withClient(ClientFixtures::getMockClient())
101+
->withStreamFactory($streamMock);
102+
103+
$identifier = 'identifer';
104+
$traits = (object)['some_trait' => 'some-value'];
105+
106+
$streamMock->expects($this->once())
107+
->method('createStream')
108+
->with($this->equalTo(json_encode([
109+
'identifier' => $identifier,
110+
'traits' => [
111+
['trait_key' => 'some_trait', 'trait_value' => 'some-value'],
112+
],
113+
'transient' => true,
114+
])));
115+
116+
$flagsmith->getIdentityFlags($identifier, $traits, true);
117+
}
118+
91119
public function testRequestConnectionErrorRaisesFlagsmithApiError()
92120
{
93121
$flagsmith = (new Flagsmith('api_key'))

0 commit comments

Comments
 (0)