From a5d78787e613b852b7af55d0dcf6915d8ea27705 Mon Sep 17 00:00:00 2001 From: Oskar Stark Date: Thu, 10 Dec 2020 14:26:39 +0100 Subject: [PATCH] [Notifier] Rework/streamline bridges (5.2) --- .../Discord/DiscordTransportFactory.php | 11 +-- .../Notifier/Bridge/Discord/README.md | 3 +- .../Tests/DiscordTransportFactoryTest.php | 54 ++++++++---- .../Discord/Tests/DiscordTransportTest.php | 29 ++++--- .../Notifier/Bridge/Discord/composer.json | 1 - .../Bridge/Esendex/EsendexTransport.php | 1 + .../Esendex/EsendexTransportFactory.php | 22 +++-- .../Notifier/Bridge/Esendex/README.md | 9 +- .../Tests/EsendexTransportFactoryTest.php | 85 +++++++++++++++++++ .../Esendex/Tests/EsendexTransportTest.php | 22 +++-- .../Bridge/Firebase/FirebaseTransport.php | 6 +- .../Firebase/Tests/FirebaseTransportTest.php | 2 +- .../Tests/FreeMobileTransportTest.php | 40 +++++---- .../Bridge/GoogleChat/GoogleChatOptions.php | 1 + .../Bridge/GoogleChat/GoogleChatTransport.php | 1 + .../GoogleChat/GoogleChatTransportFactory.php | 23 +++-- .../Notifier/Bridge/GoogleChat/README.md | 5 +- .../Tests/GoogleChatTransportFactoryTest.php | 36 +++++--- .../Tests/GoogleChatTransportTest.php | 27 +++--- .../Infobip/InfobipTransportFactory.php | 11 +-- .../Notifier/Bridge/Infobip/README.md | 1 - .../Tests/InfobipTransportFactoryTest.php | 48 +++++++---- .../Infobip/Tests/InfobipTransportTest.php | 16 ++-- .../Bridge/LinkedIn/LinkedInTransport.php | 3 +- .../LinkedIn/LinkedInTransportFactory.php | 11 +-- .../Notifier/Bridge/LinkedIn/README.md | 3 +- .../Tests/LinkedInTransportFactoryTest.php | 42 +++++---- .../LinkedIn/Tests/LinkedInTransportTest.php | 71 ++++++++-------- .../Bridge/Mattermost/MattermostTransport.php | 6 +- .../Tests/MattermostTransportFactoryTest.php | 1 + .../Notifier/Bridge/Mobyt/MobytOptions.php | 2 +- .../Notifier/Bridge/Mobyt/MobytTransport.php | 8 +- .../Bridge/Mobyt/MobytTransportFactory.php | 17 ++-- .../Component/Notifier/Bridge/Mobyt/README.md | 3 +- .../Bridge/Mobyt/Tests/MobytOptionsTest.php | 43 +++++----- .../Notifier/Bridge/Nexmo/NexmoTransport.php | 6 +- .../Bridge/Nexmo/Tests/NexmoTransportTest.php | 2 +- .../Bridge/OvhCloud/OvhCloudTransport.php | 6 +- .../OvhCloud/Tests/OvhCloudTransportTest.php | 2 +- .../Bridge/RocketChat/RocketChatTransport.php | 6 +- .../Tests/RocketChatTransportFactoryTest.php | 1 + .../Notifier/Bridge/Sendinblue/README.md | 7 +- .../Bridge/Sendinblue/SendinblueTransport.php | 6 +- .../Sendinblue/SendinblueTransportFactory.php | 19 +++-- .../Tests/SendinblueTransportFactoryTest.php | 59 +++++++++---- .../Tests/SendinblueTransportTest.php | 16 ++-- .../Notifier/Bridge/Sinch/SinchTransport.php | 6 +- .../Bridge/Sinch/Tests/SinchTransportTest.php | 2 +- .../Component/Notifier/Bridge/Slack/README.md | 22 ++--- .../Notifier/Bridge/Slack/SlackTransport.php | 1 + .../Tests/Block/SlackSectionBlockTest.php | 4 +- .../Slack/Tests/SlackTransportFactoryTest.php | 39 ++++++--- .../Bridge/Slack/Tests/SlackTransportTest.php | 8 +- .../Notifier/Bridge/Smsapi/README.md | 7 +- .../Bridge/Smsapi/SmsapiTransport.php | 1 + .../Bridge/Smsapi/SmsapiTransportFactory.php | 20 +++-- .../Tests/SmsapiTransportFactoryTest.php | 84 ++++++++++++++++++ .../Smsapi/Tests/SmsapiTransportTest.php | 50 +++++++++++ .../Notifier/Bridge/Smsapi/phpunit.xml.dist | 31 +++++++ .../Bridge/Telegram/TelegramTransport.php | 11 ++- .../Tests/TelegramTransportFactoryTest.php | 2 + .../Twilio/Tests/TwilioTransportTest.php | 2 +- .../Bridge/Twilio/TwilioTransport.php | 6 +- .../Component/Notifier/Bridge/Zulip/README.md | 7 +- .../Zulip/Tests/ZulipTransportFactoryTest.php | 84 ++++++++++++++++++ .../Bridge/Zulip/Tests/ZulipTransportTest.php | 50 +++++++++++ .../Notifier/Bridge/Zulip/ZulipTransport.php | 6 +- .../Bridge/Zulip/ZulipTransportFactory.php | 22 +++-- .../Notifier/Bridge/Zulip/phpunit.xml.dist | 31 +++++++ 69 files changed, 917 insertions(+), 373 deletions(-) create mode 100644 src/Symfony/Component/Notifier/Bridge/Esendex/Tests/EsendexTransportFactoryTest.php create mode 100644 src/Symfony/Component/Notifier/Bridge/Smsapi/Tests/SmsapiTransportFactoryTest.php create mode 100644 src/Symfony/Component/Notifier/Bridge/Smsapi/Tests/SmsapiTransportTest.php create mode 100644 src/Symfony/Component/Notifier/Bridge/Smsapi/phpunit.xml.dist create mode 100644 src/Symfony/Component/Notifier/Bridge/Zulip/Tests/ZulipTransportFactoryTest.php create mode 100644 src/Symfony/Component/Notifier/Bridge/Zulip/Tests/ZulipTransportTest.php create mode 100644 src/Symfony/Component/Notifier/Bridge/Zulip/phpunit.xml.dist diff --git a/src/Symfony/Component/Notifier/Bridge/Discord/DiscordTransportFactory.php b/src/Symfony/Component/Notifier/Bridge/Discord/DiscordTransportFactory.php index 3a8afa2551a6f..a192832f56552 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 67a176d7e0e65..243904c276520 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 09508b714fadd..40c8f4d4aabd9 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 ead3027580662..9d4d0ba0057b4 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 a47bc90ac9620..934f1f588656b 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 a216a16f98594..812c58906ed7e 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 f526f5a385151..2edf0788b3fbb 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 fd1f142ed76f4..22b93a22ba33a 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 0000000000000..469a23c985367 --- /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 667ed59d6c49d..295b5e6102244 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 1c1684d53a58b..12593b1256730 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 8f377cdd88260..1aea969dd5a9b 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 7f8d648154313..d88cd11eea345 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 a7b2b817716f7..407728ab49223 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 543b2a0a4cb04..fbe933cd56715 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 039b3f5e7a4ff..94cbc786f2532 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 d1d85ebc2dcde..8a4b55c7e8c2f 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 641277a5f2cf0..01a8d263f20e1 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 02f829be672d6..f3d63d65068dd 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 3c8a7968db0c8..6b1d6ca745b66 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 91b3d482bf730..841b659d5fc33 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 1478ebb169d30..a10c3214f4510 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 ce616021ca22b..7c4a9d214359b 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 90304963078a3..1e724846ef705 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 f13afa472301d..d6f1a8523b772 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 907b5cfc8bc0b..29cb85b15baa5 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 c4943464a3a70..51dd961963c2f 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 cbf9a2ba5f3ee..524bc5d8b769a 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 98c43e26e09e5..903f067f43d7c 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 daa774130a1f9..030c53a457301 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 dc45cd780e26a..81b74003702bb 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 1f2a793dfd348..18b37e50065f5 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 d3eda1610f723..ae86675ee681a 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 f992b3e1edd9e..0e556c1047103 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 23f20819c43d7..a56f587324e0f 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 c506d0ab96dac..d0faded96e894 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 6e4c21a28dbc7..384b879c93864 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 ad1757ad51aef..152e371000612 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 e8341582461b7..9b3699f401380 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 ef2f68b0fb4c3..fdf3eafd4a9c9 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 7d7c06e4e1989..937571f44c4e7 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 24016686f9a41..cf9336f454a24 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 889bd1c454cf1..7964d4e20cdfb 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 7f9d1f9b4b78c..daed3ed3d6e61 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 187e1291e443f..a2a1c605ef5ab 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 4528f64ed0ab1..438ba57960bab 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 0810aae702565..10f272db40258 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 7f7ea4208c995..1332e59e95b22 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 4eae10826d8ed..518c843ca2999 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 f4e144b9acf56..6cdfefaddcd15 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 7e1e98981d19d..0a1c097bcf54d 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 9c01d5b386add..8965657f28c64 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 8f54c3884c8d8..defcd0d535971 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 804ad6c399793..3491517eb6d79 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 83c3b1aaabeb6..bab366232bfe3 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 a573dbbb133a2..cbc31818688ff 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 0000000000000..86c8ee63a551d --- /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 0000000000000..1aed295e36095 --- /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 0000000000000..d6c9a4d787544 --- /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 c5f8524c84171..f84000021e69d 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 8d43b1619e200..e8ecfb6cb533f 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 5520735eca18d..f2c4eac8a7063 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 1c38a8c447447..3f7e73d1367da 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 1c5052fee9690..a81a4154a56a0 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 0000000000000..d60c7ad80f77e --- /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 0000000000000..1af5b06ecab4e --- /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 b12581abe72b7..297676202c2ae 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 a624d3f2f7fce..3d2c870cf67cd 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 0000000000000..88bfdb70204ee --- /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