From 695d5ebe8c523875e2f455c0142c4b7e99062391 Mon Sep 17 00:00:00 2001 From: Simon Leblanc Date: Sat, 19 Nov 2022 23:41:33 +0100 Subject: [PATCH] [Notifier] Add iSendPro bridge --- .../FrameworkExtension.php | 2 + .../Resources/config/notifier_transports.php | 5 + .../Notifier/Bridge/Isendpro/.gitattributes | 4 + .../Notifier/Bridge/Isendpro/.gitignore | 3 + .../Notifier/Bridge/Isendpro/CHANGELOG.md | 7 ++ .../Bridge/Isendpro/IsendproTransport.php | 115 ++++++++++++++++++ .../Isendpro/IsendproTransportFactory.php | 40 ++++++ .../Notifier/Bridge/Isendpro/LICENSE | 19 +++ .../Notifier/Bridge/Isendpro/README.md | 27 ++++ .../Tests/IsendproTransportFactoryTest.php | 85 +++++++++++++ .../Isendpro/Tests/IsendproTransportTest.php | 108 ++++++++++++++++ .../Notifier/Bridge/Isendpro/composer.json | 37 ++++++ .../Notifier/Bridge/Isendpro/phpunit.xml.dist | 31 +++++ .../Exception/UnsupportedSchemeException.php | 4 + .../UnsupportedSchemeExceptionTest.php | 3 + src/Symfony/Component/Notifier/Transport.php | 2 + 16 files changed, 492 insertions(+) create mode 100644 src/Symfony/Component/Notifier/Bridge/Isendpro/.gitattributes create mode 100644 src/Symfony/Component/Notifier/Bridge/Isendpro/.gitignore create mode 100644 src/Symfony/Component/Notifier/Bridge/Isendpro/CHANGELOG.md create mode 100644 src/Symfony/Component/Notifier/Bridge/Isendpro/IsendproTransport.php create mode 100644 src/Symfony/Component/Notifier/Bridge/Isendpro/IsendproTransportFactory.php create mode 100644 src/Symfony/Component/Notifier/Bridge/Isendpro/LICENSE create mode 100644 src/Symfony/Component/Notifier/Bridge/Isendpro/README.md create mode 100644 src/Symfony/Component/Notifier/Bridge/Isendpro/Tests/IsendproTransportFactoryTest.php create mode 100644 src/Symfony/Component/Notifier/Bridge/Isendpro/Tests/IsendproTransportTest.php create mode 100644 src/Symfony/Component/Notifier/Bridge/Isendpro/composer.json create mode 100644 src/Symfony/Component/Notifier/Bridge/Isendpro/phpunit.xml.dist diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php index 93d5de007ef9b..6f013e0d70820 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php @@ -144,6 +144,7 @@ use Symfony\Component\Notifier\Bridge\GoogleChat\GoogleChatTransportFactory; use Symfony\Component\Notifier\Bridge\Infobip\InfobipTransportFactory; use Symfony\Component\Notifier\Bridge\Iqsms\IqsmsTransportFactory; +use Symfony\Component\Notifier\Bridge\Isendpro\IsendproTransportFactory; use Symfony\Component\Notifier\Bridge\KazInfoTeh\KazInfoTehTransportFactory; use Symfony\Component\Notifier\Bridge\LightSms\LightSmsTransportFactory; use Symfony\Component\Notifier\Bridge\LinkedIn\LinkedInTransportFactory; @@ -2565,6 +2566,7 @@ private function registerNotifierConfiguration(array $config, ContainerBuilder $ GoogleChatTransportFactory::class => 'notifier.transport_factory.google-chat', InfobipTransportFactory::class => 'notifier.transport_factory.infobip', IqsmsTransportFactory::class => 'notifier.transport_factory.iqsms', + IsendproTransportFactory::class => 'notifier.transport_factory.isendpro', KazInfoTehTransportFactory::class => 'notifier.transport_factory.kaz-info-teh', LightSmsTransportFactory::class => 'notifier.transport_factory.light-sms', LinkedInTransportFactory::class => 'notifier.transport_factory.linked-in', diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/notifier_transports.php b/src/Symfony/Bundle/FrameworkBundle/Resources/config/notifier_transports.php index 237ae18a59eb7..69d0bb01bc7bb 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/notifier_transports.php +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/notifier_transports.php @@ -30,6 +30,7 @@ use Symfony\Component\Notifier\Bridge\GoogleChat\GoogleChatTransportFactory; use Symfony\Component\Notifier\Bridge\Infobip\InfobipTransportFactory; use Symfony\Component\Notifier\Bridge\Iqsms\IqsmsTransportFactory; +use Symfony\Component\Notifier\Bridge\Isendpro\IsendproTransportFactory; use Symfony\Component\Notifier\Bridge\KazInfoTeh\KazInfoTehTransportFactory; use Symfony\Component\Notifier\Bridge\LightSms\LightSmsTransportFactory; use Symfony\Component\Notifier\Bridge\LinkedIn\LinkedInTransportFactory; @@ -149,6 +150,10 @@ ->parent('notifier.transport_factory.abstract') ->tag('texter.transport_factory') + ->set('notifier.transport_factory.isendpro', IsendproTransportFactory::class) + ->parent('notifier.transport_factory.abstract') + ->tag('texter.transport_factory') + ->set('notifier.transport_factory.mobyt', MobytTransportFactory::class) ->parent('notifier.transport_factory.abstract') ->tag('texter.transport_factory') diff --git a/src/Symfony/Component/Notifier/Bridge/Isendpro/.gitattributes b/src/Symfony/Component/Notifier/Bridge/Isendpro/.gitattributes new file mode 100644 index 0000000000000..84c7add058fb5 --- /dev/null +++ b/src/Symfony/Component/Notifier/Bridge/Isendpro/.gitattributes @@ -0,0 +1,4 @@ +/Tests export-ignore +/phpunit.xml.dist export-ignore +/.gitattributes export-ignore +/.gitignore export-ignore diff --git a/src/Symfony/Component/Notifier/Bridge/Isendpro/.gitignore b/src/Symfony/Component/Notifier/Bridge/Isendpro/.gitignore new file mode 100644 index 0000000000000..c49a5d8df5c65 --- /dev/null +++ b/src/Symfony/Component/Notifier/Bridge/Isendpro/.gitignore @@ -0,0 +1,3 @@ +vendor/ +composer.lock +phpunit.xml diff --git a/src/Symfony/Component/Notifier/Bridge/Isendpro/CHANGELOG.md b/src/Symfony/Component/Notifier/Bridge/Isendpro/CHANGELOG.md new file mode 100644 index 0000000000000..1f2c8f86cde72 --- /dev/null +++ b/src/Symfony/Component/Notifier/Bridge/Isendpro/CHANGELOG.md @@ -0,0 +1,7 @@ +CHANGELOG +========= + +6.3 +--- + + * Add the bridge diff --git a/src/Symfony/Component/Notifier/Bridge/Isendpro/IsendproTransport.php b/src/Symfony/Component/Notifier/Bridge/Isendpro/IsendproTransport.php new file mode 100644 index 0000000000000..938c30a2e5562 --- /dev/null +++ b/src/Symfony/Component/Notifier/Bridge/Isendpro/IsendproTransport.php @@ -0,0 +1,115 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Notifier\Bridge\Isendpro; + +use Symfony\Component\Notifier\Exception\TransportException; +use Symfony\Component\Notifier\Exception\UnsupportedMessageTypeException; +use Symfony\Component\Notifier\Message\MessageInterface; +use Symfony\Component\Notifier\Message\SentMessage; +use Symfony\Component\Notifier\Message\SmsMessage; +use Symfony\Component\Notifier\Transport\AbstractTransport; +use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; +use Symfony\Contracts\HttpClient\Exception\DecodingExceptionInterface; +use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface; +use Symfony\Contracts\HttpClient\HttpClientInterface; + +final class IsendproTransport extends AbstractTransport +{ + protected const HOST = 'apirest.isendpro.com'; + + public function __construct( + #[\SensitiveParameter] private string $keyid, + private ?string $from = null, + private bool $noStop = false, + private bool $sandbox = false, + HttpClientInterface $client = null, + EventDispatcherInterface $dispatcher = null + ) { + parent::__construct($client, $dispatcher); + } + + public function __toString(): string + { + if (null === $this->from) { + return sprintf('isendpro://%s?no_stop=%d&sandbox=%d', $this->getEndpoint(), (int) $this->noStop, (int) $this->sandbox); + } + + return sprintf('isendpro://%s?from=%s&no_stop=%d&sandbox=%d', $this->getEndpoint(), $this->from, (int) $this->noStop, (int) $this->sandbox); + } + + public function supports(MessageInterface $message): bool + { + return $message instanceof SmsMessage; + } + + protected function doSend(MessageInterface $message): SentMessage + { + if (!$message instanceof SmsMessage) { + throw new UnsupportedMessageTypeException(__CLASS__, SmsMessage::class, $message); + } + + $messageId = bin2hex(random_bytes(7)); + + $messageData = [ + 'keyid' => $this->keyid, + 'num' => $message->getPhone(), + 'sms' => $message->getSubject(), + 'sandbox' => (int) $this->sandbox, + 'tracker' => $messageId, + ]; + + if ($this->noStop) { + $messageData['nostop'] = '1'; + } + + if ('' !== $message->getFrom()) { + $messageData['emetteur'] = $message->getFrom(); + } elseif (null !== $this->from) { + $messageData['emetteur'] = $this->from; + } + + $response = $this->client->request('POST', 'https://'.$this->getEndpoint().'/cgi-bin/sms', [ + 'headers' => [ + 'Accept' => 'application/json', + 'Cache-Control' => 'no-cache', + ], + 'json' => $messageData, + ]); + + try { + $statusCode = $response->getStatusCode(); + $result = $response->toArray(false); + $details = $result['etat']['etat'][0] ?? []; + $detailsCode = (int) ($details['code'] ?? -1); // -1 is not a valid error code on iSendPro. But if code doesn't exist, it's a very strange error (not possible normally) + + if (200 === $statusCode && 0 === $detailsCode) { + $sentMessage = new SentMessage($message, (string) $this); + $sentMessage->setMessageId($messageId); + + return $sentMessage; + } + + $errorMessage = sprintf('Unable to send the SMS: error %d.', $statusCode); + $detailsMessage = $details['message'] ?? null; + + if ($detailsMessage) { + $errorMessage .= sprintf(' Details from iSendPro: %s: "%s".', $detailsCode, $detailsMessage); + } + } catch (TransportExceptionInterface $e) { + throw new TransportException('Could not reach the remote iSendPro server.', $response, 0, $e); + } catch (DecodingExceptionInterface $e) { + $errorMessage = sprintf('Unable to send the SMS: error %d. %s', $statusCode, $e->getMessage()); + } + + throw new TransportException($errorMessage, $response); + } +} diff --git a/src/Symfony/Component/Notifier/Bridge/Isendpro/IsendproTransportFactory.php b/src/Symfony/Component/Notifier/Bridge/Isendpro/IsendproTransportFactory.php new file mode 100644 index 0000000000000..c91583c17e4d5 --- /dev/null +++ b/src/Symfony/Component/Notifier/Bridge/Isendpro/IsendproTransportFactory.php @@ -0,0 +1,40 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Notifier\Bridge\Isendpro; + +use Symfony\Component\Notifier\Exception\UnsupportedSchemeException; +use Symfony\Component\Notifier\Transport\AbstractTransportFactory; +use Symfony\Component\Notifier\Transport\Dsn; + +final class IsendproTransportFactory extends AbstractTransportFactory +{ + public function create(Dsn $dsn): IsendproTransport + { + if ('isendpro' !== $dsn->getScheme()) { + throw new UnsupportedSchemeException($dsn, 'isendpro', $this->getSupportedSchemes()); + } + + $keyid = $this->getUser($dsn); + $from = $dsn->getOption('from', null); + $noStop = filter_var($dsn->getOption('no_stop', false), \FILTER_VALIDATE_BOOLEAN); + $sandbox = filter_var($dsn->getOption('sandbox', false), \FILTER_VALIDATE_BOOLEAN); + $host = 'default' === $dsn->getHost() ? null : $dsn->getHost(); + $port = $dsn->getPort(); + + return (new IsendproTransport($keyid, $from, $noStop, $sandbox, $this->client, $this->dispatcher))->setHost($host)->setPort($port); + } + + protected function getSupportedSchemes(): array + { + return ['isendpro']; + } +} diff --git a/src/Symfony/Component/Notifier/Bridge/Isendpro/LICENSE b/src/Symfony/Component/Notifier/Bridge/Isendpro/LICENSE new file mode 100644 index 0000000000000..0ece8964f767d --- /dev/null +++ b/src/Symfony/Component/Notifier/Bridge/Isendpro/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2022 Fabien Potencier + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/src/Symfony/Component/Notifier/Bridge/Isendpro/README.md b/src/Symfony/Component/Notifier/Bridge/Isendpro/README.md new file mode 100644 index 0000000000000..6cf8368a90362 --- /dev/null +++ b/src/Symfony/Component/Notifier/Bridge/Isendpro/README.md @@ -0,0 +1,27 @@ +iSendPro Notifier +================= + +Provides [iSendPro](https://www.isendpro.com/) integration for Symfony Notifier. + +DSN example +----------- + +``` +ISENDPRO_DSN=isendpro://ACCOUNT_KEY_ID@default?from=FROM&no_stop=NO_STOP&sandbox=SANDBOX +``` + +where: + - `ACCOUNT_KEY_ID` is your iSendPro API Key ID + - `FROM` is the alphanumeric originator for the message to appear to originate from (optional) + - `NO_STOP` setting this parameter to "1" (default "0") allows removing "STOP clause" at the end of the message for non-commercial use (optional) + - `SANDBOX` setting this parameter to "1" (default "0") allows to use the notifier in sandbox mode (optional) + +See iSendPro documentation at https://www.isendpro.com/docs/#prerequis + +Resources +--------- + + * [Contributing](https://symfony.com/doc/current/contributing/index.html) + * [Report issues](https://github.com/symfony/symfony/issues) and + [send Pull Requests](https://github.com/symfony/symfony/pulls) + in the [main Symfony repository](https://github.com/symfony/symfony) diff --git a/src/Symfony/Component/Notifier/Bridge/Isendpro/Tests/IsendproTransportFactoryTest.php b/src/Symfony/Component/Notifier/Bridge/Isendpro/Tests/IsendproTransportFactoryTest.php new file mode 100644 index 0000000000000..ceda78493ccd0 --- /dev/null +++ b/src/Symfony/Component/Notifier/Bridge/Isendpro/Tests/IsendproTransportFactoryTest.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\Isendpro\Tests; + +use Symfony\Component\Notifier\Bridge\Isendpro\IsendproTransportFactory; +use Symfony\Component\Notifier\Test\TransportFactoryTestCase; + +final class IsendproTransportFactoryTest extends TransportFactoryTestCase +{ + public function createFactory(): IsendproTransportFactory + { + return new IsendproTransportFactory(); + } + + public function createProvider(): iterable + { + yield [ + 'isendpro://host.test?no_stop=0&sandbox=0', + 'isendpro://account_key_id@host.test', + ]; + + yield [ + 'isendpro://host.test?from=FROM&no_stop=0&sandbox=0', + 'isendpro://account_key_id@host.test?from=FROM', + ]; + + yield [ + 'isendpro://host.test?from=FROM&no_stop=0&sandbox=0', + 'isendpro://account_key_id@host.test?from=FROM&no_stop=0&sandbox=0', + ]; + + yield [ + 'isendpro://host.test?from=FROM&no_stop=0&sandbox=0', + 'isendpro://account_key_id@host.test?from=FROM&no_stop=false&sandbox=0', + ]; + + yield [ + 'isendpro://host.test?from=FROM&no_stop=1&sandbox=0', + 'isendpro://account_key_id@host.test?from=FROM&no_stop=1&sandbox=0', + ]; + + yield [ + 'isendpro://host.test?from=FROM&no_stop=1&sandbox=1', + 'isendpro://account_key_id@host.test?from=FROM&no_stop=1&sandbox=true', + ]; + } + + public function supportsProvider(): iterable + { + yield [true, 'isendpro://account_key_id@host?from=FROM']; + yield [false, 'somethingElse://account_key_id@default']; + } + + public function incompleteDsnProvider(): iterable + { + yield 'missing credentials' => ['isendpro://host?from=FROM']; + } + + public function missingRequiredOptionProvider(): iterable + { + yield 'missing option: account_key_id' => ['isendpro://default']; + } + + public function unsupportedSchemeProvider(): iterable + { + yield ['somethingElse://account_key_id@default']; + } + + /** + * @dataProvider missingRequiredOptionProvider + */ + public function testMissingRequiredOptionException(string $dsn, string $message = null) + { + $this->markTestIncomplete('The only required option is account key id, matched by incompleteDsnProvider'); + } +} diff --git a/src/Symfony/Component/Notifier/Bridge/Isendpro/Tests/IsendproTransportTest.php b/src/Symfony/Component/Notifier/Bridge/Isendpro/Tests/IsendproTransportTest.php new file mode 100644 index 0000000000000..bcafe34c5a263 --- /dev/null +++ b/src/Symfony/Component/Notifier/Bridge/Isendpro/Tests/IsendproTransportTest.php @@ -0,0 +1,108 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Notifier\Bridge\Isendpro\Tests; + +use Symfony\Component\HttpClient\MockHttpClient; +use Symfony\Component\Notifier\Bridge\Isendpro\IsendproTransport; +use Symfony\Component\Notifier\Exception\TransportException; +use Symfony\Component\Notifier\Message\ChatMessage; +use Symfony\Component\Notifier\Message\MessageInterface; +use Symfony\Component\Notifier\Message\SmsMessage; +use Symfony\Component\Notifier\Test\TransportTestCase; +use Symfony\Contracts\HttpClient\HttpClientInterface; +use Symfony\Contracts\HttpClient\ResponseInterface; + +final class IsendproTransportTest extends TransportTestCase +{ + public function createTransport(HttpClientInterface $client = null): IsendproTransport + { + return (new IsendproTransport('accound_key_id', null, false, false, $client ?? $this->createMock(HttpClientInterface::class)))->setHost('host.test'); + } + + public function toStringProvider(): iterable + { + yield ['isendpro://host.test?no_stop=0&sandbox=0', $this->createTransport()]; + } + + public function supportedMessagesProvider(): iterable + { + yield [new SmsMessage('0611223344', 'Hello!')]; + } + + public function unsupportedMessagesProvider(): iterable + { + yield [new ChatMessage('Hello!')]; + yield [$this->createMock(MessageInterface::class)]; + } + + public function testSendWithErrorResponseThrowsTransportException() + { + $response = $this->createMock(ResponseInterface::class); + $response->expects($this->exactly(2)) + ->method('getStatusCode') + ->willReturn(500); + + $client = new MockHttpClient(static function () use ($response): ResponseInterface { + return $response; + }); + + $transport = $this->createTransport($client); + + $this->expectException(TransportException::class); + $this->expectExceptionMessage('Unable to send the SMS: error 500.'); + + $transport->send(new SmsMessage('phone', 'testMessage')); + } + + public function testSendWithErrorResponseContainingDetailsThrowsTransportException() + { + $response = $this->createMock(ResponseInterface::class); + $response->expects($this->exactly(2)) + ->method('getStatusCode') + ->willReturn(400); + $response->expects($this->once()) + ->method('getContent') + ->willReturn(json_encode(['etat' => ['etat' => [['code' => '3', 'message' => 'Your credentials are incorrect']]]])); + + $client = new MockHttpClient(static function () use ($response): ResponseInterface { + return $response; + }); + + $transport = $this->createTransport($client); + + $this->expectException(TransportException::class); + $this->expectExceptionMessage('Unable to send the SMS: error 400. Details from iSendPro: 3: "Your credentials are incorrect".'); + + $transport->send(new SmsMessage('phone', 'testMessage')); + } + + public function testSendWithSuccessfulResponseDispatchesMessageEvent() + { + $response = $this->createMock(ResponseInterface::class); + $response->expects($this->exactly(2)) + ->method('getStatusCode') + ->willReturn(200); + $response->expects($this->once()) + ->method('getContent') + ->willReturn(json_encode(['etat' => ['etat' => [['code' => 0]]]])); + + $client = new MockHttpClient(static function () use ($response): ResponseInterface { + return $response; + }); + + $transport = $this->createTransport($client); + + $sentMessage = $transport->send(new SmsMessage('phone', 'testMessage')); + + $this->assertNotNull($sentMessage->getMessageId()); + } +} diff --git a/src/Symfony/Component/Notifier/Bridge/Isendpro/composer.json b/src/Symfony/Component/Notifier/Bridge/Isendpro/composer.json new file mode 100644 index 0000000000000..77b078b6dcee1 --- /dev/null +++ b/src/Symfony/Component/Notifier/Bridge/Isendpro/composer.json @@ -0,0 +1,37 @@ +{ + "name": "symfony/isendpro-notifier", + "type": "symfony-notifier-bridge", + "description": "Symfony iSendPro Notifier Bridge", + "keywords": ["sms", "isendpro", "notifier"], + "homepage": "https://symfony.com", + "license": "MIT", + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Simon Leblanc", + "email": "contact@leblanc-simon.eu" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "require": { + "php": ">=8.1", + "symfony/http-client": "^5.4|^6.0", + "symfony/notifier": "^6.3" + }, + "require-dev": { + "symfony/event-dispatcher": "^5.4|^6.0" + }, + "autoload": { + "psr-4": { "Symfony\\Component\\Notifier\\Bridge\\Isendpro\\": "" }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "minimum-stability": "dev" +} diff --git a/src/Symfony/Component/Notifier/Bridge/Isendpro/phpunit.xml.dist b/src/Symfony/Component/Notifier/Bridge/Isendpro/phpunit.xml.dist new file mode 100644 index 0000000000000..11bcba3a27793 --- /dev/null +++ b/src/Symfony/Component/Notifier/Bridge/Isendpro/phpunit.xml.dist @@ -0,0 +1,31 @@ + + + + + + + + + + ./Tests/ + + + + + + ./ + + + ./Resources + ./Tests + ./vendor + + + diff --git a/src/Symfony/Component/Notifier/Exception/UnsupportedSchemeException.php b/src/Symfony/Component/Notifier/Exception/UnsupportedSchemeException.php index f5b51bf9bfaaf..24232be0062a1 100644 --- a/src/Symfony/Component/Notifier/Exception/UnsupportedSchemeException.php +++ b/src/Symfony/Component/Notifier/Exception/UnsupportedSchemeException.php @@ -88,6 +88,10 @@ class UnsupportedSchemeException extends LogicException 'class' => Bridge\Iqsms\IqsmsTransportFactory::class, 'package' => 'symfony/iqsms-notifier', ], + 'isendpro' => [ + 'class' => Bridge\Isendpro\IsendproTransportFactory::class, + 'package' => 'symfony/isendpro-notifier', + ], 'lightsms' => [ 'class' => Bridge\LightSms\LightSmsTransportFactory::class, 'package' => 'symfony/light-sms-notifier', diff --git a/src/Symfony/Component/Notifier/Tests/Exception/UnsupportedSchemeExceptionTest.php b/src/Symfony/Component/Notifier/Tests/Exception/UnsupportedSchemeExceptionTest.php index 8ffb0c1f79c4c..fdf37912231fa 100644 --- a/src/Symfony/Component/Notifier/Tests/Exception/UnsupportedSchemeExceptionTest.php +++ b/src/Symfony/Component/Notifier/Tests/Exception/UnsupportedSchemeExceptionTest.php @@ -29,6 +29,7 @@ use Symfony\Component\Notifier\Bridge\GoogleChat\GoogleChatTransportFactory; use Symfony\Component\Notifier\Bridge\Infobip\InfobipTransportFactory; use Symfony\Component\Notifier\Bridge\Iqsms\IqsmsTransportFactory; +use Symfony\Component\Notifier\Bridge\Isendpro\IsendproTransportFactory; use Symfony\Component\Notifier\Bridge\LightSms\LightSmsTransportFactory; use Symfony\Component\Notifier\Bridge\LinkedIn\LinkedInTransportFactory; use Symfony\Component\Notifier\Bridge\Mailjet\MailjetTransportFactory; @@ -88,6 +89,7 @@ public static function setUpBeforeClass(): void GoogleChatTransportFactory::class => false, InfobipTransportFactory::class => false, IqsmsTransportFactory::class => false, + IsendproTransportFactory::class => false, LightSmsTransportFactory::class => false, LinkedInTransportFactory::class => false, MailjetTransportFactory::class => false, @@ -152,6 +154,7 @@ public function messageWhereSchemeIsPartOfSchemeToPackageMapProvider(): \Generat yield ['googlechat', 'symfony/google-chat-notifier']; yield ['infobip', 'symfony/infobip-notifier']; yield ['iqsms', 'symfony/iqsms-notifier']; + yield ['isendpro', 'symfony/isendpro-notifier']; yield ['lightsms', 'symfony/light-sms-notifier']; yield ['linkedin', 'symfony/linked-in-notifier']; yield ['mailjet', 'symfony/mailjet-notifier']; diff --git a/src/Symfony/Component/Notifier/Transport.php b/src/Symfony/Component/Notifier/Transport.php index b9829b8ebdf68..c46bcc59bf2f3 100644 --- a/src/Symfony/Component/Notifier/Transport.php +++ b/src/Symfony/Component/Notifier/Transport.php @@ -27,6 +27,7 @@ use Symfony\Component\Notifier\Bridge\Gitter\GitterTransportFactory; use Symfony\Component\Notifier\Bridge\Infobip\InfobipTransportFactory; use Symfony\Component\Notifier\Bridge\Iqsms\IqsmsTransportFactory; +use Symfony\Component\Notifier\Bridge\Isendpro\IsendproTransportFactory; use Symfony\Component\Notifier\Bridge\LightSms\LightSmsTransportFactory; use Symfony\Component\Notifier\Bridge\Mailjet\MailjetTransportFactory; use Symfony\Component\Notifier\Bridge\Mattermost\MattermostTransportFactory; @@ -88,6 +89,7 @@ final class Transport GitterTransportFactory::class, InfobipTransportFactory::class, IqsmsTransportFactory::class, + IsendproTransportFactory::class, LightSmsTransportFactory::class, MailjetTransportFactory::class, MattermostTransportFactory::class,