Xenon LaravelBDSms

repository·master·Indexed 41 days ago

https://github.com/arif98741/laravelbdsms

A specialized SMS gateway package for the Laravel framework designed for sending text messages to Bangladeshi mobile numbers. It supports multiple local providers, custom gateway configuration, and asynchronous sending via Laravel queues. Features include a Sender object for advanced control, a Logger facade for database logs, and integration with Discord webhooks for transmission reporting.

Tokens
22.2K
Snippets
57
Records
70
Agent score
95%

What's inside LaravelBDSms

  1. The Sender class uses a Singleton pattern

    master

    The Sender class is implemented as a Singleton to ensure efficient resource management and consistent state throughout a single request lifecycle. This allows for easy provider switching and centralized configuration management.

    Key methods in the Sender singleton:

    • getInstance(): Retrieves the singleton instance.
    • setProvider($class): Sets the active provider.
    • setConfig($config): Sets the provider configuration.
    • setMobile($mobile): Sets the recipient number.
    • setMessage($message): Sets the message content.
    • setQueue($bool): Toggles queue usage.
    • send(): Executes the sending process.
    class Sender
    {
        private static $instance = null;
    
        public static function getInstance(): Sender
        {
            if (!File::exists(config_path('sms.php'))) {
                throw new RenderException("missing config/sms.php...");
            }
    
            if (!isset(self::$instance)) {
                self::$instance = new self;
            }
    
            return self::$instance;
        }
    }
  2. How the SMS sending flow works

    master

    When you call SMS::shoot($number, $text), the following sequence occurs:

    1. Resolution: The SMS class resolves the Sender singleton, which is pre-configured with your default provider from config/sms.php.
    2. Configuration: The Sender is updated with the target mobile number and the message text.
    3. Validation: The Sender validates that the configuration, mobile number, and message are present. The specific provider then validates its own required configuration keys.
    4. Request Construction: The provider builds the API query parameters and creates a Request object.
    5. Execution: The Request object checks if queuing is enabled. If enabled, it dispatches a SendSmsJob; otherwise, it executes the HTTP request immediately via Guzzle.
    6. Reporting: The provider's generateReport() method formats the API response into a standardized JSON structure.
    7. Logging: If sms_log is enabled in your config, the system logs the transaction to the database (via Logger::createLog()) and/or the Laravel logs.
    8. Response: A JSON response is returned containing the status, provider, timestamp, mobile, and message.
  3. Understand the LaravelBDSms architecture

    master

    The package is organized into four distinct layers that handle the lifecycle of an SMS request:

    1. Facades Layer: Provides high-level access via SMS, Logger, and Request facades.
    2. Service Layer: The SMS class acts as the primary entry point for developers, offering methods like shoot() and via().
    3. Core Layer: Uses a Sender singleton to manage the state of a single SMS request (mobile number, message, provider, and configuration).
    4. Provider Layer: Implements the ProviderRoadmap interface. Each provider (e.g., Ssl, BoomCast, Infobip) is responsible for building API parameters and executing the sendRequest() method.

    Requests are ultimately processed through an HTTP Layer using a Request class that wraps GuzzleHTTP to communicate with SMS Gateway APIs.

  4. Publish Configuration and Migrations

    master

    After installation, publish the package's configuration file (config/sms.php) and the database migration for logging by running the following Artisan command:

    php artisan vendor:publish --provider="Xenon\LaravelBDSms\LaravelBDSmsServiceProvider"

    If you intend to use the database logging feature, you must also run the migrations:

    php artisan migrate
    php artisan vendor:publish --provider="Xenon\LaravelBDSms\LaravelBDSmsServiceProvider"
    php artisan migrate
  5. Queue SMS for asynchronous sending

    master

    The shootWithQueue() method allows you to send SMS asynchronously using Laravel's queue system. This includes automatic retries on failure.

    Basic Usage: Uses default settings (3 retries, 60 second backoff).

    Advanced Usage: Allows specifying a custom queue name, maximum retry attempts, and backoff duration.

    Worker Setup: To process the queued SMS, run the queue worker:

    php artisan queue:work --queue=sms_queue
    use Xenon\LaravelBDSms\Facades\SMS;
    use Xenon\LaravelBDSms\Provider\BoomCast;
    
    // Basic queue
    SMS::shootWithQueue('017XXXXXXXXX', 'Queued message');
    
    // Advanced queue settings
    SMS::shootWithQueue(
        '017XXXXXXXXX',    // Mobile number
        'Message text',     // Message
        'high_priority',    // Queue name
        10,                 // Max retry attempts
        300                 // Backoff in seconds
    );
    
    // Queued with provider selection
    SMS::via(BoomCast::class)->shootWithQueue(
        '017XXXXXXXXX',
        'Urgent message',
        'urgent_sms',
        5,
        30
    );
  6. Integrate a Custom Gateway

    master

    Use the CustomGateway provider to integrate any SMS API not natively supported. You can configure the URL, HTTP method, headers, and payload via the Sender instance.

    Key Methods:

    • setProvider(string $class)
    • setUrl(string $url)
    • setMethod(string $method) (e.g., post, get)
    • setConfig(array $config)
    • setHeaders(array $headers, bool $isJson = false)
    • setQueue(bool $enabled)
    • setQueueName(string $name)
    • setTries(int $count)
    • setBackoff(int $seconds)
    • send(): Executes the request.
    use Xenon\LaravelBDSms\Sender;
    use Xenon\LaravelBDSms\Provider\CustomGateway;
    
    $sender = Sender::getInstance();
    
    $sender->setProvider(CustomGateway::class)
           ->setUrl('https://api.yoursmsgateway.com/send')
           ->setMethod('post')
           ->setConfig([
               'api_key' => 'your_api_key',
               'sender_id' => 'YourBrand',
               'to' => '017XXXXXXXXX',
               'message' => 'Hello World!',
           ]);
    
    $response = $sender->send();
  7. Install Xenon—LaravelBDSms

    master

    Follow these steps to integrate the SMS gateway into your Laravel project:

    1. Require the package via Composer:

      composer require xenon/laravelbdsms
    2. Publish configuration and migrations:

      php artisan vendor:publish --provider=Xenon\LaravelBDSms\LaravelBDSmsServiceProvider --tag="config"
      php artisan vendor:publish --provider=Xenon\LaravelBDSms\LaravelBDSmsServiceProvider --tag="migrations"
      php artisan migrate

      Note: The migration is only required if you plan to use the database log driver.

    3. Configure credentials: Set your preferred gateway in config/sms.php and add the corresponding credentials to your .env file. For example, for the Ssl provider:

      SMS_SSL_API_TOKEN=your_token
      SMS_SSL_SID=your_sid
      SMS_SSL_CSMS_ID=your_csms_id
    4. Refresh config cache:

      php artisan config:cache
    composer require xenon/laravelbdsms
    
    php artisan vendor:publish --provider=Xenon\LaravelBDSms\LaravelBDSmsServiceProvider --tag="config"
    php artisan vendor:publish --provider=Xenon\LaravelBDSms\LaravelBDSmsServiceProvider --tag="migrations"
    php artisan migrate
    
    php artisan config:cache
  8. Register and use a custom provider

    master

    After creating your provider class, register it in config/sms.php under the providers key. You can then use it via the SMS facade using the via() method, or set it as the global default in your .env file.

    Configuration Example (config/sms.php):

    'providers' => [
        MyNewProvider::class => [
            'api_key' => env('SMS_MYNEW_API_KEY', ''),
            'sender_id' => env('SMS_MYNEW_SENDER_ID', ''),
            'type' => env('SMS_MYNEW_TYPE', 'text'),
        ],
    ]

    Usage Example:

    use Xenon\LaravelBDSms\Facades\SMS;
    use Xenon\LaravelBDSms\Provider\MyNewProvider;
    
    // Use a specific provider for this call
    SMS::via(MyNewProvider::class)->shoot('017XXXXXXXXX', 'Hello!');
    use Xenon\LaravelBDSms\Facades\SMS;
    use Xenon\LaravelBDSms\Provider\MyNewProvider;
    
    SMS::via(MyNewProvider::class)->shoot('017XXXXXXXXX', 'Hello!');
  9. Create a custom SMS provider

    master

    To add a new SMS gateway, you must implement the ProviderRoadmap interface. It is recommended to extend AbstractProvider to inherit common functionality like generateReport().

    Implementation Steps:

    1. Implement the Interface: Your class must define getData(), setData(), sendRequest(), generateReport($result, $data), and errorException().
    2. Handle the Request: Inside sendRequest(), use the Sender instance (passed via constructor) to retrieve mobile numbers, messages, and configuration. Use the Request object to execute the API call (e.g., $requestObject->post()).
    3. Validate Configuration: Implement errorException() to check for required keys in the provider's configuration array and throw a RenderException if they are missing.
    4. Register the Provider: Add your class to the providers array in config/sms.php and define its specific configuration keys.
    <?php
    
    namespace Xenon\
    LaravelBDSms\\Provider;
    
    use Xenon\\LaravelBDSms\\Handler\\RenderException;
    use Xenon\\LaravelBDSms\\Request;
    use Xenon\\LaravelBDSms\\Sender;
    
    class MyNewProvider extends AbstractProvider
    {
        private string $apiEndpoint = 'https://api.mynewprovider.com/sms/send';
    
        public function __construct(Sender $sender)
        {
            $this->senderObject = $sender;
        }
    
        public function sendRequest()
        {
            $mobile = $this->senderObject->getMobile();
            $text = $this->senderObject->getMessage();
            $config = $this->senderObject->getConfig();
            
            $query = [
                'api_key' => $config['api_key'],
                'sender_id' => $config['sender_id'],
                'recipient' => $mobile,
                'message' => $text,
                'type' => $config['type'] ?? 'text',
            ];
    
            $requestObject = new Request(
                $this->apiEndpoint,
                $query,
                $this->senderObject->getQueue(),
                [],
                $this->senderObject->getQueueName(),
                $this->senderObject->getTries(),
                $this->senderObject->getBackoff()
            );
    
            $response = $requestObject->post();
            // ... process response
        }
    
        public function errorException()
        {
            $config = $this->senderObject->getConfig();
            if (!array_key_exists('api_key', $config)) {
                throw new RenderException('api_key is required for MyNewProvider');
            }
        }
    }
  10. Handle SMS exceptions

    master

    When using the SMS facade, you should wrap calls in try-catch blocks to handle specific error types:

    ExceptionDescriptionCommon Causes
    RenderExceptionProvider/configuration errorsMissing config keys, invalid provider
    ParameterExceptionParameter validation errorsEmpty mobile/message, invalid config type
    ValidationExceptionData validation errorsInvalid data format

    Example Implementation:

    use Xenon\LaravelBDSms\Facades\SMS;
    use Xenon\LaravelBDSms\Handler\RenderException;
    use Xenon\LaravelBDSms\Handler\ParameterException;
    
    try {
        $response = SMS::shoot('017XXXXXXXXX', 'Hello World!');
    } catch (RenderException $e) {
        // Handle configuration errors (e.g. missing api_key)
        Log::error('SMS Config Error: ' . $e->getMessage());
    } catch (ParameterException $e) {
        // Handle parameter errors (e.g. empty message)
        Log::error('SMS Parameter Error: ' . $e->getMessage());
    } catch (\Exception $e) {
        // Handle all other errors
        Log::error('SMS Error: ' . $e->getMessage());
    }
    try {
        $response = SMS::shoot('017XXXXXXXXX', 'Hello World!');
    } catch (RenderException $e) {
        Log::error('SMS Config Error: ' . $e->getMessage());
    } catch (ParameterException $e) {
        Log::error('SMS Parameter Error: ' . $e->getMessage());
    } catch (\Exception $e) {
        Log::error('SMS Error: ' . $e->getMessage());
    }
  11. Configure the Discord logging driver

    master

    You can send SMS logs to a Discord channel using webhooks. Logs arrive as embeds containing the provider, recipient, status, time, message, and gateway response. Successes appear as green embeds and failures as red.

    1. Create an incoming webhook in your Discord channel via Channel Settings → Integrations → Webhooks.
    2. Set the log_driver to ['discord'] in your configuration.
    3. Add the webhook URL to your .env file.

    Note: Credential values are never sent to Discord; only the names of the config keys used are included. If the webhook fails, the error is logged to storage/logs/laravel.log.

    'log_driver' => ['discord'],
    SMS_LOG_DISCORD_WEBHOOK_URL=https://discord.com/api/webhooks/xxxxx/yyyyy