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

ModelBaseController::viewQuery()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

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