SettingsController   A
last analyzed

Complexity

Total Complexity 28

Size/Duplication

Total Lines 148
Duplicated Lines 0 %

Test Coverage

Coverage 11.22%

Importance

Changes 2
Bugs 2 Features 0
Metric Value
wmc 28
eloc 89
c 2
b 2
f 0
dl 0
loc 148
rs 10
ccs 11
cts 98
cp 0.1122

7 Methods

Rating   Name   Duplication   Size   Complexity  
A registerSettings() 0 6 1
A sanitizeGeneral() 0 18 4
A sanitizeForms() 0 10 2
A sanitizeAll() 0 6 1
A sanitizeSettingsCallback() 0 21 3
A hasMultilingualIntegration() 0 21 4
C sanitizeStrings() 0 43 13
1
<?php
2
3
namespace GeminiLabs\SiteReviews\Controllers;
4
5
use GeminiLabs\SiteReviews\Addons\Updater;
6
use GeminiLabs\SiteReviews\Database\OptionManager;
7
use GeminiLabs\SiteReviews\Exceptions\LicenseException;
8
use GeminiLabs\SiteReviews\Helpers\Arr;
9
use GeminiLabs\SiteReviews\Modules\Multilingual;
10
use GeminiLabs\SiteReviews\Modules\Notice;
11
use GeminiLabs\SiteReviews\Modules\Sanitizer;
12
13
class SettingsController extends AbstractController
14
{
15
    /**
16
     * @action admin_init
17
     */
18 8
    public function registerSettings(): void
19
    {
20 8
        register_setting(glsr()->id, OptionManager::databaseKey(), [
21 8
            'default' => glsr()->defaults(),
22 8
            'sanitize_callback' => [$this, 'sanitizeSettingsCallback'],
23 8
            'type' => 'array',
24 8
        ]);
25
    }
26
27
    /**
28
     * @param mixed $input
29
     *
30
     * @see registerSettings
31
     */
32 8
    public function sanitizeSettingsCallback($input): array
33
    {
34 8
        OptionManager::flushSettingsCache(); // remove settings from object cache before updating
35 8
        $input = Arr::consolidate($input);
36 8
        if (!array_key_exists('settings', $input)) {
37
            return $input;
38
        }
39
        $options = array_replace_recursive(glsr(OptionManager::class)->all(), [
40
            'settings' => $input['settings'],
41
        ]);
42
        $options = $this->sanitizeForms($options, $input);
43
        $options = $this->sanitizeGeneral($options, $input);
44
        $options = $this->sanitizeStrings($options, $input);
45
        $options = $this->sanitizeAll($options);
46
        $options = glsr()->filterArray('settings/sanitize', $options, $input);
47
        glsr()->action('settings/updated', $options, $input);
48
        if (filter_input(INPUT_POST, 'option_page') === glsr()->id) {
49
            glsr(Notice::class)->addSuccess(_x('Settings updated.', 'admin-text', 'site-reviews'));
50
        }
51 8
        glsr(Notice::class)->store(); // store the notices before the page reloads
52
        return $options;
53
    }
54
55
    protected function sanitizeAll(array $options): array
56
    {
57
        $values = Arr::flatten($options);
58
        $sanitizers = wp_list_pluck(glsr()->settings(), 'sanitizer');
59
        $options = (new Sanitizer($values, $sanitizers))->run();
60
        return Arr::unflatten($options);
61
    }
62
63
    protected function sanitizeForms(array $options, array $input): array
64
    {
65
        $key = 'settings.forms';
66
        $inputForm = Arr::get($input, $key);
67
        $multiFields = ['limit_assignments', 'required'];
68
        foreach ($multiFields as $name) {
69
            $defaultValue = Arr::get($inputForm, $name, []);
70
            $options = Arr::set($options, "{$key}.{$name}", $defaultValue);
71
        }
72
        return $options;
73
    }
74
75
    protected function sanitizeGeneral(array $options, array $input): array
76
    {
77
        $key = 'settings.general';
78
        $inputForm = Arr::get($input, $key);
79
        if (!$this->hasMultilingualIntegration(Arr::getAs('string', $inputForm, 'multilingual'))) {
80
            $options = Arr::set($options, $key.'.multilingual', '');
81
        }
82
        if ('' === trim(Arr::get($inputForm, 'notification_message'))) {
83
            $defaultValue = Arr::get(glsr()->defaults(), $key.'.notification_message');
84
            $options = Arr::set($options, $key.'.notification_message', $defaultValue);
85
        }
86
        if ('' === trim(Arr::get($inputForm, 'request_verification_message'))) {
87
            $defaultValue = Arr::get(glsr()->defaults(), $key.'.request_verification_message');
88
            $options = Arr::set($options, $key.'.request_verification_message', $defaultValue);
89
        }
90
        $defaultValue = Arr::get($inputForm, 'notifications', []);
91
        $options = Arr::set($options, $key.'.notifications', $defaultValue);
92
        return $options;
93
    }
94
95
    protected function sanitizeStrings(array $options, array $input): array
96
    {
97
        $strings = Arr::consolidate($input['settings']['strings'] ?? []);
98
        if (empty($strings)) {
99
            return $options;
100
        }
101
        $allowedTags = [
102
            'a' => ['class' => [], 'href' => [], 'target' => []],
103
            'span' => ['class' => []],
104
        ];
105
        $errors = [
106
            '%d' => [],
107
            '%s' => [],
108
        ];
109
        $sanitizedStrings = [];
110
        foreach ($strings as $string) {
111
            if (!isset($string['s1'])) {
112
                continue; // all entries should have this key
113
            }
114
            $string['s2'] = wp_kses($string['s2'] ?? '', $allowedTags);
115
            if (isset($string['p1'])) {
116
                $string['p2'] = wp_kses($string['p2'] ?? '', $allowedTags);
117
            }
118
            foreach ($errors as $needle => $values) {
119
                if (str_contains($string['s1'], $needle) && !str_contains($string['s2'], $needle)) {
120
                    $errors[$needle][] = $string['s2'];
121
                }
122
                if (isset($string['p1']) && str_contains($string['p1'], $needle) && !str_contains($string['p2'], $needle)) {
123
                    $errors[$needle][] = $string['p2'];
124
                }
125
            }
126
            $sanitizedStrings[] = $string;
127
        }
128
        foreach ($errors as $needle => $values) {
129
            if (!empty($values)) {
130
                glsr(Notice::class)->addError(
131
                    sprintf(_x('You forgot to include the %s placeholder tags in your Custom Text.', 'admin-text', 'site-reviews'), "<code>$needle</code>"),
132
                    $values
133
                );
134
            }
135
        }
136
        $options['settings']['strings'] = $sanitizedStrings;
137
        return $options;
138
    }
139
140
    protected function hasMultilingualIntegration(string $option): bool
141
    {
142
        $integration = glsr(Multilingual::class)->getIntegration($option);
143
        if (!$integration) {
144
            return false;
145
        }
146
        if (!$integration->isActive()) {
147
            glsr(Notice::class)->addError(sprintf(
148
                _x('Please install/activate the %s plugin to enable the integration.', 'admin-text', 'site-reviews'),
149
                $integration->pluginName
150
            ));
151
            return false;
152
        } elseif (!$integration->isSupported()) {
153
            glsr(Notice::class)->addError(sprintf(
154
                _x('Please update the %s plugin to v%s or greater to enable the integration.', 'admin-text', 'site-reviews'),
155
                $integration->pluginName,
156
                $integration->supportedVersion
157
            ));
158
            return false;
159
        }
160
        return true;
161
    }
162
}
163