[Notifier] [DX] Dsn::getRequiredOption()

This commit is contained in:
Oskar Stark 2020-12-11 11:59:39 +01:00 committed by Fabien Potencier
parent 9e47d90019
commit 3f095bf419
33 changed files with 164 additions and 130 deletions

View File

@ -11,7 +11,6 @@
namespace Symfony\Component\Notifier\Bridge\Discord; namespace Symfony\Component\Notifier\Bridge\Discord;
use Symfony\Component\Notifier\Exception\IncompleteDsnException;
use Symfony\Component\Notifier\Exception\UnsupportedSchemeException; use Symfony\Component\Notifier\Exception\UnsupportedSchemeException;
use Symfony\Component\Notifier\Transport\AbstractTransportFactory; use Symfony\Component\Notifier\Transport\AbstractTransportFactory;
use Symfony\Component\Notifier\Transport\Dsn; use Symfony\Component\Notifier\Transport\Dsn;
@ -34,12 +33,7 @@ final class DiscordTransportFactory extends AbstractTransportFactory
} }
$token = $this->getUser($dsn); $token = $this->getUser($dsn);
$webhookId = $dsn->getOption('webhook_id'); $webhookId = $dsn->getRequiredOption('webhook_id');
if (!$webhookId) {
throw new IncompleteDsnException('Missing webhook_id.', $dsn->getOriginalDsn());
}
$host = 'default' === $dsn->getHost() ? null : $dsn->getHost(); $host = 'default' === $dsn->getHost() ? null : $dsn->getHost();
$port = $dsn->getPort(); $port = $dsn->getPort();

View File

@ -14,6 +14,7 @@ namespace Symfony\Component\Notifier\Bridge\Discord\Tests;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use Symfony\Component\Notifier\Bridge\Discord\DiscordTransportFactory; use Symfony\Component\Notifier\Bridge\Discord\DiscordTransportFactory;
use Symfony\Component\Notifier\Exception\IncompleteDsnException; use Symfony\Component\Notifier\Exception\IncompleteDsnException;
use Symfony\Component\Notifier\Exception\MissingRequiredOptionException;
use Symfony\Component\Notifier\Exception\UnsupportedSchemeException; use Symfony\Component\Notifier\Exception\UnsupportedSchemeException;
use Symfony\Component\Notifier\Transport\Dsn; use Symfony\Component\Notifier\Transport\Dsn;
@ -28,11 +29,11 @@ final class DiscordTransportFactoryTest extends TestCase
$this->assertSame('discord://host.test?webhook_id=testWebhookId', (string) $transport); $this->assertSame('discord://host.test?webhook_id=testWebhookId', (string) $transport);
} }
public function testCreateWithMissingOptionWebhookIdThrowsIncompleteDsnException() public function testCreateWithMissingOptionWebhookIdThrowsMissingRequiredOptionException()
{ {
$factory = $this->createFactory(); $factory = $this->createFactory();
$this->expectException(IncompleteDsnException::class); $this->expectException(MissingRequiredOptionException::class);
$factory->create(Dsn::fromString('discord://token@host')); $factory->create(Dsn::fromString('discord://token@host'));
} }

View File

@ -11,7 +11,6 @@
namespace Symfony\Component\Notifier\Bridge\Esendex; namespace Symfony\Component\Notifier\Bridge\Esendex;
use Symfony\Component\Notifier\Exception\IncompleteDsnException;
use Symfony\Component\Notifier\Exception\UnsupportedSchemeException; use Symfony\Component\Notifier\Exception\UnsupportedSchemeException;
use Symfony\Component\Notifier\Transport\AbstractTransportFactory; use Symfony\Component\Notifier\Transport\AbstractTransportFactory;
use Symfony\Component\Notifier\Transport\Dsn; use Symfony\Component\Notifier\Transport\Dsn;
@ -32,18 +31,8 @@ final class EsendexTransportFactory extends AbstractTransportFactory
$email = $this->getUser($dsn); $email = $this->getUser($dsn);
$password = $this->getPassword($dsn); $password = $this->getPassword($dsn);
$accountReference = $dsn->getOption('accountreference'); $accountReference = $dsn->getRequiredOption('accountreference');
$from = $dsn->getRequiredOption('from');
if (!$accountReference) {
throw new IncompleteDsnException('Missing accountreference.', $dsn->getOriginalDsn());
}
$from = $dsn->getOption('from');
if (!$from) {
throw new IncompleteDsnException('Missing from.', $dsn->getOriginalDsn());
}
$host = 'default' === $dsn->getHost() ? null : $dsn->getHost(); $host = 'default' === $dsn->getHost() ? null : $dsn->getHost();
$port = $dsn->getPort(); $port = $dsn->getPort();

View File

