Test Failed
Push — develop ( 006c9f...4b441a )
by Paul
13:29
created

Controller   C

Complexity

Total Complexity 57

Size/Duplication

Total Lines 402
Duplicated Lines 0 %

Importance

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

17 Methods

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

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