Skip to content

Commit afcca88

Browse files
JamesHemeryOskarStark
authored andcommitted
[Notifier] [SpotHit] Add the bridge
1 parent 72a82c3 commit afcca88

File tree

11 files changed

+348
-0
lines changed

11 files changed

+348
-0
lines changed

src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,7 @@
126126
use Symfony\Component\Notifier\Bridge\Sinch\SinchTransportFactory;
127127
use Symfony\Component\Notifier\Bridge\Slack\SlackTransportFactory;
128128
use Symfony\Component\Notifier\Bridge\Smsapi\SmsapiTransportFactory;
129+
use Symfony\Component\Notifier\Bridge\SpotHit\SpotHitTransportFactory;
129130
use Symfony\Component\Notifier\Bridge\Telegram\TelegramTransportFactory;
130131
use Symfony\Component\Notifier\Bridge\Twilio\TwilioTransportFactory;
131132
use Symfony\Component\Notifier\Bridge\Zulip\ZulipTransportFactory;
@@ -2236,6 +2237,7 @@ private function registerNotifierConfiguration(array $config, ContainerBuilder $
22362237
AllMySmsTransportFactory::class => 'notifier.transport_factory.allmysms',
22372238
FirebaseTransportFactory::class => 'notifier.transport_factory.firebase',
22382239
FreeMobileTransportFactory::class => 'notifier.transport_factory.freemobile',
2240+
SpotHitTransportFactory::class => 'notifier.transport_factory.spothit',
22392241
OvhCloudTransportFactory::class => 'notifier.transport_factory.ovhcloud',
22402242
SinchTransportFactory::class => 'notifier.transport_factory.sinch',
22412243
ZulipTransportFactory::class => 'notifier.transport_factory.zulip',

src/Symfony/Bundle/FrameworkBundle/Resources/config/notifier_transports.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
use Symfony\Component\Notifier\Bridge\Sinch\SinchTransportFactory;
3434
use Symfony\Component\Notifier\Bridge\Slack\SlackTransportFactory;
3535
use Symfony\Component\Notifier\Bridge\Smsapi\SmsapiTransportFactory;
36+
use Symfony\Component\Notifier\Bridge\SpotHit\SpotHitTransportFactory;
3637
use Symfony\Component\Notifier\Bridge\Telegram\TelegramTransportFactory;
3738
use Symfony\Component\Notifier\Bridge\Twilio\TwilioTransportFactory;
3839
use Symfony\Component\Notifier\Bridge\Zulip\ZulipTransportFactory;
@@ -89,6 +90,10 @@
8990
->parent('notifier.transport_factory.abstract')
9091
->tag('texter.transport_factory')
9192

93+
->set('notifier.transport_factory.spothit', SpotHitTransportFactory::class)
94+
->parent('notifier.transport_factory.abstract')
95+
->tag('texter.transport_factory')
96+
9297
->set('notifier.transport_factory.ovhcloud', OvhCloudTransportFactory::class)
9398
->parent('notifier.transport_factory.abstract')
9499
->tag('texter.transport_factory')
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
CHANGELOG
2+
=========
3+
4+
5.3
5+
---
6+
7+
* Add the bridge
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
Spot-Hit Notifier
2+
=================
3+
4+
Provides [Spot-Hit](https://www.spot-hit.fr/) integration for Symfony Notifier.
5+
6+
#### DSN example
7+
8+
```
9+
SPOTHIT_DSN=spothit://TOKEN@default?from=FROM
10+
```
11+
12+
where:
13+
- `TOKEN` is your Spot-Hit API key
14+
- `FROM` is the custom sender (3-11 letters, default is a 5 digits phone number)
15+
16+
Resources
17+
---------
18+
19+
* [Spot-Hit API doc](https://www.spot-hit.fr/documentation-api).
20+
* [Contributing](https://symfony.com/doc/current/contributing/index.html)
21+
* [Report issues](https://github.com/symfony/symfony/issues) and
22+
[send Pull Requests](https://github.com/symfony/symfony/pulls)
23+
in the [main Symfony repository](https://github.com/symfony/symfony)
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\Notifier\Bridge\SpotHit;
13+
14+
use Symfony\Component\Notifier\Exception\TransportException;
15+
use Symfony\Component\Notifier\Exception\UnsupportedMessageTypeException;
16+
use Symfony\Component\Notifier\Message\MessageInterface;
17+
use Symfony\Component\Notifier\Message\SentMessage;
18+
use Symfony\Component\Notifier\Message\SmsMessage;
19+
use Symfony\Component\Notifier\Transport\AbstractTransport;
20+
use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
21+
use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface;
22+
use Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface;
23+
use Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface;
24+
use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
25+
use Symfony\Contracts\HttpClient\HttpClientInterface;
26+
27+
/**
28+
* @author James Hemery <james@yieldstudio.fr>
29+
*/
30+
final class SpotHitTransport extends AbstractTransport
31+
{
32+
protected const HOST = 'spot-hit.fr';
33+
34+
private $token;
35+
private $from;
36+
37+
public function __construct(string $token, ?string $from = null, HttpClientInterface $client = null, EventDispatcherInterface $dispatcher = null)
38+
{
39+
$this->token = $token;
40+
$this->from = $from;
41+
42+
parent::__construct($client, $dispatcher);
43+
}
44+
45+
public function __toString(): string
46+
{
47+
if (!$this->from) {
48+
return sprintf('spothit://%s', $this->getEndpoint());
49+
}
50+
51+
return sprintf('spothit://%s?from=%s', $this->getEndpoint(), $this->from);
52+
}
53+
54+
public function supports(MessageInterface $message): bool
55+
{
56+
return $message instanceof SmsMessage;
57+
}
58+
59+
/**
60+
* @param MessageInterface|SmsMessage $message
61+
*
62+
* @throws TransportExceptionInterface
63+
* @throws ClientExceptionInterface
64+
* @throws RedirectionExceptionInterface
65+
* @throws ServerExceptionInterface
66+
*/
67+
protected function doSend(MessageInterface $message): SentMessage
68+
{
69+
if (!$this->supports($message)) {
70+
throw new UnsupportedMessageTypeException(__CLASS__, SmsMessage::class, $message);
71+
}
72+
73+
$endpoint = sprintf('https://www.%s/api/envoyer/sms', $this->getEndpoint());
74+
$response = $this->client->request('POST', $endpoint, [
75+
'body' => [
76+
'key' => $this->token,
77+
'destinataires' => $message->getPhone(),
78+
'type' => 'premium',
79+
'message' => $message->getSubject(),
80+
'expediteur' => $this->from,
81+
],
82+
]);
83+
84+
$data = json_decode($response->getContent(), true);
85+
86+
if (!$data['resultat']) {
87+
$errors = \is_array($data['erreurs']) ? implode(',', $data['erreurs']) : $data['erreurs'];
88+
throw new TransportException(sprintf('[HTTP %d] Unable to send the SMS: error(s) "%s".', $response->getStatusCode(), $errors), $response);
89+
}
90+
91+
$sentMessage = new SentMessage($message, (string) $this);
92+
$sentMessage->setMessageId($data['id']);
93+
94+
return $sentMessage;
95+
}
96+
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\Notifier\Bridge\SpotHit;
13+
14+
use Symfony\Component\Notifier\Exception\UnsupportedSchemeException;
15+
use Symfony\Component\Notifier\Transport\AbstractTransportFactory;
16+
use Symfony\Component\Notifier\Transport\Dsn;
17+
use Symfony\Component\Notifier\Transport\TransportInterface;
18+
19+
/**
20+
* @author James Hemery <james@yieldstudio.fr>
21+
*/
22+
final class SpotHitTransportFactory extends AbstractTransportFactory
23+
{
24+
/**
25+
* @return SpotHitTransport
26+
*/
27+
public function create(Dsn $dsn): TransportInterface
28+
{
29+
$scheme = $dsn->getScheme();
30+
31+
if ('spothit' !== $scheme) {
32+
throw new UnsupportedSchemeException($dsn, 'spothit', $this->getSupportedSchemes());
33+
}
34+
35+
$token = $this->getUser($dsn);
36+
$from = $dsn->getOption('from');
37+
$host = 'default' === $dsn->getHost() ? null : $dsn->getHost();
38+
$port = $dsn->getPort();
39+
40+
return (new SpotHitTransport($token, $from, $this->client, $this->dispatcher))->setHost($host)->setPort($port);
41+
}
42+
43+
protected function getSupportedSchemes(): array
44+
{
45+
return ['spothit'];
46+
}
47+
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\Notifier\Bridge\SpotHit\Tests;
13+
14+
use Symfony\Component\Notifier\Bridge\SpotHit\SpotHitTransportFactory;
15+
use Symfony\Component\Notifier\Tests\TransportFactoryTestCase;
16+
use Symfony\Component\Notifier\Transport\TransportFactoryInterface;
17+
18+
final class SpotHitTransportFactoryTest extends TransportFactoryTestCase
19+
{
20+
/**
21+
* @return SpotHitTransportFactory
22+
*/
23+
public function createFactory(): TransportFactoryInterface
24+
{
25+
return new SpotHitTransportFactory();
26+
}
27+
28+
public function createProvider(): iterable
29+
{
30+
yield [
31+
'spothit://spot-hit.fr',
32+
'spothit://api_token@default',
33+
];
34+
yield [
35+
'spothit://spot-hit.fr?from=MyCompany',
36+
'spothit://api_token@default?from=MyCompany',
37+
];
38+
}
39+
40+
public function supportsProvider(): iterable
41+
{
42+
yield [true, 'spothit://api_token@default?from=MyCompany'];
43+
yield [false, 'somethingElse://api_token@default?from=MyCompany'];
44+
}
45+
46+
public function unsupportedSchemeProvider(): iterable
47+
{
48+
yield ['foobar://api_token@default?from=MyCompany'];
49+
yield ['foobar://api_token@default'];
50+
}
51+
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\Notifier\Bridge\SpotHit\Tests;
13+
14+
use Symfony\Component\Notifier\Bridge\SpotHit\SpotHitTransport;
15+
use Symfony\Component\Notifier\Message\ChatMessage;
16+
use Symfony\Component\Notifier\Message\MessageInterface;
17+
use Symfony\Component\Notifier\Message\SmsMessage;
18+
use Symfony\Component\Notifier\Tests\TransportTestCase;
19+
use Symfony\Component\Notifier\Transport\TransportInterface;
20+
use Symfony\Contracts\HttpClient\HttpClientInterface;
21+
22+
final class SpotHitTransportTest extends TransportTestCase
23+
{
24+
/**
25+
* @return SpotHitTransport
26+
*/
27+
public function createTransport(?HttpClientInterface $client = null): TransportInterface
28+
{
29+
return (new SpotHitTransport('api_token', 'MyCompany', $client ?: $this->createMock(HttpClientInterface::class)))->setHost('host.test');
30+
}
31+
32+
public function toStringProvider(): iterable
33+
{
34+
yield ['spothit://host.test?from=MyCompany', $this->createTransport()];
35+
}
36+
37+
public function supportedMessagesProvider(): iterable
38+
{
39+
yield [new SmsMessage('0611223344', 'Hello!')];
40+
yield [new SmsMessage('+33611223344', 'Hello!')];
41+
}
42+
43+
public function unsupportedMessagesProvider(): iterable
44+
{
45+
yield [new ChatMessage('Hello!')];
46+
yield [$this->createMock(MessageInterface::class)];
47+
}
48+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
{
2+
"name": "symfony/spothit-notifier",
3+
"type": "symfony-bridge",
4+
"description": "Symfony Spot-Hit Notifier Bridge",
5+
"keywords": ["sms", "spot-hit", "notifier", "symfony"],
6+
"homepage": "https://symfony.com",
7+
"license": "MIT",
8+
"authors": [
9+
{
10+
"name": "James Hemery",
11+
"homepage": "https://github.com/JamesHemery"
12+
},
13+
{
14+
"name": "Yield Studio",
15+
"homepage": "https://github.com/YieldStudio"
16+
},
17+
{
18+
"name": "Symfony Community",
19+
"homepage": "https://symfony.com/contributors"
20+
}
21+
],
22+
"require": {
23+
"php": ">=7.2.5",
24+
"symfony/http-client": "^4.3|^5.1",
25+
"symfony/notifier": "^5.3"
26+
},
27+
"autoload": {
28+
"psr-4": { "Symfony\\Component\\Notifier\\Bridge\\SpotHit\\": "" },
29+
"exclude-from-classmap": [
30+
"/Tests/"
31+
]
32+
},
33+
"minimum-stability": "dev"
34+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
3+
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xsi:noNamespaceSchemaLocation="http://schema.phpunit.de/5.2/phpunit.xsd"
5+
backupGlobals="false"
6+
colors="true"
7+
bootstrap="vendor/autoload.php"
8+
failOnRisky="true"
9+
failOnWarning="true"
10+
>
11+
<php>
12+
<ini name="error_reporting" value="-1" />
13+
</php>
14+
15+
<testsuites>
16+
<testsuite name="Symfony Spot-Hit Notifier Test Suite">
17+
<directory>./Tests/</directory>
18+
</testsuite>
19+
</testsuites>
20+
21+
<filter>
22+
<whitelist>
23+
<directory>./</directory>
24+
<exclude>
25+
<directory>./Resources</directory>
26+
<directory>./Tests</directory>
27+
<directory>./vendor</directory>
28+
</exclude>
29+
</whitelist>
30+
</filter>
31+
</phpunit>

0 commit comments

Comments
 (0)
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