├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── composer.json ├── phpcs.xml ├── phpunit.xml ├── src ├── Facade.php ├── LaravelSMSProvider.php ├── MailAdapter.php └── config.php └── tests ├── ServiceProviderTest.php └── TestCase.php /.gitignore: -------------------------------------------------------------------------------- 1 | *.swp 2 | .DS_Store 3 | vendor/ 4 | composer.lock 5 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: php 2 | 3 | php: 4 | - 7.0 5 | - 7.1 6 | 7 | before_script: 8 | - travis_retry composer self-update 9 | - travis_retry composer install --no-interaction --prefer-source --dev 10 | 11 | script: vendor/bin/phpunit 12 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Matthew Daly 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 all 13 | 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 THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # laravel-sms 2 | [![Build Status](https://travis-ci.org/matthewbdaly/laravel-sms.svg?branch=master)](https://travis-ci.org/matthewbdaly/laravel-sms) 3 | 4 | SMS service provider for Laravel and Lumen. Uses [SMS Client](https://github.com/matthewbdaly/sms-client) to enable sending SMS messages using the following drivers: 5 | 6 | * `nexmo` 7 | * `clockwork` 8 | * `textlocal` 9 | * `twilio` 10 | * `aws` (requires installation of `aws/aws-sdk-php`) 11 | * `mail` (somewhat untested and may be too generic to be much use) 12 | 13 | Also has the following drivers for testing purposes: 14 | 15 | * `log` 16 | * `null` 17 | * `requestbin` 18 | 19 | Installation for Laravel 20 | ------------------------ 21 | 22 | This package is only intended for Laravel 5.5 and up. Install it with the following command: 23 | 24 | ```bash 25 | $ composer require matthewbdaly/laravel-sms 26 | ``` 27 | 28 | Then publish the config file: 29 | 30 | ```bash 31 | $ php artisan vendor:publish 32 | ``` 33 | 34 | You will need to select the service provider `Matthewbdaly\LaravelSMS\LaravelSMSProvider`. Then set your driver and any settings required in the `.env` file for your project: 35 | 36 | ``` 37 | SMS_DRIVER=nexmo 38 | NEXMO_API_KEY=foo 39 | NEXMO_API_SECRET=bar 40 | CLOCKWORK_API_KEY=baz 41 | TEXTLOCAL_API_KEY=baz 42 | REQUESTBIN_PATH=foo 43 | AWS_SNS_API_KEY=foo 44 | AWS_SNS_API_SECRET=bar 45 | AWS_SNS_API_REGION=baz 46 | MAIL_SMS_DOMAIN=my.sms-gateway.com 47 | TWILIO_ACCOUNT_ID=foo 48 | TWILIO_API_TOKEN=bar 49 | ``` 50 | 51 | Installation for Lumen 52 | ---------------------- 53 | 54 | The installation process with Lumen is identical to that for Laravel, although if you wish to use the facade you will need to uncomment the appropriate section of `bootstrap/app.php` as usual. 55 | 56 | Usage 57 | ----- 58 | 59 | Once the package is installed and configured, you can use the facade to send SMS messages: 60 | 61 | ```php 62 | use SMS; 63 | 64 | $msg = [ 65 | 'to' => '+44 01234 567890', 66 | 'content' => 'Just testing', 67 | ]; 68 | SMS::send($msg); 69 | ``` 70 | 71 | Or fetch it from the app: 72 | 73 | ```php 74 | $msg = [ 75 | 'to' => '+44 01234 567890', 76 | 'content' => 'Just testing', 77 | ]; 78 | $sms = app()['sms'] 79 | $sms->send($msg); 80 | ``` 81 | 82 | Or resolve the interface `Matthewbdaly\SMS\Contracts\Client`: 83 | 84 | ```php 85 | $msg = [ 86 | 'to' => '+44 01234 567890', 87 | 'content' => 'Just testing', 88 | ]; 89 | $sms = app()->make('Matthewbdaly\SMS\Contracts\Client'); 90 | $sms->send($msg); 91 | ``` 92 | 93 | Here we use the `app()` helper, but you'll normally want to inject it into a constructor or method of another class. 94 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "matthewbdaly/laravel-sms", 3 | "description": "A Laravel and Lumen integration for matthewbdaly/sms-client to enable sending SMS messages", 4 | "type": "library", 5 | "keywords": ["sms","laravel","lumen"], 6 | "require": { 7 | "matthewbdaly/sms-client": "^1.0" 8 | }, 9 | "require-dev": { 10 | "orchestra/testbench": "3.5", 11 | "phpunit/phpunit": "^6.3", 12 | "mockery/mockery": "^0.9.9", 13 | "squizlabs/php_codesniffer": "^3.1", 14 | "aws/aws-sdk-php": "3.*", 15 | "psy/psysh": "^0.8.11" 16 | }, 17 | "license": "MIT", 18 | "authors": [ 19 | { 20 | "name": "Matthew Daly", 21 | "email": "matthewbdaly@gmail.com" 22 | } 23 | ], 24 | "autoload": { 25 | "psr-4": { 26 | "Matthewbdaly\\LaravelSMS\\": "src/" 27 | } 28 | }, 29 | "autoload-dev": { 30 | "psr-4": { 31 | "Tests\\": "tests/" 32 | } 33 | }, 34 | "extra": { 35 | "laravel": { 36 | "providers": [ 37 | "Matthewbdaly\\LaravelSMS\\LaravelSMSProvider" 38 | ], 39 | "aliases": { 40 | "SMS": "Matthewbdaly\\LaravelSMS\\Facade" 41 | } 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /phpcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | Coding standard for SMS API integration. 4 | src 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /phpunit.xml: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 13 | ./tests 14 | 15 | 16 | 17 | 18 | ./src 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /src/Facade.php: -------------------------------------------------------------------------------- 1 | publishes([ 32 | __DIR__.'/config.php' => config_path('sms.php'), 33 | ]); 34 | } 35 | 36 | /** 37 | * Register the application services. 38 | * 39 | * @return void 40 | */ 41 | public function register() 42 | { 43 | $this->app->singleton('sms', function ($app) { 44 | $config = $app['config']; 45 | switch ($config['sms.default']) { 46 | case 'null': 47 | $driver = new NullDriver( 48 | new GuzzleClient, 49 | new GuzzleResponse 50 | ); 51 | break; 52 | case 'nexmo': 53 | $driver = new Nexmo( 54 | new GuzzleClient, 55 | new GuzzleResponse, 56 | [ 57 | 'api_key' => $config['sms.drivers.nexmo.api_key'], 58 | 'api_secret' => $config['sms.drivers.nexmo.api_secret'], 59 | ] 60 | ); 61 | break; 62 | case 'clockwork': 63 | $driver = new Clockwork( 64 | new GuzzleClient, 65 | new GuzzleResponse, 66 | [ 67 | 'api_key' => $config['sms.drivers.clockwork.api_key'], 68 | ] 69 | ); 70 | break; 71 | case 'textlocal': 72 | $driver = new TextLocal( 73 | new GuzzleClient, 74 | new GuzzleResponse, 75 | [ 76 | 'api_key' => $config['sms.drivers.textlocal.api_key'], 77 | ] 78 | ); 79 | break; 80 | case 'twilio': 81 | $driver = new Twilio( 82 | new GuzzleClient, 83 | new GuzzleResponse, 84 | [ 85 | 'account_id' => $config['sms.drivers.twilio.account_id'], 86 | 'api_token' => $config['sms.drivers.twilio.api_token'], 87 | ] 88 | ); 89 | break; 90 | case 'requestbin': 91 | $driver = new RequestBin( 92 | new GuzzleClient, 93 | new GuzzleResponse, 94 | [ 95 | 'path' => $config['sms.drivers.requestbin.path'], 96 | ] 97 | ); 98 | break; 99 | case 'aws': 100 | $driver = new Aws([ 101 | 'api_key' => $config['sms.drivers.aws.api_key'], 102 | 'api_secret' => $config['sms.drivers.aws.api_secret'], 103 | 'api_region' => $config['sms.drivers.aws.api_region'], 104 | ]); 105 | break; 106 | case 'mail': 107 | $driver = new MailDriver(new MailAdapter, [ 108 | 'domain' => $config['sms.drivers.mail.domain'], 109 | ]); 110 | break; 111 | default: 112 | $driver = new LogDriver( 113 | $app['log'] 114 | ); 115 | break; 116 | } 117 | return new Client($driver); 118 | }); 119 | 120 | $this->app->bind('Matthewbdaly\SMS\Contracts\Client', function ($app) { 121 | return $app['sms']; 122 | }); 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /src/MailAdapter.php: -------------------------------------------------------------------------------- 1 | make('Illuminate\Contracts\Mail\Mailer'); 23 | return $mailer->to($recipient)->raw($message); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/config.php: -------------------------------------------------------------------------------- 1 | env('SMS_DRIVER', 'log'), 17 | 18 | /* 19 | |-------------------------------------------------------------------------- 20 | | Drivers 21 | |-------------------------------------------------------------------------- 22 | | 23 | | Here you can define the settings for each driver. 24 | | 25 | */ 26 | 27 | 'drivers' => [ 28 | 29 | 'clockwork' => [ 30 | 'driver' => 'clockwork', 31 | 'api_key' => env('CLOCKWORK_API_KEY', null), 32 | ], 33 | 34 | 'textlocal' => [ 35 | 'driver' => 'textlocal', 36 | 'api_key' => env('TEXTLOCAL_API_KEY', null), 37 | ], 38 | 39 | 'log' => [ 40 | 'driver' => 'log', 41 | ], 42 | 43 | 'requestbin' => [ 44 | 'path' => env('REQUESTBIN_PATH', null), 45 | ], 46 | 47 | 'nexmo' => [ 48 | 'driver' => 'nexmo', 49 | 'api_key' => env('NEXMO_API_KEY', null), 50 | 'api_secret' => env('NEXMO_API_secret', null), 51 | ], 52 | 53 | 'twilio' => [ 54 | 'driver' => 'twilio', 55 | 'account_id' => env('TWILIO_ACCOUNT_ID', null), 56 | 'api_token' => env('TWILIO_API_TOKEN', null), 57 | ], 58 | 59 | 'aws' => [ 60 | 'driver' => 'aws', 61 | 'api_key' => env('AWS_SNS_API_KEY', null), 62 | 'api_secret' => env('AWS_SNS_API_SECRET', null), 63 | 'api_region' => env('AWS_SNS_API_REGION', null), 64 | ], 65 | 66 | 'mail' => [ 67 | 'domain' => env('MAIL_SMS_DOMAIN', null), 68 | ], 69 | 70 | 'null' => [ 71 | 'driver' => 'null', 72 | ], 73 | ], 74 | ]; 75 | -------------------------------------------------------------------------------- /tests/ServiceProviderTest.php: -------------------------------------------------------------------------------- 1 | app['config']->set('sms.default', 'null'); 13 | $client = $this->app->make('sms'); 14 | $this->assertInstanceOf('Matthewbdaly\SMS\Client', $client); 15 | $this->assertEquals('Null', $client->getDriver()); 16 | } 17 | 18 | public function testDefaultDriverSetup() 19 | { 20 | $client = $this->app->make('sms'); 21 | $this->assertInstanceOf('Matthewbdaly\SMS\Client', $client); 22 | $this->assertEquals('Log', $client->getDriver()); 23 | } 24 | 25 | public function testLogDriverSetup() 26 | { 27 | $this->app['config']->set('sms.default', 'log'); 28 | $client = $this->app->make('sms'); 29 | $this->assertInstanceOf('Matthewbdaly\SMS\Client', $client); 30 | $this->assertEquals('Log', $client->getDriver()); 31 | } 32 | 33 | public function testNexmoDriverSetup() 34 | { 35 | $this->app['config']->set('sms.default', 'nexmo'); 36 | $this->app['config']->set('sms.drivers.nexmo.api_key', 'MY_NEXMO_API_KEY'); 37 | $this->app['config']->set('sms.drivers.nexmo.api_secret', 'MY_NEXMO_API_SECRET'); 38 | $client = $this->app->make('sms'); 39 | $this->assertInstanceOf('Matthewbdaly\SMS\Client', $client); 40 | $this->assertEquals('Nexmo', $client->getDriver()); 41 | } 42 | 43 | public function testClockworkDriverSetup() 44 | { 45 | $this->app['config']->set('sms.default', 'clockwork'); 46 | $this->app['config']->set('sms.drivers.clockwork.api_key', 'MY_CLOCKWORK_API_KEY'); 47 | $client = $this->app->make('sms'); 48 | $this->assertInstanceOf('Matthewbdaly\SMS\Client', $client); 49 | $this->assertEquals('Clockwork', $client->getDriver()); 50 | } 51 | 52 | public function testTextLocalDriverSetup() 53 | { 54 | $this->app['config']->set('sms.default', 'textlocal'); 55 | $this->app['config']->set('sms.drivers.textlocal.api_key', 'MY_TEXTLOCAL_API_KEY'); 56 | $client = $this->app->make('sms'); 57 | $this->assertInstanceOf('Matthewbdaly\SMS\Client', $client); 58 | $this->assertEquals('TextLocal', $client->getDriver()); 59 | } 60 | 61 | public function testRequestBinDriverSetup() 62 | { 63 | $this->app['config']->set('sms.default', 'requestbin'); 64 | $this->app['config']->set('sms.drivers.requestbin.path', 'REQUESTBIN_PATH'); 65 | $client = $this->app->make('sms'); 66 | $this->assertInstanceOf('Matthewbdaly\SMS\Client', $client); 67 | $this->assertEquals('RequestBin', $client->getDriver()); 68 | } 69 | 70 | public function testAwsSnsDriverSetup() 71 | { 72 | $this->app['config']->set('sms.default', 'aws'); 73 | $this->app['config']->set('sms.drivers.aws.api_key', 'MY_AWS_SNS_API_KEY'); 74 | $this->app['config']->set('sms.drivers.aws.api_secret', 'MY_AWS_SNS_API_SECRET'); 75 | $this->app['config']->set('sms.drivers.aws.api_region', 'MY_AWS_SNS_API_REGION'); 76 | $client = $this->app->make('sms'); 77 | $this->assertInstanceOf('Matthewbdaly\SMS\Client', $client); 78 | $this->assertEquals('Aws', $client->getDriver()); 79 | } 80 | 81 | public function testTwilioDriverSetup() 82 | { 83 | $this->app['config']->set('sms.default', 'twilio'); 84 | $this->app['config']->set('sms.drivers.aws.account_id', 'MY_TWILIO_ACCOUNT_ID'); 85 | $this->app['config']->set('sms.drivers.aws.api_token', 'MY_TWILIO_API_TOKEN'); 86 | $client = $this->app->make('sms'); 87 | $this->assertInstanceOf('Matthewbdaly\SMS\Client', $client); 88 | $this->assertEquals('Twilio', $client->getDriver()); 89 | } 90 | 91 | public function testMailDriverSetup() 92 | { 93 | $this->app['config']->set('sms.default', 'mail'); 94 | $this->app['config']->set('sms.drivers.mail.domain', 'my.sms-gateway.com'); 95 | $client = $this->app->make('sms'); 96 | $this->assertInstanceOf('Matthewbdaly\SMS\Client', $client); 97 | $this->assertEquals('Mail', $client->getDriver()); 98 | } 99 | 100 | public function testFacade() 101 | { 102 | $msg = [ 103 | 'to' => '+44 01234 567890', 104 | 'content' => 'Just testing', 105 | ]; 106 | $mock = m::mock('Matthewbdaly\SMS\Client'); 107 | $mock->shouldReceive('send')->with($msg)->once()->andReturn(true); 108 | $this->app->instance('sms', $mock); 109 | $this->assertInstanceOf('Matthewbdaly\SMS\Client', $this->app['sms']); 110 | SMS::send($msg); 111 | } 112 | 113 | public function testInject() 114 | { 115 | $client = $this->app->make('Matthewbdaly\SMS\Contracts\Client'); 116 | $this->assertInstanceOf('Matthewbdaly\SMS\Contracts\Client', $client); 117 | $this->assertInstanceOf('Matthewbdaly\SMS\Client', $client); 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /tests/TestCase.php: -------------------------------------------------------------------------------- 1 | 'Matthewbdaly\LaravelSMS\Facade' 18 | ]; 19 | } 20 | } 21 | --------------------------------------------------------------------------------