From 90973e4d17414d661658f1f4091de007de111e6c Mon Sep 17 00:00:00 2001 From: Dishant Hirpara Date: Tue, 4 Aug 2026 13:34:25 -0700 Subject: [PATCH 1/5] [PHP] Add created/modified time search params to searchAll() #9538 What changed: - Added fromCreatedTime, toCreatedTime, fromModifiedTime, toModifiedTime optional parameters to searchAll() and searchAllTestUsers() in src/SDK/Management/User.php, following the existing positional-arg / array_filter pattern used for the other optional search params in this file. - Added PHPDoc @param entries for all 4 new params on both methods. - Updated the README "Search All Users" example to show the new trailing params. Verified: - Syntax-verified with `php -l src/SDK/Management/User.php` (no syntax errors detected), using PHP 8.5.9 installed via Homebrew for this session. Not verified: - No functional/integration testing was performed. This SDK's existing UserTest.php tests are live integration tests that skip without real DESCOPE_PROJECT_ID / DESCOPE_MANAGEMENT_KEY credentials, so the new params were not exercised against a running Descope environment. --- README.md | 8 +++++++- src/SDK/Management/User.php | 36 ++++++++++++++++++++++++++++++------ 2 files changed, 37 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 04034b3..2d19249 100644 --- a/README.md +++ b/README.md @@ -474,7 +474,13 @@ $response = $descopeSDK->management->user->searchAll( ['ssoApp123'], // ssoAppIds [ // sort ['field' => 'displayName', 'desc' => true] - ] + ], + null, // tenantRoleIds + null, // tenantRoleNames + 1700000000000, // fromCreatedTime (Unix epoch milliseconds) + 1800000000000, // toCreatedTime (Unix epoch milliseconds) + 1700000000000, // fromModifiedTime (Unix epoch milliseconds) + 1800000000000 // toModifiedTime (Unix epoch milliseconds) ); print_r($response); ``` diff --git a/src/SDK/Management/User.php b/src/SDK/Management/User.php index 20d1fc0..419df55 100644 --- a/src/SDK/Management/User.php +++ b/src/SDK/Management/User.php @@ -547,6 +547,10 @@ public function loadByUserId(string $userId): array * @param string|null $text Optional string, allows free text search among all user's attributes. * @param array|null $tenantRoleIds Optional map of tenants and list of role IDs to filter by. * @param array|null $tenantRoleNames Optional map of tenants and list of role names to filter by. + * @param int|null $fromCreatedTime Optional, only include users created on or after this time (Unix epoch milliseconds). + * @param int|null $toCreatedTime Optional, only include users created on or before this time (Unix epoch milliseconds). + * @param int|null $fromModifiedTime Optional, only include users modified on or after this time (Unix epoch milliseconds). + * @param int|null $toModifiedTime Optional, only include users modified on or before this time (Unix epoch milliseconds). * @return array Return dict in the format {"users": []}. "users" contains a list of all of the found users and their information. * @throws AuthException if search operation fails. */ @@ -567,7 +571,11 @@ public function searchAll( $ssoAppIds = null, $sort = null, $tenantRoleIds = null, - $tenantRoleNames = null + $tenantRoleNames = null, + $fromCreatedTime = null, + $toCreatedTime = null, + $fromModifiedTime = null, + $toModifiedTime = null ) { // Prepare the request body ensuring PHP 7.x compatibility $body = [ @@ -593,13 +601,17 @@ public function searchAll( }, $sort) : [], 'loginIds' => [], 'tenantRoleIds' => $this->mapToValuesObject($tenantRoleIds), - 'tenantRoleNames' => $this->mapToValuesObject($tenantRoleNames) + 'tenantRoleNames' => $this->mapToValuesObject($tenantRoleNames), + 'fromCreatedTime' => $fromCreatedTime, + 'toCreatedTime' => $toCreatedTime, + 'fromModifiedTime' => $fromModifiedTime, + 'toModifiedTime' => $toModifiedTime ]; - + $body = array_filter($body, function ($value) { return $value !== null && $value !== ''; }); - + return $this->api->doPost( MgmtV1::$USERS_SEARCH_PATH, $body, @@ -1425,6 +1437,10 @@ public function loadUsers(array $userIds, bool $includeInvalidUsers = false): ar * @param string|null $text Optional free text search. * @param array|null $tenantRoleIds Optional map of tenants and list of role IDs. * @param array|null $tenantRoleNames Optional map of tenants and list of role names. + * @param int|null $fromCreatedTime Optional, only include users created on or after this time (Unix epoch milliseconds). + * @param int|null $toCreatedTime Optional, only include users created on or before this time (Unix epoch milliseconds). + * @param int|null $fromModifiedTime Optional, only include users modified on or after this time (Unix epoch milliseconds). + * @param int|null $toModifiedTime Optional, only include users modified on or before this time (Unix epoch milliseconds). * @return array Return dict in the format {"users": []}. * @throws AuthException */ @@ -1442,7 +1458,11 @@ public function searchAllTestUsers( $ssoAppIds = null, $sort = null, $tenantRoleIds = null, - $tenantRoleNames = null + $tenantRoleNames = null, + $fromCreatedTime = null, + $toCreatedTime = null, + $fromModifiedTime = null, + $toModifiedTime = null ): array { $body = [ 'loginId' => $loginId ?? '', @@ -1466,7 +1486,11 @@ public function searchAllTestUsers( }, $sort) : [], 'loginIds' => [], 'tenantRoleIds' => $this->mapToValuesObject($tenantRoleIds), - 'tenantRoleNames' => $this->mapToValuesObject($tenantRoleNames) + 'tenantRoleNames' => $this->mapToValuesObject($tenantRoleNames), + 'fromCreatedTime' => $fromCreatedTime, + 'toCreatedTime' => $toCreatedTime, + 'fromModifiedTime' => $fromModifiedTime, + 'toModifiedTime' => $toModifiedTime ]; $body = array_filter($body, function ($value) { From 42d8d7f386551c041fd7a095a3e4a32e016f736f Mon Sep 17 00:00:00 2001 From: dishanthirpara-maker Date: Tue, 11 Aug 2026 09:40:36 -0700 Subject: [PATCH 2/5] Apply suggestion from @shuni-bot[bot] Co-authored-by: shuni-bot[bot] <251468265+shuni-bot[bot]@users.noreply.github.com> --- src/SDK/Management/User.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/SDK/Management/User.php b/src/SDK/Management/User.php index 419df55..73ab063 100644 --- a/src/SDK/Management/User.php +++ b/src/SDK/Management/User.php @@ -602,10 +602,10 @@ public function searchAll( 'loginIds' => [], 'tenantRoleIds' => $this->mapToValuesObject($tenantRoleIds), 'tenantRoleNames' => $this->mapToValuesObject($tenantRoleNames), - 'fromCreatedTime' => $fromCreatedTime, - 'toCreatedTime' => $toCreatedTime, - 'fromModifiedTime' => $fromModifiedTime, - 'toModifiedTime' => $toModifiedTime + 'fromCreatedTime' => $fromCreatedTime !== null ? (int)$fromCreatedTime : null, + 'toCreatedTime' => $toCreatedTime !== null ? (int)$toCreatedTime : null, + 'fromModifiedTime' => $fromModifiedTime !== null ? (int)$fromModifiedTime : null, + 'toModifiedTime' => $toModifiedTime !== null ? (int)$toModifiedTime : null ]; $body = array_filter($body, function ($value) { From f02a3f09542461d66628307d5c0057f1765b57be Mon Sep 17 00:00:00 2001 From: dishanthirpara-maker Date: Tue, 11 Aug 2026 09:45:29 -0700 Subject: [PATCH 3/5] Apply suggestion from @shuni-bot[bot] Co-authored-by: shuni-bot[bot] <251468265+shuni-bot[bot]@users.noreply.github.com> --- src/SDK/Management/User.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/SDK/Management/User.php b/src/SDK/Management/User.php index 73ab063..57e894d 100644 --- a/src/SDK/Management/User.php +++ b/src/SDK/Management/User.php @@ -1487,10 +1487,10 @@ public function searchAllTestUsers( 'loginIds' => [], 'tenantRoleIds' => $this->mapToValuesObject($tenantRoleIds), 'tenantRoleNames' => $this->mapToValuesObject($tenantRoleNames), - 'fromCreatedTime' => $fromCreatedTime, - 'toCreatedTime' => $toCreatedTime, - 'fromModifiedTime' => $fromModifiedTime, - 'toModifiedTime' => $toModifiedTime + 'fromCreatedTime' => $fromCreatedTime !== null ? (int)$fromCreatedTime : null, + 'toCreatedTime' => $toCreatedTime !== null ? (int)$toCreatedTime : null, + 'fromModifiedTime' => $fromModifiedTime !== null ? (int)$fromModifiedTime : null, + 'toModifiedTime' => $toModifiedTime !== null ? (int)$toModifiedTime : null ]; $body = array_filter($body, function ($value) { From 5efc4f472d27736b5491cc305f611e51e7d6252e Mon Sep 17 00:00:00 2001 From: Dishant Hirpara Date: Tue, 11 Aug 2026 10:59:17 -0700 Subject: [PATCH 4/5] docs: fix boundary wording for time-filter params #9538 What changed: - Corrected $fromCreatedTime/$fromModifiedTime PHPDoc in both searchAll() and searchAllTestUsers(): "on or after" -> "after", to match confirmed backend behavior (SQL `>`, exclusive lower bound). - $toCreatedTime/$toModifiedTime already said "on or before" correctly (SQL `<=`, inclusive upper bound) - left unchanged. Verified: - Backend behavior confirmed directly in source across 3 repos in an earlier research pass: managementservice/internal/services/user.go (only the to* variants set Negative: true), common's search domain (negative flag selects Operator vs NegativeOperator), and userservice/internal/entities/search.go (Operator: " > ", NegativeOperator: " <= " for both createdtime and modifiedtime). - `php -l` reports no syntax errors. - Comment-only change; no functional code touched. Not verified: - No integration/functional testing against a live Descope API was performed; this is a documentation wording fix only. --- src/SDK/Management/User.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/SDK/Management/User.php b/src/SDK/Management/User.php index 419df55..a1e62d6 100644 --- a/src/SDK/Management/User.php +++ b/src/SDK/Management/User.php @@ -547,9 +547,9 @@ public function loadByUserId(string $userId): array * @param string|null $text Optional string, allows free text search among all user's attributes. * @param array|null $tenantRoleIds Optional map of tenants and list of role IDs to filter by. * @param array|null $tenantRoleNames Optional map of tenants and list of role names to filter by. - * @param int|null $fromCreatedTime Optional, only include users created on or after this time (Unix epoch milliseconds). + * @param int|null $fromCreatedTime Optional, only include users created after this time (Unix epoch milliseconds). * @param int|null $toCreatedTime Optional, only include users created on or before this time (Unix epoch milliseconds). - * @param int|null $fromModifiedTime Optional, only include users modified on or after this time (Unix epoch milliseconds). + * @param int|null $fromModifiedTime Optional, only include users modified after this time (Unix epoch milliseconds). * @param int|null $toModifiedTime Optional, only include users modified on or before this time (Unix epoch milliseconds). * @return array Return dict in the format {"users": []}. "users" contains a list of all of the found users and their information. * @throws AuthException if search operation fails. @@ -1437,9 +1437,9 @@ public function loadUsers(array $userIds, bool $includeInvalidUsers = false): ar * @param string|null $text Optional free text search. * @param array|null $tenantRoleIds Optional map of tenants and list of role IDs. * @param array|null $tenantRoleNames Optional map of tenants and list of role names. - * @param int|null $fromCreatedTime Optional, only include users created on or after this time (Unix epoch milliseconds). + * @param int|null $fromCreatedTime Optional, only include users created after this time (Unix epoch milliseconds). * @param int|null $toCreatedTime Optional, only include users created on or before this time (Unix epoch milliseconds). - * @param int|null $fromModifiedTime Optional, only include users modified on or after this time (Unix epoch milliseconds). + * @param int|null $fromModifiedTime Optional, only include users modified after this time (Unix epoch milliseconds). * @param int|null $toModifiedTime Optional, only include users modified on or before this time (Unix epoch milliseconds). * @return array Return dict in the format {"users": []}. * @throws AuthException From 2c94f1fe59d867d1aa72aa6e526996ba787fcf75 Mon Sep 17 00:00:00 2001 From: Dishant Hirpara Date: Fri, 14 Aug 2026 11:31:06 -0700 Subject: [PATCH 5/5] test: add mock-based test for created/modified time search params #9538 Adds a mock-based test (src/tests/Management/UserSearchMockTest.php) covering searchAll() and searchAllTestUsers() with the 4 time-filter params. Uses Guzzle's MockHandler to verify the exact request body without needing live credentials. Registered in phpunit.xml so it runs in CI. Verified: composer test passes, 96 tests / 425 assertions, 0 failures. --- phpunit.xml | 1 + src/tests/Management/UserSearchMockTest.php | 115 ++++++++++++++++++++ 2 files changed, 116 insertions(+) create mode 100644 src/tests/Management/UserSearchMockTest.php diff --git a/phpunit.xml b/phpunit.xml index 59b32e5..59b2983 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -11,6 +11,7 @@ src/tests/StaticStateIsolationTest.php src/tests/EndpointsTest.php src/tests/Management/ManagementParityTest.php + src/tests/Management/UserSearchMockTest.php src/tests/Auth/AuthParityTest.php diff --git a/src/tests/Management/UserSearchMockTest.php b/src/tests/Management/UserSearchMockTest.php new file mode 100644 index 0000000..bc8a3df --- /dev/null +++ b/src/tests/Management/UserSearchMockTest.php @@ -0,0 +1,115 @@ + []]))]); + $stack = HandlerStack::create($mock); + $stack->push(Middleware::history($requests)); + $injectedClient = new Client(['handler' => $stack]); + + $sdk = new DescopeSDK([ + 'projectId' => 'test_project_id', + 'managementKey' => 'test_management_key', + 'httpClient' => $injectedClient, + ]); + + $fromCreatedTime = 1700000000000; + $toCreatedTime = 1800000000000; + $fromModifiedTime = 1700000000000; + $toModifiedTime = 1800000000000; + + $sdk->management->user->searchAll( + null, + null, + null, + 0, + null, + 0, + false, + false, + false, + null, + null, + null, + null, + null, + null, + null, + null, + $fromCreatedTime, + $toCreatedTime, + $fromModifiedTime, + $toModifiedTime + ); + + $this->assertCount(1, $requests); + $body = json_decode((string) $requests[0]['request']->getBody(), true); + + $this->assertSame($fromCreatedTime, $body['fromCreatedTime']); + $this->assertSame($toCreatedTime, $body['toCreatedTime']); + $this->assertSame($fromModifiedTime, $body['fromModifiedTime']); + $this->assertSame($toModifiedTime, $body['toModifiedTime']); + } + + public function testSearchAllTestUsersSendsTimeFilterParams() + { + $requests = []; + $mock = new MockHandler([new Response(200, [], json_encode(['users' => []]))]); + $stack = HandlerStack::create($mock); + $stack->push(Middleware::history($requests)); + $injectedClient = new Client(['handler' => $stack]); + + $sdk = new DescopeSDK([ + 'projectId' => 'test_project_id', + 'managementKey' => 'test_management_key', + 'httpClient' => $injectedClient, + ]); + + $fromCreatedTime = 1700000000000; + $toCreatedTime = 1800000000000; + $fromModifiedTime = 1700000000000; + $toModifiedTime = 1800000000000; + + $sdk->management->user->searchAllTestUsers( + null, + null, + null, + 0, + null, + 0, + null, + null, + null, + null, + null, + null, + null, + null, + $fromCreatedTime, + $toCreatedTime, + $fromModifiedTime, + $toModifiedTime + ); + + $this->assertCount(1, $requests); + $body = json_decode((string) $requests[0]['request']->getBody(), true); + + $this->assertSame($fromCreatedTime, $body['fromCreatedTime']); + $this->assertSame($toCreatedTime, $body['toCreatedTime']); + $this->assertSame($fromModifiedTime, $body['fromModifiedTime']); + $this->assertSame($toModifiedTime, $body['toModifiedTime']); + } +}