Passed
Push — master ( 8121c6...0ea172 )
by Alberto
01:47 queued 12s
created

Control::checkboxNullable()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 10
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 7
nc 1
nop 1
dl 0
loc 10
rs 10
c 0
b 0
f 0
1
<?php
2
/**
3
 * BEdita, API-first content management framework
4
 * Copyright 2020 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\Form;
15
16
use Cake\Core\Configure;
17
use Cake\Utility\Hash;
18
use Cake\Utility\Inflector;
19
20
/**
21
 * Control class provides methods for form controls, customized by control type.
22
 * Used by SchemaHelper to build control options for a property schema (@see \App\View\Helper\SchemaHelper::controlOptions)
23
 */
24
class Control
25
{
26
    /**
27
     * Control types
28
     */
29
    public const CONTROL_TYPES = [
30
        'json',
31
        'richtext',
32
        'plaintext',
33
        'date-time',
34
        'date',
35
        'checkbox',
36
        'checkboxNullable',
37
        'enum',
38
        'categories',
39
    ];
40
41
    /**
42
     * Get control by options
43
     *
44
     * @param array $options The options
45
     * @return array
46
     */
47
    public static function control(array $options): array
48
    {
49
        $type = $options['propertyType'];
50
        $format = self::format((array)$options['schema']);
51
        $controlOptions = array_intersect_key($options, array_flip(['label', 'disabled', 'readonly', 'value']));
52
        if ($type === 'text' && in_array($format, ['email', 'uri'])) {
53
            $result = call_user_func_array(Form::getMethod(self::class, $type, $format), [$options]);
54
55
            return array_merge($controlOptions, $result);
56
        }
57
        if (!in_array($type, self::CONTROL_TYPES)) {
58
            $result = compact('type') + ['value' => $options['value']];
59
60
            return array_merge($controlOptions, $result);
61
        }
62
        $result = call_user_func_array(Form::getMethod(self::class, $type), [$options]);
63
64
        return array_merge($controlOptions, $result);
65
    }
66
67
    /**
68
     * Get format from schema
69
     *
70
     * @param array $schema The schema
71
     * @return string
72
     */
73
    public static function format(array $schema): string
74
    {
75
        if (empty($schema['oneOf'])) {
76
            return '';
77
        }
78
        foreach ($schema['oneOf'] as $item) {
79
            if (array_key_exists('format', $item)) {
80
                return (string)$item['format'];
81
            }
82
        }
83
84
        return '';
85
    }
86
87
    /**
88
     * Control for json data
89
     *
90
     * @param array $options The options
91
     * @return array
92
     */
93
    public static function json(array $options): array
94
    {
95
        return [
96
            'type' => 'textarea',
97
            'v-jsoneditor' => 'true',
98
            'class' => 'json',
99
            'value' => json_encode(Hash::get($options, 'value')),
100
        ];
101
    }
102
103
    /**
104
     * Control for plaintext
105
     *
106
     * @param array $options The options
107
     * @return array
108
     */
109
    public static function plaintext(array $options): array
110
    {
111
        return [
112
            'type' => 'textarea',
113
            'value' => Hash::get($options, 'value'),
114
        ];
115
    }
116
117
    /**
118
     * Control for richtext
119
     *
120
     * @param array $options The options
121
     * @return array
122
     */
123
    public static function richtext(array $options): array
124
    {
125
        $schema = (array)Hash::get($options, 'schema');
126
        $value = Hash::get($options, 'value');
127
        $key = !empty($schema['placeholders']) ? 'v-richeditor.placeholders' : 'v-richeditor';
128
129
        return [
130
            'type' => 'textarea',
131
            $key => json_encode(Configure::read('RichTextEditor.default.toolbar', '')),
132
            'value' => $value,
133
        ];
134
    }
135
136
    /**
137
     * Control for datetime
138
     *
139
     * @param array $options The options
140
     * @return array
141
     */
142
    public static function datetime(array $options): array
143
    {
144
        return [
145
            'type' => 'text',
146
            'v-datepicker' => 'true',
147
            'date' => 'true',
148
            'time' => 'true',
149
            'value' => Hash::get($options, 'value'),
150
            'templates' => [
151
                'inputContainer' => '<div class="input datepicker {{type}}{{required}}">{{content}}</div>',
152
            ],
153
        ];
154
    }
155
156
    /**
157
     * Control for date
158
     *
159
     * @param array $options The options
160
     * @return array
161
     */
162
    public static function date(array $options): array
163
    {
164
        return [
165
            'type' => 'text',
166
            'v-datepicker' => 'true',
167
            'date' => 'true',
168
            'value' => Hash::get($options, 'value'),
169
            'templates' => [
170
                'inputContainer' => '<div class="input datepicker {{type}}{{required}}">{{content}}</div>',
171
            ],
172
        ];
173
    }
174
175
    /**
176
     * Control for categories
177
     *
178
     * @param array $options The options
179
     * @return array
180
     */
181
    public static function categories(array $options): array
182
    {
183
        $schema = (array)Hash::get($options, 'schema');
184
        $value = Hash::get($options, 'value');
185
        $categories = array_values(array_filter(
186
            (array)Hash::get($schema, 'categories'),
187
            function ($category) {
188
                return (bool)Hash::get($category, 'enabled');
189
            }
190
        ));
191
        $options = array_map(
192
            function ($category) {
193
                return [
194
                    'value' => Hash::get($category, 'name'),
195
                    'text' => empty($category['label']) ? $category['name'] : $category['label'],
196
                ];
197
            },
198
            $categories
199
        );
200
201
        $checked = [];
202
        if (!empty($value)) {
203
            $names = (array)Hash::extract($value, '{n}.name');
204
            foreach ($categories as $category) {
205
                if (in_array($category['name'], $names)) {
206
                    $checked[] = $category['name'];
207
                }
208
            }
209
        }
210
211
        return [
212
            'type' => 'select',
213
            'options' => $options,
214
            'multiple' => 'checkbox',
215
            'value' => $checked,
216
        ];
217
    }
218
219
    /**
220
     * Control for checkbox
221
     *
222
     * @param array $options The options
223
     * @return array
224
     */
225
    public static function checkbox(array $options): array
226
    {
227
        $schema = (array)Hash::get($options, 'schema');
228
        $value = Hash::get($options, 'value');
229
        if (empty($schema['oneOf'])) {
230
            return [
231
                'type' => 'checkbox',
232
                'checked' => filter_var($value, FILTER_VALIDATE_BOOLEAN),
233
                'value' => '1',
234
            ];
235
        }
236
237
        $options = [];
238
        foreach ($schema['oneOf'] as $one) {
239
            self::oneOptions($options, $one);
240
        }
241
        if (!empty($options)) {
242
            return [
243
                'type' => 'select',
244
                'options' => $options,
245
                'multiple' => 'checkbox',
246
            ];
247
        }
248
249
        return [
250
            'type' => 'checkbox',
251
            'checked' => filter_var($value, FILTER_VALIDATE_BOOLEAN),
252
            'value' => '1',
253
        ];
254
    }
255
256
    /**
257
     * Control for checkbox nullable
258
     *
259
     * @param array $options The options
260
     * @return array
261
     */
262
    public static function checkboxNullable(array $options): array
263
    {
264
        return [
265
            'type' => 'select',
266
            'options' => [
267
                'null' => '',
268
                '1' => __('Yes'),
269
                '0' => __('No'),
270
            ],
271
            'value' => Hash::get($options, 'value'),
272
        ];
273
    }
274
275
    /**
276
     * Set options for one of `oneOf` items.
277
     *
278
     * @param array $options The options to update
279
     * @param array $one The one item to check
280
     * @return void
281
     */
282
    public static function oneOptions(array &$options, array $one): void
283
    {
284
        $type = Hash::get($one, 'type');
285
        if ($type !== 'array') {
286
            return;
287
        }
288
        $options = array_map(
289
            function ($item) {
290
                return ['value' => $item, 'text' => Inflector::humanize($item)];
291
            },
292
            (array)Hash::extract($one, 'items.enum')
293
        );
294
    }
295
296
    /**
297
     * Control for enum
298
     *
299
     * @param array $options The options
300
     * @return array
301
     */
302
    public static function enum(array $options): array
303
    {
304
        $schema = (array)Hash::get($options, 'schema');
305
        $value = Hash::get($options, 'value');
306
        $objectType = Hash::get($options, 'objectType');
307
        $property = Hash::get($options, 'property');
308
309
        if (!empty($schema['oneOf'])) {
310
            foreach ($schema['oneOf'] as $one) {
311
                if (!empty($one['enum'])) {
312
                    $schema['enum'] = $one['enum'];
313
                    array_unshift($schema['enum'], '');
314
                }
315
            }
316
        }
317
318
        return [
319
            'type' => 'select',
320
            'options' => array_map(
321
                function (string $value) use ($objectType, $property) {
322
                    $text = self::label((string)$objectType, (string)$property, $value);
323
324
                    return compact('text', 'value');
325
                },
326
                $schema['enum']
327
            ),
328
            'value' => $value,
329
        ];
330
    }
331
332
    /**
333
     * Control for email
334
     *
335
     * @param array $options The options
336
     * @return array
337
     */
338
    public static function email(array $options): array
339
    {
340
        return [
341
            'type' => 'text',
342
            'v-email' => 'true',
343
            'class' => 'email',
344
            'value' => Hash::get($options, 'value'),
345
        ];
346
    }
347
348
    /**
349
     * Control for uri
350
     *
351
     * @param array $options The options
352
     * @return array
353
     */
354
    public static function uri(array $options): array
355
    {
356
        return [
357
            'type' => 'text',
358
            'v-uri' => 'true',
359
            'class' => 'uri',
360
            'value' => Hash::get($options, 'value'),
361
        ];
362
    }
363
364
    /**
365
     * Label for property.
366
     * If set in config Properties.<type>.labels.options.<property>, return it.
367
     * Return humanize of value, otherwise.
368
     *
369
     * @param string $type The object type
370
     * @param string $property The property name
371
     * @param string $value The value
372
     * @return string
373
     */
374
    public static function label(string $type, string $property, string $value): string
375
    {
376
        $label = Configure::read(sprintf('Properties.%s.labels.options.%s', $type, $property));
377
        if (empty($label)) {
378
            return Inflector::humanize($value);
379
        }
380
        $labelVal = (string)Configure::read(sprintf('Properties.%s.labels.options.%s.%s', $type, $property, $value));
381
        if (empty($labelVal)) {
382
            return Inflector::humanize($value);
383
        }
384
385
        return $labelVal;
386
    }
387
}
388