Client::setSender()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 1
c 1
b 0
f 0
dl 0
loc 3
ccs 2
cts 2
cp 1
rs 10
cc 1
nc 1
nop 1
crap 1
1
<?php
2
3
namespace Elmage\TextNg;
4
5
use Elmage\TextNg\Enum\Param;
6
use Elmage\TextNg\Enum\Route;
7
use Elmage\TextNg\Exception\InvalidParamException;
8
use Elmage\TextNg\Exception\SendingLimitException;
9
10
class Client
11
{
12
    const VERSION = '0.1.0';
13
14
    private HttpClient $http;
15
16
    /** @var int The max number of recipients in one transaction */
17
    private int $bulkLimit = 100000;
18
19 16
    public function __construct(HttpClient $http)
20
    {
21 16
        $this->http = $http;
22 16
    }
23
24
    /**
25
     * Creates a new TextNg client.
26
     *
27
     * @param Configuration $configuration
28
     *
29
     * @return Client A new TextNg client
30
     */
31 1
    public static function create(Configuration $configuration)
32
    {
33 1
        return new static(
34 1
            $configuration->createHttpClient()
35
        );
36
    }
37
38 1
    public function getHttpClient()
39
    {
40 1
        return $this->http;
41
    }
42
43
    /**
44
     * @return array
45
     */
46 1
    public function getBalance(): array
47
    {
48
        $params = array(
49 1
            Param::CHECK_BALANCE => 1,
50
        );
51
52 1
        return $this->makeRequest('/smsbalance/', 'get', $params);
53
    }
54
55
    /**
56
     * @param int    $route
57
     * @param string $phoneNumber
58
     * @param string $message
59
     * @param string $bypassCode
60
     * @param array  $params
61
     *
62
     * @return array
63
     */
64 4
    public function sendOTP(
65
        int $route,
66
        string $phoneNumber,
67
        string $message,
68
        string $bypassCode = '',
69
        array $params = array()
70
    ): array {
71 4
        return $this->sendSMS($route, array($phoneNumber), $message, $bypassCode, $params);
72
    }
73
74
    /**
75
     * @param int    $route
76
     * @param array  $phoneNumbers
77
     * @param string $message
78
     * @param string $bypassCode
79
     * @param array  $params
80
     *
81
     * @return array
82
     */
83 7
    public function sendSMS(
84
        int $route,
85
        array $phoneNumbers,
86
        string $message,
87
        string $bypassCode = '',
88
        array $params = array()
89
    ): array {
90 7
        if (!in_array($route, Route::$routes)) {
91 1
            throw new InvalidParamException("Invalid 'Route' parameter supplied");
92
        }
93
94 6
        if (count($phoneNumbers) > $this->bulkLimit) {
95 1
            throw new SendingLimitException('Too many recipients');
96
        }
97
98 5
        $phoneNumbers = implode(',', $phoneNumbers);
99
100 5
        $params[Param::SENDER] = $this->http->getSender();
101 5
        $params[Param::ROUTE] = $route;
102 5
        $params[Param::PHONE] = trim($phoneNumbers, ',');
103 5
        $params[Param::MESSAGE] = $message;
104
105 5
        if ($bypassCode) {
106 5
            $params[Param::BYPASSCODE] = $bypassCode;
107
        }
108
109 5
        return $this->makeRequest('/pushsms/', 'post', $params);
110
    }
111
112
    /**
113
     * add customer to category list.
114
     *
115
     * @param string $customerName
116
     * @param string $customerPhone
117
     * @param $categoryID
118
     *
119
     * @return array
120
     */
121 3
    public function createCustomer(string $customerName, string $customerPhone, string $categoryID): array
122
    {
123
        $params = array(
124 3
            Param::CUSTOMER_NAME => $customerName,
125 3
            Param::CUSTOMER_PHONE => $customerPhone,
126 3
            Param::CATEGORY_ID => $categoryID,
127
        );
128
129 3
        return $this->makeRequest('/addcustomer/', 'get', $params);
130
    }
131
132
    /**remove customer from category list
133
     *
134
     *
135
     * @param string $customerPhone
136
     * @param $categoryID
137
     * @return array
138
     */
139 3
    public function removeCustomer(string $customerPhone, string $categoryID): array
140
    {
141
        $params = array(
142 3
            Param::CUSTOMER_PHONE => $customerPhone,
143 3
            Param::CATEGORY_ID => $categoryID,
144
        );
145
146 3
        return $this->makeRequest('/removecustomer/', 'get', $params);
147
    }
148
149
    /**
150
     * Get delivery report for an SMS transaction.
151
     *
152
     * @param string $reference
153
     * @param $req
154
     * @param $used_route
155
     *
156
     * @return array
157
     */
158 1
    public function getDeliveryReport(string $reference, $req, $used_route)
159
    {
160 1
        if (!in_array($used_route, Route::$routes)) {
161 1
            throw new InvalidParamException("Invalid 'used_route' parameter supplied");
162
        }
163
164
        $params = array(
165 1
            Param::REFERENCE => $reference,
166 1
            Param::REQ => $req,
167 1
            Param::USED_ROUTE => $used_route,
168
        );
169
170 1
        return $this->makeRequest('/deliveryreport/', 'get', $params);
171
    }
172
173 1
    public function setSender(string $sender): void
174
    {
175 1
        $this->http->setSender($sender);
176 1
    }
177
178
    /**------------------------------------------------------------------------------
179
     * | PRIVATE METHODS
180
     * /*------------------------------------------------------------------------------*/
181
182
    /**
183
     * This method makes the intended request than parses the response body
184
     * and returns an array of the the response data.
185
     *
186
     * @param string $path
187
     * @param string $method
188
     * @param array  $params
189
     *
190
     * @return array
191
     */
192 13
    private function makeRequest(string $path, string $method, array $params): array
193
    {
194 13
        $response = $this->http->$method($path, $params);
195 13
        $body = $response->getBody();
196
197
        // check if response by is encapsulated in curly braces
198
        // this indicates if the response is JSON or not
199
        // Yeah, I'm not checking the response header for content type because
200
        // The API docs are not consistent with certain things
201
202 13
        if (substr($body, 0, 1) == '{' && substr($body, -1) == '}') {
203 8
            return $this->requestAndExtractDetails($body);
204
        } else {
205 5
            return $this->requestAndParseTextResponse($body);
206
        }
207
    }
208
209
    /**
210
     * This method is only used where the response body is Plain Text and extra parsing and
211
     * formatting has to be done.
212
     *
213
     * @param string $body
214
     *
215
     * @return array
216
     */
217 5
    private function requestAndParseTextResponse(string $body): array
218
    {
219
        //if the response body starts with the string "ERROR"
220
        //return an array showing the status as "error" and set the error message
221
        //to the remainder part of the response body
222 5
        if (substr($body, 0, 5) == 'ERROR') {
223
            return array(
224 1
                'status' => 'error',
225 1
                'message' => substr($body, 6),
226
            );
227
        }
228
229 4
        $body = explode('||', $body);
230
231
        // Format each section of the body delimited by "||" into key value pairs
232
        // with the keys being in all lower case
233 4
        $data = array();
234
235 4
        $i = 0;
236 4
        foreach ($body as $item) {
237 4
            if (0 == $i && strpos($item, 'units')) {
238 4
                $data['units_used'] = trim(explode(' ', $item)[0]);
239
            } else {
240 4
                $data_parts = explode(':', $item);
241 4
                @$data[strtolower(trim($data_parts[0]))] = trim($data_parts[1]);
242
            }
243
244 4
            $i++;
245
        }
246
247
        // Remove the API key from the response
248 4
        unset($data[Param::API_KEY]);
249
250 4
        return $data;
251
    }
252
253
    /**
254
     * This method is only used where the response body is JSON.
255
     *
256
     * @param string $body
257
     *
258
     * @return array
259
     */
260 8
    private function requestAndExtractDetails(string $body): array
261
    {
262 8
        $details = $this->decode($body)['D']['details'];
263
264 8
        if (count($details) == 1) {
265 7
            $details = $details[0];
266
        } else {
267 1
            $details = array('data' => $details);
268
        }
269
270 8
        if (array_key_exists(Param::API_KEY, $details)) {
271 1
            unset($details[Param::API_KEY]);
272
        }
273
274 8
        return $details;
275
    }
276
277
    /**
278
     * @param $data
279
     * @param bool $assoc
280
     *
281
     * @return array
282
     */
283 8
    private function decode($data, $assoc = true): array
284
    {
285 8
        return json_decode($data, $assoc);
286
    }
287
}
288