BaseClientRemote::getDefaultAPIVersion()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 0
dl 0
loc 4
ccs 2
cts 2
cp 1
crap 1
rs 10
c 0
b 0
f 0
1
<?php
2
3
/**
4
 * Directus – <http://getdirectus.com>
5
 *
6
 * @link      The canonical repository – <https://github.com/directus/directus>
7
 * @copyright Copyright 2006-2016 RANGER Studio, LLC – <http://rangerstudio.com>
8
 * @license   GNU General Public License (v3) – <http://www.gnu.org/copyleft/gpl.html>
9
 */
10
11
namespace Directus\SDK;
12
13
use Directus\SDK\Exception\UnauthorizedRequestException;
14
use Directus\SDK\Response\Entry;
15
use Directus\SDK\Response\EntryCollection;
16
use Directus\Util\ArrayUtils;
17
use GuzzleHttp\Client as HTTPClient;
18
use GuzzleHttp\Exception\ClientException;
19
use GuzzleHttp\Psr7\Request;
20
use GuzzleHttp\Psr7\Uri;
21
use GuzzleHttp\Psr7\UriResolver;
22
23
/**
24
 * Abstract Base Client Remote
25
 *
26
 * @author Welling Guzmán <[email protected]>
27
 */
28
abstract class BaseClientRemote extends AbstractClient
0 ignored issues
show
Coding Style introduced by
BaseClientRemote does not seem to conform to the naming convention (^Abstract|Factory$).

This check examines a number of code elements and verifies that they conform to the given naming conventions.

You can set conventions for local variables, abstract classes, utility classes, constant, properties, methods, parameters, interfaces, classes, exceptions and special methods.

