Passed
Push — master ( dca2fc...188ee9 )
by
unknown
20:49 queued 08:39
created

OnlyofficeSettingsFormBuilder::buildSettingsForm()   F

Complexity

Conditions 22
Paths 720

Size

Total Lines 106
Code Lines 65

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 22
eloc 65
nc 720
nop 1
dl 0
loc 106
rs 0.3888
c 2
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/**
3
 * (c) Copyright Ascensio System SIA 2025.
4
 *
5
 * Licensed under the Apache License, Version 2.0 (the "License");
6
 * You may not use this file except in compliance with the License.
7
 * You may obtain a copy of the License at
8
 *
9
 *     http://www.apache.org/licenses/LICENSE-2.0
10
 *
11
 * Unless required by applicable law or agreed to in writing, software
12
 * distributed under the License is distributed on an "AS IS" BASIS,
13
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
 * See the License for the specific language governing permissions and
15
 * limitations under the License.
16
 */
17
require_once __DIR__ . '/../../../main/inc/global.inc.php';
18
19
class OnlyofficeSettingsFormBuilder
20
{
21
    /**
22
     * Directory with layouts for banners/partials.
23
     */
24
    private const ONLYOFFICE_LAYOUT_DIR = '/Onlyoffice/layout/';
25
26
    /**
27
     * Build OnlyOffice plugin settings form.
28
     *
29
     * Adds:
30
     *  - "Connect to demo" checkbox
31
     *  - "Test connection" submit button (server-side check)
32
     *  - Quick test LINKS (healthcheck, API, preloader) opening in a new tab
33
     *
34
     * @param OnlyofficeAppsettings $settingsManager
35
     *
36
     * @return FormValidator
37
     */
38
    public static function buildSettingsForm(OnlyofficeAppsettings $settingsManager)
39
    {
40
        $plugin = $settingsManager->plugin;
41
42
        $plugin_info = $plugin->get_info();
43
        $form = $plugin_info['settings_form'];
44
45
        $demoData = $settingsManager->getDemoData();
46
        $demoAvailable = is_array($demoData) && array_key_exists('available', $demoData)
47
            ? (bool) $demoData['available']
48
            : false;
49
50
        $connectDemoCheckbox = $form->createElement(
51
            'checkbox',
52
            'connect_demo',
53
            '',
54
            $plugin->get_lang('connect_demo') ?: 'Connect to demo'
55
        );
56
57
        if (!$demoAvailable) {
58
            $message = $plugin->get_lang('demoPeriodIsOver') ?: 'Demo trial period is over.';
59
            $connectDemoCheckbox->setAttribute('disabled', 'disabled');
60
        } else {
61
            if ($settingsManager->useDemo()) {
62
                $message = $plugin->get_lang('demoUsingMessage') ?: 'Demo is currently active.';
63
                $connectDemoCheckbox->setChecked(true);
64
            } else {
65
                $message = $plugin->get_lang('demoPrevMessage') ?: 'You can enable a 30-day demo.';
66
            }
67
        }
68
        $demoServerMessageHtml = Display::return_message($message, 'info');
69
        $demoServerMessage = $form->createElement('html', $demoServerMessageHtml);
70
71
        $bannerTemplate = self::buildTemplate('get_docs_cloud_banner', [
72
            'docs_cloud_link'    => $settingsManager->getLinkToDocs(),
73
            'banner_title'       => $plugin->get_lang('DocsCloudBannerTitle') ?: 'ONLYOFFICE Docs Cloud',
74
            'banner_main_text'   => $plugin->get_lang('DocsCloudBannerMain') ?: 'Try Docs Cloud for production use.',
75
            'banner_button_text' => $plugin->get_lang('DocsCloudBannerButton') ?: 'Learn more',
76
        ]);
77
        $banner = $form->createElement('html', $bannerTemplate);
78
79
        $testBtn = $form->createElement('submit', 'test_connection', $plugin->get_lang('TestConnection') ?: 'Test connection');
80
81
        $docUrl = $settingsManager->getDocumentServerUrl();
82
        $docAvailable = $settingsManager->useDemo() || !empty($docUrl);
83
        if ($docAvailable) {
84
            $healthUrl    = $settingsManager->getDocumentServerHealthcheckUrl();
85
            $apiUrl       = $settingsManager->getDocumentServerApiUrl();
86
            $preloaderUrl = $settingsManager->getDocumentServerPreloaderUrl();
87
88
            $quickLinksHtml = '
89
            <div class="panel panel-default" style="margin-top:8px;">
90
              <div class="panel-heading"><strong>Quick checks</strong></div>
91
              <div class="panel-body">
92
                <ul style="margin-bottom:8px;">
93
                  <li><a href="'.Security::remove_XSS($healthUrl).'" target="_blank" rel="noopener">Healthcheck</a></li>
94
                  <li><a href="'.Security::remove_XSS($apiUrl).'" target="_blank" rel="noopener">API (api.js)</a></li>
95
                  <li><a href="'.Security::remove_XSS($preloaderUrl).'" target="_blank" rel="noopener">Preloader</a></li>
96
                </ul>
97
                <p style="margin:0;">
98
                  <a href="#" onclick="var b=document.querySelector(\'button[name=test_connection],input[name=test_connection]\'); if(b){b.click();} return false;">
99
                    Run server-side test now
100
                  </a>
101
                </p>
102
              </div>
103
            </div>';
104
        } else {
105
            $quickLinksHtml = '
106
            <div class="panel panel-default" style="margin-top:8px;">
107
              <div class="panel-heading"><strong>Quick checks</strong></div>
108
              <div class="panel-body">
109
                <p>No Document Server URL configured and demo is disabled. Enable <em>Connect to demo</em> or set a server URL.</p>
110
              </div>
111
            </div>';
112
        }
113
        $quickLinksBlock = $form->createElement('html', $quickLinksHtml);
114
115
        $anchorNames = ['submit_button', 'submit', 'save', 'save_settings'];
116
        $anchor = null;
117
        foreach ($anchorNames as $name) {
118
            if (method_exists($form, 'getElement') && $form->getElement($name)) {
119
                $anchor = $name;
120
                break;
121
            }
122
        }
123
124
        if ($anchor && method_exists($form, 'insertElementBefore')) {
125
            $form->insertElementBefore($banner, $anchor);
126
            $form->insertElementBefore($demoServerMessage, $anchor);
127
            $form->insertElementBefore($connectDemoCheckbox, $anchor);
128
            $form->insertElementBefore($testBtn, $anchor);
129
            $form->insertElementBefore($quickLinksBlock, $anchor);
130
        } else {
131
            if (method_exists($form, 'addElement')) {
132
                $form->addElement('html', $banner->toHtml());
133
                $form->addElement('html', $demoServerMessage->toHtml());
134
                $form->addElement($connectDemoCheckbox);
135
                $form->addElement($testBtn);
136
                $form->addElement('html', $quickLinksBlock->toHtml());
137
            }
138
            if (function_exists('error_log')) {
139
                error_log('[OnlyOffice] settings_form: submit anchor not found; appended elements at end');
140
            }
141
        }
142
143
        return $form;
144
    }
145
146
    /**
147
     * Validate OnlyOffice plugin settings form and persist values.
148
     *
149
     * @param OnlyofficeAppsettings $settingsManager
150
     *
151
     * @return OnlyofficePlugin
152
     */
153
    public static function validateSettingsForm(OnlyofficeAppsettings $settingsManager)
154
    {
155
        $plugin = $settingsManager->plugin;
156
        $plugin_info = $plugin->get_info();
157
        $form = $plugin_info['settings_form'];
158
159
        // Read submitted values from the form.
160
        $result = $form->getSubmitValues();
161
        unset($result['submit_button']);
162
163
        // Make posted values available as runtime overrides for SettingsManager.
164
        $settingsManager->newSettings = $result;
165
166
        // Detect "Test connection" (non-destructive).
167
        $testing = isset($result['test_connection']);
168
169
        // Checkbox may be absent in POST when unchecked.
170
        $connectDemo = (bool) ($result['connect_demo'] ?? false);
171
172
        if ($testing) {
173
            $outcome = self::runSelfTest($settingsManager);
174
175
            if ($outcome['ok']) {
176
                Display::addFlash(
177
                    Display::return_message('[OnlyOffice] Connection test passed: '.$outcome['message'], 'confirmation')
178
                );
179
            } else {
180
                Display::addFlash(
181
                    Display::return_message('[OnlyOffice] Connection test failed: '.$outcome['message'], 'error')
182
                );
183
            }
184
185
            header('Location: '.$plugin->getConfigLink());
186
            exit;
187
        }
188
189
        // Persisted flow: toggle demo with vendor trial rules.
190
        if (!$settingsManager->selectDemo($connectDemo)) {
191
            $errorMsg = $plugin->get_lang('demoPeriodIsOver');
192
            self::displayError($errorMsg, $plugin->getConfigLink());
193
        }
194
195
        // Validate connectivity if a custom server is set and demo is not used.
196
        $docUrl = $settingsManager->getDocumentServerUrl();
197
        if (!empty($docUrl) && !$connectDemo) {
198
            $httpClient = new OnlyofficeHttpClient();
199
            $jwtManager = new OnlyofficeJwtManager($settingsManager);
200
            $requestService = new OnlyofficeAppRequests($settingsManager, $httpClient, $jwtManager);
201
202
            // checkDocServiceUrl() returns [error|null, version|null]
203
            [$error, $version] = $requestService->checkDocServiceUrl();
204
            if (!empty($error)) {
205
                $versionStr = !empty($version) ? '(Version '.$version.')' : '';
206
                $errorMsg = $plugin->get_lang('connectionError').'('.$error.')'.$versionStr;
207
                self::displayError($errorMsg);
208
            }
209
        }
210
211
        return $plugin;
212
    }
213
214
    /**
215
     * Run a minimal self-test using the vendor SettingsManager + existing request service.
216
     *
217
     * @param OnlyofficeAppsettings $settings
218
     *
219
     * @return array{ok: bool, message: string}
220
     */
221
    private static function runSelfTest(OnlyofficeAppsettings $settings): array
222
    {
223
        try {
224
            $docUrl = $settings->getDocumentServerUrl();
225
            if (empty($docUrl) && !$settings->useDemo()) {
226
                return [
227
                    'ok' => false,
228
                    'message' => 'No Document Server URL set and demo mode is disabled.',
229
                ];
230
            }
231
232
            $httpClient = new OnlyofficeHttpClient();
233
            $jwtManager = new OnlyofficeJwtManager($settings);
234
            $requestService = new OnlyofficeAppRequests($settings, $httpClient, $jwtManager);
235
236
            [$error, $version] = $requestService->checkDocServiceUrl();
237
238
            if (!empty($error)) {
239
                $versionStr = !empty($version) ? ' (Version '.$version.')' : '';
240
                return [
241
                    'ok' => false,
242
                    'message' => 'checkDocServiceUrl() returned error: '.$error.$versionStr,
243
                ];
244
            }
245
246
            $healthUrl = method_exists($settings, 'getDocumentServerHealthcheckUrl')
247
                ? $settings->getDocumentServerHealthcheckUrl()
248
                : null;
249
250
            $versionStr = !empty($version) ? 'Version '.$version : 'Version unknown';
251
            $extra = $healthUrl ? ' | Healthcheck: '.$healthUrl : '';
252
253
            return [
254
                'ok' => true,
255
                'message' => 'Document Server is reachable. '.$versionStr.$extra,
256
            ];
257
        } catch (\Throwable $e) {
258
            return [
259
                'ok' => false,
260
                'message' => 'Unexpected exception: '.$e->getMessage(),
261
            ];
262
        }
263
    }
264
265
    /**
266
     * Build an HTML template chunk from plugin templates directory.
267
     *
268
     * @param string $templateName
269
     * @param array  $params
270
     *
271
     * @return string
272
     */
273
    private static function buildTemplate($templateName, $params = [])
274
    {
275
        // Template is used outside of full-page context; disable auto-wrapping.
276
        $tpl = new Template('', false, false, false, false, false, false);
277
        if (!empty($params)) {
278
            foreach ($params as $key => $param) {
279
                $tpl->assign($key, $param);
280
            }
281
        }
282
283
        return $tpl->fetch(self::ONLYOFFICE_LAYOUT_DIR.$templateName.'.tpl');
284
    }
285
286
    /**
287
     * Show an error flash and optionally redirect.
288
     *
289
     * @param string      $errorMessage
290
     * @param string|null $location
291
     *
292
     * @return void
293
     */
294
    private static function displayError($errorMessage, $location = null)
295
    {
296
        Display::addFlash(
297
            Display::return_message($errorMessage, 'error')
298
        );
299
        if (null !== $location) {
300
            header('Location: '.$location);
301
            exit;
302
        }
303
    }
304
}
305