diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php index 23f000f9026a9..644403f184eca 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php @@ -2804,6 +2804,7 @@ private function registerNotifierConfiguration(array $config, ContainerBuilder $ NotifierBridge\PagerDuty\PagerDutyTransportFactory::class => 'notifier.transport_factory.pager-duty', NotifierBridge\Plivo\PlivoTransportFactory::class => 'notifier.transport_factory.plivo', NotifierBridge\Pushover\PushoverTransportFactory::class => 'notifier.transport_factory.pushover', + NotifierBridge\Pushy\PushyTransportFactory::class => 'notifier.transport_factory.pushy', NotifierBridge\Redlink\RedlinkTransportFactory::class => 'notifier.transport_factory.redlink', NotifierBridge\RingCentral\RingCentralTransportFactory::class => 'notifier.transport_factory.ring-central', NotifierBridge\RocketChat\RocketChatTransportFactory::class => 'notifier.transport_factory.rocket-chat', diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/notifier_transports.php b/src/Symfony/Bundle/FrameworkBundle/Resources/config/notifier_transports.php index c92d9b4b6ca56..07962a1edcee7 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/notifier_transports.php +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/notifier_transports.php @@ -87,6 +87,7 @@ 'ovh-cloud' => Bridge\OvhCloud\OvhCloudTransportFactory::class, 'plivo' => Bridge\Plivo\PlivoTransportFactory::class, 'pushover' => Bridge\Pushover\PushoverTransportFactory::class, + 'pushy' => Bridge\Pushy\PushyTransportFactory::class, 'redlink' => Bridge\Redlink\RedlinkTransportFactory::class, 'ring-central' => Bridge\RingCentral\RingCentralTransportFactory::class, 'sendberry' => Bridge\Sendberry\SendberryTransportFactory::class, diff --git a/src/Symfony/Component/Notifier/Bridge/Pushy/.gitattributes b/src/Symfony/Component/Notifier/Bridge/Pushy/.gitattributes new file mode 100644 index 0000000000000..84c7add058fb5 --- /dev/null +++ b/src/Symfony/Component/Notifier/Bridge/Pushy/.gitattributes @@ -0,0 +1,4 @@ +/Tests export-ignore +/phpunit.xml.dist export-ignore +/.gitattributes export-ignore +/.gitignore export-ignore diff --git a/src/Symfony/Component/Notifier/Bridge/Pushy/.gitignore b/src/Symfony/Component/Notifier/Bridge/Pushy/.gitignore new file mode 100644 index 0000000000000..c49a5d8df5c65 --- /dev/null +++ b/src/Symfony/Component/Notifier/Bridge/Pushy/.gitignore @@ -0,0 +1,3 @@ +vendor/ +composer.lock +phpunit.xml diff --git a/src/Symfony/Component/Notifier/Bridge/Pushy/CHANGELOG.md b/src/Symfony/Component/Notifier/Bridge/Pushy/CHANGELOG.md new file mode 100644 index 0000000000000..5be39cbeeb951 --- /dev/null +++ b/src/Symfony/Component/Notifier/Bridge/Pushy/CHANGELOG.md @@ -0,0 +1,7 @@ +CHANGELOG +========= + +7.1 +--- + + * Add the bridge diff --git a/src/Symfony/Component/Notifier/Bridge/Pushy/Enum/InterruptionLevel.php b/src/Symfony/Component/Notifier/Bridge/Pushy/Enum/InterruptionLevel.php new file mode 100644 index 0000000000000..92ab96a31da15 --- /dev/null +++ b/src/Symfony/Component/Notifier/Bridge/Pushy/Enum/InterruptionLevel.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\Bridge\Pushy\Enum; + +/** + * @author Joseph Bielawski + */ +enum InterruptionLevel: string +{ + case ACTIVE = 'active'; + case CRITICAL = 'critical'; + case PASSIVE = 'passive'; + case TIME_SENSITIVE = 'time-sensitive'; +} diff --git a/src/Symfony/Component/Notifier/Bridge/Pushy/LICENSE b/src/Symfony/Component/Notifier/Bridge/Pushy/LICENSE new file mode 100644 index 0000000000000..e374a5c8339d3 --- /dev/null +++ b/src/Symfony/Component/Notifier/Bridge/Pushy/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/Pushy/PushyOptions.php b/src/Symfony/Component/Notifier/Bridge/Pushy/PushyOptions.php new file mode 100644 index 0000000000000..526c74c2f379b --- /dev/null +++ b/src/Symfony/Component/Notifier/Bridge/Pushy/PushyOptions.php @@ -0,0 +1,191 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Notifier\Bridge\Pushy; + +use Symfony\Component\Notifier\Bridge\Pushy\Enum\InterruptionLevel; +use Symfony\Component\Notifier\Exception\InvalidArgumentException; +use Symfony\Component\Notifier\Message\MessageOptionsInterface; +use Symfony\Component\Notifier\Notification\Notification; + +/** + * @author Joseph Bielawski + * + * @see https://pushy.me/docs/api/send-notifications + */ +final class PushyOptions implements MessageOptionsInterface +{ + public function __construct( + private array $options = [], + ) { + } + + public static function fromNotification(Notification $notification): self + { + $options = new self(); + $options->interruptionLevel( + match ($notification->getImportance()) { + Notification::IMPORTANCE_URGENT => InterruptionLevel::CRITICAL, + Notification::IMPORTANCE_HIGH => InterruptionLevel::TIME_SENSITIVE, + Notification::IMPORTANCE_MEDIUM => InterruptionLevel::ACTIVE, + Notification::IMPORTANCE_LOW => InterruptionLevel::PASSIVE, + } + ); + + return $options; + } + + public function toArray(): array + { + return $this->options; + } + + public function getRecipientId(): ?string + { + return $this->options['to'] ?? null; + } + + /** + * @see https://pushy.me/docs/api/send-notifications#request-schema + * + * @param string|string[] $to + * + * @return $this + */ + public function to(string|array $to): static + { + $this->options['to'] = $to; + + return $this; + } + + /** + * @see https://pushy.me/docs/api/send-notifications#request-schema + * + * @return $this + */ + public function contentAvailable(bool $bool): static + { + $this->options['content_available'] = $bool; + + return $this; + } + + /** + * @see https://pushy.me/docs/api/send-notifications#request-schema + * + * @return $this + */ + public function mutableContent(bool $bool): static + { + $this->options['mutable_content'] = $bool; + + return $this; + } + + /** + * @see https://pushy.me/docs/api/send-notifications#request-schema + * + * @return $this + */ + public function ttl(int $seconds): static + { + if ($seconds > (86400 * 365)) { + throw new InvalidArgumentException('Pushy notification time to live cannot exceed 365 days.'); + } + + $this->options['time_to_live'] = $seconds; + + return $this; + } + + /** + * @see https://pushy.me/docs/api/send-notifications#request-schema + * + * @return $this + */ + public function schedule(int $seconds): static + { + if (false === \DateTime::createFromFormat('U', $seconds)) { + throw new InvalidArgumentException('Pushy notification schedule time must be correct Unix timestamp.'); + } + + if (\DateTime::createFromFormat('U', $seconds) >= new \DateTime('+1 year')) { + throw new InvalidArgumentException('Pushy notification schedule time cannot exceed 1 year.'); + } + + $this->options['schedule'] = $seconds; + + return $this; + } + + /** + * @see https://pushy.me/docs/api/send-notifications#request-schema + * + * @return $this + */ + public function collapseKey(string $collapseKey): static + { + if (32 < \strlen($collapseKey)) { + throw new InvalidArgumentException('Pushy notification collapse key cannot be longer than 32 characters.'); + } + + $this->options['collapse_key'] = $collapseKey; + + return $this; + } + + /** + * @return $this + */ + public function body(string $body): static + { + $this->options['notification']['body'] = $body; + + return $this; + } + + /** + * @see https://pushy.me/docs/api/send-notifications#request-schema + * + * @return $this + */ + public function badge(int $badge): static + { + $this->options['notification']['badge'] = $badge; + + return $this; + } + + /** + * @see https://pushy.me/docs/api/send-notifications#request-schema + * + * @return $this + */ + public function threadId(int $threadId): static + { + $this->options['notification']['thread_id'] = $threadId; + + return $this; + } + + /** + * @see https://pushy.me/docs/api/send-notifications#request-schema + * + * @return $this + */ + public function interruptionLevel(InterruptionLevel $interruptionLevel): static + { + $this->options['notification']['interruption_level'] = $interruptionLevel->value; + + return $this; + } +} diff --git a/src/Symfony/Component/Notifier/Bridge/Pushy/PushyTransport.php b/src/Symfony/Component/Notifier/Bridge/Pushy/PushyTransport.php new file mode 100644 index 0000000000000..611b45b1b05b8 --- /dev/null +++ b/src/Symfony/Component/Notifier/Bridge/Pushy/PushyTransport.php @@ -0,0 +1,95 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Notifier\Bridge\Pushy; + +use Symfony\Component\Notifier\Exception\InvalidArgumentException; +use Symfony\Component\Notifier\Exception\TransportException; +use Symfony\Component\Notifier\Exception\UnsupportedMessageTypeException; +use Symfony\Component\Notifier\Message\MessageInterface; +use Symfony\Component\Notifier\Message\PushMessage; +use Symfony\Component\Notifier\Message\SentMessage; +use Symfony\Component\Notifier\Transport\AbstractTransport; +use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; +use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface; +use Symfony\Contracts\HttpClient\HttpClientInterface; + +/** + * @author Joseph Bielawski + */ +final class PushyTransport extends AbstractTransport +{ + protected const HOST = 'api.pushy.me'; + + public function __construct( + #[\SensitiveParameter] private readonly string $apiKey, + ?HttpClientInterface $client = null, + ?EventDispatcherInterface $dispatcher = null, + ) { + parent::__construct($client, $dispatcher); + } + + public function supports(MessageInterface $message): bool + { + return $message instanceof PushMessage && (null === $message->getOptions() || $message->getOptions() instanceof PushyOptions); + } + + public function __toString(): string + { + return sprintf('pushy://%s', $this->getEndpoint()); + } + + protected function doSend(MessageInterface $message): SentMessage + { + if (!$message instanceof PushMessage) { + throw new UnsupportedMessageTypeException(__CLASS__, PushMessage::class, $message); + } + + $options = $message->getOptions()?->toArray() ?? []; + $options['data'] = $message->getContent(); + $options['notification']['title'] = $message->getSubject(); + $options['to'] ??= $message->getRecipientId(); + + if (!$options['to']) { + throw new InvalidArgumentException(sprintf('The "%s" transport required the "to" option to be set.', __CLASS__)); + } + + $endpoint = sprintf('https://%s?api_key=%s', $this->getEndpoint(), $this->apiKey); + $response = $this->client->request('POST', $endpoint, [ + 'headers' => [ + 'Accept' => 'application/json', + 'Content-Type' => 'application/json', + ], + 'json' => array_filter($options), + ]); + + try { + $statusCode = $response->getStatusCode(); + } catch (TransportExceptionInterface $e) { + throw new TransportException('Could not reach the remote Pushy server.', $response, 0, $e); + } + + if (200 !== $statusCode) { + throw new TransportException(sprintf('Unable to send the Pushy push notification: "%s".', $response->getContent(false)), $response); + } + + $result = $response->toArray(false); + + if (!isset($result['id'])) { + throw new TransportException(sprintf('Unable to find the message ID within the Pushy response: "%s".', $response->getContent(false)), $response); + } + + $sentMessage = new SentMessage($message, (string) $this); + $sentMessage->setMessageId($result['id']); + + return $sentMessage; + } +} diff --git a/src/Symfony/Component/Notifier/Bridge/Pushy/PushyTransportFactory.php b/src/Symfony/Component/Notifier/Bridge/Pushy/PushyTransportFactory.php new file mode 100644 index 0000000000000..e751fc189432f --- /dev/null +++ b/src/Symfony/Component/Notifier/Bridge/Pushy/PushyTransportFactory.php @@ -0,0 +1,41 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Notifier\Bridge\Pushy; + +use Symfony\Component\Notifier\Exception\UnsupportedSchemeException; +use Symfony\Component\Notifier\Transport\AbstractTransportFactory; +use Symfony\Component\Notifier\Transport\Dsn; +use Symfony\Component\Notifier\Transport\TransportInterface; + +/** + * @author Joseph Bielawski + */ +final class PushyTransportFactory extends AbstractTransportFactory +{ + public function create(Dsn $dsn): TransportInterface + { + if ('pushy' !== $dsn->getScheme()) { + throw new UnsupportedSchemeException($dsn, 'pushy', $this->getSupportedSchemes()); + } + + $apiKey = $dsn->getUser(); + $host = 'default' === $dsn->getHost() ? null : $dsn->getHost(); + $port = $dsn->getPort(); + + return (new PushyTransport($apiKey, $this->client, $this->dispatcher))->setHost($host)->setPort($port); + } + + protected function getSupportedSchemes(): array + { + return ['pushy']; + } +} diff --git a/src/Symfony/Component/Notifier/Bridge/Pushy/README.md b/src/Symfony/Component/Notifier/Bridge/Pushy/README.md new file mode 100644 index 0000000000000..34ca24fbb8335 --- /dev/null +++ b/src/Symfony/Component/Notifier/Bridge/Pushy/README.md @@ -0,0 +1,23 @@ +Pushy Notifier +============== + +Provides [Pushy](https://pushy.me/) integration for Symfony Notifier. + +DSN example +----------- + +``` +PUSHY_DSN=pushy://API_KEY@default +``` + +where: + + - `API_KEY` is your application's API key, viewable in Pushy dashboard + +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/Pushy/Tests/PushyOptionsTest.php b/src/Symfony/Component/Notifier/Bridge/Pushy/Tests/PushyOptionsTest.php new file mode 100644 index 0000000000000..9cf5e42c44535 --- /dev/null +++ b/src/Symfony/Component/Notifier/Bridge/Pushy/Tests/PushyOptionsTest.php @@ -0,0 +1,77 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Notifier\Bridge\Pushy\Tests; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\Notifier\Bridge\Pushy\Enum\InterruptionLevel; +use Symfony\Component\Notifier\Bridge\Pushy\PushyOptions; +use Symfony\Component\Notifier\Exception\InvalidArgumentException; + +class PushyOptionsTest extends TestCase +{ + public function testPushyOptions() + { + $options = (new PushyOptions()) + ->to('device') + ->collapseKey('key') + ->schedule($schedule = (time() + 3600)) + ->badge(1) + ->interruptionLevel(InterruptionLevel::TIME_SENSITIVE) + ->body('Hello world!') + ->contentAvailable(false) + ->mutableContent(true) + ->ttl(3600) + ->threadId(123); + + self::assertSame([ + 'to' => 'device', + 'collapse_key' => 'key', + 'schedule' => $schedule, + 'notification' => [ + 'badge' => 1, + 'interruption_level' => 'time-sensitive', + 'body' => 'Hello world!', + 'thread_id' => 123, + ], + 'content_available' => false, + 'mutable_content' => true, + 'time_to_live' => 3600, + ], $options->toArray()); + } + + public function testTimeToLiveTooBig() + { + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('Pushy notification time to live cannot exceed 365 days.'); + + (new PushyOptions()) + ->ttl(86400 * 400); + } + + public function testScheduleTooBig() + { + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('Pushy notification schedule time cannot exceed 1 year.'); + + (new PushyOptions()) + ->schedule(time() + (86400 * 400)); + } + + public function testCollapseKeyTooLong() + { + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('Pushy notification collapse key cannot be longer than 32 characters.'); + + (new PushyOptions()) + ->collapseKey(str_repeat('a', 33)); + } +} diff --git a/src/Symfony/Component/Notifier/Bridge/Pushy/Tests/PushyTransportFactoryTest.php b/src/Symfony/Component/Notifier/Bridge/Pushy/Tests/PushyTransportFactoryTest.php new file mode 100644 index 0000000000000..bf3164ac4ddab --- /dev/null +++ b/src/Symfony/Component/Notifier/Bridge/Pushy/Tests/PushyTransportFactoryTest.php @@ -0,0 +1,39 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Notifier\Bridge\Pushy\Tests; + +use Symfony\Component\Notifier\Bridge\Pushy\PushyTransportFactory; +use Symfony\Component\Notifier\Test\TransportFactoryTestCase; + +final class PushyTransportFactoryTest extends TransportFactoryTestCase +{ + public function createFactory(): PushyTransportFactory + { + return new PushyTransportFactory(); + } + + public static function createProvider(): iterable + { + yield ['pushy://api.pushy.me', 'pushy://apiKey@api.pushy.me']; + } + + public static function supportsProvider(): iterable + { + yield [true, 'pushy://apiKey']; + yield [false, 'somethingElse://apiKey']; + } + + public static function unsupportedSchemeProvider(): iterable + { + yield ['somethingElse://apiKey']; + } +} diff --git a/src/Symfony/Component/Notifier/Bridge/Pushy/Tests/PushyTransportTest.php b/src/Symfony/Component/Notifier/Bridge/Pushy/Tests/PushyTransportTest.php new file mode 100644 index 0000000000000..416e95e251017 --- /dev/null +++ b/src/Symfony/Component/Notifier/Bridge/Pushy/Tests/PushyTransportTest.php @@ -0,0 +1,108 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Notifier\Bridge\Pushy\Tests; + +use Symfony\Component\HttpClient\MockHttpClient; +use Symfony\Component\HttpClient\Response\JsonMockResponse; +use Symfony\Component\Notifier\Bridge\Pushy\PushyOptions; +use Symfony\Component\Notifier\Bridge\Pushy\PushyTransport; +use Symfony\Component\Notifier\Message\ChatMessage; +use Symfony\Component\Notifier\Message\PushMessage; +use Symfony\Component\Notifier\Notification\Notification; +use Symfony\Component\Notifier\Test\TransportTestCase; +use Symfony\Component\Notifier\Tests\Transport\DummyMessage; +use Symfony\Contracts\HttpClient\HttpClientInterface; +use Symfony\Contracts\HttpClient\ResponseInterface; + +final class PushyTransportTest extends TransportTestCase +{ + public static function createTransport(?HttpClientInterface $client = null): PushyTransport + { + return new PushyTransport('apiKey', $client ?? new MockHttpClient()); + } + + public static function toStringProvider(): iterable + { + yield ['pushy://api.pushy.me', self::createTransport()]; + } + + public static function supportedMessagesProvider(): iterable + { + yield [new PushMessage('Hello!', 'World')]; + } + + public static function unsupportedMessagesProvider(): iterable + { + yield [new ChatMessage('Hello!')]; + yield [new DummyMessage()]; + } + + public function testSendWithOptions() + { + $messageSubject = 'testMessageSubject'; + $messageContent = 'testMessageContent'; + + $expectedBody = json_encode([ + 'to' => 'device', + 'data' => $messageContent, + 'notification' => ['title' => $messageSubject], + ]); + + $client = new MockHttpClient(function (string $method, string $url, array $options = []) use ( + $expectedBody + ): ResponseInterface { + $this->assertSame($expectedBody, $options['body']); + + return new JsonMockResponse(['success' => true, 'id' => '123']); + }); + $transport = self::createTransport($client); + + $options = new PushyOptions(); + $options->to('device'); + + $sentMessage = $transport->send(new PushMessage($messageSubject, $messageContent, $options)); + + $this->assertSame('123', $sentMessage->getMessageId()); + } + + public function testSendWithNotification() + { + $messageSubject = 'testMessageSubject'; + $messageContent = 'testMessageContent'; + + $options = new PushyOptions(); + $options->to('device'); + + $notification = (new Notification($messageSubject))->content($messageContent); + $pushMessage = PushMessage::fromNotification($notification); + $pushMessage->options($options); + + $expectedBody = json_encode([ + 'to' => 'device', + 'data' => $messageContent, + 'notification' => ['title' => $messageSubject], + ]); + + $client = new MockHttpClient(function (string $method, string $url, array $options = []) use ( + $expectedBody + ): ResponseInterface { + $this->assertSame($expectedBody, $options['body']); + + return new JsonMockResponse(['success' => true, 'id' => '123']); + }); + $transport = self::createTransport($client); + + $sentMessage = $transport->send($pushMessage); + + $this->assertSame('123', $sentMessage->getMessageId()); + } +} diff --git a/src/Symfony/Component/Notifier/Bridge/Pushy/composer.json b/src/Symfony/Component/Notifier/Bridge/Pushy/composer.json new file mode 100644 index 0000000000000..a1863de2055b8 --- /dev/null +++ b/src/Symfony/Component/Notifier/Bridge/Pushy/composer.json @@ -0,0 +1,37 @@ +{ + "name": "symfony/pushy-notifier", + "type": "symfony-notifier-bridge", + "description": "Symfony Pushy Notifier Bridge", + "keywords": [ + "pushy", + "notifier" + ], + "homepage": "https://symfony.com", + "license": "MIT", + "authors": [ + { + "name": "Joseph Bielawski", + "email": "stloyd@gmail.com", + "homepage": "https://github.com/stloyd" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "require": { + "php": ">=8.2", + "symfony/http-client": "^6.4|^7.0", + "symfony/notifier": "^7.1" + }, + "require-dev": { + "symfony/event-dispatcher": "^6.4|^7.0" + }, + "autoload": { + "psr-4": {"Symfony\\Component\\Notifier\\Bridge\\Pushy\\": ""}, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "minimum-stability": "dev" +} diff --git a/src/Symfony/Component/Notifier/Bridge/Pushy/phpunit.xml.dist b/src/Symfony/Component/Notifier/Bridge/Pushy/phpunit.xml.dist new file mode 100644 index 0000000000000..91633ca9845f1 --- /dev/null +++ b/src/Symfony/Component/Notifier/Bridge/Pushy/phpunit.xml.dist @@ -0,0 +1,31 @@ + + + + + + + + + + ./Tests/ + + + + + + ./ + + ./Resources + ./Tests + ./vendor + + + + diff --git a/src/Symfony/Component/Notifier/Exception/UnsupportedSchemeException.php b/src/Symfony/Component/Notifier/Exception/UnsupportedSchemeException.php index 0d7fa06e65768..fd4054f9fdd4b 100644 --- a/src/Symfony/Component/Notifier/Exception/UnsupportedSchemeException.php +++ b/src/Symfony/Component/Notifier/Exception/UnsupportedSchemeException.php @@ -200,6 +200,10 @@ class UnsupportedSchemeException extends LogicException 'class' => Bridge\Pushover\PushoverTransportFactory::class, 'package' => 'symfony/pushover-notifier', ], + 'pushy' => [ + 'class' => Bridge\Pushy\PushyTransportFactory::class, + 'package' => 'symfony/pushy-notifier', + ], 'redlink' => [ 'class' => Bridge\Redlink\RedlinkTransportFactory::class, 'package' => 'symfony/redlink-notifier', diff --git a/src/Symfony/Component/Notifier/Tests/Exception/UnsupportedSchemeExceptionTest.php b/src/Symfony/Component/Notifier/Tests/Exception/UnsupportedSchemeExceptionTest.php index 7642d2ae17fd6..69253ef560798 100644 --- a/src/Symfony/Component/Notifier/Tests/Exception/UnsupportedSchemeExceptionTest.php +++ b/src/Symfony/Component/Notifier/Tests/Exception/UnsupportedSchemeExceptionTest.php @@ -72,6 +72,7 @@ public static function setUpBeforeClass(): void Bridge\PagerDuty\PagerDutyTransportFactory::class => false, Bridge\Plivo\PlivoTransportFactory::class => false, Bridge\Pushover\PushoverTransportFactory::class => false, + Bridge\Pushy\PushyTransportFactory::class => false, Bridge\Redlink\RedlinkTransportFactory::class => false, Bridge\RingCentral\RingCentralTransportFactory::class => false, Bridge\RocketChat\RocketChatTransportFactory::class => false, diff --git a/src/Symfony/Component/Notifier/Transport.php b/src/Symfony/Component/Notifier/Transport.php index 5b80040bbfafe..5d2ed74058da2 100644 --- a/src/Symfony/Component/Notifier/Transport.php +++ b/src/Symfony/Component/Notifier/Transport.php @@ -74,6 +74,7 @@ final class Transport Bridge\PagerDuty\PagerDutyTransportFactory::class, Bridge\Plivo\PlivoTransportFactory::class, Bridge\Pushover\PushoverTransportFactory::class, + Bridge\Pushy\PushyTransportFactory::class, Bridge\Redlink\RedlinkTransportFactory::class, Bridge\RingCentral\RingCentralTransportFactory::class, Bridge\RocketChat\RocketChatTransportFactory::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