Create Service Class
Create app/Services/RoyceBulkSMSService.php:
<?php
namespace App\Services;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Cache;
class RoyceBulkSMSService
{
protected $apiUrl;
protected $apiKey;
protected $senderId;
public function __construct()
{
$this->apiUrl = config('roycebulksms.api_url');
$this->apiKey = config('roycebulksms.api_key');
$this->senderId = config('roycebulksms.sender_id');
}
/**
* Send single SMS
*/
public function sendSMS($phoneNumber, $message, $senderId = null, $callbackUrl = null)
{
try {
$response = Http::withToken($this->apiKey)
->post("{$this->apiUrl}/send/", [
'phone_number' => $this->formatPhoneNumber($phoneNumber),
'text_message' => $message,
'sender_id' => $senderId ?? $this->senderId,
'callback_url' => $callbackUrl,
]);
if ($response->successful()) {
$data = $response->json();
Log::info('SMS sent successfully', [
'message_id' => $data['data']['message_id'] ?? null,
'recipient' => $phoneNumber
]);
return $data;
}
Log::error('SMS sending failed', [
'status' => $response->status(),
'response' => $response->body()
]);
return [
'success' => false,
'error' => $response->json()['error'] ?? 'Failed to send SMS'
];
} catch (\Exception $e) {
Log::error('SMS service exception', [
'message' => $e->getMessage()
]);
return [
'success' => false,
'error' => $e->getMessage()
];
}
}
/**
* Send bulk SMS
*/
public function sendBulkSMS(array $phoneNumbers, $message, $senderId = null)
{
try {
$response = Http::withToken($this->apiKey)
->post("{$this->apiUrl}/send-bulk/", [
'phone_number' => array_map([$this, 'formatPhoneNumber'], $phoneNumbers),
'text_message' => $message,
'sender_id' => $senderId ?? $this->senderId,
]);
if ($response->successful()) {
return $response->json();
}
return [
'success' => false,
'error' => $response->json()['error'] ?? 'Failed to send bulk SMS'
];
} catch (\Exception $e) {
return [
'success' => false,
'error' => $e->getMessage()
];
}
}
/**
* Check account balance
*/
public function checkBalance()
{
return Cache::remember('roycebulksms_balance', 300, function () {
try {
$response = Http::withToken($this->apiKey)
->get("{$this->apiUrl}/balance/");
if ($response->successful()) {
return $response->json();
}
return [
'success' => false,
'error' => 'Failed to fetch balance'
];
} catch (\Exception $e) {
return [
'success' => false,
'error' => $e->getMessage()
];
}
});
}
/**
* Get message status
*/
public function getMessageStatus($messageId)
{
try {
$response = Http::withToken($this->apiKey)
->get("{$this->apiUrl}/messages/{$messageId}/");
if ($response->successful()) {
return $response->json();
}
return [
'success' => false,
'error' => 'Failed to fetch message status'
];
} catch (\Exception $e) {
return [
'success' => false,
'error' => $e->getMessage()
];
}
}
/**
* Format phone number with country code
*/
protected function formatPhoneNumber($phoneNumber)
{
// Remove any spaces, dashes, or parentheses
$phoneNumber = preg_replace('/[\s\-\(\)]/', '', $phoneNumber);
// Add country code if not present
if (!str_starts_with($phoneNumber, '+')) {
$phoneNumber = config('roycebulksms.default_country_code') . ltrim($phoneNumber, '0');
}
return $phoneNumber;
}
/**
* Check if sufficient balance
*/
public function hasSufficientBalance($requiredUnits)
{
$balance = $this->checkBalance();
if ($balance['success'] ?? false) {
$currentBalance = $balance['data']['current_balance'] ?? 0;
return $currentBalance >= $requiredUnits;
}
return false;
}
}
?>