diff --git a/src/Symfony/Component/Notifier/Bridge/Discord/DiscordTransportFactory.php b/src/Symfony/Component/Notifier/Bridge/Discord/DiscordTransportFactory.php index 3a8afa2551a6..a192832f5655 100644 --- a/src/Symfony/Component/Notifier/Bridge/Discord/DiscordTransportFactory.php +++ b/src/Symfony/Component/Notifier/Bridge/Discord/DiscordTransportFactory.php @@ -30,6 +30,11 @@ final class DiscordTransportFactory extends AbstractTransportFactory public function create(Dsn $dsn): TransportInterface { $scheme = $dsn->getScheme(); + + if ('discord' !== $scheme) { + throw new UnsupportedSchemeException($dsn, 'discord', $this->getSupportedSchemes()); + } + $token = $this->getUser($dsn); $webhookId = $dsn->getOption('webhook_id'); @@ -40,11 +45,7 @@ public function create(Dsn $dsn): TransportInterface $host = 'default' === $dsn->getHost() ? null : $dsn->getHost(); $port = $dsn->getPort(); - if ('discord' === $scheme) { - return (new DiscordTransport($token, $webhookId, $this->client, $this->dispatcher))->setHost($host)->setPort($port); - } - - throw new UnsupportedSchemeException($dsn, 'discord', $this->getSupportedSchemes()); + return (new DiscordTransport($token, $webhookId, $this->client, $this->dispatcher))->setHost($host)->setPort($port); } protected function getSupportedSchemes(): array diff --git a/src/Symfony/Component/Notifier/Bridge/Discord/README.md b/src/Symfony/Component/Notifier/Bridge/Discord/README.md index 67a176d7e0e6..243904c27652 100644 --- a/src/Symfony/Component/Notifier/Bridge/Discord/README.md +++ b/src/Symfony/Component/Notifier/Bridge/Discord/README.md @@ -1,13 +1,12 @@ Discord Notifier ================ -Provides Discord integration for Symfony Notifier. +Provides [Discord](https://discord.com) integration for Symfony Notifier. DSN example ----------- ``` -// .env file DISCORD_DSN=discord://TOKEN@default?webhook_id=ID ``` diff --git a/src/Symfony/Component/Notifier/Bridge/Discord/Tests/DiscordTransportFactoryTest.php b/src/Symfony/Component/Notifier/Bridge/Discord/Tests/DiscordTransportFactoryTest.php index 09508b714fad..40c8f4d4aabd 100644 --- a/src/Symfony/Component/Notifier/Bridge/Discord/Tests/DiscordTransportFactoryTest.php +++ b/src/Symfony/Component/Notifier/Bridge/Discord/Tests/DiscordTransportFactoryTest.php @@ -21,46 +21,64 @@ final class DiscordTransportFactoryTest extends TestCase { public function testCreateWithDsn() { - $factory = new DiscordTransportFactory(); + $factory = $this->createFactory(); - $host = 'testHost'; - $webhookId = 'testChannel'; + $transport = $factory->create(Dsn::fromString('discord://token@host.test?webhook_id=testWebhookId')); - $transport = $factory->create(Dsn::fromString(sprintf('discord://%s@%s/?webhook_id=%s', 'token', $host, $webhookId))); - - $this->assertSame(sprintf('discord://%s?webhook_id=%s', $host, $webhookId), (string) $transport); + $this->assertSame('discord://host.test?webhook_id=testWebhookId', (string) $transport); } - public function testCreateWithNoWebhookIdThrowsMalformed() + public function testCreateWithMissingOptionWebhookIdThrowsIncompleteDsnException() { - $factory = new DiscordTransportFactory(); + $factory = $this->createFactory(); $this->expectException(IncompleteDsnException::class); $factory->create(Dsn::fromString('discord://token@host')); } - public function testCreateWithNoTokenThrowsMalformed() + public function testCreateWithNoTokenThrowsIncompleteDsnException() { - $factory = new DiscordTransportFactory(); + $factory = $this->createFactory(); $this->expectException(IncompleteDsnException::class); - $factory->create(Dsn::fromString(sprintf('discord://%s/?webhook_id=%s', 'testHost', 'testChannel'))); + $factory->create(Dsn::fromString('discord://host.test?webhook_id=testWebhookId')); + } + + public function testSupportsReturnsTrueWithSupportedScheme() + { + $factory = $this->createFactory(); + + $this->assertTrue($factory->supports(Dsn::fromString('discord://host?webhook_id=testWebhookId'))); + } + + public function testSupportsReturnsFalseWithUnsupportedScheme() + { + $factory = $this->createFactory(); + + $this->assertFalse($factory->supports(Dsn::fromString('somethingElse://host?webhook_id=testWebhookId'))); } - public function testSupportsDiscordScheme() + public function testUnsupportedSchemeThrowsUnsupportedSchemeException() { - $factory = new DiscordTransportFactory(); + $factory = $this->createFactory(); - $this->assertTrue($factory->supports(Dsn::fromString('discord://host/?webhook_id=testChannel'))); - $this->assertFalse($factory->supports(Dsn::fromString('somethingElse://host/?webhook_id=testChannel'))); + $this->expectException(UnsupportedSchemeException::class); + $factory->create(Dsn::fromString('somethingElse://token@host?webhook_id=testWebhookId')); } - public function testNonDiscordSchemeThrows() + public function testUnsupportedSchemeThrowsUnsupportedSchemeExceptionEvenIfRequiredOptionIsMissing() { - $factory = new DiscordTransportFactory(); + $factory = $this->createFactory(); $this->expectException(UnsupportedSchemeException::class); - $factory->create(Dsn::fromString('somethingElse://token@host/?webhook_id=testChannel')); + + // unsupported scheme and missing "webhook_id" option + $factory->create(Dsn::fromString('somethingElse://token@host')); + } + + private function createFactory(): DiscordTransportFactory + { + return new DiscordTransportFactory(); } } diff --git a/src/Symfony/Component/Notifier/Bridge/Discord/Tests/DiscordTransportTest.php b/src/Symfony/Component/Notifier/Bridge/Discord/Tests/DiscordTransportTest.php index ead302758066..9d4d0ba0057b 100644 --- a/src/Symfony/Component/Notifier/Bridge/Discord/Tests/DiscordTransportTest.php +++ b/src/Symfony/Component/Notifier/Bridge/Discord/Tests/DiscordTransportTest.php @@ -25,33 +25,31 @@ final class DiscordTransportTest extends TestCase { public function testToStringContainsProperties() { - $webhookId = 'testChannel'; + $transport = $this->createTransport(); - $transport = new DiscordTransport('testToken', $webhookId, $this->createMock(HttpClientInterface::class)); - $transport->setHost('testHost'); - - $this->assertSame(sprintf('discord://%s?webhook_id=%s', 'testHost', $webhookId), (string) $transport); + $this->assertSame('discord://host.test?webhook_id=testWebhookId', (string) $transport); } public function testSupportsChatMessage() { - $transport = new DiscordTransport('testToken', 'testChannel', $this->createMock(HttpClientInterface::class)); + $transport = $this->createTransport(); $this->assertTrue($transport->supports(new ChatMessage('testChatMessage'))); $this->assertFalse($transport->supports($this->createMock(MessageInterface::class))); } - public function testSendNonChatMessageThrows() + public function testSendNonChatMessageThrowsLogicException() { + $transport = $this->createTransport(); + $this->expectException(LogicException::class); - $transport = new DiscordTransport('testToken', 'testChannel', $this->createMock(HttpClientInterface::class)); $transport->send($this->createMock(MessageInterface::class)); } public function testSendChatMessageWithMoreThan2000CharsThrowsLogicException() { - $transport = new DiscordTransport('testToken', 'testChannel', $this->createMock(HttpClientInterface::class)); + $transport = $this->createTransport(); $this->expectException(LogicException::class); $this->expectExceptionMessage('The subject length of a Discord message must not exceed 2000 characters.'); @@ -61,9 +59,6 @@ public function testSendChatMessageWithMoreThan2000CharsThrowsLogicException() public function testSendWithErrorResponseThrows() { - $this->expectException(TransportException::class); - $this->expectExceptionMessageMatches('/testDescription.+testErrorCode/'); - $response = $this->createMock(ResponseInterface::class); $response->expects($this->exactly(2)) ->method('getStatusCode') @@ -76,8 +71,16 @@ public function testSendWithErrorResponseThrows() return $response; }); - $transport = new DiscordTransport('testToken', 'testChannel', $client); + $transport = $this->createTransport($client); + + $this->expectException(TransportException::class); + $this->expectExceptionMessageMatches('/testDescription.+testErrorCode/'); $transport->send(new ChatMessage('testMessage')); } + + private function createTransport(?HttpClientInterface $client = null): DiscordTransport + { + return (new DiscordTransport('testToken', 'testWebhookId', $client ?? $this->createMock(HttpClientInterface::class)))->setHost('host.test'); + } } diff --git a/src/Symfony/Component/Notifier/Bridge/Discord/composer.json b/src/Symfony/Component/Notifier/Bridge/Discord/composer.json index a47bc90ac962..934f1f588656 100644 --- a/src/Symfony/Component/Notifier/Bridge/Discord/composer.json +++ b/src/Symfony/Component/Notifier/Bridge/Discord/composer.json @@ -30,5 +30,4 @@ ] }, "minimum-stability": "dev" - } diff --git a/src/Symfony/Component/Notifier/Bridge/Esendex/EsendexTransport.php b/src/Symfony/Component/Notifier/Bridge/Esendex/EsendexTransport.php index a216a16f9859..812c58906ed7 100644 --- a/src/Symfony/Component/Notifier/Bridge/Esendex/EsendexTransport.php +++ b/src/Symfony/Component/Notifier/Bridge/Esendex/EsendexTransport.php @@ -62,6 +62,7 @@ protected function doSend(MessageInterface $message): SentMessage 'to' => $message->getPhone(), 'body' => $message->getSubject(), ]; + if (null !== $this->from) { $messageData['from'] = $this->from; } diff --git a/src/Symfony/Component/Notifier/Bridge/Esendex/EsendexTransportFactory.php b/src/Symfony/Component/Notifier/Bridge/Esendex/EsendexTransportFactory.php index f526f5a38515..2edf0788b3fb 100644 --- a/src/Symfony/Component/Notifier/Bridge/Esendex/EsendexTransportFactory.php +++ b/src/Symfony/Component/Notifier/Bridge/Esendex/EsendexTransportFactory.php @@ -11,6 +11,7 @@ namespace Symfony\Component\Notifier\Bridge\Esendex; +use Symfony\Component\Notifier\Exception\IncompleteDsnException; use Symfony\Component\Notifier\Exception\UnsupportedSchemeException; use Symfony\Component\Notifier\Transport\AbstractTransportFactory; use Symfony\Component\Notifier\Transport\Dsn; @@ -27,17 +28,28 @@ final class EsendexTransportFactory extends AbstractTransportFactory public function create(Dsn $dsn): TransportInterface { $scheme = $dsn->getScheme(); + + if ('esendex' !== $scheme) { + throw new UnsupportedSchemeException($dsn, 'esendex', $this->getSupportedSchemes()); + } + $token = $this->getUser($dsn).':'.$this->getPassword($dsn); $accountReference = $dsn->getOption('accountreference'); + + if (!$accountReference) { + throw new IncompleteDsnException('Missing accountreference.', $dsn->getOriginalDsn()); + } + $from = $dsn->getOption('from'); - $host = 'default' === $dsn->getHost() ? null : $dsn->getHost(); - $port = $dsn->getPort(); - if ('esendex' === $scheme) { - return (new EsendexTransport($token, $accountReference, $from, $this->client, $this->dispatcher))->setHost($host)->setPort($port); + if (!$from) { + throw new IncompleteDsnException('Missing from.', $dsn->getOriginalDsn()); } - throw new UnsupportedSchemeException($dsn, 'esendex', $this->getSupportedSchemes()); + $host = 'default' === $dsn->getHost() ? null : $dsn->getHost(); + $port = $dsn->getPort(); + + return (new EsendexTransport($token, $accountReference, $from, $this->client, $this->dispatcher))->setHost($host)->setPort($port); } protected function getSupportedSchemes(): array diff --git a/src/Symfony/Component/Notifier/Bridge/Esendex/README.md b/src/Symfony/Component/Notifier/Bridge/Esendex/README.md index fd1f142ed76f..22b93a22ba33 100644 --- a/src/Symfony/Component/Notifier/Bridge/Esendex/README.md +++ b/src/Symfony/Component/Notifier/Bridge/Esendex/README.md @@ -1,21 +1,20 @@ Esendex Notifier ================ -Provides Esendex integration for Symfony Notifier. +Provides [Esendex](https://esendex.com) integration for Symfony Notifier. DSN example ----------- ``` -// .env file -ESENDEX_DSN='esendex://EMAIL:PASSWORD@default?accountreference=ACCOUNT_REFERENCE&from=FROM' +ESENDEX_DSN=esendex://EMAIL:PASSWORD@default?accountreference=ACCOUNT_REFERENCE&from=FROM ``` where: - `EMAIL` is your Esendex account email - `PASSWORD` is the Esendex API password - - `ACCOUNT_REFERENCE` is the Esendex account reference that the messages should be sent from. - - `FROM` is the alphanumeric originator for the message to appear to originate from. + - `ACCOUNT_REFERENCE` is the Esendex account reference that the messages should be sent from + - `FROM` is the alphanumeric originator for the message to appear to originate from See Esendex documentation at https://developers.esendex.com/api-reference#smsapis diff --git a/src/Symfony/Component/Notifier/Bridge/Esendex/Tests/EsendexTransportFactoryTest.php b/src/Symfony/Component/Notifier/Bridge/Esendex/Tests/EsendexTransportFactoryTest.php new file mode 100644 index 000000000000..469a23c98536 --- /dev/null +++ b/src/Symfony/Component/Notifier/Bridge/Esendex/Tests/EsendexTransportFactoryTest.php @@ -0,0 +1,85 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Notifier\Bridge\Esendex\Tests; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\Notifier\Bridge\Esendex\EsendexTransportFactory; +use Symfony\Component\Notifier\Exception\IncompleteDsnException; +use Symfony\Component\Notifier\Exception\UnsupportedSchemeException; +use Symfony\Component\Notifier\Transport\Dsn; + +final class EsendexTransportFactoryTest extends TestCase +{ + public function testCreateWithDsn() + { + $factory = $this->createFactory(); + + $transport = $factory->create(Dsn::fromString('esendex://email:password@host.test?accountreference=testAccountreference&from=testFrom')); + + $this->assertSame('esendex://host.test', (string) $transport); + } + + public function testCreateWithMissingOptionAccountreferenceThrowsIncompleteDsnException() + { + $factory = $this->createFactory(); + + $this->expectException(IncompleteDsnException::class); + + $factory->create(Dsn::fromString('esendex://email:password@host?from=FROM')); + } + + public function testCreateWithMissingOptionFromThrowsIncompleteDsnException() + { + $factory = $this->createFactory(); + + $this->expectException(IncompleteDsnException::class); + + $factory->create(Dsn::fromString('esendex://email:password@host?accountreference=ACCOUNTREFERENCE')); + } + + public function testSupportsReturnsTrueWithSupportedScheme() + { + $factory = $this->createFactory(); + + $this->assertTrue($factory->supports(Dsn::fromString('esendex://email:password@host?accountreference=ACCOUNTREFERENCE&from=FROM'))); + } + + public function testSupportsReturnsFalseWithUnsupportedScheme() + { + $factory = $this->createFactory(); + + $this->assertFalse($factory->supports(Dsn::fromString('somethingElse://email:password@host?accountreference=ACCOUNTREFERENCE&from=FROM'))); + } + + public function testUnsupportedSchemeThrowsUnsupportedSchemeException() + { + $factory = $this->createFactory(); + + $this->expectException(UnsupportedSchemeException::class); + $factory->create(Dsn::fromString('somethingElse://email:password@host?accountreference=REFERENCE&from=FROM')); + } + + public function testUnsupportedSchemeThrowsUnsupportedSchemeExceptionEvenIfRequiredOptionIsMissing() + { + $factory = $this->createFactory(); + + $this->expectException(UnsupportedSchemeException::class); + + // unsupported scheme and missing "from" option + $factory->create(Dsn::fromString('somethingElse://email:password@host?accountreference=REFERENCE')); + } + + private function createFactory(): EsendexTransportFactory + { + return new EsendexTransportFactory(); + } +} diff --git a/src/Symfony/Component/Notifier/Bridge/Esendex/Tests/EsendexTransportTest.php b/src/Symfony/Component/Notifier/Bridge/Esendex/Tests/EsendexTransportTest.php index 667ed59d6c49..295b5e610224 100644 --- a/src/Symfony/Component/Notifier/Bridge/Esendex/Tests/EsendexTransportTest.php +++ b/src/Symfony/Component/Notifier/Bridge/Esendex/Tests/EsendexTransportTest.php @@ -25,23 +25,22 @@ final class EsendexTransportTest extends TestCase { public function testToString() { - $transport = new EsendexTransport('testToken', 'accountReference', 'from', $this->createMock(HttpClientInterface::class)); - $transport->setHost('testHost'); + $transport = $this->createTransport(); - $this->assertSame(sprintf('esendex://%s', 'testHost'), (string) $transport); + $this->assertSame('esendex://host.test', (string) $transport); } public function testSupportsSmsMessage() { - $transport = new EsendexTransport('testToken', 'accountReference', 'from', $this->createMock(HttpClientInterface::class)); + $transport = $this->createTransport(); $this->assertTrue($transport->supports(new SmsMessage('phone', 'testSmsMessage'))); $this->assertFalse($transport->supports($this->createMock(MessageInterface::class))); } - public function testSendNonSmsMessageThrows() + public function testSendNonSmsMessageThrowsLogicException() { - $transport = new EsendexTransport('testToken', 'accountReference', 'from', $this->createMock(HttpClientInterface::class)); + $transport = $this->createTransport(); $this->expectException(LogicException::class); $transport->send($this->createMock(MessageInterface::class)); @@ -58,10 +57,11 @@ public function testSendWithErrorResponseThrows() return $response; }); - $transport = new EsendexTransport('testToken', 'accountReference', 'from', $client); + $transport = $this->createTransport($client); $this->expectException(TransportException::class); $this->expectExceptionMessage('Unable to send the SMS: error 500.'); + $transport->send(new SmsMessage('phone', 'testMessage')); } @@ -79,10 +79,16 @@ public function testSendWithErrorResponseContainingDetailsThrows() return $response; }); - $transport = new EsendexTransport('testToken', 'accountReference', 'from', $client); + $transport = $this->createTransport($client); $this->expectException(TransportException::class); $this->expectExceptionMessage('Unable to send the SMS: error 500. Details from Esendex: accountreference_invalid: "Invalid Account Reference EX0000000".'); + $transport->send(new SmsMessage('phone', 'testMessage')); } + + private function createTransport(?HttpClientInterface $client = null): EsendexTransport + { + return (new EsendexTransport('testToken', 'testAccountReference', 'testFrom', $client ?: $this->createMock(HttpClientInterface::class)))->setHost('host.test'); + } } diff --git a/src/Symfony/Component/Notifier/Bridge/Firebase/FirebaseTransport.php b/src/Symfony/Component/Notifier/Bridge/Firebase/FirebaseTransport.php index 1c1684d53a58..12593b125673 100644 --- a/src/Symfony/Component/Notifier/Bridge/Firebase/FirebaseTransport.php +++ b/src/Symfony/Component/Notifier/Bridge/Firebase/FirebaseTransport.php @@ -88,9 +88,9 @@ protected function doSend(MessageInterface $message): SentMessage $success = $response->toArray(false); - $message = new SentMessage($message, (string) $this); - $message->setMessageId($success['results'][0]['message_id']); + $sentMessage = new SentMessage($message, (string) $this); + $sentMessage->setMessageId($success['results'][0]['message_id']); - return $message; + return $sentMessage; } } diff --git a/src/Symfony/Component/Notifier/Bridge/Firebase/Tests/FirebaseTransportTest.php b/src/Symfony/Component/Notifier/Bridge/Firebase/Tests/FirebaseTransportTest.php index 8f377cdd8826..1aea969dd5a9 100644 --- a/src/Symfony/Component/Notifier/Bridge/Firebase/Tests/FirebaseTransportTest.php +++ b/src/Symfony/Component/Notifier/Bridge/Firebase/Tests/FirebaseTransportTest.php @@ -38,7 +38,7 @@ public function testSupportsMessageInterface() $this->assertFalse($transport->supports($this->createMock(MessageInterface::class))); } - public function testSendNonSmsMessageThrowsException() + public function testSendNonSmsMessageThrowsLogicException() { $transport = $this->createTransport(); diff --git a/src/Symfony/Component/Notifier/Bridge/FreeMobile/Tests/FreeMobileTransportTest.php b/src/Symfony/Component/Notifier/Bridge/FreeMobile/Tests/FreeMobileTransportTest.php index 7f8d64815431..d88cd11eea34 100644 --- a/src/Symfony/Component/Notifier/Bridge/FreeMobile/Tests/FreeMobileTransportTest.php +++ b/src/Symfony/Component/Notifier/Bridge/FreeMobile/Tests/FreeMobileTransportTest.php @@ -22,45 +22,53 @@ final class FreeMobileTransportTest extends TestCase { public function testToStringContainsProperties() { - $transport = $this->getTransport('0611223344'); + $transport = $this->createTransport('0611223344'); $this->assertSame('freemobile://host.test?phone=0611223344', (string) $transport); } - public function testSupportsMessageInterface() + /** + * @dataProvider supportsProvider + */ + public function testSupportsMessageInterface(bool $expected, string $configuredPhoneNumber, MessageInterface $message) { - $transport = $this->getTransport('0611223344'); + $transport = $this->createTransport($configuredPhoneNumber); - $this->assertTrue($transport->supports(new SmsMessage('0611223344', 'Hello!'))); - $this->assertTrue($transport->supports(new SmsMessage('+33611223344', 'Hello!'))); - $this->assertFalse($transport->supports(new SmsMessage('0699887766', 'Hello!'))); - $this->assertFalse($transport->supports($this->createMock(MessageInterface::class))); - - $transport = $this->getTransport('+33611223344'); + $this->assertSame($expected, $transport->supports($message)); + } - $this->assertTrue($transport->supports(new SmsMessage('0611223344', 'Hello!'))); - $this->assertTrue($transport->supports(new SmsMessage('+33611223344', 'Hello!'))); + /** + * @return iterable + */ + public function supportsProvider(): iterable + { + yield [true, '0611223344', new SmsMessage('0611223344', 'Hello!')]; + yield [true, '0611223344', new SmsMessage('+33611223344', 'Hello!')]; + yield [false, '0611223344', new SmsMessage('0699887766', 'Hello!')]; + yield [false, '0611223344', $this->createMock(MessageInterface::class)]; + yield [true, '+33611223344', new SmsMessage('0611223344', 'Hello!')]; + yield [true, '+33611223344', new SmsMessage('+33611223344', 'Hello!')]; } - public function testSendNonSmsMessageThrowsException() + public function testSendNonSmsMessageThrowsLogicException() { - $transport = $this->getTransport('0611223344'); + $transport = $this->createTransport('0611223344'); $this->expectException(LogicException::class); $transport->send($this->createMock(MessageInterface::class)); } - public function testSendSmsMessageButInvalidPhoneThrowsException() + public function testSendSmsMessageButInvalidPhoneThrowsLogicException() { - $transport = $this->getTransport('0611223344'); + $transport = $this->createTransport('0611223344'); $this->expectException(LogicException::class); $transport->send(new SmsMessage('0699887766', 'Hello!')); } - private function getTransport(string $phone): FreeMobileTransport + private function createTransport(string $phone): FreeMobileTransport { return (new FreeMobileTransport('login', 'pass', $phone, $this->createMock(HttpClientInterface::class)))->setHost('host.test'); } diff --git a/src/Symfony/Component/Notifier/Bridge/GoogleChat/GoogleChatOptions.php b/src/Symfony/Component/Notifier/Bridge/GoogleChat/GoogleChatOptions.php index a7b2b817716f..407728ab4922 100644 --- a/src/Symfony/Component/Notifier/Bridge/GoogleChat/GoogleChatOptions.php +++ b/src/Symfony/Component/Notifier/Bridge/GoogleChat/GoogleChatOptions.php @@ -40,6 +40,7 @@ public static function fromNotification(Notification $notification): self if ($notification->getContent()) { $text .= "\r\n".$notification->getContent(); } + if ($exception = $notification->getExceptionAsString()) { $text .= "\r\n".'```'.$notification->getExceptionAsString().'```'; } diff --git a/src/Symfony/Component/Notifier/Bridge/GoogleChat/GoogleChatTransport.php b/src/Symfony/Component/Notifier/Bridge/GoogleChat/GoogleChatTransport.php index 543b2a0a4cb0..fbe933cd5671 100644 --- a/src/Symfony/Component/Notifier/Bridge/GoogleChat/GoogleChatTransport.php +++ b/src/Symfony/Component/Notifier/Bridge/GoogleChat/GoogleChatTransport.php @@ -89,6 +89,7 @@ protected function doSend(MessageInterface $message): SentMessage if (!$message instanceof ChatMessage) { throw new LogicException(sprintf('The "%s" transport only supports instances of "%s" (instance of "%s" given).', __CLASS__, ChatMessage::class, \get_class($message))); } + if ($message->getOptions() && !$message->getOptions() instanceof GoogleChatOptions) { throw new LogicException(sprintf('The "%s" transport only supports instances of "%s" for options.', __CLASS__, GoogleChatOptions::class)); } diff --git a/src/Symfony/Component/Notifier/Bridge/GoogleChat/GoogleChatTransportFactory.php b/src/Symfony/Component/Notifier/Bridge/GoogleChat/GoogleChatTransportFactory.php index 039b3f5e7a4f..94cbc786f253 100644 --- a/src/Symfony/Component/Notifier/Bridge/GoogleChat/GoogleChatTransportFactory.php +++ b/src/Symfony/Component/Notifier/Bridge/GoogleChat/GoogleChatTransportFactory.php @@ -32,21 +32,18 @@ public function create(Dsn $dsn): TransportInterface { $scheme = $dsn->getScheme(); - if ('googlechat' === $scheme) { - $space = explode('/', $dsn->getPath())[1]; - $accessKey = $this->getUser($dsn); - $accessToken = $this->getPassword($dsn); - $threadKey = $dsn->getOption('threadKey'); - $host = 'default' === $dsn->getHost() ? null : $dsn->getHost(); - $port = $dsn->getPort(); - - return (new GoogleChatTransport($space, $accessKey, $accessToken, $this->client, $this->dispatcher)) - ->setThreadKey($threadKey) - ->setHost($host) - ->setPort($port); + if ('googlechat' !== $scheme) { + throw new UnsupportedSchemeException($dsn, 'googlechat', $this->getSupportedSchemes()); } - throw new UnsupportedSchemeException($dsn, 'googlechat', $this->getSupportedSchemes()); + $space = explode('/', $dsn->getPath())[1]; + $accessKey = $this->getUser($dsn); + $accessToken = $this->getPassword($dsn); + $threadKey = $dsn->getOption('threadKey'); + $host = 'default' === $dsn->getHost() ? null : $dsn->getHost(); + $port = $dsn->getPort(); + + return (new GoogleChatTransport($space, $accessKey, $accessToken, $this->client, $this->dispatcher))->setThreadKey($threadKey)->setHost($host)->setPort($port); } protected function getSupportedSchemes(): array diff --git a/src/Symfony/Component/Notifier/Bridge/GoogleChat/README.md b/src/Symfony/Component/Notifier/Bridge/GoogleChat/README.md index d1d85ebc2dcd..8a4b55c7e8c2 100644 --- a/src/Symfony/Component/Notifier/Bridge/GoogleChat/README.md +++ b/src/Symfony/Component/Notifier/Bridge/GoogleChat/README.md @@ -7,15 +7,14 @@ DSN example ----------- ``` -// .env file -INFOBIP_DSN=googlechat://ACCESS_KEY:ACCESS_TOKEN@default/SPACE?threadKey=THREAD_KEY +GOOGLE_CHAT_DSN=googlechat://ACCESS_KEY:ACCESS_TOKEN@default/SPACE?threadKey=THREAD_KEY ``` where: - `ACCESS_KEY` is your Google Chat access key - `ACCESS_TOKEN` is your Google Chat access token - `SPACE` is the Google Chat space - - `THREAD_KEY` is the the Google Chat message thread to group messages into a single thread + - `THREAD_KEY` is the the Google Chat message thread to group messages into a single thread (optional) Resources --------- diff --git a/src/Symfony/Component/Notifier/Bridge/GoogleChat/Tests/GoogleChatTransportFactoryTest.php b/src/Symfony/Component/Notifier/Bridge/GoogleChat/Tests/GoogleChatTransportFactoryTest.php index 641277a5f2cf..01a8d263f20e 100644 --- a/src/Symfony/Component/Notifier/Bridge/GoogleChat/Tests/GoogleChatTransportFactoryTest.php +++ b/src/Symfony/Component/Notifier/Bridge/GoogleChat/Tests/GoogleChatTransportFactoryTest.php @@ -21,47 +21,55 @@ final class GoogleChatTransportFactoryTest extends TestCase { public function testCreateWithDsn() { - $factory = new GoogleChatTransportFactory(); + $factory = $this->createFactory(); - $dsn = 'googlechat://abcde-fghij:kl_mnopqrstwxyz%3D@chat.googleapis.com/AAAAA_YYYYY'; - $transport = $factory->create(Dsn::fromString($dsn)); + $transport = $factory->create(Dsn::fromString('googlechat://abcde-fghij:kl_mnopqrstwxyz%3D@chat.googleapis.com/AAAAA_YYYYY')); $this->assertSame('googlechat://chat.googleapis.com/AAAAA_YYYYY', (string) $transport); } public function testCreateWithThreadKeyInDsn() { - $factory = new GoogleChatTransportFactory(); + $factory = $this->createFactory(); - $dsn = 'googlechat://abcde-fghij:kl_mnopqrstwxyz%3D@chat.googleapis.com/AAAAA_YYYYY?threadKey=abcdefg'; - $transport = $factory->create(Dsn::fromString($dsn)); + $transport = $factory->create(Dsn::fromString('googlechat://abcde-fghij:kl_mnopqrstwxyz%3D@chat.googleapis.com/AAAAA_YYYYY?threadKey=abcdefg')); $this->assertSame('googlechat://chat.googleapis.com/AAAAA_YYYYY?threadKey=abcdefg', (string) $transport); } public function testCreateRequiresCredentials() { + $factory = $this->createFactory(); + $this->expectException(IncompleteDsnException::class); - $factory = new GoogleChatTransportFactory(); - $dsn = 'googlechat://chat.googleapis.com/v1/spaces/AAAAA_YYYYY/messages'; - $factory->create(Dsn::fromString($dsn)); + $factory->create(Dsn::fromString('googlechat://chat.googleapis.com/v1/spaces/AAAAA_YYYYY/messages')); } - public function testSupportsGoogleChatScheme() + public function testSupportsReturnsTrueWithSupportedScheme() { - $factory = new GoogleChatTransportFactory(); + $factory = $this->createFactory(); $this->assertTrue($factory->supports(Dsn::fromString('googlechat://host/path'))); + } + + public function testSupportsReturnsFalseWithUnsupportedScheme() + { + $factory = $this->createFactory(); + $this->assertFalse($factory->supports(Dsn::fromString('somethingElse://host/path'))); } - public function testNonGoogleChatSchemeThrows() + public function testUnsupportedSchemeThrowsUnsupportedSchemeException() { - $factory = new GoogleChatTransportFactory(); + $factory = $this->createFactory(); $this->expectException(UnsupportedSchemeException::class); - $factory->create(Dsn::fromString('somethingElse://host/path')); } + + private function createFactory(): GoogleChatTransportFactory + { + return new GoogleChatTransportFactory(); + } } diff --git a/src/Symfony/Component/Notifier/Bridge/GoogleChat/Tests/GoogleChatTransportTest.php b/src/Symfony/Component/Notifier/Bridge/GoogleChat/Tests/GoogleChatTransportTest.php index 02f829be672d..f3d63d65068d 100644 --- a/src/Symfony/Component/Notifier/Bridge/GoogleChat/Tests/GoogleChatTransportTest.php +++ b/src/Symfony/Component/Notifier/Bridge/GoogleChat/Tests/GoogleChatTransportTest.php @@ -28,7 +28,7 @@ class GoogleChatTransportTest extends TestCase { public function testToStringContainsProperties() { - $transport = new GoogleChatTransport('My-Space', 'theAccessKey', 'theAccessToken=', $this->createMock(HttpClientInterface::class)); + $transport = $this->createTransport(); $transport->setHost(null); $this->assertSame('googlechat://chat.googleapis.com/My-Space', (string) $transport); @@ -36,17 +36,17 @@ public function testToStringContainsProperties() public function testSupportsChatMessage() { - $transport = new GoogleChatTransport('My-Space', 'theAccessKey', 'theAccessToken=', $this->createMock(HttpClientInterface::class)); + $transport = $this->createTransport(); $this->assertTrue($transport->supports(new ChatMessage('testChatMessage'))); $this->assertFalse($transport->supports($this->createMock(MessageInterface::class))); } - public function testSendNonChatMessageThrows() + public function testSendNonChatMessageThrowsLogicException() { - $this->expectException(LogicException::class); + $transport = $this->createTransport(); - $transport = new GoogleChatTransport('My-Space', 'theAccessKey', 'theAccessToken=', $this->createMock(HttpClientInterface::class)); + $this->expectException(LogicException::class); $transport->send($this->createMock(MessageInterface::class)); } @@ -69,7 +69,7 @@ public function testSendWithEmptyArrayResponseThrows() return $response; }); - $transport = new GoogleChatTransport('My-Space', 'theAccessKey', 'theAccessToken=', $client); + $transport = $this->createTransport($client); $sentMessage = $transport->send(new ChatMessage('testMessage')); @@ -93,7 +93,7 @@ public function testSendWithErrorResponseThrows() return $response; }); - $transport = new GoogleChatTransport('My-Space', 'theAccessKey', 'theAccessToken=', $client); + $transport = $this->createTransport($client); $sentMessage = $transport->send(new ChatMessage('testMessage')); @@ -124,7 +124,7 @@ public function testSendWithOptions() return $response; }); - $transport = new GoogleChatTransport('My-Space', 'theAccessKey', 'theAccessToken=', $client); + $transport = $this->createTransport($client); $transport->setThreadKey('My-Thread'); $sentMessage = $transport->send(new ChatMessage('testMessage')); @@ -157,7 +157,7 @@ public function testSendWithNotification() return $response; }); - $transport = new GoogleChatTransport('My-Space', 'theAccessKey', 'theAccessToken=', $client); + $transport = $this->createTransport($client); $sentMessage = $transport->send($chatMessage); @@ -173,7 +173,7 @@ public function testSendWithInvalidOptions() return $this->createMock(ResponseInterface::class); }); - $transport = new GoogleChatTransport('My-Space', 'theAccessKey', 'theAccessToken=', $client); + $transport = $this->createTransport($client); $transport->send(new ChatMessage('testMessage', $this->createMock(MessageOptionsInterface::class))); } @@ -202,10 +202,15 @@ public function testSendWith200ResponseButNotOk() return $response; }); - $transport = new GoogleChatTransport('My-Space', 'theAccessKey', 'theAccessToken=', $client); + $transport = $this->createTransport($client); $sentMessage = $transport->send(new ChatMessage('testMessage')); $this->assertSame('spaces/My-Space/messages/abcdefg.hijklmno', $sentMessage->getMessageId()); } + + private function createTransport(?HttpClientInterface $client = null): GoogleChatTransport + { + return new GoogleChatTransport('My-Space', 'theAccessKey', 'theAccessToken=', $client ?: $this->createMock(HttpClientInterface::class)); + } } diff --git a/src/Symfony/Component/Notifier/Bridge/Infobip/InfobipTransportFactory.php b/src/Symfony/Component/Notifier/Bridge/Infobip/InfobipTransportFactory.php index 3c8a7968db0c..6b1d6ca745b6 100644 --- a/src/Symfony/Component/Notifier/Bridge/Infobip/InfobipTransportFactory.php +++ b/src/Symfony/Component/Notifier/Bridge/Infobip/InfobipTransportFactory.php @@ -31,6 +31,11 @@ final class InfobipTransportFactory extends AbstractTransportFactory public function create(Dsn $dsn): TransportInterface { $scheme = $dsn->getScheme(); + + if ('infobip' !== $scheme) { + throw new UnsupportedSchemeException($dsn, 'infobip', $this->getSupportedSchemes()); + } + $authToken = $this->getUser($dsn); $from = $dsn->getOption('from'); $host = $dsn->getHost(); @@ -40,11 +45,7 @@ public function create(Dsn $dsn): TransportInterface throw new IncompleteDsnException('Missing from.', $dsn->getOriginalDsn()); } - if ('infobip' === $scheme) { - return (new InfobipTransport($authToken, $from, $this->client, $this->dispatcher))->setHost($host)->setPort($port); - } - - throw new UnsupportedSchemeException($dsn, 'infobip', $this->getSupportedSchemes()); + return (new InfobipTransport($authToken, $from, $this->client, $this->dispatcher))->setHost($host)->setPort($port); } protected function getSupportedSchemes(): array diff --git a/src/Symfony/Component/Notifier/Bridge/Infobip/README.md b/src/Symfony/Component/Notifier/Bridge/Infobip/README.md index 91b3d482bf73..841b659d5fc3 100644 --- a/src/Symfony/Component/Notifier/Bridge/Infobip/README.md +++ b/src/Symfony/Component/Notifier/Bridge/Infobip/README.md @@ -7,7 +7,6 @@ DSN example ----------- ``` -// .env file INFOBIP_DSN=infobip://AUTH_TOKEN@INFOBIP_HOST?from=FROM ``` diff --git a/src/Symfony/Component/Notifier/Bridge/Infobip/Tests/InfobipTransportFactoryTest.php b/src/Symfony/Component/Notifier/Bridge/Infobip/Tests/InfobipTransportFactoryTest.php index 1478ebb169d3..a10c3214f451 100644 --- a/src/Symfony/Component/Notifier/Bridge/Infobip/Tests/InfobipTransportFactoryTest.php +++ b/src/Symfony/Component/Notifier/Bridge/Infobip/Tests/InfobipTransportFactoryTest.php @@ -21,43 +21,55 @@ final class InfobipTransportFactoryTest extends TestCase { public function testCreateWithDsn() { - $factory = new InfobipTransportFactory(); + $factory = $this->createFactory(); - $dsn = 'infobip://authtoken@default?from=0611223344'; - $transport = $factory->create(Dsn::fromString($dsn)); - $transport->setHost('host.test'); + $transport = $factory->create(Dsn::fromString('infobip://authtoken@host.test?from=0611223344')); $this->assertSame('infobip://host.test?from=0611223344', (string) $transport); } - public function testCreateWithNoFromThrowsMalformed() + public function testCreateWithNoFromThrowsIncompleteDsnException() { - $factory = new InfobipTransportFactory(); + $factory = $this->createFactory(); $this->expectException(IncompleteDsnException::class); + $factory->create(Dsn::fromString('infobip://authtoken@default')); + } + + public function testSupportsReturnsTrueWithSupportedScheme() + { + $factory = $this->createFactory(); - $dsnIncomplete = 'infobip://authtoken@default'; - $factory->create(Dsn::fromString($dsnIncomplete)); + $this->assertTrue($factory->supports(Dsn::fromString('infobip://authtoken@default?from=0611223344'))); } - public function testSupportsInfobipScheme() + public function testSupportsReturnsFalseWithUnsupportedScheme() { - $factory = new InfobipTransportFactory(); + $factory = $this->createFactory(); + + $this->assertFalse($factory->supports(Dsn::fromString('somethingElse://authtoken@default?from=0611223344'))); + } - $dsn = 'infobip://authtoken@default?from=0611223344'; - $dsnUnsupported = 'unsupported://authtoken@default?from=0611223344'; + public function testUnsupportedSchemeThrowsUnsupportedSchemeException() + { + $factory = $this->createFactory(); - $this->assertTrue($factory->supports(Dsn::fromString($dsn))); - $this->assertFalse($factory->supports(Dsn::fromString($dsnUnsupported))); + $this->expectException(UnsupportedSchemeException::class); + $factory->create(Dsn::fromString('somethingElse://authtoken@default?from=FROM')); } - public function testNonInfobipSchemeThrows() + public function testUnsupportedSchemeThrowsUnsupportedSchemeExceptionEvenIfRequiredOptionIsMissing() { - $factory = new InfobipTransportFactory(); + $factory = $this->createFactory(); $this->expectException(UnsupportedSchemeException::class); - $dsnUnsupported = 'unsupported://authtoken@default?from=0611223344'; - $factory->create(Dsn::fromString($dsnUnsupported)); + // unsupported scheme and missing "from" option + $factory->create(Dsn::fromString('somethingElse://authtoken@default')); + } + + private function createFactory(): InfobipTransportFactory + { + return new InfobipTransportFactory(); } } diff --git a/src/Symfony/Component/Notifier/Bridge/Infobip/Tests/InfobipTransportTest.php b/src/Symfony/Component/Notifier/Bridge/Infobip/Tests/InfobipTransportTest.php index ce616021ca22..7c4a9d214359 100644 --- a/src/Symfony/Component/Notifier/Bridge/Infobip/Tests/InfobipTransportTest.php +++ b/src/Symfony/Component/Notifier/Bridge/Infobip/Tests/InfobipTransportTest.php @@ -22,34 +22,30 @@ final class InfobipTransportTest extends TestCase { public function testToStringContainsProperties() { - $transport = $this->getTransport(); + $transport = $this->createTransport(); $this->assertSame('infobip://host.test?from=0611223344', (string) $transport); } public function testSupportsMessageInterface() { - $transport = $this->getTransport(); + $transport = $this->createTransport(); $this->assertTrue($transport->supports(new SmsMessage('0611223344', 'Hello!'))); $this->assertFalse($transport->supports($this->createMock(MessageInterface::class))); } - public function testSendNonSmsMessageThrowsException() + public function testSendNonSmsMessageThrowsLogicException() { - $transport = $this->getTransport(); + $transport = $this->createTransport(); $this->expectException(LogicException::class); $transport->send($this->createMock(MessageInterface::class)); } - private function getTransport(): InfobipTransport + private function createTransport(): InfobipTransport { - return (new InfobipTransport( - 'authtoken', - '0611223344', - $this->createMock(HttpClientInterface::class) - ))->setHost('host.test'); + return (new InfobipTransport('authtoken', '0611223344', $this->createMock(HttpClientInterface::class)))->setHost('host.test'); } } diff --git a/src/Symfony/Component/Notifier/Bridge/LinkedIn/LinkedInTransport.php b/src/Symfony/Component/Notifier/Bridge/LinkedIn/LinkedInTransport.php index 90304963078a..1e724846ef70 100644 --- a/src/Symfony/Component/Notifier/Bridge/LinkedIn/LinkedInTransport.php +++ b/src/Symfony/Component/Notifier/Bridge/LinkedIn/LinkedInTransport.php @@ -63,6 +63,7 @@ protected function doSend(MessageInterface $message): SentMessage if (!$message instanceof ChatMessage) { throw new LogicException(sprintf('The "%s" transport only supports instances of "%s" (instance of "%s" given).', __CLASS__, ChatMessage::class, \get_class($message))); } + if ($message->getOptions() && !$message->getOptions() instanceof LinkedInOptions) { throw new LogicException(sprintf('The "%s" transport only supports instances of "%s" for options.', __CLASS__, LinkedInOptions::class)); } @@ -87,7 +88,7 @@ protected function doSend(MessageInterface $message): SentMessage $result = $response->toArray(false); if (!$result['id']) { - throw new TransportException(sprintf('Unable to post the Linkedin message : "%s".', $result['error']), $response); + throw new TransportException(sprintf('Unable to post the Linkedin message: "%s".', $result['error']), $response); } $sentMessage = new SentMessage($message, (string) $this); diff --git a/src/Symfony/Component/Notifier/Bridge/LinkedIn/LinkedInTransportFactory.php b/src/Symfony/Component/Notifier/Bridge/LinkedIn/LinkedInTransportFactory.php index f13afa472301..d6f1a8523b77 100644 --- a/src/Symfony/Component/Notifier/Bridge/LinkedIn/LinkedInTransportFactory.php +++ b/src/Symfony/Component/Notifier/Bridge/LinkedIn/LinkedInTransportFactory.php @@ -26,16 +26,17 @@ class LinkedInTransportFactory extends AbstractTransportFactory public function create(Dsn $dsn): TransportInterface { $scheme = $dsn->getScheme(); + + if ('linkedin' !== $scheme) { + throw new UnsupportedSchemeException($dsn, 'linkedin', $this->getSupportedSchemes()); + } + $authToken = $this->getUser($dsn); $accountId = $this->getPassword($dsn); $host = 'default' === $dsn->getHost() ? null : $dsn->getHost(); $port = $dsn->getPort(); - if ('linkedin' === $scheme) { - return (new LinkedInTransport($authToken, $accountId, $this->client, $this->dispatcher))->setHost($host)->setPort($port); - } - - throw new UnsupportedSchemeException($dsn, 'linkedin', $this->getSupportedSchemes()); + return (new LinkedInTransport($authToken, $accountId, $this->client, $this->dispatcher))->setHost($host)->setPort($port); } protected function getSupportedSchemes(): array diff --git a/src/Symfony/Component/Notifier/Bridge/LinkedIn/README.md b/src/Symfony/Component/Notifier/Bridge/LinkedIn/README.md index 907b5cfc8bc0..29cb85b15baa 100644 --- a/src/Symfony/Component/Notifier/Bridge/LinkedIn/README.md +++ b/src/Symfony/Component/Notifier/Bridge/LinkedIn/README.md @@ -7,8 +7,7 @@ DSN example ----------- ``` -// .env file -LINKEDIN_DSN='linkedin://ACCESS_TOKEN:USER_ID@default' +LINKEDIN_DSN=linkedin://ACCESS_TOKEN:USER_ID@default ``` where: diff --git a/src/Symfony/Component/Notifier/Bridge/LinkedIn/Tests/LinkedInTransportFactoryTest.php b/src/Symfony/Component/Notifier/Bridge/LinkedIn/Tests/LinkedInTransportFactoryTest.php index c4943464a3a7..51dd961963c2 100644 --- a/src/Symfony/Component/Notifier/Bridge/LinkedIn/Tests/LinkedInTransportFactoryTest.php +++ b/src/Symfony/Component/Notifier/Bridge/LinkedIn/Tests/LinkedInTransportFactoryTest.php @@ -12,39 +12,45 @@ final class LinkedInTransportFactoryTest extends TestCase { public function testCreateWithDsn() { - $factory = new LinkedInTransportFactory(); + $factory = $this->createFactory(); - $dsn = 'linkedin://login:pass@default'; - $transport = $factory->create(Dsn::fromString($dsn)); - $transport->setHost('testHost'); + $transport = $factory->create(Dsn::fromString('linkedin://accessToken:UserId@host.test')); - $this->assertSame('linkedin://testHost', (string) $transport); + $this->assertSame('linkedin://host.test', (string) $transport); } - public function testSupportsLinkedinScheme() + public function testCreateWithOnlyAccessTokenOrUserIdThrowsIncompleteDsnException() { - $factory = new LinkedInTransportFactory(); + $factory = $this->createFactory(); - $this->assertTrue($factory->supports(Dsn::fromString('linkedin://host/path'))); - $this->assertFalse($factory->supports(Dsn::fromString('somethingElse://host/path'))); + $this->expectException(IncompleteDsnException::class); + $factory->create(Dsn::fromString('linkedin://AccessTokenOrUserId@default')); } - public function testNonLinkedinSchemeThrows() + public function testSupportsReturnsTrueWithSupportedScheme() { - $factory = new LinkedInTransportFactory(); + $factory = $this->createFactory(); - $this->expectException(UnsupportedSchemeException::class); + $this->assertTrue($factory->supports(Dsn::fromString('linkedin://host/path'))); + } - $dsn = 'foo://login:pass@default'; - $factory->create(Dsn::fromString($dsn)); + public function testSupportsReturnsFalseWithUnsupportedScheme() + { + $factory = $this->createFactory(); + + $this->assertFalse($factory->supports(Dsn::fromString('somethingElse://host/path'))); } - public function testIncompleteDsnMissingUserThrows() + public function testUnsupportedSchemeThrowsUnsupportedSchemeException() { - $factory = new LinkedInTransportFactory(); + $factory = $this->createFactory(); - $this->expectException(IncompleteDsnException::class); + $this->expectException(UnsupportedSchemeException::class); + $factory->create(Dsn::fromString('somethingElse://accessToken:UserId@default')); + } - $factory->create(Dsn::fromString('somethingElse://host/path')); + private function createFactory(): LinkedInTransportFactory + { + return new LinkedInTransportFactory(); } } diff --git a/src/Symfony/Component/Notifier/Bridge/LinkedIn/Tests/LinkedInTransportTest.php b/src/Symfony/Component/Notifier/Bridge/LinkedIn/Tests/LinkedInTransportTest.php index cbf9a2ba5f3e..524bc5d8b769 100644 --- a/src/Symfony/Component/Notifier/Bridge/LinkedIn/Tests/LinkedInTransportTest.php +++ b/src/Symfony/Component/Notifier/Bridge/LinkedIn/Tests/LinkedInTransportTest.php @@ -16,14 +16,16 @@ final class LinkedInTransportTest extends TestCase { - public function testToString() + public function testToStringContainsProperties() { - $this->assertSame(sprintf('linkedin://host.test'), (string) $this->getTransport()); + $transport = $this->createTransport(); + + $this->assertSame('linkedin://host.test', (string) $transport); } public function testSupportsChatMessage() { - $transport = $this->getTransport(); + $transport = $this->createTransport(); $this->assertTrue($transport->supports(new ChatMessage('testChatMessage'))); $this->assertFalse($transport->supports($this->createMock(MessageInterface::class))); @@ -31,10 +33,9 @@ public function testSupportsChatMessage() public function testSendNonChatMessageThrows() { - $this->expectException(LogicException::class); - - $transport = $this->getTransport(); + $transport = $this->createTransport(); + $this->expectException(LogicException::class); $transport->send($this->createMock(MessageInterface::class)); } @@ -54,7 +55,7 @@ public function testSendWithEmptyArrayResponseThrows() return $response; }); - $transport = $this->getTransport($client); + $transport = $this->createTransport($client); $transport->send(new ChatMessage('testMessage')); } @@ -77,7 +78,7 @@ public function testSendWithErrorResponseThrows() return $response; }); - $transport = $this->getTransport($client); + $transport = $this->createTransport($client); $transport->send(new ChatMessage('testMessage')); } @@ -98,19 +99,19 @@ public function testSendWithOptions() $expectedBody = json_encode([ 'specificContent' => [ - 'com.linkedin.ugc.ShareContent' => [ - 'shareCommentary' => [ - 'attributes' => [], - 'text' => 'testMessage', - ], - 'shareMediaCategory' => 'NONE', - ], + 'com.linkedin.ugc.ShareContent' => [ + 'shareCommentary' => [ + 'attributes' => [], + 'text' => 'testMessage', ], - 'visibility' => [ - 'com.linkedin.ugc.MemberNetworkVisibility' => 'PUBLIC', + 'shareMediaCategory' => 'NONE', ], + ], + 'visibility' => [ + 'com.linkedin.ugc.MemberNetworkVisibility' => 'PUBLIC', + ], 'lifecycleState' => 'PUBLISHED', - 'author' => 'urn:li:person:MyLogin', + 'author' => 'urn:li:person:AccountId', ]); $client = new MockHttpClient(function (string $method, string $url, array $options = []) use ( @@ -121,7 +122,7 @@ public function testSendWithOptions() return $response; }); - $transport = $this->getTransport($client); + $transport = $this->createTransport($client); $transport->send(new ChatMessage($message)); } @@ -145,19 +146,19 @@ public function testSendWithNotification() $expectedBody = json_encode([ 'specificContent' => [ - 'com.linkedin.ugc.ShareContent' => [ - 'shareCommentary' => [ - 'attributes' => [], - 'text' => 'testMessage', - ], - 'shareMediaCategory' => 'NONE', - ], + 'com.linkedin.ugc.ShareContent' => [ + 'shareCommentary' => [ + 'attributes' => [], + 'text' => 'testMessage', ], - 'visibility' => [ - 'com.linkedin.ugc.MemberNetworkVisibility' => 'PUBLIC', + 'shareMediaCategory' => 'NONE', ], + ], + 'visibility' => [ + 'com.linkedin.ugc.MemberNetworkVisibility' => 'PUBLIC', + ], 'lifecycleState' => 'PUBLISHED', - 'author' => 'urn:li:person:MyLogin', + 'author' => 'urn:li:person:AccountId', ]); $client = new MockHttpClient(function (string $method, string $url, array $options = []) use ( @@ -169,7 +170,7 @@ public function testSendWithNotification() return $response; }); - $transport = $this->getTransport($client); + $transport = $this->createTransport($client); $transport->send($chatMessage); } @@ -182,17 +183,13 @@ public function testSendWithInvalidOptions() return $this->createMock(ResponseInterface::class); }); - $transport = $this->getTransport($client); + $transport = $this->createTransport($client); $transport->send(new ChatMessage('testMessage', $this->createMock(MessageOptionsInterface::class))); } - public function getTransport($client = null) + private function createTransport(?HttpClientInterface $client = null): LinkedInTransport { - return (new LinkedInTransport( - 'MyToken', - 'MyLogin', - $client ?? $this->createMock(HttpClientInterface::class) - ))->setHost('host.test'); + return (new LinkedInTransport('AuthToken', 'AccountId', $client ?? $this->createMock(HttpClientInterface::class)))->setHost('host.test'); } } diff --git a/src/Symfony/Component/Notifier/Bridge/Mattermost/MattermostTransport.php b/src/Symfony/Component/Notifier/Bridge/Mattermost/MattermostTransport.php index 98c43e26e09e..903f067f43d7 100644 --- a/src/Symfony/Component/Notifier/Bridge/Mattermost/MattermostTransport.php +++ b/src/Symfony/Component/Notifier/Bridge/Mattermost/MattermostTransport.php @@ -78,9 +78,9 @@ protected function doSend(MessageInterface $message): SentMessage $success = $response->toArray(false); - $message = new SentMessage($message, (string) $this); - $message->setMessageId($success['id']); + $sentMessage = new SentMessage($sentMessage, (string) $this); + $sentMessage->setMessageId($success['id']); - return $message; + return $sentMessage; } } diff --git a/src/Symfony/Component/Notifier/Bridge/Mattermost/Tests/MattermostTransportFactoryTest.php b/src/Symfony/Component/Notifier/Bridge/Mattermost/Tests/MattermostTransportFactoryTest.php index daa774130a1f..030c53a45730 100644 --- a/src/Symfony/Component/Notifier/Bridge/Mattermost/Tests/MattermostTransportFactoryTest.php +++ b/src/Symfony/Component/Notifier/Bridge/Mattermost/Tests/MattermostTransportFactoryTest.php @@ -45,6 +45,7 @@ public function testCreateWithNoTokenThrowsIncompleteDsnException() $factory = $this->createFactory(); $this->expectException(IncompleteDsnException::class); + $factory->create(Dsn::fromString('mattermost://host.test?channel=testChannel')); } diff --git a/src/Symfony/Component/Notifier/Bridge/Mobyt/MobytOptions.php b/src/Symfony/Component/Notifier/Bridge/Mobyt/MobytOptions.php index dc45cd780e26..81b74003702b 100644 --- a/src/Symfony/Component/Notifier/Bridge/Mobyt/MobytOptions.php +++ b/src/Symfony/Component/Notifier/Bridge/Mobyt/MobytOptions.php @@ -25,7 +25,7 @@ final class MobytOptions implements MessageOptionsInterface public const MESSAGE_TYPE_QUALITY_MEDIUM = 'L'; public const MESSAGE_TYPE_QUALITY_LOW = 'LL'; - private $options = []; + private $options; public function __construct(array $options = []) { diff --git a/src/Symfony/Component/Notifier/Bridge/Mobyt/MobytTransport.php b/src/Symfony/Component/Notifier/Bridge/Mobyt/MobytTransport.php index 1f2a793dfd34..18b37e50065f 100644 --- a/src/Symfony/Component/Notifier/Bridge/Mobyt/MobytTransport.php +++ b/src/Symfony/Component/Notifier/Bridge/Mobyt/MobytTransport.php @@ -34,7 +34,7 @@ final class MobytTransport extends AbstractTransport private $from; private $typeQuality; - public function __construct(string $accountSid, string $authToken, $from, string $typeQuality, HttpClientInterface $client = null, EventDispatcherInterface $dispatcher = null) + public function __construct(string $accountSid, string $authToken, string $from, string $typeQuality, HttpClientInterface $client = null, EventDispatcherInterface $dispatcher = null) { $this->accountSid = $accountSid; $this->authToken = $authToken; @@ -93,9 +93,9 @@ protected function doSend(MessageInterface $message): SentMessage $success = $response->toArray(false); - $message = new SentMessage($message, (string) $this); - $message->setMessageId($success['order_id']); + $sentMessage = new SentMessage($message, (string) $this); + $sentMessage->setMessageId($success['order_id']); - return $message; + return $sentMessage; } } diff --git a/src/Symfony/Component/Notifier/Bridge/Mobyt/MobytTransportFactory.php b/src/Symfony/Component/Notifier/Bridge/Mobyt/MobytTransportFactory.php index d3eda1610f72..ae86675ee681 100644 --- a/src/Symfony/Component/Notifier/Bridge/Mobyt/MobytTransportFactory.php +++ b/src/Symfony/Component/Notifier/Bridge/Mobyt/MobytTransportFactory.php @@ -11,6 +11,7 @@ namespace Symfony\Component\Notifier\Bridge\Mobyt; +use Symfony\Component\Notifier\Exception\IncompleteDsnException; use Symfony\Component\Notifier\Exception\UnsupportedSchemeException; use Symfony\Component\Notifier\Transport\AbstractTransportFactory; use Symfony\Component\Notifier\Transport\Dsn; @@ -29,18 +30,24 @@ final class MobytTransportFactory extends AbstractTransportFactory public function create(Dsn $dsn): TransportInterface { $scheme = $dsn->getScheme(); + + if ('mobyt' !== $scheme) { + throw new UnsupportedSchemeException($dsn, 'mobyt', $this->getSupportedSchemes()); + } + $accountSid = $this->getUser($dsn); $authToken = $this->getPassword($dsn); $from = $dsn->getOption('from'); + + if (!$from) { + throw new IncompleteDsnException('Missing from.', $dsn->getOriginalDsn()); + } + $typeQuality = $dsn->getOption('type_quality', MobytOptions::MESSAGE_TYPE_QUALITY_LOW); $host = 'default' === $dsn->getHost() ? null : $dsn->getHost(); $port = $dsn->getPort(); - if ('mobyt' === $scheme) { - return (new MobytTransport($accountSid, $authToken, $from, $typeQuality, $this->client, $this->dispatcher))->setHost($host)->setPort($port); - } - - throw new UnsupportedSchemeException($dsn, 'mobyt', $this->getSupportedSchemes()); + return (new MobytTransport($accountSid, $authToken, $from, $typeQuality, $this->client, $this->dispatcher))->setHost($host)->setPort($port); } protected function getSupportedSchemes(): array diff --git a/src/Symfony/Component/Notifier/Bridge/Mobyt/README.md b/src/Symfony/Component/Notifier/Bridge/Mobyt/README.md index f992b3e1edd9..0e556c104710 100644 --- a/src/Symfony/Component/Notifier/Bridge/Mobyt/README.md +++ b/src/Symfony/Component/Notifier/Bridge/Mobyt/README.md @@ -7,15 +7,14 @@ DSN example ----------- ``` -// .env file MOBYT_DSN=mobyt://USER_KEY:ACCESS_TOKEN@default?from=FROM&type_quality=TYPE_QUALITY ``` where: - `USER_KEY` is your Mobyt user key - `ACCESS_TOKEN` is your Mobyt access token - - `TYPE_QUALITY` is the quality : `N` for high, `L` for medium, `LL` for low (default: `L`) - `FROM` is the sender + - `TYPE_QUALITY` is the quality : `N` for high, `L` for medium, `LL` for low (default: `L`) Resources --------- diff --git a/src/Symfony/Component/Notifier/Bridge/Mobyt/Tests/MobytOptionsTest.php b/src/Symfony/Component/Notifier/Bridge/Mobyt/Tests/MobytOptionsTest.php index 23f20819c43d..a56f587324e0 100644 --- a/src/Symfony/Component/Notifier/Bridge/Mobyt/Tests/MobytOptionsTest.php +++ b/src/Symfony/Component/Notifier/Bridge/Mobyt/Tests/MobytOptionsTest.php @@ -6,29 +6,23 @@ use Symfony\Component\Notifier\Bridge\Mobyt\MobytOptions; use Symfony\Component\Notifier\Notification\Notification; -class MobytOptionsTest extends TestCase +final class MobytOptionsTest extends TestCase { /** * @dataProvider fromNotificationDataProvider */ - public function testFromNotification($importance, $expectedMessageType) + public function testFromNotification(string $importance, string $expectedMessageType) { $notification = (new Notification('Foo'))->importance($importance); $options = (MobytOptions::fromNotification($notification))->toArray(); - $this->assertEquals($expectedMessageType, $options['message_type']); - } - - public function testFromNotificationDefaultLevel() - { - $notification = (new Notification('Foo'))->importance('Bar'); - - $options = (MobytOptions::fromNotification($notification))->toArray(); - - $this->assertEquals(MobytOptions::MESSAGE_TYPE_QUALITY_HIGH, $options['message_type']); + $this->assertSame($expectedMessageType, $options['message_type']); } + /** + * @return \Generator + */ public function fromNotificationDataProvider(): \Generator { yield [Notification::IMPORTANCE_URGENT, MobytOptions::MESSAGE_TYPE_QUALITY_HIGH]; @@ -37,14 +31,22 @@ public function fromNotificationDataProvider(): \Generator yield [Notification::IMPORTANCE_LOW, MobytOptions::MESSAGE_TYPE_QUALITY_LOW]; } + public function testFromNotificationDefaultLevel() + { + $notification = (new Notification('Foo'))->importance('Bar'); + + $options = (MobytOptions::fromNotification($notification))->toArray(); + + $this->assertSame(MobytOptions::MESSAGE_TYPE_QUALITY_HIGH, $options['message_type']); + } + public function testGetRecipientIdWhenSet() { - $options = [ + $mobytOptions = new MobytOptions([ 'recipient' => 'foo', - ]; - $mobytOptions = new MobytOptions($options); + ]); - $this->assertEquals('foo', $mobytOptions->getRecipientId()); + $this->assertSame('foo', $mobytOptions->getRecipientId()); } public function testGetRecipientIdWhenNotSet() @@ -54,11 +56,12 @@ public function testGetRecipientIdWhenNotSet() public function testToArray() { - $options = [ + $mobytOptions = new MobytOptions([ 'message' => 'foo', 'recipient' => 'bar', - ]; - $this->assertEmpty((new MobytOptions($options))->toArray()); + ]); + + $this->assertEmpty($mobytOptions->toArray()); } public function testMessageType() @@ -66,6 +69,6 @@ public function testMessageType() $mobytOptions = new MobytOptions(); $mobytOptions->messageType('foo'); - $this->assertEquals(['message_type' => 'foo'], $mobytOptions->toArray()); + $this->assertSame(['message_type' => 'foo'], $mobytOptions->toArray()); } } diff --git a/src/Symfony/Component/Notifier/Bridge/Nexmo/NexmoTransport.php b/src/Symfony/Component/Notifier/Bridge/Nexmo/NexmoTransport.php index c506d0ab96da..d0faded96e89 100644 --- a/src/Symfony/Component/Notifier/Bridge/Nexmo/NexmoTransport.php +++ b/src/Symfony/Component/Notifier/Bridge/Nexmo/NexmoTransport.php @@ -77,9 +77,9 @@ protected function doSend(MessageInterface $message): SentMessage $success = $response->toArray(false); - $message = new SentMessage($message, (string) $this); - $message->setMessageId($success['messages'][0]['message-id']); + $sentMessage = new SentMessage($message, (string) $this); + $sentMessage->setMessageId($success['messages'][0]['message-id']); - return $message; + return $sentMessage; } } diff --git a/src/Symfony/Component/Notifier/Bridge/Nexmo/Tests/NexmoTransportTest.php b/src/Symfony/Component/Notifier/Bridge/Nexmo/Tests/NexmoTransportTest.php index 6e4c21a28dbc..384b879c9386 100644 --- a/src/Symfony/Component/Notifier/Bridge/Nexmo/Tests/NexmoTransportTest.php +++ b/src/Symfony/Component/Notifier/Bridge/Nexmo/Tests/NexmoTransportTest.php @@ -35,7 +35,7 @@ public function testSupportsMessageInterface() $this->assertFalse($transport->supports($this->createMock(MessageInterface::class))); } - public function testSendNonSmsMessageThrowsException() + public function testSendNonSmsMessageThrowsLogicException() { $transport = $this->createTransport(); diff --git a/src/Symfony/Component/Notifier/Bridge/OvhCloud/OvhCloudTransport.php b/src/Symfony/Component/Notifier/Bridge/OvhCloud/OvhCloudTransport.php index ad1757ad51ae..152e37100061 100644 --- a/src/Symfony/Component/Notifier/Bridge/OvhCloud/OvhCloudTransport.php +++ b/src/Symfony/Component/Notifier/Bridge/OvhCloud/OvhCloudTransport.php @@ -94,10 +94,10 @@ protected function doSend(MessageInterface $message): SentMessage $success = $response->toArray(false); - $message = new SentMessage($message, (string) $this); - $message->setMessageId($success['ids'][0]); + $sentMessage = new SentMessage($message, (string) $this); + $sentMessage->setMessageId($success['ids'][0]); - return $message; + return $sentMessage; } /** diff --git a/src/Symfony/Component/Notifier/Bridge/OvhCloud/Tests/OvhCloudTransportTest.php b/src/Symfony/Component/Notifier/Bridge/OvhCloud/Tests/OvhCloudTransportTest.php index e8341582461b..9b3699f40138 100644 --- a/src/Symfony/Component/Notifier/Bridge/OvhCloud/Tests/OvhCloudTransportTest.php +++ b/src/Symfony/Component/Notifier/Bridge/OvhCloud/Tests/OvhCloudTransportTest.php @@ -35,7 +35,7 @@ public function testSupportsMessageInterface() $this->assertFalse($transport->supports($this->createMock(MessageInterface::class))); } - public function testSendNonSmsMessageThrowsException() + public function testSendNonSmsMessageThrowsLogicException() { $transport = $this->createTransport(); diff --git a/src/Symfony/Component/Notifier/Bridge/RocketChat/RocketChatTransport.php b/src/Symfony/Component/Notifier/Bridge/RocketChat/RocketChatTransport.php index ef2f68b0fb4c..fdf3eafd4a9c 100644 --- a/src/Symfony/Component/Notifier/Bridge/RocketChat/RocketChatTransport.php +++ b/src/Symfony/Component/Notifier/Bridge/RocketChat/RocketChatTransport.php @@ -92,9 +92,9 @@ protected function doSend(MessageInterface $message): SentMessage $success = $response->toArray(false); - $message = new SentMessage($message, (string) $this); - $message->setMessageId($success['message']['_id']); + $sentMessage = new SentMessage($message, (string) $this); + $sentMessage->setMessageId($success['message']['_id']); - return $message; + return $sentMessage; } } diff --git a/src/Symfony/Component/Notifier/Bridge/RocketChat/Tests/RocketChatTransportFactoryTest.php b/src/Symfony/Component/Notifier/Bridge/RocketChat/Tests/RocketChatTransportFactoryTest.php index 7d7c06e4e198..937571f44c4e 100644 --- a/src/Symfony/Component/Notifier/Bridge/RocketChat/Tests/RocketChatTransportFactoryTest.php +++ b/src/Symfony/Component/Notifier/Bridge/RocketChat/Tests/RocketChatTransportFactoryTest.php @@ -36,6 +36,7 @@ public function testCreateWithNoTokenThrowsIncompleteDsnException() $factory = $this->createFactory(); $this->expectException(IncompleteDsnException::class); + $factory->create(Dsn::fromString('rocketchat://host.test?channel=testChannel')); } diff --git a/src/Symfony/Component/Notifier/Bridge/Sendinblue/README.md b/src/Symfony/Component/Notifier/Bridge/Sendinblue/README.md index 24016686f9a4..cf9336f454a2 100644 --- a/src/Symfony/Component/Notifier/Bridge/Sendinblue/README.md +++ b/src/Symfony/Component/Notifier/Bridge/Sendinblue/README.md @@ -1,19 +1,18 @@ Sendinblue Notifier =================== -Provides Sendinblue integration for Symfony Notifier. +Provides [Sendinblue](https://sendinblue.com) integration for Symfony Notifier. DSN example ----------- ``` -// .env file -SENDINBLUE_DSN=sendinblue://API_KEY@default?sender=PHONE +SENDINBLUE_DSN=sendinblue://API_KEY@default?sender=SENDER ``` where: - `API_KEY` is your api key from your Sendinblue account - - `PHONE` is your sender's phone number + - `SENDER` is your sender's phone number See more info at https://developers.sendinblue.com/reference#sendtransacsms diff --git a/src/Symfony/Component/Notifier/Bridge/Sendinblue/SendinblueTransport.php b/src/Symfony/Component/Notifier/Bridge/Sendinblue/SendinblueTransport.php index 889bd1c454cf..7964d4e20cdf 100644 --- a/src/Symfony/Component/Notifier/Bridge/Sendinblue/SendinblueTransport.php +++ b/src/Symfony/Component/Notifier/Bridge/Sendinblue/SendinblueTransport.php @@ -75,9 +75,9 @@ protected function doSend(MessageInterface $message): SentMessage $success = $response->toArray(false); - $message = new SentMessage($message, (string) $this); - $message->setMessageId($success['messageId']); + $sentMessage = new SentMessage($message, (string) $this); + $sentMessage->setMessageId($success['messageId']); - return $message; + return $sentMessage; } } diff --git a/src/Symfony/Component/Notifier/Bridge/Sendinblue/SendinblueTransportFactory.php b/src/Symfony/Component/Notifier/Bridge/Sendinblue/SendinblueTransportFactory.php index 7f9d1f9b4b78..daed3ed3d6e6 100644 --- a/src/Symfony/Component/Notifier/Bridge/Sendinblue/SendinblueTransportFactory.php +++ b/src/Symfony/Component/Notifier/Bridge/Sendinblue/SendinblueTransportFactory.php @@ -29,20 +29,23 @@ final class SendinblueTransportFactory extends AbstractTransportFactory */ public function create(Dsn $dsn): TransportInterface { - if (!$sender = $dsn->getOption('sender')) { - throw new IncompleteDsnException('Missing sender.', $dsn->getOriginalDsn()); + $scheme = $dsn->getScheme(); + + if ('sendinblue' !== $scheme) { + throw new UnsupportedSchemeException($dsn, 'sendinblue', $this->getSupportedSchemes()); } - $scheme = $dsn->getScheme(); $apiKey = $this->getUser($dsn); - $host = 'default' === $dsn->getHost() ? null : $dsn->getHost(); - $port = $dsn->getPort(); + $sender = $dsn->getOption('sender'); - if ('sendinblue' === $scheme) { - return (new SendinblueTransport($apiKey, $sender, $this->client, $this->dispatcher))->setHost($host)->setPort($port); + if (!$sender) { + throw new IncompleteDsnException('Missing sender.', $dsn->getOriginalDsn()); } - throw new UnsupportedSchemeException($dsn, 'sendinblue', $this->getSupportedSchemes()); + $host = 'default' === $dsn->getHost() ? null : $dsn->getHost(); + $port = $dsn->getPort(); + + return (new SendinblueTransport($apiKey, $sender, $this->client, $this->dispatcher))->setHost($host)->setPort($port); } protected function getSupportedSchemes(): array diff --git a/src/Symfony/Component/Notifier/Bridge/Sendinblue/Tests/SendinblueTransportFactoryTest.php b/src/Symfony/Component/Notifier/Bridge/Sendinblue/Tests/SendinblueTransportFactoryTest.php index 187e1291e443..a2a1c605ef5a 100644 --- a/src/Symfony/Component/Notifier/Bridge/Sendinblue/Tests/SendinblueTransportFactoryTest.php +++ b/src/Symfony/Component/Notifier/Bridge/Sendinblue/Tests/SendinblueTransportFactoryTest.php @@ -14,43 +14,72 @@ use PHPUnit\Framework\TestCase; use Symfony\Component\Notifier\Bridge\Sendinblue\SendinblueTransportFactory; use Symfony\Component\Notifier\Exception\IncompleteDsnException; +use Symfony\Component\Notifier\Exception\UnsupportedSchemeException; use Symfony\Component\Notifier\Transport\Dsn; final class SendinblueTransportFactoryTest extends TestCase { public function testCreateWithDsn() { - $factory = $this->initFactory(); + $factory = $this->createFactory(); - $dsn = 'sendinblue://apiKey@default?sender=0611223344'; - $transport = $factory->create(Dsn::fromString($dsn)); - $transport->setHost('host.test'); + $transport = $factory->create(Dsn::fromString('sendinblue://apiKey@host.test?sender=0611223344')); $this->assertSame('sendinblue://host.test?sender=0611223344', (string) $transport); } - public function testCreateWithNoPhoneThrowsMalformed() + public function testCreateWithMissingOptionSenderThrowsIncompleteDsnException() { - $factory = $this->initFactory(); + $factory = $this->createFactory(); $this->expectException(IncompleteDsnException::class); - $dsnIncomplete = 'sendinblue://apiKey@default'; - $factory->create(Dsn::fromString($dsnIncomplete)); + $factory->create(Dsn::fromString('sendinblue://apiKey@host.test')); } - public function testSupportsSendinblueScheme() + public function testCreateWithNoApiKeyThrowsIncompleteDsnException() { - $factory = $this->initFactory(); + $factory = $this->createFactory(); - $dsn = 'sendinblue://apiKey@default?sender=0611223344'; - $dsnUnsupported = 'foobarmobile://apiKey@default?sender=0611223344'; + $this->expectException(IncompleteDsnException::class); + + $factory->create(Dsn::fromString('sendinblue://default?sender=0611223344')); + } + + public function testSupportsReturnsTrueWithSupportedScheme() + { + $factory = $this->createFactory(); + + $this->assertTrue($factory->supports(Dsn::fromString('sendinblue://apiKey@default?sender=0611223344'))); + } + + public function testSupportsReturnsFalseWithUnsupportedScheme() + { + $factory = $this->createFactory(); + + $this->assertFalse($factory->supports(Dsn::fromString('somethingElse://apiKey@default?sender=0611223344'))); + } + + public function testUnsupportedSchemeThrowsUnsupportedSchemeException() + { + $factory = $this->createFactory(); + + $this->expectException(UnsupportedSchemeException::class); + + $factory->create(Dsn::fromString('somethingElse://apiKey@default?sender=0611223344')); + } + + public function testUnsupportedSchemeThrowsUnsupportedSchemeExceptionEvenIfRequiredOptionIsMissing() + { + $factory = $this->createFactory(); + + $this->expectException(UnsupportedSchemeException::class); - $this->assertTrue($factory->supports(Dsn::fromString($dsn))); - $this->assertFalse($factory->supports(Dsn::fromString($dsnUnsupported))); + // unsupported scheme and missing "from" option + $factory->create(Dsn::fromString('somethingElse://apiKey@host')); } - private function initFactory(): SendinblueTransportFactory + private function createFactory(): SendinblueTransportFactory { return new SendinblueTransportFactory(); } diff --git a/src/Symfony/Component/Notifier/Bridge/Sendinblue/Tests/SendinblueTransportTest.php b/src/Symfony/Component/Notifier/Bridge/Sendinblue/Tests/SendinblueTransportTest.php index 4528f64ed0ab..438ba57960ba 100644 --- a/src/Symfony/Component/Notifier/Bridge/Sendinblue/Tests/SendinblueTransportTest.php +++ b/src/Symfony/Component/Notifier/Bridge/Sendinblue/Tests/SendinblueTransportTest.php @@ -25,22 +25,22 @@ final class SendinblueTransportTest extends TestCase { public function testToStringContainsProperties() { - $transport = $this->initTransport(); + $transport = $this->createTransport(); $this->assertSame('sendinblue://host.test?sender=0611223344', (string) $transport); } public function testSupportsMessageInterface() { - $transport = $this->initTransport(); + $transport = $this->createTransport(); $this->assertTrue($transport->supports(new SmsMessage('0611223344', 'Hello!'))); $this->assertFalse($transport->supports($this->createMock(MessageInterface::class))); } - public function testSendNonSmsMessageThrowsException() + public function testSendNonSmsMessageThrowsLogicException() { - $transport = $this->initTransport(); + $transport = $this->createTransport(); $this->expectException(LogicException::class); $transport->send($this->createMock(MessageInterface::class)); @@ -60,17 +60,15 @@ public function testSendWithErrorResponseThrows() return $response; }); - $transport = $this->initTransport($client); + $transport = $this->createTransport($client); $this->expectException(TransportException::class); $this->expectExceptionMessage('Unable to send the SMS: bad request'); $transport->send(new SmsMessage('phone', 'testMessage')); } - private function initTransport(?HttpClientInterface $client = null): SendinblueTransport + private function createTransport(?HttpClientInterface $client = null): SendinblueTransport { - return (new SendinblueTransport( - 'api-key', '0611223344', $client ?: $this->createMock(HttpClientInterface::class) - ))->setHost('host.test'); + return (new SendinblueTransport('api-key', '0611223344', $client ?: $this->createMock(HttpClientInterface::class)))->setHost('host.test'); } } diff --git a/src/Symfony/Component/Notifier/Bridge/Sinch/SinchTransport.php b/src/Symfony/Component/Notifier/Bridge/Sinch/SinchTransport.php index 0810aae70256..10f272db4025 100644 --- a/src/Symfony/Component/Notifier/Bridge/Sinch/SinchTransport.php +++ b/src/Symfony/Component/Notifier/Bridge/Sinch/SinchTransport.php @@ -76,9 +76,9 @@ protected function doSend(MessageInterface $message): SentMessage $success = $response->toArray(false); - $message = new SentMessage($message, (string) $this); - $message->setMessageId($success['id']); + $sentMessage = new SentMessage($message, (string) $this); + $sentMessage->setMessageId($success['id']); - return $message; + return $sentMessage; } } diff --git a/src/Symfony/Component/Notifier/Bridge/Sinch/Tests/SinchTransportTest.php b/src/Symfony/Component/Notifier/Bridge/Sinch/Tests/SinchTransportTest.php index 7f7ea4208c99..1332e59e95b2 100644 --- a/src/Symfony/Component/Notifier/Bridge/Sinch/Tests/SinchTransportTest.php +++ b/src/Symfony/Component/Notifier/Bridge/Sinch/Tests/SinchTransportTest.php @@ -35,7 +35,7 @@ public function testSupportsMessageInterface() $this->assertFalse($transport->supports($this->createMock(MessageInterface::class))); } - public function testSendNonSmsMessageThrowsException() + public function testSendNonSmsMessageThrowsLogicException() { $transport = $this->createTransport(); diff --git a/src/Symfony/Component/Notifier/Bridge/Slack/README.md b/src/Symfony/Component/Notifier/Bridge/Slack/README.md index 4eae10826d8e..518c843ca299 100644 --- a/src/Symfony/Component/Notifier/Bridge/Slack/README.md +++ b/src/Symfony/Component/Notifier/Bridge/Slack/README.md @@ -7,29 +7,25 @@ DSN example ----------- ``` -SLACK_DSN=slack://default/ID +SLACK_DSN=slack://TOKEN@default?channel=CHANNEL ``` where: -- `ID` is your webhook id (e.g. `/XXXXXXXXX/XXXXXXXXX/XXXXXXXXXXXXXXXXXXXXXXXX`) +- `TOKEN` is your Bot User OAuth Access Token (they begin with `xoxb-`) +- `CHANNEL` is a channel, private group, or IM channel to send message to, it can be an encoded ID, or a name. -in this case: +valid DSN's are: ``` -SLACK_DSN=slack://default/XXXXXXXXX/XXXXXXXXX/XXXXXXXXXXXXXXXXXXXXXXXX +SLACK_DSN=slack://xoxb-......@default?channel=my-channel-name +SLACK_DSN=slack://xoxb-......@default?channel=@fabien ``` -DSN example ------------ - +invalid DSN's are: ``` -// .env file -SLACK_DSN=slack://TOKEN@default?channel=CHANNEL +SLACK_DSN=slack://xoxb-......@default?channel=#my-channel-name +SLACK_DSN=slack://xoxb-......@default?channel=fabien ``` -where: -- `TOKEN` is your Bot User OAuth Access Token -- `CHANNEL` is a Channel, private group, or IM channel to send message to. Can be an encoded ID, or a name - Resources --------- diff --git a/src/Symfony/Component/Notifier/Bridge/Slack/SlackTransport.php b/src/Symfony/Component/Notifier/Bridge/Slack/SlackTransport.php index f4e144b9acf5..6cdfefaddcd1 100644 --- a/src/Symfony/Component/Notifier/Bridge/Slack/SlackTransport.php +++ b/src/Symfony/Component/Notifier/Bridge/Slack/SlackTransport.php @@ -59,6 +59,7 @@ protected function doSend(MessageInterface $message): SentMessage if (!$message instanceof ChatMessage) { throw new LogicException(sprintf('The "%s" transport only supports instances of "%s" (instance of "%s" given).', __CLASS__, ChatMessage::class, get_debug_type($message))); } + if ($message->getOptions() && !$message->getOptions() instanceof SlackOptions) { throw new LogicException(sprintf('The "%s" transport only supports instances of "%s" for options.', __CLASS__, SlackOptions::class)); } diff --git a/src/Symfony/Component/Notifier/Bridge/Slack/Tests/Block/SlackSectionBlockTest.php b/src/Symfony/Component/Notifier/Bridge/Slack/Tests/Block/SlackSectionBlockTest.php index 7e1e98981d19..0a1c097bcf54 100644 --- a/src/Symfony/Component/Notifier/Bridge/Slack/Tests/Block/SlackSectionBlockTest.php +++ b/src/Symfony/Component/Notifier/Bridge/Slack/Tests/Block/SlackSectionBlockTest.php @@ -17,7 +17,7 @@ final class SlackSectionBlockTest extends TestCase { - public function testCanBeInstantiated(): void + public function testCanBeInstantiated() { $section = new SlackSectionBlock(); $section->text('section text'); @@ -44,7 +44,7 @@ public function testCanBeInstantiated(): void ], $section->toArray()); } - public function testThrowsWhenFieldsLimitReached(): void + public function testThrowsWhenFieldsLimitReached() { $section = new SlackSectionBlock(); for ($i = 0; $i < 10; ++$i) { diff --git a/src/Symfony/Component/Notifier/Bridge/Slack/Tests/SlackTransportFactoryTest.php b/src/Symfony/Component/Notifier/Bridge/Slack/Tests/SlackTransportFactoryTest.php index 9c01d5b386ad..8965657f28c6 100644 --- a/src/Symfony/Component/Notifier/Bridge/Slack/Tests/SlackTransportFactoryTest.php +++ b/src/Symfony/Component/Notifier/Bridge/Slack/Tests/SlackTransportFactoryTest.php @@ -22,44 +22,55 @@ final class SlackTransportFactoryTest extends TestCase { public function testCreateWithDsn() { - $factory = new SlackTransportFactory(); + $factory = $this->createFactory(); - $transport = $factory->create(Dsn::fromString('slack://testUser@testHost/?channel=testChannel')); + $transport = $factory->create(Dsn::fromString('slack://testUser@host.test/?channel=testChannel')); - $this->assertSame('slack://testHost?channel=testChannel', (string) $transport); + $this->assertSame('slack://host.test?channel=testChannel', (string) $transport); } public function testCreateWithDeprecatedDsn() { + $factory = $this->createFactory(); + $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessage('Support for Slack webhook DSN has been dropped since 5.2 (maybe you haven\'t updated the DSN when upgrading from 5.1).'); - $factory = new SlackTransportFactory(); $factory->create(Dsn::fromString('slack://default/XXXXXXXXX/XXXXXXXXX/XXXXXXXXXXXXXXXXXXXXXXXX')); } - public function testCreateWithNoTokenThrowsMalformed() + public function testCreateWithNoTokenThrowsInclompleteDsnException() { - $factory = new SlackTransportFactory(); + $factory = $this->createFactory(); $this->expectException(IncompleteDsnException::class); - $factory->create(Dsn::fromString(sprintf('slack://%s/?channel=%s', 'testHost', 'testChannel'))); + $factory->create(Dsn::fromString('slack://host.test?channel=testChannel')); } - public function testSupportsScheme() + public function testSupportsReturnsTrueWithSupportedScheme() { - $factory = new SlackTransportFactory(); + $factory = $this->createFactory(); - $this->assertTrue($factory->supports(Dsn::fromString('slack://host/?channel=testChannel'))); - $this->assertFalse($factory->supports(Dsn::fromString('somethingElse://host/?channel=testChannel'))); + $this->assertTrue($factory->supports(Dsn::fromString('slack://host?channel=testChannel'))); } - public function testNonSlackSchemeThrows() + public function testSupportsReturnsFalseWithUnsupportedScheme() { - $factory = new SlackTransportFactory(); + $factory = $this->createFactory(); + + $this->assertFalse($factory->supports(Dsn::fromString('somethingElse://host?channel=testChannel'))); + } + + public function testUnsupportedSchemeThrowsUnsupportedSchemeException() + { + $factory = $this->createFactory(); $this->expectException(UnsupportedSchemeException::class); + $factory->create(Dsn::fromString('somethingElse://host?channel=testChannel')); + } - $factory->create(Dsn::fromString('somethingElse://user:pwd@host/?channel=testChannel')); + private function createFactory(): SlackTransportFactory + { + return new SlackTransportFactory(); } } diff --git a/src/Symfony/Component/Notifier/Bridge/Slack/Tests/SlackTransportTest.php b/src/Symfony/Component/Notifier/Bridge/Slack/Tests/SlackTransportTest.php index 8f54c3884c8d..defcd0d53597 100644 --- a/src/Symfony/Component/Notifier/Bridge/Slack/Tests/SlackTransportTest.php +++ b/src/Symfony/Component/Notifier/Bridge/Slack/Tests/SlackTransportTest.php @@ -31,9 +31,9 @@ public function testToStringContainsProperties() $channel = 'test Channel'; // invalid channel name to test url encoding of the channel $transport = new SlackTransport('testToken', $channel, $this->createMock(HttpClientInterface::class)); - $transport->setHost('testHost'); + $transport->setHost('host.test'); - $this->assertSame('slack://testHost?channel=test+Channel', (string) $transport); + $this->assertSame('slack://host.test?channel=test+Channel', (string) $transport); } public function testSupportsChatMessage() @@ -46,10 +46,10 @@ public function testSupportsChatMessage() public function testSendNonChatMessageThrowsLogicException() { - $this->expectException(LogicException::class); - $transport = new SlackTransport('testToken', 'testChannel', $this->createMock(HttpClientInterface::class)); + $this->expectException(LogicException::class); + $transport->send($this->createMock(MessageInterface::class)); } diff --git a/src/Symfony/Component/Notifier/Bridge/Smsapi/README.md b/src/Symfony/Component/Notifier/Bridge/Smsapi/README.md index 804ad6c39979..3491517eb6d7 100644 --- a/src/Symfony/Component/Notifier/Bridge/Smsapi/README.md +++ b/src/Symfony/Component/Notifier/Bridge/Smsapi/README.md @@ -1,19 +1,18 @@ SMSAPI Notifier =============== -Provides Smsapi integration for Symfony Notifier. +Provides [Smsapi](https://ssl.smsapi.pl) integration for Symfony Notifier. DSN example ----------- ``` -// .env file SMSAPI_DSN=smsapi://TOKEN@default?from=FROM ``` where: - - `TOKEN` is API Token (OAuth) - - `FROM` is sender name + - `TOKEN` is your API Token (OAuth) + - `FROM` is the sender name See your account info at https://ssl.smsapi.pl/ diff --git a/src/Symfony/Component/Notifier/Bridge/Smsapi/SmsapiTransport.php b/src/Symfony/Component/Notifier/Bridge/Smsapi/SmsapiTransport.php index 83c3b1aaabeb..bab366232bfe 100644 --- a/src/Symfony/Component/Notifier/Bridge/Smsapi/SmsapiTransport.php +++ b/src/Symfony/Component/Notifier/Bridge/Smsapi/SmsapiTransport.php @@ -22,6 +22,7 @@ /** * @author Marcin Szepczynski + * * @experimental in 5.2 */ final class SmsapiTransport extends AbstractTransport diff --git a/src/Symfony/Component/Notifier/Bridge/Smsapi/SmsapiTransportFactory.php b/src/Symfony/Component/Notifier/Bridge/Smsapi/SmsapiTransportFactory.php index a573dbbb133a..cbc31818688f 100644 --- a/src/Symfony/Component/Notifier/Bridge/Smsapi/SmsapiTransportFactory.php +++ b/src/Symfony/Component/Notifier/Bridge/Smsapi/SmsapiTransportFactory.php @@ -11,6 +11,7 @@ namespace Symfony\Component\Notifier\Bridge\Smsapi; +use Symfony\Component\Notifier\Exception\IncompleteDsnException; use Symfony\Component\Notifier\Exception\UnsupportedSchemeException; use Symfony\Component\Notifier\Transport\AbstractTransportFactory; use Symfony\Component\Notifier\Transport\Dsn; @@ -18,6 +19,7 @@ /** * @author Marcin Szepczynski + * * @experimental in 5.2 */ class SmsapiTransportFactory extends AbstractTransportFactory @@ -28,16 +30,22 @@ class SmsapiTransportFactory extends AbstractTransportFactory public function create(Dsn $dsn): TransportInterface { $scheme = $dsn->getScheme(); - $authToken = $dsn->getUser(); - $host = 'default' === $dsn->getHost() ? null : $dsn->getHost(); + + if ('smsapi' !== $scheme) { + throw new UnsupportedSchemeException($dsn, 'smsapi', $this->getSupportedSchemes()); + } + + $authToken = $this->getUser($dsn); $from = $dsn->getOption('from'); - $port = $dsn->getPort(); - if ('smsapi' === $scheme) { - return (new SmsapiTransport($authToken, $from, $this->client, $this->dispatcher))->setHost($host)->setPort($port); + if (!$from) { + throw new IncompleteDsnException('Missing from.', $dsn->getOriginalDsn()); } - throw new UnsupportedSchemeException($dsn, 'smsapi', $this->getSupportedSchemes()); + $host = 'default' === $dsn->getHost() ? null : $dsn->getHost(); + $port = $dsn->getPort(); + + return (new SmsapiTransport($authToken, $from, $this->client, $this->dispatcher))->setHost($host)->setPort($port); } protected function getSupportedSchemes(): array diff --git a/src/Symfony/Component/Notifier/Bridge/Smsapi/Tests/SmsapiTransportFactoryTest.php b/src/Symfony/Component/Notifier/Bridge/Smsapi/Tests/SmsapiTransportFactoryTest.php new file mode 100644 index 000000000000..86c8ee63a551 --- /dev/null +++ b/src/Symfony/Component/Notifier/Bridge/Smsapi/Tests/SmsapiTransportFactoryTest.php @@ -0,0 +1,84 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Notifier\Bridge\Smsapi\Tests; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\Notifier\Bridge\Smsapi\SmsapiTransportFactory; +use Symfony\Component\Notifier\Exception\IncompleteDsnException; +use Symfony\Component\Notifier\Exception\UnsupportedSchemeException; +use Symfony\Component\Notifier\Transport\Dsn; + +final class SmsapiTransportFactoryTest extends TestCase +{ + public function testCreateWithDsn() + { + $factory = $this->createFactory(); + + $transport = $factory->create(Dsn::fromString('smsapi://token@host.test?from=testFrom')); + + $this->assertSame('smsapi://host.test?from=testFrom', (string) $transport); + } + + public function testCreateWithMissingOptionFromThrowsIncompleteDsnException() + { + $factory = $this->createFactory(); + + $this->expectException(IncompleteDsnException::class); + + $factory->create(Dsn::fromString('smsapi://token@host')); + } + + public function testCreateWithNoTokenThrowsIncompleteDsnException() + { + $factory = $this->createFactory(); + + $this->expectException(IncompleteDsnException::class); + $factory->create(Dsn::fromString('smsapi://host.test?from=testFrom')); + } + + public function testSupportsReturnsTrueWithSupportedScheme() + { + $factory = $this->createFactory(); + + $this->assertTrue($factory->supports(Dsn::fromString('smsapi://host?from=testFrom'))); + } + + public function testSupportsReturnsFalseWithUnsupportedScheme() + { + $factory = $this->createFactory(); + + $this->assertFalse($factory->supports(Dsn::fromString('somethingElse://host?from=testFrom'))); + } + + public function testUnsupportedSchemeThrowsUnsupportedSchemeException() + { + $factory = $this->createFactory(); + + $this->expectException(UnsupportedSchemeException::class); + $factory->create(Dsn::fromString('somethingElse://token@host?from=testFrom')); + } + + public function testUnsupportedSchemeThrowsUnsupportedSchemeExceptionEvenIfRequiredOptionIsMissing() + { + $factory = $this->createFactory(); + + $this->expectException(UnsupportedSchemeException::class); + + // unsupported scheme and missing "from" option + $factory->create(Dsn::fromString('somethingElse://token@host')); + } + + private function createFactory(): SmsapiTransportFactory + { + return new SmsapiTransportFactory(); + } +} diff --git a/src/Symfony/Component/Notifier/Bridge/Smsapi/Tests/SmsapiTransportTest.php b/src/Symfony/Component/Notifier/Bridge/Smsapi/Tests/SmsapiTransportTest.php new file mode 100644 index 000000000000..1aed295e3609 --- /dev/null +++ b/src/Symfony/Component/Notifier/Bridge/Smsapi/Tests/SmsapiTransportTest.php @@ -0,0 +1,50 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Notifier\Bridge\Smsapi\Tests; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\Notifier\Bridge\Smsapi\SmsapiTransport; +use Symfony\Component\Notifier\Exception\LogicException; +use Symfony\Component\Notifier\Message\MessageInterface; +use Symfony\Component\Notifier\Message\SmsMessage; +use Symfony\Contracts\HttpClient\HttpClientInterface; + +final class SmsapiTransportTest extends TestCase +{ + public function testToStringContainsProperties() + { + $transport = $this->createTransport(); + + $this->assertSame('smsapi://test.host?from=testFrom', (string) $transport); + } + + public function testSupportsMessageInterface() + { + $transport = $this->createTransport(); + + $this->assertTrue($transport->supports(new SmsMessage('0611223344', 'Hello!'))); + $this->assertFalse($transport->supports($this->createMock(MessageInterface::class))); + } + + public function testSendNonChatMessageThrows() + { + $transport = $this->createTransport(); + + $this->expectException(LogicException::class); + $transport->send($this->createMock(MessageInterface::class)); + } + + private function createTransport(): SmsapiTransport + { + return (new SmsapiTransport('testToken', 'testFrom', $this->createMock(HttpClientInterface::class)))->setHost('test.host'); + } +} diff --git a/src/Symfony/Component/Notifier/Bridge/Smsapi/phpunit.xml.dist b/src/Symfony/Component/Notifier/Bridge/Smsapi/phpunit.xml.dist new file mode 100644 index 000000000000..d6c9a4d78754 --- /dev/null +++ b/src/Symfony/Component/Notifier/Bridge/Smsapi/phpunit.xml.dist @@ -0,0 +1,31 @@ + + + + + + + + + + ./Tests/ + + + + + + ./ + + ./Resources + ./Tests + ./vendor + + + + diff --git a/src/Symfony/Component/Notifier/Bridge/Telegram/TelegramTransport.php b/src/Symfony/Component/Notifier/Bridge/Telegram/TelegramTransport.php index c5f8524c8417..f84000021e69 100644 --- a/src/Symfony/Component/Notifier/Bridge/Telegram/TelegramTransport.php +++ b/src/Symfony/Component/Notifier/Bridge/Telegram/TelegramTransport.php @@ -21,10 +21,9 @@ use Symfony\Contracts\HttpClient\HttpClientInterface; /** - * TelegramTransport. - * * To get the chat id, send a message in Telegram with the user you want - * and then curl 'https://api.telegram.org/bot%token%/getUpdates' | json_pp + * and then execute curl 'https://api.telegram.org/bot%token%/getUpdates' | json_pp + * command. * * @author Fabien Potencier * @@ -96,9 +95,9 @@ protected function doSend(MessageInterface $message): SentMessage $success = $response->toArray(false); - $message = new SentMessage($message, (string) $this); - $message->setMessageId($success['result']['message_id']); + $sentMessage = new SentMessage($message, (string) $this); + $sentMessage->setMessageId($success['result']['message_id']); - return $message; + return $sentMessage; } } diff --git a/src/Symfony/Component/Notifier/Bridge/Telegram/Tests/TelegramTransportFactoryTest.php b/src/Symfony/Component/Notifier/Bridge/Telegram/Tests/TelegramTransportFactoryTest.php index 8d43b1619e20..e8ecfb6cb533 100644 --- a/src/Symfony/Component/Notifier/Bridge/Telegram/Tests/TelegramTransportFactoryTest.php +++ b/src/Symfony/Component/Notifier/Bridge/Telegram/Tests/TelegramTransportFactoryTest.php @@ -33,6 +33,7 @@ public function testCreateWithNoPasswordThrowsIncompleteDsnException() $factory = $this->createFactory(); $this->expectException(IncompleteDsnException::class); + $factory->create(Dsn::fromString('telegram://simpleToken@host.test?channel=testChannel')); } @@ -41,6 +42,7 @@ public function testCreateWithNoTokenThrowsIncompleteDsnException() $factory = $this->createFactory(); $this->expectException(IncompleteDsnException::class); + $factory->create(Dsn::fromString('telegram://host.test?channel=testChannel')); } diff --git a/src/Symfony/Component/Notifier/Bridge/Twilio/Tests/TwilioTransportTest.php b/src/Symfony/Component/Notifier/Bridge/Twilio/Tests/TwilioTransportTest.php index 5520735eca18..f2c4eac8a706 100644 --- a/src/Symfony/Component/Notifier/Bridge/Twilio/Tests/TwilioTransportTest.php +++ b/src/Symfony/Component/Notifier/Bridge/Twilio/Tests/TwilioTransportTest.php @@ -35,7 +35,7 @@ public function testSupportsMessageInterface() $this->assertFalse($transport->supports($this->createMock(MessageInterface::class))); } - public function testSendNonSmsMessageThrowsException() + public function testSendNonSmsMessageThrowsLogicException() { $transport = $this->createTransport(); diff --git a/src/Symfony/Component/Notifier/Bridge/Twilio/TwilioTransport.php b/src/Symfony/Component/Notifier/Bridge/Twilio/TwilioTransport.php index 1c38a8c44744..3f7e73d1367d 100644 --- a/src/Symfony/Component/Notifier/Bridge/Twilio/TwilioTransport.php +++ b/src/Symfony/Component/Notifier/Bridge/Twilio/TwilioTransport.php @@ -76,9 +76,9 @@ protected function doSend(MessageInterface $message): SentMessage $success = $response->toArray(false); - $message = new SentMessage($message, (string) $this); - $message->setMessageId($success['sid']); + $sentMessage = new SentMessage($message, (string) $this); + $sentMessage->setMessageId($success['sid']); - return $message; + return $sentMessage; } } diff --git a/src/Symfony/Component/Notifier/Bridge/Zulip/README.md b/src/Symfony/Component/Notifier/Bridge/Zulip/README.md index 1c5052fee969..a81a4154a56a 100644 --- a/src/Symfony/Component/Notifier/Bridge/Zulip/README.md +++ b/src/Symfony/Component/Notifier/Bridge/Zulip/README.md @@ -1,20 +1,19 @@ Zulip Notifier ============== -Provides Zulip integration for Symfony Notifier. +Provides [Zulip](https://zulip.comw) integration for Symfony Notifier. DSN example ----------- ``` -// .env file -ZULIP_DSN=zulip://EMAIL:TOKEN@default?channel=Channel +ZULIP_DSN=zulip://EMAIL:TOKEN@default?channel=CHANNEL ``` where: - `EMAIL` is your Zulip email - `TOKEN` is your Zulip token - - `Channel` is the channel + - `CHANNEL` is the channel Resources --------- diff --git a/src/Symfony/Component/Notifier/Bridge/Zulip/Tests/ZulipTransportFactoryTest.php b/src/Symfony/Component/Notifier/Bridge/Zulip/Tests/ZulipTransportFactoryTest.php new file mode 100644 index 000000000000..d60c7ad80f77 --- /dev/null +++ b/src/Symfony/Component/Notifier/Bridge/Zulip/Tests/ZulipTransportFactoryTest.php @@ -0,0 +1,84 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Notifier\Bridge\Zulip\Tests; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\Notifier\Bridge\Zulip\ZulipTransportFactory; +use Symfony\Component\Notifier\Exception\IncompleteDsnException; +use Symfony\Component\Notifier\Exception\UnsupportedSchemeException; +use Symfony\Component\Notifier\Transport\Dsn; + +final class ZulipTransportFactoryTest extends TestCase +{ + public function testCreateWithDsn() + { + $factory = $this->createFactory(); + + $transport = $factory->create(Dsn::fromString('zulip://email:token@host.test?channel=testChannel')); + + $this->assertSame('zulip://host.test?channel=testChannel', (string) $transport); + } + + public function testCreateWithMissingOptionChannelThrowsIncompleteDsnException() + { + $factory = $this->createFactory(); + + $this->expectException(IncompleteDsnException::class); + + $factory->create(Dsn::fromString('zulip://email:token@host')); + } + + public function testCreateWithOnlyEmailOrTokenThrowsIncompleteDsnException() + { + $factory = $this->createFactory(); + + $this->expectException(IncompleteDsnException::class); + $factory->create(Dsn::fromString('zulip://testOneOfEmailOrToken@host.test?channel=testChannel')); + } + + public function testSupportsReturnsTrueWithSupportedScheme() + { + $factory = $this->createFactory(); + + $this->assertTrue($factory->supports(Dsn::fromString('zulip://host?channel=testChannel'))); + } + + public function testSupportsReturnsFalseWithUnsupportedScheme() + { + $factory = $this->createFactory(); + + $this->assertFalse($factory->supports(Dsn::fromString('somethingElse://host?channel=testChannel'))); + } + + public function testUnsupportedSchemeThrowsUnsupportedSchemeException() + { + $factory = $this->createFactory(); + + $this->expectException(UnsupportedSchemeException::class); + $factory->create(Dsn::fromString('somethingElse://email:token@host?channel=testChannel')); + } + + public function testUnsupportedSchemeThrowsUnsupportedSchemeExceptionEvenIfRequiredOptionIsMissing() + { + $factory = $this->createFactory(); + + $this->expectException(UnsupportedSchemeException::class); + + // unsupported scheme and missing "channel" option + $factory->create(Dsn::fromString('somethingElse://email:token@host')); + } + + private function createFactory(): ZulipTransportFactory + { + return new ZulipTransportFactory(); + } +} diff --git a/src/Symfony/Component/Notifier/Bridge/Zulip/Tests/ZulipTransportTest.php b/src/Symfony/Component/Notifier/Bridge/Zulip/Tests/ZulipTransportTest.php new file mode 100644 index 000000000000..1af5b06ecab4 --- /dev/null +++ b/src/Symfony/Component/Notifier/Bridge/Zulip/Tests/ZulipTransportTest.php @@ -0,0 +1,50 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Notifier\Bridge\Zulip\Tests; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\Notifier\Bridge\Zulip\ZulipTransport; +use Symfony\Component\Notifier\Exception\LogicException; +use Symfony\Component\Notifier\Message\ChatMessage; +use Symfony\Component\Notifier\Message\MessageInterface; +use Symfony\Contracts\HttpClient\HttpClientInterface; + +final class ZulipTransportTest extends TestCase +{ + public function testToStringContainsProperties() + { + $transport = $this->createTransport(); + + $this->assertSame('zulip://test.host?channel=testChannel', (string) $transport); + } + + public function testSupportsChatMessage() + { + $transport = $this->createTransport(); + + $this->assertTrue($transport->supports(new ChatMessage('testChatMessage'))); + $this->assertFalse($transport->supports($this->createMock(MessageInterface::class))); + } + + public function testSendNonChatMessageThrows() + { + $transport = $this->createTransport(); + + $this->expectException(LogicException::class); + $transport->send($this->createMock(MessageInterface::class)); + } + + private function createTransport(): ZulipTransport + { + return (new ZulipTransport('testEmail', 'testToken', 'testChannel', $this->createMock(HttpClientInterface::class)))->setHost('test.host'); + } +} diff --git a/src/Symfony/Component/Notifier/Bridge/Zulip/ZulipTransport.php b/src/Symfony/Component/Notifier/Bridge/Zulip/ZulipTransport.php index b12581abe72b..297676202c2a 100644 --- a/src/Symfony/Component/Notifier/Bridge/Zulip/ZulipTransport.php +++ b/src/Symfony/Component/Notifier/Bridge/Zulip/ZulipTransport.php @@ -93,9 +93,9 @@ protected function doSend(MessageInterface $message): SentMessage $success = $response->toArray(false); - $message = new SentMessage($message, (string) $this); - $message->setMessageId($success['id']); + $sentMessage = new SentMessage($message, (string) $this); + $sentMessage->setMessageId($success['id']); - return $message; + return $sentMessage; } } diff --git a/src/Symfony/Component/Notifier/Bridge/Zulip/ZulipTransportFactory.php b/src/Symfony/Component/Notifier/Bridge/Zulip/ZulipTransportFactory.php index a624d3f2f7fc..3d2c870cf67c 100644 --- a/src/Symfony/Component/Notifier/Bridge/Zulip/ZulipTransportFactory.php +++ b/src/Symfony/Component/Notifier/Bridge/Zulip/ZulipTransportFactory.php @@ -11,6 +11,7 @@ namespace Symfony\Component\Notifier\Bridge\Zulip; +use Symfony\Component\Notifier\Exception\IncompleteDsnException; use Symfony\Component\Notifier\Exception\UnsupportedSchemeException; use Symfony\Component\Notifier\Transport\AbstractTransportFactory; use Symfony\Component\Notifier\Transport\Dsn; @@ -24,27 +25,30 @@ class ZulipTransportFactory extends AbstractTransportFactory { /** - * {@inheritdoc} + * @return ZulipTransport */ public function create(Dsn $dsn): TransportInterface { $scheme = $dsn->getScheme(); + + if ('zulip' !== $scheme) { + throw new UnsupportedSchemeException($dsn, 'zulip', $this->getSupportedSchemes()); + } + $email = $this->getUser($dsn); $token = $this->getPassword($dsn); $channel = $dsn->getOption('channel'); - $host = $dsn->getHost(); - $port = $dsn->getPort(); - if ('zulip' === $scheme) { - return (new ZulipTransport($email, $token, $channel, $this->client, $this->dispatcher))->setHost($host)->setPort($port); + if (!$channel) { + throw new IncompleteDsnException('Missing channel.', $dsn->getOriginalDsn()); } - throw new UnsupportedSchemeException($dsn, 'zulip', $this->getSupportedSchemes()); + $host = $dsn->getHost(); + $port = $dsn->getPort(); + + return (new ZulipTransport($email, $token, $channel, $this->client, $this->dispatcher))->setHost($host)->setPort($port); } - /** - * {@inheritdoc} - */ protected function getSupportedSchemes(): array { return ['zulip']; diff --git a/src/Symfony/Component/Notifier/Bridge/Zulip/phpunit.xml.dist b/src/Symfony/Component/Notifier/Bridge/Zulip/phpunit.xml.dist new file mode 100644 index 000000000000..88bfdb70204e --- /dev/null +++ b/src/Symfony/Component/Notifier/Bridge/Zulip/phpunit.xml.dist @@ -0,0 +1,31 @@ + + + + + + + + + + ./Tests/ + + + + + + ./ + + ./Resources + ./Tests + ./vendor + + + + pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy