Skip to content

Commit ee8916f

Browse files
authored
add alias events support (#57)
* add alias function to LDClient * add `contextKind` to events that require the new field * add tests for alias and contextKind
1 parent 710b6cd commit ee8916f

File tree

3 files changed

+125
-1
lines changed

3 files changed

+125
-1
lines changed

src/LaunchDarkly/Impl/EventFactory.php

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,9 @@ public function newEvalEvent($flag, $user, $detail, $default, $prereqOfFlag = nu
3939
if (($addExperimentData || $this->_withReasons) && $detail->getReason()) {
4040
$e['reason'] = $detail->getReason()->jsonSerialize();
4141
}
42+
if ($user->getAnonymous()) {
43+
$e['contextKind'] = 'anonymousUser';
44+
}
4245
return $e;
4346
}
4447

@@ -63,6 +66,9 @@ public function newDefaultEvent($flag, $user, $detail)
6366
if ($this->_withReasons && $detail->getReason()) {
6467
$e['reason'] = $detail->getReason()->jsonSerialize();
6568
}
69+
if ($user->getAnonymous()) {
70+
$e['contextKind'] = 'anonymousUser';
71+
}
6672
return $e;
6773
}
6874

@@ -80,6 +86,9 @@ public function newUnknownFlagEvent($key, $user, $detail)
8086
if ($this->_withReasons && $detail->getReason()) {
8187
$e['reason'] = $detail->getReason()->jsonSerialize();
8288
}
89+
if ($user->getAnonymous()) {
90+
$e['contextKind'] = 'anonymousUser';
91+
}
8392
return $e;
8493
}
8594

@@ -107,9 +116,35 @@ public function newCustomEvent($eventName, $user, $data, $metricValue)
107116
if (isset($metricValue)) {
108117
$e['metricValue'] = $metricValue;
109118
}
119+
if ($user->getAnonymous()) {
120+
$e['contextKind'] = 'anonymousUser';
121+
}
122+
return $e;
123+
}
124+
125+
public function newAliasEvent($user, $previousUser)
126+
{
127+
$e = array(
128+
'kind' => 'alias',
129+
'key' => strval($user->getKey()),
130+
'contextKind' => static::contextKind($user),
131+
'previousKey' => strval($previousUser->getKey()),
132+
'previousContextKind' => static::contextKind($previousUser),
133+
'creationDate' => Util::currentTimeUnixMillis()
134+
);
135+
110136
return $e;
111137
}
112138

