diff --git a/composer.json b/composer.json index ff966ad6dfc30..a0c64e31bc888 100644 --- a/composer.json +++ b/composer.json @@ -135,6 +135,7 @@ "dragonmantank/cron-expression": "^3.1", "egulias/email-validator": "^2.1.10|^3.1|^4", "guzzlehttp/promises": "^1.4|^2.0", + "jolicode/jolinotif": "^2.7.2", "league/html-to-markdown": "^5.0", "league/uri": "^6.5|^7.0", "masterminds/html5": "^2.7.2", diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php index d7c4403b0ae1b..75cfe1d1f0d84 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php @@ -2766,6 +2766,7 @@ private function registerNotifierConfiguration(array $config, ContainerBuilder $ } $container->getDefinition('notifier.channel.sms')->setArgument(0, null); $container->getDefinition('notifier.channel.push')->setArgument(0, null); + $container->getDefinition('notifier.channel.desktop')->setArgument(0, null); } $container->getDefinition('notifier.channel_policy')->setArgument(0, $config['channel_policy']); @@ -2801,6 +2802,7 @@ private function registerNotifierConfiguration(array $config, ContainerBuilder $ NotifierBridge\Infobip\InfobipTransportFactory::class => 'notifier.transport_factory.infobip', NotifierBridge\Iqsms\IqsmsTransportFactory::class => 'notifier.transport_factory.iqsms', NotifierBridge\Isendpro\IsendproTransportFactory::class => 'notifier.transport_factory.isendpro', + NotifierBridge\JoliNotif\JoliNotifTransportFactory::class => 'notifier.transport_factory.joli-notif', NotifierBridge\KazInfoTeh\KazInfoTehTransportFactory::class => 'notifier.transport_factory.kaz-info-teh', NotifierBridge\LightSms\LightSmsTransportFactory::class => 'notifier.transport_factory.light-sms', NotifierBridge\LineNotify\LineNotifyTransportFactory::class => 'notifier.transport_factory.line-notify', diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/notifier.php b/src/Symfony/Bundle/FrameworkBundle/Resources/config/notifier.php index 3bd19b8ddc061..95a4d12e9ef1a 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/notifier.php +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/notifier.php @@ -15,6 +15,7 @@ use Symfony\Component\Notifier\Channel\BrowserChannel; use Symfony\Component\Notifier\Channel\ChannelPolicy; use Symfony\Component\Notifier\Channel\ChatChannel; +use Symfony\Component\Notifier\Channel\DesktopChannel; use Symfony\Component\Notifier\Channel\EmailChannel; use Symfony\Component\Notifier\Channel\PushChannel; use Symfony\Component\Notifier\Channel\SmsChannel; @@ -24,6 +25,7 @@ use Symfony\Component\Notifier\EventListener\SendFailedMessageToNotifierListener; use Symfony\Component\Notifier\FlashMessage\DefaultFlashMessageImportanceMapper; use Symfony\Component\Notifier\Message\ChatMessage; +use Symfony\Component\Notifier\Message\DesktopMessage; use Symfony\Component\Notifier\Message\PushMessage; use Symfony\Component\Notifier\Message\SmsMessage; use Symfony\Component\Notifier\Messenger\MessageHandler; @@ -76,6 +78,10 @@ ->args([service('texter.transports'), service('messenger.default_bus')->ignoreOnInvalid()]) ->tag('notifier.channel', ['channel' => 'push']) + ->set('notifier.channel.desktop', DesktopChannel::class) + ->args([service('texter.transports'), service('messenger.default_bus')->ignoreOnInvalid()]) + ->tag('notifier.channel', ['channel' => 'desktop']) + ->set('notifier.monolog_handler', NotifierHandler::class) ->args([service('notifier')]) @@ -126,6 +132,10 @@ ->args([service('texter.transports')]) ->tag('messenger.message_handler', ['handles' => PushMessage::class]) + ->set('texter.messenger.desktop_handler', MessageHandler::class) + ->args([service('texter.transports')]) + ->tag('messenger.message_handler', ['handles' => DesktopMessage::class]) + ->set('notifier.notification_logger_listener', NotificationLoggerListener::class) ->tag('kernel.event_subscriber') diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/notifier_transports.php b/src/Symfony/Bundle/FrameworkBundle/Resources/config/notifier_transports.php index a773899f710a0..7c8002993db0b 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/notifier_transports.php +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/notifier_transports.php @@ -72,6 +72,7 @@ 'infobip' => Bridge\Infobip\InfobipTransportFactory::class, 'iqsms' => Bridge\Iqsms\IqsmsTransportFactory::class, 'isendpro' => Bridge\Isendpro\IsendproTransportFactory::class, + 'joli-notif' => Bridge\JoliNotif\JoliNotifTransportFactory::class, 'kaz-info-teh' => Bridge\KazInfoTeh\KazInfoTehTransportFactory::class, 'light-sms' => Bridge\LightSms\LightSmsTransportFactory::class, 'lox24' => Bridge\Lox24\Lox24TransportFactory::class, diff --git a/src/Symfony/Component/Notifier/Bridge/JoliNotif/.gitattributes b/src/Symfony/Component/Notifier/Bridge/JoliNotif/.gitattributes new file mode 100644 index 0000000000000..14c3c35940427 --- /dev/null +++ b/src/Symfony/Component/Notifier/Bridge/JoliNotif/.gitattributes @@ -0,0 +1,3 @@ +/Tests export-ignore +/phpunit.xml.dist export-ignore +/.git* export-ignore diff --git a/src/Symfony/Component/Notifier/Bridge/JoliNotif/.gitignore b/src/Symfony/Component/Notifier/Bridge/JoliNotif/.gitignore new file mode 100644 index 0000000000000..c49a5d8df5c65 --- /dev/null +++ b/src/Symfony/Component/Notifier/Bridge/JoliNotif/.gitignore @@ -0,0 +1,3 @@ +vendor/ +composer.lock +phpunit.xml diff --git a/src/Symfony/Component/Notifier/Bridge/JoliNotif/CHANGELOG.md b/src/Symfony/Component/Notifier/Bridge/JoliNotif/CHANGELOG.md new file mode 100644 index 0000000000000..00149ea5ac6f5 --- /dev/null +++ b/src/Symfony/Component/Notifier/Bridge/JoliNotif/CHANGELOG.md @@ -0,0 +1,7 @@ +CHANGELOG +========= + +7.2 +--- + + * Add the bridge diff --git a/src/Symfony/Component/Notifier/Bridge/JoliNotif/JoliNotifOptions.php b/src/Symfony/Component/Notifier/Bridge/JoliNotif/JoliNotifOptions.php new file mode 100644 index 0000000000000..325c75647b768 --- /dev/null +++ b/src/Symfony/Component/Notifier/Bridge/JoliNotif/JoliNotifOptions.php @@ -0,0 +1,83 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Notifier\Bridge\JoliNotif; + +use Symfony\Component\Notifier\Exception\InvalidArgumentException; +use Symfony\Component\Notifier\Message\MessageOptionsInterface; + +/** + * @author Ahmed Ghanem + */ +final class JoliNotifOptions implements MessageOptionsInterface +{ + public function __construct( + private ?string $iconPath = null, + private array $extraOptions = [], + ) { + } + + public function toArray(): array + { + return [ + 'icon_path' => $this->iconPath, + 'extra_options' => $this->extraOptions, + ]; + } + + public function getRecipientId(): ?string + { + return null; + } + + /** + * @return $this + */ + public function setIconPath(string $iconPath): static + { + $this->iconPath = $iconPath; + + return $this; + } + + public function getIconPath(): ?string + { + return $this->iconPath; + } + + /** + * Extra options maybe supported and effective by the JoliNotif package on some operating systems + * while not on others. + * For more details, you can always check the package page on GitHub (https://github.com/jolicode/JoliNotif). + * + * @return $this + */ + public function setExtraOption(string $key, string|int $value): static + { + $this->extraOptions[$key] = $value; + + return $this; + } + + public function getExtraOption(string $key): string|int + { + if (!isset($this->extraOptions[$key])) { + throw new InvalidArgumentException(\sprintf('The extra option "%s" cannot be fetched as it does not exist.', $key)); + } + + return $this->extraOptions[$key]; + } + + public function getExtraOptions(): array + { + return $this->extraOptions; + } +} diff --git a/src/Symfony/Component/Notifier/Bridge/JoliNotif/JoliNotifTransport.php b/src/Symfony/Component/Notifier/Bridge/JoliNotif/JoliNotifTransport.php new file mode 100644 index 0000000000000..edc13e76d477a --- /dev/null +++ b/src/Symfony/Component/Notifier/Bridge/JoliNotif/JoliNotifTransport.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\JoliNotif; + +use Joli\JoliNotif\DefaultNotifier as JoliNotifier; +use Joli\JoliNotif\Notification as JoliNotification; +use Symfony\Component\Notifier\Exception\LogicException; +use Symfony\Component\Notifier\Exception\RuntimeException; +use Symfony\Component\Notifier\Exception\UnsupportedMessageTypeException; +use Symfony\Component\Notifier\Message\DesktopMessage; +use Symfony\Component\Notifier\Message\MessageInterface; +use Symfony\Component\Notifier\Message\SentMessage; +use Symfony\Component\Notifier\Transport\AbstractTransport; +use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; + +/** + * @author Ahmed Ghanem + */ +final class JoliNotifTransport extends AbstractTransport +{ + public function __construct( + private readonly JoliNotifier $joliNotifier, + ?EventDispatcherInterface $dispatcher = null, + ) { + parent::__construct(null, $dispatcher); + } + + public function __toString(): string + { + return \sprintf('jolinotif://%s', $this->getEndpoint()); + } + + public function supports(MessageInterface $message): bool + { + return $message instanceof DesktopMessage && (null === $message->getOptions() || $message->getOptions() instanceof JoliNotifOptions); + } + + protected function doSend(MessageInterface $message): SentMessage + { + if (!$message instanceof DesktopMessage) { + throw new UnsupportedMessageTypeException(__CLASS__, DesktopMessage::class, $message); + } + + if (($options = $message->getOptions()) && !$options instanceof JoliNotifOptions) { + throw new LogicException(\sprintf('The "%s" transport only supports an instance of the "%s" as an option class.', __CLASS__, JoliNotifOptions::class)); + } + + $joliNotification = $this->buildJoliNotificationObject($message, $options); + + if (false === $this->joliNotifier->send($joliNotification)) { + throw new RuntimeException(\sprintf('An error occurred while sending a notification via the "%s" transport.', __CLASS__)); + } + + return new SentMessage($message, (string) $this); + } + + private function buildJoliNotificationObject(DesktopMessage $message, ?JoliNotifOptions $options = null): JoliNotification + { + $joliNotification = new JoliNotification(); + + $joliNotification->setTitle($message->getSubject()); + $joliNotification->setBody($message->getContent()); + + if ($options) { + if ($iconPath = $options->getIconPath()) { + $joliNotification->setIcon($iconPath); + } + + foreach ($options->getExtraOptions() as $extraOptionKey => $extraOptionValue) { + $joliNotification->addOption($extraOptionKey, $extraOptionValue); + } + } + + return $joliNotification; + } +} diff --git a/src/Symfony/Component/Notifier/Bridge/JoliNotif/JoliNotifTransportFactory.php b/src/Symfony/Component/Notifier/Bridge/JoliNotif/JoliNotifTransportFactory.php new file mode 100644 index 0000000000000..6a171fb19d4e8 --- /dev/null +++ b/src/Symfony/Component/Notifier/Bridge/JoliNotif/JoliNotifTransportFactory.php @@ -0,0 +1,44 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Notifier\Bridge\JoliNotif; + +use Joli\JoliNotif\DefaultNotifier as JoliNotifier; +use Symfony\Component\Notifier\Exception\UnsupportedSchemeException; +use Symfony\Component\Notifier\Transport\AbstractTransportFactory; +use Symfony\Component\Notifier\Transport\Dsn; + +/** + * @author Ahmed Ghanem + */ +final class JoliNotifTransportFactory extends AbstractTransportFactory +{ + private const SCHEME_NAME = 'jolinotif'; + + public function create(Dsn $dsn): JoliNotifTransport + { + if (self::SCHEME_NAME !== $dsn->getScheme()) { + throw new UnsupportedSchemeException($dsn, self::SCHEME_NAME, $this->getSupportedSchemes()); + } + + return (new JoliNotifTransport(new JoliNotifier(), $this->dispatcher))->setHost($dsn->getHost())->setPort($dsn->getPort()); + } + + /** + * @return string[] + */ + protected function getSupportedSchemes(): array + { + return [ + self::SCHEME_NAME, + ]; + } +} diff --git a/src/Symfony/Component/Notifier/Bridge/JoliNotif/LICENSE b/src/Symfony/Component/Notifier/Bridge/JoliNotif/LICENSE new file mode 100644 index 0000000000000..e374a5c8339d3 --- /dev/null +++ b/src/Symfony/Component/Notifier/Bridge/JoliNotif/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2024-present 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/JoliNotif/README.md b/src/Symfony/Component/Notifier/Bridge/JoliNotif/README.md new file mode 100644 index 0000000000000..06801292d39ae --- /dev/null +++ b/src/Symfony/Component/Notifier/Bridge/JoliNotif/README.md @@ -0,0 +1,20 @@ +JoliNotif Notifier Bridge +========================= + +Provides a [JoliNotif](https://github.com/jolicode/JoliNotif) integration for +the Symfony Notifier Component. + +DSN example +----------- + +``` +JOLINOTIF_DSN=jolinotif://default +``` + +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/JoliNotif/Tests/JoliNotifOptionsTest.php b/src/Symfony/Component/Notifier/Bridge/JoliNotif/Tests/JoliNotifOptionsTest.php new file mode 100644 index 0000000000000..6a254804aa13d --- /dev/null +++ b/src/Symfony/Component/Notifier/Bridge/JoliNotif/Tests/JoliNotifOptionsTest.php @@ -0,0 +1,48 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Notifier\Bridge\JoliNotif\Tests; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\Notifier\Bridge\JoliNotif\JoliNotifOptions; +use Symfony\Component\Notifier\Exception\InvalidArgumentException; + +/** + * @author Ahmed Ghanem + */ +class JoliNotifOptionsTest extends TestCase +{ + public function testToArray() + { + $joliOptions = new JoliNotifOptions(); + + $joliOptions->setIconPath('/sample/icon/path'); + $joliOptions->setExtraOption('subtitle', 'This is a subtitle'); + $joliOptions->setExtraOption('sound', 'Frog'); + + $this->assertSame([ + 'icon_path' => '/sample/icon/path', + 'extra_options' => [ + 'subtitle' => 'This is a subtitle', + 'sound' => 'Frog', + ], + ], $joliOptions->toArray()); + } + + public function testNonExistExtraOption() + { + $joliOptions = new JoliNotifOptions(); + + $this->expectException(InvalidArgumentException::class); + + $joliOptions->getExtraOption('non-exist-option'); + } +} diff --git a/src/Symfony/Component/Notifier/Bridge/JoliNotif/Tests/JoliNotifTransportFactoryTest.php b/src/Symfony/Component/Notifier/Bridge/JoliNotif/Tests/JoliNotifTransportFactoryTest.php new file mode 100644 index 0000000000000..7fc16e1efac87 --- /dev/null +++ b/src/Symfony/Component/Notifier/Bridge/JoliNotif/Tests/JoliNotifTransportFactoryTest.php @@ -0,0 +1,45 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Notifier\Bridge\JoliNotif\Tests; + +use Symfony\Component\Notifier\Bridge\JoliNotif\JoliNotifTransportFactory; +use Symfony\Component\Notifier\Test\TransportFactoryTestCase; + +/** + * @author Ahmed Ghanem + */ +final class JoliNotifTransportFactoryTest extends TransportFactoryTestCase +{ + public static function createProvider(): iterable + { + yield [ + 'jolinotif://host.test', + 'jolinotif://host.test?some_option=true', + ]; + } + + public static function supportsProvider(): iterable + { + yield [true, 'jolinotif://host.test']; + yield [false, 'somethingElse://host.test']; + } + + public static function unsupportedSchemeProvider(): iterable + { + yield ['somethingElse://user:pass@host.test?some_option=88']; + } + + public function createFactory(): JoliNotifTransportFactory + { + return new JoliNotifTransportFactory(); + } +} diff --git a/src/Symfony/Component/Notifier/Bridge/JoliNotif/Tests/JoliNotifTransportTest.php b/src/Symfony/Component/Notifier/Bridge/JoliNotif/Tests/JoliNotifTransportTest.php new file mode 100644 index 0000000000000..13beaa46fb074 --- /dev/null +++ b/src/Symfony/Component/Notifier/Bridge/JoliNotif/Tests/JoliNotifTransportTest.php @@ -0,0 +1,52 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Notifier\Bridge\JoliNotif\Tests; + +use Joli\JoliNotif\DefaultNotifier as JoliNotifier; +use Symfony\Component\Notifier\Bridge\JoliNotif\JoliNotifOptions; +use Symfony\Component\Notifier\Bridge\JoliNotif\JoliNotifTransport; +use Symfony\Component\Notifier\Message\ChatMessage; +use Symfony\Component\Notifier\Message\DesktopMessage; +use Symfony\Component\Notifier\Test\TransportTestCase; +use Symfony\Component\Notifier\Tests\Transport\DummyMessage; +use Symfony\Contracts\HttpClient\HttpClientInterface; + +/** + * @author Ahmed Ghanem + */ +final class JoliNotifTransportTest extends TransportTestCase +{ + public static function toStringProvider(): iterable + { + yield ['jolinotif://localhost', self::createTransport()]; + } + + public static function createTransport(?HttpClientInterface $client = null): JoliNotifTransport + { + return new JoliNotifTransport(new JoliNotifier()); + } + + public static function supportedMessagesProvider(): iterable + { + $message = new DesktopMessage('Worker Status', 'Task#2 has finished successfully'); + + $message->setOptions((new JoliNotifOptions())->setIconPath('/path/to/notification/icon')); + + yield [$message]; + } + + public static function unsupportedMessagesProvider(): iterable + { + yield [new ChatMessage('Hello!')]; + yield [new DummyMessage()]; + } +} diff --git a/src/Symfony/Component/Notifier/Bridge/JoliNotif/composer.json b/src/Symfony/Component/Notifier/Bridge/JoliNotif/composer.json new file mode 100644 index 0000000000000..6cf229a903447 --- /dev/null +++ b/src/Symfony/Component/Notifier/Bridge/JoliNotif/composer.json @@ -0,0 +1,38 @@ +{ + "name": "symfony/joli-notif-notifier", + "type": "symfony-notifier-bridge", + "description": "Symfony JoliNotif Notifier Bridge", + "keywords": [ + "joli-notif", + "desktop-notifications", + "notifier" + ], + "homepage": "https://symfony.com", + "license": "MIT", + "authors": [ + { + "name": "Ahmed Ghanem", + "email": "ahmedghanem7361@gmail.com", + "homepage": "https://github.com/ahmedghanem00" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "require": { + "php": ">=8.2", + "jolicode/jolinotif": "^2.7.2", + "symfony/http-client": "^7.2", + "symfony/notifier": "^7.2" + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Notifier\\Bridge\\JoliNotif\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "minimum-stability": "dev" +} diff --git a/src/Symfony/Component/Notifier/Bridge/JoliNotif/phpunit.xml.dist b/src/Symfony/Component/Notifier/Bridge/JoliNotif/phpunit.xml.dist new file mode 100644 index 0000000000000..018d59bae1ff6 --- /dev/null +++ b/src/Symfony/Component/Notifier/Bridge/JoliNotif/phpunit.xml.dist @@ -0,0 +1,31 @@ + + + + + + + + + + ./Tests/ + + + + + + ./ + + + ./Resources + ./Tests + ./vendor + + + diff --git a/src/Symfony/Component/Notifier/CHANGELOG.md b/src/Symfony/Component/Notifier/CHANGELOG.md index 11d6954372cca..4c5843021fa71 100644 --- a/src/Symfony/Component/Notifier/CHANGELOG.md +++ b/src/Symfony/Component/Notifier/CHANGELOG.md @@ -1,6 +1,11 @@ CHANGELOG ========= +7.2 +--- + + * Add `Desktop` channel + 6.3 --- diff --git a/src/Symfony/Component/Notifier/Channel/DesktopChannel.php b/src/Symfony/Component/Notifier/Channel/DesktopChannel.php new file mode 100644 index 0000000000000..649634ea83c2f --- /dev/null +++ b/src/Symfony/Component/Notifier/Channel/DesktopChannel.php @@ -0,0 +1,47 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Notifier\Channel; + +use Symfony\Component\Notifier\Message\DesktopMessage; +use Symfony\Component\Notifier\Notification\DesktopNotificationInterface; +use Symfony\Component\Notifier\Notification\Notification; +use Symfony\Component\Notifier\Recipient\RecipientInterface; + +/** + * @author Ahmed Ghanem + */ +class DesktopChannel extends AbstractChannel +{ + public function notify(Notification $notification, RecipientInterface $recipient, ?string $transportName = null): void + { + if ($notification instanceof DesktopNotificationInterface) { + $message = $notification->asDesktopMessage($recipient, $transportName); + } + + $message ??= DesktopMessage::fromNotification($notification); + + if (null !== $transportName) { + $message->setTransport($transportName); + } + + if (null === $this->bus) { + $this->transport->send($message); + } else { + $this->bus->dispatch($message); + } + } + + public function supports(Notification $notification, RecipientInterface $recipient): bool + { + return true; + } +} diff --git a/src/Symfony/Component/Notifier/Exception/UnsupportedSchemeException.php b/src/Symfony/Component/Notifier/Exception/UnsupportedSchemeException.php index feecb383bf7d4..99915ab8f36db 100644 --- a/src/Symfony/Component/Notifier/Exception/UnsupportedSchemeException.php +++ b/src/Symfony/Component/Notifier/Exception/UnsupportedSchemeException.php @@ -112,6 +112,10 @@ class UnsupportedSchemeException extends LogicException 'class' => Bridge\Isendpro\IsendproTransportFactory::class, 'package' => 'symfony/isendpro-notifier', ], + 'jolinotif' => [ + 'class' => Bridge\JoliNotif\JoliNotifTransportFactory::class, + 'package' => 'symfony/joli-notif-notifier', + ], 'kaz-info-teh' => [ 'class' => Bridge\KazInfoTeh\KazInfoTehTransportFactory::class, 'package' => 'symfony/kaz-info-teh-notifier', diff --git a/src/Symfony/Component/Notifier/Message/DesktopMessage.php b/src/Symfony/Component/Notifier/Message/DesktopMessage.php new file mode 100644 index 0000000000000..9b1f9edf4b69b --- /dev/null +++ b/src/Symfony/Component/Notifier/Message/DesktopMessage.php @@ -0,0 +1,119 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Notifier\Message; + +use Symfony\Component\Notifier\Notification\Notification; + +/** + * @author Ahmed Ghanem + */ +class DesktopMessage implements MessageInterface, FromNotificationInterface +{ + private ?string $transport = null; + private ?Notification $notification = null; + + public function __construct( + private string $subject, + private string $content, + private ?MessageOptionsInterface $options = null, + ) { + } + + public static function fromNotification(Notification $notification): self + { + $message = new self($notification->getSubject(), $notification->getContent()); + + $message->setNotification($notification); + + return $message; + } + + public function getSubject(): string + { + return $this->subject; + } + + public function getContent(): string + { + return $this->content; + } + + public function getRecipientId(): ?string + { + return $this->options?->getRecipientId(); + } + + /** + * @return $this + */ + public function setSubject(string $subject): static + { + $this->subject = $subject; + + return $this; + } + + /** + * @return $this + */ + public function setContent(string $content): static + { + $this->content = $content; + + return $this; + } + + /** + * @return $this + */ + public function setOptions(MessageOptionsInterface $options): static + { + $this->options = $options; + + return $this; + } + + public function getOptions(): ?MessageOptionsInterface + { + return $this->options; + } + + public function getTransport(): ?string + { + return $this->transport; + } + + /** + * @return $this + */ + public function setTransport(string $transport): static + { + $this->transport = $transport; + + return $this; + } + + public function getNotification(): ?Notification + { + return $this->notification; + } + + /** + * @return $this + */ + public function setNotification(Notification $notification): static + { + $this->notification = $notification; + + return $this; + } +} diff --git a/src/Symfony/Component/Notifier/Notification/DesktopNotificationInterface.php b/src/Symfony/Component/Notifier/Notification/DesktopNotificationInterface.php new file mode 100644 index 0000000000000..c474b3876f079 --- /dev/null +++ b/src/Symfony/Component/Notifier/Notification/DesktopNotificationInterface.php @@ -0,0 +1,23 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Notifier\Notification; + +use Symfony\Component\Notifier\Message\DesktopMessage; +use Symfony\Component\Notifier\Recipient\RecipientInterface; + +/** + * @author Ahmed Ghanem + */ +interface DesktopNotificationInterface +{ + public function asDesktopMessage(RecipientInterface $recipient, ?string $transport = null): ?DesktopMessage; +} diff --git a/src/Symfony/Component/Notifier/Tests/Message/DesktopMessageTest.php b/src/Symfony/Component/Notifier/Tests/Message/DesktopMessageTest.php new file mode 100644 index 0000000000000..6021202a8ee09 --- /dev/null +++ b/src/Symfony/Component/Notifier/Tests/Message/DesktopMessageTest.php @@ -0,0 +1,67 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Notifier\Tests\Message; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\Notifier\Message\DesktopMessage; +use Symfony\Component\Notifier\Notification\Notification; + +/** + * @author Ahmed Ghanem + */ +class DesktopMessageTest extends TestCase +{ + public function testCanBeConstructed() + { + $message = new DesktopMessage('Hello', 'World'); + + $this->assertSame('Hello', $message->getSubject()); + $this->assertSame('World', $message->getContent()); + } + + public function testSetSubject() + { + $message = new DesktopMessage('Hello', 'World'); + + $message->setSubject('dlrow olleH'); + + $this->assertSame('dlrow olleH', $message->getSubject()); + } + + public function testSetContent() + { + $message = new DesktopMessage('Hello', 'World'); + + $message->setContent('dlrow olleH'); + + $this->assertSame('dlrow olleH', $message->getContent()); + } + + public function testSetTransport() + { + $message = new DesktopMessage('Hello', 'World'); + + $message->setTransport('next_one'); + + $this->assertSame('next_one', $message->getTransport()); + } + + public function testCreateFromNotification() + { + $notification = (new Notification('Hello'))->content('World'); + $message = DesktopMessage::fromNotification($notification); + + $this->assertSame('Hello', $message->getSubject()); + $this->assertSame('World', $message->getContent()); + $this->assertSame($notification, $message->getNotification()); + } +} diff --git a/src/Symfony/Component/Notifier/Transport.php b/src/Symfony/Component/Notifier/Transport.php index 92b84b7c9ea70..b4df0729f40d0 100644 --- a/src/Symfony/Component/Notifier/Transport.php +++ b/src/Symfony/Component/Notifier/Transport.php @@ -52,6 +52,7 @@ final class Transport Bridge\Infobip\InfobipTransportFactory::class, Bridge\Iqsms\IqsmsTransportFactory::class, Bridge\Isendpro\IsendproTransportFactory::class, + Bridge\JoliNotif\JoliNotifTransportFactory::class, Bridge\KazInfoTeh\KazInfoTehTransportFactory::class, Bridge\LightSms\LightSmsTransportFactory::class, Bridge\LineNotify\LineNotifyTransportFactory::class, pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy