Skip to content

Commit 6d95716

Browse files
committed
add Laravel Notification WhatsAppChannel
1 parent 1324971 commit 6d95716

File tree

6 files changed

+224
-16
lines changed

6 files changed

+224
-16
lines changed

src/Exceptions/CouldNotSendNotification.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,10 @@
22

33
namespace NotificationChannels\WhatsApp\Exceptions;
44

5-
class CouldNotSendNotification extends \Exception
5+
final class CouldNotSendNotification extends \Exception
66
{
7-
public static function serviceRespondedWithAnError($response)
7+
public static function serviceRespondedWithAnError($responseBody)
88
{
9-
return new static("Descriptive error message.");
9+
return new self($responseBody);
1010
}
1111
}

src/WhatsAppChannel.php

Lines changed: 35 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,30 +2,52 @@
22

33
namespace NotificationChannels\WhatsApp;
44

5-
use NotificationChannels\WhatsApp\Exceptions\CouldNotSendNotification;
65
use Illuminate\Notifications\Notification;
6+
use Netflie\WhatsAppCloudApi\Response;
7+
use Netflie\WhatsAppCloudApi\Response\ResponseException;
8+
use Netflie\WhatsAppCloudApi\WhatsAppCloudApi;
9+
use NotificationChannels\WhatsApp\Exceptions\CouldNotSendNotification;
710

811
class WhatsAppChannel
912
{
10-
public function __construct()
13+
/*
14+
* HTTP WhatsApp Cloud API wrapper
15+
*/
16+
private WhatsAppCloudApi $whatsapp;
17+
18+
public function __construct(WhatsAppCloudApi $whatsapp)
1119
{
12-
// Initialisation code here
20+
$this->whatsapp = $whatsapp;
1321
}
1422

1523
/**
1624
* Send the given notification.
17-
*
18-
* @param mixed $notifiable
19-
* @param \Illuminate\Notifications\Notification $notification
20-
*
21-
* @throws \NotificationChannels\WhatsApp\Exceptions\CouldNotSendNotification
2225
*/
23-
public function send($notifiable, Notification $notification)
26+
public function send($notifiable, Notification $notification): ?Response
2427
{
25-
//$response = [a call to the api of your notification send]
28+
// @phpstan-ignore-next-line
29+
$message = $notification->toWhatsApp($notifiable);
30+
31+
if (!$message->hasRecipient()) {
32+
$to = $notifiable->routeNotificationFor('whatsapp', $notification)
33+
?? $notifiable->routeNotificationFor(self::class, $notification);
34+
35+
if (!$to) {
36+
return null;
37+
}
38+
39+
$message->to($to);
40+
}
2641

27-
// if ($response->error) { // replace this by the code need to check for errors
28-
// throw CouldNotSendNotification::serviceRespondedWithAnError($response);
29-
// }
42+
try {
43+
return $this->whatsapp->sendTemplate(
44+
$message->recipient(),
45+
$message->configuredName(),
46+
$message->configuredLanguage(),
47+
$message->components()
48+
);
49+
} catch (ResponseException $e) {
50+
throw CouldNotSendNotification::serviceRespondedWithAnError($e->response()->body());
51+
}
3052
}
3153
}

tests/Support/DummyNotifiable.php

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<?php
2+
3+
namespace NotificationChannels\WhatsApp\Test\Support;
4+
5+
class DummyNotifiable
6+
{
7+
use \Illuminate\Notifications\Notifiable;
8+
9+
public function routeNotificationForWhatsApp()
10+
{
11+
return '0123456789';
12+
}
13+
}

