From 06014fa5cbf053165d717b8ca25d93add8dfc5ff Mon Sep 17 00:00:00 2001 From: felix Date: Wed, 20 May 2026 15:07:49 +0200 Subject: [PATCH 1/2] added tests for managing channels and updated channel object structure --- README.md | 63 ++++++++++ src/PushinatorClient.php | 118 ++++++++++++++++++ tests/ChannelsTest.php | 251 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 432 insertions(+) create mode 100644 tests/ChannelsTest.php diff --git a/README.md b/README.md index 88b8c40..da6c322 100644 --- a/README.md +++ b/README.md @@ -41,4 +41,67 @@ try { } catch (Exception $e) { echo "Error: " . $e->getMessage(); } +``` + +### Managing Channels + +All channel methods return an array with the decoded JSON response from the API. On failure, a `RuntimeException` is thrown. + +#### List channels + +```php +$channels = $client->listChannels(); +// $channels['data'] — array of channel objects +``` + +#### Create a channel + +```php +$channel = $client->createChannel( + name: 'My Channel', + description: 'Optional description', // optional + acknowledgmentEnabled: true // optional, default false +); +// $channel['data'] — created channel object +``` + +#### Get a channel + +```php +$channel = $client->getChannel('PUSHINATOR_CHANNEL_ID'); +// $channel['data'] — channel object +``` + +#### Update a channel + +```php +$channel = $client->updateChannel( + channelId: 'PUSHINATOR_CHANNEL_ID', + name: 'Updated Name', + description: 'Updated description', // optional + acknowledgmentEnabled: false // optional +); +// $channel['data'] — updated channel object +``` + +#### Delete a channel + +```php +$channel = $client->deleteChannel('PUSHINATOR_CHANNEL_ID'); +// $channel['data'] — deleted channel object +``` + +#### Channel object structure + +```json +{ + "data": { + "id": "channel-id", + "name": "My Channel", + "description": "Optional description", + "acknowledgment_enabled": false, + "created_at": "2024-01-01T00:00:00.000000Z", + "updated_at": "2024-01-01T00:00:00.000000Z" + } +} ``` \ No newline at end of file diff --git a/src/PushinatorClient.php b/src/PushinatorClient.php index f228970..b8c5dc0 100644 --- a/src/PushinatorClient.php +++ b/src/PushinatorClient.php @@ -64,4 +64,122 @@ public function sendNotification(string $channelId, string $notification): void ); } } + + /** + * List all channels. + * + * @return array + */ + public function listChannels(): array + { + return $this->request('GET', '/api/v2/channels'); + } + + /** + * Create a new channel. + * + * @param string $name + * @param string|null $description + * @param bool|null $acknowledgmentEnabled + * @return array + */ + public function createChannel(string $name, ?string $description = null, ?bool $acknowledgmentEnabled = null): array + { + $body = ['name' => $name]; + + if ($description !== null) { + $body['description'] = $description; + } + + if ($acknowledgmentEnabled !== null) { + $body['acknowledgment_enabled'] = $acknowledgmentEnabled; + } + + return $this->request('POST', '/api/v2/channels', $body); + } + + /** + * Get a channel by ID. + * + * @param string $channelId + * @return array + */ + public function getChannel(string $channelId): array + { + return $this->request('GET', "/api/v2/channels/{$channelId}"); + } + + /** + * Update a channel by ID. + * + * @param string $channelId + * @param string $name + * @param string|null $description + * @param bool|null $acknowledgmentEnabled + * @return array + */ + public function updateChannel(string $channelId, string $name, ?string $description = null, ?bool $acknowledgmentEnabled = null): array + { + $body = ['name' => $name]; + + if ($description !== null) { + $body['description'] = $description; + } + + if ($acknowledgmentEnabled !== null) { + $body['acknowledgment_enabled'] = $acknowledgmentEnabled; + } + + return $this->request('PUT', "/api/v2/channels/{$channelId}", $body); + } + + /** + * Delete a channel by ID. + * + * @param string $channelId + * @return array + */ + public function deleteChannel(string $channelId): array + { + return $this->request('DELETE', "/api/v2/channels/{$channelId}"); + } + + /** + * @param string $method + * @param string $path + * @param array $body + * @return array + */ + private function request(string $method, string $path, array $body = []): array + { + try { + $options = [ + 'headers' => [ + 'Authorization' => "Bearer {$this->apiToken}", + 'Content-Type' => 'application/json', + 'User-Agent' => self::$userAgent, + ], + ]; + + if (!empty($body)) { + $options['json'] = $body; + } + + $response = $this->client->request($method, self::$baseUrl . $path, $options); + + if ($response->getStatusCode() !== 200) { + throw new \RuntimeException( + "Request failed. Status: {$response->getStatusCode()}, Body: {$response->getBody()}" + ); + } + + return json_decode($response->getBody()->getContents(), true); + } catch (GuzzleException $e) { + throw new \RuntimeException( + "Request failed: {$e->getMessage()}", + $e->getCode(), + $e + ); + } + } } diff --git a/tests/ChannelsTest.php b/tests/ChannelsTest.php new file mode 100644 index 0000000..7ef1bb0 --- /dev/null +++ b/tests/ChannelsTest.php @@ -0,0 +1,251 @@ +push($history); + + return new PushinatorClient('test-token', new Client(['handler' => $handlerStack])); + } + + private function channelResponse(array $overrides = []): array + { + return array_merge([ + 'id' => 'channel-123', + 'name' => 'Test Channel', + 'description' => 'A test channel', + 'acknowledgment_enabled' => false, + 'created_at' => '2024-01-01T00:00:00.000000Z', + 'updated_at' => '2024-01-01T00:00:00.000000Z', + ], $overrides); + } + + // ------------------------------------------------------------------------- + // listChannels + // ------------------------------------------------------------------------- + + #[Test] + public function testListChannelsRequest() + { + $container = []; + $responseData = ['data' => [$this->channelResponse()]]; + $pushinator = $this->makeClient( + [new Response(200, [], json_encode($responseData))], + $container + ); + + $result = $pushinator->listChannels(); + + $request = $container[0]['request']; + $this->assertEquals('GET', $request->getMethod()); + $this->assertEquals('https://api.pushinator.com/api/v2/channels', $request->getUri()); + $this->assertEquals('Bearer test-token', $request->getHeaderLine('Authorization')); + $this->assertEquals('application/json', $request->getHeaderLine('Content-Type')); + $this->assertEquals('pushinator-php/1.0', $request->getHeaderLine('User-Agent')); + $this->assertEquals($responseData, $result); + } + + #[Test] + public function testListChannelsFailure() + { + $pushinator = $this->makeClient([new Response(500)]); + + $this->expectException(\RuntimeException::class); + $pushinator->listChannels(); + } + + // ------------------------------------------------------------------------- + // createChannel + // ------------------------------------------------------------------------- + + #[Test] + public function testCreateChannelRequest() + { + $container = []; + $responseData = ['data' => $this->channelResponse()]; + $pushinator = $this->makeClient( + [new Response(200, [], json_encode($responseData))], + $container + ); + + $result = $pushinator->createChannel('Test Channel', 'A test channel', true); + + $request = $container[0]['request']; + $this->assertEquals('POST', $request->getMethod()); + $this->assertEquals('https://api.pushinator.com/api/v2/channels', $request->getUri()); + $this->assertEquals('Bearer test-token', $request->getHeaderLine('Authorization')); + $this->assertEquals('application/json', $request->getHeaderLine('Content-Type')); + $this->assertEquals('pushinator-php/1.0', $request->getHeaderLine('User-Agent')); + $this->assertEquals( + '{"name":"Test Channel","description":"A test channel","acknowledgment_enabled":true}', + $request->getBody()->getContents() + ); + $this->assertEquals($responseData, $result); + } + + #[Test] + public function testCreateChannelWithNameOnly() + { + $container = []; + $pushinator = $this->makeClient( + [new Response(200, [], json_encode(['data' => $this->channelResponse()]))], + $container + ); + + $pushinator->createChannel('Test Channel'); + + $this->assertEquals( + '{"name":"Test Channel"}', + $container[0]['request']->getBody()->getContents() + ); + } + + #[Test] + public function testCreateChannelFailure() + { + $pushinator = $this->makeClient([new Response(500)]); + + $this->expectException(\RuntimeException::class); + $pushinator->createChannel('Test Channel'); + } + + // ------------------------------------------------------------------------- + // getChannel + // ------------------------------------------------------------------------- + + #[Test] + public function testGetChannelRequest() + { + $container = []; + $responseData = ['data' => $this->channelResponse()]; + $pushinator = $this->makeClient( + [new Response(200, [], json_encode($responseData))], + $container + ); + + $result = $pushinator->getChannel('channel-123'); + + $request = $container[0]['request']; + $this->assertEquals('GET', $request->getMethod()); + $this->assertEquals('https://api.pushinator.com/api/v2/channels/channel-123', $request->getUri()); + $this->assertEquals('Bearer test-token', $request->getHeaderLine('Authorization')); + $this->assertEquals('application/json', $request->getHeaderLine('Content-Type')); + $this->assertEquals('pushinator-php/1.0', $request->getHeaderLine('User-Agent')); + $this->assertEquals($responseData, $result); + } + + #[Test] + public function testGetChannelNotFound() + { + $pushinator = $this->makeClient([new Response(404)]); + + $this->expectException(\RuntimeException::class); + $pushinator->getChannel('channel-123'); + } + + // ------------------------------------------------------------------------- + // updateChannel + // ------------------------------------------------------------------------- + + #[Test] + public function testUpdateChannelRequest() + { + $container = []; + $responseData = ['data' => $this->channelResponse(['name' => 'Updated Channel'])]; + $pushinator = $this->makeClient( + [new Response(200, [], json_encode($responseData))], + $container + ); + + $result = $pushinator->updateChannel('channel-123', 'Updated Channel', 'New description', false); + + $request = $container[0]['request']; + $this->assertEquals('PUT', $request->getMethod()); + $this->assertEquals('https://api.pushinator.com/api/v2/channels/channel-123', $request->getUri()); + $this->assertEquals('Bearer test-token', $request->getHeaderLine('Authorization')); + $this->assertEquals('application/json', $request->getHeaderLine('Content-Type')); + $this->assertEquals('pushinator-php/1.0', $request->getHeaderLine('User-Agent')); + $this->assertEquals( + '{"name":"Updated Channel","description":"New description","acknowledgment_enabled":false}', + $request->getBody()->getContents() + ); + $this->assertEquals($responseData, $result); + } + + #[Test] + public function testUpdateChannelWithNameOnly() + { + $container = []; + $pushinator = $this->makeClient( + [new Response(200, [], json_encode(['data' => $this->channelResponse()]))], + $container + ); + + $pushinator->updateChannel('channel-123', 'Updated Channel'); + + $this->assertEquals( + '{"name":"Updated Channel"}', + $container[0]['request']->getBody()->getContents() + ); + } + + #[Test] + public function testUpdateChannelNotFound() + { + $pushinator = $this->makeClient([new Response(404)]); + + $this->expectException(\RuntimeException::class); + $pushinator->updateChannel('channel-123', 'Updated Channel'); + } + + // ------------------------------------------------------------------------- + // deleteChannel + // ------------------------------------------------------------------------- + + #[Test] + public function testDeleteChannelRequest() + { + $container = []; + $responseData = ['data' => $this->channelResponse()]; + $pushinator = $this->makeClient( + [new Response(200, [], json_encode($responseData))], + $container + ); + + $result = $pushinator->deleteChannel('channel-123'); + + $request = $container[0]['request']; + $this->assertEquals('DELETE', $request->getMethod()); + $this->assertEquals('https://api.pushinator.com/api/v2/channels/channel-123', $request->getUri()); + $this->assertEquals('Bearer test-token', $request->getHeaderLine('Authorization')); + $this->assertEquals('application/json', $request->getHeaderLine('Content-Type')); + $this->assertEquals('pushinator-php/1.0', $request->getHeaderLine('User-Agent')); + $this->assertEquals($responseData, $result); + } + + #[Test] + public function testDeleteChannelNotFound() + { + $pushinator = $this->makeClient([new Response(404)]); + + $this->expectException(\RuntimeException::class); + $pushinator->deleteChannel('channel-123'); + } +} From 5f973938cf8306e7a8a52d5742610975214b210a Mon Sep 17 00:00:00 2001 From: felix Date: Thu, 21 May 2026 18:18:06 +0200 Subject: [PATCH 2/2] added tests for managing channels and updated channel object structure --- README.md | 2 -- src/PushinatorClient.php | 8 -------- tests/ChannelsTest.php | 4 ++-- 3 files changed, 2 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index da6c322..2ab0617 100644 --- a/README.md +++ b/README.md @@ -60,7 +60,6 @@ $channels = $client->listChannels(); $channel = $client->createChannel( name: 'My Channel', description: 'Optional description', // optional - acknowledgmentEnabled: true // optional, default false ); // $channel['data'] — created channel object ``` @@ -79,7 +78,6 @@ $channel = $client->updateChannel( channelId: 'PUSHINATOR_CHANNEL_ID', name: 'Updated Name', description: 'Updated description', // optional - acknowledgmentEnabled: false // optional ); // $channel['data'] — updated channel object ``` diff --git a/src/PushinatorClient.php b/src/PushinatorClient.php index b8c5dc0..6adc5cc 100644 --- a/src/PushinatorClient.php +++ b/src/PushinatorClient.php @@ -91,10 +91,6 @@ public function createChannel(string $name, ?string $description = null, ?bool $ $body['description'] = $description; } - if ($acknowledgmentEnabled !== null) { - $body['acknowledgment_enabled'] = $acknowledgmentEnabled; - } - return $this->request('POST', '/api/v2/channels', $body); } @@ -126,10 +122,6 @@ public function updateChannel(string $channelId, string $name, ?string $descript $body['description'] = $description; } - if ($acknowledgmentEnabled !== null) { - $body['acknowledgment_enabled'] = $acknowledgmentEnabled; - } - return $this->request('PUT', "/api/v2/channels/{$channelId}", $body); } diff --git a/tests/ChannelsTest.php b/tests/ChannelsTest.php index 7ef1bb0..9841abb 100644 --- a/tests/ChannelsTest.php +++ b/tests/ChannelsTest.php @@ -94,7 +94,7 @@ public function testCreateChannelRequest() $this->assertEquals('application/json', $request->getHeaderLine('Content-Type')); $this->assertEquals('pushinator-php/1.0', $request->getHeaderLine('User-Agent')); $this->assertEquals( - '{"name":"Test Channel","description":"A test channel","acknowledgment_enabled":true}', + '{"name":"Test Channel","description":"A test channel"}', $request->getBody()->getContents() ); $this->assertEquals($responseData, $result); @@ -183,7 +183,7 @@ public function testUpdateChannelRequest() $this->assertEquals('application/json', $request->getHeaderLine('Content-Type')); $this->assertEquals('pushinator-php/1.0', $request->getHeaderLine('User-Agent')); $this->assertEquals( - '{"name":"Updated Channel","description":"New description","acknowledgment_enabled":false}', + '{"name":"Updated Channel","description":"New description"}', $request->getBody()->getContents() ); $this->assertEquals($responseData, $result);