diff --git a/src/Symfony/Component/Notifier/Bridge/Esendex/CHANGELOG.md b/src/Symfony/Component/Notifier/Bridge/Esendex/CHANGELOG.md index aba2665873c56..ed529f6ec9f9f 100644 --- a/src/Symfony/Component/Notifier/Bridge/Esendex/CHANGELOG.md +++ b/src/Symfony/Component/Notifier/Bridge/Esendex/CHANGELOG.md @@ -5,10 +5,10 @@ CHANGELOG ----- * The bridge is not marked as `@experimental` anymore -* [BC BREAK] Changed signature of `EsendexTransport::__construct()` method from: - `public function __construct(string $token, string $accountReference, string $from, HttpClientInterface $client = null, EventDispatcherInterface $dispatcher = null)` - to: - `public function __construct(string $email, string $password, string $accountReference, string $from, HttpClientInterface $client = null, EventDispatcherInterface $dispatcher = null)` + * [BC BREAK] Change signature of `EsendexTransport::__construct()` method from: + `public function __construct(string $token, string $accountReference, string $from, HttpClientInterface $client = null, EventDispatcherInterface $dispatcher = null)` + to: + `public function __construct(string $email, string $password, string $accountReference, string $from, HttpClientInterface $client = null, EventDispatcherInterface $dispatcher = null)` 5.2.0 ----- diff --git a/src/Symfony/Component/Notifier/Bridge/LinkedIn/CHANGELOG.md b/src/Symfony/Component/Notifier/Bridge/LinkedIn/CHANGELOG.md index d61929abd637c..6d85f7a21e1f4 100644 --- a/src/Symfony/Component/Notifier/Bridge/LinkedIn/CHANGELOG.md +++ b/src/Symfony/Component/Notifier/Bridge/LinkedIn/CHANGELOG.md @@ -5,7 +5,7 @@ CHANGELOG ----- * The bridge is not marked as `@experimental` anymore -* [BC BREAK] `LinkedInTransportFactory` is now final + * [BC BREAK] `LinkedInTransportFactory` is now final 5.2.0 ----- diff --git a/src/Symfony/Component/Notifier/Bridge/Mattermost/CHANGELOG.md b/src/Symfony/Component/Notifier/Bridge/Mattermost/CHANGELOG.md index 34c179f2c7ea5..0d13c17d5f01f 100644 --- a/src/Symfony/Component/Notifier/Bridge/Mattermost/CHANGELOG.md +++ b/src/Symfony/Component/Notifier/Bridge/Mattermost/CHANGELOG.md @@ -5,10 +5,10 @@ CHANGELOG ----- * The bridge is not marked as `@experimental` anymore -* [BC BREAK] Changed signature of `MattermostTransport::__construct()` method from: - `public function __construct(string $token, string $channel, HttpClientInterface $client = null, EventDispatcherInterface $dispatcher = null, string $path = null)` - to: - `public function __construct(string $token, string $channel, ?string $path = null, HttpClientInterface $client = null, EventDispatcherInterface $dispatcher = null)` + * [BC BREAK] Change signature of `MattermostTransport::__construct()` method from: + `public function __construct(string $token, string $channel, HttpClientInterface $client = null, EventDispatcherInterface $dispatcher = null, string $path = null)` + to: + `public function __construct(string $token, string $channel, ?string $path = null, HttpClientInterface $client = null, EventDispatcherInterface $dispatcher = null)` 5.1.0 ----- diff --git a/src/Symfony/Component/Notifier/Bridge/Slack/Tests/SlackTransportFactoryTest.php b/src/Symfony/Component/Notifier/Bridge/Slack/Tests/SlackTransportFactoryTest.php index 8d6a5fb3be975..3841ebbb51687 100644 --- a/src/Symfony/Component/Notifier/Bridge/Slack/Tests/SlackTransportFactoryTest.php +++ b/src/Symfony/Component/Notifier/Bridge/Slack/Tests/SlackTransportFactoryTest.php @@ -52,7 +52,7 @@ public function testCreateWithDeprecatedDsn() $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->create(Dsn::fromString('slack://default/XXXXXXXXX/XXXXXXXXX/XXXXXXXXXXXXXXXXXXXXXXXX')); + $factory->create(new Dsn('slack://default/XXXXXXXXX/XXXXXXXXX/XXXXXXXXXXXXXXXXXXXXXXXX')); } public function supportsProvider(): iterable diff --git a/src/Symfony/Component/Notifier/Bridge/Zulip/CHANGELOG.md b/src/Symfony/Component/Notifier/Bridge/Zulip/CHANGELOG.md index b4a92ac9bde52..7dd18183aa127 100644 --- a/src/Symfony/Component/Notifier/Bridge/Zulip/CHANGELOG.md +++ b/src/Symfony/Component/Notifier/Bridge/Zulip/CHANGELOG.md @@ -5,8 +5,8 @@ CHANGELOG ----- * The bridge is not marked as `@experimental` anymore -* [BC BREAK] `ZulipTransport` is now final -* [BC BREAK] `ZulipTransportFactory` is now final + * [BC BREAK] `ZulipTransport` is now final + * [BC BREAK] `ZulipTransportFactory` is now final 5.2.0 ----- diff --git a/src/Symfony/Component/Notifier/CHANGELOG.md b/src/Symfony/Component/Notifier/CHANGELOG.md index 88403dba518b9..d2a6ed54cc1ee 100644 --- a/src/Symfony/Component/Notifier/CHANGELOG.md +++ b/src/Symfony/Component/Notifier/CHANGELOG.md @@ -5,6 +5,11 @@ CHANGELOG ----- * The component is not marked as `@experimental` anymore + * [BC BREAK] Change signature of `Dsn::__construct()` method from: + `public function __construct(string $scheme, string $host, ?string $user = null, ?string $password = null, ?int $port = null, array $options = [], ?string $path = null)` + to: + `public function __construct(string $dsn)` + * [BC BREAK] Remove `Dsn::fromString()` method * [BC BREAK] Changed the return type of `AbstractTransportFactory::getEndpoint()` from `?string` to `string` * Added `DSN::getRequiredOption` method which throws a new `MissingRequiredOptionException`. diff --git a/src/Symfony/Component/Notifier/Tests/Transport/DsnTest.php b/src/Symfony/Component/Notifier/Tests/Transport/DsnTest.php index abd12a5134e84..7dccb3398a9fe 100644 --- a/src/Symfony/Component/Notifier/Tests/Transport/DsnTest.php +++ b/src/Symfony/Component/Notifier/Tests/Transport/DsnTest.php @@ -19,79 +19,136 @@ final class DsnTest extends TestCase { /** - * @dataProvider fromStringProvider + * @dataProvider constructProvider */ - public function testFromString(string $string, Dsn $expectedDsn) + public function testConstruct(string $dsnString, string $scheme, string $host, ?string $user = null, ?string $password = null, ?int $port = null, array $options = [], ?string $path = null) { - $actualDsn = Dsn::fromString($string); + $dsn = new Dsn($dsnString); + $this->assertSame($dsnString, $dsn->getOriginalDsn()); - $this->assertSame($expectedDsn->getScheme(), $actualDsn->getScheme()); - $this->assertSame($expectedDsn->getHost(), $actualDsn->getHost()); - $this->assertSame($expectedDsn->getPort(), $actualDsn->getPort()); - $this->assertSame($expectedDsn->getUser(), $actualDsn->getUser()); - $this->assertSame($expectedDsn->getPassword(), $actualDsn->getPassword()); - $this->assertSame($expectedDsn->getPath(), $actualDsn->getPath()); - $this->assertSame($expectedDsn->getOption('from'), $actualDsn->getOption('from')); - - $this->assertSame($string, $actualDsn->getOriginalDsn()); + $this->assertSame($scheme, $dsn->getScheme()); + $this->assertSame($host, $dsn->getHost()); + $this->assertSame($user, $dsn->getUser()); + $this->assertSame($password, $dsn->getPassword()); + $this->assertSame($port, $dsn->getPort()); + $this->assertSame($path, $dsn->getPath()); + $this->assertSame($options, $dsn->getOptions()); } - public function fromStringProvider(): iterable + public function constructProvider(): iterable { yield 'simple dsn' => [ 'scheme://localhost', - new Dsn('scheme', 'localhost', null, null, null, [], null), + 'scheme', + 'localhost', ]; yield 'simple dsn including @ sign, but no user/password/token' => [ 'scheme://@localhost', - new Dsn('scheme', 'localhost', null, null), + 'scheme', + 'localhost', ]; yield 'simple dsn including : sign and @ sign, but no user/password/token' => [ 'scheme://:@localhost', - new Dsn('scheme', 'localhost', null, null), + 'scheme', + 'localhost', ]; yield 'simple dsn including user, : sign and @ sign, but no password' => [ 'scheme://user1:@localhost', - new Dsn('scheme', 'localhost', 'user1', null), + 'scheme', + 'localhost', + 'user1', ]; yield 'simple dsn including : sign, password, and @ sign, but no user' => [ 'scheme://:pass@localhost', - new Dsn('scheme', 'localhost', null, 'pass'), + 'scheme', + 'localhost', + null, + 'pass', ]; yield 'dsn with user and pass' => [ 'scheme://u$er:pa$s@localhost', - new Dsn('scheme', 'localhost', 'u$er', 'pa$s', null, [], null), + 'scheme', + 'localhost', + 'u$er', + 'pa$s', ]; yield 'dsn with user and pass and custom port' => [ 'scheme://u$er:pa$s@localhost:8000', - new Dsn('scheme', 'localhost', 'u$er', 'pa$s', '8000', [], null), + 'scheme', + 'localhost', + 'u$er', + 'pa$s', + 8000, ]; yield 'dsn with user and pass, custom port and custom path' => [ 'scheme://u$er:pa$s@localhost:8000/channel', - new Dsn('scheme', 'localhost', 'u$er', 'pa$s', '8000', [], '/channel'), + 'scheme', + 'localhost', + 'u$er', + 'pa$s', + 8000, + [], + '/channel', ]; - yield 'dsn with user and pass, custom port, custom path and custom options' => [ + yield 'dsn with user and pass, custom port, custom path and custom option' => [ 'scheme://u$er:pa$s@localhost:8000/channel?from=FROM', - new Dsn('scheme', 'localhost', 'u$er', 'pa$s', '8000', ['from' => 'FROM'], '/channel'), + 'scheme', + 'localhost', + 'u$er', + 'pa$s', + 8000, + [ + 'from' => 'FROM', + ], + '/channel', + ]; + + yield 'dsn with user and pass, custom port, custom path and custom options' => [ + 'scheme://u$er:pa$s@localhost:8000/channel?from=FROM&to=TO', + 'scheme', + 'localhost', + 'u$er', + 'pa$s', + 8000, + [ + 'from' => 'FROM', + 'to' => 'TO', + ], + '/channel', + ]; + + yield 'dsn with user and pass, custom port, custom path and custom options and custom options keep the same order' => [ + 'scheme://u$er:pa$s@localhost:8000/channel?to=TO&from=FROM', + 'scheme', + 'localhost', + 'u$er', + 'pa$s', + 8000, + [ + 'to' => 'TO', + 'from' => 'FROM', + ], + '/channel', ]; } /** * @dataProvider invalidDsnProvider */ - public function testInvalidDsn(string $dsn, string $exceptionMessage) + public function testInvalidDsn(string $dsnString, string $exceptionMessage) { $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessage($exceptionMessage); - Dsn::fromString($dsn); + + new Dsn($dsnString); } public function invalidDsnProvider(): iterable @@ -112,38 +169,75 @@ public function invalidDsnProvider(): iterable ]; } - public function testGetOption() + /** + * @dataProvider getOptionProvider + */ + public function testGetOption($expected, string $dsnString, string $option, ?string $default = null) { - $options = ['with_value' => 'some value', 'nullable' => null]; - $dsn = new Dsn('scheme', 'localhost', 'u$er', 'pa$s', '8000', $options, '/channel'); + $dsn = new Dsn($dsnString); - $this->assertSame('some value', $dsn->getOption('with_value')); - $this->assertSame('default', $dsn->getOption('nullable', 'default')); - $this->assertSame('default', $dsn->getOption('not_existent_property', 'default')); + $this->assertSame($expected, $dsn->getOption($option, $default)); } - public function testGetRequiredOptionGetsOptionIfSet() + public function getOptionProvider(): iterable { - $options = ['with_value' => 'some value']; - $dsn = new Dsn('scheme', 'localhost', 'u$er', 'pa$s', '8000', $options, '/channel'); + yield [ + 'foo', + 'scheme://localhost?with_value=foo', + 'with_value', + ]; + + yield [ + '', + 'scheme://localhost?empty=', + 'empty', + ]; - $this->assertSame('some value', $dsn->getRequiredOption('with_value')); + yield [ + '0', + 'scheme://localhost?zero=0', + 'zero', + ]; + + yield [ + 'default-value', + 'scheme://localhost?option=value', + 'non_existent_property', + 'default-value', + ]; + } + + /** + * @dataProvider getRequiredOptionProvider + */ + public function testGetRequiredOption(string $expectedValue, string $options, string $option) + { + $dsn = new Dsn(sprintf('scheme://localhost?%s', $options)); + + $this->assertSame($expectedValue, $dsn->getRequiredOption($option)); } - public function testGetRequiredOptionGetsOptionIfValueIsZero() + public function getRequiredOptionProvider(): iterable { - $options = ['timeout' => 0]; - $dsn = new Dsn('scheme', 'localhost', 'u$er', 'pa$s', '8000', $options, '/channel'); + yield [ + 'value', + 'with_value=value', + 'with_value', + ]; - $this->assertSame(0, $dsn->getRequiredOption('timeout')); + yield [ + '0', + 'timeout=0', + 'timeout', + ]; } /** * @dataProvider getRequiredOptionThrowsMissingRequiredOptionExceptionProvider */ - public function testGetRequiredOptionThrowsMissingRequiredOptionException(string $expectedExceptionMessage, array $options, string $option) + public function testGetRequiredOptionThrowsMissingRequiredOptionException(string $expectedExceptionMessage, string $options, string $option) { - $dsn = new Dsn('scheme', 'localhost', 'u$er', 'pa$s', '8000', $options, '/channel'); + $dsn = new Dsn(sprintf('scheme://localhost?%s', $options)); $this->expectException(MissingRequiredOptionException::class); $this->expectExceptionMessage($expectedExceptionMessage); @@ -155,20 +249,14 @@ public function getRequiredOptionThrowsMissingRequiredOptionExceptionProvider(): { yield [ 'The option "foo_bar" is required but missing.', - ['with_value' => 'some value'], + 'with_value=value', 'foo_bar', ]; yield [ 'The option "with_empty_string" is required but missing.', - ['with_empty_string' => ''], + 'with_empty_string=', 'with_empty_string', ]; - - yield [ - 'The option "with_null" is required but missing.', - ['with_null' => null], - 'with_null', - ]; } } diff --git a/src/Symfony/Component/Notifier/Tests/Transport/NullTransportFactoryTest.php b/src/Symfony/Component/Notifier/Tests/Transport/NullTransportFactoryTest.php index a2682a7957c44..470b848372bab 100644 --- a/src/Symfony/Component/Notifier/Tests/Transport/NullTransportFactoryTest.php +++ b/src/Symfony/Component/Notifier/Tests/Transport/NullTransportFactoryTest.php @@ -41,14 +41,14 @@ public function testCreateThrowsUnsupportedSchemeException() { $this->expectException(UnsupportedSchemeException::class); - $this->nullTransportFactory->create(new Dsn('foo', '')); + $this->nullTransportFactory->create(new Dsn('foo://localhost')); } public function testCreate() { $this->assertInstanceOf( NullTransport::class, - $this->nullTransportFactory->create(new Dsn('null', '')) + $this->nullTransportFactory->create(new Dsn('null://null')) ); } } diff --git a/src/Symfony/Component/Notifier/Tests/TransportFactoryTestCase.php b/src/Symfony/Component/Notifier/Tests/TransportFactoryTestCase.php index c539f5d652816..3215e31eafc95 100644 --- a/src/Symfony/Component/Notifier/Tests/TransportFactoryTestCase.php +++ b/src/Symfony/Component/Notifier/Tests/TransportFactoryTestCase.php @@ -13,8 +13,8 @@ use PHPUnit\Framework\TestCase; use Symfony\Component\Notifier\Exception\IncompleteDsnException; -use Symfony\Component\Notifier\Exception\UnsupportedSchemeException; use Symfony\Component\Notifier\Exception\MissingRequiredOptionException; +use Symfony\Component\Notifier\Exception\UnsupportedSchemeException; use Symfony\Component\Notifier\Transport\Dsn; use Symfony\Component\Notifier\Transport\TransportFactoryInterface; @@ -68,7 +68,7 @@ public function testSupports(bool $expected, string $dsn) { $factory = $this->createFactory(); - $this->assertSame($expected, $factory->supports(Dsn::fromString($dsn))); + $this->assertSame($expected, $factory->supports(new Dsn($dsn))); } /** @@ -77,7 +77,7 @@ public function testSupports(bool $expected, string $dsn) public function testCreate(string $expected, string $dsn) { $factory = $this->createFactory(); - $transport = $factory->create(Dsn::fromString($dsn)); + $transport = $factory->create(new Dsn($dsn)); $this->assertSame($expected, (string) $transport); } @@ -89,7 +89,7 @@ public function testUnsupportedSchemeException(string $dsn, string $message = nu { $factory = $this->createFactory(); - $dsn = Dsn::fromString($dsn); + $dsn = new Dsn($dsn); $this->expectException(UnsupportedSchemeException::class); if (null !== $message) { @@ -106,7 +106,7 @@ public function testIncompleteDsnException(string $dsn, string $message = null) { $factory = $this->createFactory(); - $dsn = Dsn::fromString($dsn); + $dsn = new Dsn($dsn); $this->expectException(IncompleteDsnException::class); if (null !== $message) { @@ -119,11 +119,11 @@ public function testIncompleteDsnException(string $dsn, string $message = null) /** * @dataProvider missingRequiredOptionProvider */ - public function testMissingRequiredOptionException(string $dsn, string $message = null): void + public function testMissingRequiredOptionException(string $dsn, string $message = null) { $factory = $this->createFactory(); - $dsn = Dsn::fromString($dsn); + $dsn = new Dsn($dsn); $this->expectException(MissingRequiredOptionException::class); if (null !== $message) { diff --git a/src/Symfony/Component/Notifier/Transport.php b/src/Symfony/Component/Notifier/Transport.php index c2c8d2d8409bb..43ab3469b88a9 100644 --- a/src/Symfony/Component/Notifier/Transport.php +++ b/src/Symfony/Component/Notifier/Transport.php @@ -112,7 +112,7 @@ public function fromString(string $dsn): TransportInterface return new RoundRobinTransport($this->createFromDsns($dsns)); } - return $this->fromDsnObject(Dsn::fromString($dsn)); + return $this->fromDsnObject(new Dsn($dsn)); } public function fromDsnObject(Dsn $dsn): TransportInterface @@ -133,7 +133,7 @@ private function createFromDsns(array $dsns): array { $transports = []; foreach ($dsns as $dsn) { - $transports[] = $this->fromDsnObject(Dsn::fromString($dsn)); + $transports[] = $this->fromDsnObject(new Dsn($dsn)); } return $transports; diff --git a/src/Symfony/Component/Notifier/Transport/Dsn.php b/src/Symfony/Component/Notifier/Transport/Dsn.php index 0e2e2abd67579..16f722356578b 100644 --- a/src/Symfony/Component/Notifier/Transport/Dsn.php +++ b/src/Symfony/Component/Notifier/Transport/Dsn.php @@ -16,6 +16,7 @@ /** * @author Fabien Potencier + * @author Oskar Stark */ final class Dsn { @@ -24,23 +25,14 @@ final class Dsn private $user; private $password; private $port; - private $options; private $path; - private $dsn; + private $options; + private $originalDsn; - public function __construct(string $scheme, string $host, ?string $user = null, ?string $password = null, ?int $port = null, array $options = [], ?string $path = null) + public function __construct(string $dsn) { - $this->scheme = $scheme; - $this->host = $host; - $this->user = $user; - $this->password = $password; - $this->port = $port; - $this->options = $options; - $this->path = $path; - } + $this->originalDsn = $dsn; - public static function fromString(string $dsn): self - { if (false === $parsedDsn = parse_url($dsn)) { throw new InvalidArgumentException(sprintf('The "%s" notifier DSN is invalid.', $dsn)); } @@ -48,21 +40,18 @@ public static function fromString(string $dsn): self if (!isset($parsedDsn['scheme'])) { throw new InvalidArgumentException(sprintf('The "%s" notifier DSN must contain a scheme.', $dsn)); } + $this->scheme = $parsedDsn['scheme']; if (!isset($parsedDsn['host'])) { throw new InvalidArgumentException(sprintf('The "%s" notifier DSN must contain a host (use "default" by default).', $dsn)); } + $this->host = $parsedDsn['host']; - $user = '' !== ($parsedDsn['user'] ?? '') ? urldecode($parsedDsn['user']) : null; - $password = '' !== ($parsedDsn['pass'] ?? '') ? urldecode($parsedDsn['pass']) : null; - $port = $parsedDsn['port'] ?? null; - $path = $parsedDsn['path'] ?? null; - parse_str($parsedDsn['query'] ?? '', $query); - - $dsnObject = new self($parsedDsn['scheme'], $parsedDsn['host'], $user, $password, $port, $query, $path); - $dsnObject->dsn = $dsn; - - return $dsnObject; + $this->user = '' !== ($parsedDsn['user'] ?? '') ? urldecode($parsedDsn['user']) : null; + $this->password = '' !== ($parsedDsn['pass'] ?? '') ? urldecode($parsedDsn['pass']) : null; + $this->port = $parsedDsn['port'] ?? null; + $this->path = $parsedDsn['path'] ?? null; + parse_str($parsedDsn['query'] ?? '', $this->options); } public function getScheme(): string @@ -104,6 +93,11 @@ public function getRequiredOption(string $key) return $this->options[$key]; } + public function getOptions(): array + { + return $this->options; + } + public function getPath(): ?string { return $this->path; @@ -111,6 +105,6 @@ public function getPath(): ?string public function getOriginalDsn(): string { - return $this->dsn; + return $this->originalDsn; } }