diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..3be69ca --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,24 @@ +# Contributing + +👍 First off, thanks for taking the time to contribute! 👍 + +When contributing to this project, please first discuss the change you wish to make in an [Issue](https://github.com/enricodias/smsdev-php/issues/new). + +## Coding conventions + +- Use the [PSR-12](https://www.php-fig.org/psr/psr-12/) coding style. +- Follow the PHPMD and PHPCS rules when possible. +- Include DocBlocks in new methods, classes and properties. +- Create the appropriate tests for any new feature. +- Update the README.md explaining new or modified features. +- Follow the SOLID principles. + +Please note, if your changes are purely to things like README, CHANGELOG etc, you can add ```[skip ci]``` as the last line of your commit message and your PR won't be run through our continuous integration systems. We ask that you use ```[skip ci]``` where appropriate as it helps to get changes through CI faster and doesn't waste resources kindly donated to the Open Source community. + +## Guidelines for merging + +- Issue 1 Pull Request per feature. Don't lump unrelated changes together. +- Use the present tense ("Add feature" not "Added feature"). +- Use the imperative mood ("Change string to..." not "Changes string to..."). +- Limit the first line to 72 characters or less. +- Reference issues and pull requests liberally after the first line. diff --git a/README.md b/README.md index 6b43c3e..ac9eaea 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,122 @@ # smsdev-php -A PHP library that wraps the smsdev.com.br API + +[![Build Status](https://travis-ci.com/enricodias/smsdev-php.svg?branch=master)](https://travis-ci.com/enricodias/smsdev-php) +[![Code Coverage](https://scrutinizer-ci.com/g/enricodias/smsdev-php/badges/coverage.png?b=master)](https://scrutinizer-ci.com/g/enricodias/smsdev-php/?branch=master) +[![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/enricodias/smsdev-php/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/enricodias/smsdev-php/?branch=master) +[![Latest version](http://img.shields.io/packagist/v/enricodias/smsdev.svg)](https://packagist.org/packages/enricodias/smsdev) +[![Downloads total](http://img.shields.io/packagist/dt/enricodias/smsdev.svg)](https://packagist.org/packages/enricodias/smsdev) +[![License](http://img.shields.io/packagist/l/enricodias/smsdev.svg)](https://github.com/enricodias/smsdev-php/blob/master/LICENSE.md) + +Send and receive SMS using [SmsDev.com.br](https://www.smsdev.com.br) + +## Installation + +Require this package with Composer in the root directory of your project. + +```bash +composer require enricodias/smsdev-php +``` + +## Usage + +Create a new instance with your API key: + +```php +$SmsDev = new \enricodias\SmsDev('API_KEY'); +``` + +Set any date format to be used in all date methods: + +```php +$SmsDev->setDateFormat('Y-m-d H:i:s'); // default is 'U', timestamp +``` + +### Sending an SMS message + +```php +$SmsDev->send(5511988881111, 'SMS Message'); // returns true if the API accepts the message + +var_dump($SmsDev->getResult()); // Returns the raw API response. +``` + +The country code optional. The default is 55 (Brazil). + +### Receiving SMS messages + +Get unread messages in a specific date interval: + +```php +$SmsDev->setFilter() + ->isUnread() + ->dateBetween('2018-01-19', '2019-01-19') + ->fetch(); +``` + +Search for a specific message id: + +```php +$SmsDev->setFilter() + ->byId(2515974) + ->fetch(); +``` + +### Parsing the response + +After fetching the messages you can either access the raw API response using ```getResult()``` or use the function ```parsedMessages()``` to get a simplified array: + +```php +$SmsDev->setDateFormat('U'); // timestamp + +$messages = $SmsDev->parsedMessages(); + +var_dump($messages); + +/* +array(1) { + ['date'] => '1529418914' + ['number'] => '5511988887777' + ['message'] => 'Message' +} +*/ +``` + +Dates are converted to the format specified in ```setDateFormat()```. + +### Date filters + +The following filters are equivalent: + +```php +$SmsDev->setFilter() + ->dateBetween('2018-01-19', '2019-01-19') + ->fetch(); + +$SmsDev->setFilter() + ->dateBetween('2018-01-19', '') + ->dateTo('2019-01-19') + ->fetch(); + +$SmsDev->setFilter() + ->dateBetween('', '2019-01-19') + ->dateFrom('2018-01-19') + ->fetch(); + +$SmsDev->setFilter() + ->dateFrom('2018-01-19') + ->dateTo('2019-01-19') + ->fetch(); +``` + +## Timezone problems + +The API uses the timezone America/Sao_Paulo. Using another timezone in your application will force you to convert dates locally in order to get correct values. + +> Ex: if you are using UTC-4 and receive a new message, it will look like the message came from the future because America/Sao_Paulo is UTC-3. + +This class solves this problem by automatically correcting dates both in search filters and in parsed messages. Only the dates in raw API responses are not converted. + +## TODO + +- Verify phone number locally. +- Check the status of sent messages. +- Send multiple SMS messages. diff --git a/composer.json b/composer.json index c4085f6..398aa09 100644 --- a/composer.json +++ b/composer.json @@ -2,7 +2,7 @@ "name": "enricodias/smsdev", "type": "library", "license": "MIT", - "description": "A wrapper to the SmsDev.com.br API.", + "description": "Send and receive SMS using SmsDev.com.br", "keywords": ["smsdev", "sms"], "authors": [ { diff --git a/src/SmsDev.php b/src/SmsDev.php index f5415f4..d462327 100644 --- a/src/SmsDev.php +++ b/src/SmsDev.php @@ -5,22 +5,68 @@ use GuzzleHttp\Client; use GuzzleHttp\Psr7\Request; +/** + * SmsDev + * + * Send and receive SMS using SmsDev.com.br + * + * @see https://www.smsdev.com.br/ SMSDev API. + * + * @author Enrico Dias + */ class SmsDev { + /** + * API url. + * + * @var string + */ private $_apiUrl = 'https://api.smsdev.com.br'; + /** + * API key. + * + * @var string + */ private $_apiKey = ''; + /** + * API timezone. + * + * @object \DateTimeZone + */ private $_apiTimeZone; + /** + * Date format to be used in all date functions. + * + * @var string + */ private $_dateFormat = 'U'; + /** + * Query string to be sent to the API as a search filter. + * + * The default 'status' = 1 will return all received messages. + * + * @var array + */ private $_query = [ 'status' => 1 ]; + /** + * Raw API response/ + * + * @var array + */ private $_result = []; + /** + * Creates a new SmsDev instance with an API key and sets the default API timezone. + * + * @param string $apiKey + */ public function __construct($apiKey = '') { $this->_apiKey = $apiKey; @@ -31,11 +77,13 @@ public function __construct($apiKey = '') /** * Send an SMS message. * + * This method does not guarantee that the recipient received the massage since the message delivery is async. + * * TODO: verify phone number locally. * - * @param int $number - * @param string $message - * @return bool + * @param int $number Recipient's number. + * @param string $message SMS message. + * @return bool true if the API accepted the request. */ public function send($number, $message) { @@ -62,6 +110,12 @@ public function send($number, $message) return true; } + /** + * Sets the date format to be used in all date functions. + * + * @param string $dateFormat A valid date format (ex: Y-m-d). + * @return SmsDev Return itself for chaining. + */ public function setDateFormat($dateFormat) { $this->_dateFormat = $dateFormat; @@ -69,6 +123,11 @@ public function setDateFormat($dateFormat) return $this; } + /** + * Resets the search filter. + * + * @return SmsDev Return itself for chaining. + */ public function setFilter() { $this->_query = [ @@ -78,6 +137,11 @@ public function setFilter() return $this; } + /** + * Sets the search filter to return unread messages only. + * + * @return SmsDev Return itself for chaining. + */ public function isUnread() { $this->_query['status'] = 0; @@ -85,6 +149,12 @@ public function isUnread() return $this; } + /** + * Sets the search filter to return a message with a specific id. + * + * @param int $id Message id. + * @return SmsDev Return itself for chaining. + */ public function byId($id) { $id = intval($id); @@ -94,21 +164,48 @@ public function byId($id) return $this; } + /** + * Sets the search filter to return messages older than a specific date. + * + * @param string $date A valid date. + * @return SmsDev Return itself for chaining. + */ public function dateFrom($date) { return $this->parseDate('date_from', $date); } + /** + * Sets the search filter to return messages newer than a specific date. + * + * @param string $date A valid date. + * @return SmsDev Return itself for chaining. + */ public function dateTo($date) { return $this->parseDate('date_to', $date); } + /** + * Sets the search filter to return messages between a specific date interval. + * + * @param string $dateFrom Minimum date. + * @param string $dateTo Maximum date. + * @return SmsDev Return itself for chaining. + */ public function dateBetween($dateFrom, $dateTo) { return $this->dateFrom($dateFrom)->dateTo($dateTo); } + /** + * Query the API for received messages using search filters. + * + * @see SmsDev::$_query Search filters. + * @see SmsDev::$_result API response. + * + * @return bool True if the request if the API response is valid. + */ public function fetch() { $this->_result = []; @@ -134,6 +231,15 @@ public function fetch() return false; } + /** + * Parse the received messages in a more useful format with the fields date, number and message. + * + * The dates received by the API are converted to SmsDev::$_dateFormat. + * + * @see SmsDev::$_dateFormat Date format to be used in all date functions. + * + * @return array List of received messages. + */ public function parsedMessages() { $localTimeZone = new \DateTimeZone(date_default_timezone_get()); @@ -160,6 +266,11 @@ public function parsedMessages() return $messages; } + /** + * Get the current balance/credits. + * + * @return int Current balance in BRL cents. + */ public function getBalance() { $this->_result = []; @@ -183,11 +294,30 @@ public function getBalance() return (int) $this->_result['saldo_sms']; } + /** + * Get the raw API response from the last response received. + * + * @see SmsDev::$_result Raw API response. + * + * @return array Raw API response. + */ public function getResult() { return $this->_result; } + /** + * Convert a date to format supported by the API. + * + * The API requires the date format d/m/Y, but in this class any valid date format is supported. + * Since the API is always using the timezone America/Sao_Paulo, this function must also do timezone conversions. + * + * @see SmsDev::$_dateFormat Date format to be used in all date functions. + * + * @param string $key The filter key to be set as a search filter. + * @param string $date A valid date format. + * @return SmsDev Return itself for chaining. + */ private function parseDate($key, $date) { $parsedDate = \DateTime::createFromFormat($this->_dateFormat, $date); @@ -203,6 +333,12 @@ private function parseDate($key, $date) return $this; } + /** + * Sends a request to the smsdev.com.br API. + * + * @param \GuzzleHttp\Psr7\Request $request Request object. + * @return bool True if the API response is valid. + */ private function makeRequest($request) { $client = $this->getGuzzleClient();