Loading history...
29
{
30
    /**
31
     * Directus base url
32
     *
33
     * @var string
34
     */
35
    protected $baseUrl = 'http://localhost';
36
37
    /**
38
     * Directus hosted base url format
39
     *
40
     * @var string
41
     */
42
    protected $hostedBaseUrlFormat = 'https://%s.directus.io';
43
44
    /**
45
     * Directus Server base endpoint
46
     *
47
     * @var string
48
     */
49
    protected $baseEndpoint;
50
51
    /**
52
     * API Version
53
     *
54
     * @var string
55
     */
56
    protected $apiVersion;
57
58
    /**
59
     * Directus Hosted endpoint format.
60
     *
61
     * @var string
62
     */
63
    protected $hostedBaseEndpointFormat;
64
65
    /**
66
     * Directus Hosted Instance Key
67
     *
68
     * @var int|string
69
     */
70
    protected $instanceKey;
71
72
    /**
73
     * Authentication Token
74
     *
75
     * @var string
76
     */
77
    protected $accessToken;
78
79
    /**
80
     * HTTP Client
81
     *
82
     * @var \GuzzleHttp\Client
83
     */
84
    protected $httpClient;
85
86
    /**
87
     * HTTP Client request timeout
88
     *
89
     * @var int
90
     */
91
    protected $timeout = 60;
92
93
    const ACTIVITY_GET_ENDPOINT = 'activity';
94
95
    const BOOKMARKS_CREATE_ENDPOINT = 'bookmarks';
96
    const BOOKMARKS_READ_ENDPOINT = 'bookmarks/%s';
97
    const BOOKMARKS_DELETE_ENDPOINT = 'bookmarks/%s';
98
    const BOOKMARKS_ALL_ENDPOINT = 'bookmarks';
99
    const BOOKMARKS_USER_ENDPOINT = 'bookmarks/user/%s';
100
101
    const TABLE_ENTRIES_ENDPOINT = 'tables/%s/rows';
102
    const TABLE_ENTRY_ENDPOINT = 'tables/%s/rows/%s';
103
    const TABLE_ENTRY_CREATE_ENDPOINT = 'tables/%s/rows';
104
    const TABLE_ENTRY_UPDATE_ENDPOINT = 'tables/%s/rows/%s';
105
    const TABLE_ENTRY_DELETE_ENDPOINT = 'tables/%s/rows/%s';
106
    const TABLE_LIST_ENDPOINT = 'tables';
107
    const TABLE_INFORMATION_ENDPOINT = 'tables/%s';
108
    const TABLE_PREFERENCES_ENDPOINT = 'tables/%s/preferences';
109
    const TABLE_CREATE_ENDPOINT = 'privileges/1'; // ID not being used but required @TODO: REMOVE IT
110
    const TABLE_DELETE_ENDPOINT = 'tables/%s';
111
112
    const COLUMN_LIST_ENDPOINT = 'tables/%s/columns';
113
    const COLUMN_CREATE_ENDPOINT = 'tables/%s/columns';
114
    const COLUMN_DELETE_ENDPOINT = 'tables/%s/columns/%s';
115
    const COLUMN_INFORMATION_ENDPOINT = 'tables/%s/columns/%s';
116
    const COLUMN_OPTIONS_CREATE_ENDPOINT = 'tables/%s/columns/%s/%s';
117
118
    const GROUP_LIST_ENDPOINT = 'groups';
119
    const GROUP_CREATE_ENDPOINT = 'groups';
120
    const GROUP_INFORMATION_ENDPOINT = 'groups/%s';
121
    const GROUP_PRIVILEGES_ENDPOINT = 'privileges/%s';
122
    const GROUP_PRIVILEGES_CREATE_ENDPOINT = 'privileges/%s';
123
124
    const FILE_LIST_ENDPOINT = 'files';
125
    const FILE_CREATE_ENDPOINT = 'files';
126
    const FILE_UPDATE_ENDPOINT = 'files/%s';
127
    const FILE_INFORMATION_ENDPOINT = 'files/%s';
128
129
    const SETTING_LIST_ENDPOINT = 'settings';
130
    const SETTING_COLLECTION_GET_ENDPOINT = 'settings/%s';
131
    const SETTING_COLLECTION_UPDATE_ENDPOINT = 'settings/%s';
132
133
    const MESSAGES_CREATE_ENDPOINT = 'messages/rows';
134
    const MESSAGES_LIST_ENDPOINT = 'messages/rows';
135
    const MESSAGES_GET_ENDPOINT = 'messages/rows/%s';
136
    const MESSAGES_USER_LIST_ENDPOINT = 'messages/user/%s';
137
138
    const UTILS_RANDOM_ENDPOINT = 'random';
139
    const UTILS_HASH_ENDPOINT = 'hash';
140
141 38
    public function __construct($accessToken, $options = [])
142
    {
143 38
        $this->accessToken = $accessToken;
144
145 38
        if (isset($options['base_url'])) {
146 4
            $this->baseUrl = rtrim($options['base_url'], '/');
147 2
        }
148
149 38
        $instanceKey = isset($options['instance_key']) ? $options['instance_key'] : false;
150 38
        if ($instanceKey) {
151 2
            $this->instanceKey = $instanceKey;
152 2
            $this->baseUrl = sprintf($this->hostedBaseUrlFormat, $instanceKey);
153 1
        }
154
155 38
        $this->apiVersion = isset($options['version']) ? $options['version'] : $this->getDefaultAPIVersion();
156 38
        $this->baseEndpoint = $this->baseUrl . '/api/' . $this->getAPIVersion();
157
158 38
        $this->setHTTPClient($this->getDefaultHTTPClient());
159 38
    }
160
161
    /**
162
     * Get the base endpoint url
163
     *
164
     * @return string
165
     */
166 34
    public function getBaseEndpoint()
167
    {
168 34
        return $this->baseEndpoint;
169
    }
170
171
    /**
172
     * Get the base url
173
     *
174
     * @return string
175
     */
176 2
    public function getBaseUrl()
177
    {
178 2
        return $this->baseUrl;
179
    }
180
181
    /**
182
     * Get API Version
183
     *
184
     * @return int|string
185
     */
186 38
    public function getAPIVersion()
187
    {
188 38
        return $this->apiVersion;
189
    }
190
191
    /**
192
     * Gets the default API version
193
     *
194
     * @return string
195
     */
196 38
    public function getDefaultAPIVersion()
197
    {
198 38
        return '1.1';
199
    }
200
201
    /**
202
     * Get the authentication access token
203
     *
204
     * @return string
205
     */
206 32
    public function getAccessToken()
207
    {
208 32
        return $this->accessToken;
209
    }
210
211
    /**
212
     * Set a new authentication access token
213
     *
214
     * @param $newAccessToken
215
     */
216 2
    public function setAccessToken($newAccessToken)
217
    {
218 2
        $this->accessToken = $newAccessToken;
219 2
    }
220
221
    /**
222
     * Get the Directus hosted instance key
223
     *
224
     * @return null|string
0 ignored issues
show
Documentation introduced by
Should the return type not be integer|string?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
225
     */
226 4
    public function getInstanceKey()
227
    {
228 4
        return $this->instanceKey;
229
    }
230
231
    /**
232
     * Set the HTTP Client
233
     *
234
     * @param HTTPClient $httpClient
235
     */
236 38
    public function setHTTPClient(HTTPClient $httpClient)
237
    {
238 38
        $this->httpClient = $httpClient;
239 38
    }
240
241
    /**
242
     * Get the HTTP Client
243
     *
244
     * @return HTTPClient|null
245
     */
246 38
    public function getHTTPClient()
247
    {
248 38
        return $this->httpClient;
249
    }
250
251
    /**
252
     * Get the default HTTP Client
253
     *
254
     * @return HTTPClient
255
     */
256 38
    public function getDefaultHTTPClient()
257
    {
258 38
        $baseUrlAttr = $this->isPsr7Version() ? 'base_uri' : 'base_url';
259
260 38
        return new HTTPClient([
261 38
            $baseUrlAttr => rtrim($this->baseEndpoint, '/') . '/'
262 19
        ]);
263
    }
264
265
    /**
266
     * Checks whether guzzle 6 is used
267
     *
268
     * @return bool
269
     */
270 38
    public function isPsr7Version()
271
    {
272 38
        return (bool) version_compare(HTTPClient::VERSION, '6.0.0', '>=');
273
    }
274
275
    /**
276
     * Perform a HTTP Request
277
     *
278
     * @param $method
279
     * @param $path
280
     * @param array $params
281
     *
282
     * @return Entry|EntryCollection
283
     *
284
     * @throws UnauthorizedRequestException
285
     */
286 28
    public function performRequest($method, $path, array $params = [])
287
    {
288 28
        $request = $this->buildRequest($method, $path, $params);
289
290
        try {
291 28
            $response = $this->httpClient->send($request);
292 28
            $content = json_decode($response->getBody()->getContents(), true);
293 14
        } catch (ClientException $ex) {
294
            if ($ex->getResponse()->getStatusCode() == 401) {
295
                if ($this->isPsr7Version()) {
296
                    $uri = $request->getUri();
297
                } else {
298
                    $uri = $request->getUrl();
0 ignored issues
show
Bug introduced by
The method getUrl() does not seem to exist on object<GuzzleHttp\Psr7\Request>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
299
                }
300
301
                $message = sprintf('Unauthorized %s Request to %s', $request->getMethod(), $uri);
302
303
                throw new UnauthorizedRequestException($message);
304
            }
305
306
            throw $ex;
307
        }
308
309 28
        return $this->createResponseFromData($content);
310
    }
311
312
    /**
313
     * Build a request object
314
     *
315
     * @param $method
316
     * @param $path
317
     * @param $params
318
     *
319
     * @return \GuzzleHttp\Message\Request|Request
0 ignored issues
show
Documentation introduced by
Should the return type not be \GuzzleHttp\Message\Requ...equestInterface|Request?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
320
     */
321 30
    public function buildRequest($method, $path, array $params = [])
322
    {
323 30
        $body = ArrayUtils::get($params, 'body', null);
324 30
        $query = ArrayUtils::get($params, 'query', null);
325 30
        $options = [];
326
327 30
        if (in_array($method, ['POST', 'PUT', 'PATCH']) && $body) {
328
            $options['body'] = $body;
329
        }
330
331 30
        if ($query) {
332
            $options['query'] = $query;
333
        }
334
335 30
        return $this->createRequest($method, $path, $options);
336
    }
337
338
    /**
339
     * Creates a request for 5.x or 6.x guzzle version
340
     *
341
     * @param $method
342
     * @param $path
343
     * @param $options
344
     *
345
     * @return \GuzzleHttp\Message\Request|\GuzzleHttp\Message\RequestInterface|Request
346
     */
347 30
    public function createRequest($method, $path, $options)
348
    {
349 30
        if ($this->isPsr7Version()) {
350
            $headers = [
351 30
                'Content-Type'  => 'application/json',
352 30
                'Authorization' => 'Bearer ' . $this->getAccessToken(),
353 15
            ];
354
355 30
            $body = ArrayUtils::get($options, 'body', null);
356 30
            $uri = UriResolver::resolve(new Uri($this->getBaseEndpoint() . '/'), new Uri($path));
357
358 30
            if ($body) {
359
                $body = json_encode($body);
360
            }
361
362 30
            if (ArrayUtils::has($options, 'query')) {
363
                $query = $options['query'];
364
365
                if (is_array($query)) {
366
                    $query = http_build_query($query, null, '&', PHP_QUERY_RFC3986);
367
                }
368
369
                if (!is_string($query)) {
370
                    throw new \InvalidArgumentException('query must be a string or array');
371
                }
372
373
                $uri = $uri->withQuery($query);
374
            }
375
376 30
            $request = new Request($method, $uri, $headers, $body);
377 15
        } else {
378
            $options['auth'] = [$this->accessToken, ''];
379
380
            $request = $this->httpClient->createRequest($method, $path, $options);
0 ignored issues
show
Bug introduced by
The method createRequest() does not exist on GuzzleHttp\Client. Did you maybe mean request()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
381
382
            $query = ArrayUtils::get($options, 'query');
383
            if ($query) {
384
                $q = $request->getQuery();
385
                foreach($query as $key => $value) {
386
                    $q->set($key, $value);
387
                }
388
            }
389
        }
390
391 30
        return $request;
392
    }
393
394
    /**
395
     * Build a endpoint path based on a format
396
     *
397
     * @param string $pathFormat
398
     * @param string|array $variables
399
     *
400
     * @return string
401
     */
402 24
    public function buildPath($pathFormat, $variables = [])
403
    {
404 24
        return vsprintf(ltrim($pathFormat, '/'), $variables);
405
    }
406
}
407