@ -14,6 +14,7 @@ namespace Symfony\Component\Notifier\Bridge\Esendex\Tests;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use Symfony\Component\Notifier\Bridge\Esendex\EsendexTransportFactory; use Symfony\Component\Notifier\Bridge\Esendex\EsendexTransportFactory;
use Symfony\Component\Notifier\Exception\IncompleteDsnException; use Symfony\Component\Notifier\Exception\IncompleteDsnException;
use Symfony\Component\Notifier\Exception\MissingRequiredOptionException;
use Symfony\Component\Notifier\Exception\UnsupportedSchemeException; use Symfony\Component\Notifier\Exception\UnsupportedSchemeException;
use Symfony\Component\Notifier\Transport\Dsn; use Symfony\Component\Notifier\Transport\Dsn;
@ -46,20 +47,20 @@ final class EsendexTransportFactoryTest extends TestCase
$factory->create(Dsn::fromString('esendex://email:@host?accountreference=testAccountreference&from=FROM')); $factory->create(Dsn::fromString('esendex://email:@host?accountreference=testAccountreference&from=FROM'));
} }
public function testCreateWithMissingOptionAccountreferenceThrowsIncompleteDsnException() public function testCreateWithMissingOptionAccountreferenceThrowsMissingRequiredOptionException()
{ {
$factory = $this->createFactory(); $factory = $this->createFactory();
$this->expectException(IncompleteDsnException::class); $this->expectException(MissingRequiredOptionException::class);
$factory->create(Dsn::fromString('esendex://email:password@host?from=FROM')); $factory->create(Dsn::fromString('esendex://email:password@host?from=FROM'));
} }
public function testCreateWithMissingOptionFromThrowsIncompleteDsnException() public function testCreateWithMissingOptionFromThrowsMissingRequiredOptionException()
{ {
$factory = $this->createFactory(); $factory = $this->createFactory();
$this->expectException(IncompleteDsnException::class); $this->expectException(MissingRequiredOptionException::class);
$factory->create(Dsn::fromString('esendex://email:password@host?accountreference=ACCOUNTREFERENCE')); $factory->create(Dsn::fromString('esendex://email:password@host?accountreference=ACCOUNTREFERENCE'));
} }

View File

@ -11,7 +11,6 @@
namespace Symfony\Component\Notifier\Bridge\FreeMobile; namespace Symfony\Component\Notifier\Bridge\FreeMobile;
use Symfony\Component\Notifier\Exception\IncompleteDsnException;
use Symfony\Component\Notifier\Exception\UnsupportedSchemeException; use Symfony\Component\Notifier\Exception\UnsupportedSchemeException;
use Symfony\Component\Notifier\Transport\AbstractTransportFactory; use Symfony\Component\Notifier\Transport\AbstractTransportFactory;
use Symfony\Component\Notifier\Transport\Dsn; use Symfony\Component\Notifier\Transport\Dsn;
@ -35,11 +34,7 @@ final class FreeMobileTransportFactory extends AbstractTransportFactory
$login = $this->getUser($dsn); $login = $this->getUser($dsn);
$password = $this->getPassword($dsn); $password = $this->getPassword($dsn);
$phone = $dsn->getOption('phone'); $phone = $dsn->getRequiredOption('phone');
if (!$phone) {
throw new IncompleteDsnException('Missing phone.', $dsn->getOriginalDsn());
}
$host = 'default' === $dsn->getHost() ? null : $dsn->getHost(); $host = 'default' === $dsn->getHost() ? null : $dsn->getHost();
$port = $dsn->getPort(); $port = $dsn->getPort();

View File

@ -39,7 +39,7 @@ final class FreeMobileTransportFactoryTest extends TransportFactoryTestCase
yield [false, 'somethingElse://login:pass@default?phone=0611223344']; yield [false, 'somethingElse://login:pass@default?phone=0611223344'];
} }
public function incompleteDsnProvider(): iterable public function missingRequiredOptionProvider(): iterable
{ {
yield 'missing option: phone' => ['freemobile://login:pass@default']; yield 'missing option: phone' => ['freemobile://login:pass@default'];
} }

View File

@ -11,7 +11,6 @@
namespace Symfony\Component\Notifier\Bridge\Infobip; namespace Symfony\Component\Notifier\Bridge\Infobip;
use Symfony\Component\Notifier\Exception\IncompleteDsnException;
use Symfony\Component\Notifier\Exception\UnsupportedSchemeException; use Symfony\Component\Notifier\Exception\UnsupportedSchemeException;
use Symfony\Component\Notifier\Transport\AbstractTransportFactory; use Symfony\Component\Notifier\Transport\AbstractTransportFactory;
use Symfony\Component\Notifier\Transport\Dsn; use Symfony\Component\Notifier\Transport\Dsn;
@ -35,14 +34,10 @@ final class InfobipTransportFactory extends AbstractTransportFactory
} }
$authToken = $this->getUser($dsn); $authToken = $this->getUser($dsn);
$from = $dsn->getOption('from'); $from = $dsn->getRequiredOption('from');
$host = $dsn->getHost(); $host = $dsn->getHost();
$port = $dsn->getPort(); $port = $dsn->getPort();
if (!$from) {
throw new IncompleteDsnException('Missing from.', $dsn->getOriginalDsn());
}
return (new InfobipTransport($authToken, $from, $this->client, $this->dispatcher))->setHost($host)->setPort($port); return (new InfobipTransport($authToken, $from, $this->client, $this->dispatcher))->setHost($host)->setPort($port);
} }

