Passed
Push — develop ( 0c90fe...52144d )
by Nikolay
04:57
created

BaseController::customWikiLinks()   B

Complexity

Conditions 11
Paths 58

Size

Total Lines 47
Code Lines 33

Duplication

Lines 0
Ratio 0 %

Importance

Changes 3
Bugs 0 Features 0
Metric Value
eloc 33
c 3
b 0
f 0
dl 0
loc 47
rs 7.3166
cc 11
nc 58
nop 0

How to fix   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
 * MikoPBX - free phone system for small business
4
 * Copyright (C) 2017-2020 Alexey Portnov and Nikolay Beketov
5
 *
6
 * This program is free software: you can redistribute it and/or modify
7
 * it under the terms of the GNU General Public License as published by
8
 * the Free Software Foundation; either version 3 of the License, or
9
 * (at your option) any later version.
10
 *
11
 * This program is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 * GNU General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU General Public License along with this program.
17
 * If not, see <https://www.gnu.org/licenses/>.
18
 */
19
20
namespace MikoPBX\AdminCabinet\Controllers;
21
22
use Exception;
23
use GuzzleHttp;
24
use MikoPBX\Common\Models\{PbxExtensionModules, PbxSettings};
25
use MikoPBX\Common\Providers\ManagedCacheProvider;
26
use MikoPBX\Core\System\Util;
27
use Phalcon\Cache\Adapter\Redis;
28
use Phalcon\Http\ResponseInterface;
29
use Phalcon\Mvc\{Controller, View};
30
use Phalcon\Tag;
31
use Phalcon\Text;
32
use Sentry\SentrySdk;
33
34
/**
35
 * @property \Phalcon\Session\Manager session
36
 * @property \MikoPBX\Common\Providers\TranslationProvider translation
37
 * @property string language
38
 * @property bool showModuleStatusToggle if false it hides status toggle on current UI page
39
 * @property \MikoPBX\AdminCabinet\Library\Elements elements
40
 * @property \Phalcon\Flash\Session flash
41
 * @property \Phalcon\Tag tag
42
 * @property \Phalcon\Config\Adapter\Json config
43
 * @property \Phalcon\Logger loggerAuth
44
 */
