Passed
Push — master ( c3c58e...8ab7e2 )
by Maurício
08:33
created

Footer   C

Complexity

Total Complexity 54

Size/Duplication

Total Lines 361
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
wmc 54
eloc 144
c 0
b 0
f 0
dl 0
loc 361
rs 6.4799

13 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 7 1
A getDebugMessage() 0 16 5
B _removeRecursion() 0 15 7
A _getDemoMessage() 0 22 2
A disable() 0 3 1
B getDisplay() 0 59 10
D getSelfUrl() 0 47 15
A getScripts() 0 3 1
A setMinimal() 0 3 1
A getErrorMessages() 0 13 2
A setAjax() 0 3 1
A _setHistory() 0 13 6
A _getSelfLink() 0 17 2

How to fix   Complexity   

Complex Class

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

1
<?php
2
/* vim: set expandtab sw=4 ts=4 sts=4: */
3
/**
4
 * Used to render the footer of PMA's pages
5
 *
6
 * @package PhpMyAdmin
7
 */
8
declare(strict_types=1);
9
10
namespace PhpMyAdmin;
11
12
use Traversable;
13
14
/**
15
 * Class used to output the footer
16
 *
17
 * @package PhpMyAdmin
18
 */
19
class Footer
20
{
21
    /**
22
     * Scripts instance
23
     *
24
     * @access private
25
     * @var Scripts
26
     */
27
    private $_scripts;
28
    /**
29
     * Whether we are servicing an ajax request.
30
     *
31
     * @access private
32
     * @var bool
33
     */
34
    private $_isAjax;
35
    /**
36
     * Whether to only close the BODY and HTML tags
37
     * or also include scripts, errors and links
38
     *
39
     * @access private
40
     * @var bool
41
     */
42
    private $_isMinimal;
43
    /**
44
     * Whether to display anything
45
     *
46
     * @access private
47
     * @var bool
48
     */
49
    private $_isEnabled;
50
51
    /**
52
     * @var Relation
53
     */
54
    private $relation;
55
56
    /**
57
     * @var Template
58
     */
59
    private $template;
60
61
    /**
62
     * Creates a new class instance
63
     */
64
    public function __construct()
65
    {
66
        $this->template = new Template();
67
        $this->_isEnabled = true;
68
        $this->_scripts = new Scripts();
69
        $this->_isMinimal = false;
70
        $this->relation = new Relation($GLOBALS['dbi']);
71
    }
72
73
    /**
74
     * Returns the message for demo server to error messages
75
     *
76
     * @return string
77
     */
78
    private function _getDemoMessage(): string
79
    {
80
        $message = '<a href="/">' . __('phpMyAdmin Demo Server') . '</a>: ';
81
        if (@file_exists(ROOT_PATH . 'revision-info.php')) {
82
            $revision = '';
83
            $fullrevision = '';
84
            $repobase = '';
85
            $repobranchbase = '';
86
            $branch = '';
87
            include ROOT_PATH . 'revision-info.php';
88
            $message .= sprintf(
89
                __('Currently running Git revision %1$s from the %2$s branch.'),
90
                '<a target="_blank" rel="noopener noreferrer" href="' . $repobase . $fullrevision . '">'
91
                . $revision . '</a>',
92
                '<a target="_blank" rel="noopener noreferrer" href="' . $repobranchbase . $branch . '">'
93
                . $branch . '</a>'
94
            );
95
        } else {
96
            $message .= __('Git information missing!');
97
        }
98
99
        return Message::notice($message)->getDisplay();
100
    }
101
102
    /**
103
     * Remove recursions and iterator objects from an object
104
     *
105
     * @param object|array $object Object to clean
106
     * @param array        $stack  Stack used to keep track of recursion,
107
     *                             need not be passed for the first time
108
     *
109
     * @return object Reference passed object
110
     */
111
    private static function _removeRecursion(&$object, array $stack = [])
112
    {
113
        if ((is_object($object) || is_array($object)) && $object) {
0 ignored issues
show
introduced by
The condition is_array($object) is always true.
Loading history...
114
            if ($object instanceof Traversable) {
115
                $object = "***ITERATOR***";
116
            } elseif (! in_array($object, $stack, true)) {
117
                $stack[] = $object;
118
                foreach ($object as &$subobject) {
119
                    self::_removeRecursion($subobject, $stack);
120
                }
121
            } else {
122
                $object = "***RECURSION***";
123
            }
124
        }
125
        return $object;
126
    }
127
128
    /**
129
     * Renders the debug messages
130
     *
131
     * @return string
132
     */
133
    public function getDebugMessage(): string
134
    {
135
        $retval = '\'null\'';
136
        if ($GLOBALS['cfg']['DBG']['sql']
137
            && empty($_REQUEST['no_debug'])
138
            && ! empty($_SESSION['debug'])
139
        ) {
140
            // Remove recursions and iterators from $_SESSION['debug']
141
            self::_removeRecursion($_SESSION['debug']);
142
143
            $retval = json_encode($_SESSION['debug']);
144
            $_SESSION['debug'] = [];
145
            return json_last_error() ? '\'false\'' : $retval;
146
        }
147
        $_SESSION['debug'] = [];
148
        return $retval;
149
    }
150
151
    /**
152
     * Returns the url of the current page
153
     *
154
     * @return string
155
     */
156
    public function getSelfUrl(): string
157
    {
158
        $params = [];
159
        if (isset($_GET['route']) || isset($_POST['route'])) {
160
            $params['route'] = $_GET['route'] ?? $_POST['route'];
161
        }
162
        if (isset($GLOBALS['db']) && strlen($GLOBALS['db']) > 0) {
163
            $params['db'] = $GLOBALS['db'];
164
        }
165
        if (isset($GLOBALS['table']) && strlen($GLOBALS['table']) > 0) {
166
            $params['table'] = $GLOBALS['table'];
167
        }
168
        $params['server'] = $GLOBALS['server'];
169
        if (isset($_REQUEST['target']) && strlen($_REQUEST['target']) > 0) {
170
            $params['target'] = $_REQUEST['target'];
171
        }
172
173
        // needed for server privileges tabs
174
        if (isset($_GET['viewing_mode'])
175
            && in_array($_GET['viewing_mode'], ['server', 'db', 'table'])
176
        ) {
177
            $params['viewing_mode'] = $_GET['viewing_mode'];
178
        }
179
        /*
180
         * @todo    coming from /server/privileges, here $db is not set,
181
         *          add the following condition below when that is fixed
182
         *          && $_GET['checkprivsdb'] == $db
183
         */
184
        if (isset($_GET['checkprivsdb'])
185
        ) {
186
            $params['checkprivsdb'] = $_GET['checkprivsdb'];
187
        }
188
        /*
189
         * @todo    coming from /server/privileges, here $table is not set,
190
         *          add the following condition below when that is fixed
191
         *          && $_REQUEST['checkprivstable'] == $table
192
         */
193
        if (isset($_GET['checkprivstable'])
194
        ) {
195
            $params['checkprivstable'] = $_GET['checkprivstable'];
196
        }
197
        if (isset($_REQUEST['single_table'])
198
            && in_array($_REQUEST['single_table'], [true, false])
199
        ) {
200
            $params['single_table'] = $_REQUEST['single_table'];
201
        }
202
        return basename(Core::getenv('SCRIPT_NAME')) . Url::getCommonRaw($params);
203
    }
204
205
    /**
206
     * Renders the link to open a new page
207
     *
208
     * @param string $url The url of the page
209
     *
210
     * @return string
211
     */
212
    private function _getSelfLink(string $url): string
213
    {
214
        $retval  = '';
215
        $retval .= '<div id="selflink" class="print_ignore">';
216
        $retval .= '<a href="' . htmlspecialchars($url) . '"'
217
            . ' title="' . __('Open new phpMyAdmin window') . '" target="_blank" rel="noopener noreferrer">';
218
        if (Util::showIcons('TabsMode')) {
219
            $retval .= Util::getImage(
220
                'window-new',
221
                __('Open new phpMyAdmin window')
222
            );
223
        } else {
224
            $retval .=  __('Open new phpMyAdmin window');
225
        }
226
        $retval .= '</a>';
227
        $retval .= '</div>';
228
        return $retval;
229
    }
230
231
    /**
232
     * Renders the link to open a new page
233
     *
234
     * @return string
235
     */
236
    public function getErrorMessages(): string
237
    {
238
        $retval = '';
239
        if ($GLOBALS['error_handler']->hasDisplayErrors()) {
240
            $retval .= $GLOBALS['error_handler']->getDispErrors();
241
        }
242
243
        /**
244
         * Report php errors
245
         */
246
        $GLOBALS['error_handler']->reportErrors();
247
248
        return $retval;
249
    }
250
251
    /**
252
     * Saves query in history
253
     *
254
     * @return void
255
     */
256
    private function _setHistory(): void
257
    {
258
        if (! Core::isValid($_REQUEST['no_history'])
259
            && empty($GLOBALS['error_message'])
260
            && ! empty($GLOBALS['sql_query'])
261
            && isset($GLOBALS['dbi'])
262
            && $GLOBALS['dbi']->isUserType('logged')
263
        ) {
264
            $this->relation->setHistory(
265
                Core::ifSetOr($GLOBALS['db'], ''),
266
                Core::ifSetOr($GLOBALS['table'], ''),
267
                $GLOBALS['cfg']['Server']['user'],
268
                $GLOBALS['sql_query']
269
            );
270
        }
271
    }
272
273
    /**
274
     * Disables the rendering of the footer
275
     *
276
     * @return void
277
     */
278
    public function disable(): void
279
    {
280
        $this->_isEnabled = false;
281
    }
282
283
    /**
284
     * Set the ajax flag to indicate whether
285
     * we are servicing an ajax request
286
     *
287
     * @param bool $isAjax Whether we are servicing an ajax request
288
     *
289
     * @return void
290
     */
291
    public function setAjax(bool $isAjax): void
292
    {
293
        $this->_isAjax = $isAjax;
294
    }
295
296
    /**
297
     * Turn on minimal display mode
298
     *
299
     * @return void
300
     */
301
    public function setMinimal(): void
302
    {
303
        $this->_isMinimal = true;
304
    }
305
306
    /**
307
     * Returns the Scripts object
308
     *
309
     * @return Scripts object
310
     */
311
    public function getScripts(): Scripts
312
    {
313
        return $this->_scripts;
314
    }
315
316
    /**
317
     * Renders the footer
318
     *
319
     * @return string
320
     */
321
    public function getDisplay(): string
322
    {
323
        $this->_setHistory();
324
        if ($this->_isEnabled) {
325
            if (! $this->_isAjax && ! $this->_isMinimal) {
326
                if (Core::getenv('SCRIPT_NAME')
327
                    && empty($_POST)
328
                    && ! $this->_isAjax
329
                ) {
330
                    $url = $this->getSelfUrl();
331
                    $header = Response::getInstance()->getHeader();
332
                    $scripts = $header->getScripts()->getFiles();
333
                    $menuHash = $header->getMenu()->getHash();
334
                    // prime the client-side cache
335
                    $this->_scripts->addCode(
336
                        sprintf(
337
                            'if (! (history && history.pushState)) '
338
                            . 'MicroHistory.primer = {'
339
                            . ' url: "%s",'
340
                            . ' scripts: %s,'
341
                            . ' menuHash: "%s"'
342
                            . '};',
343
                            Sanitize::escapeJsString($url),
344
                            json_encode($scripts),
345
                            Sanitize::escapeJsString($menuHash)
346
                        )
347
                    );
348
                }
349
                if (Core::getenv('SCRIPT_NAME')
350
                    && ! $this->_isAjax
351
                ) {
352
                    $url = $this->getSelfUrl();
353
                    $selfLink = $this->_getSelfLink($url);
354
                }
355
                $this->_scripts->addCode(
356
                    'var debugSQLInfo = ' . $this->getDebugMessage() . ';'
357
                );
358
359
                $errorMessages = $this->getErrorMessages();
360
                $scripts = $this->_scripts->getDisplay();
361
362
                if ($GLOBALS['cfg']['DBG']['demo']) {
363
                    $demoMessage = $this->_getDemoMessage();
364
                }
365
366
                $footer = Config::renderFooter();
367
            }
368
            return $this->template->render('footer', [
369
                'is_ajax' => $this->_isAjax,
370
                'is_minimal' => $this->_isMinimal,
371
                'self_link' => $selfLink ?? '',
372
                'error_messages' => $errorMessages ?? '',
373
                'scripts' => $scripts ?? '',
374
                'is_demo' => $GLOBALS['cfg']['DBG']['demo'],
375
                'demo_message' => $demoMessage ?? '',
376
                'footer' => $footer ?? '',
377
            ]);
378
        }
379
        return '';
380
    }
381
}
382