├── LICENSE.md
├── README.md
├── composer.json
├── config
└── vonage.php
└── src
├── Channels
└── VonageSmsChannel.php
├── Facades
└── Vonage.php
├── Messages
└── VonageMessage.php
├── Vonage.php
└── VonageChannelServiceProvider.php
/LICENSE.md:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) Taylor Otwell
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in
13 | all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | THE SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Laravel Vonage Notification Channel
2 |
3 |
4 |
5 |
6 |
7 |
8 | ## Official Documentation
9 |
10 | Documentation for Laravel Vonage Notification Channel can be found on the [Laravel website](https://laravel.com/docs/notifications#sms-notifications).
11 |
12 | ## Contributing
13 |
14 | Thank you for considering contributing to Vonage Notification Channel! The contribution guide can be found in the [Laravel documentation](https://laravel.com/docs/contributions).
15 |
16 | ## Code of Conduct
17 |
18 | In order to ensure that the Laravel community is welcoming to all, please review and abide by the [Code of Conduct](https://laravel.com/docs/contributions#code-of-conduct).
19 |
20 | ## Security Vulnerabilities
21 |
22 | Please review [our security policy](https://github.com/laravel/vonage-notification-channel/security/policy) on how to report security vulnerabilities.
23 |
24 | ## License
25 |
26 | Laravel Vonage Notification Channel is open-sourced software licensed under the [MIT license](LICENSE.md).
27 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "laravel/vonage-notification-channel",
3 | "description": "Vonage Notification Channel for laravel.",
4 | "keywords": ["laravel", "notifications", "vonage", "nexmo"],
5 | "license": "MIT",
6 | "authors": [
7 | {
8 | "name": "Taylor Otwell",
9 | "email": "taylor@laravel.com"
10 | }
11 | ],
12 | "require": {
13 | "php": "^8.0",
14 | "illuminate/notifications": "^8.0|^9.0|^10.0|^11.0|^12.0",
15 | "illuminate/support": "^8.0|^9.0|^10.0|^11.0|^12.0",
16 | "vonage/client-core": "^4.0.4"
17 | },
18 | "require-dev": {
19 | "guzzlehttp/guzzle": "^7.2",
20 | "mockery/mockery": "^1.0",
21 | "orchestra/testbench": "^6.0|^7.0|^8.0|^9.0|^10.0",
22 | "phpstan/phpstan": "^1.10",
23 | "phpunit/phpunit": "^9.0|^10.4|^11.5"
24 | },
25 | "autoload": {
26 | "psr-4": {
27 | "Illuminate\\Notifications\\": "src/"
28 | }
29 | },
30 | "autoload-dev": {
31 | "psr-4": {
32 | "Illuminate\\Notifications\\Tests\\": "tests/"
33 | }
34 | },
35 | "config": {
36 | "sort-packages": true,
37 | "allow-plugins": {
38 | "composer/package-versions-deprecated": true
39 | }
40 | },
41 | "extra": {
42 | "branch-alias": {
43 | "dev-master": "3.x-dev"
44 | },
45 | "laravel": {
46 | "providers": [
47 | "Illuminate\\Notifications\\VonageChannelServiceProvider"
48 | ],
49 | "aliases": {
50 | "Vonage": "Illuminate\\Notifications\\Facades\\Vonage"
51 | }
52 | }
53 | },
54 | "minimum-stability": "dev",
55 | "prefer-stable": true
56 | }
57 |
--------------------------------------------------------------------------------
/config/vonage.php:
--------------------------------------------------------------------------------
1 | env('VONAGE_SMS_FROM'),
17 |
18 | /*
19 | |--------------------------------------------------------------------------
20 | | API Credentials
21 | |--------------------------------------------------------------------------
22 | |
23 | | The following configuration options contain your API credentials, which
24 | | may be accessed from your Vonage dashboard. These credentials may be
25 | | used to authenticate with the Vonage API so you may send messages.
26 | |
27 | */
28 |
29 | 'api_key' => env('VONAGE_KEY'),
30 |
31 | 'api_secret' => env('VONAGE_SECRET'),
32 |
33 | 'application_id' => env('VONAGE_APPLICATION_ID'),
34 |
35 | /*
36 | |--------------------------------------------------------------------------
37 | | Signature Secret
38 | |--------------------------------------------------------------------------
39 | |
40 | | If your application is receiving webhooks from Vonage, you may wish to
41 | | configure a message signature secret so that you can ensure each of
42 | | the inbound webhook calls are actually originating within Vonage.
43 | |
44 | */
45 |
46 | 'signature_secret' => env('VONAGE_SIGNATURE_SECRET'),
47 |
48 | /*
49 | |--------------------------------------------------------------------------
50 | | Private Key
51 | |--------------------------------------------------------------------------
52 | |
53 | | Some of Vonage's recent APIs utilize JWTs for authentication, which also
54 | | require a private key so that they may be signed. You may define your
55 | | application's private key string below via the configuration value.
56 | |
57 | */
58 |
59 | 'private_key' => env('VONAGE_PRIVATE_KEY'),
60 |
61 | /*
62 | |--------------------------------------------------------------------------
63 | | Application Identifiers
64 | |--------------------------------------------------------------------------
65 | |
66 | | Adding an application name and version may assist you in identifying
67 | | problems with your application or when viewing analytics for your
68 | | application's API usage within the dedicated Vonage dashboards.
69 | |
70 | */
71 |
72 | 'app' => [
73 | 'name' => env('VONAGE_APP_NAME', 'Laravel'),
74 | 'version' => env('VONAGE_APP_VERSION', '1.1.2'),
75 | ],
76 |
77 | ];
78 |
--------------------------------------------------------------------------------
/src/Channels/VonageSmsChannel.php:
--------------------------------------------------------------------------------
1 | from = $from;
36 | $this->client = $client;
37 | }
38 |
39 | /**
40 | * Send the given notification.
41 | *
42 | * @param mixed $notifiable
43 | * @param \Illuminate\Notifications\Notification $notification
44 | * @return \Vonage\SMS\Collection|null
45 | */
46 | public function send($notifiable, Notification $notification)
47 | {
48 | if (! $to = $notifiable->routeNotificationFor('vonage', $notification)) {
49 | return;
50 | }
51 |
52 | $message = $notification->toVonage($notifiable);
53 |
54 | if (is_string($message)) {
55 | $message = new VonageMessage($message);
56 | }
57 |
58 | $vonageSms = new SMS(
59 | $to,
60 | $message->from ?: $this->from,
61 | trim($message->content),
62 | $message->type
63 | );
64 |
65 | $vonageSms->setClientRef($message->clientReference);
66 |
67 | if ($message->statusCallback) {
68 | $vonageSms->setDeliveryReceiptCallback($message->statusCallback);
69 | }
70 |
71 | return ($message->client ?? $this->client)->sms()->send($vonageSms);
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/src/Facades/Vonage.php:
--------------------------------------------------------------------------------
1 | content = $content;
58 | }
59 |
60 | /**
61 | * Set the message content.
62 | *
63 | * @param string $content
64 | * @return $this
65 | */
66 | public function content($content)
67 | {
68 | $this->content = $content;
69 |
70 | return $this;
71 | }
72 |
73 | /**
74 | * Set the phone number the message should be sent from.
75 | *
76 | * @param string $from
77 | * @return $this
78 | */
79 | public function from($from)
80 | {
81 | $this->from = $from;
82 |
83 | return $this;
84 | }
85 |
86 | /**
87 | * Set the message type.
88 | *
89 | * @return $this
90 | */
91 | public function unicode()
92 | {
93 | $this->type = 'unicode';
94 |
95 | return $this;
96 | }
97 |
98 | /**
99 | * Set the client reference (up to 40 characters).
100 | *
101 | * @param string $clientReference
102 | * @return $this
103 | */
104 | public function clientReference($clientReference)
105 | {
106 | $this->clientReference = $clientReference;
107 |
108 | return $this;
109 | }
110 |
111 | /**
112 | * Set the webhook callback URL to update the message status.
113 | *
114 | * @param string $callback
115 | * @return $this
116 | */
117 | public function statusCallback(string $callback)
118 | {
119 | $this->statusCallback = $callback;
120 |
121 | return $this;
122 | }
123 |
124 | /**
125 | * Set the Vonage client instance.
126 | *
127 | * @param \Vonage\Client $client
128 | * @return $this
129 | */
130 | public function usingClient($client)
131 | {
132 | $this->client = $client;
133 |
134 | return $this;
135 | }
136 | }
137 |
--------------------------------------------------------------------------------
/src/Vonage.php:
--------------------------------------------------------------------------------
1 | config = $config;
40 | $this->client = $client;
41 | }
42 |
43 | /**
44 | * Create a new Vonage instance.
45 | *
46 | * @param array $config
47 | * @param \Psr\Http\Client\ClientInterface|null $client
48 | * @return static
49 | */
50 | public static function make(array $config, ?ClientInterface $client = null)
51 | {
52 | return new static($config, $client);
53 | }
54 |
55 | /**
56 | * Create a new Vonage Client.
57 | *
58 | * @return \Vonage\Client
59 | *
60 | * @throws \RuntimeException
61 | */
62 | public function client()
63 | {
64 | $privateKeyCredentials = null;
65 |
66 | if ($privateKey = $this->config['private_key'] ?? null) {
67 | if (! $appId = $this->config['application_id'] ?? null) {
68 | throw new RuntimeException('You must provide a vonage.application_id when using a private key.');
69 | }
70 |
71 | $privateKeyCredentials = new Keypair($this->loadPrivateKey($privateKey), $appId);
72 | }
73 |
74 | $basicCredentials = null;
75 |
76 | if ($apiSecret = $this->config['api_secret'] ?? null) {
77 | $basicCredentials = new Basic($this->config['api_key'], $apiSecret);
78 | }
79 |
80 | $signatureCredentials = null;
81 |
82 | if ($signatureSecret = $this->config['signature_secret'] ?? null) {
83 | $signatureCredentials = new SignatureSecret($this->config['api_key'], $signatureSecret, $this->config['signature_method'] ?? 'md5hash');
84 | }
85 |
86 | if ($basicCredentials && $signatureCredentials) {
87 | throw new RuntimeException('Provide either vonage.api_secret or vonage.signature_secret, not both.');
88 | }
89 |
90 | if ($privateKeyCredentials && $basicCredentials) {
91 | $credentials = new Container($privateKeyCredentials, $basicCredentials);
92 | } elseif ($privateKeyCredentials && $signatureCredentials) {
93 | $credentials = new Container($privateKeyCredentials, $signatureCredentials);
94 | } elseif ($privateKeyCredentials) {
95 | $credentials = $privateKeyCredentials;
96 | } elseif ($signatureCredentials) {
97 | $credentials = $signatureCredentials;
98 | } elseif ($basicCredentials) {
99 | $credentials = $basicCredentials;
100 | } else {
101 | $combinations = [
102 | 'api_key + api_secret',
103 | 'api_key + signature_secret',
104 | 'private_key + application_id',
105 | 'api_key + api_secret + private_key + application_id',
106 | 'api_key + signature_secret + private_key + application_id',
107 | ];
108 |
109 | throw new RuntimeException(
110 | 'Please provide your Vonage API credentials. Possible combinations: '
111 | .join(', ', $combinations)
112 | );
113 | }
114 |
115 | return new Client($credentials, $this->config, $this->client);
116 | }
117 |
118 | /**
119 | * Load the private key contents from the root directory of the application.
120 | *
121 | * @return string
122 | */
123 | protected function loadPrivateKey($key)
124 | {
125 | if (Str::startsWith($key, '-----BEGIN PRIVATE KEY-----')) {
126 | return $key;
127 | }
128 |
129 | if (! Str::startsWith($key, '/')) {
130 | $key = base_path($key);
131 | }
132 |
133 | return trim(file_get_contents($key));
134 | }
135 | }
136 |
--------------------------------------------------------------------------------
/src/VonageChannelServiceProvider.php:
--------------------------------------------------------------------------------
1 | mergeConfigFrom(__DIR__.'/../config/vonage.php', 'vonage');
21 |
22 | $this->app->singleton(Client::class, function ($app) {
23 | $config = $app['config']['vonage'];
24 |
25 | $httpClient = null;
26 |
27 | if ($httpClient = $config['http_client'] ?? null) {
28 | $httpClient = $app->make($httpClient);
29 | } elseif (! class_exists('GuzzleHttp\Client')) {
30 | throw new RuntimeException(
31 | 'The Vonage client requires a "psr/http-client-implementation" class such as Guzzle.'
32 | );
33 | }
34 |
35 | return Vonage::make($app['config']['vonage'], $httpClient)->client();
36 | });
37 |
38 | $this->app->bind(VonageSmsChannel::class, function ($app) {
39 | return new VonageSmsChannel(
40 | $app->make(Client::class),
41 | $app['config']['vonage.sms_from']
42 | );
43 | });
44 |
45 | Notification::resolved(function (ChannelManager $service) {
46 | $service->extend('vonage', function ($app) {
47 | return $app->make(VonageSmsChannel::class);
48 | });
49 | });
50 | }
51 |
52 | /**
53 | * Bootstrap the application services.
54 | *
55 | * @return void
56 | */
57 | public function boot()
58 | {
59 | if ($this->app->runningInConsole()) {
60 | $this->publishes([
61 | __DIR__.'/../config/vonage.php' => $this->app->configPath('vonage.php'),
62 | ], 'vonage');
63 | }
64 | }
65 | }
66 |
--------------------------------------------------------------------------------