Completed
Push — master ( 7bc838...e972b3 )
by Maurício
01:35 queued 18s
created

ServerDatabasesController::indexAction()   B

Complexity

Conditions 6
Paths 8

Size

Total Lines 70
Code Lines 52

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 52
dl 0
loc 70
rs 8.425
c 0
b 0
f 0
cc 6
nc 8
nop 1

How to fix   Long Method   

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
/* vim: set expandtab sw=4 ts=4 sts=4: */
3
/**
4
 * Holds the PhpMyAdmin\Controllers\Server\ServerDatabasesController
5
 *
6
 * @package PhpMyAdmin\Controllers
7
 */
8
declare(strict_types=1);
9
10
namespace PhpMyAdmin\Controllers\Server;
11
12
use PhpMyAdmin\Charsets;
13
use PhpMyAdmin\Controllers\Controller;
14
use PhpMyAdmin\DatabaseInterface;
15
use PhpMyAdmin\Message;
16
use PhpMyAdmin\Url;
17
use PhpMyAdmin\Util;
18
19
/**
20
 * Handles viewing and creating and deleting databases
21
 *
22
 * @package PhpMyAdmin\Controllers
23
 */
24
class ServerDatabasesController extends Controller
25
{
26
    /**
27
     * @var array array of database details
28
     */
29
    private $databases = [];
30
31
    /**
32
     * @var int number of databases
33
     */
34
    private $databaseCount = 0;
35
36
    /**
37
     * @var string sort by column
38
     */
39
    private $sortBy;
40
41
    /**
42
     * @var string sort order of databases
43
     */
44
    private $sortOrder;
45
46
    /**
47
     * @var boolean whether to show database statistics
48
     */
49
    private $hasStatistics;
50
51
    /**
52
     * @var int position in list navigation
53
     */
54
    private $position;
55
56
    /**
57
     * Index action
58
     *
59
     * @param array $params Request parameters
60
     *
61
     * @return string HTML
62
     */
63
    public function indexAction(array $params): string
64
    {
65
        global $cfg, $server, $dblist, $is_create_db_priv;
66
        global $replication_info, $db_to_create, $pmaThemeImage, $text_dir;
67
68
        include_once ROOT_PATH . 'libraries/replication.inc.php';
69
        include_once ROOT_PATH . 'libraries/server_common.inc.php';
70
71
        $this->setSortDetails($params['sort_by'], $params['sort_order']);
72
        $this->hasStatistics = ! empty($params['statistics']);
73
        $this->position = ! empty($params['pos']) ? (int) $params['pos'] : 0;
74
75
        /**
76
         * Gets the databases list
77
         */
78
        if ($server > 0) {
79
            $this->databases = $this->dbi->getDatabasesFull(
80
                null,
81
                $this->hasStatistics,
82
                DatabaseInterface::CONNECT_USER,
83
                $this->sortBy,
84
                $this->sortOrder,
85
                $this->position,
86
                true
87
            );
88
            $this->databaseCount = count($dblist->databases);
89
        }
90
91
        $urlParams = [
92
            'statistics' => $this->hasStatistics,
93
            'pos' => $this->position,
94
            'sort_by' => $this->sortBy,
95
            'sort_order' => $this->sortOrder,
96
        ];
97
98
        $databases = $this->getDatabases($replication_types ?? []);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $replication_types seems to never exist and therefore isset should always be false.
Loading history...
99
100
        $collationDropdownBox = '';
101
        if ($cfg['ShowCreateDb'] && $is_create_db_priv) {
102
            $collationDropdownBox = Charsets::getCollationDropdownBox(
103
                $this->dbi,
104
                $cfg['Server']['DisableIS'],
105
                'db_collation',
106
                null,
107
                $this->dbi->getServerCollation(),
108
                true
109
            );
110
        }
111
112
        $headerStatistics = $this->getStatisticsColumns();
113
114
        return $this->template->render('server/databases/index', [
115
            'is_create_database_shown' => $cfg['ShowCreateDb'],
116
            'has_create_database_privileges' => $is_create_db_priv,
117
            'has_statistics' => $this->hasStatistics,
118
            'database_to_create' => $db_to_create,
119
            'databases' => $databases['databases'],
120
            'total_statistics' => $databases['total_statistics'],
121
            'header_statistics' => $headerStatistics,
122
            'collation_dropdown_box' => $collationDropdownBox,
123
            'database_count' => $this->databaseCount,
124
            'pos' => $this->position,
125
            'url_params' => $urlParams,
126
            'max_db_list' => $cfg['MaxDbList'],
127
            'has_master_replication' => $replication_info['master']['status'],
128
            'has_slave_replication' => $replication_info['slave']['status'],
129
            'is_drop_allowed' => $this->dbi->isSuperuser() || $cfg['AllowUserDropDatabase'],
130
            'default_tab_database' => $cfg['DefaultTabDatabase'],
131
            'pma_theme_image' => $pmaThemeImage,
132
            'text_dir' => $text_dir,
133
        ]);
134
    }
135
136
    /**
137
     * Handles creating a new database
138
     *
139
     * @param array $params Request parameters
140
     *
141
     * @return array JSON
142
     */
143
    public function createDatabaseAction(array $params): array
144
    {
145
        global $cfg, $db;
146
147
        /**
148
         * Builds and executes the db creation sql query
149
         */
150
        $sqlQuery = 'CREATE DATABASE ' . Util::backquote($params['new_db']);
0 ignored issues
show
Bug introduced by
Are you sure PhpMyAdmin\Util::backquote($params['new_db']) of type array|mixed|string can be used in concatenation? ( Ignorable by Annotation )

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

150
        $sqlQuery = 'CREATE DATABASE ' . /** @scrutinizer ignore-type */ Util::backquote($params['new_db']);
Loading history...
151
        if (! empty($params['db_collation'])) {
152
            list($databaseCharset) = explode('_', $params['db_collation']);
153
            $charsets = Charsets::getMySQLCharsets(
154
                $this->dbi,
155
                $cfg['Server']['DisableIS']
156
            );
157
            $collations = Charsets::getMySQLCollations(
158
                $this->dbi,
159
                $cfg['Server']['DisableIS']
160
            );
161
            if (in_array($databaseCharset, $charsets)
162
                && in_array($params['db_collation'], $collations[$databaseCharset])
163
            ) {
164
                $sqlQuery .= ' DEFAULT'
165
                    . Util::getCharsetQueryPart($params['db_collation']);
166
            }
167
        }
168
        $sqlQuery .= ';';
169
170
        $result = $this->dbi->tryQuery($sqlQuery);
171
172
        if (! $result) {
173
            // avoid displaying the not-created db name in header or navi panel
174
            $db = '';
175
176
            $message = Message::rawError($this->dbi->getError());
0 ignored issues
show
Bug introduced by
It seems like $this->dbi->getError() can also be of type boolean; however, parameter $message of PhpMyAdmin\Message::rawError() 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

176
            $message = Message::rawError(/** @scrutinizer ignore-type */ $this->dbi->getError());
Loading history...
177
            $json = ['message' => $message];
178
179
            $this->response->setRequestStatus(false);
180
        } else {
181
            $db = $params['new_db'];
182
183
            $message = Message::success(__('Database %1$s has been created.'));
184
            $message->addParam($params['new_db']);
185
186
            $json = [
187
                'message' => $message,
188
                'sql_query' => Util::getMessage(null, $sqlQuery, 'success'),
189
                'url_query' => Util::getScriptNameForOption(
190
                    $cfg['DefaultTabDatabase'],
191
                    'database'
192
                ) . Url::getCommon(['db' => $params['new_db']]),
193
            ];
194
        }
195
196
        return $json;
197
    }
198
199
    /**
200
     * Handles dropping multiple databases
201
     *
202
     * @param array $params Request parameters
203
     *
204
     * @return array JSON
205
     */
206
    public function dropDatabasesAction(array $params): array
207
    {
208
        global $submit_mult, $mult_btn, $selected;
209
210
        if (! isset($params['selected_dbs'])) {
211
            $message = Message::error(__('No databases selected.'));
212
        } else {
213
            $action = 'server_databases.php';
214
            $err_url = $action . Url::getCommon();
215
216
            $submit_mult = 'drop_db';
217
            $mult_btn = __('Yes');
218
219
            include ROOT_PATH . 'libraries/mult_submits.inc.php';
220
221
            if (empty($message)) { // no error message
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $message seems to never exist and therefore empty should always be true.
Loading history...
222
                $numberOfDatabases = count($selected);
223
                $message = Message::success(
224
                    _ngettext(
225
                        '%1$d database has been dropped successfully.',
226
                        '%1$d databases have been dropped successfully.',
227
                        $numberOfDatabases
228
                    )
229
                );
230
                $message->addParam($numberOfDatabases);
231
            }
232
        }
233
234
        $json = [];
235
        if ($message instanceof Message) {
236
            $json = ['message' => $message];
237
            $this->response->setRequestStatus($message->isSuccess());
238
        }
239
240
        return $json;
241
    }
242
243
    /**
244
     * Extracts parameters sort order and sort by
245
     *
246
     * @param string|null $sortBy    sort by
247
     * @param string|null $sortOrder sort order
248
     *
249
     * @return void
250
     */
251
    private function setSortDetails(?string $sortBy, ?string $sortOrder): void
252
    {
253
        if (empty($sortBy)) {
254
            $this->sortBy = 'SCHEMA_NAME';
255
        } else {
256
            $sortByWhitelist = [
257
                'SCHEMA_NAME',
258
                'DEFAULT_COLLATION_NAME',
259
                'SCHEMA_TABLES',
260
                'SCHEMA_TABLE_ROWS',
261
                'SCHEMA_DATA_LENGTH',
262
                'SCHEMA_INDEX_LENGTH',
263
                'SCHEMA_LENGTH',
264
                'SCHEMA_DATA_FREE',
265
            ];
266
            $this->sortBy = 'SCHEMA_NAME';
267
            if (in_array($sortBy, $sortByWhitelist)) {
268
                $this->sortBy = $sortBy;
269
            }
270
        }
271
272
        $this->sortOrder = 'asc';
273
        if (isset($sortOrder)
274
            && mb_strtolower($sortOrder) === 'desc'
275
        ) {
276
            $this->sortOrder = 'desc';
277
        }
278
    }
279
280
    /**
281
     * Returns database list
282
     *
283
     * @param array $replicationTypes replication types
284
     *
285
     * @return array
286
     */
287
    private function getDatabases(array $replicationTypes): array
288
    {
289
        global $replication_info;
290
291
        $databases = [];
292
        $totalStatistics = $this->getStatisticsColumns();
293
        foreach ($this->databases as $database) {
294
            $replication = [
295
                'master' => [
296
                    'status' => $replication_info['master']['status'],
297
                ],
298
                'slave' => [
299
                    'status' => $replication_info['slave']['status'],
300
                ],
301
            ];
302
            foreach ($replicationTypes as $type) {
303
                if ($replication_info[$type]['status']) {
304
                    $key = array_search(
305
                        $database["SCHEMA_NAME"],
306
                        $replication_info[$type]['Ignore_DB']
307
                    );
308
                    if (strlen((string) $key) > 0) {
309
                        $replication[$type]['is_replicated'] = false;
310
                    } else {
311
                        $key = array_search(
312
                            $database["SCHEMA_NAME"],
313
                            $replication_info[$type]['Do_DB']
314
                        );
315
316
                        if (strlen((string) $key) > 0
317
                            || count($replication_info[$type]['Do_DB']) == 0
318
                        ) {
319
                            // if ($key != null) did not work for index "0"
320
                            $replication[$type]['is_replicated'] = true;
321
                        }
322
                    }
323
                }
324
            }
325
326
            $statistics = $this->getStatisticsColumns();
327
            if ($this->hasStatistics) {
328
                foreach (array_keys($statistics) as $key) {
329
                    $statistics[$key]['raw'] = $database[$key] ?? null;
330
                    $totalStatistics[$key]['raw'] += (int) $database[$key] ?? 0;
331
                }
332
            }
333
334
            $databases[] = [
335
                'name' => $database['SCHEMA_NAME'],
336
                'collation' => [
337
                    'name' => $database['DEFAULT_COLLATION_NAME'],
338
                    'description' => Charsets::getCollationDescr(
339
                        $database['DEFAULT_COLLATION_NAME']
340
                    ),
341
                ],
342
                'statistics' => $statistics,
343
                'replication' => $replication,
344
                'is_system_schema' => $this->dbi->isSystemSchema(
345
                    $database['SCHEMA_NAME'],
346
                    true
347
                ),
348
            ];
349
        }
350
351
        return [
352
            'databases' => $databases,
353
            'total_statistics' => $totalStatistics,
354
        ];
355
    }
356
357
    /**
358
     * Prepares the statistics columns
359
     *
360
     * @return array
361
     */
362
    private function getStatisticsColumns(): array
363
    {
364
        return [
365
            'SCHEMA_TABLES' => [
366
                'title' => __('Tables'),
367
                'format' => 'number',
368
                'raw' => 0,
369
            ],
370
            'SCHEMA_TABLE_ROWS' => [
371
                'title' => __('Rows'),
372
                'format' => 'number',
373
                'raw' => 0,
374
            ],
375
            'SCHEMA_DATA_LENGTH' => [
376
                'title' => __('Data'),
377
                'format' => 'byte',
378
                'raw' => 0,
379
            ],
380
            'SCHEMA_INDEX_LENGTH' => [
381
                'title' => __('Indexes'),
382
                'format' => 'byte',
383
                'raw' => 0,
384
            ],
385
            'SCHEMA_LENGTH' => [
386
                'title' => __('Total'),
387
                'format' => 'byte',
388
                'raw' => 0,
389
            ],
390
            'SCHEMA_DATA_FREE' => [
391
                'title' => __('Overhead'),
392
                'format' => 'byte',
393
                'raw' => 0,
394
            ],
395
        ];
396
    }
397
}
398