From 9815a7d5e291f32b1cc4a53bf0b6efd545768358 Mon Sep 17 00:00:00 2001 From: Aditya Alif Nugraha Date: Mon, 14 Apr 2025 16:46:57 +0200 Subject: [PATCH 1/7] Add Query Threads --- lib/GetStream/StreamChat/Client.php | 27 +++++++++ tests/integration/IntegrationTest.php | 87 +++++++++++++++++++++++++++ 2 files changed, 114 insertions(+) diff --git a/lib/GetStream/StreamChat/Client.php b/lib/GetStream/StreamChat/Client.php index 6b45f85..bbc426d 100644 --- a/lib/GetStream/StreamChat/Client.php +++ b/lib/GetStream/StreamChat/Client.php @@ -886,6 +886,33 @@ public function queryChannels(array $filterConditions, ?array $sort = null, ?arr return $this->post("channels", $options); } + /** Queries threads. + * You can query threads based on built-in fields as well as any custom field you add to threads. + * Multiple filters can be combined using AND, OR logical operators, each filter can use its + * comparison (equality, inequality, greater than, greater or equal, etc.). + * You can find the complete list of supported operators in the query syntax section of the docs. + * @link https://getstream.io/chat/docs/php/query_threads/?language=php + * @throws StreamException + */ + public function queryThreads(array $filterConditions, ?array $sort = null, ?array $options = null): StreamResponse + { + if ($options === null) { + $options = []; + } + + $sortFields = []; + if ($sort !== null) { + foreach ($sort as $k => $v) { + $sortFields[] = ["field" => $k, "direction" => $v]; + } + } + + $options["filter_conditions"] = $filterConditions; + $options["sort"] = $sortFields; + + return $this->post("threads", $options); + } + /** Creates a channel type. * @link https://getstream.io/chat/docs/php/channel_features/?language=php * @throws StreamException diff --git a/tests/integration/IntegrationTest.php b/tests/integration/IntegrationTest.php index 0c7e8be..fecf2d9 100644 --- a/tests/integration/IntegrationTest.php +++ b/tests/integration/IntegrationTest.php @@ -1520,4 +1520,91 @@ public function testExportUsers() } $this->assertSame($response["status"], "completed"); } + + public function testQueryThreadsWithFilter() + { + // Create a thread by sending a message with a parent_id + $parentMessage = $this->channel->sendMessage(["text" => "Parent message"], $this->user1["id"]); + $threadMessage = $this->channel->sendMessage( + ["text" => "Thread message", "parent_id" => $parentMessage["message"]["id"]], + $this->user2["id"] + ); + + // Query threads with filter + $response = $this->client->queryThreads( + ["parent_id" => ['$eq' => $parentMessage["message"]["id"]]] + ); + + // Verify the response + $this->assertTrue(array_key_exists("threads", (array)$response)); + $this->assertGreaterThanOrEqual(1, count($response["threads"])); + + // Clean up + $this->channel->deleteMessage($threadMessage["message"]["id"]); + $this->channel->deleteMessage($parentMessage["message"]["id"]); + } + + public function testQueryThreadsWithSort() + { + // Create multiple threads + $parentMessage1 = $this->channel->sendMessage(["text" => "Parent message 1"], $this->user1["id"]); + $threadMessage1 = $this->channel->sendMessage( + ["text" => "Thread message 1", "parent_id" => $parentMessage1["message"]["id"]], + $this->user2["id"] + ); + + $parentMessage2 = $this->channel->sendMessage(["text" => "Parent message 2"], $this->user1["id"]); + $threadMessage2 = $this->channel->sendMessage( + ["text" => "Thread message 2", "parent_id" => $parentMessage2["message"]["id"]], + $this->user2["id"] + ); + + // Query threads with sort + $response = $this->client->queryThreads( + [], // No filter + ["created_at" => -1] // Sort by created_at descending + ); + + // Verify the response + $this->assertTrue(array_key_exists("threads", (array)$response)); + $this->assertGreaterThanOrEqual(2, count($response["threads"])); + + // Clean up + $this->channel->deleteMessage($threadMessage1["message"]["id"]); + $this->channel->deleteMessage($parentMessage1["message"]["id"]); + $this->channel->deleteMessage($threadMessage2["message"]["id"]); + $this->channel->deleteMessage($parentMessage2["message"]["id"]); + } + + public function testQueryThreadsWithFilterAndSort() + { + // Create multiple threads + $parentMessage1 = $this->channel->sendMessage(["text" => "Parent message 1"], $this->user1["id"]); + $threadMessage1 = $this->channel->sendMessage( + ["text" => "Thread message 1", "parent_id" => $parentMessage1["message"]["id"]], + $this->user2["id"] + ); + + $parentMessage2 = $this->channel->sendMessage(["text" => "Parent message 2"], $this->user1["id"]); + $threadMessage2 = $this->channel->sendMessage( + ["text" => "Thread message 2", "parent_id" => $parentMessage2["message"]["id"]], + $this->user2["id"] + ); + + // Query threads with both filter and sort + $response = $this->client->queryThreads( + ["created_by_user_id" => ['$eq' => $this->user2["id"]]], // Filter by creator + ["created_at" => -1] // Sort by created_at descending + ); + + // Verify the response + $this->assertTrue(array_key_exists("threads", (array)$response)); + $this->assertGreaterThanOrEqual(2, count($response["threads"])); + + // Clean up + $this->channel->deleteMessage($threadMessage1["message"]["id"]); + $this->channel->deleteMessage($parentMessage1["message"]["id"]); + $this->channel->deleteMessage($threadMessage2["message"]["id"]); + $this->channel->deleteMessage($parentMessage2["message"]["id"]); + } } From 9e9247ac1582c61eadb21905a7cc8a721a8fc09b Mon Sep 17 00:00:00 2001 From: Aditya Alif Nugraha Date: Mon, 14 Apr 2025 16:50:42 +0200 Subject: [PATCH 2/7] Fix lint --- lib/GetStream/StreamChat/Client.php | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/lib/GetStream/StreamChat/Client.php b/lib/GetStream/StreamChat/Client.php index bbc426d..1842942 100644 --- a/lib/GetStream/StreamChat/Client.php +++ b/lib/GetStream/StreamChat/Client.php @@ -888,13 +888,12 @@ public function queryChannels(array $filterConditions, ?array $sort = null, ?arr /** Queries threads. * You can query threads based on built-in fields as well as any custom field you add to threads. - * Multiple filters can be combined using AND, OR logical operators, each filter can use its - * comparison (equality, inequality, greater than, greater or equal, etc.). + * Multiple filters can be combined, each filter can use its comparison (equality, inequality, greater than, greater or equal, etc.). * You can find the complete list of supported operators in the query syntax section of the docs. - * @link https://getstream.io/chat/docs/php/query_threads/?language=php + * @link https://getstream.io/chat/docs/php/threads/#filtering-and-sorting-threads * @throws StreamException */ - public function queryThreads(array $filterConditions, ?array $sort = null, ?array $options = null): StreamResponse + public function queryThreads(array $filter, ?array $sort = null, ?array $options = null): StreamResponse { if ($options === null) { $options = []; @@ -907,7 +906,7 @@ public function queryThreads(array $filterConditions, ?array $sort = null, ?arra } } - $options["filter_conditions"] = $filterConditions; + $options["filter"] = $filter; $options["sort"] = $sortFields; return $this->post("threads", $options); From 01aef2cf918f2a6c8289ee1ee17ab9a603b546dd Mon Sep 17 00:00:00 2001 From: Aditya Alif Nugraha Date: Mon, 14 Apr 2025 16:52:44 +0200 Subject: [PATCH 3/7] Fix phan --- lib/GetStream/StreamChat/Client.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/GetStream/StreamChat/Client.php b/lib/GetStream/StreamChat/Client.php index 1842942..3d3a228 100644 --- a/lib/GetStream/StreamChat/Client.php +++ b/lib/GetStream/StreamChat/Client.php @@ -898,17 +898,17 @@ public function queryThreads(array $filter, ?array $sort = null, ?array $options if ($options === null) { $options = []; } - + $sortFields = []; if ($sort !== null) { foreach ($sort as $k => $v) { $sortFields[] = ["field" => $k, "direction" => $v]; } } - + $options["filter"] = $filter; $options["sort"] = $sortFields; - + return $this->post("threads", $options); } From e50d2c3bec8eba90d8a72d36d6654bef88b50e46 Mon Sep 17 00:00:00 2001 From: Aditya Alif Nugraha Date: Mon, 14 Apr 2025 17:08:48 +0200 Subject: [PATCH 4/7] Fix test --- lib/GetStream/StreamChat/Client.php | 3 ++- tests/integration/IntegrationTest.php | 14 +++++++++----- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/lib/GetStream/StreamChat/Client.php b/lib/GetStream/StreamChat/Client.php index 3d3a228..15b4515 100644 --- a/lib/GetStream/StreamChat/Client.php +++ b/lib/GetStream/StreamChat/Client.php @@ -906,7 +906,8 @@ public function queryThreads(array $filter, ?array $sort = null, ?array $options } } - $options["filter"] = $filter; + $filterObject = (object)$filter; + $options["filter"] = $filterObject; $options["sort"] = $sortFields; return $this->post("threads", $options); diff --git a/tests/integration/IntegrationTest.php b/tests/integration/IntegrationTest.php index fecf2d9..de6fefb 100644 --- a/tests/integration/IntegrationTest.php +++ b/tests/integration/IntegrationTest.php @@ -1532,7 +1532,9 @@ public function testQueryThreadsWithFilter() // Query threads with filter $response = $this->client->queryThreads( - ["parent_id" => ['$eq' => $parentMessage["message"]["id"]]] + ["parent_id" => ['$eq' => $parentMessage["message"]["id"]]], + null, + ["user_id" => $this->user1["id"]] ); // Verify the response @@ -1561,8 +1563,9 @@ public function testQueryThreadsWithSort() // Query threads with sort $response = $this->client->queryThreads( - [], // No filter - ["created_at" => -1] // Sort by created_at descending + [], + ["created_at" => -1], + ["user_id" => $this->user1["id"]] ); // Verify the response @@ -1593,8 +1596,9 @@ public function testQueryThreadsWithFilterAndSort() // Query threads with both filter and sort $response = $this->client->queryThreads( - ["created_by_user_id" => ['$eq' => $this->user2["id"]]], // Filter by creator - ["created_at" => -1] // Sort by created_at descending + ["created_by_user_id" => ['$eq' => $this->user2["id"]]], + ["created_at" => -1], + ["user_id" => $this->user1["id"]] ); // Verify the response From eebd9074378ef294c05ff79a4035ebc8ad86066a Mon Sep 17 00:00:00 2001 From: Aditya Alif Nugraha Date: Mon, 14 Apr 2025 17:19:45 +0200 Subject: [PATCH 5/7] Add support empty param --- lib/GetStream/StreamChat/Client.php | 16 ++++-- tests/integration/IntegrationTest.php | 71 ++++++++++++++++++--------- 2 files changed, 61 insertions(+), 26 deletions(-) diff --git a/lib/GetStream/StreamChat/Client.php b/lib/GetStream/StreamChat/Client.php index 15b4515..24e2f9d 100644 --- a/lib/GetStream/StreamChat/Client.php +++ b/lib/GetStream/StreamChat/Client.php @@ -906,9 +906,19 @@ public function queryThreads(array $filter, ?array $sort = null, ?array $options } } - $filterObject = (object)$filter; - $options["filter"] = $filterObject; - $options["sort"] = $sortFields; + + if (!empty($filter)) { + $filterObject = (object)$filter; + $options["filter"] = $filterObject; + } else { + $options["filter"] = null; + } + + if (!empty($sortFields)) { + $options["sort"] = $sortFields; + } else { + $options["sort"] = null; + } return $this->post("threads", $options); } diff --git a/tests/integration/IntegrationTest.php b/tests/integration/IntegrationTest.php index de6fefb..e72921e 100644 --- a/tests/integration/IntegrationTest.php +++ b/tests/integration/IntegrationTest.php @@ -560,7 +560,7 @@ public function testPendingMessage() $msg = ["id" => $msgId, "text" => "hello world"]; $response1 = $this->channel->sendMessage($msg, $this->user1["id"], null, ["pending" => true]); $this->assertSame($msgId, $response1["message"]["id"]); - + $response = $this->client->queryChannels(["id" => $this->channel->id], null, ['user_id' => $this->user1["id"]]); // check if length of $response["channels"][0]['pending_messages']) is 1 $this->assertSame(1, sizeof($response["channels"][0]['pending_messages'])); @@ -1440,18 +1440,18 @@ public function testSendMessageWithRestrictedVisibility() "text" => "secret message", "restricted_visibility" => [$this->user1["id"]] ]; - - + + $response = $this->channel->sendMessage($msg, $this->user1["id"]); $this->assertNotNull($response["message"]["restricted_visibility"]); $this->assertEquals([$this->user1["id"]], $response["message"]["restricted_visibility"]); - + } public function testUpdateMessageWithRestrictedVisibility() { $this->channel->addMembers([$this->user1["id"], $this->user2["id"]]); - + // First send a regular message $msgId = $this->generateGuid(); $msg = [ @@ -1459,7 +1459,7 @@ public function testUpdateMessageWithRestrictedVisibility() "text" => "original message" ]; $response = $this->channel->sendMessage($msg, $this->user1["id"]); - + // Then update it with restricted visibility $updatedMsg = [ "id" => $msgId, @@ -1467,7 +1467,7 @@ public function testUpdateMessageWithRestrictedVisibility() "restricted_visibility" => [$this->user1["id"]], "user" => ["id" => $this->user1["id"]] ]; - + $response = $this->client->updateMessage($updatedMsg); $this->assertNotNull($response["message"]["restricted_visibility"]); $this->assertEquals([$this->user1["id"]], $response["message"]["restricted_visibility"]); @@ -1476,7 +1476,7 @@ public function testUpdateMessageWithRestrictedVisibility() public function testUpdateMessagePartialWithRestrictedVisibility() { $this->channel->addMembers([$this->user1["id"], $this->user2["id"]]); - + // First send a regular message $msgId = $this->generateGuid(); $msg = [ @@ -1484,7 +1484,7 @@ public function testUpdateMessagePartialWithRestrictedVisibility() "text" => "original message" ]; $response = $this->channel->sendMessage($msg, $this->user1["id"]); - + // Then do a partial update with restricted visibility $response = $this->client->partialUpdateMessage( $msgId, @@ -1496,7 +1496,7 @@ public function testUpdateMessagePartialWithRestrictedVisibility() ], $this->user1["id"] ); - + $this->assertNotNull($response["message"]["restricted_visibility"]); $this->assertEquals([$this->user1["id"]], $response["message"]["restricted_visibility"]); } @@ -1529,23 +1529,23 @@ public function testQueryThreadsWithFilter() ["text" => "Thread message", "parent_id" => $parentMessage["message"]["id"]], $this->user2["id"] ); - + // Query threads with filter $response = $this->client->queryThreads( ["parent_id" => ['$eq' => $parentMessage["message"]["id"]]], null, ["user_id" => $this->user1["id"]] ); - + // Verify the response $this->assertTrue(array_key_exists("threads", (array)$response)); $this->assertGreaterThanOrEqual(1, count($response["threads"])); - + // Clean up $this->channel->deleteMessage($threadMessage["message"]["id"]); $this->channel->deleteMessage($parentMessage["message"]["id"]); } - + public function testQueryThreadsWithSort() { // Create multiple threads @@ -1554,31 +1554,31 @@ public function testQueryThreadsWithSort() ["text" => "Thread message 1", "parent_id" => $parentMessage1["message"]["id"]], $this->user2["id"] ); - + $parentMessage2 = $this->channel->sendMessage(["text" => "Parent message 2"], $this->user1["id"]); $threadMessage2 = $this->channel->sendMessage( ["text" => "Thread message 2", "parent_id" => $parentMessage2["message"]["id"]], $this->user2["id"] ); - + // Query threads with sort $response = $this->client->queryThreads( [], ["created_at" => -1], ["user_id" => $this->user1["id"]] ); - + // Verify the response $this->assertTrue(array_key_exists("threads", (array)$response)); $this->assertGreaterThanOrEqual(2, count($response["threads"])); - + // Clean up $this->channel->deleteMessage($threadMessage1["message"]["id"]); $this->channel->deleteMessage($parentMessage1["message"]["id"]); $this->channel->deleteMessage($threadMessage2["message"]["id"]); $this->channel->deleteMessage($parentMessage2["message"]["id"]); } - + public function testQueryThreadsWithFilterAndSort() { // Create multiple threads @@ -1587,28 +1587,53 @@ public function testQueryThreadsWithFilterAndSort() ["text" => "Thread message 1", "parent_id" => $parentMessage1["message"]["id"]], $this->user2["id"] ); - + $parentMessage2 = $this->channel->sendMessage(["text" => "Parent message 2"], $this->user1["id"]); $threadMessage2 = $this->channel->sendMessage( ["text" => "Thread message 2", "parent_id" => $parentMessage2["message"]["id"]], $this->user2["id"] ); - + // Query threads with both filter and sort $response = $this->client->queryThreads( ["created_by_user_id" => ['$eq' => $this->user2["id"]]], ["created_at" => -1], ["user_id" => $this->user1["id"]] ); - + // Verify the response $this->assertTrue(array_key_exists("threads", (array)$response)); $this->assertGreaterThanOrEqual(2, count($response["threads"])); - + // Clean up $this->channel->deleteMessage($threadMessage1["message"]["id"]); $this->channel->deleteMessage($parentMessage1["message"]["id"]); $this->channel->deleteMessage($threadMessage2["message"]["id"]); $this->channel->deleteMessage($parentMessage2["message"]["id"]); } + + public function testQueryThreadsWithoutFilterAndSort() + { + // Create a thread by sending a message with a parent_id + $parentMessage = $this->channel->sendMessage(["text" => "Parent message for no filter test"], $this->user1["id"]); + $threadMessage = $this->channel->sendMessage( + ["text" => "Thread message for no filter test", "parent_id" => $parentMessage["message"]["id"]], + $this->user2["id"] + ); + + // Query threads without filter and sort parameters + $response = $this->client->queryThreads( + [], // Empty filter + null, // No sort + ["user_id" => $this->user1["id"]] // Only providing user_id in options + ); + + // Verify the response + $this->assertTrue(array_key_exists("threads", (array)$response)); + $this->assertGreaterThanOrEqual(1, count($response["threads"])); + + // Clean up + $this->channel->deleteMessage($threadMessage["message"]["id"]); + $this->channel->deleteMessage($parentMessage["message"]["id"]); + } } From 82b86ce05cf4e2b9cb517d0d2f30c66061434487 Mon Sep 17 00:00:00 2001 From: Aditya Alif Nugraha Date: Mon, 14 Apr 2025 17:24:10 +0200 Subject: [PATCH 6/7] Remove clean up --- tests/integration/IntegrationTest.php | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/tests/integration/IntegrationTest.php b/tests/integration/IntegrationTest.php index e72921e..53fac0f 100644 --- a/tests/integration/IntegrationTest.php +++ b/tests/integration/IntegrationTest.php @@ -1540,10 +1540,6 @@ public function testQueryThreadsWithFilter() // Verify the response $this->assertTrue(array_key_exists("threads", (array)$response)); $this->assertGreaterThanOrEqual(1, count($response["threads"])); - - // Clean up - $this->channel->deleteMessage($threadMessage["message"]["id"]); - $this->channel->deleteMessage($parentMessage["message"]["id"]); } public function testQueryThreadsWithSort() @@ -1571,12 +1567,6 @@ public function testQueryThreadsWithSort() // Verify the response $this->assertTrue(array_key_exists("threads", (array)$response)); $this->assertGreaterThanOrEqual(2, count($response["threads"])); - - // Clean up - $this->channel->deleteMessage($threadMessage1["message"]["id"]); - $this->channel->deleteMessage($parentMessage1["message"]["id"]); - $this->channel->deleteMessage($threadMessage2["message"]["id"]); - $this->channel->deleteMessage($parentMessage2["message"]["id"]); } public function testQueryThreadsWithFilterAndSort() @@ -1604,12 +1594,6 @@ public function testQueryThreadsWithFilterAndSort() // Verify the response $this->assertTrue(array_key_exists("threads", (array)$response)); $this->assertGreaterThanOrEqual(2, count($response["threads"])); - - // Clean up - $this->channel->deleteMessage($threadMessage1["message"]["id"]); - $this->channel->deleteMessage($parentMessage1["message"]["id"]); - $this->channel->deleteMessage($threadMessage2["message"]["id"]); - $this->channel->deleteMessage($parentMessage2["message"]["id"]); } public function testQueryThreadsWithoutFilterAndSort() @@ -1631,9 +1615,5 @@ public function testQueryThreadsWithoutFilterAndSort() // Verify the response $this->assertTrue(array_key_exists("threads", (array)$response)); $this->assertGreaterThanOrEqual(1, count($response["threads"])); - - // Clean up - $this->channel->deleteMessage($threadMessage["message"]["id"]); - $this->channel->deleteMessage($parentMessage["message"]["id"]); } } From d807ba7da6eca202390d27f506a9fd1a23af5a5e Mon Sep 17 00:00:00 2001 From: Aditya Alif Nugraha Date: Mon, 14 Apr 2025 17:29:31 +0200 Subject: [PATCH 7/7] Fix test example --- tests/integration/IntegrationTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/integration/IntegrationTest.php b/tests/integration/IntegrationTest.php index 53fac0f..ed44c2e 100644 --- a/tests/integration/IntegrationTest.php +++ b/tests/integration/IntegrationTest.php @@ -1532,7 +1532,7 @@ public function testQueryThreadsWithFilter() // Query threads with filter $response = $this->client->queryThreads( - ["parent_id" => ['$eq' => $parentMessage["message"]["id"]]], + ["parent_message_id" => ['$eq' => $parentMessage["message"]["id"]]], null, ["user_id" => $this->user1["id"]] );