Completed
Push — master ( 0aa541...09a9f8 )
by Enrico
22s queued 10s
created

SmsDev::makeRequest()   A

Complexity

Conditions 4
Paths 3

Size

Total Lines 21
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 9
CRAP Score 4

Importance

Changes 0
Metric Value
cc 4
eloc 9
nc 3
nop 1
dl 0
loc 21
ccs 9
cts 9
cp 1
crap 4
rs 9.9666
c 0
b 0
f 0
1
<?php
2
3
namespace enricodias;
4
5
use GuzzleHttp\Client;
6
use GuzzleHttp\Psr7\Request;
7
8
/**
9
 * SmsDev
10
 * 
11
 * Send and receive SMS using SmsDev.com.br
12
 * 
13
 * @see https://www.smsdev.com.br/ SMSDev API.
14
 * 
15
 * @author Enrico Dias <[email protected]>
16
 */
17
class SmsDev
18
{
19
    /**
20
     * API url.
21
     *
22
     * @var string
23
     */
24
    private $_apiUrl = 'https://api.smsdev.com.br/v1';
25
26
    /**
27
     * API key.
28
     *
29
     * @var string
30
     */
31
    private $_apiKey = '';
32
33
    /**
34
     * API timezone.
35
     *
36
     * @object \DateTimeZone
37
     */
38
    private $_apiTimeZone;
39
40
    /**
41
     * Date format to be used in all date functions.
42
     *
43
     * @var string
44
     */
45
    private $_dateFormat = 'U';
46
47
    /**
48
     * Query string to be sent to the API as a search filter.
49
     *
50
     * The default 'status' = 1 will return all received messages.
51
     * 
52
     * @var array
53
     */
54
    private $_query = [
55
        'status' => 1
56
    ];
57
58
    /**
59
     * Raw API response/
60
     *
61
     * @var array
62
     */
63
    private $_result = [];
64
65
    /**
66
     * Creates a new SmsDev instance with an API key and sets the default API timezone.
67
     *
68
     * @param string $apiKey
69
     */
70 23
    public function __construct($apiKey = '')
71
    {
72 23
        $this->_apiKey = $apiKey;
73
74 23
        $this->_apiTimeZone = new \DateTimeZone('America/Sao_Paulo');
75 23
    }
76
77
    /**
78
     * Send an SMS message.
79
     * 
80
     * This method does not guarantee that the recipient received the massage since the message delivery is async.
81
     * 
82
     * TODO: verify phone number locally.
83
     *
84
     * @param int $number Recipient's number.
85
     * @param string $message SMS message.
86
     * @return bool true if the API accepted the request.
87
     */
88 8
    public function send($number, $message)
89
    {
90 8
        $this->_result = [];
91
92 8
        $request = new Request(
93 8
            'POST',
94 8
            $this->_apiUrl.'/send',
95
            [
96 8
                'Accept' => 'application/json',
97 8
            ],
98 8
            json_encode([
99 8
                'key'    => $this->_apiKey,
100 8
                'type'   => 9,
101 8
                'number' => $number,
102 8
                'msg'    => $message,
103 8
            ])
104 8
        );
105
106 8
        if ($this->makeRequest($request) === false) return false;
107
108 7
        if ($this->_result['situacao'] !== 'OK') return false;
109
110 3
        return true;
111
    }
112
113
    /**
114
     * Sets the date format to be used in all date functions.
115
     *
116
     * @param string $dateFormat A valid date format (ex: Y-m-d).
117
     * @return SmsDev Return itself for chaining.
118
     */
119 9
    public function setDateFormat($dateFormat)
120
    {
121 9
        $this->_dateFormat = $dateFormat;
122
123 9
        return $this;
124
    }
125
126
    /**
127
     * Resets the search filter.
128
     *
129
     * @return SmsDev Return itself for chaining.
130
     */
131 11
    public function setFilter()
132
    {
133 11
        $this->_query = [
134
            'status' => 1
135 11
        ];
136
137 11
        return $this;
138
    }
139
140
    /**
141
     * Sets the search filter to return unread messages only.
142
     *
143
     * @return SmsDev Return itself for chaining.
144
     */
145 3
    public function isUnread()
146
    {
147 3
        $this->_query['status'] = 0;
148
149 3
        return $this;
150
    }
151
152
    /**
153
     * Sets the search filter to return a message with a specific id.
154
     *
155
     * @param int $id Message id.
156
     * @return SmsDev Return itself for chaining.
157
     */
158 3
    public function byId($id)
159
    {
160 3
        $id = intval($id);
161
162 3
        if ($id > 0) $this->_query['id'] = $id;
163
164 3
        return $this;
165
    }
166
167
    /**
168
     * Sets the search filter to return messages older than a specific date.
169
     *
170
     * @param string $date A valid date.
171
     * @return SmsDev Return itself for chaining.
172
     */
173 5
    public function dateFrom($date)
174
    {
175 5
        return $this->parseDate('date_from', $date);
176
    }
177
178
    /**
179
     * Sets the search filter to return messages newer than a specific date.
180
     *
181
     * @param string $date A valid date.
182
     * @return SmsDev Return itself for chaining.
183
     */
184 4
    public function dateTo($date)
185
    {
186 4
        return $this->parseDate('date_to', $date);
187
    }
188
189
    /**
190
     * Sets the search filter to return messages between a specific date interval.
191
     *
192
     * @param string $dateFrom Minimum date.
193
     * @param string $dateTo Maximum date.
194
     * @return SmsDev Return itself for chaining.
195
     */
196 2
    public function dateBetween($dateFrom, $dateTo)
197
    {
198 2
        return $this->dateFrom($dateFrom)->dateTo($dateTo);
199
    }
200
201
    /**
202
     * Query the API for received messages using search filters.
203
     * 
204
     * @see SmsDev::$_query Search filters.
205
     * @see SmsDev::$_result API response.
206
     *
207
     * @return bool True if the request if the API response is valid.
208
     */
209 13
    public function fetch()
210
    {
211 13
        $this->_result = [];
212
213 13
        $this->_query['key'] = $this->_apiKey;
214
215 13
        $request = new Request(
216 13
            'GET',
217 13
            $this->_apiUrl.'/inbox',
218
            [
219 13
                'Accept' => 'application/json',
220 13
            ],
221 13
            json_encode(
222 13
                $this->_query
223 13
            )
224 13
        );
225
226 13
        if ($this->makeRequest($request) === false) return false;
227
228
        // resets the filters
229 4
        $this->setFilter();
230
231 4
        if (is_array($this->_result)) return true;
232
233
        return false;
234
    }
235
236
    /**
237
     * Parse the received messages in a more useful format with the fields date, number and message.
238
     * 
239
     * The dates received by the API are converted to SmsDev::$_dateFormat.
240
     *
241
     * @see SmsDev::$_dateFormat Date format to be used in all date functions.
242
     * 
243
     * @return array List of received messages.
244
     */
245 5
    public function parsedMessages()
246
    {
247 5
        $localTimeZone = new \DateTimeZone(date_default_timezone_get());
248
249 5
        $messages = [];
250
251 5
        foreach ($this->_result as $key => $result) {
252
253 3
            if (is_array($result) === false) continue;
254
255 3
            if (is_array($result) === false || array_key_exists('id_sms_read', $result) === false) continue;
256
257 2
            $id = $result['id_sms_read'];
258 2
            $date = \DateTime::createFromFormat('d/m/Y H:i:s', $result['data_read'], $this->_apiTimeZone);
259
260 2
            $date->setTimezone($localTimeZone);
261
262 2
            $messages[$id] = [
263 2
                'date'    => $date->format($this->_dateFormat),
264 2
                'number'  => $result['telefone'],
265 2
                'message' => $result['descricao'],
266
            ];
267
268 5
        }
269
270 5
        return $messages;
271
    }
272
273
    /**
274
     * Get the current balance/credits.
275
     *
276
     * @return int Current balance in BRL cents.
277
     */
278 3
    public function getBalance()
279
    {
280 3
        $this->_result = [];
281
282 3
        $request = new Request(
283 3
            'GET',
284 3
            $this->_apiUrl.'/balance',
285
            [
286 3
                'Accept' => 'application/json',
287 3
            ],
288 3
            json_encode([
289 3
                'key'    => $this->_apiKey,
290 3
                'action' => 'saldo',
291 3
            ])
292 3
        );
293
294 3
        $this->makeRequest($request);
295
296 3
        if (array_key_exists('saldo_sms', $this->_result) === false) return 0;
297
298 1
        return (int) $this->_result['saldo_sms'];
299
    }
300
301
    /**
302
     * Get the raw API response from the last response received.
303
     *
304
     * @see SmsDev::$_result Raw API response.
305
     * 
306
     * @return array Raw API response.
307
     */
308 2
    public function getResult()
309
    {
310 2
        return $this->_result;
311
    }
312
313
    /**
314
     * Convert a date to format supported by the API.
315
     * 
316
     * The API requires the date format d/m/Y, but in this class any valid date format is supported.
317
     * Since the API is always using the timezone America/Sao_Paulo, this function must also do timezone conversions.
318
     *
319
     * @see SmsDev::$_dateFormat Date format to be used in all date functions.
320
     * 
321
     * @param string $key The filter key to be set as a search filter.
322
     * @param string $date A valid date format.
323
     * @return SmsDev Return itself for chaining.
324
     */
325 5
    private function parseDate($key, $date)
326
    {
327 5
        $parsedDate = \DateTime::createFromFormat($this->_dateFormat, $date);
328
329 5
        if ($parsedDate !== false) {
330
            
331 5
            $parsedDate->setTimezone($this->_apiTimeZone);
332
333 5
            $this->_query[$key] = $parsedDate->format('d/m/Y');
334
335 5
        }
336
337 5
        return $this;
338
    }
339
340
    /**
341
     * Sends a request to the smsdev.com.br API.
342
     *
343
     * @param \GuzzleHttp\Psr7\Request $request Request object.
344
     * @return bool True if the API response is valid.
345
     */
346 23
    private function makeRequest($request)
347
    {
348 23
        $client = $this->getGuzzleClient();
349
350
        try {
351
352 23
            $response = $client->send($request);
353
354 23
        } catch (\Exception $e) {
355
            
356 1
            return false;
357
            
358
        }
359
360 23
        $response = json_decode($response->getBody(), true);
361
        
362 23
        if (json_last_error() != JSON_ERROR_NONE || is_array($response) === false) return false;
363
364 12
        $this->_result = $response;
365
366 12
        return true;
367
    }
368
369
    /**
370
     * Creates GuzzleHttp\Client to be used in API requests.
371
     * This method is needed to test API calls in unit tests.
372
     *
373
     * @return object GuzzleHttp\Client instance.
374
     * 
375
     * @codeCoverageIgnore
376
     */
377
    protected function getGuzzleClient()
378
    {
379
        return new Client();
380
    }
381
}