Passed
Pull Request — master (#38)
by Dante
03:00 queued 01:04
created

BEditaClient::authenticate()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 1
eloc 3
c 2
b 0
f 0
nc 1
nop 2
dl 0
loc 6
rs 10
1
<?php
2
/**
3
 * BEdita, API-first content management framework
4
 * Copyright 2022 Atlas Srl, ChannelWeb Srl, Chialab Srl
5
 *
6
 * Licensed under The MIT License
7
 * For full copyright and license information, please see the LICENSE.txt
8
 * Redistributions of files must retain the above copyright notice.
9
 */
10
11
namespace BEdita\SDK;
12
13
/**
14
 * BEdita4 API Client class
15
 */
16
class BEditaClient extends BaseClient
17
{
18
    /**
19
     * Classic authentication via POST /auth using username and password
20
     *
21
     * @param string $username username
22
     * @param string $password password
23
     * @return array|null Response in array format
24
     */
25
    public function authenticate(string $username, string $password): ?array
26
    {
27
        $this->unsetAuthorization();
28
        $body = json_encode(compact('username', 'password'));
29
30
        return $this->post('/auth', $body, ['Content-Type' => 'application/json']);
31
    }
32
33
    /**
34
     * Send a GET request a list of resources or objects or a single resource or object
35
     *
36
     * @param string $path Endpoint URL path to invoke
37
     * @param array|null $query Optional query string
38
     * @param array|null $headers Headers
39
     * @return array|null Response in array format
40
     */
41
    public function get(string $path, ?array $query = null, ?array $headers = null): ?array
42
    {
43
        $this->sendRequestRetry('GET', $path, $query, $headers);
44
45
        return $this->getResponseBody();
46
    }
47
48
    /**
49
     * GET a list of resources or objects of a given type
50
     *
51
     * @param string $type Object type name
52
     * @param array|null $query Optional query string
53
     * @param array|null $headers Custom request headers
54
     * @return array|null Response in array format
55
     */
56
    public function getObjects(string $type = 'objects', ?array $query = null, ?array $headers = null): ?array
57
    {
58
        return $this->get(sprintf('/%s', $type), $query, $headers);
59
    }
60
61
    /**
62
     * GET a single object of a given type
63
     *
64
     * @param int|string $id Object id
65
     * @param string $type Object type name
66
     * @param array|null $query Optional query string
67
     * @param array|null $headers Custom request headers
68
     * @return array|null Response in array format
69
     */
70
    public function getObject($id, string $type = 'objects', ?array $query = null, ?array $headers = null): ?array
71
    {
72
        return $this->get(sprintf('/%s/%s', $type, $id), $query, $headers);
73
    }
74
75
    /**
76
     * Get a list of related resources or objects
77
     *
78
     * @param int|string $id Resource id or object uname/id
79
     * @param string $type Type name
80
     * @param string $relation Relation name
81
     * @param array|null $query Optional query string
82
     * @param array|null $headers Custom request headers
83
     * @return array|null Response in array format
84
     */
85
    public function getRelated($id, string $type, string $relation, ?array $query = null, ?array $headers = null): ?array
86
    {
87
        return $this->get(sprintf('/%s/%s/%s', $type, $id, $relation), $query, $headers);
88
    }
89
90
    /**
91
     * Add a list of related resources or objects
92
     *
93
     * @param int|string $id Resource id or object uname/id
94
     * @param string $type Type name
95
     * @param string $relation Relation name
96
     * @param array $data Related resources or objects to add, MUST contain id and type
97
     * @param array|null $headers Custom request headers
98
     * @return array|null Response in array format
99
     */
100
    public function addRelated($id, string $type, string $relation, array $data, ?array $headers = null): ?array
101
    {
102
        $body = compact('data');
103
104
        return $this->post(sprintf('/%s/%s/relationships/%s', $type, $id, $relation), json_encode($body), $headers);
105
    }
106
107
    /**
108
     * Remove a list of related resources or objects
109
     *
110
     * @param int|string $id Resource id or object uname/id
111
     * @param string $type Type name
112
     * @param string $relation Relation name
113
     * @param array $data Related resources or objects to remove from relation
114
     * @param array|null $headers Custom request headers
115
     * @return array|null Response in array format
116
     */
117
    public function removeRelated($id, string $type, string $relation, array $data, ?array $headers = null): ?array
118
    {
119
        $body = compact('data');
120
121
        return $this->delete(sprintf('/%s/%s/relationships/%s', $type, $id, $relation), json_encode($body), $headers);
122
    }
123
124
    /**
125
     * Replace a list of related resources or objects: previuosly related are removed and replaced with these.
126
     *
127
     * @param int|string $id Object id
128
     * @param string $type Object type name
129
     * @param string $relation Relation name
130
     * @param array $data Related resources or objects to insert
131
     * @param array|null $headers Custom request headers
132
     * @return array|null Response in array format
133
     */
134
    public function replaceRelated($id, string $type, string $relation, array $data, ?array $headers = null): ?array
135
    {
136
        $body = compact('data');
137
138
        return $this->patch(sprintf('/%s/%s/relationships/%s', $type, $id, $relation), json_encode($body), $headers);
139
    }
140
141
    /**
142
     * Create a new object or resource (POST) or modify an existing one (PATCH)
143
     *
144
     * @param string $type Object or resource type name
145
     * @param array $data Object or resource data to save
146
     * @param array|null $headers Custom request headers
147
     * @return array|null Response in array format
148
     */
149
    public function save(string $type, array $data, ?array $headers = null): ?array
150
    {
151
        $id = null;
152
        if (array_key_exists('id', $data)) {
153
            $id = $data['id'];
154
            unset($data['id']);
155
        }
156
157
        $body = [
158
            'data' => [
159
                'type' => $type,
160
                'attributes' => $data,
161
            ],
162
        ];
163
        if (!$id) {
164
            return $this->post(sprintf('/%s', $type), json_encode($body), $headers);
165
        }
166
        $body['data']['id'] = $id;
167
168
        return $this->patch(sprintf('/%s/%s', $type, $id), json_encode($body), $headers);
169
    }
170
171
    /**
172
     * [DEPRECATED] Create a new object (POST) or modify an existing one (PATCH)
173
     *
174
     * @param string $type Object type name
175
     * @param array $data Object data to save
176
     * @param array|null $headers Custom request headers
177
     * @return array|null Response in array format
178
     * @deprecated Use `save()` method instead
179
     * @codeCoverageIgnore
180
     */
181
    public function saveObject(string $type, array $data, ?array $headers = null): ?array
182
    {
183
        return $this->save($type, $data, $headers);
184
    }
185
186
    /**
187
     * Delete an object (DELETE) => move to trashcan.
188
     *
189
     * @param int|string $id Object id
190
     * @param string $type Object type name
191
     * @return array|null Response in array format
192
     */
193
    public function deleteObject($id, string $type): ?array
194
    {
195
        return $this->delete(sprintf('/%s/%s', $type, $id));
196
    }
197
198
    /**
199
     * Remove an object => permanently remove object from trashcan.
200
     *
201
     * @param int|string $id Object id
202
     * @return array|null Response in array format
203
     */
204
    public function remove($id): ?array
205
    {
206
        return $this->delete(sprintf('/trash/%s', $id));
207
    }
208
209
    /**
210
     * Upload file (POST)
211
     *
212
     * @param string $filename The file name
213
     * @param string $filepath File full path: could be on a local filesystem or a remote reachable URL
214
     * @param array|null $headers Custom request headers
215
     * @return array|null Response in array format
216
     * @throws BEditaClientException
217
     */
218
    public function upload(string $filename, string $filepath, ?array $headers = null): ?array
219
    {
220
        if (!file_exists($filepath)) {
221
            throw new BEditaClientException('File not found', 500);
222
        }
223
        $file = file_get_contents($filepath);
224
        if (!$file) {
225
            throw new BEditaClientException('File get contents failed', 500);
226
        }
227
        if (empty($headers['Content-Type'])) {
228
            $headers['Content-Type'] = mime_content_type($filepath);
229
        }
230
231
        return $this->post(sprintf('/streams/upload/%s', $filename), $file, $headers);
232
    }
233
234
    /**
235
     * Create media by type and body data and link it to a stream:
236
     *  - `POST /:type` with `$body` as payload, create media object
237
     *  - `PATCH /streams/:stream_id/relationships/object` modify stream adding relation to media
238
     *  - `GET /:type/:id` get media data
239
     *
240
     * @param string $streamId The stream identifier
241
     * @param string $type The type
242
     * @param array $body The body data
243
     * @return array|null Response in array format
244
     * @throws BEditaClientException
245
     */
246
    public function createMediaFromStream($streamId, string $type, array $body): ?array
247
    {
248
        $response = $this->post(sprintf('/%s', $type), json_encode($body));
249
        if (empty($response)) {
250
            throw new BEditaClientException('Invalid response from POST ' . sprintf('/%s', $type));
251
        }
252
        $id = $response['data']['id'];
253
        $data = compact('id', 'type');
254
        $body = compact('data');
255
        $response = $this->patch(sprintf('/streams/%s/relationships/object', $streamId), json_encode($body));
256
        if (empty($response)) {
257
            throw new BEditaClientException('Invalid response from PATCH ' . sprintf('/streams/%s/relationships/object', $id));
258
        }
259
260
        return $this->getObject($data['id'], $data['type']);
261
    }
262
263
    /**
264
     * Thumbnail request using `GET /media/thumbs` endpoint
265
     *
266
     *  Usage:
267
     *          thumbs(123) => `GET /media/thumbs/123`
268
     *          thumbs(123, ['preset' => 'glide']) => `GET /media/thumbs/123&preset=glide`
269
     *          thumbs(null, ['ids' => '123,124,125']) => `GET /media/thumbs?ids=123,124,125`
270
     *          thumbs(null, ['ids' => '123,124,125', 'preset' => 'async']) => `GET /media/thumbs?ids=123,124,125&preset=async`
271
     *          thumbs(123, ['options' => ['w' => 100, 'h' => 80, 'fm' => 'jpg']]) => `GET /media/thumbs/123/options[w]=100&options[h]=80&options[fm]=jpg` (these options could be not available... just set in preset(s))
272
     *
273
     * @param int|null $id the media Id.
274
     * @param array $query The query params for thumbs call.
275
     * @return array|null Response in array format
276
     */
277
    public function thumbs($id = null, $query = []): ?array
278
    {
279
        if (empty($id) && empty($query['ids'])) {
280
            throw new BEditaClientException('Invalid empty id|ids for thumbs');
281
        }
282
        $endpoint = '/media/thumbs';
283
        if (!empty($id)) {
284
            $endpoint .= sprintf('/%d', $id);
285
        }
286
287
        return $this->get($endpoint, $query);
288
    }
289
290
    /**
291
     * Get JSON SCHEMA of a resource or object
292
     *
293
     * @param string $type Object or resource type name
294
     * @return array|null JSON SCHEMA in array format
295
     */
296
    public function schema(string $type): ?array
297
    {
298
        $h = ['Accept' => 'application/schema+json'];
299
300
        return $this->get(sprintf('/model/schema/%s', $type), null, $h);
301
    }
302
303
    /**
304
     * Get info of a relation (data, params) and get left/right object types
305
     *
306
     * @param string $name relation name
307
     * @return array|null relation data in array format
308
     */
309
    public function relationData(string $name): ?array
310
    {
311
        $query = [
312
            'include' => 'left_object_types,right_object_types',
313
        ];
314
315
        return $this->get(sprintf('/model/relations/%s', $name), $query);
316
    }
317
318
    /**
319
     * Restore object from trash
320
     *
321
     * @param int|string $id Object id
322
     * @param string $type Object type name
323
     * @return array|null Response in array format
324
     */
325
    public function restoreObject($id, string $type): ?array
326
    {
327
        $body = [
328
            'data' => [
329
                'id' => $id,
330
                'type' => $type,
331
            ],
332
        ];
333
334
        return $this->patch(sprintf('/%s/%s', 'trash', $id), json_encode($body));
335
    }
336
337
    /**
338
     * Send a PATCH request to modify a single resource or object
339
     *
340
     * @param string $path Endpoint URL path to invoke
341
     * @param mixed $body Request body
342
     * @param array|null $headers Custom request headers
343
     * @return array|null Response in array format
344
     */
345
    public function patch(string $path, $body, ?array $headers = null): ?array
346
    {
347
        $this->sendRequestRetry('PATCH', $path, null, $headers, $body);
348
349
        return $this->getResponseBody();
350
    }
351
352
    /**
353
     * Send a POST request for creating resources or objects or other operations like /auth
354
     *
355
     * @param string $path Endpoint URL path to invoke
356
     * @param mixed $body Request body
357
     * @param array|null $headers Custom request headers
358
     * @return array|null Response in array format
359
     */
360
    public function post(string $path, $body, ?array $headers = null): ?array
361
    {
362
        $this->sendRequestRetry('POST', $path, null, $headers, $body);
363
364
        return $this->getResponseBody();
365
    }
366
367
    /**
368
     * Send a DELETE request
369
     *
370
     * @param string $path Endpoint URL path to invoke.
371
     * @param mixed $body Request body
372
     * @param array|null $headers Custom request headers
373
     * @return array|null Response in array format.
374
     */
375
    public function delete(string $path, $body = null, ?array $headers = null): ?array
376
    {
377
        $this->sendRequestRetry('DELETE', $path, null, $headers, $body);
378
379
        return $this->getResponseBody();
380
    }
381
}
382