1
|
|
|
<?php |
2
|
|
|
/** |
3
|
|
|
* BEdita, API-first content management framework |
4
|
|
|
* Copyright 2018 ChannelWeb Srl, Chialab Srl |
5
|
|
|
* |
6
|
|
|
* This file is part of BEdita: you can redistribute it and/or modify |
7
|
|
|
* it under the terms of the GNU Lesser General Public License as published |
8
|
|
|
* by the Free Software Foundation, either version 3 of the License, or |
9
|
|
|
* (at your option) any later version. |
10
|
|
|
* |
11
|
|
|
* See LICENSE.LGPL or <http://gnu.org/licenses/lgpl-3.0.html> for more details. |
12
|
|
|
*/ |
13
|
|
|
namespace App\Controller; |
14
|
|
|
|
15
|
|
|
use App\Core\Exception\UploadException; |
16
|
|
|
use BEdita\SDK\BEditaClientException; |
17
|
|
|
use Cake\Event\Event; |
18
|
|
|
use Cake\Http\Exception\InternalErrorException; |
19
|
|
|
use Cake\Http\Response; |
20
|
|
|
use Cake\Utility\Hash; |
21
|
|
|
use Psr\Log\LogLevel; |
22
|
|
|
|
23
|
|
|
/** |
24
|
|
|
* Modules controller: list, add, edit, remove objects |
25
|
|
|
* |
26
|
|
|
* @property \App\Controller\Component\ProjectConfigurationComponent $ProjectConfiguration |
27
|
|
|
* @property \App\Controller\Component\PropertiesComponent $Properties |
28
|
|
|
*/ |
29
|
|
|
class ModulesController extends AppController |
30
|
|
|
{ |
31
|
|
|
protected const FIXED_RELATIONSHIPS = [ |
32
|
|
|
'parent', |
33
|
|
|
'children', |
34
|
|
|
'parents', |
35
|
|
|
'translations', |
36
|
|
|
'streams', |
37
|
|
|
'roles', |
38
|
|
|
]; |
39
|
|
|
|
40
|
|
|
/** |
41
|
|
|
* Object type currently used |
42
|
|
|
* |
43
|
|
|
* @var string |
44
|
|
|
*/ |
45
|
|
|
protected $objectType = null; |
46
|
|
|
|
47
|
|
|
/** |
48
|
|
|
* {@inheritDoc} |
49
|
|
|
*/ |
50
|
|
|
public function initialize() : void |
51
|
|
|
{ |
52
|
|
|
parent::initialize(); |
53
|
|
|
|
54
|
|
|
$this->loadComponent('Properties'); |
55
|
|
|
$this->loadComponent('ProjectConfiguration'); |
56
|
|
|
|
57
|
|
|
if (!empty($this->request)) { |
58
|
|
|
$this->objectType = $this->request->getParam('object_type'); |
59
|
|
|
$this->Modules->setConfig('currentModuleName', $this->objectType); |
60
|
|
|
$this->Schema->setConfig('type', $this->objectType); |
61
|
|
|
} |
62
|
|
|
|
63
|
|
|
$this->Security->setConfig('unlockedActions', ['saveJson']); |
64
|
|
|
} |
65
|
|
|
|
66
|
|
|
/** |
67
|
|
|
* {@inheritDoc} |
68
|
|
|
* @codeCoverageIgnore |
69
|
|
|
*/ |
70
|
|
|
public function beforeRender(Event $event) : ?Response |
71
|
|
|
{ |
72
|
|
|
$this->set('objectType', $this->objectType); |
73
|
|
|
|
74
|
|
|
return parent::beforeRender($event); |
|
|
|
|
75
|
|
|
} |
76
|
|
|
|
77
|
|
|
/** |
78
|
|
|
* Display resources list. |
79
|
|
|
* |
80
|
|
|
* @return \Cake\Http\Response|null |
81
|
|
|
*/ |
82
|
|
|
public function index() : ?Response |
83
|
|
|
{ |
84
|
|
|
$this->request->allowMethod(['get']); |
85
|
|
|
|
86
|
|
|
// handle filter and query parameters using session |
87
|
|
|
$result = $this->applySessionFilter(); |
88
|
|
|
if ($result != null) { |
89
|
|
|
return $result; |
90
|
|
|
} |
91
|
|
|
|
92
|
|
|
try { |
93
|
|
|
$response = $this->apiClient->getObjects($this->objectType, $this->request->getQueryParams()); |
94
|
|
|
} catch (BEditaClientException $e) { |
95
|
|
|
$this->log($e, LogLevel::ERROR); |
96
|
|
|
$this->Flash->error($e->getMessage(), ['params' => $e]); |
97
|
|
|
// remove session filter to avoid error repetition |
98
|
|
|
$session = $this->request->getSession(); |
99
|
|
|
$session->delete(sprintf('%s.filter', $this->Modules->getConfig('currentModuleName'))); |
100
|
|
|
|
101
|
|
|
return $this->redirect(['_name' => 'dashboard']); |
102
|
|
|
} |
103
|
|
|
|
104
|
|
|
$this->ProjectConfiguration->read(); |
105
|
|
|
|
106
|
|
|
$objects = (array)$response['data']; |
107
|
|
|
$this->set('objects', $objects); |
108
|
|
|
$this->set('meta', (array)$response['meta']); |
109
|
|
|
$this->set('links', (array)$response['links']); |
110
|
|
|
$this->set('types', ['right' => $this->descendants()]); |
111
|
|
|
|
112
|
|
|
if (!empty($this->request->getQueryParams()['autocomplete'])) { |
113
|
|
|
$this->render('autocomplete'); |
114
|
|
|
} |
115
|
|
|
|
116
|
|
|
$this->set('properties', $this->Properties->indexList($this->objectType)); |
117
|
|
|
|
118
|
|
|
// base/custom filters for filter view |
119
|
|
|
$this->set('filter', $this->Properties->filterList($this->objectType)); |
120
|
|
|
|
121
|
|
|
// base/custom bulk actions for index view |
122
|
|
|
$this->set('bulkActions', $this->Properties->bulkList($this->objectType)); |
123
|
|
|
|
124
|
|
|
// objectTypes schema |
125
|
|
|
$this->set('schema', $this->getSchemaForIndex($this->objectType)); |
126
|
|
|
|
127
|
|
|
// set prevNext for views navigations |
128
|
|
|
$this->setObjectNav($objects); |
129
|
|
|
|
130
|
|
|
return null; |
131
|
|
|
} |
132
|
|
|
|
133
|
|
|
/** |
134
|
|
|
* Retrieve descendants of `$this->objectType` if any |
135
|
|
|
* |
136
|
|
|
* @return array |
137
|
|
|
*/ |
138
|
|
|
protected function descendants() : array |
139
|
|
|
{ |
140
|
|
|
if (!$this->Modules->isAbstract($this->objectType)) { |
141
|
|
|
return []; |
142
|
|
|
} |
143
|
|
|
$filter = [ |
144
|
|
|
'parent' => $this->objectType, |
145
|
|
|
'enabled' => true, |
146
|
|
|
]; |
147
|
|
|
$sort = 'name'; |
148
|
|
|
|
149
|
|
|
try { |
150
|
|
|
$descendants = $this->apiClient->get('/model/object_types', compact('filter', 'sort') + ['fields' => 'name']); |
151
|
|
|
} catch (BEditaClientException $e) { |
152
|
|
|
// Error! Return empty list. |
153
|
|
|
$this->log($e, LogLevel::ERROR); |
154
|
|
|
|
155
|
|
|
return []; |
156
|
|
|
} |
157
|
|
|
|
158
|
|
|
return (array)Hash::extract($descendants, 'data.{n}.attributes.name'); |
159
|
|
|
} |
160
|
|
|
|
161
|
|
|
/** |
162
|
|
|
* View single resource. |
163
|
|
|
* |
164
|
|
|
* @param string|int $id Resource ID. |
165
|
|
|
* @return \Cake\Http\Response|null |
166
|
|
|
*/ |
167
|
|
|
public function view($id) : ?Response |
168
|
|
|
{ |
169
|
|
|
$this->request->allowMethod(['get']); |
170
|
|
|
|
171
|
|
|
try { |
172
|
|
|
$response = $this->apiClient->getObject($id, $this->objectType); |
173
|
|
|
} catch (BEditaClientException $e) { |
174
|
|
|
// Error! Back to index. |
175
|
|
|
$this->log($e, LogLevel::ERROR); |
176
|
|
|
$this->Flash->error(__('Error retrieving the requested content'), ['params' => $e]); |
177
|
|
|
|
178
|
|
|
return $this->redirect(['_name' => 'modules:list', 'object_type' => $this->objectType]); |
179
|
|
|
} |
180
|
|
|
$this->ProjectConfiguration->read(); |
181
|
|
|
|
182
|
|
|
$revision = Hash::get($response, 'meta.schema.' . $this->objectType . '.revision', null); |
183
|
|
|
$schema = $this->Schema->getSchema($this->objectType, $revision); |
184
|
|
|
|
185
|
|
|
$object = $response['data']; |
186
|
|
|
$included = (!empty($response['included'])) ? $response['included'] : []; |
187
|
|
|
$this->set(compact('object', 'included', 'schema')); |
188
|
|
|
$this->set('properties', $this->Properties->viewGroups($object, $this->objectType)); |
189
|
|
|
|
190
|
|
|
// relatinos between objects |
191
|
|
|
$relationsSchema = array_intersect_key($this->Schema->getRelationsSchema(), $object['relationships']); |
192
|
|
|
// relations between objects and resources |
193
|
|
|
$resourceRelations = array_diff(array_keys($object['relationships']), array_keys($relationsSchema), self::FIXED_RELATIONSHIPS); |
194
|
|
|
|
195
|
|
|
$this->set(compact('relationsSchema', 'resourceRelations')); |
196
|
|
|
$this->set('objectRelations', array_keys($relationsSchema)); |
197
|
|
|
|
198
|
|
|
// set objectNav |
199
|
|
|
$objectNav = $this->getObjectNav((string)$id); |
200
|
|
|
$this->set('objectNav', $objectNav); |
201
|
|
|
|
202
|
|
|
return null; |
203
|
|
|
} |
204
|
|
|
|
205
|
|
|
/** |
206
|
|
|
* View single resource by id, doing a proper redirect (302) to resource module view by type. |
207
|
|
|
* If no resource found by ID, redirect to referer. |
208
|
|
|
* |
209
|
|
|
* @param string|int $id Resource ID. |
210
|
|
|
* @return \Cake\Http\Response|null |
211
|
|
|
*/ |
212
|
|
|
public function uname($id) : ?Response |
213
|
|
|
{ |
214
|
|
|
try { |
215
|
|
|
$response = $this->apiClient->get(sprintf('/objects/%s', $id)); |
216
|
|
|
} catch (BEditaClientException $e) { |
217
|
|
|
if ($e->getCode() === 404) { |
218
|
|
|
$error = sprintf(__('Resource "%s" not found', true), $id); |
219
|
|
|
} else { |
220
|
|
|
$error = sprintf(__('Resource "%s" not available. Error: %s', true), $id, $e->getMessage()); |
221
|
|
|
} |
222
|
|
|
$this->Flash->error($error); |
223
|
|
|
|
224
|
|
|
return $this->redirect($this->referer()); |
225
|
|
|
} |
226
|
|
|
$_name = 'modules:view'; |
227
|
|
|
$object_type = $response['data']['type']; |
228
|
|
|
$id = $response['data']['id']; |
229
|
|
|
|
230
|
|
|
return $this->redirect(compact('_name', 'object_type', 'id')); |
231
|
|
|
} |
232
|
|
|
|
233
|
|
|
/** |
234
|
|
|
* Display new resource form. |
235
|
|
|
* |
236
|
|
|
* @return \Cake\Http\Response|null |
237
|
|
|
*/ |
238
|
|
|
public function create() : ?Response |
239
|
|
|
{ |
240
|
|
|
$this->viewBuilder()->setTemplate('view'); |
241
|
|
|
|
242
|
|
|
// Create stub object with empty `attributes`. |
243
|
|
|
$schema = $this->Schema->getSchema(); |
244
|
|
|
if (!is_array($schema)) { |
245
|
|
|
$this->Flash->error(__('Cannot create abstract objects or objects without schema')); |
246
|
|
|
|
247
|
|
|
return $this->redirect(['_name' => 'modules:list', 'object_type' => $this->objectType]); |
248
|
|
|
} |
249
|
|
|
$attributes = array_fill_keys( |
250
|
|
|
array_keys( |
251
|
|
|
array_filter( |
252
|
|
|
$schema['properties'], |
253
|
|
|
function ($schema) { |
254
|
|
|
return empty($schema['readOnly']); |
255
|
|
|
} |
256
|
|
|
) |
257
|
|
|
), |
258
|
|
|
'' |
259
|
|
|
); |
260
|
|
|
$object = [ |
261
|
|
|
'type' => $this->objectType, |
262
|
|
|
'attributes' => $attributes, |
263
|
|
|
]; |
264
|
|
|
|
265
|
|
|
$this->set(compact('object', 'schema')); |
266
|
|
|
$this->set('properties', $this->Properties->viewGroups($object, $this->objectType)); |
267
|
|
|
|
268
|
|
|
return null; |
269
|
|
|
} |
270
|
|
|
|
271
|
|
|
/** |
272
|
|
|
* Create or edit single resource. |
273
|
|
|
* |
274
|
|
|
* @return \Cake\Http\Response|null |
275
|
|
|
*/ |
276
|
|
|
public function save() : ?Response |
277
|
|
|
{ |
278
|
|
|
$this->request->allowMethod(['post']); |
279
|
|
|
$requestData = $this->prepareRequest($this->objectType); |
280
|
|
|
|
281
|
|
|
try { |
282
|
|
|
if (!empty($requestData['_api'])) { |
283
|
|
|
foreach ($requestData['_api'] as $api) { |
284
|
|
|
extract($api); // method, id, type, relation, relatedIds |
285
|
|
|
if (in_array($method, ['addRelated', 'removeRelated', 'replaceRelated'])) { |
286
|
|
|
$this->apiClient->{$method}($id, $this->objectType, $relation, $relatedIds); |
287
|
|
|
} |
288
|
|
|
} |
289
|
|
|
} |
290
|
|
|
unset($requestData['_api']); |
291
|
|
|
|
292
|
|
|
// upload file (if available) |
293
|
|
|
$this->Modules->upload($requestData); |
294
|
|
|
|
295
|
|
|
// save data |
296
|
|
|
$response = $this->apiClient->save($this->objectType, $requestData); |
297
|
|
|
} catch (InternalErrorException | BEditaClientException | UploadException $e) { |
298
|
|
|
// Error! Back to object view or index. |
299
|
|
|
$this->log($e, LogLevel::ERROR); |
300
|
|
|
$this->Flash->error($e->getMessage(), ['params' => $e]); |
301
|
|
|
|
302
|
|
|
if ($this->request->getData('id')) { |
303
|
|
|
return $this->redirect(['_name' => 'modules:view', 'object_type' => $this->objectType, 'id' => $this->request->getData('id')]); |
304
|
|
|
} |
305
|
|
|
|
306
|
|
|
return $this->redirect(['_name' => 'modules:list', 'object_type' => $this->objectType]); |
307
|
|
|
} |
308
|
|
|
|
309
|
|
|
// annoying message removed, restore with https://github.com/bedita/manager/issues/71 |
310
|
|
|
// $this->Flash->success(__('Object saved')); |
311
|
|
|
|
312
|
|
|
return $this->redirect([ |
313
|
|
|
'_name' => 'modules:view', |
314
|
|
|
'object_type' => $this->objectType, |
315
|
|
|
'id' => Hash::get($response, 'data.id'), |
316
|
|
|
]); |
317
|
|
|
} |
318
|
|
|
|
319
|
|
|
/** |
320
|
|
|
* Create new object from ajax request. |
321
|
|
|
* |
322
|
|
|
* @return void |
323
|
|
|
*/ |
324
|
|
|
public function saveJson() : void |
325
|
|
|
{ |
326
|
|
|
$this->viewBuilder()->setClassName('Json'); // force json response |
327
|
|
|
$this->request->allowMethod(['post']); |
328
|
|
|
$requestData = $this->prepareRequest($this->objectType); |
329
|
|
|
|
330
|
|
|
try { |
331
|
|
|
// upload file (if available) |
332
|
|
|
$this->Modules->upload($requestData); |
333
|
|
|
|
334
|
|
|
// save data |
335
|
|
|
$response = $this->apiClient->save($this->objectType, $requestData); |
336
|
|
|
} catch (BEditaClientException $error) { |
337
|
|
|
$this->log($error, LogLevel::ERROR); |
338
|
|
|
|
339
|
|
|
$this->set(compact('error')); |
340
|
|
|
$this->set('_serialize', ['error']); |
341
|
|
|
|
342
|
|
|
return; |
343
|
|
|
} |
344
|
|
|
if ($response['data']) { |
345
|
|
|
$response['data'] = [ $response['data'] ]; |
346
|
|
|
} |
347
|
|
|
|
348
|
|
|
$this->getThumbsUrls($response); |
|
|
|
|
349
|
|
|
|
350
|
|
|
$this->set((array)$response); |
351
|
|
|
$this->set('_serialize', array_keys($response)); |
352
|
|
|
} |
353
|
|
|
|
354
|
|
|
/** |
355
|
|
|
* Clone single object. |
356
|
|
|
* |
357
|
|
|
* @param string|int $id Object ID. |
358
|
|
|
* @return \Cake\Http\Response|null |
359
|
|
|
*/ |
360
|
|
|
public function clone($id) : ?Response |
361
|
|
|
{ |
362
|
|
|
$this->viewBuilder()->setTemplate('view'); |
363
|
|
|
|
364
|
|
|
$schema = $this->Schema->getSchema(); |
365
|
|
|
if (!is_array($schema)) { |
366
|
|
|
$this->Flash->error(__('Cannot create abstract objects or objects without schema')); |
367
|
|
|
|
368
|
|
|
return $this->redirect(['_name' => 'modules:list', 'object_type' => $this->objectType]); |
369
|
|
|
} |
370
|
|
|
try { |
371
|
|
|
$response = $this->apiClient->getObject($id, $this->objectType); |
372
|
|
|
$attributes = $response['data']['attributes']; |
373
|
|
|
$attributes['uname'] = ''; |
374
|
|
|
unset($attributes['relationships']); |
375
|
|
|
$attributes['title'] = $this->request->getQuery('title'); |
376
|
|
|
} catch (BEditaClientException $e) { |
377
|
|
|
$this->log($e, LogLevel::ERROR); |
378
|
|
|
$this->Flash->error($e->getMessage(), ['params' => $e]); |
379
|
|
|
|
380
|
|
|
return $this->redirect(['_name' => 'modules:view', 'object_type' => $this->objectType, 'id' => $id]); |
381
|
|
|
} |
382
|
|
|
$object = [ |
383
|
|
|
'type' => $this->objectType, |
384
|
|
|
'attributes' => $attributes, |
385
|
|
|
]; |
386
|
|
|
$this->set(compact('object', 'schema')); |
387
|
|
|
$this->set('properties', $this->Properties->viewGroups($object, $this->objectType)); |
388
|
|
|
|
389
|
|
|
return null; |
390
|
|
|
} |
391
|
|
|
|
392
|
|
|
/** |
393
|
|
|
* Delete single resource. |
394
|
|
|
* |
395
|
|
|
* @return \Cake\Http\Response|null |
396
|
|
|
*/ |
397
|
|
|
public function delete() : ?Response |
398
|
|
|
{ |
399
|
|
|
$this->request->allowMethod(['post']); |
400
|
|
|
$ids = []; |
401
|
|
|
if (!empty($this->request->getData('ids'))) { |
402
|
|
|
if (is_string($this->request->getData('ids'))) { |
403
|
|
|
$ids = explode(',', $this->request->getData('ids')); |
|
|
|
|
404
|
|
|
} |
405
|
|
|
} else { |
406
|
|
|
$ids = [$this->request->getData('id')]; |
407
|
|
|
} |
408
|
|
|
foreach ($ids as $id) { |
409
|
|
|
try { |
410
|
|
|
$this->apiClient->deleteObject($id, $this->objectType); |
411
|
|
|
} catch (BEditaClientException $e) { |
412
|
|
|
$this->log($e, LogLevel::ERROR); |
413
|
|
|
$this->Flash->error($e->getMessage(), ['params' => $e]); |
414
|
|
|
if (!empty($this->request->getData('id'))) { |
415
|
|
|
return $this->redirect(['_name' => 'modules:view', 'object_type' => $this->objectType, 'id' => $this->request->getData('id')]); |
416
|
|
|
} |
417
|
|
|
|
418
|
|
|
return $this->redirect(['_name' => 'modules:view', 'object_type' => $this->objectType]); |
419
|
|
|
} |
420
|
|
|
} |
421
|
|
|
$this->Flash->success(__('Object(s) deleted')); |
422
|
|
|
|
423
|
|
|
return $this->redirect([ |
424
|
|
|
'_name' => 'modules:list', |
425
|
|
|
'object_type' => $this->objectType, |
426
|
|
|
]); |
427
|
|
|
} |
428
|
|
|
|
429
|
|
|
/** |
430
|
|
|
* Relation data load callig api `GET /:object_type/:id/related/:relation` |
431
|
|
|
* |
432
|
|
|
* @param string|int $id the object identifier. |
433
|
|
|
* @param string $relation the relating name. |
434
|
|
|
* @return void |
435
|
|
|
*/ |
436
|
|
|
public function relatedJson($id, string $relation) : void |
437
|
|
|
{ |
438
|
|
|
$this->request->allowMethod(['get']); |
439
|
|
|
try { |
440
|
|
|
$response = $this->apiClient->getRelated($id, $this->objectType, $relation, $this->request->getQueryParams()); |
441
|
|
|
} catch (BEditaClientException $error) { |
442
|
|
|
$this->log($error, LogLevel::ERROR); |
443
|
|
|
|
444
|
|
|
$this->set(compact('error')); |
445
|
|
|
$this->set('_serialize', ['error']); |
446
|
|
|
|
447
|
|
|
return; |
448
|
|
|
} |
449
|
|
|
|
450
|
|
|
$this->getThumbsUrls($response); |
|
|
|
|
451
|
|
|
|
452
|
|
|
$this->set((array)$response); |
453
|
|
|
$this->set('_serialize', array_keys($response)); |
454
|
|
|
} |
455
|
|
|
|
456
|
|
|
/** |
457
|
|
|
* Load resources of $type callig api `GET /:type/` |
458
|
|
|
* Json response |
459
|
|
|
* |
460
|
|
|
* @param string|int $id the object identifier. |
461
|
|
|
* @param string $type the resource type name. |
462
|
|
|
* @return void |
463
|
|
|
*/ |
464
|
|
|
public function resourcesJson($id, string $type) : void |
465
|
|
|
{ |
466
|
|
|
$this->request->allowMethod(['get']); |
467
|
|
|
|
468
|
|
|
try { |
469
|
|
|
$response = $this->apiClient->get($type, $this->request->getQueryParams()); |
470
|
|
|
} catch (BEditaClientException $error) { |
471
|
|
|
$this->log($error, LogLevel::ERROR); |
472
|
|
|
|
473
|
|
|
$this->set(compact('error')); |
474
|
|
|
$this->set('_serialize', ['error']); |
475
|
|
|
|
476
|
|
|
return; |
477
|
|
|
} |
478
|
|
|
|
479
|
|
|
$this->set((array)$response); |
480
|
|
|
$this->set('_serialize', array_keys($response)); |
|
|
|
|
481
|
|
|
} |
482
|
|
|
|
483
|
|
|
/** |
484
|
|
|
* Relation data load callig api `GET /:object_type/:id/relationships/:relation` |
485
|
|
|
* Json response |
486
|
|
|
* |
487
|
|
|
* @param string|int $id the object identifier. |
488
|
|
|
* @param string $relation the relating name. |
489
|
|
|
* @return void |
490
|
|
|
*/ |
491
|
|
|
public function relationshipsJson($id, string $relation) : void |
492
|
|
|
{ |
493
|
|
|
$this->request->allowMethod(['get']); |
494
|
|
|
$path = sprintf('/%s/%s/%s', $this->objectType, $id, $relation); |
495
|
|
|
|
496
|
|
|
try { |
497
|
|
|
switch ($relation) { |
498
|
|
|
case 'children': |
499
|
|
|
$available = '/objects'; |
500
|
|
|
break; |
501
|
|
|
case 'parent': |
502
|
|
|
case 'parents': |
503
|
|
|
$available = '/folders'; |
504
|
|
|
break; |
505
|
|
|
default: |
506
|
|
|
$response = $this->apiClient->get($path, ['page_size' => 1]); // page_size 1: we need just the available |
507
|
|
|
$available = $response['links']['available']; |
508
|
|
|
} |
509
|
|
|
|
510
|
|
|
$response = $this->apiClient->get($available, $this->request->getQueryParams()); |
511
|
|
|
|
512
|
|
|
$this->getThumbsUrls($response); |
|
|
|
|
513
|
|
|
} catch (BEditaClientException $ex) { |
514
|
|
|
$this->log($ex, LogLevel::ERROR); |
515
|
|
|
|
516
|
|
|
$this->set([ |
517
|
|
|
'error' => $ex->getMessage(), |
518
|
|
|
'_serialize' => ['error'], |
519
|
|
|
]); |
520
|
|
|
|
521
|
|
|
return; |
522
|
|
|
} |
523
|
|
|
|
524
|
|
|
$this->set((array)$response); |
525
|
|
|
$this->set('_serialize', array_keys($response)); |
526
|
|
|
} |
527
|
|
|
|
528
|
|
|
/** |
529
|
|
|
* Retrieve thumbnails URL of related objects in `meta.url` if present. |
530
|
|
|
* |
531
|
|
|
* @param array $response Related objects response. |
532
|
|
|
* @return void |
533
|
|
|
*/ |
534
|
|
|
public function getThumbsUrls(array &$response) : void |
535
|
|
|
{ |
536
|
|
|
if (empty($response['data'])) { |
537
|
|
|
return; |
538
|
|
|
} |
539
|
|
|
|
540
|
|
|
// extract ids of objects |
541
|
|
|
$ids = (array)Hash::extract($response, 'data.{n}[type=/images|videos/].id'); |
542
|
|
|
if (empty($ids)) { |
543
|
|
|
return; |
544
|
|
|
} |
545
|
|
|
|
546
|
|
|
$thumbs = '/media/thumbs?ids=' . implode(',', $ids) . '&options[w]=400'; // TO-DO this hardcoded 400 should be in param/conf of some sort |
547
|
|
|
|
548
|
|
|
$thumbsResponse = $this->apiClient->get($thumbs, $this->request->getQueryParams()); |
549
|
|
|
|
550
|
|
|
$thumbsUrl = $thumbsResponse['meta']['thumbnails']; |
551
|
|
|
|
552
|
|
|
foreach ($response['data'] as &$object) { |
553
|
|
|
$thumbnail = Hash::get($object, 'attributes.provider_thumbnail'); |
554
|
|
|
if ($thumbnail) { |
555
|
|
|
$object['meta']['thumb_url'] = $thumbnail; |
556
|
|
|
continue; // if provider_thumbnail is found there's no need to extract it from thumbsResponse |
557
|
|
|
} |
558
|
|
|
|
559
|
|
|
// extract url of the matching objectid's thumb |
560
|
|
|
$thumbnail = (array)Hash::extract($thumbsUrl, sprintf('{*}[id=%s].url', $object['id'])); |
561
|
|
|
if (count($thumbnail)) { |
562
|
|
|
$object['meta']['thumb_url'] = $thumbnail[0]; |
563
|
|
|
} |
564
|
|
|
} |
565
|
|
|
} |
566
|
|
|
|
567
|
|
|
/** |
568
|
|
|
* Bulk change actions for objects |
569
|
|
|
* |
570
|
|
|
* @return \Cake\Http\Response|null |
571
|
|
|
*/ |
572
|
|
|
public function bulkActions() : ?Response |
573
|
|
|
{ |
574
|
|
|
$requestData = $this->request->getData(); |
575
|
|
|
$this->request->allowMethod(['post']); |
576
|
|
|
|
577
|
|
|
if (!empty($requestData['ids'] && is_string($requestData['ids']))) { |
578
|
|
|
$ids = $requestData['ids']; |
579
|
|
|
$errors = []; |
580
|
|
|
|
581
|
|
|
// extract valid attributes to change |
582
|
|
|
$attributes = array_filter( |
583
|
|
|
$requestData['attributes'], |
584
|
|
|
function ($value) { |
585
|
|
|
return ($value !== null && $value !== ''); |
586
|
|
|
} |
587
|
|
|
); |
588
|
|
|
|
589
|
|
|
// export selected (filter by id) |
590
|
|
|
$ids = explode(',', $ids); |
591
|
|
|
foreach ($ids as $id) { |
592
|
|
|
$data = array_merge($attributes, ['id' => $id]); |
593
|
|
|
try { |
594
|
|
|
$this->apiClient->save($this->objectType, $data); |
595
|
|
|
} catch (BEditaClientException $e) { |
596
|
|
|
$errors[] = [ |
597
|
|
|
'id' => $id, |
598
|
|
|
'message' => $e->getAttributes() |
599
|
|
|
]; |
600
|
|
|
} |
601
|
|
|
} |
602
|
|
|
|
603
|
|
|
// if errors occured on any single save show error message |
604
|
|
|
if (!empty($errors)) { |
605
|
|
|
$this->log($errors, LogLevel::ERROR); |
606
|
|
|
$this->Flash->error(__('Bulk Action failed on: '), ['params' => $errors]); |
607
|
|
|
} |
608
|
|
|
} |
609
|
|
|
|
610
|
|
|
return $this->redirect(['_name' => 'modules:list', 'object_type' => $this->objectType, '?' => $this->request->getQuery()]); |
611
|
|
|
} |
612
|
|
|
|
613
|
|
|
/** |
614
|
|
|
* get object properties and format them for index |
615
|
|
|
* |
616
|
|
|
* @param string $objectType objecte type name |
617
|
|
|
* |
618
|
|
|
* @return array $schema |
619
|
|
|
*/ |
620
|
|
|
public function getSchemaForIndex($objectType) : array |
621
|
|
|
{ |
622
|
|
|
$schema = (array)$this->Schema->getSchema($objectType); |
623
|
|
|
|
624
|
|
|
// if prop is an enum then prepend an empty string for select element |
625
|
|
|
if (!empty($schema['properties'])) { |
626
|
|
|
foreach ($schema['properties'] as &$property) { |
627
|
|
|
if (isset($property['enum'])) { |
628
|
|
|
array_unshift($property['enum'], ''); |
629
|
|
|
} |
630
|
|
|
} |
631
|
|
|
} |
632
|
|
|
|
633
|
|
|
return $schema; |
634
|
|
|
} |
635
|
|
|
} |
636
|
|
|
|
This check looks for function or method calls that always return null and whose return value is used.
The method
getObject()
can return nothing but null, so it makes no sense to use the return value.The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.