Passed
Push — master ( 36215f...294853 )
by Dante
01:52
created

ModulesController   D

Complexity

Total Complexity 59

Size/Duplication

Total Lines 654
Duplicated Lines 0 %

Importance

Changes 2
Bugs 1 Features 0
Metric Value
eloc 323
dl 0
loc 654
rs 4.08
c 2
b 1
f 0
wmc 59

20 Methods

Rating   Name   Duplication   Size   Complexity  
A getObjectType() 0 3 1
B delete() 0 27 6
A related() 0 27 3
A getSchemaForIndex() 0 14 4
A resources() 0 17 2
A relationships() 0 21 2
A setObjectType() 0 3 1
A availableRelationshipsUrl() 0 16 3
A users() 0 14 1
A beforeRender() 0 5 1
A index() 0 52 5
A get() 0 15 1
B clone() 0 32 6
A setup() 0 30 4
A view() 0 50 3
A create() 0 34 2
A uname() 0 18 3
A setupViewRelations() 0 24 1
A initialize() 0 19 2
B save() 0 67 8

How to fix   Complexity   

Complex Class

Complex classes like ModulesController often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use ModulesController, and based on these observations, apply Extract Interface, too.

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\Utility\ApiConfigTrait;
16
use App\Utility\CacheTools;
17
use App\Utility\Message;
18
use App\Utility\PermissionsTrait;
19
use BEdita\SDK\BEditaClientException;
20
use BEdita\WebTools\Utility\ApiTools;
21
use Cake\Core\Configure;
22
use Cake\Event\Event;
23
use Cake\Event\EventInterface;
24
use Cake\Http\Exception\UnauthorizedException;
25
use Cake\Http\Response;
26
use Cake\I18n\I18n;
27
use Cake\Utility\Hash;
28
use Exception;
29
use Psr\Log\LogLevel;
30
31
/**
32
 * Modules controller: list, add, edit, remove objects
33
 *
34
 * @property \App\Controller\Component\CategoriesComponent $Categories
35
 * @property \App\Controller\Component\ChildrenComponent $Children
36
 * @property \App\Controller\Component\HistoryComponent $History
37
 * @property \App\Controller\Component\ObjectsEditorsComponent $ObjectsEditors
38
 * @property \App\Controller\Component\ParentsComponent $Parents
39
 * @property \App\Controller\Component\ProjectConfigurationComponent $ProjectConfiguration
40
 * @property \App\Controller\Component\PropertiesComponent $Properties
41
 * @property \App\Controller\Component\QueryComponent $Query
42
 * @property \App\Controller\Component\ThumbsComponent $Thumbs
43
 * @property \BEdita\WebTools\Controller\Component\ApiFormatterComponent $ApiFormatter
44
 */
