Passed
Pull Request — master (#800)
by Stefano
03:23
created

ModelBaseController::create()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 26
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 15
c 0
b 0
f 0
dl 0
loc 26
rs 9.7666
cc 1
nc 1
nop 0
1
<?php
2
/**
3
 * BEdita, API-first content management framework
4
 * Copyright 2022 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\Model;
14
15
use App\Controller\AppController;
16
use BEdita\SDK\BEditaClientException;
17
use Cake\Event\EventInterface;
18
use Cake\Http\Exception\UnauthorizedException;
19
use Cake\Http\Response;
20
use Cake\Utility\Hash;
21
22
/**
23
 * Model base controller class
24
 *
25
 * @property \App\Controller\Component\PropertiesComponent $Properties
26
 */
27
abstract class ModelBaseController extends AppController
28
{
29
    /**
30
     * Resource type in use (object_types, properties, property_types)
31
     *
32
     * @var string
33
     */
34
    protected $resourceType = null;
35
36
    /**
37
     * Single resource view existence flag.
38
     *
39
     * @var bool
40
     */
41
    protected $singleView = true;
42
43
    /**
44
     * @inheritDoc
45
     */
46
    public function initialize(): void
47
    {
48
        parent::initialize();
49
50
        $this->loadComponent('Properties');
51
52
        $this->Schema->setConfig([
53
            'type' => $this->resourceType,
54
            'internalSchema' => true,
55
        ]);
56
    }
57
58
    /**
59
     * {@inheritDoc}
60
     *
61
     * Restrict `model` module access to `admin` for now
62
     *
63
     * @param \Cake\Event\EventInterface $event An Event instance
64
     * @return \Cake\Http\Response|null
65
     */
66
    public function beforeFilter(EventInterface $event): ?Response
67
    {
68
        $res = parent::beforeFilter($event);
69
        if ($res !== null) {
70
            return $res;
71
        }
72
73
        /** @var \Authentication\Identity|null $user */
74
        $user = $this->Authentication->getIdentity();
75
        if (empty($user->get('roles')) || !in_array('admin', $user->get('roles'))) {
76
            throw new UnauthorizedException(__('Module access not authorized'));
77
        }
78
79
        return null;
80
    }
81
82
    /**
83
     * Display resources list.
84
     *
85
     * @return \Cake\Http\Response|null
86
     */
87
    public function index(): ?Response
88
    {
89
        $this->getRequest()->allowMethod(['get']);
90
        $query = $this->getRequest()->getQueryParams() + ['page_size' => 500];
91
92
        try {
93
            $response = $this->apiClient->get(
94
                sprintf('/model/%s', $this->resourceType),
95
                $query
96
            );
97
        } catch (BEditaClientException $e) {
98
            $this->log($e->getMessage(), 'error');
99
            $this->Flash->error($e->getMessage(), ['params' => $e]);
100
101
            return $this->redirect(['_name' => 'dashboard']);
102
        }
103
104
        $this->set('resources', (array)$response['data']);
105
        $this->set('meta', (array)$response['meta']);
106
        $this->set('links', (array)$response['links']);
107
        $this->set('schema', $this->Schema->getSchema());
108
        $this->set('properties', $this->Properties->indexList($this->resourceType));
109
        $this->set('filter', $this->Properties->filterList($this->resourceType));
110
111
        return null;
112
    }
113
114
    /**
115
     * View single resource.
116
     *
117
     * @param string|int $id Resource ID.
118
     * @return \Cake\Http\Response|null
119
     */
120
    public function view($id): ?Response
121
    {
122
        try {
123
            $response = $this->apiClient->get(sprintf('/model/%s/%s', $this->resourceType, $id));
124
        } catch (BEditaClientException $e) {
125
            $this->log($e->getMessage(), 'error');
126
            $this->Flash->error($e->getMessage(), ['params' => $e]);
127
128
            return $this->redirect(['_name' => 'model:list:' . $this->resourceType]);
129
        }
130
131
        $resource = (array)$response['data'];
132
        $this->set(compact('resource'));
133
        $this->set('schema', $this->Schema->getSchema());
134
        $this->set('properties', $this->Properties->viewGroups($resource, $this->resourceType));
135
136
        return null;
137
    }
138
139
    /**
140
     * Display new resource form.
141
     *
142
     * @return \Cake\Http\Response|null
143
     */
144
    public function create(): ?Response
145
    {
146
        $this->viewBuilder()->setTemplate('view');
147
148
        // Create stub resource with empty `attributes`.
149
        $schema = $this->Schema->getSchema();
150
        $attributes = array_fill_keys(
151
            array_keys(
152
                array_filter(
153
                    $schema['properties'],
154
                    function ($schema) {
155
                        return empty($schema['readOnly']);
156
                    }
157
                )
158
            ),
159
            ''
160
        );
161
        $resource = [
162
            'type' => $this->resourceType,
163
            'attributes' => $attributes,
164
        ];
165
166
        $this->set(compact('resource', 'schema'));
167
        $this->set('properties', $this->Properties->viewGroups($resource, $this->resourceType));
168
169
        return null;
170
    }
171
172
    /**
173
     * Save resource.
174
     *
175
     * @return \Cake\Http\Response|null
176
     */
177
    public function save(): ?Response
178
    {
179
        $data = $this->prepareRequest($this->resourceType);
180
        unset($data['_csrfToken']);
181
        $id = Hash::get($data, 'id');
182
        unset($data['id']);
183
        $body = [
184
            'data' => [
185
                'type' => $this->resourceType,
186
                'attributes' => $data,
187
            ],
188
        ];
189
        $endpoint = sprintf('/model/%s', $this->resourceType);
190
191
        try {
192
            if (empty($id)) {
193
                $response = $this->apiClient->post($endpoint, json_encode($body));
194
                $id = Hash::get($response, 'data.id');
195
            } else {
196
                $body['data']['id'] = $id;
197
                $this->apiClient->patch(sprintf('%s/%s', $endpoint, $id), json_encode($body));
198
            }
199
        } catch (BEditaClientException $e) {
200
            $this->log($e->getMessage(), 'error');
201
            $this->Flash->error($e->getMessage(), ['params' => $e]);
202
        }
203
204
        if (!$this->singleView || empty($id)) {
205
            return $this->redirect(['_name' => 'model:list:' . $this->resourceType]);
206
        }
207
208
        return $this->redirect(
209
            [
210
                '_name' => 'model:view:' . $this->resourceType,
211
                'id' => $id,
212
            ]
213
        );
214
    }
215
216
    /**
217
     * Remove single resource.
218
     *
219
     * @param string $id Resource ID.
220
     * @return \Cake\Http\Response|null
221
     */
222
    public function remove(string $id): ?Response
223
    {
224
        try {
225
            $this->apiClient->delete(sprintf('/model/%s/%s', $this->resourceType, $id));
226
        } catch (BEditaClientException $e) {
227
            $this->log($e->getMessage(), 'error');
228
            $this->Flash->error($e->getMessage(), ['params' => $e]);
229
        }
230
231
        return $this->redirect(['_name' => 'model:list:' . $this->resourceType]);
232
    }
233
234
    /**
235
     * @inheritDoc
236
     */
237
    public function beforeRender(EventInterface $event): ?Response
238
    {
239
        $this->set('resourceType', $this->resourceType);
240
        $this->set('moduleLink', ['_name' => 'model:list:' . $this->resourceType]);
241
242
        return parent::beforeRender($event);
243
    }
244
}
245