From 71cb434b7182bb43fc6d2cd50425dd2676d9fc12 Mon Sep 17 00:00:00 2001 From: Ben Lobaugh Date: Tue, 26 Aug 2025 21:13:14 -0700 Subject: [PATCH 1/2] Added Organization Feature Flags functionality in Organizations by introducing the getFeatureFlags($organizationId) method. Added tests to validate organization feature flags. Resolved a deprecated notice in the OrganizationsTest to ensure compatibility with newer PHP versions. Implemented support for reading Vault items. Expanded the test suite to encompass Vault-related functionalities. --- lib/Organizations.php | 24 +++++ lib/Resource/VaultObject.php | 27 ++++++ lib/Vault.php | 78 ++++++++++++++++ tests/WorkOS/OrganizationsTest.php | 64 +++++++++++++ tests/WorkOS/VaultTest.php | 139 +++++++++++++++++++++++++++++ 5 files changed, 332 insertions(+) create mode 100644 lib/Resource/VaultObject.php create mode 100644 lib/Vault.php create mode 100644 tests/WorkOS/VaultTest.php diff --git a/lib/Organizations.php b/lib/Organizations.php index 283be2e..840095d 100644 --- a/lib/Organizations.php +++ b/lib/Organizations.php @@ -250,4 +250,28 @@ public function listOrganizationRoles($organizationId) return [$roles]; } + + /** + * Get feature flags for an organization. + * + * @param string $organizationId WorkOS organization ID to fetch feature flags for + * + * @throws Exception\WorkOSException + * + * @return array Feature flags for the organization + */ + public function getFeatureFlags($organizationId) + { + $featureFlagsPath = "organizations/{$organizationId}/feature-flags"; + + $response = Client::request( + Client::METHOD_GET, + $featureFlagsPath, + null, + null, + true + ); + + return $response; + } } diff --git a/lib/Resource/VaultObject.php b/lib/Resource/VaultObject.php new file mode 100644 index 0000000..b0c1b8b --- /dev/null +++ b/lib/Resource/VaultObject.php @@ -0,0 +1,27 @@ + "id", + "name" => "name", + "updated_at" => "updatedAt", + "value" => "value", + "metadata" => "metadata" + ]; +} diff --git a/lib/Vault.php b/lib/Vault.php new file mode 100644 index 0000000..2f4fd50 --- /dev/null +++ b/lib/Vault.php @@ -0,0 +1,78 @@ + $limit, + "before" => $before, + "after" => $after, + "order" => $order + ]; + + $response = Client::request( + Client::METHOD_GET, + $vaultObjectsPath, + null, + $params, + true + ); + + $vaultObjects = []; + list($before, $after) = Util\Request::parsePaginationArgs($response); + foreach ($response["data"] as $responseData) { + \array_push($vaultObjects, Resource\VaultObject::constructFromResponse($responseData)); + } + + return [$before, $after, $vaultObjects]; + } + + + + +} diff --git a/tests/WorkOS/OrganizationsTest.php b/tests/WorkOS/OrganizationsTest.php index 200cc11..f2f2a89 100644 --- a/tests/WorkOS/OrganizationsTest.php +++ b/tests/WorkOS/OrganizationsTest.php @@ -10,6 +10,11 @@ class OrganizationsTest extends TestCase setUp as protected traitSetUp; } + /** + * @var Organizations + */ + protected $organizations; + protected function setUp(): void { $this->traitSetUp(); @@ -190,6 +195,25 @@ public function testListOrganizationRoles() $this->assertSame($role, $roles[0]->toArray()); } + public function testGetFeatureFlags() + { + $featureFlagsPath = "organizations/org_01EHQMYV6MBK39QC5PZXHY59C3/feature-flags"; + + $result = $this->featureFlagsResponseFixture(); + + $this->mockRequest( + Client::METHOD_GET, + $featureFlagsPath, + null, + null, + true, + $result + ); + + $response = $this->organizations->getFeatureFlags("org_01EHQMYV6MBK39QC5PZXHY59C3"); + $this->assertSame(json_decode($result, true), $response); + } + // Fixtures private function createOrganizationResponseFixture() @@ -342,4 +366,44 @@ private function roleFixture() "updated_at" => "2024-01-01T00:00:00.000Z" ]; } + + private function featureFlagsResponseFixture() + { + return json_encode([ + "object" => "list", + "data" => [ + [ + "object" => "feature_flag", + "id" => "flag_01K2QR5YSWRB8J7GGAG05Y24HQ", + "slug" => "flag3", + "name" => "Flag3", + "description" => "", + "created_at" => "2025-08-15T20:54:13.561Z", + "updated_at" => "2025-08-15T20:54:13.561Z" + ], + [ + "object" => "feature_flag", + "id" => "flag_01K2QR5HGK2HQVFDZ4T60GWGVD", + "slug" => "flag2", + "name" => "Flag2", + "description" => "", + "created_at" => "2025-08-15T20:53:59.952Z", + "updated_at" => "2025-08-15T20:53:59.952Z" + ], + [ + "object" => "feature_flag", + "id" => "flag_01K2QKSH38RF4P9FV917PE24R3", + "slug" => "flag1", + "name" => "Flag1", + "description" => "", + "created_at" => "2025-08-15T19:37:32.005Z", + "updated_at" => "2025-08-15T19:37:32.005Z" + ], + ], + "list_metadata" => [ + "before" => "", + "after" => "" + ] + ]); + } } diff --git a/tests/WorkOS/VaultTest.php b/tests/WorkOS/VaultTest.php new file mode 100644 index 0000000..2b3e00d --- /dev/null +++ b/tests/WorkOS/VaultTest.php @@ -0,0 +1,139 @@ +traitSetUp(); + + $this->withApiKey(); + $this->vault = new Vault(); + } + + public function testGetVaultObject() + { + $vaultObjectPath = "vault/v1/kv/vault_obj_01EHQMYV6MBK39QC5PZXHY59C3"; + + $result = $this->vaultObjectResponseFixture(); + + $this->mockRequest( + Client::METHOD_GET, + $vaultObjectPath, + null, + null, + true, + $result + ); + + $vaultObject = $this->vaultObjectFixture(); + + $response = $this->vault->getVaultObject("vault_obj_01EHQMYV6MBK39QC5PZXHY59C3"); + $this->assertSame($vaultObject, $response->toArray()); + } + + public function testListVaultObjects() + { + $vaultObjectsPath = "vault/v1/kv"; + + $result = $this->vaultObjectsResponseFixture(); + + $params = [ + "limit" => 10, + "before" => null, + "after" => null, + "order" => null + ]; + + $this->mockRequest( + Client::METHOD_GET, + $vaultObjectsPath, + null, + $params, + true, + $result + ); + + $vaultObjects = $this->vaultObjectsFixture(); + + list($before, $after, $response) = $this->vault->listVaultObjects(); + $this->assertSame($vaultObjects, $response[0]->toArray()); + } + + + + + + + + // Fixtures + + private function vaultObjectResponseFixture() + { + return json_encode([ + "id" => "vault_obj_01EHQMYV6MBK39QC5PZXHY59C3", + "name" => "Test Vault Object", + "updated_at" => "2024-01-01T00:00:00.000Z", + "value" => null, + "metadata" => [] + ]); + } + + private function vaultObjectFixture() + { + return [ + "id" => "vault_obj_01EHQMYV6MBK39QC5PZXHY59C3", + "name" => "Test Vault Object", + "updatedAt" => "2024-01-01T00:00:00.000Z", + "value" => null, + "metadata" => [] + ]; + } + + private function vaultObjectsResponseFixture() + { + return json_encode([ + "object" => "list", + "data" => [ + [ + "id" => "vault_obj_01EHQMYV6MBK39QC5PZXHY59C3", + "name" => "Test Vault Object", + "updated_at" => "2024-01-01T00:00:00.000Z", + "value" => null, + "metadata" => [] + ] + ], + "list_metadata" => [ + "before" => null, + "after" => null + ] + ]); + } + + private function vaultObjectsFixture() + { + return [ + "id" => "vault_obj_01EHQMYV6MBK39QC5PZXHY59C3", + "name" => "Test Vault Object", + "updatedAt" => "2024-01-01T00:00:00.000Z", + "value" => null, + "metadata" => [] + ]; + } + + + + +} From 714a9e939a1b24dc167485a3bc3436cc9ef8429c Mon Sep 17 00:00:00 2001 From: Ben Lobaugh Date: Tue, 25 Nov 2025 08:29:33 -0800 Subject: [PATCH 2/2] Added patch with pagination and other changes from @nicknisi This brings it into alignment with the Node SDK --- lib/Organizations.php | 33 +++++++++++++++++++++----- lib/Resource/FeatureFlag.php | 37 ++++++++++++++++++++++++++++++ lib/Resource/VaultObject.php | 2 +- tests/WorkOS/OrganizationsTest.php | 29 +++++++++++++++++++---- 4 files changed, 90 insertions(+), 11 deletions(-) create mode 100644 lib/Resource/FeatureFlag.php diff --git a/lib/Organizations.php b/lib/Organizations.php index 840095d..93d63f8 100644 --- a/lib/Organizations.php +++ b/lib/Organizations.php @@ -252,26 +252,47 @@ public function listOrganizationRoles($organizationId) } /** - * Get feature flags for an organization. + * List feature flags for an organization. * * @param string $organizationId WorkOS organization ID to fetch feature flags for + * @param int $limit Maximum number of records to return + * @param null|string $before FeatureFlag ID to look before + * @param null|string $after FeatureFlag ID to look after + * @param Resource\Order $order The Order in which to paginate records * * @throws Exception\WorkOSException * - * @return array Feature flags for the organization + * @return array{?string, ?string, Resource\FeatureFlag[]} An array containing the FeatureFlag ID to use as before and after cursor, and an array of FeatureFlag instances */ - public function getFeatureFlags($organizationId) - { + public function listOrganizationFeatureFlags( + $organizationId, + $limit = self::DEFAULT_PAGE_SIZE, + $before = null, + $after = null, + $order = null + ) { $featureFlagsPath = "organizations/{$organizationId}/feature-flags"; + $params = [ + "limit" => $limit, + "before" => $before, + "after" => $after, + "order" => $order + ]; $response = Client::request( Client::METHOD_GET, $featureFlagsPath, null, - null, + $params, true ); - return $response; + $featureFlags = []; + list($before, $after) = Util\Request::parsePaginationArgs($response); + foreach ($response["data"] as $responseData) { + \array_push($featureFlags, Resource\FeatureFlag::constructFromResponse($responseData)); + } + + return [$before, $after, $featureFlags]; } } diff --git a/lib/Resource/FeatureFlag.php b/lib/Resource/FeatureFlag.php new file mode 100644 index 0000000..8c58a7c --- /dev/null +++ b/lib/Resource/FeatureFlag.php @@ -0,0 +1,37 @@ + "id", + "slug" => "slug", + "name" => "name", + "description" => "description", + "created_at" => "createdAt", + "updated_at" => "updatedAt" + ]; +} diff --git a/lib/Resource/VaultObject.php b/lib/Resource/VaultObject.php index b0c1b8b..ed18919 100644 --- a/lib/Resource/VaultObject.php +++ b/lib/Resource/VaultObject.php @@ -20,7 +20,7 @@ class VaultObject extends BaseWorkOSResource public const RESPONSE_TO_RESOURCE_KEY = [ "id" => "id", "name" => "name", - "updated_at" => "updatedAt", + "updated_at" => "updatedAt", "value" => "value", "metadata" => "metadata" ]; diff --git a/tests/WorkOS/OrganizationsTest.php b/tests/WorkOS/OrganizationsTest.php index f2f2a89..6826798 100644 --- a/tests/WorkOS/OrganizationsTest.php +++ b/tests/WorkOS/OrganizationsTest.php @@ -195,23 +195,32 @@ public function testListOrganizationRoles() $this->assertSame($role, $roles[0]->toArray()); } - public function testGetFeatureFlags() + public function testListOrganizationFeatureFlags() { $featureFlagsPath = "organizations/org_01EHQMYV6MBK39QC5PZXHY59C3/feature-flags"; $result = $this->featureFlagsResponseFixture(); + $params = [ + "limit" => 10, + "before" => null, + "after" => null, + "order" => null + ]; + $this->mockRequest( Client::METHOD_GET, $featureFlagsPath, null, - null, + $params, true, $result ); - $response = $this->organizations->getFeatureFlags("org_01EHQMYV6MBK39QC5PZXHY59C3"); - $this->assertSame(json_decode($result, true), $response); + $featureFlag = $this->featureFlagFixture(); + + list($before, $after, $featureFlags) = $this->organizations->listOrganizationFeatureFlags("org_01EHQMYV6MBK39QC5PZXHY59C3"); + $this->assertSame($featureFlag, $featureFlags[0]->toArray()); } // Fixtures @@ -367,6 +376,18 @@ private function roleFixture() ]; } + private function featureFlagFixture() + { + return [ + "id" => "flag_01K2QR5YSWRB8J7GGAG05Y24HQ", + "slug" => "flag3", + "name" => "Flag3", + "description" => "", + "createdAt" => "2025-08-15T20:54:13.561Z", + "updatedAt" => "2025-08-15T20:54:13.561Z" + ]; + } + private function featureFlagsResponseFixture() { return json_encode([