View File

@ -13,7 +13,7 @@ namespace Symfony\Component\Notifier\Bridge\Infobip\Tests;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use Symfony\Component\Notifier\Bridge\Infobip\InfobipTransportFactory; use Symfony\Component\Notifier\Bridge\Infobip\InfobipTransportFactory;
use Symfony\Component\Notifier\Exception\IncompleteDsnException; use Symfony\Component\Notifier\Exception\MissingRequiredOptionException;
use Symfony\Component\Notifier\Exception\UnsupportedSchemeException; use Symfony\Component\Notifier\Exception\UnsupportedSchemeException;
use Symfony\Component\Notifier\Transport\Dsn; use Symfony\Component\Notifier\Transport\Dsn;
@ -28,11 +28,11 @@ final class InfobipTransportFactoryTest extends TestCase
$this->assertSame('infobip://host.test?from=0611223344', (string) $transport); $this->assertSame('infobip://host.test?from=0611223344', (string) $transport);
} }
public function testCreateWithNoFromThrowsIncompleteDsnException() public function testCreateWithNoFromThrowsMissingRequiredOptionException()
{ {
$factory = $this->createFactory(); $factory = $this->createFactory();
$this->expectException(IncompleteDsnException::class); $this->expectException(MissingRequiredOptionException::class);
$factory->create(Dsn::fromString('infobip://authtoken@default')); $factory->create(Dsn::fromString('infobip://authtoken@default'));
} }

View File

@ -11,7 +11,6 @@
namespace Symfony\Component\Notifier\Bridge\Iqsms; namespace Symfony\Component\Notifier\Bridge\Iqsms;
use Symfony\Component\Notifier\Exception\IncompleteDsnException;
use Symfony\Component\Notifier\Exception\UnsupportedSchemeException; use Symfony\Component\Notifier\Exception\UnsupportedSchemeException;
use Symfony\Component\Notifier\Transport\AbstractTransportFactory; use Symfony\Component\Notifier\Transport\AbstractTransportFactory;
use Symfony\Component\Notifier\Transport\Dsn; use Symfony\Component\Notifier\Transport\Dsn;
@ -35,12 +34,7 @@ final class IqsmsTransportFactory extends AbstractTransportFactory
$login = $this->getUser($dsn); $login = $this->getUser($dsn);
$password = $this->getPassword($dsn); $password = $this->getPassword($dsn);
$from = $dsn->getOption('from'); $from = $dsn->getRequiredOption('from');
if (!$from) {
throw new IncompleteDsnException('Missing from.', $dsn->getOriginalDsn());
}
$host = 'default' === $dsn->getHost() ? null : $dsn->getHost(); $host = 'default' === $dsn->getHost() ? null : $dsn->getHost();
$port = $dsn->getPort(); $port = $dsn->getPort();

View File

@ -11,7 +11,6 @@
namespace Symfony\Component\Notifier\Bridge\Mattermost; namespace Symfony\Component\Notifier\Bridge\Mattermost;
use Symfony\Component\Notifier\Exception\IncompleteDsnException;
use Symfony\Component\Notifier\Exception\UnsupportedSchemeException; use Symfony\Component\Notifier\Exception\UnsupportedSchemeException;
use Symfony\Component\Notifier\Transport\AbstractTransportFactory; use Symfony\Component\Notifier\Transport\AbstractTransportFactory;
use Symfony\Component\Notifier\Transport\Dsn; use Symfony\Component\Notifier\Transport\Dsn;
@ -32,12 +31,7 @@ final class MattermostTransportFactory extends AbstractTransportFactory
$path = $dsn->getPath(); $path = $dsn->getPath();
$token = $this->getUser($dsn); $token = $this->getUser($dsn);
$channel = $dsn->getOption('channel'); $channel = $dsn->getRequiredOption('channel');
if (!$channel) {
throw new IncompleteDsnException('Missing channel.', $dsn->getOriginalDsn());
}
$host = $dsn->getHost(); $host = $dsn->getHost();
$port = $dsn->getPort(); $port = $dsn->getPort();

View File

@ -59,7 +59,11 @@ final class MattermostTransportFactoryTest extends TransportFactoryTestCase
public function incompleteDsnProvider(): iterable public function incompleteDsnProvider(): iterable
{ {
yield 'missing option: token' => ['mattermost://host.test?channel=testChannel']; yield 'missing token' => ['mattermost://host.test?channel=testChannel'];
}
public function missingRequiredOptionProvider(): iterable
{
yield 'missing option: channel' => ['mattermost://token@host']; yield 'missing option: channel' => ['mattermost://token@host'];
} }

View File