tests/Support/DummyNotification.php

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<?php
2+
3+
namespace NotificationChannels\WhatsApp\Test\Support;
4+
5+
use Illuminate\Notifications\Notification;
6+
use NotificationChannels\WhatsApp\WhatsAppTemplate;
7+
8+
class DummyNotification extends Notification
9+
{
10+
public function toWhatsApp($notifiable): WhatsAppTemplate
11+
{
12+
return WhatsAppTemplate::create()
13+
->name('invoice_created')
14+
->to('34678741298');
15+
}
16+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<?php
2+
3+
namespace NotificationChannels\WhatsApp\Test\Support;
4+
5+
use Illuminate\Notifications\Notification;
6+
use NotificationChannels\WhatsApp\WhatsAppTemplate;
7+
8+
class DummyNotificationWithoutRecipient extends Notification
9+
{
10+
public function toWhatsApp($notifiable): WhatsAppTemplate
11+
{
12+
return WhatsAppTemplate::create()
13+
->name('invoice_created');
14+
}
15+
}

tests/WhatsAppChannelTest.php

Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
<?php
2+
3+
namespace NotificationChannels\WhatsApp\Test;
4+
5+
use Illuminate\Notifications\Notifiable;
6+
use Illuminate\Notifications\Notification;
7+
use Netflie\WhatsAppCloudApi\Http\ClientHandler;
8+
use Netflie\WhatsAppCloudApi\Http\RawResponse;
9+
use Netflie\WhatsAppCloudApi\WhatsAppCloudApi;
10+
use NotificationChannels\WhatsApp\Exceptions\CouldNotSendNotification;
11+
use NotificationChannels\WhatsApp\Test\Support\DummyNotifiable;
12+
use NotificationChannels\WhatsApp\Test\Support\DummyNotification;
13+
use NotificationChannels\WhatsApp\Test\Support\DummyNotificationWithoutRecipient;
14+
use NotificationChannels\WhatsApp\WhatsAppChannel;
15+
use PHPUnit\Framework\TestCase;
16+
17+
final class WhatsAppChannelTest extends TestCase
18+
{
19+
private ClientHandler $httpClient;
20+
21+
private WhatsAppCloudApi $whatsapp;
22+
23+
private WhatsAppChannel $channel;
24+
25+
public function setUp(): void
26+
{
27+
parent::setUp();
28+
29+
$this->httpClient = \Mockery::mock(ClientHandler::class);
30+
31+
$this->whatsapp = new WhatsAppCloudApi([
32+
'from_phone_number_id' => '34676202545',
33+
'access_token' => 'super-secret',
34+
'client_handler' => $this->httpClient,
35+
]);
36+
$this->channel = new WhatsAppChannel($this->whatsapp);
37+
}
38+
39+
/** @test */
40+
public function it_can_send_a_notification()
41+
{
42+
$notifiable = $this->getMockForTrait(Notifiable::class);
43+
$notification = new DummyNotification();
44+
45+
$body = [
46+
'messaging_product' => 'whatsapp',
47+
'recipient_type' => 'individual',
48+
'to' => $notification->toWhatsApp($notifiable)->recipient(),
49+
'type' => 'template',
50+
'template' => [
51+
'name' => $notification->toWhatsApp($notifiable)->configuredName(),
52+
'language' => ['code' => $notification->toWhatsApp($notifiable)->configuredLanguage()],
53+
'components' => [],
54+
],
55+
];
56+
$headers = [
57+
'Authorization' => 'Bearer super-secret',
58+
'Content-Type' => 'application/json',
59+
];
60+
$expectedResponse = new RawResponse($headers, json_encode($body), 200);
61+
62+
$response = $this->sendMockNotification($notifiable, $notification, $expectedResponse);
63+
64+
$this->assertEquals(json_encode($body), $response->body());
65+
$this->assertEquals(200, $response->httpStatusCode());
66+
$this->assertNotEmpty($notification->toWhatsApp($notifiable)->recipient());
67+
$this->assertNotEmpty($notification->toWhatsApp($notifiable)->configuredName());
68+
$this->assertNotEmpty($notification->toWhatsApp($notifiable)->configuredLanguage());
69+
}
70+
71+
/** @test */
72+
public function it_can_send_a_notification_if_notifiable_provide_a_recipient_from_route()
73+
{
74+
$notifiable = new DummyNotifiable();
75+
$notification = new DummyNotificationWithoutRecipient();
76+
77+
$body = [
78+
'messaging_product' => 'whatsapp',
79+
'recipient_type' => 'individual',
80+
'to' => $notifiable->routeNotificationForWhatsApp(),
81+
'type' => 'template',
82+
'template' => [
83+
'name' => $notification->toWhatsApp($notifiable)->configuredName(),
84+
'language' => ['code' => $notification->toWhatsApp($notifiable)->configuredLanguage()],
85+
'components' => [],
86+
],
87+
];
88+
$headers = [
89+
'Authorization' => 'Bearer super-secret',
90+
'Content-Type' => 'application/json',
91+
];
92+
$expectedResponse = new RawResponse($headers, json_encode($body), 200);
93+
94+
$response = $this->sendMockNotification($notifiable, $notification, $expectedResponse);
95+
96+
$this->assertEquals(json_encode($body), $response->body());
97+
$this->assertEquals(200, $response->httpStatusCode());
98+
$this->assertNotEmpty($body['to']);
99+
$this->assertNotEmpty($notification->toWhatsApp($notifiable)->configuredName());
100+
$this->assertNotEmpty($notification->toWhatsApp($notifiable)->configuredLanguage());
101+
}
102+
103+
/** @test */
104+
public function it_does_not_send_a_notification_if_the_notifiable_does_not_provide_a_recipient()
105+
{
106+
$notifiable = $this->getMockForTrait(Notifiable::class);
107+
$notification = new DummyNotificationWithoutRecipient();
108+
109+
$httpClient = \Mockery::mock(ClientHandler::class);
110+
$httpClient->shouldNotHaveReceived('send');
111+
112+
$response = $this->channel->send($notifiable, $notification);
113+
114+
$this->assertNull($response);
115+
}
116+
117+
/** @test */
118+
public function send_notification_failed()
119+
{
120+
$notifiable = $this->getMockForTrait(Notifiable::class);
121+
$notification = new DummyNotification();
122+
$expectedResponse = new RawResponse([], json_encode(['error' => true]), 500);
123+
124+
$this->expectException(CouldNotSendNotification::class);
125+
$response = $this->sendMockNotification($notifiable, $notification, $expectedResponse);
126+
127+
$this->assertNull($response);
128+
}
129+
130+
private function sendMockNotification(
131+
$notifiable,
132+
Notification $notification,
133+
RawResponse $expectedResponse
134+
) {
135+
$this->httpClient
136+
->shouldReceive('send')
137+
->once()
138+
->andReturns($expectedResponse);
139+
140+
return $this->channel->send($notifiable, $notification);
141+
}
142+
}

0 commit comments

Comments
 (0)