139+
private static function contextKind($user)
140+
{
141+
if ($user->getAnonymous()) {
142+
return 'anonymousUser';
143+
} else {
144+
return 'user';
145+
}
146+
}
147+
113148
private static function isExperiment($flag, $reason)
114149
{
115150
if ($reason) {

src/LaunchDarkly/LDClient.php

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -375,7 +375,7 @@ public function allFlags($user)
375375
public function allFlagsState($user, $options = array())
376376
{
377377
if (is_null($user) || is_null($user->getKey())) {
378-
$this->_logger->warn("allFlagsState called with null user or null/empty user key! Returning empty state");
378+
$this->_logger->warning("allFlagsState called with null user or null/empty user key! Returning empty state");
379379
return new FeatureFlagsState(false);
380380
}
381381
if ($this->isOffline()) {
@@ -408,6 +408,34 @@ public function allFlagsState($user, $options = array())
408408
return $state;
409409
}
410410

411+
/**
412+
* Associates two users for analytics purposes.
413+
*
414+
* This can be helpful in the situation where a person is represented by multiple
415+
* LaunchDarkly users. This may happen, for example, when a person initially logs into
416+
* an application-- the person might be represented by an anonymous user prior to logging
417+
* in and a different user after logging in, as denoted by a different user key.
418+
*
419+
* @param LDUser $user the newly identified user.
420+
* @param LDUser $previousUser the previously identified user.
421+
* @return void
422+
*/
423+
public function alias($user, $previousUser)
424+
{
425+
if (is_null($user) || is_null($user->getKey())) {
426+
$this->_logger->warning("Alias called with null user or null/empty user!");
427+
return;
428+
}
429+
430+
if (is_null($previousUser) || is_null($previousUser->getKey())) {
431+
$this->_logger->warning("Alias called with null user or null/empty previousUser!");
432+
return;
433+
}
434+
435+
$event = $this->_eventFactoryDefault->newAliasEvent($user, $previousUser);
436+
$this->_eventProcessor->enqueue($event);
437+
}
438+
411439
/**
412440
* Generates an HMAC sha256 hash for use in Secure mode.
413441
*

tests/LDClientTest.php

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -313,6 +313,27 @@ public function testVariationDetailSendsEventForUnknownFlag()
313313
$this->assertEquals(array('kind' => 'ERROR', 'errorKind' => 'FLAG_NOT_FOUND'), $event['reason']);
314314
}
315315

316+
317+
public function testVariationWithAnonymousUserSendsEventWithAnonymousContextKind()
318+
{
319+
$ep = new MockEventProcessor();
320+
$client = $this->makeClient(array('event_processor' => $ep));
321+
322+
$flag = $this->makeOffFlagWithValue('feature', 'value');
323+
324+
$anon_builder = new LDUserBuilder("[email protected]");
325+
$anon = $anon_builder->anonymous(true)->build();
326+
327+
$client->variation('feature', $anon, 'default');
328+
329+
$queue = $ep->getEvents();
330+
$this->assertEquals(1, sizeof($queue));
331+
332+
$event = $queue[0];
333+
334+
$this->assertEquals('anonymousUser', $event['contextKind']);
335+
}
336+
316337
public function testAllFlagsReturnsFlagValues()
317338
{
318339
$flagJson = array(
@@ -593,6 +614,46 @@ public function testTrackSendsEventWithDataAndMetricValue()
593614
$this->assertEquals($metricValue, $event['metricValue']);
594615
}
595616

617+
public function testTrackWithAnonymousUserSendsEventWithAnonymousContextKind()
618+
{
619+
$ep = new MockEventProcessor();
620+
$client = $this->makeClient(array('event_processor' => $ep));
621+
622+
$anon_builder = new LDUserBuilder("[email protected]");
623+
$anon = $anon_builder->anonymous(true)->build();
624+
625+
$client->track('eventkey', $anon);
626+
$queue = $ep->getEvents();
627+
$this->assertEquals(1, sizeof($queue));
628+
$event = $queue[0];
629+
$this->assertEquals('custom', $event['kind']);
630+
$this->assertEquals('anonymousUser', $event['contextKind']);
631+
}
632+
633+
public function testAliasEventsAreCorrect()
634+
{
635+
$ep = new MockEventProcessor();
636+
$client = $this->makeClient(array('event_processor' => $ep));
637+
638+
$user_builder = new LDUserBuilder("[email protected]");
639+
$user = $user_builder->anonymous(false)->build();
640+
$anon_builder = new LDUserBuilder("[email protected]");
641+
$anon = $anon_builder->anonymous(true)->build();
642+
643+
$client->alias($user, $anon);
644+
645+
$queue = $ep->getEvents();
646+
$this->assertEquals(1, sizeof($queue));
647+
648+
$event = $queue[0];
649+
650+
$this->assertEquals('alias', $event['kind']);
651+
$this->assertEquals($user->getKey(), $event['key']);
652+
$this->assertEquals('user', $event['contextKind']);
653+
$this->assertEquals($anon->getKey(), $event['previousKey']);
654+
$this->assertEquals('anonymousUser', $event['previousContextKind']);
655+
}
656+
596657
public function testEventsAreNotPublishedIfSendEventsIsFalse()
597658
{
598659
// In order to do this test, we cannot provide a mock object for Event_Processor_,

0 commit comments

Comments
 (0)