Skip to content

Commit 90d3b55

Browse files
feat: add trackNow and identifyNow (#17)
Co-authored-by: Tom Roelofs <tom@techbite.nl>
1 parent d47264a commit 90d3b55

File tree

10 files changed

+230
-13
lines changed

10 files changed

+230
-13
lines changed

README.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,12 @@ Segment::forUser($user)->track('User Signed Up', [
139139
Segment::track('User Signed Up', [
140140
'source' => 'Product Hunt',
141141
]);
142+
143+
// If you have defer enabled in the config
144+
// you can still track an event immediately using trackNow.
145+
Segment::trackNow('User Signed Up', [
146+
'source' => 'Product Hunt',
147+
]);
142148
```
143149

144150
### For identifying users
@@ -156,6 +162,12 @@ Segment::identify([
156162
'last_logged_in' => '2021-03-24 20:05:30',
157163
'latest_subscription_amount' => '$24.60',
158164
]);
165+
166+
// If you have defer enabled in the config
167+
// you can still identify a user immediately using identifyNow.
168+
Segment::identifyNow('User Signed Up', [
169+
'source' => 'Product Hunt',
170+
]);
159171
```
160172

161173
### Laravel Notifications

src/Facades/Fakes/SegmentFake.php

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -72,9 +72,7 @@ public function push(CanBeSentToSegment $segment): void
7272
}
7373
}
7474

75-
public function terminate(): void
76-
{
77-
}
75+
public function terminate(): void {}
7876

7977
public function assertIdentified(Closure|int|null $callback = null): void
8078
{

src/Facades/Segment.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,9 @@
1313
* @method static void setGlobalUser(CanBeIdentifiedForSegment $globalUser)
1414
* @method static void setGlobalContext(?array $globalContext)
1515
* @method static void track(string $event, ?array $eventData = null)
16+
* @method static void trackNow(string $event, ?array $eventData = null)
1617
* @method static void identify(?array $identifyData = null)
18+
* @method static void identifyNow(?array $identifyData = null)
1719
* @method static PendingUserSegment forUser(CanBeIdentifiedForSegment $user)
1820
* @method static void push(CanBeSentToSegment $segment)
1921
* @method static void terminate()

src/PendingUserSegment.php

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,18 @@ public function track(string $event, ?array $eventData = null): void
2727
);
2828
}
2929

30+
/**
31+
* @param array<string, mixed>|null $eventData
32+
*/
33+
public function trackNow(string $event, ?array $eventData = null): void
34+
{
35+
$this->service->push(
36+
new SimpleSegmentEvent($this->user, $event, $eventData)
37+
);
38+
39+
$this->service->terminate();
40+
}
41+
3042
/**
3143
* @param array<string, mixed>|null $identifyData
3244
*/
@@ -36,4 +48,16 @@ public function identify(?array $identifyData = null): void
3648
new SimpleSegmentIdentify($this->user, $identifyData)
3749
);
3850
}
51+
52+
/**
53+
* @param array<string, mixed>|null $identifyData
54+
*/
55+
public function identifyNow(?array $identifyData = null): void
56+
{
57+
$this->service->push(
58+
new SimpleSegmentIdentify($this->user, $identifyData)
59+
);
60+
61+
$this->service->terminate();
62+
}
3963
}

src/SegmentService.php

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,7 @@ class SegmentService implements SegmentServiceContract
2828
*/
2929
public function __construct(
3030
private readonly array $config
31-
) {
32-
}
31+
) {}
3332

3433
public function setGlobalUser(CanBeIdentifiedForSegment $globalUser): void
3534
{
@@ -54,6 +53,18 @@ public function track(string $event, ?array $eventData = null): void
5453
);
5554
}
5655

