ViewManager   F
last analyzed

Complexity

Total Complexity 60

Size/Duplication

Total Lines 460
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 163
c 1
b 0
f 0
dl 0
loc 460
rs 3.6
wmc 60

18 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 42 4
A maybeRenderIframes() 0 19 3
A getControllerClassName() 0 3 1
A printHelp() 0 12 3
A isThemeAvailable() 0 3 1
A getContainer() 0 3 1
A setReloadBrowser() 0 5 1
C getTheme() 0 38 15
A setSessionTheme() 0 4 2
A getCookieTheme() 0 5 2
A getSessionTheme() 0 5 2
A setForm() 0 30 4
A getHelpLink() 0 7 1
B icon() 0 33 7
A getRequestTheme() 0 5 2
A setCookieTheme() 0 4 2
A getReloadBrowser() 0 3 1
B getThemeFolders() 0 33 8

How to fix   Complexity   

Complex Class

Complex classes like ViewManager 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 ViewManager, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
/**
4
 * PHPPgAdmin 6.1.3
5
 */
6
7
namespace PHPPgAdmin;
8
9
/**
10
 * @file
11
 * Class to hold various commonly used functions
12
 *
13
 * Id: Misc.php,v 1.171 2008/03/17 21:35:48 ioguix Exp $
14
 */
15
16
/**
17
 * Class to hold various commonly used functions.
18
 *
19
 * Release: Misc.php,v 1.171 2008/03/17 21:35:48 ioguix Exp $
20
 */
