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

ObjectTypesController::addCustomProperties()   A

Complexity

Conditions 4
Paths 3

Size

Total Lines 18
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
eloc 12
nc 3
nop 0
dl 0
loc 18
rs 9.8666
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 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
        $this->set('propertyTypesOptions', $this->Properties->typesOptions());
80
        $this->set('associationsOptions', $this->Properties->associationsOptions((array)Hash::get($resource, 'attributes.associations')));
81
        // setup `currentAttributes`
82
        $this->Modules->setupAttributes($resource);
83
84
        return null;
85
    }
86
87
    /**
88
     * Update schema using resource.
89
     * If core type, skip.
90
     * Otherwise, set table and parent_name.
91
     *
92
     * @param array $schema The schema
93
     * @param array $resource The resource
94
     * @return array
95
     */
96
    protected function updateSchema(array $schema, array $resource): array
97
    {
98
        if ((bool)Hash::get($resource, 'meta.core_type')) {
99
            return $schema;
100
        }
101
        $schema['properties']['table'] = [
102
            'type' => 'string',
103
            'enum' => $this->tables($resource),
104
        ];
105
        $schema['properties']['parent_name'] = [
106
            'type' => 'string',
107
            'enum' => array_merge([''], $this->Schema->abstractTypes()),
108
        ];
109
110
        return $schema;
111
    }
112
113
    /**
114
     * Get available tables list
115
     *
116
     * @return array
117
     */
118
    protected function tables(array $resource): array
119
    {
120
        $tables = array_unique(
121
            array_merge(
122
                self::TABLES,
123
                (array)Configure::read('Model.objectTypesTables')
124
            )
125
        );
126
        $tables = array_unique(
127
            array_merge(
128
                $tables,
129
                (array)Hash::get($resource, 'attributes.table')
130
            )
131
        );
132
        sort($tables);
133
134
        return $tables;
135
    }
136
137
    /**
138
     * Separate properties between `inherited`, `core`  and `custom`
139
     *
140
     * @param array $data Property array
141
     * @param string $name Object type name
142
     * @return array
143
     */
144
    protected function prepareProperties(array $data, string $name): array
145
    {
146
        $inherited = $core = $custom = [];
147
        foreach ($data as $prop) {
148
            if (!is_numeric($prop['id'])) {
149
                $type = $prop['attributes']['object_type_name'];
150
                if ($type == $name) {
151
                    $core[] = $prop;
152
                } else {
153
                    $inherited[] = $prop;
154
                }
155
            } else {
156
                $custom[] = $prop;
157
            }
158
        }
159
160
        return [
161
            'core' => Hash::sort($core, '{n}.attributes.name'),
162
            'inherited' => Hash::sort($inherited, '{n}.attributes.name'),
163
            'custom' => Hash::sort($custom, '{n}.attributes.name'),
164
        ];
165
    }
166
167
    /**
168
     * Save object type.
169
     *
170
     * @return \Cake\Http\Response|null
171
     */
172
    public function save(): ?Response
173
    {
174
        $this->addCustomProperties();
175
        $this->request = $this->request->withoutData('addedProperties');
176
        if ($this->request->getData('associations') === '') {
177
            $this->request = $this->request->withData('associations', null);
178
        }
179
180
        return parent::save();
181
    }
182
183
    /**
184
     * Add custom property
185
     *
186
     * @return void
187
     */
188
    protected function addCustomProperties(): void
189
    {
190
        $added = json_decode((string)$this->request->getData('addedProperties'), true);
191
        if (empty($added) || !is_array($added)) {
192
            return;
193
        }
194
        $objectTypeName = $this->request->getData('name');
195
196
        foreach ($added as $prop) {
197
            $data = [
198
                'type' => 'properties',
199
                'attributes' => [
200
                    'name' => Hash::get($prop, 'name'),
201
                    'property_type_name' => Hash::get($prop, 'type'),
202
                    'object_type_name' => $objectTypeName,
203
                ],
204
            ];
205
            $this->apiClient->post('/model/properties', json_encode(compact('data')));
206
        }
207
    }
208
}
209