diff --git a/src/Core/Omit.php b/src/Core/Omit.php new file mode 100644 index 000000000..aaaaec4ee --- /dev/null +++ b/src/Core/Omit.php @@ -0,0 +1,18 @@ + $params */ $params = Util::removeNulls( [ - 'agentID' => $agentID, 'callbackURL' => $callbackURL, 'defaultForAppCalls' => $defaultForAppCalls, 'sandbox' => $sandbox, @@ -222,6 +224,12 @@ public function update( ], ); + // agent_id carries meaning as an explicit null (unbind), so it skips removeNulls() + // entirely instead of being stripped alongside every other unset field above. + if (!($agentID instanceof Omit)) { + $params['agentID'] = $agentID; + } + // @phpstan-ignore-next-line argument.type $response = $this->raw->update($number, params: $params, requestOptions: $requestOptions); diff --git a/tests/Services/Channels/VoiceTest.php b/tests/Services/Channels/VoiceTest.php index c9bb06038..540e59ede 100644 --- a/tests/Services/Channels/VoiceTest.php +++ b/tests/Services/Channels/VoiceTest.php @@ -2,6 +2,8 @@ namespace Tests\Services\Channels; +use Http\Discovery\Psr17FactoryDiscovery; +use Http\Mock\Client as MockTransporter; use PHPUnit\Framework\Attributes\CoversNothing; use PHPUnit\Framework\Attributes\Test; use PHPUnit\Framework\TestCase; @@ -71,6 +73,63 @@ public function testUpdate(): void $this->assertInstanceOf(APIResponseOfVoiceNumber::class, $result); } + #[Test] + public function testUpdateSendsExplicitNullToUnbindAgent(): void + { + $transporter = new MockTransporter; + $transporter->setDefaultResponse( + Psr17FactoryDiscovery::findResponseFactory() + ->createResponse() + ->withStatus(200) + ->withHeader('Content-Type', 'application/json') + ->withBody(Psr17FactoryDiscovery::findStreamFactory()->createStream( + json_encode(['data' => []], flags: Util::JSON_ENCODE_FLAGS) ?: '' + )) + ); + + $client = new Client( + baseUrl: 'http://localhost', + apiKey: 'My API Key', + requestOptions: ['transporter' => $transporter], + ); + + $client->channels->voice->update('+12125550100', agentID: null); + + $this->assertNotFalse($requested = $transporter->getRequests()[0] ?? false); + /** @var array $sent */ + $sent = json_decode((string) $requested->getBody(), true); + $this->assertArrayHasKey('agent_id', $sent); + $this->assertNull($sent['agent_id']); + } + + #[Test] + public function testUpdateOmitsAgentIdWhenNotPassed(): void + { + $transporter = new MockTransporter; + $transporter->setDefaultResponse( + Psr17FactoryDiscovery::findResponseFactory() + ->createResponse() + ->withStatus(200) + ->withHeader('Content-Type', 'application/json') + ->withBody(Psr17FactoryDiscovery::findStreamFactory()->createStream( + json_encode(['data' => []], flags: Util::JSON_ENCODE_FLAGS) ?: '' + )) + ); + + $client = new Client( + baseUrl: 'http://localhost', + apiKey: 'My API Key', + requestOptions: ['transporter' => $transporter], + ); + + $client->channels->voice->update('+12125550100', status: 'ACTIVE'); + + $this->assertNotFalse($requested = $transporter->getRequests()[0] ?? false); + /** @var array $sent */ + $sent = json_decode((string) $requested->getBody(), true); + $this->assertArrayNotHasKey('agent_id', $sent); + } + #[Test] public function testList(): void {