Passed
Push — master ( 360a7e...05dafc )
by William
10:25 queued 12s
created

RelationController::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 23
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 8
dl 0
loc 23
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 12

How to fix   Many Parameters   

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

1
<?php
2
/**
3
 * Holds the PhpMyAdmin\Controllers\Table\RelationController
4
 *
5
 * @package PhpMyAdmin\Controllers
6
 */
7
declare(strict_types=1);
8
9
namespace PhpMyAdmin\Controllers\Table;
10
11
use PhpMyAdmin\Core;
12
use PhpMyAdmin\DatabaseInterface;
13
use PhpMyAdmin\Html\Generator;
14
use PhpMyAdmin\Index;
15
use PhpMyAdmin\Relation;
16
use PhpMyAdmin\Response;
17
use PhpMyAdmin\Table;
18
use PhpMyAdmin\Template;
19
use PhpMyAdmin\Util;
20
21
/**
22
 * Handles table relation logic
23
 *
24
 * @package PhpMyAdmin\Controllers
25
 */
26
class RelationController extends AbstractController
27
{
28
    /**
29
     * @var array
30
     */
31
    protected $options_array;
32
33
    /**
34
     * @var array
35
     */
36
    protected $cfgRelation;
37
38
    /**
39
     * @var array
40
     */
41
    protected $existrel;
42
43
    /**
44
     * @var string
45
     */
46
    protected $tbl_storage_engine;
47
48
    /**
49
     * @var array
50
     */
51
    protected $existrel_foreign;
52
53
    /**
54
     * @var Table
55
     */
56
    protected $upd_query;
57
58
    /**
59
     * @var Relation
60
     */
61
    private $relation;
62
63
    /**
64
     * Constructor
65
     *
66
     * @param Response          $response           Response object
67
     * @param DatabaseInterface $dbi                DatabaseInterface object
68
     * @param Template          $template           Template object
69
     * @param string            $db                 Database name
70
     * @param string            $table              Table name
71
     * @param array|null        $options_array      Options
72
     * @param array|null        $cfgRelation        Config relation
73
     * @param string            $tbl_storage_engine Table storage engine
74
     * @param array|null        $existrel           Relations
75
     * @param array|null        $existrel_foreign   External relations
76
     * @param Table             $upd_query          Update query
77
     * @param Relation          $relation           Relation instance
78
     */
79
    public function __construct(
80
        $response,
81
        $dbi,
82
        Template $template,
83
        $db,
84
        $table,
85
        $options_array,
86
        $cfgRelation,
87
        $tbl_storage_engine,
88
        $existrel,
89
        $existrel_foreign,
90
        $upd_query,
91
        Relation $relation
92
    ) {
93
        parent::__construct($response, $dbi, $template, $db, $table);
94
95
        $this->options_array = $options_array;
96
        $this->cfgRelation = $cfgRelation;
97
        $this->tbl_storage_engine = $tbl_storage_engine;
98
        $this->existrel = $existrel;
99
        $this->existrel_foreign = $existrel_foreign;
100
        $this->upd_query = $upd_query;
101
        $this->relation = $relation;
102
    }
103
104
    /**
105
     * Index
106
     *
107
     * @return void
108
     */
109
    public function indexAction()
110
    {
111
        global $route;
112
113
        // Send table of column names to populate corresponding dropdowns depending
114
        // on the current selection
115
        if (isset($_POST['getDropdownValues'])
116
            && $_POST['getDropdownValues'] === 'true'
117
        ) {
118
            // if both db and table are selected
119
            if (isset($_POST['foreignTable'])) {
120
                $this->getDropdownValueForTableAction();
121
            } else { // if only the db is selected
122
                $this->getDropdownValueForDbAction();
123
            }
124
            return;
125
        }
126
127
        $this->response->getHeader()->getScripts()->addFiles(
128
            [
129
                'table/relation.js',
130
                'indexes.js',
131
            ]
132
        );
133
134
        // Set the database
135
        $this->dbi->selectDb($this->db);
136
137
        // updates for Internal relations
138
        if (isset($_POST['destination_db']) && $this->cfgRelation['relwork']) {
139
            $this->updateForInternalRelationAction();
140
        }
141
142
        // updates for foreign keys
143
        $this->updateForForeignKeysAction();
144
145
        // Updates for display field
146
        if ($this->cfgRelation['displaywork'] && isset($_POST['display_field'])) {
147
            $this->updateForDisplayField();
148
        }
149
150
        // If we did an update, refresh our data
151
        if (isset($_POST['destination_db']) && $this->cfgRelation['relwork']) {
152
            $this->existrel = $this->relation->getForeigners(
153
                $this->db,
154
                $this->table,
155
                '',
156
                'internal'
157
            );
158
        }
159
        if (isset($_POST['destination_foreign_db'])
160
            && Util::isForeignKeySupported($this->tbl_storage_engine)
161
        ) {
162
            $this->existrel_foreign = $this->relation->getForeigners(
163
                $this->db,
164
                $this->table,
165
                '',
166
                'foreign'
167
            );
168
        }
169
170
        /**
171
         * Dialog
172
         */
173
        // Now find out the columns of our $table
174
        // need to use DatabaseInterface::QUERY_STORE with $this->dbi->numRows()
175
        // in mysqli
176
        $columns = $this->dbi->getColumns($this->db, $this->table);
177
178
        $column_array = [];
179
        $column_hash_array = [];
180
        $column_array[''] = '';
181
        foreach ($columns as $column) {
182
            if (strtoupper($this->tbl_storage_engine) == 'INNODB'
183
                || ! empty($column['Key'])
184
            ) {
185
                $column_array[$column['Field']] = $column['Field'];
186
                $column_hash_array[$column['Field']] = md5($column['Field']);
187
            }
188
        }
189
        if ($GLOBALS['cfg']['NaturalOrder']) {
190
            uksort($column_array, 'strnatcasecmp');
191
        }
192
193
        // common form
194
        $engine = $this->dbi->getTable($this->db, $this->table)->getStorageEngine();
195
        $foreignKeySupported = Util::isForeignKeySupported($this->tbl_storage_engine);
196
        $this->response->addHTML(
197
            $this->template->render('table/relation/common_form', [
198
                'is_foreign_key_supported' => Util::isForeignKeySupported($engine),
199
                'db' => $this->db,
200
                'table' => $this->table,
201
                'cfg_relation' => $this->cfgRelation,
202
                'tbl_storage_engine' => $this->tbl_storage_engine,
203
                'existrel' => isset($this->existrel) ? $this->existrel : [],
204
                'existrel_foreign' => is_array($this->existrel_foreign) && array_key_exists('foreign_keys_data', $this->existrel_foreign)
205
                    ? $this->existrel_foreign['foreign_keys_data'] : [],
206
                'options_array' => $this->options_array,
207
                'column_array' => $column_array,
208
                'column_hash_array' => $column_hash_array,
209
                'save_row' => array_values($columns),
210
                'url_params' => $GLOBALS['url_params'],
211
                'databases' => $GLOBALS['dblist']->databases,
212
                'dbi' => $this->dbi,
213
                'default_sliders_state' => $GLOBALS['cfg']['InitialSlidersState'],
214
                'foreignKeySupported' => $foreignKeySupported,
215
                'displayIndexesHtml' => $foreignKeySupported ? Index::getHtmlForDisplayIndexes() : null,
216
                'route' => $route,
217
            ])
218
        );
219
    }
220
221
    /**
222
     * Update for display field
223
     *
224
     * @return void
225
     */
226
    public function updateForDisplayField()
227
    {
228
        if ($this->upd_query->updateDisplayField(
229
            $_POST['display_field'],
230
            $this->cfgRelation
231
        )
232
        ) {
233
            $this->response->addHTML(
234
                Generator::getMessage(
235
                    __('Display column was successfully updated.'),
236
                    '',
237
                    'success'
238
                )
239
            );
240
        }
241
    }
242
243
    /**
244
     * Update for FK
245
     *
246
     * @return void
247
     */
248
    public function updateForForeignKeysAction()
249
    {
250
        $multi_edit_columns_name = isset($_POST['foreign_key_fields_name'])
251
            ? $_POST['foreign_key_fields_name']
252
            : null;
253
        $preview_sql_data = '';
254
        $seen_error = false;
255
256
        // (for now, one index name only; we keep the definitions if the
257
        // foreign db is not the same)
258
        if (isset($_POST['destination_foreign_db'], $_POST['destination_foreign_table'])
259
            && isset($_POST['destination_foreign_column'])) {
260
            [$html, $preview_sql_data, $display_query, $seen_error]
261
                = $this->upd_query->updateForeignKeys(
262
                    $_POST['destination_foreign_db'],
263
                    $multi_edit_columns_name,
0 ignored issues
show
Bug introduced by
It seems like $multi_edit_columns_name can also be of type null; however, parameter $multi_edit_columns_name of PhpMyAdmin\Table::updateForeignKeys() does only seem to accept array, 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

263
                    /** @scrutinizer ignore-type */ $multi_edit_columns_name,
Loading history...
264
                    $_POST['destination_foreign_table'],
265
                    $_POST['destination_foreign_column'],
266
                    $this->options_array,
267
                    $this->table,
268
                    is_array($this->existrel_foreign) && array_key_exists('foreign_keys_data', $this->existrel_foreign)
0 ignored issues
show
Bug introduced by
It seems like is_array($this->existrel...eign_keys_data'] : null can also be of type null; however, parameter $existrel_foreign of PhpMyAdmin\Table::updateForeignKeys() does only seem to accept array, 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

268
                    /** @scrutinizer ignore-type */ is_array($this->existrel_foreign) && array_key_exists('foreign_keys_data', $this->existrel_foreign)
Loading history...
269
                    ? $this->existrel_foreign['foreign_keys_data']
270
                    : null
271
                );
272
            $this->response->addHTML($html);
273
        }
274
275
        // If there is a request for SQL previewing.
276
        if (isset($_POST['preview_sql'])) {
277
            Core::previewSQL($preview_sql_data);
278
        }
279
280
        if (! empty($display_query) && ! $seen_error) {
281
            $GLOBALS['display_query'] = $display_query;
282
            $this->response->addHTML(
283
                Generator::getMessage(
284
                    __('Your SQL query has been executed successfully.'),
285
                    null,
286
                    'success'
287
                )
288
            );
289
        }
290
    }
291
292
    /**
293
     * Update for internal relation
294
     *
295
     * @return void
296
     */
297
    public function updateForInternalRelationAction()
298
    {
299
        $multi_edit_columns_name = isset($_POST['fields_name'])
300
            ? $_POST['fields_name']
301
            : null;
302
303
        if ($this->upd_query->updateInternalRelations(
304
            $multi_edit_columns_name,
0 ignored issues
show
Bug introduced by
It seems like $multi_edit_columns_name can also be of type null; however, parameter $multi_edit_columns_name of PhpMyAdmin\Table::updateInternalRelations() does only seem to accept array, 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

304
            /** @scrutinizer ignore-type */ $multi_edit_columns_name,
Loading history...
305
            $_POST['destination_db'],
306
            $_POST['destination_table'],
307
            $_POST['destination_column'],
308
            $this->cfgRelation,
309
            isset($this->existrel) ? $this->existrel : null
310
        )
311
        ) {
312
            $this->response->addHTML(
313
                Generator::getMessage(
314
                    __('Internal relationships were successfully updated.'),
315
                    '',
316
                    'success'
317
                )
318
            );
319
        }
320
    }
321
322
    /**
323
     * Send table columns for foreign table dropdown
324
     *
325
     * @return void
326
     *
327
     */
328
    public function getDropdownValueForTableAction()
329
    {
330
        $foreignTable = $_POST['foreignTable'];
331
        $table_obj = $this->dbi->getTable($_POST['foreignDb'], $foreignTable);
332
        // Since views do not have keys defined on them provide the full list of
333
        // columns
334
        if ($table_obj->isView()) {
335
            $columnList = $table_obj->getColumns(false, false);
336
        } else {
337
            $columnList = $table_obj->getIndexedColumns(false, false);
338
        }
339
        $columns = [];
340
        foreach ($columnList as $column) {
341
            $columns[] = htmlspecialchars($column);
342
        }
343
        if ($GLOBALS['cfg']['NaturalOrder']) {
344
            usort($columns, 'strnatcasecmp');
345
        }
346
        $this->response->addJSON('columns', $columns);
347
348
        // @todo should be: $server->db($db)->table($table)->primary()
349
        $primary = Index::getPrimary($foreignTable, $_POST['foreignDb']);
350
        if (false === $primary) {
351
            return;
352
        }
353
354
        $this->response->addJSON('primary', array_keys($primary->getColumns()));
355
    }
356
357
    /**
358
     * Send database selection values for dropdown
359
     *
360
     * @return void
361
     *
362
     */
363
    public function getDropdownValueForDbAction()
364
    {
365
        $tables = [];
366
        $foreign = isset($_POST['foreign']) && $_POST['foreign'] === 'true';
367
368
        if ($foreign) {
369
            $query = 'SHOW TABLE STATUS FROM '
370
                . Util::backquote($_POST['foreignDb']);
0 ignored issues
show
Bug introduced by
Are you sure PhpMyAdmin\Util::backquote($_POST['foreignDb']) 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

370
                . /** @scrutinizer ignore-type */ Util::backquote($_POST['foreignDb']);
Loading history...
371
            $tables_rs = $this->dbi->query(
372
                $query,
373
                DatabaseInterface::CONNECT_USER,
374
                DatabaseInterface::QUERY_STORE
375
            );
376
377
            while ($row = $this->dbi->fetchArray($tables_rs)) {
0 ignored issues
show
Bug introduced by
It seems like $tables_rs can also be of type false; however, parameter $result of PhpMyAdmin\DatabaseInterface::fetchArray() does only seem to accept object, 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

377
            while ($row = $this->dbi->fetchArray(/** @scrutinizer ignore-type */ $tables_rs)) {
Loading history...
378
                if (isset($row['Engine'])
379
                    &&  mb_strtoupper($row['Engine']) == $this->tbl_storage_engine
380
                ) {
381
                    $tables[] = htmlspecialchars($row['Name']);
382
                }
383
            }
384
        } else {
385
            $query = 'SHOW TABLES FROM '
386
                . Util::backquote($_POST['foreignDb']);
387
            $tables_rs = $this->dbi->query(
388
                $query,
389
                DatabaseInterface::CONNECT_USER,
390
                DatabaseInterface::QUERY_STORE
391
            );
392
            while ($row = $this->dbi->fetchArray($tables_rs)) {
393
                $tables[] = htmlspecialchars($row[0]);
394
            }
395
        }
396
        if ($GLOBALS['cfg']['NaturalOrder']) {
397
            usort($tables, 'strnatcasecmp');
398
        }
399
        $this->response->addJSON('tables', $tables);
400
    }
401
}
402