Passed
Push — develop ( 0b5f25...28eec5 )
by Paul
13:25
created

Transformer::controlAlerts()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 2
Bugs 0 Features 1
Metric Value
eloc 3
c 2
b 0
f 1
dl 0
loc 6
ccs 0
cts 5
cp 0
rs 10
cc 1
nc 1
nop 0
crap 2
1
<?php
2
3
namespace GeminiLabs\SiteReviews\Integrations\Breakdance;
4
5
use GeminiLabs\SiteReviews\Helper;
6
use GeminiLabs\SiteReviews\Helpers\Arr;
7
use GeminiLabs\SiteReviews\Helpers\Str;
8
use GeminiLabs\SiteReviews\Integrations\Breakdance\Defaults\ControlDefaults;
9
10
use function Breakdance\Elements\c;
11
12
class Transformer extends \ArrayObject
13
{
14
    public string $location;
15
    public string $shortcode;
16
17
    protected array $alerts;
18
    protected array $popouts;
19
    protected array $sections;
20
21
    public function __construct(string $location, array $config, string $shortcode = '')
22
    {
23
        $this->location = in_array($location, ['content', 'design', 'settings'])
24
            ? $location
25
            : 'content';
26
        $this->shortcode = $shortcode;
27
        $this->alerts = $this->controlAlerts();
28
        $this->popouts = $this->controlPopouts();
29
        $this->sections = $this->controlSections();
30
        $controls = $this->processConfig($config);
31
        parent::__construct($controls, \ArrayObject::STD_PROP_LIST | \ArrayObject::ARRAY_AS_PROPS);
32
    }
33
34
    public function control(array $args): array
35
    {
36
        $control = glsr(ControlDefaults::class)->restrict($args);
37
        return c(
38
            $control['slug'],
39
            $control['label'],
40
            $control['children'],
41
            $control['options'],
42
            $control['enableMediaQueries'],
43
            $control['enableHover'],
44
            $control['keywords']
45
        );
46
    }
47
48
    public function controls(): array
49
    {
50
        $items = [];
51
        foreach ($this as $item) {
52
            $items[$item['path']] = $item['control'];
53
        }
54
        $items = Arr::unflatten(array_filter($items));
55
        $controls = [];
56
        foreach ($items as $slug => $children) {
57
            $section = $this->section($slug);
58
            foreach ($children as $key => $child) {
59
                if (!str_starts_with($key, 'popout_')) {
60
                    $section['children'][] = $child;
61
                    continue;
62
                }
63
                $popoutSlug = Str::removePrefix($key, 'popout_');
64
                $section['children'][] = $this->popout($popoutSlug, array_values($child));
65
            }
66
            $controls[] = $section;
67
        }
68
        return $controls;
69
    }
70
71
    public function description(array $args, string $style = 'default'): array
72
    {
73
        if (empty($args['description'])) {
74
            return [];
75
        }
76
        $options = [
77
            'alertBoxOptions' => [
78
                'style' => $style,
79
                'content' => $args['description'],
80
            ],
81
            'layout' => 'vertical',
82
            'type' => 'alert_box',
83
        ];
84
        return $this->control([
85
            'options' => wp_parse_args($options, $args['options'] ?? []),
86
            'slug' => "{$args['slug']}_description_alert",
87
        ]);
88
    }
89
90
    public function popout(string $slug, array $children): array
91
    {
92
        return $this->control([
93
            'children' => $children,
94
            'label' => $this->popouts[$slug] ?? Str::titleCase($slug),
95
            'slug' => $slug,
96
            'options' => [
97
                'type' => 'section',
98
                'sectionOptions' => [
99
                    'type' => 'popout',
100
                ],
101
            ],
102
        ]);
103
    }
104
105
    public function section(string $slug, array $children = []): array
106
    {
107
        return $this->control([
108
            'children' => $children,
109
            'label' => $this->sections[$slug] ?? Str::titleCase($slug),
110
            'slug' => $slug,
111
            'options' => [
112
                'layout' => 'vertical',
113
                'type' => 'section',
114
            ],
115
        ]);
116
    }
117
118
    protected function controlAlerts(): array
119
    {
120
        $alerts = [
121
            'schema' => 'warning',
122
        ];
123
        return glsr()->filterArray('breakdance/controls/alerts', $alerts, $this);
124
    }
125
126
    protected function controlPopouts(): array
127
    {
128
        $popouts = [
129
            'display' => esc_html_x('Display', 'admin-text', 'site-reviews'),
130
            'filters' => esc_html_x('Filters', 'admin-text', 'site-reviews'),
131
            'hide' => esc_html_x('Hide', 'admin-text', 'site-reviews'),
132
            'schema' => esc_html_x('Schema', 'admin-text', 'site-reviews'),
133
            'text' => esc_html_x('Text', 'admin-text', 'site-reviews'),
134
        ];
135
        return glsr()->filterArray('breakdance/controls/popouts', $popouts, $this);
136
    }
137
138
    protected function controlSections(): array
139
    {
140
        $sections = [ // order is intentional
141
            'general' => esc_html_x('General', 'admin-text', 'site-reviews'),
142
            'advanced' => esc_html_x('Advanced', 'admin-text', 'site-reviews'),
143
        ];
144
        return glsr()->filterArray('breakdance/controls/sections', $sections, $this);
145
    }
146
147
    protected function pathPrefix(string $group): string
148
    {
149
        if (array_key_exists($group, $this->sections)) {
150
            return $group;
151
        }
152
        if (array_key_exists($group, $this->popouts)) {
153
            return "general.popout_{$group}";
154
        }
155
        return 'general';
156
    }
157
158
    /**
159
     * @return array[] Each array has a "path" and "control" key
160
     */
161
    protected function processConfig(array $config): array
162
    {
163
        $config = glsr()->filterArray('breakdance/config', $config, $this);
164
        $controls = [];
165
        foreach ($config as $slug => $args) {
166
            $args = wp_parse_args($args, [
167
                'description' => '',
168
                'group' => 'general',
169
                'label' => '',
170
                'slug' => $slug,
171
                'type' => '',
172
            ]);
173
            $path = $this->pathPrefix($args['group']);
174
            $method = Helper::buildMethodName('transform', ($args['type'] ?: 'unknown'));
175
            if (method_exists($this, $method)) {
176
                $control = call_user_func([$this, $method], $args);
177
            } else {
178
                if (empty($args['options']['type'])) {
179
                    $args['options'] = ['type' => ($args['type'] ?: 'text')];
180
                }
181
                $control = $this->control($args);
182
            }
183
            $controlId = $args['slug'] ?? $slug; // because the slug might have been changed
184
            $controls[$controlId] = [
185
                'control' => $control,
186
                'path' => "{$path}.{$controlId}",
187
            ];
188
            if (!empty($args['description']) && !empty($control)) {
189
                $descriptionControl = $this->description($args, $this->alerts[$controlId] ?? 'default');
190
                $descriptionId = "{$controlId}_description_alert";
191
                $controls[$descriptionId] = [
192
                    'control' => $descriptionControl,
193
                    'path' => "{$path}.{$descriptionId}",
194
                ];
195
            }
196
        }
197
        return glsr()->filterArray('breakdance/controls', $controls, $this);
198
    }
199
200
    protected function transformCheckbox(array $args): array
201
    {
202
        $control = $this->control([
203
            'label' => $args['label'],
204
            'slug' => $args['slug'],
205
            'options' => [
206
                'layout' => 'inline',
207
                'type' => 'toggle',
208
            ],
209
        ]);
210
        if (!empty($args['options'])) {
211
            $control['options']['type'] = 'section';
212
            foreach ($args['options'] as $slug => $label) {
213
                $control['children'][] = $this->control([
214
                    'label' => $label,
215
                    'slug' => $slug,
216
                    'options' => [
217
                        'layout' => 'inline',
218
                        'type' => 'toggle',
219
                    ],
220
                ]);
221
            }
222
        }
223
        return $control;
224
    }
225
226
    protected function transformNumber(array $args): array
227
    {
228
        return $this->control([
229
            'slug' => $args['slug'],
230
            'label' => $args['label'],
231
            'options' => [
232
                'layout' => 'inline',
233
                'type' => 'number',
234
                'rangeOptions' => [
235
                    'min' => Arr::getAs('int', $args, 'min', 0),
236
                    'max' => Arr::getAs('int', $args, 'max', 1),
237
                    'step' => Arr::getAs('int', $args, 'step', 1),
238
                ],
239
            ],
240
        ]);
241
    }
242
243
    protected function transformSelect(array $args): array
244
    {
245
        $control = $this->control([
246
            'label' => $args['label'],
247
            'slug' => $args['slug'],
248
            'options' => [
249
                'layout' => 'vertical',
250
                'placeholder' => $args['placeholder'] ?? esc_html_x('Select...', 'admin-text', 'site-reviews'),
251
                'type' => 'dropdown',
252
            ],
253
        ]);
254
        if (!isset($args['options'])) {
255
            // Unfortunately we can't use this yet because Breakdance does not support
256
            // AJAX searching in multiselect controls.
257
            // $control['options']['type'] = 'multiselect';
258
            // $control['options']['searchable'] = true;
259
            // $control['options']['multiselectOptions']['populate'] = [
260
            //     'fetchDataAction' => glsr()->prefix.'breakdance_'.$args['slug'],
261
            //     'fetchContextPath' => 'content.general.'.$args['slug'],
262
            // ];
263
            $control['options']['type'] = 'post_chooser';
264
            $control['options']['postChooserOptions'] = [
265
                'multiple' => $args['multiple'] ?? false,
266
                'postType' => glsr()->prefix.$args['slug'],
267
                'showThumbnails' => in_array($args['slug'], [
268
                    'assigned_posts',
269
                    'assigned_users',
270
                    'author',
271
                ]),
272
            ];
273
            return $control;
274
        }
275
        if (!empty($args['options'])) {
276
            $callback = fn ($value, $text) => compact('text', 'value');
277
            $items = array_map($callback, array_keys($args['options']), $args['options']);
278
            $control['options']['items'] = $items;
279
            return $control;
280
        }
281
        return [];
282
    }
283
284
    protected function transformText(array $args): array
285
    {
286
        $slug = $args['slug'];
287
        if ('id' === $slug) {
288
            $slug = 'attr_id';
289
        }
290
        if ('class' === $slug) {
291
            $slug = 'attr_class';
292
        }
293
        return $this->control([
294
            'label' => $args['label'],
295
            'slug' => $slug,
296
            'options' => [
297
                'layout' => 'vertical',
298
                'type' => 'text',
299
            ],
300
        ]);
301
    }
302
}
303