Passed
Push — master ( c6b243...f27f2e )
by Felipe
08:33 queued 04:05
created

IndexesController::doSaveCreateIndex()   B

Complexity

Conditions 4
Paths 6

Size

Total Lines 38
Code Lines 25

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 38
rs 8.5806
c 0
b 0
f 0
cc 4
eloc 25
nc 6
nop 0
1
<?php
2
3
/**
4
 * PHPPgAdmin v6.0.0-beta.33
5
 */
6
7
namespace PHPPgAdmin\Controller;
8
9
use PHPPgAdmin\Decorators\Decorator;
10
11
/**
12
 * Base controller class.
13
 *
14
 * @package PHPPgAdmin
15
 */
16
class IndexesController extends BaseController
17
{
18
    public $controller_name = 'IndexesController';
19
20
    /**
21
     * Default method to render the controller according to the action parameter.
22
     */
23
    public function render()
24
    {
25
        $lang = $this->lang;
26
27
        $action = $this->action;
28
        if ('tree' == $action) {
29
            return $this->doTree();
30
        }
31
32
        $this->printHeader($lang['strindexes'], '<script src="' . \SUBFOLDER . '/js/indexes.js" type="text/javascript"></script>');
33
34
        $onloadInit = false;
35
        if ('create_index' == $action || 'save_create_index' == $action) {
36
            $onloadInit = true;
37
        }
38
        $this->printBody(true, 'detailbody', $onloadInit);
39
40
        switch ($action) {
41
            case 'cluster_index':
42
                if (isset($_POST['cluster'])) {
43
                    $this->doClusterIndex(false);
44
                } else {
45
                    $this->doDefault();
46
                }
47
48
                break;
49
            case 'confirm_cluster_index':
50
                $this->doClusterIndex(true);
51
52
                break;
53
            case 'reindex':
54
                $this->doReindex();
55
56
                break;
57
            case 'save_create_index':
58
                if (isset($_POST['cancel'])) {
59
                    $this->doDefault();
60
                } else {
61
                    $this->doSaveCreateIndex();
62
                }
63
64
                break;
65
            case 'create_index':
66
                $this->doCreateIndex();
67
68
                break;
69
            case 'drop_index':
70
                if (isset($_POST['drop'])) {
71
                    $this->doDropIndex(false);
72
                } else {
73
                    $this->doDefault();
74
                }
75
76
                break;
77
            case 'confirm_drop_index':
78
                $this->doDropIndex(true);
79
80
                break;
81
            default:
82
                $this->doDefault();
83
84
                break;
85
        }
86
87
        return $this->printFooter();
88
    }
89
90
    public function doDefault($msg = '')
91
    {
92
        $lang = $this->lang;
93
        $data = $this->misc->getDatabaseAccessor();
94
95
        $indPre = function (&$rowdata, $actions) use ($data, $lang) {
96
            if ($data->phpBool($rowdata->fields['indisprimary'])) {
97
                $rowdata->fields['+constraints'] = $lang['strprimarykey'];
98
                $actions['drop']['disable']      = true;
99
            } elseif ($data->phpBool($rowdata->fields['indisunique'])) {
100
                $rowdata->fields['+constraints'] = $lang['struniquekey'];
101
                $actions['drop']['disable']      = true;
102
            } else {
103
                $rowdata->fields['+constraints'] = '';
104
            }
105
106
            return $actions;
107
        };
108
        if (!isset($_REQUEST['subject'])) {
109
            $_REQUEST['subject'] = 'table';
110
        }
111
112
        $subject = urlencode($_REQUEST['subject']);
113
        $object  = urlencode($_REQUEST[$_REQUEST['subject']]);
114
115
        $this->printTrail($subject);
116
        $this->printTabs($subject, 'indexes');
117
        $this->printMsg($msg);
118
119
        $indexes = $data->getIndexes($_REQUEST[$_REQUEST['subject']]);
120
121
        $columns = [
122
            'index'       => [
123
                'title' => $lang['strname'],
124
                'field' => Decorator::field('indname'),
125
            ],
126
            'definition'  => [
127
                'title' => $lang['strdefinition'],
128
                'field' => Decorator::field('inddef'),
129
            ],
130
            'constraints' => [
131
                'title'  => $lang['strconstraints'],
132
                'field'  => Decorator::field('+constraints'),
133
                'type'   => 'verbatim',
134
                'params' => ['align' => 'center'],
135
            ],
136
            'clustered'   => [
137
                'title' => $lang['strclustered'],
138
                'field' => Decorator::field('indisclustered'),
139
                'type'  => 'yesno',
140
            ],
141
            'actions'     => [
142
                'title' => $lang['stractions'],
143
            ],
144
            'comment'     => [
145
                'title' => $lang['strcomment'],
146
                'field' => Decorator::field('idxcomment'),
147
            ],
148
        ];
149
150
        $url = \SUBFOLDER . '/src/views/indexes';
151
152
        $actions = [
153
            'cluster' => [
154
                'content' => $lang['strclusterindex'],
155
                'attr'    => [
156
                    'href' => [
157
                        'url'     => $url,
158
                        'urlvars' => [
159
                            'action'  => 'confirm_cluster_index',
160
                            'subject' => $subject,
161
                            $subject  => $object,
162
                            'index'   => Decorator::field('indname'),
163
                        ],
164
                    ],
165
                ],
166
            ],
167
            'reindex' => [
168
                'content' => $lang['strreindex'],
169
                'attr'    => [
170
                    'href' => [
171
                        'url'     => $url,
172
                        'urlvars' => [
173
                            'action'  => 'reindex',
174
                            'subject' => $subject,
175
                            $subject  => $object,
176
                            'index'   => Decorator::field('indname'),
177
                        ],
178
                    ],
179
                ],
180
            ],
181
            'drop'    => [
182
                'content' => $lang['strdrop'],
183
                'attr'    => [
184
                    'href' => [
185
                        'url'     => $url,
186
                        'urlvars' => [
187
                            'action'  => 'confirm_drop_index',
188
                            'subject' => $subject,
189
                            $subject  => $object,
190
                            'index'   => Decorator::field('indname'),
191
                        ],
192
                    ],
193
                ],
194
            ],
195
        ];
196
197
        echo $this->printTable($indexes, $columns, $actions, 'indexes-indexes', $lang['strnoindexes'], $indPre);
198
199
        $this->printNavLinks([
1 ignored issue
show
Coding Style introduced by
The opening parenthesis of a multi-line function call should be the last content on the line.
Loading history...
200
            'create' => [
201
                'attr'    => [
202
                    'href' => [
203
                        'url'     => 'indexes',
204
                        'urlvars' => [
205
                            'action'   => 'create_index',
206
                            'server'   => $_REQUEST['server'],
207
                            'database' => $_REQUEST['database'],
208
                            'schema'   => $_REQUEST['schema'],
209
                            $subject   => $object,
210
                            'subject'  => $subject,
211
                        ],
212
                    ],
213
                ],
214
                'content' => $lang['strcreateindex'],
215
            ],
216
        ], 'indexes-indexes', get_defined_vars());
1 ignored issue
show
Coding Style introduced by
For multi-line function calls, the closing parenthesis should be on a new line.

If a function call spawns multiple lines, the coding standard suggests to move the closing parenthesis to a new line:

someFunctionCall(
    $firstArgument,
    $secondArgument,
    $thirdArgument
); // Closing parenthesis on a new line.
Loading history...
217
    }
218
219
    public function doTree()
220
    {
221
        $lang = $this->lang;
0 ignored issues
show
Unused Code introduced by
The assignment to $lang is dead and can be removed.
Loading history...
222
        $data = $this->misc->getDatabaseAccessor();
223
        if (!isset($_REQUEST['subject'])) {
224
            $_REQUEST['subject'] = 'table';
225
        }
226
227
        $subject = urlencode($_REQUEST['subject']);
228
        $object  = urlencode($_REQUEST[$_REQUEST['subject']]);
229
230
        $indexes = $data->getIndexes($object);
231
232
        $reqvars = $this->misc->getRequestVars($subject);
0 ignored issues
show
Unused Code introduced by
The assignment to $reqvars is dead and can be removed.
Loading history...
233
234
        $getIcon = function ($f) {
235
            if ('t' == $f['indisprimary']) {
236
                return 'PrimaryKey';
237
            }
238
239
            if ('t' == $f['indisunique']) {
240
                return 'UniqueConstraint';
241
            }
242
243
            return 'Index';
244
        };
245
246
        $attrs = [
247
            'text' => Decorator::field('indname'),
248
            'icon' => Decorator::callback($getIcon),
249
        ];
250
251
        return $this->printTree($indexes, $attrs, 'indexes');
252
    }
253
254
    /**
255
     * Show confirmation of cluster index and perform actual cluster.
256
     *
257
     * @param mixed $confirm
258
     */
259
    public function doClusterIndex($confirm)
260
    {
261
        $lang = $this->lang;
262
        $data = $this->misc->getDatabaseAccessor();
263
264
        if (!isset($_REQUEST['subject'])) {
265
            $_REQUEST['subject'] = 'table';
266
        }
267
        $subject = urlencode($_REQUEST['subject']);
268
        $object  = urlencode($_REQUEST[$subject]);
269
270
        //$this->printTrail($subject);
271
272
        if ($confirm) {
273
            // Default analyze to on
274
            $_REQUEST['analyze'] = true;
275
276
            $this->printTrail('index');
277
            $this->printTabs($subject, 'indexes');
278
            $this->printTitle($lang['strclusterindex'], 'pg.index.cluster');
279
280
            echo '<p>', sprintf($lang['strconfcluster'], $this->misc->printVal($_REQUEST['index'])), '</p>' . "\n";
281
282
            echo '<form action="' . \SUBFOLDER . '/src/views/indexes" method="post">' . "\n";
283
            echo '<p><input type="checkbox" id="analyze" name="analyze"', (isset($_REQUEST['analyze']) ? ' checked="checked"' : ''), ' />';
284
            echo "<label for=\"analyze\">{$lang['stranalyze']}</label></p>" . "\n";
285
            echo '<input type="hidden" name="action" value="cluster_index" />' . "\n";
286
            echo '<input type="hidden" name="table" value="', htmlspecialchars($object), '" />' . "\n";
287
            echo '<input type="hidden" name="index" value="', htmlspecialchars($_REQUEST['index']), '" />' . "\n";
288
            echo $this->misc->form;
289
            echo "<input type=\"submit\" name=\"cluster\" value=\"{$lang['strclusterindex']}\" />" . "\n";
290
            echo "<input type=\"submit\" name=\"cancel\" value=\"{$lang['strcancel']}\" />" . "\n";
291
            echo '</form>' . "\n";
292
        } else {
293
            set_time_limit(0);
294
            list($status, $sql) = $data->clusterIndex($object, $_POST['index']);
295
            if (0 == $status) {
296
                if (isset($_POST['analyze'])) {
297
                    $status = $data->analyzeDB($object);
298
                    if (0 == $status) {
299
                        $this->doDefault($sql . '<br>' . $lang['strclusteredgood'] . ' ' . $lang['stranalyzegood']);
300
                    } else {
301
                        $this->doDefault($sql . '<br>' . $lang['stranalyzebad']);
302
                    }
303
                } else {
304
                    $this->doDefault($sql . '<br>' . $lang['strclusteredgood']);
305
                }
306
            } else {
307
                $this->doDefault($sql . '<br>' . $lang['strclusteredbad']);
308
            }
309
        }
310
    }
311
312
    public function doReindex()
313
    {
314
        $lang = $this->lang;
315
        $data = $this->misc->getDatabaseAccessor();
316
        set_time_limit(0);
317
        $status = $data->reindex('INDEX', $_REQUEST['index']);
318
        if (0 == $status) {
319
            $this->doDefault($lang['strreindexgood']);
320
        } else {
321
            $this->doDefault($lang['strreindexbad']);
322
        }
323
    }
324
325
    /**
326
     * Displays a screen where they can enter a new index.
327
     *
328
     * @param mixed $msg
329
     */
330
    public function doCreateIndex($msg = '')
331
    {
332
        $lang = $this->lang;
333
        $data = $this->misc->getDatabaseAccessor();
334
335
        $subject = urlencode($this->getRequestParam('subject', 'table'));
336
        $object  = urlencode($this->getRequestParam($subject));
337
338
        $formIndexName = $this->getPostParam('formIndexName', '');
339
        $formIndexType = $this->getPostParam('formIndexType');
340
        $formUnique    = $this->getPostParam('formUnique');
341
        $formConcur    = $this->getPostParam('formConcur');
342
        $formWhere     = $this->getPostParam('formWhere', '');
343
        $formSpc       = $this->getPostParam('formSpc', '');
344
345
        $attrs = $data->getTableAttributes($object);
346
        // Fetch all tablespaces from the database
347
        if ($data->hasTablespaces()) {
348
            $tablespaces = $data->getTablespaces();
349
        }
350
        $this->prtrace('tablespaces', $tablespaces->recordCount());
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $tablespaces does not seem to be defined for all execution paths leading up to this point.
Loading history...
351
        $this->printTrail($subject);
352
        $this->printTabs($subject, 'indexes');
353
        $this->printTitle($lang['strcreateindex'], 'pg.index.create');
354
        $this->printMsg($msg);
355
356
        $selColumns = new \PHPPgAdmin\XHtml\XHtmlSelect('TableColumnList', true, 10);
357
        $selColumns->set_style('width: 14em;');
358
359
        if ($attrs->recordCount() > 0) {
360
            while (!$attrs->EOF) {
361
                $attname = new \PHPPgAdmin\XHtml\XHtmlOption($attrs->fields['attname']);
362
                $selColumns->add($attname);
363
                $attrs->moveNext();
364
            }
365
        }
366
367
        $selIndex = new \PHPPgAdmin\XHtml\XHtmlSelect('IndexColumnList[]', true, 10);
368
        $selIndex->set_style('width: 14em;');
369
        $selIndex->set_attribute('id', 'IndexColumnList');
370
        $buttonAdd = new \PHPPgAdmin\XHtml\XHtmlButton('add', '>>');
371
        $buttonAdd->set_attribute('onclick', 'buttonPressed(this);');
372
        $buttonAdd->set_attribute('type', 'button');
373
374
        $buttonRemove = new \PHPPgAdmin\XHtml\XHtmlButton('remove', '<<');
375
        $buttonRemove->set_attribute('onclick', 'buttonPressed(this);');
376
        $buttonRemove->set_attribute('type', 'button');
377
378
        echo '<form onsubmit="doSelectAll();" name="formIndex" action="indexes" method="post">' . "\n";
379
380
        echo '<table>' . "\n";
381
        echo '<tr><th class="data required" colspan="3">' . $lang['strindexname'] . '</th></tr>';
382
        echo '<tr>';
383
        echo '<td class="data1" colspan="3">';
384
        echo 'Index name cannot exceed ' . $data->_maxNameLen . ' characters<br>';
385
        echo '<input type="text" name="formIndexName" size="32" placeholder="Index Name" maxlength="' .
386
        $data->_maxNameLen . '" value="' .
387
        htmlspecialchars($formIndexName) . '" />';
388
        echo '</td>';
389
        echo '</tr>';
390
391
        echo '<tr>';
392
        echo '<th class="data">' . $lang['strtablecolumnlist'] . '</th><th class="data">&nbsp;</th>';
393
        echo '<th class="data required">' . $lang['strindexcolumnlist'] . '</th>';
394
        echo '</tr>' . "\n";
395
396
        echo '<tr><td class="data1">' . $selColumns->fetch() . '</td>' . "\n";
397
        echo '<td class="data1">' . $buttonRemove->fetch() . $buttonAdd->fetch() . '</td>';
398
        echo '<td class="data1">' . $selIndex->fetch() . '</td></tr>' . "\n";
399
        echo '<tr>';
400
        echo '<th class="data left required" scope="row">' . $lang['strindextype'] . '</th>';
401
        echo '<td colspan="2" class="data1"><select name="formIndexType">';
402
        foreach ($data->typIndexes as $v) {
403
            echo '<option value="', htmlspecialchars($v), '"',
404
            ($v == $formIndexType) ? ' selected="selected"' : '', '>', htmlspecialchars($v), '</option>' . "\n";
405
        }
406
        echo '</select></td></tr>' . "\n";
407
        echo '<tr>';
408
        echo "<th class=\"data left\" scope=\"row\"><label for=\"formUnique\">{$lang['strunique']}</label></th>";
409
        echo '<td  colspan="2" class="data1"><input type="checkbox" id="formUnique" name="formUnique"', ($formUnique ? 'checked="checked"' : ''), ' /></td>';
410
        echo '</tr>';
411
        echo '<tr>';
412
        echo "<th class=\"data left\" scope=\"row\">{$lang['strwhere']}</th>";
413
        echo '<td  colspan="2"  class="data1">(<input name="formWhere" size="32" maxlength="' . $data->_maxNameLen . '" value="' . htmlspecialchars($formWhere) . '" />)</td>';
414
        echo '</tr>';
415
416
        // Tablespace (if there are any)
417
        if ($data->hasTablespaces() && $tablespaces->recordCount() > 0) {
418
            echo '<tr>' . "\n";
419
            echo "<th class=\"data left\">{$lang['strtablespace']}</th>" . "\n";
420
            echo '<td  colspan="2" class="data1">';
421
            echo "\n\t\t\t<select name=\"formSpc\">" . "\n";
422
            // Always offer the default (empty) option
423
            echo "\t\t\t\t<option value=\"\"",
424
            ('' == $formSpc) ? ' selected="selected"' : '', '></option>' . "\n";
425
            // Display all other tablespaces
426
            while (!$tablespaces->EOF) {
427
                $spcname = htmlspecialchars($tablespaces->fields['spcname']);
428
                echo "\t\t\t\t<option value=\"{$spcname}\"",
429
                ($spcname == $formSpc) ? ' selected="selected"' : '', ">{$spcname}</option>" . "\n";
430
                $tablespaces->moveNext();
431
            }
432
            echo "\t\t\t</select>\n\t\t</td>\n\t</tr>" . "\n";
433
        }
434
435
        if ($data->hasConcurrentIndexBuild()) {
436
            echo '<tr>';
437
            echo "<th class=\"data left\" scope=\"row\"><label for=\"formConcur\">{$lang['strconcurrently']}</label></th>";
438
            echo '<td  colspan="2"  class="data1"><input type="checkbox" id="formConcur" name="formConcur"', ($formConcur ? 'checked="checked"' : ''), ' /></td>';
439
            echo '</tr>';
440
        }
441
442
        echo '</table>';
443
444
        echo '<p><input type="hidden" name="action" value="save_create_index" />' . "\n";
445
        echo $this->misc->form;
446
        echo '<input type="hidden" name="subject" value="', htmlspecialchars($subject), '" />' . "\n";
447
        echo '<input type="hidden" name="' . $subject . '" value="', htmlspecialchars($object), '" />' . "\n";
448
        echo "<input type=\"submit\" value=\"{$lang['strcreate']}\" />" . "\n";
449
        echo "<input type=\"submit\" name=\"cancel\" value=\"{$lang['strcancel']}\" /></p>" . "\n";
450
        echo '</form>' . "\n";
451
    }
452
453
    /**
454
     * Actually creates the new index in the database.
455
     *
456
     * @@ Note: this function can't handle columns with commas in them
457
     */
458
    public function doSaveCreateIndex()
459
    {
460
        $lang = $this->lang;
461
        $data = $this->misc->getDatabaseAccessor();
462
463
        if (!isset($_POST['subject'])) {
464
            $_POST['subject'] = 'table';
465
        }
466
        $subject = urlencode($_POST['subject']);
467
        $object  = urlencode($_POST[$subject]);
468
469
        // Handle databases that don't have partial indexes
470
        $formWhere = $this->getPostParam('formWhere', '');
471
472
        // Default tablespace to null if it isn't set
473
        $formSpc = $this->getPostParam('formSpc');
474
475
        $IndexColumnList = $this->getPostParam('IndexColumnList', '');
476
477
        // Check that they've given a name and at least one column
478
        if ('' == $IndexColumnList) {
479
            $this->doCreateIndex($lang['strindexneedscols']);
480
        } else {
481
            list($status, $sql) = $data->createIndex(
482
                $this->getPostParam('formIndexName', ''),
483
                $object,
484
                $IndexColumnList,
485
                $this->getPostParam('formIndexType'),
486
                $this->getPostParam('formUnique'),
487
                $formWhere,
488
                $formSpc,
489
                $this->getPostParam('formConcur')
490
            );
491
492
            if (0 == $status) {
493
                $this->doDefault($sql . '<br>' . $lang['strindexcreated']);
494
            } else {
495
                $this->doCreateIndex($lang['strindexcreatedbad']);
496
            }
497
        }
498
    }
499
500
    /**
501
     * Show confirmation of drop index and perform actual drop.
502
     *
503
     * @param mixed $confirm
504
     */
505
    public function doDropIndex($confirm)
506
    {
507
        $lang = $this->lang;
508
        $data = $this->misc->getDatabaseAccessor();
509
510
        $subject = urlencode($this->getRequestParam('subject', 'table'));
0 ignored issues
show
Unused Code introduced by
The assignment to $subject is dead and can be removed.
Loading history...
511
        $object  = urlencode($this->getRequestParam($this->getRequestParam('subject', 'table')));
512
513
        if ($confirm) {
514
            $this->printTrail('index');
515
            $this->printTitle($lang['strdrop'], 'pg.index.drop');
516
517
            echo '<p>', sprintf($lang['strconfdropindex'], $this->misc->printVal($this->getRequestParam('index'))), '</p>' . "\n";
518
            echo '<form action="' . \SUBFOLDER . '/src/views/indexes" method="post">' . "\n";
519
            echo '<input type="hidden" name="action" value="drop_index" />' . "\n";
520
            echo '<input type="hidden" name="table" value="', htmlspecialchars($object), '" />' . "\n";
521
            echo '<input type="hidden" name="index" value="', htmlspecialchars($this->getRequestParam('index')), '" />' . "\n";
522
            echo $this->misc->form;
523
            echo '<p><input type="checkbox" id="cascade" name="cascade" value="1" />';
524
            echo '<label for="cascade">' . $lang['strcascade'] . '</label></p>' . "\n";
525
            echo "<input type=\"submit\" name=\"drop\" value=\"{$lang['strdrop']}\" />" . "\n";
526
            echo "<input type=\"submit\" name=\"cancel\" value=\"{$lang['strcancel']}\" />" . "\n";
527
            echo '</form>' . "\n";
528
        } else {
529
            try {
530
                list($status, $sql) = $data->dropIndex($this->getPostParam('index'), $this->getPostParam('cascade'));
531
                if (0 == $status) {
532
                    $this->doDefault($sql . "\n" . $lang['strindexdropped']);
533
                } else {
534
                    $this->doDefault($sql . "\n" . $lang['strindexdroppedbad']);
535
                }
536
            } catch (\PHPPgAdmin\ADOdbException $e) {
537
                $this->doDefault($lang['strindexdroppedbad']);
538
            }
539
        }
540
    }
541
}
542