Completed
Push — master ( a4c3be...e5bf7c )
by Samuel
12s queued 10s
created

Client::makeRequest()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 14
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 3

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 6
c 1
b 0
f 0
dl 0
loc 14
ccs 6
cts 6
cp 1
rs 10
cc 3
nc 2
nop 3
crap 3
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 10
    public function __construct(HttpClient $http)
20
    {
21 10
        $this->http = $http;
22 10
    }
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 1
    public function getDeliveryReport(string $reference, $req, $used_route)
113
    {
114 1
        if (!in_array($used_route, Route::$routes)) {
115 1
            throw new InvalidParamException("Invalid 'used_route' parameter supplied");
116
        }
117
118
        $params = array(
119 1
            Param::REFERENCE => $reference,
120 1
            Param::REQ => $req,
121 1
            Param::USED_ROUTE => $used_route,
122
        );
123
124 1
        return $this->makeRequest('/deliveryreport/', 'get', $params);
125
    }
126
127 1
    public function setSender(string $sender): void
128
    {
129 1
        $this->http->setSender($sender);
130 1
    }
131
132
    /**------------------------------------------------------------------------------
133
     * | PRIVATE METHODS
134
     * /*------------------------------------------------------------------------------*/
135
136
    /**
137
     * This method makes the intended request than parses the response body
138
     * and returns an array of the the response data.
139
     *
140
     * @param string $path
141
     * @param string $method
142
     * @param array  $params
143
     *
144
     * @return array
145
     */
146 7
    private function makeRequest(string $path, string $method, array $params): array
147
    {
148 7
        $response = $this->http->$method($path, $params);
149 7
        $body = $response->getBody();
150
151
        // check if response by is encapsulated in curly braces
152
        // this indicates if the response is JSON or not
153
        // Yeah, I'm not checking the response header for content type because
154
        // The API docs are not consistent with certain things
155
156 7
        if (substr($body, 0, 1) == '{' && substr($body, -1) == '}') {
157 2
            return $this->requestAndExtractDetails($body);
158
        } else {
159 5
            return $this->requestAndParseTextResponse($body);
160
        }
161
    }
162
163
    /**
164
     * This method is only used where the response body is Plain Text and extra parsing and
165
     * formatting has to be done.
166
     *
167
     * @param string $body
168
     *
169
     * @return array
170
     */
171 5
    private function requestAndParseTextResponse(string $body): array
172
    {
173
        //if the response body starts with the string "ERROR"
174
        //return an array showing the status as "error" and set the error message
175
        //to the remainder part of the response body
176 5
        if (substr($body, 0, 5) == 'ERROR') {
177
            return array(
178 1
                'status' => 'error',
179 1
                'message' => substr($body, 6),
180
            );
181
        }
182
183 4
        $body = explode('||', $body);
184
185
        // Format each section of the body delimited by "||" into key value pairs
186
        // with the keys being in all lower case
187 4
        $data = array();
188
189 4
        $i = 0;
190 4
        foreach ($body as $item) {
191 4
            if (0 == $i && strpos($item, 'units')) {
192 4
                $data['units_used'] = trim(explode(' ', $item)[0]);
193
            } else {
194 4
                $data_parts = explode(':', $item);
195 4
                @$data[strtolower(trim($data_parts[0]))] = trim($data_parts[1]);
196
            }
197
198 4
            $i++;
199
        }
200
201
        // Remove the API key from the response
202 4
        unset($data[Param::API_KEY]);
203
204 4
        return $data;
205
    }
206
207
    /**
208
     * This method is only used where the response body is JSON.
209
     *
210
     * @param string $body
211
     *
212
     * @return array
213
     */
214 2
    private function requestAndExtractDetails(string $body): array
215
    {
216 2
        $details = $this->decode($body)['D']['details'];
217
218 2
        if (count($details) == 1) {
219 1
            $details = $details[0];
220
        } else {
221 1
            $details = array('data' => $details);
222
        }
223
224 2
        if (array_key_exists(Param::API_KEY, $details)) {
225 1
            unset($details[Param::API_KEY]);
226
        }
227
228 2
        return $details;
229
    }
230
231
    /**
232
     * @param $data
233
     * @param bool $assoc
234
     *
235
     * @return array
236
     */
237 2
    private function decode($data, $assoc = true): array
238
    {
239 2
        return json_decode($data, $assoc);
240
    }
241
}
242