Controller   C
last analyzed

Complexity

Total Complexity 57

Size/Duplication

Total Lines 403
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 57
eloc 202
c 1
b 0
f 0
dl 0
loc 403
rs 5.04

17 Methods

Rating   Name   Duplication   Size   Complexity  
B filterSettingsPrefixedId() 0 19 8
A filterControls() 0 27 4
A filterSettingsClass() 0 15 3
A filterSettingsMultiCheckbox() 0 19 6
A filterBuilderI18n() 0 5 1
A verifyAjaxRequest() 0 6 3
A filterThemeStyleGroups() 0 19 4
A includedIds() 0 7 1
A searchPostId() 0 23 3
A prefixedResults() 0 12 3
A searchAssignedPosts() 0 27 4
A searchAuthor() 0 20 3
A filterThemeStyleControls() 0 25 4
A searchAssignedUsers() 0 22 3
A registerElements() 0 7 2
A searchAssignedTerms() 0 15 2
A printInlineStyles() 0 40 3

How to fix   Complexity   

Complex Class

Complex classes like Controller often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Controller, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
namespace GeminiLabs\SiteReviews\Integrations\Bricks;
4
5
use GeminiLabs\SiteReviews\Controllers\AbstractController;
6
use GeminiLabs\SiteReviews\Database;
7
use GeminiLabs\SiteReviews\Helpers\Arr;
8
use GeminiLabs\SiteReviews\Helpers\Str;
9
use GeminiLabs\SiteReviews\Helpers\Svg;
10
use GeminiLabs\SiteReviews\Modules\Sanitizer;
11
12
class Controller extends AbstractController
13
{
14
    /**
15
     * @param array $i18n
16
     *
17
     * @filter bricks/builder/i18n
18
     */
19
    public function filterBuilderI18n($i18n): array
20
    {
21
        $i18n = Arr::consolidate($i18n);
22
        $i18n[glsr()->id] = glsr()->name;
23
        return $i18n;
24
    }
25
26
    /**
27
     * @param array $controls
28
     *
29
     * @filter bricks/elements/site_review/controls
30
     * @filter bricks/elements/site_reviews/controls
31
     * @filter bricks/elements/site_reviews_form/controls
32
     * @filter bricks/elements/site_reviews_summary/controls
33
     */
34
    public function filterControls($controls): array
35
    {
36
        $sections = [
37
            'display' => esc_html_x('Display', 'admin-text', 'site-reviews'),
38
            'hide' => esc_html_x('Hide', 'admin-text', 'site-reviews'),
39
            'schema' => esc_html_x('Schema', 'admin-text', 'site-reviews'),
40
            'text' => esc_html_x('Text', 'admin-text', 'site-reviews'),
41
        ];
42
        $sectioned = [];
43
        foreach ($controls as $key => $control) {
44
            $group = $control['group'] ?? 'general';
45
            if (!array_key_exists($group, $sections)) {
46
                $sectioned[$key] = $control;
47
                continue;
48
            }
49
            if (!array_key_exists("separator_{$group}", $sectioned)) {
50
                $sectioned["separator_{$group}"] = [
51
                    'group' => 'general',
52
                    'label' => esc_html($sections[$group] ?? ucfirst($group)),
53
                    'tab' => 'content',
54
                    'type' => 'separator',
55
                ];
56
            }
57
            $control['group'] = 'general';
58
            $sectioned[$key] = $control;
59
        }
60
        return $sectioned;
61
    }
62
63
    /**
64
     * @param \Bricks\Element $element
0 ignored issues
show
Bug introduced by
The type Bricks\Element was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
65
     *
66
     * @filter bricks/element/settings:100
67
     */
68
    public function filterSettingsClass($settings, $element): array
69
    {
70
        $settings = Arr::consolidate($settings);
71
        if (!is_a($element, BricksElement::class)) {
72
            return $settings;
73
        }
74
        $classes = $settings['class'] ?? '';
75
        $classes = explode(' ', $classes);
76
        if ($preset = $element->styledSetting('style_preset')) {
77
            $classes[] = "is-style-{$preset}";
78
        }
79
        $classes = $element->styledClasses($classes);
80
        $classes = implode(' ', $classes);
81
        $settings['class'] = glsr(Sanitizer::class)->sanitizeAttrClass($classes);
82
        return $settings;
83
    }
84
85
    /**
86
     * Consolidate multi-checkbox values because Bricks does not allow them.
87
     *
88
     * @param \Bricks\Element $element
89
     *
90
     * @filter bricks/element/settings
91
     */
92
    public function filterSettingsMultiCheckbox($settings, $element): array
93
    {
94
        $settings = Arr::consolidate($settings);
95
        if (!is_a($element, BricksElement::class)) {
96
            return $settings;
97
        }
98
        foreach ($element->elementConfig() as $key => $control) {
99
            $type = $control['type'] ?? '';
100
            $options = Arr::getAs('array', $control, 'options');
101
            if ('checkbox' !== $type || empty($options)) {
102
                continue;
103
            }
104
            $values = array_filter(
105
                array_keys($settings),
106
                fn ($k) => !empty($settings[$k]) && str_starts_with($k, "{$key}_")
107
            );
108
            $settings[$key] = array_map(fn ($k) => Str::removePrefix($k, "{$key}_"), $values);
109
        }
110
        return $settings;
111
    }
112
113
    /**
114
     * Remove the "id::" prefix used to maintain javascript sorting.
115
     *
116
     * @param \Bricks\Element $element
117
     *
118
     * @filter bricks/element/settings
119
     */
120
    public function filterSettingsPrefixedId($settings, $element): array
121
    {
122
        $settings = Arr::consolidate($settings);
123
        if (!is_a($element, BricksElement::class)) {
124
            return $settings;
125
        }
126
        foreach ($settings as $key => $value) {
127
            if (is_string($value) && str_starts_with($value, 'id::')) {
128
                $settings[$key] = Str::removePrefix($value, 'id::');
129
                continue;
130
            }
131
            if (is_array($value) && wp_is_numeric_array($value)) {
132
                $settings[$key] = array_map(
133
                    fn ($val) => is_string($val) ? Str::removePrefix($val, 'id::') : '',
134
                    $value
135
                );
136
            }
137
        }
138
        return $settings;
139
    }
140
141
    /**
142
     * @filter bricks/theme_styles/controls
143
     */
144
    public function filterThemeStyleControls(array $controls): array
145
    {
146
        $shortcodes = [
147
            'site_review',
148
            'site_reviews',
149
            'site_reviews_form',
150
            'site_reviews_summary',
151
        ];
152
        if (!class_exists('Bricks\Elements')) {
153
            return $controls;
154
        }
155
        foreach ($shortcodes as $shortcode) {
156
            if ($element = \Bricks\Elements::$elements[$shortcode] ?? false) {
0 ignored issues
show
Bug introduced by
The type Bricks\Elements was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
157
                $instance = new $element['class']();
158
                $instance->set_controls();
159
                $instance->controls = apply_filters("bricks/elements/$shortcode/controls", $instance->controls);
160
                $themeControls = array_filter($instance->controls, fn ($control) => !empty($control['themeStyle']));
161
                array_walk($themeControls, function (&$control) use ($shortcode) {
162
                    $control['group'] = $shortcode;
163
                    unset($control['required']);
164
                });
165
                $controls[$shortcode] = $themeControls;
166
            }
167
        }
168
        return $controls;
169
    }
170
171
    /**
172
     * @filter bricks/theme_styles/control_groups
173
     */
174
    public function filterThemeStyleGroups(array $groups): array
175
    {
176
        $shortcodes = [
177
            'site_review',
178
            'site_reviews',
179
            'site_reviews_form',
180
            'site_reviews_summary',
181
        ];
182
        if (!class_exists('Bricks\Elements')) {
183
            return $groups;
184
        }
185
        foreach ($shortcodes as $shortcode) {
186
            if ($element = \Bricks\Elements::$elements[$shortcode] ?? false) {
187
                $groups[$shortcode] = [
188
                    'title' => sprintf('%s - %s', glsr()->name, $element['label']),
189
                ];
190
            }
191
        }
192
        return $groups;
193
    }
194
195
    /**
196
     * @action wp_enqueue_scripts
197
     */
198
    public function printInlineStyles(): void
199
    {
200
        if (!function_exists('bricks_is_builder')) {
201
            return;
202
        }
203
        if (!bricks_is_builder()) {
204
            return;
205
        }
206
        $iconForm = Svg::encoded('assets/images/icons/bricks/icon-form.svg');
207
        $iconReview = Svg::encoded('assets/images/icons/bricks/icon-review.svg');
208
        $iconReviews = Svg::encoded('assets/images/icons/bricks/icon-reviews.svg');
209
        $iconSummary = Svg::encoded('assets/images/icons/bricks/icon-summary.svg');
210
        $css = "
211
            i[class^='ti-site_review']::before {
212
                background-color: currentColor;
213
                content: '';
214
                display: inline-block;
215
                height: 1em;
216
                mask-position: center;
217
                mask-repeat: no-repeat;
218
                mask-size: 100%;
219
                width: 1em;
220
            }
221
            i.ti-site_reviews_form::before {
222
                mask-image: url(\"{$iconForm}\");
223
            }
224
            i.ti-site_review::before {
225
                mask-image: url(\"{$iconReview}\");
226
            }
227
            i.ti-site_reviews::before {
228
                mask-image: url(\"{$iconReviews}\");
229
            }
230
            i.ti-site_reviews_summary::before {
231
                mask-image: url(\"{$iconSummary}\");
232
            }
233
            .glsr :is(a,button,input,textarea,select,.dz-clickable) {
234
                pointer-events: none !important;
235
            }
236
        ";
237
        wp_add_inline_style('bricks-builder', $css);
238
    }
239
240
    /**
241
     * @action init
242
     */
243
    public function registerElements(): void
244
    {
245
        if (class_exists('Bricks\Element')) {
246
            BricksSiteReview::registerElement();
247
            BricksSiteReviews::registerElement();
248
            BricksSiteReviewsForm::registerElement();
249
            BricksSiteReviewsSummary::registerElement();
250
        }
251
    }
252
253
    /**
254
     * @action wp_ajax_bricks_glsr_assigned_posts
255
     */
256
    public function searchAssignedPosts(): void
257
    {
258
        $this->verifyAjaxRequest();
259
        $query = stripslashes_deep(sanitize_text_field((string) filter_input(INPUT_GET, 'search')));
260
        $args = [
261
            'post__in' => [],
262
            'posts_per_page' => 25,
263
        ];
264
        if (is_numeric($query)) {
265
            $args['post__in'][] = (int) $query;
266
        } else {
267
            $args['s'] = $query;
268
        }
269
        $posts = glsr(Database::class)->posts($args);
270
        if ($include = $this->includedIds($posts)) {
271
            $posts += glsr(Database::class)->posts([
272
                'post__in' => $include,
273
            ]);
274
        }
275
        $results = $this->prefixedResults($posts);
276
        if (empty($query)) {
277
            $results = [
278
                'post_id' => esc_html_x('The Current Page', 'admin-text', 'site-reviews'),
279
                'parent_id' => esc_html_x('The Parent Page', 'admin-text', 'site-reviews'),
280
            ] + $results;
281
        }
282
        wp_send_json_success($results);
283
    }
284
285
    /**
286
     * @action wp_ajax_bricks_glsr_assigned_terms
287
     */
288
    public function searchAssignedTerms(): void
289
    {
290
        $this->verifyAjaxRequest();
291
        $query = stripslashes_deep(sanitize_text_field((string) filter_input(INPUT_GET, 'search')));
292
        $terms = glsr(Database::class)->terms([
293
            'number' => 25,
294
            'search' => $query,
295
        ]);
296
        if ($include = $this->includedIds($terms)) {
297
            $terms += glsr(Database::class)->terms([
298
                'term_taxonomy_id' => $include,
299
            ]);
300
        }
301
        $results = $this->prefixedResults($terms);
302
        wp_send_json_success($results);
303
    }
304
305
    /**
306
     * @action wp_ajax_bricks_glsr_assigned_users
307
     */
308
    public function searchAssignedUsers(): void
309
    {
310
        $this->verifyAjaxRequest();
311
        $query = stripslashes_deep(sanitize_text_field((string) filter_input(INPUT_GET, 'search')));
312
        $users = glsr(Database::class)->users([
313
            'number' => 25,
314
            'search_wild' => $query,
315
        ]);
316
        if ($include = $this->includedIds($users)) {
317
            $users += glsr(Database::class)->users([
318
                'include' => $include,
319
            ]);
320
        }
321
        $results = $this->prefixedResults($users);
322
        if (empty($query)) {
323
            $results = [
324
                'user_id' => esc_html_x('The Logged In User', 'admin-text', 'site-reviews'),
325
                'author_id' => esc_html_x('The Page Author', 'admin-text', 'site-reviews'),
326
                'profile_id' => esc_html_x('The Profile User', 'admin-text', 'site-reviews'),
327
            ] + $results;
328
        }
329
        wp_send_json_success($results);
330
    }
331
332
    /**
333
     * @action wp_ajax_bricks_glsr_author
334
     */
335
    public function searchAuthor(): void
336
    {
337
        $this->verifyAjaxRequest();
338
        $query = stripslashes_deep(sanitize_text_field((string) filter_input(INPUT_GET, 'search')));
339
        $users = glsr(Database::class)->users([
340
            'number' => 25,
341
            'search_wild' => $query,
342
        ]);
343
        if ($include = $this->includedIds($users)) {
344
            $users += glsr(Database::class)->users([
345
                'include' => $include,
346
            ]);
347
        }
348
        $results = $this->prefixedResults($users);
349
        if (empty($query)) {
350
            $results = [
351
                'user_id' => esc_html_x('The Logged In User', 'admin-text', 'site-reviews'),
352
            ] + $results;
353
        }
354
        wp_send_json_success($results);
355
    }
356
357
    /**
358
     * @action wp_ajax_bricks_glsr_post_id
359
     */
360
    public function searchPostId(): void
361
    {
362
        $this->verifyAjaxRequest();
363
        $query = stripslashes_deep(sanitize_text_field((string) filter_input(INPUT_GET, 'search')));
364
        $args = [
365
            'post__in' => [],
366
            'post_type' => glsr()->post_type,
367
            'posts_per_page' => 25,
368
        ];
369
        if (is_numeric($query)) {
370
            $args['post__in'][] = (int) $query;
371
        } else {
372
            $args['s'] = (string) $query;
373
        }
374
        $posts = glsr(Database::class)->posts($args);
375
        if ($include = $this->includedIds($posts)) {
376
            $posts += glsr(Database::class)->posts([
377
                'post__in' => $include,
378
                'post_type' => glsr()->post_type,
379
            ]);
380
        }
381
        $results = $this->prefixedResults($posts);
382
        wp_send_json_success($results);
383
    }
384
385
    protected function includedIds(array $results): array
386
    {
387
        $ids = filter_input(INPUT_GET, 'include', FILTER_DEFAULT, FILTER_FORCE_ARRAY) ?? [];
388
        $ids = array_map(fn ($id) => Str::removePrefix((string) $id, 'id::'), $ids);
389
        $ids = Arr::uniqueInt($ids);
390
        $ids = array_filter($ids, fn ($id) => !array_key_exists($id, $results));
391
        return $ids;
392
    }
393
394
    protected function prefixedResults(array $results, bool $prefixTitle = true): array
395
    {
396
        if ($prefixTitle) {
397
            array_walk($results, function (&$title, $key) {
398
                if (is_numeric($key)) {
399
                    $title = "{$key}: {$title}";
400
                }
401
            });
402
        }
403
        return array_combine(
404
            array_map(fn ($key) => "id::{$key}", array_keys($results)),
405
            $results
406
        );
407
    }
408
409
    protected function verifyAjaxRequest(): void
410
    {
411
        if (method_exists('Bricks\Ajax', 'verify_request')) { // @phpstan-ignore-line
412
            \Bricks\Ajax::verify_request('bricks-nonce-builder');
0 ignored issues
show
Bug introduced by
The type Bricks\Ajax was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
413
        } elseif (!check_ajax_referer('bricks-nonce-builder', 'nonce', false)) {
414
            wp_send_json_error('verify_nonce: "bricks-nonce-builder" is invalid.');
415
        }
416
    }
417
}
418