@ -11,7 +11,6 @@
namespace Symfony\Component\Notifier\Bridge\Mobyt; namespace Symfony\Component\Notifier\Bridge\Mobyt;
use Symfony\Component\Notifier\Exception\IncompleteDsnException;
use Symfony\Component\Notifier\Exception\UnsupportedSchemeException; use Symfony\Component\Notifier\Exception\UnsupportedSchemeException;
use Symfony\Component\Notifier\Transport\AbstractTransportFactory; use Symfony\Component\Notifier\Transport\AbstractTransportFactory;
use Symfony\Component\Notifier\Transport\Dsn; use Symfony\Component\Notifier\Transport\Dsn;
@ -35,12 +34,7 @@ final class MobytTransportFactory extends AbstractTransportFactory
$accountSid = $this->getUser($dsn); $accountSid = $this->getUser($dsn);
$authToken = $this->getPassword($dsn); $authToken = $this->getPassword($dsn);
$from = $dsn->getOption('from'); $from = $dsn->getRequiredOption('from');
if (!$from) {
throw new IncompleteDsnException('Missing from.', $dsn->getOriginalDsn());
}
$typeQuality = $dsn->getOption('type_quality', MobytOptions::MESSAGE_TYPE_QUALITY_LOW); $typeQuality = $dsn->getOption('type_quality', MobytOptions::MESSAGE_TYPE_QUALITY_LOW);
$host = 'default' === $dsn->getHost() ? null : $dsn->getHost(); $host = 'default' === $dsn->getHost() ? null : $dsn->getHost();
$port = $dsn->getPort(); $port = $dsn->getPort();

View File

@ -11,7 +11,6 @@
namespace Symfony\Component\Notifier\Bridge\Nexmo; namespace Symfony\Component\Notifier\Bridge\Nexmo;
use Symfony\Component\Notifier\Exception\IncompleteDsnException;
use Symfony\Component\Notifier\Exception\UnsupportedSchemeException; use Symfony\Component\Notifier\Exception\UnsupportedSchemeException;
use Symfony\Component\Notifier\Transport\AbstractTransportFactory; use Symfony\Component\Notifier\Transport\AbstractTransportFactory;
use Symfony\Component\Notifier\Transport\Dsn; use Symfony\Component\Notifier\Transport\Dsn;
@ -35,12 +34,7 @@ final class NexmoTransportFactory extends AbstractTransportFactory
$apiKey = $this->getUser($dsn); $apiKey = $this->getUser($dsn);
$apiSecret = $this->getPassword($dsn); $apiSecret = $this->getPassword($dsn);
$from = $dsn->getOption('from'); $from = $dsn->getRequiredOption('from');
if (!$from) {
throw new IncompleteDsnException('Missing from.', $dsn->getOriginalDsn());
}
$host = 'default' === $dsn->getHost() ? null : $dsn->getHost(); $host = 'default' === $dsn->getHost() ? null : $dsn->getHost();
$port = $dsn->getPort(); $port = $dsn->getPort();

View File

@ -39,7 +39,7 @@ final class NexmoTransportFactoryTest extends TransportFactoryTestCase
yield [false, 'somethingElse://apiKey:apiSecret@default?from=0611223344']; yield [false, 'somethingElse://apiKey:apiSecret@default?from=0611223344'];
} }
public function incompleteDsnProvider(): iterable public function missingRequiredOptionProvider(): iterable
{ {
yield 'missing option: from' => ['nexmo://apiKey:apiSecret@default']; yield 'missing option: from' => ['nexmo://apiKey:apiSecret@default'];
} }

View File

@ -11,7 +11,6 @@
namespace Symfony\Component\Notifier\Bridge\OvhCloud; namespace Symfony\Component\Notifier\Bridge\OvhCloud;
use Symfony\Component\Notifier\Exception\IncompleteDsnException;
use Symfony\Component\Notifier\Exception\UnsupportedSchemeException; use Symfony\Component\Notifier\Exception\UnsupportedSchemeException;
use Symfony\Component\Notifier\Transport\AbstractTransportFactory; use Symfony\Component\Notifier\Transport\AbstractTransportFactory;
use Symfony\Component\Notifier\Transport\Dsn; use Symfony\Component\Notifier\Transport\Dsn;
@ -32,18 +31,8 @@ final class OvhCloudTransportFactory extends AbstractTransportFactory
$applicationKey = $this->getUser($dsn); $applicationKey = $this->getUser($dsn);
$applicationSecret = $this->getPassword($dsn); $applicationSecret = $this->getPassword($dsn);
$consumerKey = $dsn->getOption('consumer_key'); $consumerKey = $dsn->getRequiredOption('consumer_key');
$serviceName = $dsn->getRequiredOption('service_name');
if (!$consumerKey) {
throw new IncompleteDsnException('Missing consumer_key.', $dsn->getOriginalDsn());
}
$serviceName = $dsn->getOption('service_name');
if (!$serviceName) {
throw new IncompleteDsnException('Missing service_name.', $dsn->getOriginalDsn());
}
$host = 'default' === $dsn->getHost() ? null : $dsn->getHost(); $host = 'default' === $dsn->getHost() ? null : $dsn->getHost();
$port = $dsn->getPort(); $port = $dsn->getPort();

View File