45
class ModulesController extends AppController
46
{
47
    use ApiConfigTrait;
48
    use PermissionsTrait;
49
50
    /**
51
     * Object type currently used
52
     *
53
     * @var string
54
     */
55
    protected $objectType = null;
56
57
    /**
58
     * @inheritDoc
59
     */
60
    public function initialize(): void
61
    {
62
        parent::initialize();
63
64
        $this->loadComponent('Children');
65
        $this->loadComponent('History');
66
        $this->loadComponent('ObjectsEditors');
67
        $this->loadComponent('Parents');
68
        $this->loadComponent('Properties');
69
        $this->loadComponent('ProjectConfiguration');
70
        $this->loadComponent('Query');
71
        $this->loadComponent('Thumbs', Configure::read('Thumbs', []));
72
        $this->loadComponent('BEdita/WebTools.ApiFormatter');
73
        if ($this->getRequest()->getParam('object_type')) {
74
            $this->objectType = $this->getRequest()->getParam('object_type');
75
            $this->Modules->setConfig('currentModuleName', $this->objectType);
76
            $this->Schema->setConfig('type', $this->objectType);
77
        }
78
        $this->Security->setConfig('unlockedActions', ['save', 'setup']);
79
    }
80
81
    /**
82
     * {@inheritDoc}
83
     *
84
     * @codeCoverageIgnore
85
     */
86
    public function beforeRender(EventInterface $event): ?Response
87
    {
88
        $this->set('objectType', $this->objectType);
89
90
        return parent::beforeRender($event);
91
    }
92
93
    /**
94
     * Display resources list.
95
     *
96
     * @return \Cake\Http\Response|null
97
     */
98
    public function index(): ?Response
99
    {
100
        $this->getRequest()->allowMethod(['get']);
101
102
        // handle filter and query parameters using session
103
        $result = $this->applySessionFilter();
104
        if ($result != null) {
105
            return $result;
106
        }
107
108
        try {
109
            $params = $this->Query->index();
110
            $response = $this->apiClient->getObjects($this->objectType, $params);
111
            if (empty($params['q']) && empty($params['filter'])) {
112
                CacheTools::setModuleCount((array)$response, $this->Modules->getConfig('currentModuleName'));
113
            }
114
        } catch (BEditaClientException $e) {
115
            $this->log($e->getMessage(), LogLevel::ERROR);
116
            $this->Flash->error($e->getMessage(), ['params' => $e]);
117
            // remove session filter to avoid error repetition
118
            $session = $this->getRequest()->getSession();
119
            $session->delete(sprintf('%s.filter', $this->Modules->getConfig('currentModuleName')));
120
121
            return $this->redirect(['_name' => 'dashboard']);
122
        }
123
124
        $this->ProjectConfiguration->read();
125
126
        $response = $this->ApiFormatter->embedIncluded((array)$response);
127
        $objects = (array)Hash::get($response, 'data');
128
        $this->set('objects', $objects);
129
        $this->set('meta', (array)Hash::get($response, 'meta'));
130
        $this->set('links', (array)Hash::get($response, 'links'));
131
        $this->set('types', ['right' => $this->Schema->descendants($this->objectType)]);
132
133
        $this->set('properties', $this->Properties->indexList($this->objectType));
134
135
        // base/custom filters for filter view
136
        $this->set('filter', $this->Properties->filterList($this->objectType));
137
138
        // base/custom bulk actions for index view
139
        $this->set('bulkActions', $this->Properties->bulkList($this->objectType));
140
141
        // objectTypes schema
142
        $this->set('schema', $this->getSchemaForIndex($this->objectType));
143
        // custom properties
144
        $this->set('customProps', $this->Schema->customProps($this->objectType));
145
146
        // set prevNext for views navigations
147
        $this->setObjectNav($objects);
148
149
        return null;
150
    }
151
152
    /**
153
     * View single resource.
154
     *
155
     * @param string|int $id Resource ID.
156
     * @return \Cake\Http\Response|null
157
     */
158
    public function view($id): ?Response
159
    {
160
        $this->getRequest()->allowMethod(['get']);
161
162
        try {
163
            $query = ['count' => 'all'];
164
            $response = $this->apiClient->getObject($id, $this->objectType, $query);
165
        } catch (BEditaClientException $e) {
166
            // Error! Back to index.
167
            $this->log($e->getMessage(), LogLevel::ERROR);
168
            $this->Flash->error(__('Error retrieving the requested content'), ['params' => $e]);
169
170
            return $this->redirect(['_name' => 'modules:list', 'object_type' => $this->objectType]);
171
        }
172
        $this->ProjectConfiguration->read();
173
174
        $revision = Hash::get($response, 'meta.schema.' . $this->objectType . '.revision', null);
175
        $schema = $this->Schema->getSchema($this->objectType, $revision);
176
177
        $object = $response['data'];
178
179
        // setup `currentAttributes` and recover failure data from session.
180
        $this->Modules->setupAttributes($object);
181
182
        $included = !empty($response['included']) ? $response['included'] : [];
183
        $typeIncluded = Hash::combine($included, '{n}.id', '{n}', '{n}.type');
184
        $streams = Hash::get($typeIncluded, 'streams');
185
        $this->History->load($id, $object);
186
        $this->set(compact('object', 'included', 'schema', 'streams'));
187
        $this->set('properties', $this->Properties->viewGroups($object, $this->objectType));
188
        $this->set('foldersSchema', $this->Schema->getSchema('folders'));
189
190
        $computedRelations = array_reduce(
191
            array_keys($object['relationships']),
192
            function ($acc, $relName) use ($schema) {
193
                $acc[$relName] = (array)Hash::get($schema, sprintf('relations.%s', $relName), []);
194
195
                return $acc;
196
            },
197
            []
198
        );
199
        $this->setupViewRelations($computedRelations);
200
201
        // set objectNav
202
        $objectNav = $this->getObjectNav((string)$id);
203
        $this->set('objectNav', $objectNav);
204
205
        $this->ObjectsEditors->update((string)$id);
206
207
        return null;
208
    }
209
210
    /**
211
     * View single resource by id, doing a proper redirect (302) to resource module view by type.
212
     * If no resource found by ID, redirect to referer.
213
     *
214
     * @param string|int $id Resource ID.
215
     * @return \Cake\Http\Response|null
216
     */
217
    public function uname($id): ?Response
218
    {
219
        try {
220
            $response = $this->apiClient->get(sprintf('/objects/%s', $id));
221
        } catch (BEditaClientException $e) {
222
            $msg = $e->getMessage();
223
            $msgNotFound = sprintf(__('Resource "%s" not found', true), $id);
224
            $msgNotAvailable = sprintf(__('Resource "%s" not available. Error: %s', true), $id, $msg);
225
            $error = $e->getCode() === 404 ? $msgNotFound : $msgNotAvailable;
226
            $this->Flash->error($error);
227
228
            return $this->redirect($this->referer());
229
        }
230
        $_name = 'modules:view';
231
        $object_type = $response['data']['type'];
232
        $id = $response['data']['id'];
233
234
        return $this->redirect(compact('_name', 'object_type', 'id'));
235
    }
236
237
    /**
238
     * Display new resource form.
239
     *
240
     * @return \Cake\Http\Response|null
241
     */
242
    public function create(): ?Response
243
    {
244
        $this->viewBuilder()->setTemplate('view');
245
246
        // Create stub object with empty `attributes`.
247
        $schema = $this->Schema->getSchema();
248
        if (!is_array($schema)) {
249
            $this->Flash->error(__('Cannot create abstract objects or objects without schema'));
250
251
            return $this->redirect(['_name' => 'modules:list', 'object_type' => $this->objectType]);
252
        }
253
        $attributes = array_fill_keys(
254
            array_keys(
255
                array_filter(
256
                    $schema['properties'],
257
                    function ($schema) {
258
                        return empty($schema['readOnly']);
259
                    }
260
                )
261
            ),
262
            null
263
        );
264
        $object = [
265
            'type' => $this->objectType,
266
            'attributes' => $attributes,
267
        ];
268
269
        $this->set(compact('object', 'schema'));
270
        $this->set('properties', $this->Properties->viewGroups($object, $this->objectType));
271
        $this->ProjectConfiguration->read();
272
273
        $this->setupViewRelations((array)Hash::get($schema, 'relations'));
274
275
        return null;
276
    }
277
278
    /**
279
     * Create new object from ajax request.
280
     *
281
     * @return void
282
     */
283
    public function save(): void
284
    {
285
        $this->viewBuilder()->setClassName('Json'); // force json response
286
        $this->getRequest()->allowMethod(['post']);
287
        $requestData = $this->prepareRequest($this->objectType);
288
        unset($requestData['_csrfToken']);
289
        // extract related objects data
290
        $relatedData = (array)Hash::get($requestData, '_api');
291
        unset($requestData['_api']);
292
293
        try {
294
            $uname = Hash::get($requestData, 'uname');
295
            if (!empty($uname) && is_numeric($uname)) {
296
                $this->set(['error' => __('Invalid numeric uname. Change it to a valid string')]);
297
                $this->setSerialize(['error']);
298
299
                return;
300
            }
301
            $id = Hash::get($requestData, 'id');
302
            // skip save if no data changed
303
            if (empty($relatedData) && count($requestData) === 1 && !empty($id)) {
304
                $response = $this->apiClient->getObject($id, $this->objectType, ['count' => 'all']);
305
                $this->Thumbs->urls($response);
306
                $this->set((array)$response);
307
                $this->setSerialize(array_keys($response));
308
309
                return;
310
            }
311
312
            // upload file (if available)
313
            $this->Modules->upload($requestData);
314
315
            // save data
316
            $lang = I18n::getLocale();
317
            $headers = ['Accept-Language' => $lang];
318
            $response = $this->apiClient->save($this->objectType, $requestData, $headers);
319
            $this->savePermissions(
320
                (array)$response,
321
                (array)$this->Schema->getSchema($this->objectType),
322
                (array)Hash::get($requestData, 'permissions')
323
            );
324
            $id = (string)Hash::get($response, 'data.id');
325
            $this->Modules->saveRelated($id, $this->objectType, $relatedData);
326
            $options = [
327
                'id' => Hash::get($response, 'data.id'),
328
                'type' => $this->objectType,
329
                'data' => $requestData,
330
            ];
331
            $event = new Event('Controller.afterSave', $this, $options);
332
            $this->getEventManager()->dispatch($event);
333
        } catch (BEditaClientException $error) {
334
            $message = new Message($error);
335
            $this->log($message->get(), LogLevel::ERROR);
336
            $this->Flash->error($message->get(), ['params' => $error]);
337
            $this->set(['error' => $message->get()]);
338
            $this->setSerialize(['error']);
339
340
            return;
341
        }
342
        if ($response['data']) {
343
            $response['data'] = [ $response['data'] ];
344
        }
345
346
        $this->Thumbs->urls($response);
347
348
        $this->set((array)$response);
349
        $this->setSerialize(array_keys($response));
350
    }
351
352
    /**
353
     * Clone single object.
354
     *
355
     * @param string|int $id Object ID.
356
     * @return \Cake\Http\Response|null
357
     */
358
    public function clone($id): ?Response
359
    {
360
        $this->viewBuilder()->setTemplate('view');
361
        $schema = $this->Schema->getSchema();
362
        if (!is_array($schema)) {
363
            $this->Flash->error(__('Cannot create abstract objects or objects without schema'));
364
365
            return $this->redirect(['_name' => 'modules:list', 'object_type' => $this->objectType]);
366
        }
367
        try {
368
            $modified = [
369
                'title' => $this->getRequest()->getQuery('title'),
370
                'status' => 'draft',
371
            ];
372
            $reset = (array)Configure::read(sprintf('Clone.%s.reset', $this->objectType));
373
            foreach ($reset as $field) {
374
                $modified[$field] = null;
375
            }
376
            $included = [];
377
            foreach (['relationships', 'translations'] as $attribute) {
378
                if ($this->getRequest()->getQuery($attribute) === 'true') {
379
                    $included[] = $attribute;
380
                }
381
            }
382
            $clone = $this->apiClient->clone($this->objectType, $id, $modified, $included);
383
            $id = (string)Hash::get($clone, 'data.id');
384
        } catch (BEditaClientException $e) {
385
            $this->log($e->getMessage(), LogLevel::ERROR);
386
            $this->Flash->error($e->getMessage(), ['params' => $e]);
387
        }
388
389
        return $this->redirect(['_name' => 'modules:view', 'object_type' => $this->objectType, 'id' => $id]);
390
    }
391
392
    /**
393
     * Delete single resource.
394
     *
395
     * @return \Cake\Http\Response|null
396
     */
397
    public function delete(): ?Response
398
    {
399
        $this->getRequest()->allowMethod(['post']);
400
        $id = $this->getRequest()->getData('id');
401
        $ids = $this->getRequest()->getData('ids');
402
        $ids = is_string($ids) ? explode(',', $ids) : $ids;
403
        $ids = empty($ids) ? [$id] : $ids;
404
        try {
405
            $this->apiClient->deleteObjects($ids, $this->objectType);
406
            $eventManager = $this->getEventManager();
407
            foreach ($ids as $id) {
408
                $event = new Event('Controller.afterDelete', $this, ['id' => $id, 'type' => $this->objectType]);
409
                $eventManager->dispatch($event);
410
            }
411
        } catch (BEditaClientException $e) {
412
            $this->log($e->getMessage(), LogLevel::ERROR);
413
            $this->Flash->error($e->getMessage(), ['params' => $e]);
414
            $id = $this->getRequest()->getData('id');
415
            $options = empty($id) ? $this->referer() : ['_name' => 'modules:view', 'object_type' => $this->objectType, 'id' => $id];
416
417
            return $this->redirect($options);
418
        }
419
        $this->Flash->success(__('Object(s) deleted'));
420
421
        return $this->redirect([
422
            '_name' => 'modules:list',
423
            'object_type' => $this->objectType,
424
        ]);
425
    }
426
427
    /**
428
     * Relation data load via API => `GET /:object_type/:id/related/:relation`
429
     *
430
     * @param string|int $id The object ID.
431
     * @param string $relation The relation name.
432
     * @return void
433
     */
434
    public function related($id, string $relation): void
435
    {
436
        if ($id === 'new') {
437
            $this->set('data', []);
438
            $this->setSerialize(['data']);
439
440
            return;
441
        }
442
443
        $this->getRequest()->allowMethod(['get']);
444
        $query = $this->Query->prepare($this->getRequest()->getQueryParams());
445
        try {
446
            $response = $this->apiClient->getRelated($id, $this->objectType, $relation, $query);
447
            $response = $this->ApiFormatter->embedIncluded((array)$response);
448
        } catch (BEditaClientException $error) {
449
            $this->log($error->getMessage(), LogLevel::ERROR);
450
451
            $this->set(compact('error'));
452
            $this->setSerialize(['error']);
453
454
            return;
455
        }
456
457
        $this->Thumbs->urls($response);
458
459
        $this->set((array)$response);
460
        $this->setSerialize(array_keys($response));
461
    }
462
463
    /**
464
     * Load resources of $type callig api `GET /:type/`
465
     * Json response
466
     *
467
     * @param string|int $id the object identifier.
468
     * @param string $type the resource type name.
469
     * @return void
470
     */
471
    public function resources($id, string $type): void
472
    {
473
        $this->getRequest()->allowMethod(['get']);
474
        $query = $this->Query->prepare($this->getRequest()->getQueryParams());
475
        try {
476
            $response = $this->apiClient->get($type, $query);
477
        } catch (BEditaClientException $error) {
478
            $this->log($error, LogLevel::ERROR);
479
480
            $this->set(compact('error'));
481
            $this->setSerialize(['error']);
482
483
            return;
484
        }
485
486
        $this->set((array)$response);
487
        $this->setSerialize(array_keys($response));
488
    }
489
490
    /**
491
     * Relation data load calling api `GET /:object_type/:id/relationships/:relation`
492
     * Json response
493
     *
494
     * @param string|int $id The object ID.
495
     * @param string $relation The relation name.
496
     * @return void
497
     */
498
    public function relationships($id, string $relation): void
499
    {
500
        $this->getRequest()->allowMethod(['get']);
501
        $available = $this->availableRelationshipsUrl($relation);
502
503
        try {
504
            $query = $this->Query->prepare($this->getRequest()->getQueryParams());
505
            $response = $this->apiClient->get($available, $query);
506
507
            $this->Thumbs->urls($response);
508
        } catch (BEditaClientException $ex) {
509
            $this->log($ex->getMessage(), LogLevel::ERROR);
510
511
            $this->set('error', $ex->getMessage());
512
            $this->setSerialize(['error']);
513
514
            return;
515
        }
516
517
        $this->set((array)$response);
518
        $this->setSerialize(array_keys($response));
519
    }
520
521
    /**
522
     * Retrieve URL to get objects available for a relation
523
     *
524
     * @param string $relation The relation name.
525
     * @return string
526
     */
527
    protected function availableRelationshipsUrl(string $relation): string
528
    {
529
        $defaults = [
530
            'children' => '/objects',
531
            'parent' => '/folders',
532
            'parents' => '/folders',
533
        ];
534
        $defaultUrl = (string)Hash::get($defaults, $relation);
535
        if (!empty($defaultUrl)) {
536
            return $defaultUrl;
537
        }
538
539
        $relationsSchema = $this->Schema->getRelationsSchema();
540
        $types = $this->Modules->relatedTypes($relationsSchema, $relation);
541
542
        return count($types) === 1 ? sprintf('/%s', $types[0]) : '/objects?filter[type][]=' . implode('&filter[type][]=', $types);
543
    }
544
545
    /**
546
     * get object properties and format them for index
547
     *
548
     * @param string $objectType objecte type name
549
     * @return array $schema
550
     */
551
    public function getSchemaForIndex($objectType): array
552
    {
553
        $schema = (array)$this->Schema->getSchema($objectType);
554
555
        // if prop is an enum then prepend an empty string for select element
556
        if (!empty($schema['properties'])) {
557
            foreach ($schema['properties'] as &$property) {
558
                if (isset($property['enum'])) {
559
                    array_unshift($property['enum'], '');
560
                }
561
            }
562
        }
563
564
        return $schema;
565
    }
566
567
    /**
568
     * Get objectType
569
     *
570
     * @return string|null
571
     */
572
    public function getObjectType(): ?string
573
    {
574
        return $this->objectType;
575
    }
576
577
    /**
578
     * Set objectType
579
     *
580
     * @param string|null $objectType The object type
581
     * @return void
582
     */
583
    public function setObjectType(?string $objectType): void
584
    {
585
        $this->objectType = $objectType;
586
    }
587
588
    /**
589
     * Set schemasByType and filtersByType, considering relations and schemas.
590
     *
591
     * @param array $relations The relations
592
     * @return void
593
     */
594
    private function setupViewRelations(array $relations): void
595
    {
596
        // setup relations schema
597
        $relationsSchema = $this->Schema->getRelationsSchema();
598
        $this->set('relationsSchema', $relationsSchema);
599
600
        // setup relations metadata
601
        $this->Modules->setupRelationsMeta(
602
            $relationsSchema,
603
            $relations,
604
            $this->Properties->relationsList($this->objectType),
605
            $this->Properties->hiddenRelationsList($this->objectType),
606
            $this->Properties->readonlyRelationsList($this->objectType)
607
        );
608
609
        // set right types, considering the object type relations
610
        $rel = (array)$this->viewBuilder()->getVar('relationsSchema');
611
        $rightTypes = \App\Utility\Schema::rightTypes($rel);
612
        $this->set('rightTypes', $rightTypes);
613
614
        // set schemas for relations right types
615
        $schemasByType = $this->Schema->getSchemasByType($rightTypes);
616
        $this->set('schemasByType', $schemasByType);
617
        $this->set('filtersByType', $this->Properties->filtersByType($rightTypes));
618
    }
619
620
    /**
621
     * Get list of users / no email, no relationships, no links, no schema, no included.
622
     *
623
     * @return void
624
     */
625
    public function users(): void
626
    {
627
        $this->viewBuilder()->setClassName('Json');
628
        $this->getRequest()->allowMethod('get');
629
        $query = array_merge(
630
            $this->getRequest()->getQueryParams(),
631
            ['fields' => 'id,title,username,name,surname']
632
        );
633
        $response = (array)$this->apiClient->get('users', $query);
634
        $response = ApiTools::cleanResponse($response);
635
        $data = (array)Hash::get($response, 'data');
636
        $meta = (array)Hash::get($response, 'meta');
637
        $this->set(compact('data', 'meta'));
638
        $this->setSerialize(['data', 'meta']);
639
    }
640
641
    /**
642
     * Get single resource, minimal data / no relationships, no links, no schema, no included.
643
     *
644
     * @param string $id The object ID
645
     * @return void
646
     */
647
    public function get(string $id): void
648
    {
649
        $this->viewBuilder()->setClassName('Json');
650
        $this->getRequest()->allowMethod('get');
651
        $response = (array)$this->apiClient->getObject($id, 'objects');
652
        $query = array_merge(
653
            $this->getRequest()->getQueryParams(),
654
            ['fields' => 'id,title,description,uname,status,media_url']
655
        );
656
        $response = (array)$this->apiClient->getObject($id, $response['data']['type'], $query);
657
        $response = ApiTools::cleanResponse($response);
658
        $data = (array)Hash::get($response, 'data');
659
        $meta = (array)Hash::get($response, 'meta');
660
        $this->set(compact('data', 'meta'));
661
        $this->setSerialize(['data', 'meta']);
662
    }
663
664
    /**
665
     * Setup module.
666
     *
667
     * @return \Cake\Http\Response|null
668
     */
669
    public function setup(): ?Response
670
    {
671
        /** @var \Authentication\Identity|null $user */
672
        $user = $this->Authentication->getIdentity();
673
        $roles = (array)$user->get('roles');
674
        if (!in_array('admin', $roles)) {
675
            throw new UnauthorizedException(__('You are not authorized to access here'));
676
        }
677
        $this->getRequest()->allowMethod(['get', 'post']);
678
        if ($this->getRequest()->is('post')) {
679
            try {
680
                $requestData = $this->getRequest()->getData();
681
                $configurationKey = $requestData['configurationKey'] ?? null;
682
                unset($requestData['configurationKey']);
683
                $propertyName = explode('.', $configurationKey)[0];
684
                $subkey = explode('.', $configurationKey)[1];
685
                $propertyValue = (array)Configure::read($propertyName);
686
                $propertyValue = (array)Hash::insert($propertyValue, $subkey, $requestData);
687
                $this->saveApiConfig($propertyName, $propertyValue);
688
                $response = 'Configuration saved';
689
                $this->set('response', $response);
690
                $this->setSerialize(['response']);
691
            } catch (Exception $e) {
692
                $error = $e->getMessage();
693
                $this->set('error', $error);
694
                $this->setSerialize(['error']);
695
            }
696
        }
697
698
        return null;
699
    }
700
}
701