Passed
Pull Request — master (#815)
by Stefano
02:40
created

ObjectTypesController::updateSchema()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 15
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 1 Features 0
Metric Value
eloc 9
c 1
b 1
f 0
dl 0
loc 15
rs 9.9666
cc 2
nc 2
nop 2
1
<?php
2
/**
3
 * BEdita, API-first content management framework
4
 * Copyright 2019 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 BEdita\SDK\BEditaClientException;
16
use Cake\Core\Configure;
17
use Cake\Http\Response;
18
use Cake\Utility\Hash;
19
use Psr\Log\LogLevel;
20
21
/**
22
 * Object Types Model Controller: list, add, edit, remove object types
23
 *
24
 * @property \App\Controller\Component\PropertiesComponent $Properties
25
 * @property \App\Controller\Component\SchemaComponent $Schema
26
 */
27
class ObjectTypesController extends ModelBaseController
28
{
29
    /**
30
     * Core tables list.
31
     *
32
     * @var array
33
     */
34
    public const TABLES = [
35
        'BEdita/Core.Folders',
36
        'BEdita/Core.Links',
37
        'BEdita/Core.Locations',
38
        'BEdita/Core.Media',
39
        'BEdita/Core.Objects',
40
        'BEdita/Core.Profiles',
41
        'BEdita/Core.Publications',
42
        'BEdita/Core.Users',
43
    ];
44
    /**
45
     * Resource type currently used
46
     *
47
     * @var string
48
     */
49
    protected $resourceType = 'object_types';
50
51
    /**
52
     * @inheritDoc
53
     */
54
    public function view($id): ?Response
55
    {
56
        parent::view($id);
57
58
        // retrieve additional data
59
        $resource = (array)$this->viewBuilder()->getVar('resource');
60
        $name = Hash::get($resource, 'attributes.name', 'undefined');
61
        $filter = ['object_type' => $name];
62
        try {
63
            $response = $this->apiClient->get(
64
                '/model/properties',
65
                compact('filter') + ['page_size' => 100]
66
            );
67
        } catch (BEditaClientException $e) {
68
            $this->log($e->getMessage(), LogLevel::ERROR);
69
            $this->Flash->error($e->getMessage(), ['params' => $e]);
70
71
            return $this->redirect(['_name' => 'model:list:' . $this->resourceType]);
72
        }
73
74
        $objectTypeProperties = $this->prepareProperties((array)$response['data'], $name);
75
        $this->set(compact('objectTypeProperties'));
76
        $schema = $this->Schema->getSchema();
77
        $this->set('schema', $this->updateSchema($schema, $resource));
78
        $this->set('properties', $this->Properties->viewGroups($resource, $this->resourceType));
79
80
        return null;
81
    }
82
83
    /**
84
     * Update schema using resource.
85
     * If core type, skip.
86
     * Otherwise, set table and parent_name.
87
     *
88
     * @param array $schema The schema
89
     * @param array $resource The resource
90
     * @return array
91
     */
92
    protected function updateSchema(array $schema, array $resource): array
93
    {
94
        if ((bool)Hash::get($resource, 'meta.core_type')) {
95
            return $schema;
96
        }
97
        $schema['properties']['table'] = [
98
            'type' => 'string',
99
            'enum' => $this->tables($resource),
100
        ];
101
        $schema['properties']['parent_name'] = [
102
            'type' => 'string',
103
            'enum' => array_merge([''], $this->Schema->abstractTypes()),
104
        ];
105
106
        return $schema;
107
    }
108
109
    /**
110
     * Get available tables list
111
     *
112
     * @return array
113
     */
114
    protected function tables(array $resource): array
115
    {
116
        $tables = array_unique(
117
            array_merge(
118
                self::TABLES,
119
                (array)Configure::read('Model.objectTypesTables')
120
            )
121
        );
122
        $tables = array_unique(
123
            array_merge(
124
                $tables,
125
                (array)Hash::get($resource, 'attributes.table')
126
            )
127
        );
128
        sort($tables);
129
130
        return $tables;
131
    }
132
133
    /**
134
     * Separate properties between `inherited`, `core`  and `custom`
135
     *
136
     * @param array $data Property array
137
     * @param string $name Object type name
138
     * @return array
139
     */
140
    protected function prepareProperties(array $data, string $name): array
141
    {
142
        $inherited = $core = $custom = [];
143
        foreach ($data as $prop) {
144
            if (!is_numeric($prop['id'])) {
145
                $type = $prop['attributes']['object_type_name'];
146
                if ($type == $name) {
147
                    $core[] = $prop;
148
                } else {
149
                    $inherited[] = $prop;
150
                }
151
            } else {
152
                $custom[] = $prop;
153
            }
154
        }
155
156
        return compact('inherited', 'core', 'custom');
157
    }
158
159
    /**
160
     * Save object type.
161
     *
162
     * @return \Cake\Http\Response|null
163
     */
164
    public function save(): ?Response
165
    {
166
        $this->addCustomProperty();
167
        $this->request = $this->request->withoutData('prop_name')
168
            ->withoutData('prop_type');
169
170
        return parent::save();
171
    }
172
173
    /**
174
     * Add custom property
175
     *
176
     * @return void
177
     */
178
    protected function addCustomProperty(): void
179
    {
180
        $name = $this->request->getData('prop_name');
181
        $type = $this->request->getData('prop_type');
182
        if (empty($name) || empty($type)) {
183
            return;
184
        }
185
186
        $data = [
187
            'type' => 'properties',
188
            'attributes' => compact('name') + [
189
                'property_type_name' => $type,
190
                'object_type_name' => $this->request->getData('name'),
191
            ],
192
        ];
193
        $this->apiClient->post('/model/properties', json_encode(compact('data')));
194
    }
195
}
196