@ -39,7 +39,7 @@ final class OvhCloudTransportFactoryTest extends TransportFactoryTestCase
yield [false, 'somethingElse://key:secret@default?consumer_key=consumerKey&service_name=serviceName']; yield [false, 'somethingElse://key:secret@default?consumer_key=consumerKey&service_name=serviceName'];
} }
public function incompleteDsnProvider(): iterable public function missingRequiredOptionProvider(): iterable
{ {
yield 'missing option: consumer_key' => ['ovhcloud://key:secret@default?service_name=serviceName']; yield 'missing option: consumer_key' => ['ovhcloud://key:secret@default?service_name=serviceName'];
yield 'missing option: service_name' => ['ovhcloud://key:secret@default?consumer_key=consumerKey']; yield 'missing option: service_name' => ['ovhcloud://key:secret@default?consumer_key=consumerKey'];

View File

@ -44,7 +44,7 @@ final class RocketChatTransportFactoryTest extends TransportFactoryTestCase
public function incompleteDsnProvider(): iterable public function incompleteDsnProvider(): iterable
{ {
yield 'missing option: token' => ['rocketchat://host.test?channel=testChannel']; yield 'missing token' => ['rocketchat://host.test?channel=testChannel'];
} }
public function unsupportedSchemeProvider(): iterable public function unsupportedSchemeProvider(): iterable

View File

@ -11,7 +11,6 @@
namespace Symfony\Component\Notifier\Bridge\Sendinblue; namespace Symfony\Component\Notifier\Bridge\Sendinblue;
use Symfony\Component\Notifier\Exception\IncompleteDsnException;
use Symfony\Component\Notifier\Exception\UnsupportedSchemeException; use Symfony\Component\Notifier\Exception\UnsupportedSchemeException;
use Symfony\Component\Notifier\Transport\AbstractTransportFactory; use Symfony\Component\Notifier\Transport\AbstractTransportFactory;
use Symfony\Component\Notifier\Transport\Dsn; use Symfony\Component\Notifier\Transport\Dsn;
@ -34,12 +33,7 @@ final class SendinblueTransportFactory extends AbstractTransportFactory
} }
$apiKey = $this->getUser($dsn); $apiKey = $this->getUser($dsn);
$sender = $dsn->getOption('sender'); $sender = $dsn->getRequiredOption('sender');
if (!$sender) {
throw new IncompleteDsnException('Missing sender.', $dsn->getOriginalDsn());
}
$host = 'default' === $dsn->getHost() ? null : $dsn->getHost(); $host = 'default' === $dsn->getHost() ? null : $dsn->getHost();
$port = $dsn->getPort(); $port = $dsn->getPort();

View File

@ -14,6 +14,7 @@ namespace Symfony\Component\Notifier\Bridge\Sendinblue\Tests;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use Symfony\Component\Notifier\Bridge\Sendinblue\SendinblueTransportFactory; use Symfony\Component\Notifier\Bridge\Sendinblue\SendinblueTransportFactory;
use Symfony\Component\Notifier\Exception\IncompleteDsnException; use Symfony\Component\Notifier\Exception\IncompleteDsnException;
use Symfony\Component\Notifier\Exception\MissingRequiredOptionException;
use Symfony\Component\Notifier\Exception\UnsupportedSchemeException; use Symfony\Component\Notifier\Exception\UnsupportedSchemeException;
use Symfony\Component\Notifier\Transport\Dsn; use Symfony\Component\Notifier\Transport\Dsn;
@ -28,11 +29,11 @@ final class SendinblueTransportFactoryTest extends TestCase
$this->assertSame('sendinblue://host.test?sender=0611223344', (string) $transport); $this->assertSame('sendinblue://host.test?sender=0611223344', (string) $transport);
} }
public function testCreateWithMissingOptionSenderThrowsIncompleteDsnException() public function testCreateWithMissingOptionSenderThrowsMissingRequiredOptionException()
{ {
$factory = $this->createFactory(); $factory = $this->createFactory();
$this->expectException(IncompleteDsnException::class); $this->expectException(MissingRequiredOptionException::class);
$factory->create(Dsn::fromString('sendinblue://apiKey@host.test')); $factory->create(Dsn::fromString('sendinblue://apiKey@host.test'));
} }

View File

@ -11,7 +11,6 @@
namespace Symfony\Component\Notifier\Bridge\Sinch; namespace Symfony\Component\Notifier\Bridge\Sinch;
use Symfony\Component\Notifier\Exception\IncompleteDsnException;
use Symfony\Component\Notifier\Exception\UnsupportedSchemeException; use Symfony\Component\Notifier\Exception\UnsupportedSchemeException;
use Symfony\Component\Notifier\Transport\AbstractTransportFactory; use Symfony\Component\Notifier\Transport\AbstractTransportFactory;
use Symfony\Component\Notifier\Transport\Dsn; use Symfony\Component\Notifier\Transport\Dsn;
@ -32,12 +31,7 @@ final class SinchTransportFactory extends AbstractTransportFactory
$accountSid = $this->getUser($dsn); $accountSid = $this->getUser($dsn);
$authToken = $this->getPassword($dsn); $authToken = $this->getPassword($dsn);
$from = $dsn->getOption('from'); $from = $dsn->getRequiredOption('from');
if (!$from) {
throw new IncompleteDsnException('Missing from.', $dsn->getOriginalDsn());
}
$host = 'default' === $dsn->getHost() ? null : $dsn->getHost(); $host = 'default' === $dsn->getHost() ? null : $dsn->getHost();
$port = $dsn->getPort(); $port = $dsn->getPort();

