Passed
Push — master ( 2a18fa...bd0118 )
by Ehsan
03:31
created

ApiClient::prepareRequestBody()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 14
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 14
ccs 6
cts 6
cp 1
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 7
nc 2
nop 2
crap 2
1
<?php
2
3
namespace Botonomous\client;
4
5
use Botonomous\Config;
6
use Botonomous\ImChannel;
7
use Botonomous\Team;
8
use Botonomous\utility\ArrayUtility;
9
use /* @noinspection PhpUndefinedClassInspection */
10
    GuzzleHttp\Client;
11
use /* @noinspection PhpUndefinedClassInspection */
12
    GuzzleHttp\Psr7\Request;
13
14
/**
15
 * Class ApiClient.
16
 */
17
class ApiClient
18
{
19
    const BASE_URL = 'https://slack.com/api/';
20
    const CONTENT_TYPE = 'application/x-www-form-urlencoded';
21
22
    private $arguments = [
23
        'rtm.start' => [
24
            'required' => [
25
                'token',
26
            ],
27
            'optional' => [
28
                'simple_latest',
29
                'no_unreads',
30
                'mpim_aware',
31
            ],
32
        ],
33
        'chat.postMessage' => [
34
            'required' => [
35
                'token',
36
                'channel',
37
                'text',
38
            ],
39
            'optional' => [
40
                'parse',
41
                'link_names',
42
                'attachments',
43
                'unfurl_links',
44
                'unfurl_media',
45
                'username',
46
                'as_user',
47
                'icon_url',
48
                'icon_emoji',
49
            ],
50
        ],
51
        'oauth.access' => [
52
            'required' => [
53
                'client_id',
54
                'client_secret',
55
                'code',
56
            ],
57
            'optional' => [
58
                'redirect_uri',
59
            ],
60
        ],
61
        'team.info' => [
62
            'required' => [
63
                'token',
64
            ],
65
        ],
66
        'im.list' => [
67
            'required' => [
68
                'token',
69
            ],
70
        ],
71
        'users.list' => [
72
            'required' => [
73
                'token',
74
            ],
75
            'optional' => [
76
                'presence',
77
            ],
78
        ],
79
        'users.info' => [
80
            'required' => [
81
                'token',
82
                'user',
83
            ],
84
        ],
85
    ];
86
87
    private $client;
88
    private $token;
89
    private $arrayUtility;
90
91
    /**
92
     * ApiClient constructor.
93
     *
94
     * @param null $token
95
     */
96 43
    public function __construct($token = null)
97
    {
98 43
        $this->setToken($token);
99 43
    }
100
101
    /**
102
     * API CURL Call with post method.
103
     *
104
     * @param string $method
105
     * @param array  $arguments
106
     *
107
     * @throws \Exception
108
     *
109
     * @return mixed
110
     */
111 33
    public function apiCall($method, array $arguments = [])
112
    {
113
        try {
114 33
            $requestBody = $this->prepareRequestBody($method, $arguments);
115 30
            $response = $this->sendRequest($method, $requestBody);
116 28
            return $this->processResponse($response);
117 6
        } catch (\Exception $e) {
118 6
            throw $e;
119
        }
120
    }
121
122 30
    private function sendRequest($method, $requestBody)
123
    {
124
        try {
125
            /** @noinspection PhpUndefinedClassInspection */
126 30
            $request = new Request('POST', self::BASE_URL.$method, ['Content-Type' => self::CONTENT_TYPE], $requestBody);
0 ignored issues
show
Coding Style introduced by
This line exceeds maximum limit of 120 characters; contains 121 characters

Overly long lines are hard to read on any screen. Most code styles therefor impose a maximum limit on the number of characters in a line.

Loading history...
127 30
            return $this->getClient()->send($request);
128 2
        } catch (\Exception $e) {
129 2
            throw new \Exception('Failed to send data to the Slack API: '.$e->getMessage());
130
        }
131
    }
132
133
    /**
134
     * @param $method
135
     * @param array $arguments
136
     *
137
     * @throws \Exception
138
     *
139
     * @return string
140
     */
141 33
    private function prepareRequestBody($method, array $arguments = [])
142
    {
143 33
        $arguments = array_merge($arguments, $this->getArgs());
144
145
        // check the required arguments are provided
146
        try {
147 33
            $this->validateRequiredArguments($method, $arguments);
148 3
        } catch (\Exception $e) {
149 3
            throw new \Exception('Missing required argument(s): '.$e->getMessage());
150
        }
151
152
        // filter unwanted arguments
153 30
        return http_build_query($this->filterArguments($method, $arguments));
154
    }
155
156
    /**
157
     * @param $response
158
     *
159
     * @throws \Exception
160
     *
161
     * @return mixed
162
     */
163 28
    private function processResponse($response)
164
    {
165 28
        $response = json_decode($response->getBody()->getContents(), true);
166
167 28
        if (!is_array($response)) {
168 1
            throw new \Exception('Failed to process response from the Slack API');
169
        }
170
171 27
        return $response;
172
    }
173
174
    /**
175
     * @throws \Exception
176
     *
177
     * @return array
178
     */
179 34
    public function getArgs()
180
    {
181 34
        $config = new Config();
182
183
        return [
184 34
            'token'    => $this->getToken(),
185 34
            'username' => $config->get('botUsername'),
186 34
            'as_user'  => $config->get('asUser'),
187 34
            'icon_url' => $config->get('iconURL'),
188
        ];
189
    }
190
191
    /**
192
     * @param $arguments
193
     *
194
     * @return mixed
195
     */
196 2
    public function chatPostMessage($arguments)
197
    {
198 2
        return $this->apiCall('chat.postMessage', $arguments);
199
    }
200
201
    /**
202
     * @param $arguments
203
     *
204
     * @throws \Exception
205
     *
206
     * @return mixed
207
     */
208 1
    public function rtmStart($arguments)
209
    {
210 1
        return $this->apiCall('rtm.start', $arguments);
211
    }
212
213
    /**
214
     * @throws \Exception
215
     *
216
     * @return array
217
     * @return Team
218
     */
219 4
    public function teamInfo()
220
    {
221 4
        $teamInfo = $this->apiCall('team.info');
222
223 4
        if (!isset($teamInfo['team'])) {
224 2
            return [];
225
        }
226
227 2
        return $teamInfo['team'];
228
    }
229
230
    /**
231
     * @return null|\Botonomous\AbstractBaseSlack
232
     */
233 2
    public function teamInfoAsObject()
234
    {
235 2
        $teamInfo = $this->teamInfo();
236
237 2
        if (empty($teamInfo)) {
238
            /* @noinspection PhpInconsistentReturnPointsInspection */
239 1
            return;
240
        }
241
242
        // return as object
243 1
        return (new Team())->load($teamInfo);
244
    }
245
246
    /**
247
     * List all the Slack users in the team.
248
     *
249
     * @return array
250
     */
251 2
    public function usersList()
252
    {
253 2
        $result = $this->apiCall('users.list');
254
255 2
        if (!isset($result['members'])) {
256 1
            return [];
257
        }
258
259 1
        return $result['members'];
260
    }
261
262
    /**
263
     * Return a user by Slack user id.
264
     *
265
     * @param $arguments
266
     *
267
     * @throws \Exception
268
     *
269
     * @return mixed
270
     */
271 10
    public function userInfo($arguments)
272
    {
273 10
        $result = $this->apiCall('users.info', $arguments);
274
275 10
        if (!isset($result['user'])) {
276
            /* @noinspection PhpInconsistentReturnPointsInspection */
277 4
            return;
278
        }
279
280 6
        return $result['user'];
281
    }
282
283
    /**
284
     * @throws \Exception
285
     *
286
     * @return mixed
287
     */
288 1
    public function test()
289
    {
290 1
        return $this->apiCall('api.test');
291
    }
292
293
    /**
294
     * @throws \Exception
295
     *
296
     * @return array
297
     */
298 5
    public function imList()
299
    {
300 5
        $result = $this->apiCall('im.list');
301
302 5
        if (!isset($result['ims'])) {
303 2
            return [];
304
        }
305
306 4
        return $result['ims'];
307
    }
308
309
    /**
310
     * @return array
311
     */
312 4
    public function imListAsObject()
313
    {
314 4
        $imChannels = $this->imList();
315
316 4
        $imChannelObjects = [];
317 4
        if (empty($imChannels)) {
318 1
            return $imChannelObjects;
319
        }
320
321 3
        foreach ($imChannels as $imChannel) {
322 3
            $imChannelObjects[$imChannel['id']] = (new ImChannel())->load($imChannel);
323
        }
324
325 3
        return $imChannelObjects;
326
    }
327
328
    /**
329
     * @param $arguments
330
     *
331
     * @throws \Exception
332
     *
333
     * @return mixed
334
     */
335 5
    public function oauthAccess($arguments)
336
    {
337 5
        return $this->apiCall('oauth.access', $arguments);
338
    }
339
340
    /** @noinspection PhpUndefinedClassInspection
341
     * @param Client $client
342
     */
343 33
    public function setClient(Client $client)
344
    {
345 33
        $this->client = $client;
346 33
    }
347
348
    /** @noinspection PhpUndefinedClassInspection
349
     * @return Client|null
350
     */
351 30
    public function getClient()
352
    {
353 30
        if (!isset($this->client)) {
354
            /* @noinspection PhpUndefinedClassInspection */
355 8
            $this->setClient(new Client());
356
        }
357
358 30
        return $this->client;
359
    }
360
361
    /**
362
     * @param $method
363
     * @param $arguments
364
     *
365
     * @throws \Exception
366
     *
367
     * @return bool
368
     */
369 33
    private function validateRequiredArguments($method, $arguments)
370
    {
371 33
        $validArguments = $this->getArguments($method);
372
373 33
        if (empty($validArguments['required'])) {
374 3
            return true;
375
        }
376
377 30
        foreach ($validArguments['required'] as $argument) {
378 30
            if ($this->getArrayUtility()->arrayKeyValueExists($argument, $arguments) !== true) {
379 30
                throw new \Exception("{$argument} must be provided for {$method}");
380
            }
381
        }
382
383 27
        return true;
384
    }
385
386
    /**
387
     * @param null $method
388
     *
389
     * @throws \Exception
390
     *
391
     * @return mixed
392
     */
393 35
    public function getArguments($method = null)
394
    {
395 35
        if ($method !== null) {
396 34
            if (!isset($this->arguments[$method])) {
397
                /* @noinspection PhpInconsistentReturnPointsInspection */
398 3
                return;
399
            }
400
401 31
            return $this->arguments[$method];
402
        }
403
404 1
        return $this->arguments;
405
    }
406
407
    /**
408
     * @param array $arguments
409
     */
410 1
    public function setArguments(array $arguments)
411
    {
412 1
        $this->arguments = $arguments;
413 1
    }
414
415
    /**
416
     * @param       $method
417
     * @param array $arguments
418
     *
419
     * @return array
420
     */
421 31
    public function filterArguments($method, array $arguments)
422
    {
423 31
        $validArguments = $this->getArguments($method);
424
425 31
        if (empty($validArguments)) {
426 3
            return $arguments;
427
        }
428
429 28
        if (!isset($validArguments['optional'])) {
430 19
            $validArguments['optional'] = [];
431
        }
432
433 28
        $extractedArguments = array_merge($validArguments['required'], $validArguments['optional']);
434
435 28
        return (new ArrayUtility())->filterArray($arguments, $extractedArguments);
436
    }
437
438
    /**
439
     * @return string
440
     */
441 34
    public function getToken()
442
    {
443
        // fall back to config
444 34
        if (empty($this->token)) {
445 34
            $this->setToken((new Config())->get('botUserToken'));
446
        }
447
448 34
        return $this->token;
449
    }
450
451
    /**
452
     * @param string $token
453
     */
454 43
    public function setToken($token)
455
    {
456 43
        $this->token = $token;
457 43
    }
458
459
    /**
460
     * @return ArrayUtility
461
     */
462 30
    public function getArrayUtility()
463
    {
464 30
        if (!isset($this->arrayUtility)) {
465 30
            $this->setArrayUtility(new ArrayUtility());
466
        }
467
468 30
        return $this->arrayUtility;
469
    }
470
471
    /**
472
     * @param ArrayUtility $arrayUtility
473
     */
474 30
    public function setArrayUtility(ArrayUtility $arrayUtility)
475
    {
476 30
        $this->arrayUtility = $arrayUtility;
477 30
    }
478
}
479