Passed
Pull Request — master (#816)
by Stefano
02:47
created

PropertiesComponent::typesOptions()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 18
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 2 Features 0
Metric Value
eloc 13
c 2
b 2
f 0
dl 0
loc 18
rs 9.8333
cc 2
nc 2
nop 0
1
<?php
2
/**
3
 * BEdita, API-first content management framework
4
 * Copyright 2018 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
14
namespace App\Controller\Component;
15
16
use App\Utility\CacheTools;
17
use BEdita\WebTools\ApiClientProvider;
18
use Cake\Cache\Cache;
19
use Cake\Controller\Component;
20
use Cake\Core\Configure;
21
use Cake\Utility\Hash;
22
use Cake\Utility\Inflector;
23
24
/**
25
 * Component to handle properties view in modules.
26
 *
27
 * @property \App\Controller\Component\ConfigComponent $Config
28
 */
29
class PropertiesComponent extends Component
30
{
31
    /**
32
     * @inheritDoc
33
     */
34
    protected $components = ['Config'];
35
36
    /**
37
     * Default properties groups
38
     *
39
     * @var array
40
     */
41
    protected $defaultGroups = [
42
        'view' => [
43
            // always open on the top
44
            'core' => [
45
                'title',
46
                'description',
47
            ],
48
            // publishing related
49
            'publish' => [
50
                'uname',
51
                'status',
52
                'publish_start',
53
                'publish_end',
54
            ],
55
            // power users
56
            'advanced' => [
57
                'extra',
58
            ],
59
            // remaining attributes
60
            // items listed here only used for ordering, not listed if present in other groups
61
            'other' => [
62
                'body',
63
                'lang',
64
                // remaining attributes
65
            ],
66
        ],
67
        // index properties list
68
        // don't include: 'id', 'status', and 'modified' => always listed
69
        'index' => [
70
            'title',
71
        ],
72
73
        'filter' => [
74
            'status',
75
        ],
76
        'bulk' => [
77
            'status',
78
        ],
79
    ];
80
81
    /**
82
     * Properties to exclude from groups view
83
     *
84
     * @var array
85
     */
86
    protected $excluded = [
87
        'categories',
88
        'date_ranges',
89
        'tags',
90
        'lang',
91
    ];
92
93
    /**
94
     * Init properties
95
     *
96
     * @return void
97
     */
98
    public function startup(): void
99
    {
100
        $cacheKey = CacheTools::cacheKey('properties');
101
        $properties = Cache::read($cacheKey, 'default');
102
        if (!empty($properties)) {
103
            $this->setConfig('Properties', $properties);
104
105
            return;
106
        }
107
        Configure::load('properties');
108
        $properties = $this->Config->read('Properties');
109
        $defaultProperties = (array)Configure::read('DefaultProperties');
110
        $keys = array_unique(
111
            array_merge(
112
                array_keys($properties),
113
                array_keys($defaultProperties)
114
            )
115
        );
116
        sort($keys);
117
        $config = [];
118
        foreach ($keys as $key) {
119
            $config[$key] = array_merge(
120
                (array)Hash::get($defaultProperties, $key),
121
                (array)Hash::get($properties, $key)
122
            );
123
        }
124
        $this->setConfig('Properties', $config);
125
        Cache::write($cacheKey, $config);
126
    }
127
128
    /**
129
     * Setup object attributes into groups from configuration for the view.
130
     * An array with a key for each group will be created.
131
     *
132
     * Displayed view groups are
133
     *      + 'core' always open on the top
134
     *      + 'publish' publishing related
135
     *      + 'advanced' for power users (JSON mainly)
136
     *      + 'other' remaining attributes
137
     *
138
     * Customization available via `Properties.{type}.view` configuration where properties
139
     * names can be grouped in `core`, `publish`, `advanced` and `other` as well
140
     *
141
     * Properties not present in $object will not be set in any group unless they're listed
142
     * under `_keep` in the above configuration.
143
     *
144
     * Properties in `Properties.{type}.view._hide` will be removed from groups.
145
     *
146
     * Properties in internal `$excluded` array will be removed from groups.
147
     *
148
     * @param array  $object Object data to view
149
     * @param string $type   Object type
150
     * @return array
151
     */
152
    public function viewGroups(array $object, string $type): array
153
    {
154
        $properties = $used = [];
155
        $keep = (array)$this->getConfig(sprintf('Properties.%s.view._keep', $type), []);
156
        $hide = (array)$this->getConfig(sprintf('Properties.%s.view._hide', $type), []);
157
        $attributes = array_merge(array_fill_keys($keep, ''), (array)Hash::get($object, 'attributes'));
158
        $attributes = array_diff_key($attributes, array_flip($this->excluded));
159
        $attributes = array_diff_key($attributes, array_flip($hide));
160
        $defaults = array_merge($this->getConfig(sprintf('Properties.%s.view', $type), []), $this->defaultGroups['view']);
161
        unset($defaults['_keep']);
162
163
        foreach ($defaults as $group => $items) {
164
            $key = sprintf('Properties.%s.view.%s', $type, $group);
165
            $list = $this->getConfig($key, $items);
166
            $p = [];
167
            foreach ($list as $item) {
168
                if (array_key_exists($item, $attributes)) {
169
                    $p[$item] = $attributes[$item];
170
                }
171
            }
172
            $properties[$group] = $p;
173
            if ($group !== 'other') {
174
                $used = array_merge($used, $list);
175
            }
176
        }
177
        // add remaining properties to 'other' group
178
        $properties['other'] = array_diff_key($properties['other'], array_flip($used));
179
        $properties['other'] += array_diff_key($attributes, array_flip($used));
180
181
        return $properties;
182
    }
183
184
    /**
185
     * List properties to display in `index` view
186
     *
187
     * @param string $type Object type name
188
     * @return array
189
     */
190
    public function indexList(string $type): array
191
    {
192
        $list = $this->getConfig(sprintf('Properties.%s.index', $type), $this->defaultGroups['index']);
193
194
        return array_diff($list, ['id', 'status', 'modified']);
195
    }
196
197
    /**
198
     * List of filter to display in `filter` view
199
     *
200
     * @param string $type Object type name
201
     * @return array
202
     */
203
    public function filterList(string $type): array
204
    {
205
        return $this->getConfig(sprintf('Properties.%s.filter', $type), $this->defaultGroups['filter']);
206
    }
207
208
    /**
209
     * List of all filters, grouped by type, for passed `$types` list
210
     *
211
     * @param string[] $types List of types to get filters of
212
     * @return array
213
     */
214
    public function filtersByType(array $types): array
215
    {
216
        if (empty($types)) {
217
            return [];
218
        }
219
220
        return array_filter(
221
            array_reduce(
222
                $types,
223
                function (array $accumulator, string $type) {
224
                    $accumulator[$type] = $this->filterList($type);
225
226
                    return $accumulator;
227
                },
228
                []
229
            )
230
        );
231
    }
232
233
    /**
234
     * List of bulk actions to display in `index` view
235
     *
236
     * @param string $type Object type name
237
     * @return array
238
     */
239
    public function bulkList(string $type): array
240
    {
241
        return (array)$this->getConfig(sprintf('Properties.%s.bulk', $type), $this->defaultGroups['bulk']);
242
    }
243
244
    /**
245
     * List of ordered relations to display.
246
     * Relations not included will be displayed after these.
247
     *
248
     * @param string $type Object type name
249
     * @return array
250
     */
251
    public function relationsList(string $type): array
252
    {
253
        return (array)$this->getConfig(sprintf('Properties.%s.relations', $type), []);
254
    }
255
256
    /**
257
     * List of hidden relations.
258
     *
259
     * @param string $type Object type name
260
     * @return array
261
     */
262
    public function hiddenRelationsList(string $type): array
263
    {
264
        return (array)$this->getConfig(sprintf('Properties.%s.relations._hide', $type), []);
265
    }
266
267
    /**
268
     * List of readonly relations.
269
     *
270
     * @param string $type Object type name
271
     * @return array
272
     */
273
    public function readonlyRelationsList(string $type): array
274
    {
275
        return (array)$this->getConfig(sprintf('Properties.%s.relations._readonly', $type), []);
276
    }
277
278
    /**
279
     * Types options for property Type select combo
280
     *
281
     * @return array
282
     */
283
    public function typesOptions(): array
284
    {
285
        $label = __('Type');
286
        $type = 'select';
287
        $options = ['' => ''];
288
        $apiClient = ApiClientProvider::getApiClient();
289
        $query = [
290
            'page_size' => 100,
291
            'sort' => 'id',
292
        ];
293
        $response = (array)$apiClient->get('/model/property_types', $query);
294
        $types = (array)Hash::extract($response, 'data.{n}.attributes.name');
295
        foreach ($types as $value) {
296
            $text = Inflector::humanize($value);
297
            $options[] = compact('text', 'value');
298
        }
299
300
        return compact('label', 'type', 'options');
301
    }
302
303
    /**
304
     * Get associations options for select multiple as list of checkboxes
305
     *
306
     * @param array $value The value
307
     * @return array
308
     */
309
    public function associationsOptions(array $value): array
310
    {
311
        $fields = [
312
            'DateRanges',
313
            'Streams',
314
            'Categories',
315
            'Tags',
316
        ];
317
        $fields = array_unique(array_merge($fields, $value));
318
        foreach ($fields as $text) {
319
            $value = $text;
320
            $options[] = compact('text', 'value');
321
        }
322
323
        return $options;
324
    }
325
}
326