View File

@ -39,7 +39,7 @@ final class SinchTransportFactoryTest extends TransportFactoryTestCase
yield [false, 'somethingElse://accountSid:authToken@default?from=0611223344']; yield [false, 'somethingElse://accountSid:authToken@default?from=0611223344'];
} }
public function incompleteDsnProvider(): iterable public function missingRequiredOptionProvider(): iterable
{ {
yield 'missing option: from' => ['sinch://accountSid:authToken@default']; yield 'missing option: from' => ['sinch://accountSid:authToken@default'];
} }

View File

@ -11,7 +11,6 @@
namespace Symfony\Component\Notifier\Bridge\Smsapi; namespace Symfony\Component\Notifier\Bridge\Smsapi;
use Symfony\Component\Notifier\Exception\IncompleteDsnException;
use Symfony\Component\Notifier\Exception\UnsupportedSchemeException; use Symfony\Component\Notifier\Exception\UnsupportedSchemeException;
use Symfony\Component\Notifier\Transport\AbstractTransportFactory; use Symfony\Component\Notifier\Transport\AbstractTransportFactory;
use Symfony\Component\Notifier\Transport\Dsn; use Symfony\Component\Notifier\Transport\Dsn;
@ -36,12 +35,7 @@ final class SmsapiTransportFactory extends AbstractTransportFactory
} }
$authToken = $this->getUser($dsn); $authToken = $this->getUser($dsn);
$from = $dsn->getOption('from'); $from = $dsn->getRequiredOption('from');
if (!$from) {
throw new IncompleteDsnException('Missing from.', $dsn->getOriginalDsn());
}
$host = 'default' === $dsn->getHost() ? null : $dsn->getHost(); $host = 'default' === $dsn->getHost() ? null : $dsn->getHost();
$port = $dsn->getPort(); $port = $dsn->getPort();

View File

@ -14,6 +14,7 @@ namespace Symfony\Component\Notifier\Bridge\Smsapi\Tests;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use Symfony\Component\Notifier\Bridge\Smsapi\SmsapiTransportFactory; use Symfony\Component\Notifier\Bridge\Smsapi\SmsapiTransportFactory;
use Symfony\Component\Notifier\Exception\IncompleteDsnException; use Symfony\Component\Notifier\Exception\IncompleteDsnException;
use Symfony\Component\Notifier\Exception\MissingRequiredOptionException;
use Symfony\Component\Notifier\Exception\UnsupportedSchemeException; use Symfony\Component\Notifier\Exception\UnsupportedSchemeException;
use Symfony\Component\Notifier\Transport\Dsn; use Symfony\Component\Notifier\Transport\Dsn;
@ -28,11 +29,11 @@ final class SmsapiTransportFactoryTest extends TestCase
$this->assertSame('smsapi://host.test?from=testFrom', (string) $transport); $this->assertSame('smsapi://host.test?from=testFrom', (string) $transport);
} }
public function testCreateWithMissingOptionFromThrowsIncompleteDsnException() public function testCreateWithMissingOptionFromThrowsMissingRequiredOptionException()
{ {
$factory = $this->createFactory(); $factory = $this->createFactory();
$this->expectException(IncompleteDsnException::class); $this->expectException(MissingRequiredOptionException::class);
$factory->create(Dsn::fromString('smsapi://token@host')); $factory->create(Dsn::fromString('smsapi://token@host'));
} }

View File

@ -39,7 +39,7 @@ final class TwilioTransportFactoryTest extends TransportFactoryTestCase
yield [false, 'somethingElse://accountSid:authToken@default?from=0611223344']; yield [false, 'somethingElse://accountSid:authToken@default?from=0611223344'];
} }
public function incompleteDsnProvider(): iterable public function missingRequiredOptionProvider(): iterable
{ {
yield 'missing option: from' => ['twilio://accountSid:authToken@default']; yield 'missing option: from' => ['twilio://accountSid:authToken@default'];
} }

View File

@ -11,7 +11,6 @@
namespace Symfony\Component\Notifier\Bridge\Twilio; namespace Symfony\Component\Notifier\Bridge\Twilio;
use Symfony\Component\Notifier\Exception\IncompleteDsnException;
use Symfony\Component\Notifier\Exception\UnsupportedSchemeException; use Symfony\Component\Notifier\Exception\UnsupportedSchemeException;
use Symfony\Component\Notifier\Transport\AbstractTransportFactory; use Symfony\Component\Notifier\Transport\AbstractTransportFactory;
use Symfony\Component\Notifier\Transport\Dsn; use Symfony\Component\Notifier\Transport\Dsn;
@ -35,12 +34,7 @@ final class TwilioTransportFactory extends AbstractTransportFactory
$accountSid = $this->getUser($dsn); $accountSid = $this->getUser($dsn);
$authToken = $this->getPassword($dsn); $authToken = $this->getPassword($dsn);
$from = $dsn->getOption('from'); $from = $dsn->getRequiredOption('from');
if (!$from) {
throw new IncompleteDsnException('Missing from.', $dsn->getOriginalDsn());
}
$host = 'default' === $dsn->getHost() ? null : $dsn->getHost(); $host = 'default' === $dsn->getHost() ? null : $dsn->getHost();
$port = $dsn->getPort(); $port = $dsn->getPort();

