diff --git a/.changeset/green-groups-identify.md b/.changeset/green-groups-identify.md new file mode 100644 index 0000000..545a238 --- /dev/null +++ b/.changeset/green-groups-identify.md @@ -0,0 +1,5 @@ +--- +"posthog-php": minor +--- + +Add an optional `distinctId`/`distinct_id` override for `groupIdentify()` events. diff --git a/bin/posthog b/bin/posthog index 2568b50..49d8d40 100755 --- a/bin/posthog +++ b/bin/posthog @@ -81,13 +81,15 @@ switch ($options['type']) { break; case 'groupIdentify': - PostHog::groupIdentify( - array( - 'groupType' => $options['groupType'], - 'groupKey' => $options['groupKey'], - 'properties' => parse_json($options['properties']) - ) + $message = array( + 'groupType' => $options['groupType'], + 'groupKey' => $options['groupKey'], + 'properties' => parse_json($options['properties']) ); + if (!empty($options['distinctId'])) { + $message['distinctId'] = $options['distinctId']; + } + PostHog::groupIdentify($message); break; case 'getFeatureFlag': @@ -121,7 +123,7 @@ function usage(): string "\n posthog --type capture --distinctId \"id\" --event \"event name\" --properties '{ \"json\": \"object\" }'" . "\n posthog --type identify --distinctId \"id\" --properties '{ \"json\": \"object\" }'" . "\n posthog --type alias --distinctId \"id\" --alias \"alias\"" . - "\n posthog --type groupIdentify --groupType \"organization\" --groupKey \"id:5\" --properties '{ \"json\": \"object\" }'" . + "\n posthog --type groupIdentify --groupType \"organization\" --groupKey \"id:5\" --distinctId \"user-id\" --properties '{ \"json\": \"object\" }'" . "\n posthog --type getFeatureFlag --flag some-flag --apiKey phc_... --host localhost:8010 --no-ssl" . "\n posthog --type getFeatureFlag --flag some-flag --apiKey phc_... --host localhost:8010 --no-ssl" . "\n\n\n"; diff --git a/lib/PostHog.php b/lib/PostHog.php index 6dbe3fc..c4b76bf 100644 --- a/lib/PostHog.php +++ b/lib/PostHog.php @@ -110,7 +110,8 @@ public static function identify(array $message) /** * Adds properties to a group. * - * @param array $message Must contain keys `groupType`, `groupKey`, `properties` + * @param array $message Must contain keys `groupType`, `groupKey`; accepts optional `properties` + * and `distinctId`/`distinct_id` to override the default synthetic ID. * @return boolean whether the groupIdentify call succeeded * @throws Exception */ @@ -123,9 +124,24 @@ public static function groupIdentify(array $message) $message["properties"] = array(); } + $distinctId = "\${$message['groupType']}_{$message['groupKey']}"; + if ( + array_key_exists("distinctId", $message) + && is_scalar($message["distinctId"]) + && (string) $message["distinctId"] !== "" + ) { + $distinctId = (string) $message["distinctId"]; + } elseif ( + array_key_exists("distinct_id", $message) + && is_scalar($message["distinct_id"]) + && (string) $message["distinct_id"] !== "" + ) { + $distinctId = (string) $message["distinct_id"]; + } + $msg = array( "event" => "\$groupidentify", - "distinctId" => "\${$message['groupType']}_{$message['groupKey']}", + "distinctId" => $distinctId, "properties" => array( "\$group_type" => $message["groupType"], "\$group_key" => $message["groupKey"], diff --git a/test/RequestContextTest.php b/test/RequestContextTest.php index 5b21af6..7b025f3 100644 --- a/test/RequestContextTest.php +++ b/test/RequestContextTest.php @@ -438,6 +438,38 @@ public function testContextDoesNotMutateGroupIdentifyProperties(): void $this->assertArrayNotHasKey('$session_id', $event['properties']); } + public function testGroupIdentifyAllowsDistinctIdOverride(): void + { + PostHog::groupIdentify([ + 'groupType' => 'organization', + 'groupKey' => 'acme', + 'distinctId' => 'user-123', + 'properties' => ['name' => 'Acme Inc.'], + ]); + + $event = $this->flushAndGetEvents()[0]; + + $this->assertSame('user-123', $event['distinct_id']); + $this->assertSame('$groupidentify', $event['event']); + $this->assertSame('organization', $event['properties']['$group_type']); + $this->assertSame('acme', $event['properties']['$group_key']); + $this->assertSame(['name' => 'Acme Inc.'], $event['properties']['$group_set']); + } + + public function testGroupIdentifyAllowsSnakeCaseDistinctIdOverride(): void + { + PostHog::groupIdentify([ + 'groupType' => 'organization', + 'groupKey' => 'acme', + 'distinct_id' => 'snake-user-123', + 'properties' => ['name' => 'Acme Inc.'], + ]); + + $event = $this->flushAndGetEvents()[0]; + + $this->assertSame('snake-user-123', $event['distinct_id']); + } + public function testEvaluateFlagsUsesContextDistinctIdWhenOmitted(): void { PostHog::withContext(['distinctId' => 'context-user'], function (): void {