Skip to content

[Notifier] Rework/streamline bridges (5.2) #39428

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Dec 18, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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');

Expand All @@ -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
Expand Down
3 changes: 1 addition & 2 deletions src/Symfony/Component/Notifier/Bridge/Discord/README.md
Original file line number Diff line number Diff line change
@@ -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
```

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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.');
Expand All @@ -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')
Expand All @@ -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');
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,5 +30,4 @@
]
},
"minimum-stability": "dev"

}
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ protected function doSend(MessageInterface $message): SentMessage
'to' => $message->getPhone(),
'body' => $message->getSubject(),
];

if (null !== $this->from) {
$messageData['from'] = $this->from;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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
Expand Down
9 changes: 4 additions & 5 deletions src/Symfony/Component/Notifier/Bridge/Esendex/README.md
Original file line number Diff line number Diff line change
@@ -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

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
<?php

/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* 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();
}
}
Loading