View File

@ -14,6 +14,7 @@ namespace Symfony\Component\Notifier\Bridge\Zulip\Tests;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use Symfony\Component\Notifier\Bridge\Zulip\ZulipTransportFactory; use Symfony\Component\Notifier\Bridge\Zulip\ZulipTransportFactory;
use Symfony\Component\Notifier\Exception\IncompleteDsnException; use Symfony\Component\Notifier\Exception\IncompleteDsnException;
use Symfony\Component\Notifier\Exception\MissingRequiredOptionException;
use Symfony\Component\Notifier\Exception\UnsupportedSchemeException; use Symfony\Component\Notifier\Exception\UnsupportedSchemeException;
use Symfony\Component\Notifier\Transport\Dsn; use Symfony\Component\Notifier\Transport\Dsn;
@ -28,11 +29,11 @@ final class ZulipTransportFactoryTest extends TestCase
$this->assertSame('zulip://host.test?channel=testChannel', (string) $transport); $this->assertSame('zulip://host.test?channel=testChannel', (string) $transport);
} }
public function testCreateWithMissingOptionChannelThrowsIncompleteDsnException() public function testCreateWithMissingOptionChannelThrowsMissingRequiredOptionException()
{ {
$factory = $this->createFactory(); $factory = $this->createFactory();
$this->expectException(IncompleteDsnException::class); $this->expectException(MissingRequiredOptionException::class);
$factory->create(Dsn::fromString('zulip://email:token@host')); $factory->create(Dsn::fromString('zulip://email:token@host'));
} }

View File

@ -11,7 +11,6 @@
namespace Symfony\Component\Notifier\Bridge\Zulip; namespace Symfony\Component\Notifier\Bridge\Zulip;
use Symfony\Component\Notifier\Exception\IncompleteDsnException;
use Symfony\Component\Notifier\Exception\UnsupportedSchemeException; use Symfony\Component\Notifier\Exception\UnsupportedSchemeException;
use Symfony\Component\Notifier\Transport\AbstractTransportFactory; use Symfony\Component\Notifier\Transport\AbstractTransportFactory;
use Symfony\Component\Notifier\Transport\Dsn; use Symfony\Component\Notifier\Transport\Dsn;
@ -35,12 +34,7 @@ final class ZulipTransportFactory extends AbstractTransportFactory
$email = $this->getUser($dsn); $email = $this->getUser($dsn);
$token = $this->getPassword($dsn); $token = $this->getPassword($dsn);
$channel = $dsn->getOption('channel'); $channel = $dsn->getRequiredOption('channel');
if (!$channel) {
throw new IncompleteDsnException('Missing channel.', $dsn->getOriginalDsn());
}
$host = $dsn->getHost(); $host = $dsn->getHost();
$port = $dsn->getPort(); $port = $dsn->getPort();

View File

@ -6,6 +6,7 @@ CHANGELOG
* The component is not marked as `@experimental` anymore * The component is not marked as `@experimental` anymore
* [BC BREAK] Changed the return type of `AbstractTransportFactory::getEndpoint()` from `?string` to `string` * [BC BREAK] Changed the return type of `AbstractTransportFactory::getEndpoint()` from `?string` to `string`
* Added `DSN::getRequiredOption` method which throws a new `MissingRequiredOptionException`.
5.2.0 5.2.0
----- -----

View File

@ -0,0 +1,27 @@
<?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\Exception;
/**
* @author Oskar Stark <oskarstark@googlemail.com>
*
* @experimental in 5.3
*/
class MissingRequiredOptionException extends IncompleteDsnException
{
public function __construct(string $option, string $dsn = null, ?\Throwable $previous = null)
{
$message = sprintf('The option "%s" is required but missing.', $option);
parent::__construct($message, $dsn, $previous);
}
}

View File

