Passed
Push — master ( 44e71f...97e7bf )
by Ehsan
03:23
created

ApiClient::setArrayUtility()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 3
cts 3
cp 1
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 1
crap 1
1
<?php
2
3
namespace Botonomous\client;
4
5
use Botonomous\Config;
6
use Botonomous\ImChannel;
7
use Botonomous\Team;
8
use /* @noinspection PhpUndefinedClassInspection */
9
    GuzzleHttp\Client;
10
use /* @noinspection PhpUndefinedClassInspection */
11
    GuzzleHttp\Psr7\Request;
12
13
/**
14
 * Class ApiClient.
15
 */
16
class ApiClient extends AbstractClient
17
{
18
    const BASE_URL = 'https://slack.com/api/';
19
    const CONTENT_TYPE = 'application/x-www-form-urlencoded';
20
21
    private $arguments = [
22
        'rtm.start' => [
23
            'required' => [
24
                'token',
25
            ],
26
            'optional' => [
27
                'simple_latest',
28
                'no_unreads',
29
                'mpim_aware',
30
            ],
31
        ],
32
        'chat.postMessage' => [
33
            'required' => [
34
                'token',
35
                'channel',
36
                'text',
37
            ],
38
            'optional' => [
39
                'parse',
40
                'link_names',
41
                'attachments',
42
                'unfurl_links',
43
                'unfurl_media',
44
                'username',
45
                'as_user',
46
                'icon_url',
47
                'icon_emoji',
48
            ],
49
        ],
50
        'oauth.access' => [
51
            'required' => [
52
                'client_id',
53
                'client_secret',
54
                'code',
55
            ],
56
            'optional' => [
57
                'redirect_uri',
58
            ],
59
        ],
60
        'team.info' => [
61
            'required' => [
62
                'token',
63
            ],
64
        ],
65
        'im.list' => [
66
            'required' => [
67
                'token',
68
            ],
69
        ],
70
        'users.list' => [
71
            'required' => [
72
                'token',
73
            ],
74
            'optional' => [
75
                'presence',
76
            ],
77
        ],
78
        'users.info' => [
79
            'required' => [
80
                'token',
81
                'user',
82
            ],
83
        ],
84
    ];
85
86
    private $client;
87
    private $token;
88
89
    /**
90
     * ApiClient constructor.
91
     *
92
     * @param null $token
93
     */
94 43
    public function __construct($token = null)
95
    {
96 43
        $this->setToken($token);
97 43
    }
98
99
    /**
100
     * API CURL Call with post method.
101
     *
102
     * @param string $method
103
     * @param array  $arguments
104
     *
105
     * @throws \Exception
106
     *
107
     * @return mixed
108
     */
109 33
    public function apiCall($method, array $arguments = [])
110
    {
111
        try {
112 33
            $requestBody = $this->prepareRequestBody($method, $arguments);
113 30
            $response = $this->sendRequest($method, $requestBody);
114
115 28
            return $this->processResponse($response);
116 6
        } catch (\Exception $e) {
117 6
            throw $e;
118
        }
119
    }
120
121
    /**
122
     * @param $method
123
     * @param $requestBody
124
     *
125
     * @throws \Exception
126
     *
127
     * @return mixed|\Psr\Http\Message\ResponseInterface
128
     */
129 30
    private function sendRequest($method, $requestBody)
130
    {
131
        try {
132
            /** @noinspection PhpUndefinedClassInspection */
133 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...
134
135 30
            return $this->getClient()->send($request);
136 2
        } catch (\Exception $e) {
137 2
            throw new \Exception('Failed to send data to the Slack API: '.$e->getMessage());
138
        }
139
    }
140
141
    /**
142
     * @param $method
143
     * @param array $arguments
144
     *
145
     * @throws \Exception
146
     *
147
     * @return string
148
     */
149 33
    private function prepareRequestBody($method, array $arguments = [])
150
    {
151 33
        $arguments = array_merge($arguments, $this->getArgs());
152
153
        // check the required arguments are provided
154
        try {
155 33
            $this->validateRequiredArguments($method, $arguments);
156 3
        } catch (\Exception $e) {
157 3
            throw new \Exception('Missing required argument(s): '.$e->getMessage());
158
        }
159
160
        // filter unwanted arguments
161 30
        return http_build_query($this->filterArguments($method, $arguments));
162
    }
163
164
    /**
165
     * @param $response
166
     *
167
     * @throws \Exception
168
     *
169
     * @return mixed
170
     */
171 28
    private function processResponse($response)
172
    {
173 28
        $response = json_decode($response->getBody()->getContents(), true);
174
175 28
        if (!is_array($response)) {
176 1
            throw new \Exception('Failed to process response from the Slack API');
177
        }
178
179 27
        return $response;
180
    }
181
182
    /**
183
     * @throws \Exception
184
     *
185
     * @return array
186
     */
187 34
    public function getArgs()
188
    {
189 34
        $config = new Config();
190
191
        return [
192 34
            'token'    => $this->getToken(),
193 34
            'username' => $config->get('botUsername'),
194 34
            'as_user'  => $config->get('asUser'),
195 34
            'icon_url' => $config->get('iconURL'),
196
        ];
197
    }
198
199
    /**
200
     * @param $arguments
201
     *
202
     * @return mixed
203
     */
204 2
    public function chatPostMessage($arguments)
205
    {
206 2
        return $this->apiCall('chat.postMessage', $arguments);
207
    }
208
209
    /**
210
     * @param $arguments
211
     *
212
     * @throws \Exception
213
     *
214
     * @return mixed
215
     */
216 1
    public function rtmStart($arguments)
217
    {
218 1
        return $this->apiCall('rtm.start', $arguments);
219
    }
220
221
    /**
222
     * @throws \Exception
223
     *
224
     * @return array
225
     * @return Team
226
     */
227 4
    public function teamInfo()
228
    {
229 4
        $teamInfo = $this->apiCall('team.info');
230
231 4
        if (!isset($teamInfo['team'])) {
232 2
            return [];
233
        }
234
235 2
        return $teamInfo['team'];
236
    }
237
238
    /**
239
     * @return null|\Botonomous\AbstractBaseSlack
240
     */
241 2
    public function teamInfoAsObject()
242
    {
243 2
        $teamInfo = $this->teamInfo();
244
245 2
        if (empty($teamInfo)) {
246
            /* @noinspection PhpInconsistentReturnPointsInspection */
247 1
            return;
248
        }
249
250
        // return as object
251 1
        return (new Team())->load($teamInfo);
252
    }
253
254
    /**
255
     * List all the Slack users in the team.
256
     *
257
     * @return array
258
     */
259 2
    public function usersList()
260
    {
261 2
        $result = $this->apiCall('users.list');
262
263 2
        if (!isset($result['members'])) {
264 1
            return [];
265
        }
266
267 1
        return $result['members'];
268
    }
269
270
    /**
271
     * Return a user by Slack user id.
272
     *
273
     * @param $arguments
274
     *
275
     * @throws \Exception
276
     *
277
     * @return mixed
278
     */
279 10
    public function userInfo($arguments)
280
    {
281 10
        $result = $this->apiCall('users.info', $arguments);
282
283 10
        if (!isset($result['user'])) {
284
            /* @noinspection PhpInconsistentReturnPointsInspection */
285 4
            return;
286
        }
287
288 6
        return $result['user'];
289
    }
290
291
    /**
292
     * @throws \Exception
293
     *
294
     * @return mixed
295
     */
296 1
    public function test()
297
    {
298 1
        return $this->apiCall('api.test');
299
    }
300
301
    /**
302
     * @throws \Exception
303
     *
304
     * @return array
305
     */
306 5
    public function imList()
307
    {
308 5
        $result = $this->apiCall('im.list');
309
310 5
        if (!isset($result['ims'])) {
311 2
            return [];
312
        }
313
314 4
        return $result['ims'];
315
    }
316
317
    /**
318
     * @return array
319
     */
320 4
    public function imListAsObject()
321
    {
322 4
        $imChannels = $this->imList();
323
324 4
        $imChannelObjects = [];
325 4
        if (empty($imChannels)) {
326 1
            return $imChannelObjects;
327
        }
328
329 3
        foreach ($imChannels as $imChannel) {
330 3
            $imChannelObjects[$imChannel['id']] = (new ImChannel())->load($imChannel);
331
        }
332
333 3
        return $imChannelObjects;
334
    }
335
336
    /**
337
     * @param $arguments
338
     *
339
     * @throws \Exception
340
     *
341
     * @return mixed
342
     */
343 5
    public function oauthAccess($arguments)
344
    {
345 5
        return $this->apiCall('oauth.access', $arguments);
346
    }
347
348
    /** @noinspection PhpUndefinedClassInspection
349
     * @param Client $client
350
     */
351 33
    public function setClient(Client $client)
352
    {
353 33
        $this->client = $client;
354 33
    }
355
356
    /** @noinspection PhpUndefinedClassInspection
357
     * @return Client|null
358
     */
359 30
    public function getClient()
360
    {
361 30
        if (!isset($this->client)) {
362
            /* @noinspection PhpUndefinedClassInspection */
363 8
            $this->setClient(new Client());
364
        }
365
366 30
        return $this->client;
367
    }
368
369
    /**
370
     * @param $method
371
     * @param $arguments
372
     *
373
     * @throws \Exception
374
     *
375
     * @return bool
376
     */
377 33
    private function validateRequiredArguments($method, $arguments)
378
    {
379 33
        $validArguments = $this->getArguments($method);
380
381 33
        if (empty($validArguments['required'])) {
382 3
            return true;
383
        }
384
385 30
        foreach ($validArguments['required'] as $argument) {
386 30
            if ($this->getArrayUtility()->arrayKeyValueExists($argument, $arguments) !== true) {
387 30
                throw new \Exception("{$argument} must be provided for {$method}");
388
            }
389
        }
390
391 27
        return true;
392
    }
393
394
    /**
395
     * @param null $method
396
     *
397
     * @throws \Exception
398
     *
399
     * @return mixed
400
     */
401 35
    public function getArguments($method = null)
402
    {
403 35
        if ($method !== null) {
404 34
            if (!isset($this->arguments[$method])) {
405
                /* @noinspection PhpInconsistentReturnPointsInspection */
406 3
                return;
407
            }
408
409 31
            return $this->arguments[$method];
410
        }
411
412 1
        return $this->arguments;
413
    }
414
415
    /**
416
     * @param array $arguments
417
     */
418 1
    public function setArguments(array $arguments)
419
    {
420 1
        $this->arguments = $arguments;
421 1
    }
422
423
    /**
424
     * @param       $method
425
     * @param array $arguments
426
     *
427
     * @return array
428
     */
429 31
    public function filterArguments($method, array $arguments)
430
    {
431 31
        $validArguments = $this->getArguments($method);
432
433 31
        if (empty($validArguments)) {
434 3
            return $arguments;
435
        }
436
437 28
        if (!isset($validArguments['optional'])) {
438 19
            $validArguments['optional'] = [];
439
        }
440
441 28
        $extractedArguments = array_merge($validArguments['required'], $validArguments['optional']);
442
443 28
        return $this->getArrayUtility()->filterArray($arguments, $extractedArguments);
444
    }
445
446
    /**
447
     * @return string
448
     */
449 34
    public function getToken()
450
    {
451
        // fall back to config
452 34
        if (empty($this->token)) {
453 34
            $this->setToken((new Config())->get('botUserToken'));
454
        }
455
456 34
        return $this->token;
457
    }
458
459
    /**
460
     * @param string $token
461
     */
462 43
    public function setToken($token)
463
    {
464 43
        $this->token = $token;
465 43
    }
466
}
467