diff --git a/ClickSendOptions.php b/ClickSendOptions.php index ea9b71f..2995b73 100644 --- a/ClickSendOptions.php +++ b/ClickSendOptions.php @@ -18,11 +18,9 @@ */ final class ClickSendOptions implements MessageOptionsInterface { - private array $options; - - public function __construct(array $options = []) - { - $this->options = $options; + public function __construct( + private array $options = [], + ) { } public function getRecipientId(): ?string diff --git a/ClickSendTransport.php b/ClickSendTransport.php index 76abd4b..65f48bc 100644 --- a/ClickSendTransport.php +++ b/ClickSendTransport.php @@ -51,7 +51,7 @@ public function __toString(): string 'from_email' => $this->fromEmail, ]); - return sprintf('clicksend://%s%s', $this->getEndpoint(), $query ? '?'.http_build_query($query, '', '&') : ''); + return \sprintf('clicksend://%s%s', $this->getEndpoint(), $query ? '?'.http_build_query($query, '', '&') : ''); } public function supports(MessageInterface $message): bool @@ -68,26 +68,26 @@ protected function doSend(MessageInterface $message): SentMessage throw new UnsupportedMessageTypeException(__CLASS__, SmsMessage::class, $message); } - $endpoint = sprintf('https://%s/v3/sms/send', $this->getEndpoint()); + $endpoint = \sprintf('https://%s/v3/sms/send', $this->getEndpoint()); $options = $message->getOptions()?->toArray() ?? []; $options['body'] = $message->getSubject(); $options['from'] = $message->getFrom() ?: $this->from; $options['source'] ??= $this->source; $options['list_id'] ??= $this->listId; - $options['from_email'] ?? $this->fromEmail; + $options['from_email'] ??= $this->fromEmail; if (isset($options['from']) && !preg_match('/^[a-zA-Z0-9\s]{3,11}$/', $options['from']) && !preg_match('/^\+[1-9]\d{1,14}$/', $options['from'])) { - throw new InvalidArgumentException(sprintf('The "From" number "%s" is not a valid phone number, shortcode, or alphanumeric sender ID.', $options['from'])); + throw new InvalidArgumentException(\sprintf('The "From" number "%s" is not a valid phone number, shortcode, or alphanumeric sender ID.', $options['from'])); } - if ($options['list_id'] ?? false) { + if (!$options['list_id']) { $options['to'] = $message->getPhone(); } $response = $this->client->request('POST', $endpoint, [ 'auth_basic' => [$this->apiUsername, $this->apiKey], - 'json' => array_filter($options), + 'json' => ['messages' => [array_filter($options)]], ]); try { @@ -98,7 +98,7 @@ protected function doSend(MessageInterface $message): SentMessage if (200 !== $statusCode) { $error = $response->getContent(false); - throw new TransportException(sprintf('Unable to send the SMS - "%s".', $error ?: 'unknown failure'), $response); + throw new TransportException(\sprintf('Unable to send the SMS - "%s".', $error ?: 'unknown failure'), $response); } return new SentMessage($message, (string) $this); diff --git a/Tests/ClickSendTransportFactoryTest.php b/Tests/ClickSendTransportFactoryTest.php index 670447f..6640d0c 100644 --- a/Tests/ClickSendTransportFactoryTest.php +++ b/Tests/ClickSendTransportFactoryTest.php @@ -12,10 +12,13 @@ namespace Symfony\Component\Notifier\Bridge\ClickSend\Tests; use Symfony\Component\Notifier\Bridge\ClickSend\ClickSendTransportFactory; -use Symfony\Component\Notifier\Test\TransportFactoryTestCase; +use Symfony\Component\Notifier\Test\AbstractTransportFactoryTestCase; +use Symfony\Component\Notifier\Test\IncompleteDsnTestTrait; -final class ClickSendTransportFactoryTest extends TransportFactoryTestCase +final class ClickSendTransportFactoryTest extends AbstractTransportFactoryTestCase { + use IncompleteDsnTestTrait; + public function createFactory(): ClickSendTransportFactory { return new ClickSendTransportFactory(); diff --git a/Tests/ClickSendTransportTest.php b/Tests/ClickSendTransportTest.php index 166bb10..532c5ac 100644 --- a/Tests/ClickSendTransportTest.php +++ b/Tests/ClickSendTransportTest.php @@ -24,7 +24,7 @@ final class ClickSendTransportTest extends TransportTestCase { - public static function createTransport(?HttpClientInterface $client = null, string $from = 'test_from', string $source = 'test_source', int $listId = 99, string $fromEmail = 'foo@bar.com'): ClickSendTransport + public static function createTransport(?HttpClientInterface $client = null, ?string $from = 'test_from', ?string $source = 'test_source', ?int $listId = 99, ?string $fromEmail = 'foo@bar.com'): ClickSendTransport { return new ClickSendTransport('test_username', 'test_key', $from, $source, $listId, $fromEmail, $client ?? new MockHttpClient()); } @@ -49,7 +49,7 @@ public function testInvalidArgumentExceptionIsThrownIfFromIsInvalid(string $from $transport = $this->createTransport(null, $from); $this->expectException(InvalidArgumentException::class); - $this->expectExceptionMessage(sprintf('The "From" number "%s" is not a valid phone number, shortcode, or alphanumeric sender ID.', $from)); + $this->expectExceptionMessage(\sprintf('The "From" number "%s" is not a valid phone number, shortcode, or alphanumeric sender ID.', $from)); $transport->send(new SmsMessage('+33612345678', 'Hello!')); } @@ -63,16 +63,47 @@ public function testNoInvalidArgumentExceptionIsThrownIfFromIsValid(string $from $response = $this->createMock(ResponseInterface::class); $response->expects(self::exactly(2))->method('getStatusCode')->willReturn(200); $response->expects(self::once())->method('getContent')->willReturn(''); - $client = new MockHttpClient(function (string $method, string $url) use ($response): ResponseInterface { + $client = new MockHttpClient(function (string $method, string $url, array $options) use ($response): ResponseInterface { self::assertSame('POST', $method); self::assertSame('https://rest.clicksend.com/v3/sms/send', $url); + $body = json_decode($options['body'], true); + self::assertIsArray($body); + self::assertArrayHasKey('messages', $body); + $message = reset($body['messages']); + self::assertArrayHasKey('from_email', $message); + self::assertArrayHasKey('list_id', $message); + self::assertArrayNotHasKey('to', $message); + return $response; }); $transport = $this->createTransport($client, $from); $transport->send($message); } + public function testNoInvalidArgumentExceptionIsThrownIfFromIsValidWithoutOptionalParameters() + { + $message = new SmsMessage('+33612345678', 'Hello!'); + $response = $this->createMock(ResponseInterface::class); + $response->expects(self::exactly(2))->method('getStatusCode')->willReturn(200); + $response->expects(self::once())->method('getContent')->willReturn(''); + $client = new MockHttpClient(function (string $method, string $url, array $options) use ($response): ResponseInterface { + self::assertSame('POST', $method); + self::assertSame('https://rest.clicksend.com/v3/sms/send', $url); + + $body = json_decode($options['body'], true); + self::assertIsArray($body); + self::assertArrayHasKey('messages', $body); + $message = reset($body['messages']); + self::assertArrayNotHasKey('list_id', $message); + self::assertArrayHasKey('to', $message); + + return $response; + }); + $transport = $this->createTransport($client, null, null, null, null); + $transport->send($message); + } + public static function toStringProvider(): iterable { yield ['clicksend://rest.clicksend.com?from=test_from&source=test_source&list_id=99&from_email=foo%40bar.com', self::createTransport()]; diff --git a/composer.json b/composer.json index b3c7c27..1676fea 100644 --- a/composer.json +++ b/composer.json @@ -21,13 +21,13 @@ "require": { "php": ">=8.2", "symfony/http-client": "^6.4|^7.0", - "symfony/notifier": "^6.4|^7.0" + "symfony/notifier": "^7.2" }, "require-dev": { "symfony/event-dispatcher": "^6.4|^7.0" }, "autoload": { - "psr-4": {"Symfony\\Component\\Notifier\\Bridge\\ClickSend\\": ""}, + "psr-4": { "Symfony\\Component\\Notifier\\Bridge\\ClickSend\\": "" }, "exclude-from-classmap": [ "/Tests/" ]