Skip to content

Commit 9ec8205

Browse files
committed
initial commit: add Laravel SmsApi Notification Channel with configuration, exceptions, and tests
0 parents  commit 9ec8205

20 files changed

+1219
-0
lines changed

.gitignore

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
/vendor/
2+
composer.lock
3+
.env
4+
.env.testing
5+
build
6+
.phpunit.cache
7+
.idea

README.md

Lines changed: 232 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,232 @@
1+
# Laravel SmsApi Notification Channel
2+
3+
[![Latest Version on Packagist](https://img.shields.io/packagist/v/webxscripts/laravel-smsapi-notification-channel.svg?style=flat-square)](https://packagist.org/packages/webxscripts/laravel-smsapi-notification-channel)
4+
[![GitHub Tests Action Status](https://img.shields.io/github/actions/workflow/status/webxscripts/laravel-smsapi-notification-channel/run-tests.yml?branch=main&label=tests&style=flat-square)](https://github.com/webxscripts/laravel-smsapi-notification-channel/actions?query=workflow%3Arun-tests+branch%3Amain)
5+
[![GitHub Code Style Action Status](https://img.shields.io/github/actions/workflow/status/webxscripts/laravel-smsapi-notification-channel/fix-php-code-style-issues.yml?branch=main&label=code%20style&style=flat-square)](https://github.com/webxscripts/laravel-smsapi-notification-channel/actions?query=workflow%3A"Fix+PHP+code+style+issues"+branch%3Amain)
6+
[![Total Downloads](https://img.shields.io/packagist/dt/webxscripts/laravel-smsapi-notification-channel.svg?style=flat-square)](https://packagist.org/packages/webxscripts/laravel-smsapi-notification-channel)
7+
8+
Modern Laravel Notification Channel for SmsApi PHP Client with support for Laravel 11+ and PHP 8.2+.
9+
10+
## Features
11+
12+
- 🚀 **Modern PHP 8.2+ features** - Readonly classes, named arguments, match expressions
13+
- 📱 **Full SmsApi support** - All SmsApi features including templates, parameters, and delivery options
14+
- 🔧 **Type-safe** - Full type hints and PHPStan level 8 compliance
15+
- 🧪 **Well tested** - Comprehensive test suite with Pest PHP
16+
- 🎯 **Laravel 11+ optimized** - Built specifically for modern Laravel versions
17+
- 🔒 **Immutable messages** - Thread-safe message building with fluent interface
18+
- 📋 **Multiple phone resolution methods** - Flexible ways to get phone numbers from notifiables
19+
20+
## Installation
21+
22+
```bash
23+
composer require webxscripts/laravel-smsapi-notification-channel
24+
```
25+
26+
Publish the configuration file:
27+
28+
```bash
29+
php artisan vendor:publish --tag=smsapi-config
30+
```
31+
32+
## Configuration
33+
34+
Add these environment variables to your `.env` file:
35+
36+
```env
37+
SMSAPI_TOKEN=your_api_token_here
38+
SMSAPI_SERVICE=com
39+
SMSAPI_FROM=YourApp
40+
```
41+
42+
### Available Services
43+
44+
- `com` - SMSAPI.COM (international, default)
45+
- `pl` - SMSAPI.PL (Poland)
46+
47+
For SMSAPI.SE or SMSAPI.BG, use:
48+
```env
49+
SMSAPI_SERVICE=com
50+
SMSAPI_URI=https://api.smsapi.se/
51+
```
52+
53+
## Usage
54+
55+
### Basic Usage
56+
57+
Create a notification:
58+
59+
```bash
60+
php artisan make:notification OrderConfirmation
61+
```
62+
63+
Implement the `toSmsApi` method:
64+
65+
```php
66+
<?php
67+
68+
namespace App\Notifications;
69+
70+
use Illuminate\Notifications\Notification;
71+
use WebXScripts\SmsApiNotification\SmsApiMessage;
72+
73+
class OrderConfirmation extends Notification
74+
{
75+
public function __construct(
76+
private readonly string $orderNumber
77+
) {}
78+
79+
public function via($notifiable): array
80+
{
81+
return ['smsapi'];
82+
}
83+
84+
public function toSmsApi($notifiable): SmsApiMessage
85+
{
86+
return SmsApiMessage::create("Your order #{$this->orderNumber} has been confirmed!")
87+
->from('MyShop');
88+
}
89+
}
90+
```
91+
92+
### Advanced Usage with All Options
93+
94+
```php
95+
public function toSmsApi($notifiable): SmsApiMessage
96+
{
97+
return SmsApiMessage::create('Your verification code: 123456')
98+
->from('MyApp')
99+
->encoding('utf-8')
100+
->test(app()->environment('testing'))
101+
->fast(true)
102+
->normalize(true)
103+
->single(false)
104+
->expirationDate(now()->addMinutes(5))
105+
->notifyUrl('https://example.com/sms-delivery-report')
106+
->template('verification_code')
107+
->param1($this->code)
108+
->param2($notifiable->name);
109+
}
110+
```
111+
112+
### Phone Number Resolution
113+
114+
The channel resolves phone numbers in this priority order:
115+
116+
1. **SmsApiNotifiable interface** (recommended):
117+
```php
118+
use WebXScripts\SmsApiNotification\Contracts\SmsApiNotifiable;
119+
120+
class User extends Model implements SmsApiNotifiable
121+
{
122+
public function getSmsApiPhoneNumber(): string
123+
{
124+
return $this->phone_number;
125+
}
126+
}
127+
```
128+
129+
2. **Notification routing method**:
130+
```php
131+
class User extends Model
132+
{
133+
public function routeNotificationForSmsApi(): string
134+
{
135+
return $this->phone_number;
136+
}
137+
}
138+
```
139+
140+
3. **Generic SMS routing method**:
141+
```php
142+
public function routeNotificationForSms(): string
143+
{
144+
return $this->phone;
145+
}
146+
```
147+
148+
4. **Model attributes**: `phone` or `phone_number`
149+
150+
### Sending Notifications
151+
152+
```php
153+
use App\Notifications\OrderConfirmation;
154+
155+
// Single user
156+
$user = User::find(1);
157+
$user->notify(new OrderConfirmation('ORD-12345'));
158+
159+
// Multiple users
160+
$users = User::whereNotNull('phone')->get();
161+
Notification::send($users, new OrderConfirmation('ORD-12345'));
162+
163+
// On-demand notifications
164+
Notification::route('smsapi', '+48123456789')
165+
->notify(new OrderConfirmation('ORD-12345'));
166+
```
167+
168+
## Available Message Methods
169+
170+
All methods return a new immutable instance:
171+
172+
```php
173+
SmsApiMessage::create('content')
174+
->from(string $sender) // Sender name/number
175+
->encoding(string $encoding) // Message encoding (default: utf-8)
176+
->test(bool $test) // Test mode
177+
->fast(bool $fast) // Fast delivery
178+
->normalize(bool $normalize) // Normalize phone numbers
179+
->noUnicode(bool $noUnicode) // Disable unicode
180+
->single(bool $single) // Send as single message
181+
->notifyUrl(string $url) // Delivery report webhook URL
182+
->expirationDate(DateTimeInterface $date) // Message expiration
183+
->timeRestriction(string $restriction) // Time-based delivery restrictions
184+
->partnerId(string $partnerId) // Partner ID
185+
->checkIdx(bool $checkIdx) // Validate IDX
186+
->idx(array $idx) // IDX array for external tracking
187+
->template(string $template) // Template name
188+
->param1(string $param) // Template parameter 1
189+
->param2(string $param) // Template parameter 2
190+
->param3(string $param) // Template parameter 3
191+
->param4(string $param); // Template parameter 4
192+
```
193+
194+
## Error Handling
195+
196+
The package includes specific exceptions:
197+
198+
```php
199+
use WebXScripts\SmsApiNotification\Exceptions\{
200+
InvalidNotificationException,
201+
MissingApiTokenException,
202+
MissingPhoneNumberException
203+
};
204+
205+
try {
206+
$user->notify(new OrderConfirmation('ORD-12345'));
207+
} catch (MissingPhoneNumberException $e) {
208+
Log::warning('User has no phone number', ['user' => $user->id]);
209+
} catch (MissingApiTokenException $e) {
210+
Log::error('SmsApi token not configured');
211+
}
212+
```
213+
214+
## Testing
215+
216+
```bash
217+
# Run tests
218+
composer test
219+
220+
# Run tests with coverage
221+
composer test-coverage
222+
223+
# Format code
224+
composer format
225+
226+
# Analyze code
227+
composer analyse
228+
```
229+
230+
## License
231+
232+
The MIT License (MIT). Please see [License File](LICENSE.md) for more information.

composer.json

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
{
2+
"name": "webxscripts/laravel-smsapi-notification-channel",
3+
"description": "Modern Laravel Notification Channel for SmsApi PHP Client",
4+
"keywords": [
5+
"sms",
6+
"notification",
7+
"laravel",
8+
"smsapi",
9+
"channel"
10+
],
11+
"homepage": "https://github.com/WebXScripts/laravel-smsapi-notification-channel",
12+
"license": "MIT",
13+
"version": "1.0.0",
14+
"authors": [
15+
{
16+
"name": "WebXScripts",
17+
"email": "nevobusiness@gmail.com",
18+
"homepage": "https://webxscripts.ovh"
19+
}
20+
],
21+
"require": {
22+
"php": "^8.2",
23+
"illuminate/notifications": "^11.0|^12.0",
24+
"illuminate/support": "^11.0|^12.0",
25+
"smsapi/php-client": "^3.0"
26+
},
27+
"require-dev": {
28+
"orchestra/testbench": "^9.0|^10.0",
29+
"phpunit/phpunit": "^10.0|^11.0",
30+
"phpstan/phpstan": "^1.10",
31+
"laravel/pint": "^1.0",
32+
"pestphp/pest": "^2.0",
33+
"pestphp/pest-plugin-laravel": "^2.0",
34+
"mockery/mockery": "^1.6"
35+
},
36+
"autoload": {
37+
"psr-4": {
38+
"WebXScripts\\SmsApiNotification\\": "src/"
39+
}
40+
},
41+
"autoload-dev": {
42+
"psr-4": {
43+
"WebXScripts\\SmsApiNotification\\Tests\\": "tests/"
44+
}
45+
},
46+
"extra": {
47+
"laravel": {
48+
"providers": [
49+
"WebXScripts\\SmsApiNotification\\SmsApiNotificationServiceProvider"
50+
]
51+
}
52+
},
53+
"config": {
54+
"sort-packages": true,
55+
"allow-plugins": {
56+
"pestphp/pest-plugin": true
57+
}
58+
},
59+
"scripts": {
60+
"test": "pest",
61+
"test:unit": "pest tests/Unit",
62+
"test:feature": "pest tests/Feature",
63+
"test:coverage": "pest --coverage --min=80",
64+
"test:coverage-html": "pest --coverage-html=build/coverage",
65+
"format": "pint",
66+
"format:test": "pint --test",
67+
"analyse": "phpstan analyse --memory-limit=2G",
68+
"analyse:baseline": "phpstan analyse --generate-baseline",
69+
"check": [
70+
"@format:test",
71+
"@analyse",
72+
"@test"
73+
],
74+
"fix": [
75+
"@format",
76+
"@test"
77+
]
78+
},
79+
"minimum-stability": "stable",
80+
"prefer-stable": true
81+
}

config/smsapi.php

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
return [
6+
/*
7+
|--------------------------------------------------------------------------
8+
| SmsApi API Token
9+
|--------------------------------------------------------------------------
10+
|
11+
| Your SmsApi API token. You can get it from your SmsApi dashboard.
12+
| https://ssl.smsapi.com/ or https://ssl.smsapi.pl/
13+
|
14+
*/
15+
'api_token' => env('SMSAPI_TOKEN'),
16+
17+
/*
18+
|--------------------------------------------------------------------------
19+
| SmsApi Service
20+
|--------------------------------------------------------------------------
21+
|
22+
| The SmsApi service to use:
23+
| - 'com' for SMSAPI.COM (international)
24+
| - 'pl' for SMSAPI.PL (Poland)
25+
|
26+
*/
27+
'service' => env('SMSAPI_SERVICE', 'com'),
28+
29+
/*
30+
|--------------------------------------------------------------------------
31+
| Custom SmsApi URI
32+
|--------------------------------------------------------------------------
33+
|
34+
| Custom URI for SmsApi service (optional).
35+
| For SMSAPI.SE: https://api.smsapi.se/
36+
| For SMSAPI.BG: https://api.smsapi.bg/
37+
|
38+
*/
39+
'uri' => env('SMSAPI_URI'),
40+
41+
/*
42+
|--------------------------------------------------------------------------
43+
| Default Sender Name
44+
|--------------------------------------------------------------------------
45+
|
46+
| Default sender name for SMS messages. This can be overridden
47+
| per message using the from() method on SmsApiMessage.
48+
|
49+
*/
50+
'from' => env('SMSAPI_FROM'),
51+
];

phpstan.neon

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
parameters:
2+
level: 8
3+
paths:
4+
- src
5+
- tests
6+
tmpDir: build/phpstan
7+
checkOctaneCompatibility: true
8+
checkModelProperties: true
9+
checkMissingIterableValueType: false

0 commit comments

Comments
 (0)