Passed
Pull Request — master (#2)
by Enrico
03:12 queued 01:16
created

SmsDev::fetch()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 23
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 12
CRAP Score 3.004

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 3
eloc 11
c 1
b 0
f 0
nc 3
nop 0
dl 0
loc 23
ccs 12
cts 13
cp 0.9231
crap 3.004
rs 9.9
1
<?php
2
3
namespace enricodias\SmsDev;
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';
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 22
    public function __construct($apiKey = '')
71
    {
72 22
        $this->_apiKey = $apiKey;
73
74 22
        $this->_apiTimeZone = new \DateTimeZone('America/Sao_Paulo');
75 22
    }
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
            'GET',
94 8
            $this->_apiUrl.'/send',
95
            [
96
                'query' => [
97 8
                    'key'    => $this->_apiKey,
98 8
                    'type'   => 9,
99 8
                    'number' => $number,
100 8
                    'msg'    => $message,
101 8
                ],
102 8
                'Accept' => 'application/json',
103
            ]
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 8
    public function setDateFormat($dateFormat)
120
    {
121 8
        $this->_dateFormat = $dateFormat;
122
123 8
        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 12
    public function fetch()
210
    {
211 12
        $this->_result = [];
212
213 12
        $this->_query['key'] = $this->_apiKey;
214
215 12
        $request = new Request(
216 12
            'GET',
217 12
            $this->_apiUrl.'/get',
218
            [
219 12
                'query'  => $this->_query,
220 12
                'Accept' => 'application/json',
221
            ]
222 12
        );
223
224 12
        if ($this->makeRequest($request) === false) return false;
225
226
        // resets the filters
227 4
        $this->setFilter();
228
229 4
        if (is_array($this->_result)) return true;
230
231
        return false;
232
    }
233
234
    /**
235
     * Parse the received messages in a more useful format with the fields date, number and message.
236
     * 
237
     * The dates received by the API are converted to SmsDev::$_dateFormat.
238
     *
239
     * @see SmsDev::$_dateFormat Date format to be used in all date functions.
240
     * 
241
     * @return array List of received messages.
242
     */
243 4
    public function parsedMessages()
244
    {
245 4
        $localTimeZone = new \DateTimeZone(date_default_timezone_get());
246
247 4
        $messages = [];
248
249 4
        foreach ($this->_result as $key => $result) {
250
251 3
            if (array_key_exists('id_sms_read', $result) === false) continue;
252
253 2
            $id = $result['id_sms_read'];
254 2
            $date = \DateTime::createFromFormat('d/m/Y H:i:s', $result['data_read'], $this->_apiTimeZone);
255
256 2
            $date->setTimezone($localTimeZone);
257
258 2
            $messages[$id] = [
259 2
                'date'    => $date->format($this->_dateFormat),
260 2
                'number'  => $result['telefone'],
261 2
                'message' => $result['descricao'],
262
            ];
263
264 4
        }
265
266 4
        return $messages;
267
    }
268
269
    /**
270
     * Get the current balance/credits.
271
     *
272
     * @return int Current balance in BRL cents.
273
     */
274 3
    public function getBalance()
275
    {
276 3
        $this->_result = [];
277
278 3
        $request = new Request(
279 3
            'GET',
280 3
            $this->_apiUrl.'/get',
281
            [
282
                'query' => [
283 3
                    'key'    => $this->_apiKey,
284 3
                    'action' => 'saldo',
285 3
                ],
286 3
                'Accept' => 'application/json',
287
            ]
288 3
        );
289
290 3
        $this->makeRequest($request);
291
292 3
        if (array_key_exists('saldo_sms', $this->_result) === false) return 0;
293
294 1
        return (int) $this->_result['saldo_sms'];
295
    }
296
297
    /**
298
     * Get the raw API response from the last response received.
299
     *
300
     * @see SmsDev::$_result Raw API response.
301
     * 
302
     * @return array Raw API response.
303
     */
304 2
    public function getResult()
305
    {
306 2
        return $this->_result;
307
    }
308
309
    /**
310
     * Convert a date to format supported by the API.
311
     * 
312
     * The API requires the date format d/m/Y, but in this class any valid date format is supported.
313
     * Since the API is always using the timezone America/Sao_Paulo, this function must also do timezone conversions.
314
     *
315
     * @see SmsDev::$_dateFormat Date format to be used in all date functions.
316
     * 
317
     * @param string $key The filter key to be set as a search filter.
318
     * @param string $date A valid date format.
319
     * @return SmsDev Return itself for chaining.
320
     */
321 5
    private function parseDate($key, $date)
322
    {
323 5
        $parsedDate = \DateTime::createFromFormat($this->_dateFormat, $date);
324
325 5
        if ($parsedDate !== false) {
326
            
327 5
            $parsedDate->setTimezone($this->_apiTimeZone);
328
329 5
            $this->_query[$key] = $parsedDate->format('d/m/Y');
330
331 5
        }
332
333 5
        return $this;
334
    }
335
336
    /**
337
     * Sends a request to the smsdev.com.br API.
338
     *
339
     * @param \GuzzleHttp\Psr7\Request $request Request object.
340
     * @return bool True if the API response is valid.
341
     */
342 22
    private function makeRequest($request)
343
    {
344 22
        $client = $this->getGuzzleClient();
345
346
        try {
347
348 22
            $response = $client->send($request);
349
350 22
        } catch (\Exception $e) {
351
            
352 1
            return false;
353
            
354
        }
355
356 22
        $response = json_decode($response->getBody(), true);
357
        
358 22
        if (json_last_error() != JSON_ERROR_NONE || is_array($response) === false) return false;
359
360 12
        $this->_result = $response;
361
362 12
        return true;
363
    }
364
365
    /**
366
     * Creates GuzzleHttp\Client to be used in API requests.
367
     * This method is needed to test API calls in unit tests.
368
     *
369
     * @return object GuzzleHttp\Client instance.
370
     * 
371
     * @codeCoverageIgnore
372
     */
373
    protected function getGuzzleClient()
374
    {
375
        return new Client();
376
    }
377
}