1
|
|
|
<?php |
2
|
|
|
/* |
3
|
|
|
* This file is part of the FreshSinchBundle |
4
|
|
|
* |
5
|
|
|
* (c) Artem Genvald <[email protected]> |
6
|
|
|
* |
7
|
|
|
* For the full copyright and license information, please view the LICENSE |
8
|
|
|
* file that was distributed with this source code. |
9
|
|
|
*/ |
10
|
|
|
|
11
|
|
|
namespace Fresh\SinchBundle\Service; |
12
|
|
|
|
13
|
|
|
use Fresh\SinchBundle\Helper\SinchSmsStatus; |
14
|
|
|
use GuzzleHttp\Client; |
15
|
|
|
use GuzzleHttp\Exception\ClientException; |
16
|
|
|
use GuzzleHttp\Exception\GuzzleException; |
17
|
|
|
use Symfony\Component\HttpFoundation\Response; |
18
|
|
|
|
19
|
|
|
/** |
20
|
|
|
* SinchService |
21
|
|
|
* |
22
|
|
|
* @author Artem Genvald <[email protected]> |
23
|
|
|
*/ |
24
|
|
|
class SinchService |
25
|
|
|
{ |
26
|
|
|
/** |
27
|
|
|
* @var Client $guzzleHTTPClient Guzzle HTTP client |
28
|
|
|
*/ |
29
|
|
|
private $guzzleHTTPClient; |
30
|
|
|
|
31
|
|
|
/** |
32
|
|
|
* @var string $host Host |
33
|
|
|
*/ |
34
|
|
|
private $host; |
35
|
|
|
|
36
|
|
|
/** |
37
|
|
|
* @var string $key Key |
38
|
|
|
*/ |
39
|
|
|
private $key; |
40
|
|
|
|
41
|
|
|
/** |
42
|
|
|
* @var string $secret Secret |
43
|
|
|
*/ |
44
|
|
|
private $secret; |
45
|
|
|
|
46
|
|
|
/** |
47
|
|
|
* @var string $from From |
48
|
|
|
*/ |
49
|
|
|
private $from; |
50
|
|
|
|
51
|
|
|
/** |
52
|
|
|
* Constructor |
53
|
|
|
* |
54
|
|
|
* @param string $host Host |
55
|
|
|
* @param string $key Key |
56
|
|
|
* @param string $secret Secret |
57
|
|
|
* @param string|null $from From |
58
|
|
|
*/ |
59
|
|
|
public function __construct($host, $key, $secret, $from = null) |
60
|
|
|
{ |
61
|
|
|
$this->host = $host; |
62
|
|
|
$this->key = $key; |
63
|
|
|
$this->secret = $secret; |
64
|
|
|
$this->from = $from; |
65
|
|
|
|
66
|
|
|
$this->guzzleHTTPClient = new Client([ |
67
|
|
|
'base_uri' => rtrim($this->host, '/'), |
68
|
|
|
]); |
69
|
|
|
} |
70
|
|
|
|
71
|
|
|
// region Public API |
72
|
|
|
|
73
|
|
|
/** |
74
|
|
|
* Send SMS |
75
|
|
|
* |
76
|
|
|
* @param string $phoneNumber Phone number |
77
|
|
|
* @param string $messageText Message text |
78
|
|
|
* @param string|null $from From |
79
|
|
|
* |
80
|
|
|
* @return int Message ID |
81
|
|
|
* |
82
|
|
|
* @throws \Fresh\SinchBundle\Exception\SinchException |
83
|
|
|
* @throws GuzzleException |
84
|
|
|
*/ |
85
|
|
|
public function sendSMS($phoneNumber, $messageText, $from = null) |
86
|
|
|
{ |
87
|
|
|
$uri = '/v1/sms/'.$phoneNumber; // @todo validate phone number |
88
|
|
|
|
89
|
|
|
$body = [ |
90
|
|
|
'auth' => [$this->key, $this->secret], |
91
|
|
|
'headers' => ['X-Timestamp' => (new \DateTime('now'))->format('c')], // ISO 8601 date format |
92
|
|
|
'json' => ['message' => $messageText], |
93
|
|
|
]; |
94
|
|
|
|
95
|
|
|
if (null !== $from) { |
96
|
|
|
$body['json']['from'] = $from; |
97
|
|
|
} elseif (null !== $this->from) { |
98
|
|
|
$body['json']['from'] = $this->from; |
99
|
|
|
} |
100
|
|
|
|
101
|
|
|
try { |
102
|
|
|
$response = $this->guzzleHTTPClient->post($uri, $body); |
103
|
|
|
} catch (ClientException $e) { |
104
|
|
|
throw SinchExceptionResolver::createAppropriateSinchException($e); |
105
|
|
|
} |
106
|
|
|
|
107
|
|
|
$messageId = null; |
108
|
|
|
if (Response::HTTP_OK === $response->getStatusCode() && $response->hasHeader('Content-Type') && |
109
|
|
|
'application/json; charset=utf-8' === $response->getHeaderLine('Content-Type') |
110
|
|
|
) { |
111
|
|
|
$content = $response->getBody()->getContents(); |
112
|
|
|
$content = json_decode($content, true); |
113
|
|
|
|
114
|
|
|
if (isset($content['messageId']) && array_key_exists('messageId', $content)) { |
115
|
|
|
$messageId = $content['messageId']; |
116
|
|
|
} |
117
|
|
|
}; |
118
|
|
|
|
119
|
|
|
return $messageId; |
120
|
|
|
} |
121
|
|
|
|
122
|
|
|
/** |
123
|
|
|
* Get status of sent SMS |
124
|
|
|
* |
125
|
|
|
* Available SMS statuses: Successful, Pending, Faulted, Unknown |
126
|
|
|
* |
127
|
|
|
* @param int $messageId Message ID |
128
|
|
|
* |
129
|
|
|
* @return string SMS status |
130
|
|
|
* |
131
|
|
|
* @throws GuzzleException |
132
|
|
|
*/ |
133
|
|
|
public function getStatusOfSMS($messageId) |
134
|
|
|
{ |
135
|
|
|
$response = $this->sendRequestToCheckStatusOfSMS($messageId); |
136
|
|
|
$result = ''; |
137
|
|
|
|
138
|
|
|
if (isset($response['status']) && array_key_exists('status', $response)) { |
139
|
|
|
$result = $response['status']; |
140
|
|
|
} |
141
|
|
|
|
142
|
|
|
return $result; |
143
|
|
|
} |
144
|
|
|
|
145
|
|
|
// endregion |
146
|
|
|
|
147
|
|
|
// region Check status helpers |
148
|
|
|
|
149
|
|
|
/** |
150
|
|
|
* Returns true if SMS with some ID was sent successfully, otherwise returns false |
151
|
|
|
* |
152
|
|
|
* @param int $messageId Message ID |
153
|
|
|
* |
154
|
|
|
* @return bool True if SMS was sent successfully, otherwise - false |
155
|
|
|
*/ |
156
|
|
View Code Duplication |
public function smsIsSentSuccessfully($messageId) |
|
|
|
|
157
|
|
|
{ |
158
|
|
|
$response = $this->sendRequestToCheckStatusOfSMS($messageId); |
159
|
|
|
|
160
|
|
|
$result = false; |
161
|
|
|
if (isset($response['status']) && SinchSmsStatus::SUCCESSFUL === $response['status']) { |
162
|
|
|
$result = true; |
163
|
|
|
} |
164
|
|
|
|
165
|
|
|
return $result; |
166
|
|
|
} |
167
|
|
|
|
168
|
|
|
/** |
169
|
|
|
* Returns true if SMS with some ID is still pending, otherwise returns false |
170
|
|
|
* |
171
|
|
|
* @param int $messageId Message ID |
172
|
|
|
* |
173
|
|
|
* @return bool True if SMS is still pending, otherwise - false |
174
|
|
|
*/ |
175
|
|
View Code Duplication |
public function smsIsPending($messageId) |
|
|
|
|
176
|
|
|
{ |
177
|
|
|
$response = $this->sendRequestToCheckStatusOfSMS($messageId); |
178
|
|
|
|
179
|
|
|
$result = false; |
180
|
|
|
if (isset($response['status']) && SinchSmsStatus::PENDING === $response['status']) { |
181
|
|
|
$result = true; |
182
|
|
|
} |
183
|
|
|
|
184
|
|
|
return $result; |
185
|
|
|
} |
186
|
|
|
|
187
|
|
|
/** |
188
|
|
|
* Returns true if SMS with some ID was faulted, otherwise returns false |
189
|
|
|
* |
190
|
|
|
* @param int $messageId Message ID |
191
|
|
|
* |
192
|
|
|
* @return bool True if SMS was faulted, otherwise - false |
193
|
|
|
*/ |
194
|
|
View Code Duplication |
public function smsIsFaulted($messageId) |
|
|
|
|
195
|
|
|
{ |
196
|
|
|
$response = $this->sendRequestToCheckStatusOfSMS($messageId); |
197
|
|
|
|
198
|
|
|
$result = false; |
199
|
|
|
if (isset($response['status']) && SinchSmsStatus::FAULTED === $response['status']) { |
200
|
|
|
$result = true; |
201
|
|
|
} |
202
|
|
|
|
203
|
|
|
return $result; |
204
|
|
|
} |
205
|
|
|
|
206
|
|
|
/** |
207
|
|
|
* Returns true if SMS with some ID in unknown status, otherwise returns false |
208
|
|
|
* |
209
|
|
|
* @param int $messageId Message ID |
210
|
|
|
* |
211
|
|
|
* @return bool True if SMS in unknown status, otherwise - false |
212
|
|
|
*/ |
213
|
|
View Code Duplication |
public function smsInUnknownStatus($messageId) |
|
|
|
|
214
|
|
|
{ |
215
|
|
|
$response = $this->sendRequestToCheckStatusOfSMS($messageId); |
216
|
|
|
|
217
|
|
|
$result = false; |
218
|
|
|
if (isset($response['status']) && SinchSmsStatus::UNKNOWN === $response['status']) { |
219
|
|
|
$result = true; |
220
|
|
|
} |
221
|
|
|
|
222
|
|
|
return $result; |
223
|
|
|
} |
224
|
|
|
|
225
|
|
|
// endregion |
226
|
|
|
|
227
|
|
|
// region Private functions |
228
|
|
|
|
229
|
|
|
/** |
230
|
|
|
* Send request to check status of SMS |
231
|
|
|
* |
232
|
|
|
* @param int $messageId Message ID |
233
|
|
|
* |
234
|
|
|
* @return array|null |
235
|
|
|
* |
236
|
|
|
* @throws \Fresh\SinchBundle\Exception\SinchException |
237
|
|
|
*/ |
238
|
|
|
private function sendRequestToCheckStatusOfSMS($messageId) |
239
|
|
|
{ |
240
|
|
|
$uri = '/v1/message/status/'.$messageId; |
241
|
|
|
|
242
|
|
|
$body = [ |
243
|
|
|
'auth' => [$this->key, $this->secret], |
244
|
|
|
'headers' => ['X-Timestamp' => (new \DateTime('now'))->format('c')], |
245
|
|
|
]; |
246
|
|
|
|
247
|
|
|
try { |
248
|
|
|
$response = $this->guzzleHTTPClient->get($uri, $body); |
249
|
|
|
} catch (ClientException $e) { |
250
|
|
|
throw SinchExceptionResolver::createAppropriateSinchException($e); |
251
|
|
|
} |
252
|
|
|
|
253
|
|
|
$result = null; |
254
|
|
|
|
255
|
|
|
if (Response::HTTP_OK === $response->getStatusCode() && $response->hasHeader('Content-Type') && |
256
|
|
|
'application/json; charset=utf-8' === $response->getHeaderLine('Content-Type') |
257
|
|
|
) { |
258
|
|
|
$content = $response->getBody()->getContents(); |
259
|
|
|
$result = json_decode($content, true); |
260
|
|
|
}; |
261
|
|
|
|
262
|
|
|
return $result; |
263
|
|
|
} |
264
|
|
|
|
265
|
|
|
// endregion |
266
|
|
|
} |
267
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.