45
class BaseController extends Controller
46
{
47
    protected string $actionName;
48
    protected string $controllerName;
49
    protected string $controllerNameUnCamelized;
50
51
    public const WIKI_LINKS = '/var/etc/wiki-links-LANG.json';
52
53
    /**
54
     * Initializes base class
55
     */
56
    public function initialize(): void
57
    {
58
        $this->actionName = $this->dispatcher->getActionName();
59
        $this->controllerName = Text::camelize($this->dispatcher->getControllerName(), '_');
60
        $this->controllerNameUnCamelized = Text::uncamelize($this->controllerName, '-');
61
62
        if ($this->request->isAjax() === false) {
63
            $this->prepareView();
64
        }
65
    }
66
67
    /**
68
     * Customization of links to the wiki documentation for modules.
69
     * @param array $links
70
     * @return void
71
     */
72
    private function customModuleWikiLinks(array $links): void
73
    {
74
        $this->view->urlToWiki = $links[$this->language][$this->view->urlToWiki] ?? $this->view->urlToWiki;
75
        $this->view->urlToSupport = $links[$this->language][$this->view->urlToSupport] ?? $this->view->urlToSupport;
76
    }
77
78
    /**
79
     * Customization of links to the wiki documentation.
80
     * @return void
81
     */
82
    private function customWikiLinks(): void
83
    {
84
        if (!$this->session->has(SessionController::SESSION_ID)) {
85
            return;
86
        }
87
        /** @var Redis $cache */
88
        $cache = $this->di->getShared(ManagedCacheProvider::SERVICE_NAME);
89
        $links = $cache->get('WIKI_LINKS');
90
91
        if ($links === null) {
92
            $ttl = 86400;
93
            $client = new GuzzleHttp\Client();
94
            $url = 'https://raw.githubusercontent.com/mikopbx/Core/master/src/Common/WikiLinks/' . $this->language . '.json';
95
            try {
96
                $res = $client->request('GET', $url, ['timeout', 1, 'connect_timeout' => 1, 'read_timeout' => 1]);
97
            } catch (Exception $e) {
98
                $res = null;
99
                $ttl = 3600;
100
                if ($e->getCode() !== 404) {
101
                    Util::sysLogMsg('BaseController', 'Error access to raw.githubusercontent.com');
102
                }
103
            }
104
            $links = null;
105
            if ($res && $res->getStatusCode() === 200) {
106
                try {
107
                    $links = json_decode($res->getBody(), true, 512, JSON_THROW_ON_ERROR);
108
                } catch (Exception $e) {
109
                    $ttl = 3600;
110
                }
111
            }
112
            if (!is_array($links)) {
113
                $links = [];
114
            }
115
            $cache->set('WIKI_LINKS', $links, $ttl);
116
        }
117
118
        $filename = str_replace('LANG', $this->language, self::WIKI_LINKS);
119
        if (file_exists($filename)) {
120
            try {
121
                $local_links = json_decode(file_get_contents($filename), true, 512, JSON_THROW_ON_ERROR);
122
                $links = $local_links;
123
            } catch (\Exception $e) {
124
                Util::sysLogMsg('BaseController', $e->getMessage());
125
            }
126
        }
127
        $this->view->urlToWiki = $links[$this->view->urlToWiki] ?? $this->view->urlToWiki;
128
        $this->view->urlToSupport = $links[$this->view->urlToSupport] ?? $this->view->urlToSupport;
129
    }
130
131
    /**
132
     * Prepares some environments to every controller and view
133
     *
134
     */
135
    protected function prepareView(): void
136
    {
137
        date_default_timezone_set(PbxSettings::getValueByKey('PBXTimezone'));
138
        $this->view->PBXVersion = PbxSettings::getValueByKey('PBXVersion');
139
        $this->view->MetaTegHeadDescription=$this->translation->_('MetategHeadDescription');
140
        if ($this->session->has(SessionController::SESSION_ID)) {
141
            $this->view->PBXLicense = PbxSettings::getValueByKey('PBXLicense');
142
        } else {
143
            $this->view->PBXLicense = '';
144
        }
145
        // Module and PBX version caching for proper PBX operation when installing modules.
146
        $versionHash = $this->getVersionsHash();
147
        $this->session->set('versionHash', $versionHash);
148
149
        $this->view->WebAdminLanguage = PbxSettings::getValueByKey('WebAdminLanguage');
150
        $this->view->AvailableLanguages = json_encode($this->elements->getAvailableWebAdminLanguages());
151
        $this->view->submitMode = $this->session->get('SubmitMode')??'SaveSettings';
152
153
        // Allow anonymous statistics collection for JS code
154
        if (PbxSettings::getValueByKey('SendMetrics') === '1') {
155
            touch('/tmp/sendmetrics');
156
            $this->view->lastSentryEventId = SentrySdk::getCurrentHub()->getLastEventId();
157
        } else {
158
            if (file_exists('/tmp/sendmetrics')) {
159
                unlink('/tmp/sendmetrics');
160
            }
161
            $this->view->lastSentryEventId = null;
162
        }
163
164
        $title = 'MikoPBX';
165
        switch ($this->actionName) {
166
            case'index':
167
            case'delete':
168
            case'save':
169
            case'modify':
170
            case'*** WITHOUT ACTION ***':
171
                $title .= '|' . $this->translation->_("Breadcrumb{$this->controllerName}");
172
                break;
173
            default:
174
                $title .= '|' . $this->translation->_("Breadcrumb{$this->controllerName}{$this->actionName}");
175
        }
176
        Tag::setTitle($title);
177
        $this->view->t = $this->translation;
178
        $this->view->debugMode = $this->config->path('adminApplication.debugMode');
179
        $this->view->urlToLogo = $this->url->get('assets/img/logo-mikopbx.svg');
180
        $this->view->urlToWiki = "https://wiki.mikopbx.com/{$this->controllerNameUnCamelized}";
181
        if ($this->language === 'ru') {
182
            $this->view->urlToSupport = 'https://www.mikopbx.ru/support/?fromPBX=true';
183
        } else {
184
            $this->view->urlToSupport = 'https://www.mikopbx.com/support/?fromPBX=true';
185
        }
186
        $this->view->urlToController = $this->url->get($this->controllerNameUnCamelized);
187
        $this->view->represent = '';
188
        $this->view->cacheName = "{$this->controllerName}{$this->actionName}{$this->language}{$versionHash}";
189
190
        $isExternalModuleController = stripos($this->dispatcher->getNamespaceName(), '\\Module') === 0;
191
        // We can disable module status toggle from module controller, using the showModuleStatusToggle variable
192
        if (property_exists($this, 'showModuleStatusToggle')) {
193
            $this->view->setVar('showModuleStatusToggle', $this->showModuleStatusToggle);
194
        } else {
195
            $this->view->setVar('showModuleStatusToggle', true);
196
        }
197
198
        // Add module variables into view
199
        if ($isExternalModuleController) {
200
            $moduleLinks = [];
201
            /** @var PbxExtensionModules $module */
202
            $module = PbxExtensionModules::findFirstByUniqid($this->controllerName);
203
            if ($module === null) {
204
                $module = new PbxExtensionModules();
205
                $module->disabled = '1';
206
                $module->name = 'Unknown module';
207
            } else {
208
                try {
209
                    $links = json_decode($module->wiki_links, true, 512, JSON_THROW_ON_ERROR);
0 ignored issues
show
Bug introduced by
It seems like $module->wiki_links can also be of type null; however, parameter $json of json_decode() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

209
                    $links = json_decode(/** @scrutinizer ignore-type */ $module->wiki_links, true, 512, JSON_THROW_ON_ERROR);
Loading history...
210
                    if (is_array($links)) {
211
                        $moduleLinks = $links;
212
                    }
213
                } catch (\JsonException $e) {
214
                    Util::sysLogMsg(__CLASS__, $e->getMessage());
215
                }
216
            }
217
            $this->view->setVar('module', $module);
218
            $this->customModuleWikiLinks($moduleLinks);
219
220
            // If it is module we have to use another volt template
221
            $this->view->setTemplateAfter('modules');
222
        } else {
223
            $this->customWikiLinks();
224
            $this->view->setTemplateAfter('main');
225
        }
226
227
    }
228
229
    /**
230
     * Generates common hash sum for correct combine CSS and JS according to installed modules
231
     *
232
     */
233
    private function getVersionsHash(): string
234
    {
235
        $result = PbxSettings::getValueByKey('PBXVersion');
236
        $modulesVersions = PbxExtensionModules::getModulesArray();
237
        foreach ($modulesVersions as $module) {
238
            $result .= "{$module['id']}{$module['version']}";
239
        }
240
        return md5($result);
241
    }
242
243
    /**
244
     * Changes the AJAX response by expected format
245
     *
246
     * @return \Phalcon\Http\ResponseInterface
247
     */
248
    public function afterExecuteRoute():ResponseInterface
249
    {
250
        if ($this->request->isAjax() === true) {
251
            $this->view->setRenderLevel(View::LEVEL_NO_RENDER);
252
            $this->response->setContentType('application/json', 'UTF-8');
253
            $data = $this->view->getParamsToView();
254
255
            /* Set global params if is not set in controller/action */
256
            if (is_array($data) && isset($data['raw_response'])) {
257
                $result = $data['raw_response'];
258
            } elseif (is_array($data)) {
259
                $data['success'] = array_key_exists('success', $data) ? $data['success'] : true;
260
                $data['reload'] = array_key_exists('reload', $data) ? $data['reload'] : false;
261
                $data['message'] = $data['message'] ?? $this->flash->getMessages();
262
263
                // Let's add information about the last error to display a dialog window for the user.
264
                if (file_exists('/tmp/sendmetrics')) {
265
                    $data['lastSentryEventId'] = SentrySdk::getCurrentHub()->getLastEventId();
266
                }
267
                $result = json_encode($data);
268
            } else {
269
                $result = '';
270
            }
271
272
            $this->response->setContent($result);
273
        }
274
275
        return $this->response->send();
276
    }
277
278
    /**
279
     * Callback before execute any route
280
     */
281
    public function beforeExecuteRoute(): void
282
    {
283
        if ($this->request->isPost()) {
284
            $data = $this->request->getPost('submitMode');
285
            if (!empty($data)) {
286
                $this->session->set('SubmitMode', $data);
287
            }
288
        }
289
    }
290
291
    /**
292
     * Change page without reload browser page
293
     *
294
     * @param string $uri
295
     */
296
    protected function forward(string $uri): void
297
    {
298
        $uriParts = explode('/', $uri);
299
        $params = array_slice($uriParts, 2);
300
301
        $this->dispatcher->forward(
302
            [
303
                'controller' => $uriParts[0],
304
                'action' => $uriParts[1],
305
                'params' => $params,
306
            ]
307
308
        );
309
    }
310
311
    /**
312
     * Removes all dangerous symbols from CallerID
313
     * @param string $callerId
314
     *
315
     * @return string
316
     */
317
    protected function sanitizeCallerId(string $callerId): string
318
    {
319
        return preg_replace('/[^a-zA-Zа-яА-Я0-9 ]/ui', '', $callerId);
320
    }
321
322
    /**
323
     * Sorts array by priority field
324
     *
325
     * @param $a
326
     * @param $b
327
     *
328
     * @return int|null
329
     */
330
    protected function sortArrayByPriority($a, $b): ?int
331
    {
332
        if (is_array($a)) {
333
            $a = (int)$a['priority'];
334
        } else {
335
            $a = (int)$a->priority;
336
        }
337
338
        if (is_array($b)) {
339
            $b = (int)$b['priority'];
340
        } else {
341
            $b = (int)$b->priority;
342
        }
343
344
        if ($a === $b) {
345
            return 0;
346
        } else {
347
            return ($a < $b) ? -1 : 1;
348
        }
349
    }
350
}
351