21
class ViewManager extends \Slim\Views\Twig
22
{
23
    use \PHPPgAdmin\Traits\HelperTrait;
24
25
    /**
26
     * @var array
27
     */
28
    public $appLangFiles = [];
29
30
    /**
31
     * @var string
32
     */
33
    public $appName = '';
34
35
    /**
36
     * @var string
37
     */
38
    public $appVersion = '';
39
40
    /**
41
     * @var string
42
     */
43
    public $form = '';
44
45
    /**
46
     * @var string
47
     */
48
    public $href = '';
49
50
    /**
51
     * @var array
52
     */
53
    public $lang = [];
54
55
    /**
56
     * @var array
57
     */
58
    public $conf;
59
60
    /**
61
     * @var string
62
     * @psalm-suppress PropertyNotSetInConstructor
63
     */
64
    public $phpMinVer;
65
66
    /**
67
     * @var string
68
     * @psalm-suppress PropertyNotSetInConstructor
69
     */
70
    public $postgresqlMinVer;
71
72
    /**
73
     * @var \PHPPgAdmin\Misc
74
     */
75
    public $misc;
76
77
    /**
78
     * @var \PHPPgAdmin\ContainerUtils
79
     */
80
    protected $container;
81
82
    /**
83
     * Undocumented variable.
84
     *
85
     * @var array
86
     */
87
    private static $themeFolders = [];
88
89
    private $_connection;
0 ignored issues
show
introduced by
The private property $_connection is not used, and could be removed.
Loading history...
90
91
    /**
92
     * @var bool
93
     */
94
    private $_no_db_connection = false;
0 ignored issues
show
introduced by
The private property $_no_db_connection is not used, and could be removed.
Loading history...
95
96
    /**
97
     * @var bool
98
     */
99
    private $_reload_browser = false;
100
101
    private $_data;
0 ignored issues
show
introduced by
The private property $_data is not used, and could be removed.
Loading history...
102
103
    private $_database;
0 ignored issues
show
introduced by
The private property $_database is not used, and could be removed.
Loading history...
104
105
    /**
106
     * @var string
107
     */
108
    private $_server_id;
0 ignored issues
show
introduced by
The private property $_server_id is not used, and could be removed.
Loading history...
109
110
    private $_server_info;
0 ignored issues
show
introduced by
The private property $_server_info is not used, and could be removed.
Loading history...
111
112
    /**
113
     * @var string
114
     */
115
    private $_error_msg = '';
0 ignored issues
show
introduced by
The private property $_error_msg is not used, and could be removed.
Loading history...
116
117
    /**
118
     * Undocumented variable.
119
     *
120
     * @var self
121
     */
122
    private static $instance;
0 ignored issues
show
introduced by
The private property $instance is not used, and could be removed.
Loading history...
123
124
    /**
125
     * @param mixed                      $path
126
     * @param mixed                      $settings
127
     * @param \PHPPgAdmin\ContainerUtils $c
128
     */
129
    public function __construct($path, $settings, \PHPPgAdmin\ContainerUtils $c)
130
    {
131
        $this->lang = $c->get('lang');
132
        $this->conf = $c->get('conf');
133
        $this->misc = $c->get('misc');
134
        parent::__construct($path, $settings);
135
        $this->container = $c;
136
        $environment = $c->get('environment');
137
        $base_script_trailing_str = \mb_substr($environment['SCRIPT_NAME'], 1);
138
        $request_basepath = $c['request']->getUri()->getBasePath();
139
        // Instantiate and add Slim specific extension
140
        $basePath = \rtrim(\str_ireplace($base_script_trailing_str, '', $request_basepath), '/');
141
142
        $this->addExtension(new \Slim\Views\TwigExtension($c['router'], $basePath));
143
144
        $this->offsetSet('subfolder', \containerInstance()->subFolder);
145
        $this->offsetSet('theme', $this->misc->getConf('theme'));
146
        $this->offsetSet('Favicon', $this->icon('Favicon'));
147
        $this->offsetSet('Introduction', $this->icon('Introduction'));
148
        $this->offsetSet('lang', $this->lang);
149
150
        $this->offsetSet('applangdir', $this->lang['applangdir']);
151
152
        $this->offsetSet('appName', $c->get('settings')['appName']);
153
154
        $_theme = $this->getTheme($this->conf, $this->misc->getServerInfo());
155
156
        // If a theme comes in the request, overwrite whatever theme was set to cookie and settion store
157
        if ($_request_theme = $this->getRequestTheme()) {
158
            $this->setCookieTheme($_request_theme);
159
            $this->setSessionTheme($_request_theme);
160
            $_theme = $_request_theme;
161
        }
162
163
        if (!$this->getSessionTheme() || !$this->getCookieTheme()) {
164
            // If there's no session theme, or cookie theme,
165
            // store the latest one we determined from request, session,cookie, conf or default
166
            /* save the selected theme in cookie for a year */
167
            \setcookie('ppaTheme', $_theme, \time() + 31536000, '/');
168
            $_SESSION['ppaTheme'] = $_theme;
169
        }
170
        $this->misc->setConf('theme', $_theme);
171
    }
172
173
    /**
174
     * Internally sets the reload browser property.
175
     *
176
     * @param bool $flag sets internal $_reload_browser var which will be passed to the footer methods
177
     *
178
     * @return \PHPPgAdmin\ViewManager this class instance
179
     */
180
    public function setReloadBrowser($flag): self
181
    {
182
        $this->_reload_browser = (bool) $flag;
183
184
        return $this;
185
    }
186
187
    /**
188
     * @return bool
189
     */
190
    public function getReloadBrowser(): bool
191
    {
192
        return $this->_reload_browser;
193
    }
194
195
    public function maybeRenderIframes(\Slim\Http\Response $response, string $subject, string $query_string): \Slim\Http\Response
196
    {
197
        $c = $this->getContainer();
198
199
        $in_test = $this->offsetGet('in_test');
200
201
        if ('1' === $in_test) {
202
            $className = self::getControllerClassName($subject);
203
            $controller = new $className($c);
204
205
            return $controller->render();
206
        }
207
208
        $viewVars = [
209
            'url' => '/src/views/' . $subject . ($query_string ? '?' . $query_string : ''),
210
            'headertemplate' => 'header.twig',
211
        ];
212
213
        return $this->render($response, 'iframe_view.twig', $viewVars);
214
    }
215
216
    /**
217
     * Gets the theme from
218
     * 1. The $_REQUEST global (when it's chosen from start screen)
219
     * 2. Server specific config theme 3.- $_SESSION global (subsequent requests after 1.) 4.- $_COOKIE global (mostly
220
     *    fallback for $_SESSION after 1.- and 3.-) 5.- theme as set in config 6.- 'default' theme.
221
     *
222
     * @param array      $conf         The conf
223
     * @param null|mixed $_server_info
224
     *
225
     * @return string the theme
226
     */
227
    public function getTheme(array $conf, $_server_info = null)
228
    {
229
        $_theme = 'default';
230
        // List of themes
231
        $themefolders = $this->getThemeFolders();
232
233
        // Check if theme is in $_REQUEST, $_SESSION or $_COOKIE
234
        // 1.- First priority: $_REQUEST, this happens when you use the selector
235
        if (\array_key_exists('theme', $_REQUEST) &&
236
            \array_key_exists($_REQUEST['theme'], $themefolders)
237
        ) {
238
            $_theme = $_REQUEST['theme'];
239
        } elseif ( // otherwise, see if there's a theme associated with this particular server
240
            null !== $_server_info &&
241
            \array_key_exists('theme', $_server_info) &&
242
            \is_string($_server_info['theme']) &&
243
            \array_key_exists($_COOKIE['ppaTheme'], $themefolders)
244
        ) {
245
            $_theme = $_server_info['theme'];
246
        } elseif (isset($_SESSION) && \array_key_exists('ppaTheme', $_SESSION) &&
247
            \array_key_exists($_SESSION['ppaTheme'], $themefolders)
248
        ) {
249
            // otherwise check $_SESSION
250
            $_theme = $_SESSION['ppaTheme'];
251
        } elseif (\array_key_exists('ppaTheme', $_COOKIE) &&
252
            \array_key_exists($_COOKIE['ppaTheme'], $themefolders)
253
        ) {
254
            // oterwise check $_COOKIE
255
            $_theme = $_COOKIE['ppaTheme'];
256
        } elseif ( // see if there's a valid theme set in config file
257
            \array_key_exists('theme', $conf) &&
258
            \is_string($conf['theme']) &&
259
            \array_key_exists($conf['theme'], $themefolders)
260
        ) {
261
            $_theme = $conf['theme'];
262
        }
263
264
        return $_theme;
265
    }
266
267
    /**
268
     * Sets the form tracking variable.
269
     */
270
    public function setForm(): string
271
    {
272
        $form = [];
273
274
        if ($this->container->server) {
275
            $form[] = \sprintf(
276
                '<input type="hidden" name="%s" value="%s" />',
277
                'server',
278
                \htmlspecialchars($this->container->server)
279
            );
280
        }
281
282
        if ($this->container->database) {
283
            $form[] = \sprintf(
284
                '<input type="hidden" name="%s" value="%s" />',
285
                'database',
286
                \htmlspecialchars($this->container->database)
287
            );
288
        }
289
290
        if ($this->container->schema) {
291
            $form[] = \sprintf(
292
                '<input type="hidden" name="%s" value="%s" />',
293
                'schema',
294
                \htmlspecialchars($this->container->schema)
295
            );
296
        }
297
        $this->form = \implode("\n", $form);
298
299
        return $this->form;
300
    }
301
302
    /**
303
     * Displays link to the context help.
304
     *
305
     * @param string $str      the string that the context help is related to (already escaped)
306
     * @param string $help     help section identifier
307
     * @param bool   $do_print true to echo, false to return
308
     *
309
     * @return string|void
310
     */
311
    public function printHelp($str, $help = null, $do_print = true)
312
    {
313
        if (null !== $help) {
314
            $helplink = $this->getHelpLink($help);
315
            $str .= '<a class="help" href="' . $helplink . '" title="' . $this->lang['strhelp'] . '" target="phppgadminhelp">';
316
            $str .= $this->lang['strhelpicon'] . '</a>';
317
        }
318
319
        if ($do_print) {
320
            echo $str;
321
        } else {
322
            return $str;
323
        }
324
    }
325
326
    /**
327
     * Gets the help link.
328
     *
329
     * @param string $help The help subject
330
     *
331
     * @return string the help link
332
     */
333
    public function getHelpLink($help)
334
    {
335
        return \htmlspecialchars(
336
            $this->container->getSubfolder('help?help=') .
337
                \urlencode($help) .
338
                '&server=' .
339
                \urlencode($this->misc->getServerId())
340
        );
341
    }
342
343
    /**
344
     * @param string $icon
345
     *
346
     * @return string
347
     */
348
    public function icon($icon = ''): string
349
    {
350
        $icon = (string) ($icon ?? '');
351
352
        $theme = $this->conf['theme'];
353
        $path = 'assets/images/themes';
354
        $default_icon = \sprintf('%s/%s/default/DisconnectedServer.png', \containerInstance()->subFolder, $path);
355
356
        if (\is_readable(\sprintf('%s/%s/%s/%s.png', \containerInstance()->BASE_PATH, $path, $theme, $icon))) {
357
            return \sprintf('%s/%s/%s/%s.png', \containerInstance()->subFolder, $path, $theme, $icon);
358
        }
359
360
        if (\is_readable(\sprintf('%s/%s/%s/%s.gif', \containerInstance()->BASE_PATH, $path, $theme, $icon))) {
361
            return \sprintf('%s/%s/%s/%s.gif', \containerInstance()->subFolder, $path, $theme, $icon);
362
        }
363
364
        if (\is_readable(\sprintf('%s/%s/%s/%s.ico', \containerInstance()->BASE_PATH, $path, $theme, $icon))) {
365
            return \sprintf('%s/%s/%s/%s.ico', \containerInstance()->subFolder, $path, $theme, $icon);
366
        }
367
368
        if (\is_readable(\sprintf('%s/%s/default/%s.png', \containerInstance()->BASE_PATH, $path, $icon))) {
369
            return \sprintf('%s/%s/default/%s.png', \containerInstance()->subFolder, $path, $icon);
370
        }
371
372
        if (\is_readable(\sprintf('%s/%s/default/%s.gif', \containerInstance()->BASE_PATH, $path, $icon))) {
373
            return \sprintf('%s/%s/default/%s.gif', \containerInstance()->subFolder, $path, $icon);
374
        }
375
376
        if (\is_readable(\sprintf('%s/%s/default/%s.ico', \containerInstance()->BASE_PATH, $path, $icon))) {
377
            return \sprintf('%s/%s/default/%s.ico', \containerInstance()->subFolder, $path, $icon);
378
        }
379
380
        return $default_icon;
381
    }
382
383
    private function getCookieTheme(): ?string
384
    {
385
        $cookie_theme = $_COOKIE['ppaTheme'] ?? null;
386
387
        return $this->isThemeAvailable($cookie_theme) ? $cookie_theme : null;
388
    }
389
390
    private function getSessionTheme(): ?string
391
    {
392
        $session_theme = $_SESSION['ppaTheme'] ?? null;
393
394
        return $this->isThemeAvailable($session_theme) ? $session_theme : null;
395
    }
396
397
    private function getRequestTheme(): ?string
398
    {
399
        $request_theme = $_REQUEST['theme'] ?? null;
400
401
        return $this->isThemeAvailable($request_theme) ? $request_theme : null;
402
    }
403
404
    private function isThemeAvailable(?string $_theme = null): bool
405
    {
406
        return \array_key_exists($_theme, $this->getThemeFolders());
407
    }
408
409
    private function setCookieTheme(string $_theme): void
410
    {
411
        if ($this->isThemeAvailable($_theme)) {
412
            \setcookie('ppaTheme', $_theme, \time() + 31536000, '/');
413
        }
414
    }
415
416
    private function setSessionTheme(string $_theme): void
417
    {
418
        if ($this->isThemeAvailable($_theme)) {
419
            $_SESSION['ppaTheme'] = $_theme;
420
        }
421
    }
422
423
    /**
424
     * Undocumented function.
425
     *
426
     * @param string $subject
427
     * @psalm-suppress LessSpecificReturnStatement
428
     * @psalm-suppress MoreSpecificReturnType
429
     *
430
     * @return class-string
0 ignored issues
show
Documentation Bug introduced by
The doc comment class-string at position 0 could not be parsed: Unknown type name 'class-string' at position 0 in class-string.
Loading history...
431
     */
432
    private static function getControllerClassName(string $subject): string
433
    {
434
        return '\PHPPgAdmin\Controller\\' . \ucfirst($subject) . 'Controller';
435
    }
436
437
    private function getContainer(): \PHPPgAdmin\ContainerUtils
438
    {
439
        return $this->container;
440
    }
441
442
    /**
443
     * Traverse THEME_PATH, consider as theme folders those which
444
     * contain a `global.css` stylesheet.
445
     *
446
     * @return array the theme folders
447
     */
448
    private function getThemeFolders(): array
449
    {
450
        if (!empty(self::$themeFolders)) {
451
            return self::$themeFolders;
452
        }
453
        // no THEME_PATH (how?) then return empty array
454
        if (!$gestor = \opendir(containerInstance()->THEME_PATH)) {
455
            \closedir($gestor);
456
457
            return [];
458
        }
459
        $themefolders = [];
460
461
        /* This is the right way to iterate on a folder */
462
        while (false !== ($foldername = \readdir($gestor))) {
463
            if ('.' === $foldername || '..' === $foldername) {
464
                continue;
465
            }
466
467
            $folderpath = \sprintf('%s%s%s', \containerInstance()->THEME_PATH, \DIRECTORY_SEPARATOR, $foldername);
468
            $stylesheet = \sprintf('%s%s%s', $folderpath, \DIRECTORY_SEPARATOR, 'global.css');
469
            // if $folderpath if indeed a folder and contains a global.css file, then it's a theme
470
            if (\is_dir($folderpath) &&
471
                \is_file($stylesheet)
472
            ) {
473
                $themefolders[$foldername] = $folderpath;
474
            }
475
        }
476
477
        \closedir($gestor);
478
        self::$themeFolders = $themefolders;
479
480
        return $themefolders;
481
    }
482
}
483