56+
/**
57+
* @param array<string, mixed> $eventData
58+
*/
59+
public function trackNow(string $event, ?array $eventData = null): void
60+
{
61+
$this->push(
62+
new SimpleSegmentEvent($this->globalUser, $event, $eventData)
63+
);
64+
65+
$this->terminate();
66+
}
67+
5768
/**
5869
* @param array<string, mixed> $identifyData
5970
*/
@@ -64,6 +75,18 @@ public function identify(?array $identifyData = null): void
6475
);
6576
}
6677

78+
/**
79+
* @param array<string, mixed> $identifyData
80+
*/
81+
public function identifyNow(?array $identifyData = null): void
82+
{
83+
$this->push(
84+
new SimpleSegmentIdentify($this->globalUser, $identifyData)
85+
);
86+
87+
$this->terminate();
88+
}
89+
6790
public function forUser(CanBeIdentifiedForSegment $user): PendingUserSegment
6891
{
6992
return new PendingUserSegment($this, $user);

src/SimpleSegmentEvent.php

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,7 @@ public function __construct(
1616
private readonly CanBeIdentifiedForSegment $user,
1717
private readonly string $event,
1818
private readonly ?array $eventData = null,
19-
) {
20-
}
19+
) {}
2120

2221
public function toSegment(): SegmentPayload
2322
{

src/SimpleSegmentIdentify.php

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,7 @@ class SimpleSegmentIdentify implements CanBeSentToSegment
1515
public function __construct(
1616
private CanBeIdentifiedForSegment $user,
1717
private ?array $identifyData = null
18-
) {
19-
}
18+
) {}
2019

2120
public function toSegment(): SegmentPayload
2221
{

tests/Stubs/SegmentTestNotification.php

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,7 @@ class SegmentTestNotification extends Notification implements CanNotifyViaSegmen
1414
{
1515
public function __construct(
1616
private int $number
17-
) {
18-
}
17+
) {}
1918

2019
public function via(object $notifiable): array
2120
{

tests/Stubs/SegmentTestUser.php

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,7 @@ class SegmentTestUser implements CanBeIdentifiedForSegment
1111

1212
public function __construct(
1313
private string $id
14-
) {
15-
}
14+
) {}
1615

1716
public function getSegmentIdentifier(): string
1817
{

tests/Unit/SegmentServiceTest.php

Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,168 @@
254254
});
255255
});
256256

