Passed
Pull Request — master (#965)
by Stefano
01:13
created

ObjectTypesController::addCustomProperties()   A

Complexity

Conditions 4
Paths 3

Size

Total Lines 19
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
eloc 13
nc 3
nop 0
dl 0
loc 19
rs 9.8333
c 0
b 0
f 0
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 create(): ?Response
55
    {
56
        parent::create();
57
        $this->set('propertyTypesOptions', $this->Properties->typesOptions());
58
59
        return null;
60
    }
61
62
    /**
63
     * @inheritDoc
64
     */
65
    public function view($id): ?Response
66
    {
67
        parent::view($id);
68
69
        // retrieve additional data
70
        $resource = (array)$this->viewBuilder()->getVar('resource');
71
        $name = Hash::get($resource, 'attributes.name', 'undefined');
72
        $filter = ['object_type' => $name];
73
        try {
74
            $response = $this->apiClient->get(
75
                '/model/properties',
76
                compact('filter') + ['page_size' => 100]
77
            );
78
        } catch (BEditaClientException $e) {
79
            $this->log($e->getMessage(), LogLevel::ERROR);
80
            $this->Flash->error($e->getMessage(), ['params' => $e]);
81
82
            return $this->redirect(['_name' => 'model:list:' . $this->resourceType]);
83
        }
84
85
        $objectTypeProperties = $this->prepareProperties((array)$response['data'], $name);
86
        $this->set(compact('objectTypeProperties'));
87
        $schema = $this->Schema->getSchema();
88
        $this->set('schema', $this->updateSchema($schema, $resource));
89
        $this->set('properties', $this->Properties->viewGroups($resource, $this->resourceType));
90
        $this->set('propertyTypesOptions', $this->Properties->typesOptions());
91
        $this->set('associationsOptions', $this->Properties->associationsOptions((array)Hash::get($resource, 'attributes.associations')));
92
        // setup `currentAttributes`
93
        $this->Modules->setupAttributes($resource);
94
95
        return null;
96
    }
97
98
    /**
99
     * Update schema using resource.
100
     * If core type, skip.
101
     * Otherwise, set table and parent_name.
102
     *
103
     * @param array $schema The schema
104
     * @param array $resource The resource
105
     * @return array
106
     */
107
    protected function updateSchema(array $schema, array $resource): array
108
    {
109
        if ((bool)Hash::get($resource, 'meta.core_type')) {
110
            return $schema;
111
        }
112
        $schema['properties']['table'] = [
113
            'type' => 'string',
114
            'enum' => $this->tables($resource),
115
        ];
116
        $schema['properties']['parent_name'] = [
117
            'type' => 'string',
118
            'enum' => array_merge([''], $this->Schema->abstractTypes()),
119
        ];
120
121
        return $schema;
122
    }
123
124
    /**
125
     * Get available tables list
126
     *
127
     * @return array
128
     */
129
    protected function tables(array $resource): array
130
    {
131
        $tables = array_unique(
132
            array_merge(
133
                self::TABLES,
134
                (array)Configure::read('Model.objectTypesTables')
135
            )
136
        );
137
        $tables = array_unique(
138
            array_merge(
139
                $tables,
140
                (array)Hash::get($resource, 'attributes.table')
141
            )
142
        );
143
        sort($tables);
144
145
        return $tables;
146
    }
147
148
    /**
149
     * Separate properties between `inherited`, `core`  and `custom`
150
     *
151
     * @param array $data Property array
152
     * @param string $name Object type name
153
     * @return array
154
     */
155
    protected function prepareProperties(array $data, string $name): array
156
    {
157
        $inherited = $core = $custom = [];
158
        foreach ($data as $prop) {
159
            if (!is_numeric($prop['id'])) {
160
                $type = $prop['attributes']['object_type_name'];
161
                if ($type == $name) {
162
                    $core[] = $prop;
163
                } else {
164
                    $inherited[] = $prop;
165
                }
166
            } else {
167
                $custom[] = $prop;
168
            }
169
        }
170
171
        return [
172
            'core' => Hash::sort($core, '{n}.attributes.name'),
173
            'inherited' => Hash::sort($inherited, '{n}.attributes.name'),
174
            'custom' => Hash::sort($custom, '{n}.attributes.name'),
175
        ];
176
    }
177
178
    /**
179
     * Save object type.
180
     *
181
     * @return \Cake\Http\Response|null
182
     */
183
    public function save(): ?Response
184
    {
185
        $this->addCustomProperties();
186
        $this->request = $this->request->withoutData('addedProperties');
187
        if ($this->request->getData('associations') === '') {
188
            $this->request = $this->request->withData('associations', null);
189
        }
190
191
        return parent::save();
192
    }
193
194
    /**
195
     * Add custom property
196
     *
197
     * @return void
198
     */
199
    protected function addCustomProperties(): void
200
    {
201
        $added = json_decode((string)$this->request->getData('addedProperties'), true);
202
        if (empty($added) || !is_array($added)) {
203
            return;
204
        }
205
        $objectTypeName = $this->request->getData('name');
206
207
        foreach ($added as $prop) {
208
            $data = [
209
                'type' => 'properties',
210
                'attributes' => [
211
                    'description' => Hash::get($prop, 'description'),
212
                    'name' => Hash::get($prop, 'name'),
213
                    'property_type_name' => Hash::get($prop, 'type'),
214
                    'object_type_name' => $objectTypeName,
215
                ],
216
            ];
217
            $this->apiClient->post('/model/properties', json_encode(compact('data')));
218
        }
219
    }
220
}
221