Passed
Push — master ( 5fb0b3...a1dc53 )
by Dante
01:22
created

BEditaClient::post()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

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