257+
it('terminates directly when using trackNow while deferred is enabled', function () {
258+
// Given we have a user
259+
$user = new SegmentTestUser('abcd');
260+
261+
// And we are deferring
262+
setDefer(true);
263+
264+
// And we have set a write key
265+
setWriteKey();
266+
267+
// And we are faking the Http facade
268+
Http::fake();
269+
270+
// And we call the track method
271+
Segment::forUser($user)->trackNow('Something Happened', [
272+
'name' => 'special',
273+
]);
274+
275+
// Then we have made the calls to Segment
276+
Http::assertSent(function (Request $request) {
277+
return $request->hasHeader('Content-Type', 'application/json')
278+
&& $request->hasHeader('Authorization', 'Bearer '.base64_encode('key_1234:'))
279+
&& $request->url() === 'https://api.segment.io/v1/batch'
280+
&& $request['context'] === []
281+
&& count($request['batch']) === 1
282+
&& arraysMatch($request['batch'][0], [
283+
'type' => 'track',
284+
'userId' => 'abcd',
285+
'timestamp' => (new DateTime())->format('Y-m-d\TH:i:s\Z'),
286+
'properties' => [
287+
'name' => 'special',
288+
],
289+
'event' => 'Something Happened',
290+
]);
291+
});
292+
});
293+
294+
it('terminates directly when using identifyNow while deferred is enabled', function () {
295+
// Given we have a user
296+
$user = new SegmentTestUser('abcd');
297+
298+
// And we are deferring
299+
setDefer(true);
300+
301+
// And we have set a write key
302+
setWriteKey();
303+
304+
// And we are faking the Http facade
305+
Http::fake();
306+
307+
// And we call the track method
308+
Segment::forUser($user)->identifyNow([
309+
'seen_email' => true,
310+
]);
311+
312+
// Then we have made the calls to Segment
313+
Http::assertSent(function (Request $request) {
314+
return $request->hasHeader('Content-Type', 'application/json')
315+
&& $request->hasHeader('Authorization', 'Bearer '.base64_encode('key_1234:'))
316+
&& $request->url() === 'https://api.segment.io/v1/batch'
317+
&& $request['context'] === []
318+
&& count($request['batch']) === 1
319+
&& arraysMatch($request['batch'][0], [
320+
'type' => 'identify',
321+
'userId' => 'abcd',
322+
'timestamp' => (new DateTime())->format('Y-m-d\TH:i:s\Z'),
323+
'traits' => [
324+
'seen_email' => true,
325+
],
326+
]);
327+
});
328+
});
329+
330+
it('terminates directly when using trackNow while deferred is enabled with global user and context', function () {
331+
// Given we have a user
332+
$user = new SegmentTestUser('abcd');
333+
334+
// And we are deferring
335+
setDefer(true);
336+
337+
// And we have set a write key
338+
setWriteKey();
339+
340+
// And we have set global user
341+
Segment::setGlobalUser($user);
342+
343+
// And we have set global context
344+
Segment::setGlobalContext([
345+
'ip' => '127.0.0.1',
346+
]);
347+
348+
// And we are faking the Http facade
349+
Http::fake();
350+
351+
// And we call the track method
352+
Segment::trackNow('Something Happened', [
353+
'name' => 'special',
354+
]);
355+
356+
// Then we have made the calls to Segment
357+
Http::assertSent(function (Request $request) {
358+
return $request->hasHeader('Content-Type', 'application/json')
359+
&& $request->hasHeader('Authorization', 'Bearer '.base64_encode('key_1234:'))
360+
&& $request->url() === 'https://api.segment.io/v1/batch'
361+
&& $request['context'] === ['ip' => '127.0.0.1']
362+
&& count($request['batch']) === 1
363+
&& arraysMatch($request['batch'][0], [
364+
'type' => 'track',
365+
'userId' => 'abcd',
366+
'timestamp' => (new DateTime())->format('Y-m-d\TH:i:s\Z'),
367+
'properties' => [
368+
'name' => 'special',
369+
],
370+
'event' => 'Something Happened',
371+
]);
372+
});
373+
});
374+
375+
it('terminates directly when using identifyNow while deferred is enabled with global user and context', function () {
376+
// Given we have a user
377+
$user = new SegmentTestUser('abcd');
378+
379+
// And we are deferring
380+
setDefer(true);
381+
382+
// And we have set a write key
383+
setWriteKey();
384+
385+
// And we have set global user
386+
Segment::setGlobalUser($user);
387+
388+
// And we have set global context
389+
Segment::setGlobalContext([
390+
'ip' => '127.0.0.1',
391+
]);
392+
393+
// And we are faking the Http facade
394+
Http::fake();
395+
396+
// And we call the track method
397+
Segment::identifyNow([
398+
'seen_email' => true,
399+
]);
400+
401+
// Then we have made the calls to Segment
402+
Http::assertSent(function (Request $request) {
403+
return $request->hasHeader('Content-Type', 'application/json')
404+
&& $request->hasHeader('Authorization', 'Bearer '.base64_encode('key_1234:'))
405+
&& $request->url() === 'https://api.segment.io/v1/batch'
406+
&& $request['context'] === ['ip' => '127.0.0.1']
407+
&& count($request['batch']) === 1
408+
&& arraysMatch($request['batch'][0], [
409+
'type' => 'identify',
410+
'userId' => 'abcd',
411+
'timestamp' => (new DateTime())->format('Y-m-d\TH:i:s\Z'),
412+
'traits' => [
413+
'seen_email' => true,
414+
],
415+
]);
416+
});
417+
});
418+
257419
it('does not sent tracking events when not enabled', function () {
258420
// Given we have a user
259421
$user = new SegmentTestUser('abcd');

0 commit comments

Comments
 (0)