@ -13,6 +13,7 @@ namespace Symfony\Component\Notifier\Tests\Transport;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use Symfony\Component\Notifier\Exception\InvalidArgumentException; use Symfony\Component\Notifier\Exception\InvalidArgumentException;
use Symfony\Component\Notifier\Exception\MissingRequiredOptionException;
use Symfony\Component\Notifier\Transport\Dsn; use Symfony\Component\Notifier\Transport\Dsn;
final class DsnTest extends TestCase final class DsnTest extends TestCase
@ -120,4 +121,54 @@ final class DsnTest extends TestCase
$this->assertSame('default', $dsn->getOption('nullable', 'default')); $this->assertSame('default', $dsn->getOption('nullable', 'default'));
$this->assertSame('default', $dsn->getOption('not_existent_property', 'default')); $this->assertSame('default', $dsn->getOption('not_existent_property', 'default'));
} }
public function testGetRequiredOptionGetsOptionIfSet()
{
$options = ['with_value' => 'some value'];
$dsn = new Dsn('scheme', 'localhost', 'u$er', 'pa$s', '8000', $options, '/channel');
$this->assertSame('some value', $dsn->getRequiredOption('with_value'));
}
public function testGetRequiredOptionGetsOptionIfValueIsZero()
{
$options = ['timeout' => 0];
$dsn = new Dsn('scheme', 'localhost', 'u$er', 'pa$s', '8000', $options, '/channel');
$this->assertSame(0, $dsn->getRequiredOption('timeout'));
}
/**
* @dataProvider getRequiredOptionThrowsMissingRequiredOptionExceptionProvider
*/
public function testGetRequiredOptionThrowsMissingRequiredOptionException(string $expectedExceptionMessage, array $options, string $option)
{
$dsn = new Dsn('scheme', 'localhost', 'u$er', 'pa$s', '8000', $options, '/channel');
$this->expectException(MissingRequiredOptionException::class);
$this->expectExceptionMessage($expectedExceptionMessage);
$dsn->getRequiredOption($option);
}
public function getRequiredOptionThrowsMissingRequiredOptionExceptionProvider(): iterable
{
yield [
'The option "foo_bar" is required but missing.',
['with_value' => 'some value'],
'foo_bar',
];
yield [
'The option "with_empty_string" is required but missing.',
['with_empty_string' => ''],
'with_empty_string',
];
yield [
'The option "with_null" is required but missing.',
['with_null' => null],
'with_null',
];
}
} }

View File

@ -14,6 +14,7 @@ namespace Symfony\Component\Notifier\Tests;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use Symfony\Component\Notifier\Exception\IncompleteDsnException; use Symfony\Component\Notifier\Exception\IncompleteDsnException;
use Symfony\Component\Notifier\Exception\UnsupportedSchemeException; use Symfony\Component\Notifier\Exception\UnsupportedSchemeException;
use Symfony\Component\Notifier\Exception\MissingRequiredOptionException;
use Symfony\Component\Notifier\Transport\Dsn; use Symfony\Component\Notifier\Transport\Dsn;
use Symfony\Component\Notifier\Transport\TransportFactoryInterface; use Symfony\Component\Notifier\Transport\TransportFactoryInterface;
@ -52,6 +53,14 @@ abstract class TransportFactoryTestCase extends TestCase
return []; return [];
} }
/**
* @return iterable<array{0: string, 1: string|null}>
*/
public function missingRequiredOptionProvider(): iterable
{
return [];
}
/** /**
* @dataProvider supportsProvider * @dataProvider supportsProvider
*/ */
@ -106,4 +115,21 @@ abstract class TransportFactoryTestCase extends TestCase
$factory->create($dsn); $factory->create($dsn);
} }
/**
* @dataProvider missingRequiredOptionProvider
*/
public function testMissingRequiredOptionException(string $dsn, string $message = null): void
{
$factory = $this->createFactory();
$dsn = Dsn::fromString($dsn);
$this->expectException(MissingRequiredOptionException::class);
if (null !== $message) {
$this->expectExceptionMessage($message);
}
$factory->create($dsn);
}
} }

View File

@ -12,6 +12,7 @@
namespace Symfony\Component\Notifier\Transport; namespace Symfony\Component\Notifier\Transport;
use Symfony\Component\Notifier\Exception\InvalidArgumentException; use Symfony\Component\Notifier\Exception\InvalidArgumentException;
use Symfony\Component\Notifier\Exception\MissingRequiredOptionException;
/** /**
* @author Fabien Potencier <fabien@symfony.com> * @author Fabien Potencier <fabien@symfony.com>
@ -94,6 +95,15 @@ final class Dsn
return $this->options[$key] ?? $default; return $this->options[$key] ?? $default;
} }
public function getRequiredOption(string $key)
{
if (!\array_key_exists($key, $this->options) || '' === trim($this->options[$key])) {
throw new MissingRequiredOptionException($key);
}
return $this->options[$key];
}
public function getPath(): ?string public function getPath(): ?string
{ {
return $this->path; return $this->path;

View File

@ -12,6 +12,7 @@
namespace Symfony\Component\Notifier\Transport; namespace Symfony\Component\Notifier\Transport;
use Symfony\Component\Notifier\Exception\IncompleteDsnException; use Symfony\Component\Notifier\Exception\IncompleteDsnException;
use Symfony\Component\Notifier\Exception\MissingRequiredOptionException;
use Symfony\Component\Notifier\Exception\UnsupportedSchemeException; use Symfony\Component\Notifier\Exception\UnsupportedSchemeException;
/** /**
@ -22,6 +23,7 @@ interface TransportFactoryInterface
/** /**
* @throws UnsupportedSchemeException * @throws UnsupportedSchemeException
* @throws IncompleteDsnException * @throws IncompleteDsnException
* @throws MissingRequiredOptionException
*/ */
public function create(Dsn $dsn): TransportInterface; public function create(Dsn $dsn): TransportInterface;