Passed
Pull Request — develop (#92)
by Felipe
06:19
created

ViewsController   F

Complexity

Total Complexity 112

Size/Duplication

Total Lines 901
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
dl 0
loc 901
rs 1.263
c 0
b 0
f 0
wmc 112

11 Methods

Rating   Name   Duplication   Size   Complexity  
D render() 0 83 17
C doDrop() 0 67 12
F doSaveCreateWiz() 0 130 34
B doDefault() 0 132 1
D doSelectRows() 0 127 17
F doSetParamsCreate() 0 147 18
B doCreate() 0 43 5
B doSubTree() 0 31 1
B doWizardCreate() 0 35 2
A doTree() 0 21 1
A doSaveCreate() 0 19 4

How to fix   Complexity   

Complex Class

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

1
<?php
2
0 ignored issues
show
Coding Style introduced by
You must use "/**" style comments for a file comment
Loading history...
3
/*
4
 * PHPPgAdmin v6.0.0-beta.30
5
 */
6
7
namespace PHPPgAdmin\Controller;
8
9
use \PHPPgAdmin\Decorators\Decorator;
10
11
/**
12
 * Base controller class
13
 */
5 ignored issues
show
Coding Style introduced by
Missing @category tag in class comment
Loading history...
Coding Style introduced by
Missing @package tag in class comment
Loading history...
Coding Style introduced by
Missing @author tag in class comment
Loading history...
Coding Style introduced by
Missing @license tag in class comment
Loading history...
Coding Style introduced by
Missing @link tag in class comment
Loading history...
14
class ViewsController extends BaseController
15
{
16
    public $script          = 'views.php';
17
    public $controller_name = 'ViewsController';
18
    public $table_place     = 'views-views';
19
20
    public function render()
1 ignored issue
show
Coding Style introduced by
Missing function doc comment
Loading history...
21
    {
22
        $conf = $this->conf;
0 ignored issues
show
Unused Code introduced by
The assignment to $conf is dead and can be removed.
Loading history...
23
24
        $lang   = $this->lang;
25
        $action = $this->action;
26
27
        if ('tree' == $action) {
28
            return $this->doTree();
29
        }
30
        if ('subtree' == $action) {
31
            return $this->doSubTree();
32
        }
33
34
        $data = $this->misc->getDatabaseAccessor();
0 ignored issues
show
Unused Code introduced by
The assignment to $data is dead and can be removed.
Loading history...
35
36
        $this->printHeader($lang['strviews']);
37
        $this->printBody();
38
39
        switch ($action) {
40
            case 'selectrows':
41
                if (!isset($_REQUEST['cancel'])) {
42
                    $this->doSelectRows(false);
43
                } else {
44
                    $this->doDefault();
45
                }
46
47
                break;
48
            case 'confselectrows':
49
                $this->doSelectRows(true);
50
51
                break;
52
            case 'save_create_wiz':
53
                if (isset($_REQUEST['cancel'])) {
54
                    $this->doDefault();
55
                } else {
56
                    $this->doSaveCreateWiz();
57
                }
58
59
                break;
60
            case 'wiz_create':
61
                $this->doWizardCreate();
62
63
                break;
64
            case 'set_params_create':
65
                if (isset($_POST['cancel'])) {
66
                    $this->doDefault();
67
                } else {
68
                    $this->doSetParamsCreate();
69
                }
70
71
                break;
72
            case 'save_create':
73
                if (isset($_REQUEST['cancel'])) {
74
                    $this->doDefault();
75
                } else {
76
                    $this->doSaveCreate();
77
                }
78
79
                break;
80
            case 'create':
81
                $this->doCreate();
82
83
                break;
84
            case 'drop':
85
                if (isset($_POST['drop'])) {
86
                    $this->doDrop(false);
87
                } else {
88
                    $this->doDefault();
89
                }
90
91
                break;
92
            case 'confirm_drop':
93
                $this->doDrop(true);
94
95
                break;
96
            default:
97
                $this->doDefault();
98
99
                break;
100
        }
101
102
        return $this->printFooter();
103
    }
104
105
    /**
106
     * Show default list of views in the database
107
     * @param mixed $msg
1 ignored issue
show
Coding Style introduced by
Missing parameter comment
Loading history...
108
     */
109
    public function doDefault($msg = '')
110
    {
111
        $conf = $this->conf;
112
113
        $lang = $this->lang;
114
        $data = $this->misc->getDatabaseAccessor();
115
116
        $this->printTrail('schema');
117
        $this->printTabs('schema', 'views');
118
        $this->printMsg($msg);
119
120
        $views = $data->getViews();
121
122
        $columns = [
123
            'view'    => [
124
                'title' => $lang['strview'],
125
                'field' => Decorator::field('relname'),
126
                'url'   => SUBFOLDER . "/redirect/view?{$this->misc->href}&amp;",
127
                'vars'  => ['view' => 'relname'],
128
            ],
129
            'owner'   => [
130
                'title' => $lang['strowner'],
131
                'field' => Decorator::field('relowner'),
132
            ],
133
            'actions' => [
134
                'title' => $lang['stractions'],
135
            ],
136
            'comment' => [
137
                'title' => $lang['strcomment'],
138
                'field' => Decorator::field('relcomment'),
139
            ],
140
        ];
141
142
        $actions = [
143
            'multiactions' => [
144
                'keycols' => ['view' => 'relname'],
145
                'url'     => 'views.php',
146
            ],
147
            'browse'       => [
148
                'content' => $lang['strbrowse'],
149
                'attr'    => [
150
                    'href' => [
151
                        'url'     => 'display.php',
152
                        'urlvars' => [
153
                            'action'  => 'confselectrows',
154
                            'subject' => 'view',
155
                            'return'  => 'schema',
156
                            'view'    => Decorator::field('relname'),
157
                        ],
158
                    ],
159
                ],
160
            ],
161
            'select'       => [
162
                'content' => $lang['strselect'],
163
                'attr'    => [
164
                    'href' => [
165
                        'url'     => 'views.php',
166
                        'urlvars' => [
167
                            'action' => 'confselectrows',
168
                            'view'   => Decorator::field('relname'),
169
                        ],
170
                    ],
171
                ],
172
            ],
173
174
            // Insert is possible if the relevant rule for the view has been created.
175
            //            'insert' => array(
176
            //                'title'    => $lang['strinsert'],
177
            //                'url'    => "views.php?action=confinsertrow&amp;{$this->misc->href}&amp;",
178
            //                'vars'    => array('view' => 'relname'),
179
            //            ),
180
181
            'alter'        => [
182
                'content' => $lang['stralter'],
183
                'attr'    => [
184
                    'href' => [
185
                        'url'     => 'viewproperties.php',
186
                        'urlvars' => [
187
                            'action' => 'confirm_alter',
188
                            'view'   => Decorator::field('relname'),
189
                        ],
190
                    ],
191
                ],
192
            ],
193
            'drop'         => [
194
                'multiaction' => 'confirm_drop',
195
                'content'     => $lang['strdrop'],
196
                'attr'        => [
197
                    'href' => [
198
                        'url'     => 'views.php',
199
                        'urlvars' => [
200
                            'action' => 'confirm_drop',
201
                            'view'   => Decorator::field('relname'),
202
                        ],
203
                    ],
204
                ],
205
            ],
206
        ];
207
208
        echo $this->printTable($views, $columns, $actions, $this->table_place, $lang['strnoviews']);
209
210
        $navlinks = [
211
            'create'    => [
212
                'attr'    => [
213
                    'href' => [
214
                        'url'     => 'views.php',
215
                        'urlvars' => [
216
                            'action'   => 'create',
217
                            'server'   => $_REQUEST['server'],
218
                            'database' => $_REQUEST['database'],
219
                            'schema'   => $_REQUEST['schema'],
220
                        ],
221
                    ],
222
                ],
223
                'content' => $lang['strcreateview'],
224
            ],
225
            'createwiz' => [
226
                'attr'    => [
227
                    'href' => [
228
                        'url'     => 'views.php',
229
                        'urlvars' => [
230
                            'action'   => 'wiz_create',
231
                            'server'   => $_REQUEST['server'],
232
                            'database' => $_REQUEST['database'],
233
                            'schema'   => $_REQUEST['schema'],
234
                        ],
235
                    ],
236
                ],
237
                'content' => $lang['strcreateviewwiz'],
238
            ],
239
        ];
240
        $this->printNavLinks($navlinks, $this->table_place, get_defined_vars());
241
    }
242
243
    /**
244
     * Generate XML for the browser tree.
245
     */
246
    public function doTree()
247
    {
248
        $conf = $this->conf;
0 ignored issues
show
Unused Code introduced by
The assignment to $conf is dead and can be removed.
Loading history...
249
250
        $lang = $this->lang;
0 ignored issues
show
Unused Code introduced by
The assignment to $lang is dead and can be removed.
Loading history...
251
        $data = $this->misc->getDatabaseAccessor();
252
253
        $views = $data->getViews();
254
255
        $reqvars = $this->misc->getRequestVars('view');
256
257
        $attrs = [
258
            'text'       => Decorator::field('relname'),
259
            'icon'       => 'View',
260
            'iconAction' => Decorator::url('display.php', $reqvars, ['view' => Decorator::field('relname')]),
261
            'toolTip'    => Decorator::field('relcomment'),
262
            'action'     => Decorator::redirecturl('redirect.php', $reqvars, ['view' => Decorator::field('relname')]),
263
            'branch'     => Decorator::url('views.php', $reqvars, ['action' => 'subtree', 'view' => Decorator::field('relname')]),
264
        ];
265
266
        return $this->printTree($views, $attrs, 'views');
267
    }
268
269
    public function doSubTree()
1 ignored issue
show
Coding Style introduced by
Missing function doc comment
Loading history...
270
    {
271
        $conf = $this->conf;
0 ignored issues
show
Unused Code introduced by
The assignment to $conf is dead and can be removed.
Loading history...
272
273
        $lang = $this->lang;
0 ignored issues
show
Unused Code introduced by
The assignment to $lang is dead and can be removed.
Loading history...
274
        $data = $this->misc->getDatabaseAccessor();
0 ignored issues
show
Unused Code introduced by
The assignment to $data is dead and can be removed.
Loading history...
275
276
        $tabs    = $this->misc->getNavTabs('view');
277
        $items   = $this->adjustTabsForTree($tabs);
278
        $reqvars = $this->misc->getRequestVars('view');
279
280
        $attrs = [
281
            'text'   => Decorator::field('title'),
282
            'icon'   => Decorator::field('icon'),
283
            'action' => Decorator::actionurl(Decorator::field('url'), $reqvars, Decorator::field('urlvars'), ['view' => $_REQUEST['view']]),
284
            'branch' => Decorator::ifempty(
285
                Decorator::field('branch'),
286
                '',
287
                Decorator::url(
288
                    Decorator::field('url'),
289
                    Decorator::field('urlvars'),
290
                    $reqvars,
291
                    [
292
                        'action' => 'tree',
293
                        'view'   => $_REQUEST['view'],
294
                    ]
295
                )
296
            ),
297
        ];
298
299
        return $this->printTree($items, $attrs, 'view');
300
    }
301
302
    /**
303
     * Ask for select parameters and perform select
304
     * @param mixed $confirm
1 ignored issue
show
Coding Style introduced by
Missing parameter comment
Loading history...
305
     * @param mixed $msg
1 ignored issue
show
Coding Style introduced by
Missing parameter comment
Loading history...
306
     */
307
    public function doSelectRows($confirm, $msg = '')
308
    {
309
        $conf = $this->conf;
0 ignored issues
show
Unused Code introduced by
The assignment to $conf is dead and can be removed.
Loading history...
310
311
        $lang = $this->lang;
312
        $data = $this->misc->getDatabaseAccessor();
313
314
        if ($confirm) {
315
            $this->printTrail('view');
316
            $this->printTabs('view', 'select');
317
            $this->printMsg($msg);
318
319
            $attrs = $data->getTableAttributes($_REQUEST['view']);
320
321
            echo '<form action="' . SUBFOLDER . '/src/views/' . $this->script . '" method="post" id="selectform">';
322
            echo "\n";
323
324
            if ($attrs->recordCount() > 0) {
325
                // JavaScript for select all feature
326
                echo "<script type=\"text/javascript\">\n";
327
                echo "//<![CDATA[\n";
328
                echo "	function selectAll() {\n";
329
                echo "		for (var i=0; i<document.getElementById('selectform').elements.length; i++) {\n";
330
                echo "			var e = document.getElementById('selectform').elements[i];\n";
331
                echo "			if (e.name.indexOf('show') == 0) { \n ";
332
                echo "				e.checked = document.getElementById('selectform').selectall.checked;\n";
333
                echo "			}\n";
334
                echo "		}\n";
335
                echo "	}\n";
336
                echo "//]]>\n";
337
                echo "</script>\n";
338
339
                echo "<table>\n";
340
341
                // Output table header
342
                echo "<tr><th class=\"data\">{$lang['strshow']}</th><th class=\"data\">{$lang['strcolumn']}</th>";
343
                echo "<th class=\"data\">{$lang['strtype']}</th><th class=\"data\">{$lang['stroperator']}</th>";
344
                echo "<th class=\"data\">{$lang['strvalue']}</th></tr>";
345
346
                $i = 0;
347
                while (!$attrs->EOF) {
348
                    $attrs->fields['attnotnull'] = $data->phpBool($attrs->fields['attnotnull']);
349
                    // Set up default value if there isn't one already
350
                    if (!isset($_REQUEST['values'][$attrs->fields['attname']])) {
351
                        $_REQUEST['values'][$attrs->fields['attname']] = null;
352
                    }
353
354
                    if (!isset($_REQUEST['ops'][$attrs->fields['attname']])) {
355
                        $_REQUEST['ops'][$attrs->fields['attname']] = null;
356
                    }
357
358
                    // Continue drawing row
359
                    $id = (0 == ($i % 2) ? '1' : '2');
360
                    echo "<tr class=\"data{$id}\">\n";
361
                    echo '<td style="white-space:nowrap;">';
362
                    echo '<input type="checkbox" name="show[', htmlspecialchars($attrs->fields['attname']), ']"',
363
                    isset($_REQUEST['show'][$attrs->fields['attname']]) ? ' checked="checked"' : '', ' /></td>';
364
                    echo '<td style="white-space:nowrap;">', $this->misc->printVal($attrs->fields['attname']), '</td>';
365
                    echo '<td style="white-space:nowrap;">', $this->misc->printVal($data->formatType($attrs->fields['type'], $attrs->fields['atttypmod'])), '</td>';
366
                    echo '<td style="white-space:nowrap;">';
367
                    echo "<select name=\"ops[{$attrs->fields['attname']}]\">\n";
368
                    foreach (array_keys($data->selectOps) as $v) {
369
                        echo '<option value="', htmlspecialchars($v), '"', ($_REQUEST['ops'][$attrs->fields['attname']] == $v) ? ' selected="selected"' : '',
370
                        '>', htmlspecialchars($v), "</option>\n";
371
                    }
372
                    echo "</select></td>\n";
373
                    echo '<td style="white-space:nowrap;">', $data->printField(
374
                        "values[{$attrs->fields['attname']}]",
375
                        $_REQUEST['values'][$attrs->fields['attname']],
376
                        $attrs->fields['type']
377
                    ), '</td>';
378
                    echo "</tr>\n";
379
                    $i++;
380
                    $attrs->moveNext();
381
                }
382
                // Select all checkbox
383
                echo "<tr><td colspan=\"5\"><input type=\"checkbox\" id=\"selectall\" name=\"selectall\" accesskey=\"a\" onclick=\"javascript:selectAll()\" /><label for=\"selectall\">{$lang['strselectallfields']}</label></td></tr>";
384
                echo "</table>\n";
385
            } else {
386
                echo "<p>{$lang['strinvalidparam']}</p>\n";
387
            }
388
389
            echo "<p><input type=\"hidden\" name=\"action\" value=\"selectrows\" />\n";
390
            echo '<input type="hidden" name="view" value="', htmlspecialchars($_REQUEST['view']), "\" />\n";
391
            echo "<input type=\"hidden\" name=\"subject\" value=\"view\" />\n";
392
            echo $this->misc->form;
393
            echo "<input type=\"submit\" name=\"select\" accesskey=\"r\" value=\"{$lang['strselect']}\" />\n";
394
            echo "<input type=\"submit\" name=\"cancel\" value=\"{$lang['strcancel']}\" /></p>\n";
395
            echo "</form>\n";
396
397
            return;
398
        }
399
        if (!isset($_POST['show'])) {
400
            $_POST['show'] = [];
401
        }
402
403
        if (!isset($_POST['values'])) {
404
            $_POST['values'] = [];
405
        }
406
407
        if (!isset($_POST['nulls'])) {
408
            $_POST['nulls'] = [];
409
        }
410
411
        // Verify that they haven't supplied a value for unary operators
412
        foreach ($_POST['ops'] as $k => $v) {
413
            if ('p' == $data->selectOps[$v] && $_POST['values'][$k] != '') {
414
                $this->doSelectRows(true, $lang['strselectunary']);
415
416
                return;
417
            }
418
        }
419
420
        if (0 == sizeof($_POST['show'])) {
421
            return $this->doSelectRows(true, $lang['strselectneedscol']);
422
        }
423
        // Generate query SQL
424
        $query = $data->getSelectSQL($_REQUEST['view'], array_keys($_POST['show']), $_POST['values'], $_POST['ops']);
425
426
        $_REQUEST['query']  = $query;
427
        $_REQUEST['return'] = 'schema';
428
429
        $this->setNoOutput(true);
430
431
        $display_controller = new DisplayController($this->getContainer());
432
433
        return $display_controller->render();
434
    }
435
436
    /**
437
     * Show confirmation of drop and perform actual drop
438
     * @param mixed $confirm
1 ignored issue
show
Coding Style introduced by
Missing parameter comment
Loading history...
439
     */
440
    public function doDrop($confirm)
441
    {
442
        $conf = $this->conf;
0 ignored issues
show
Unused Code introduced by
The assignment to $conf is dead and can be removed.
Loading history...
443
444
        $lang = $this->lang;
445
        $data = $this->misc->getDatabaseAccessor();
446
447
        if (empty($_REQUEST['view']) && empty($_REQUEST['ma'])) {
448
            return $this->doDefault($lang['strspecifyviewtodrop']);
449
        }
450
451
        if ($confirm) {
452
            $this->printTrail('view');
453
            $this->printTitle($lang['strdrop'], 'pg.view.drop');
454
455
            echo '<form action="' . SUBFOLDER . "/src/views/views.php\" method=\"post\">\n";
456
457
            //If multi drop
458
            if (isset($_REQUEST['ma'])) {
459
                foreach ($_REQUEST['ma'] as $v) {
460
                    $a = unserialize(htmlspecialchars_decode($v, ENT_QUOTES));
461
                    echo '<p>', sprintf($lang['strconfdropview'], $this->misc->printVal($a['view'])), "</p>\n";
462
                    echo '<input type="hidden" name="view[]" value="', htmlspecialchars($a['view']), "\" />\n";
463
                }
464
            } else {
465
                echo '<p>', sprintf($lang['strconfdropview'], $this->misc->printVal($_REQUEST['view'])), "</p>\n";
466
                echo '<input type="hidden" name="view" value="', htmlspecialchars($_REQUEST['view']), "\" />\n";
467
            }
468
469
            echo "<input type=\"hidden\" name=\"action\" value=\"drop\" />\n";
470
471
            echo $this->misc->form;
472
            echo "<p><input type=\"checkbox\" id=\"cascade\" name=\"cascade\" /> <label for=\"cascade\">{$lang['strcascade']}</label></p>\n";
473
            echo "<input type=\"submit\" name=\"drop\" value=\"{$lang['strdrop']}\" />\n";
474
            echo "<input type=\"submit\" name=\"cancel\" value=\"{$lang['strcancel']}\" />\n";
475
            echo "</form>\n";
476
        } else {
477
            if (is_array($_POST['view'])) {
478
                $msg    = '';
479
                $status = $data->beginTransaction();
480
                if (0 == $status) {
481
                    foreach ($_POST['view'] as $s) {
482
                        $status = $data->dropView($s, isset($_POST['cascade']));
483
                        if (0 == $status) {
484
                            $msg .= sprintf('%s: %s<br />', htmlentities($s, ENT_QUOTES, 'UTF-8'), $lang['strviewdropped']);
485
                        } else {
486
                            $data->endTransaction();
487
                            $this->doDefault(sprintf('%s%s: %s<br />', $msg, htmlentities($s, ENT_QUOTES, 'UTF-8'), $lang['strviewdroppedbad']));
488
489
                            return;
490
                        }
491
                    }
492
                }
493
                if (0 == $data->endTransaction()) {
494
                    // Everything went fine, back to the Default page....
495
                    $this->misc->setReloadBrowser(true);
496
                    $this->doDefault($msg);
497
                } else {
498
                    $this->doDefault($lang['strviewdroppedbad']);
499
                }
500
            } else {
501
                $status = $data->dropView($_POST['view'], isset($_POST['cascade']));
502
                if (0 == $status) {
503
                    $this->misc->setReloadBrowser(true);
504
                    $this->doDefault($lang['strviewdropped']);
505
                } else {
506
                    $this->doDefault($lang['strviewdroppedbad']);
507
                }
508
            }
509
        }
510
    }
511
512
    /**
513
     * Sets up choices for table linkage, and which fields to select for the view we're creating
514
     * @param mixed $msg
1 ignored issue
show
Coding Style introduced by
Missing parameter comment
Loading history...
515
     */
516
    public function doSetParamsCreate($msg = '')
517
    {
518
        $conf = $this->conf;
0 ignored issues
show
Unused Code introduced by
The assignment to $conf is dead and can be removed.
Loading history...
519
520
        $lang = $this->lang;
521
        $data = $this->misc->getDatabaseAccessor();
522
523
        // Check that they've chosen tables for the view definition
524
        if (!isset($_POST['formTables'])) {
525
            $this->doWizardCreate($lang['strviewneedsdef']);
526
        } else {
527
            // Initialise variables
528
            if (!isset($_REQUEST['formView'])) {
529
                $_REQUEST['formView'] = '';
530
            }
531
532
            if (!isset($_REQUEST['formComment'])) {
533
                $_REQUEST['formComment'] = '';
534
            }
535
536
            $this->printTrail('schema');
537
            $this->printTitle($lang['strcreateviewwiz'], 'pg.view.create');
538
            $this->printMsg($msg);
539
540
            $tblCount = sizeof($_POST['formTables']);
541
            //unserialize our schema/table information and store in arrSelTables
542
            for ($i = 0; $i < $tblCount; $i++) {
543
                $arrSelTables[] = unserialize($_POST['formTables'][$i]);
544
            }
545
546
            $linkCount = $tblCount;
0 ignored issues
show
Unused Code introduced by
The assignment to $linkCount is dead and can be removed.
Loading history...
547
548
            //get linking keys
549
            $rsLinkKeys = $data->getLinkingKeys($arrSelTables);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $arrSelTables does not seem to be defined for all execution paths leading up to this point.
Loading history...
550
            $linkCount  = $rsLinkKeys->recordCount() > $tblCount ? $rsLinkKeys->recordCount() : $tblCount;
551
552
            $arrFields = []; //array that will hold all our table/field names
553
554
            //if we have schemas we need to specify the correct schema for each table we're retrieiving
555
            //with getTableAttributes
556
            $curSchema = $data->_schema;
557
            for ($i = 0; $i < $tblCount; $i++) {
558
                if ($arrSelTables[$i]['schemaname'] != $data->_schema) {
559
                    $data->setSchema($arrSelTables[$i]['schemaname']);
560
                }
561
562
                $attrs = $data->getTableAttributes($arrSelTables[$i]['tablename']);
563
                while (!$attrs->EOF) {
564
                    $arrFields["{$arrSelTables[$i]['schemaname']}.{$arrSelTables[$i]['tablename']}.{$attrs->fields['attname']}"] = serialize(
565
                        [
566
                        'schemaname' => $arrSelTables[$i]['schemaname'],
567
                        'tablename'  => $arrSelTables[$i]['tablename'],
568
                        'fieldname'  => $attrs->fields['attname']]
569
                    );
570
                    $attrs->moveNext();
571
                }
572
573
                $data->setSchema($curSchema);
574
            }
575
            asort($arrFields);
576
577
            echo '<form action="' . SUBFOLDER . "/src/views/views.php\" method=\"post\">\n";
578
            echo "<table>\n";
579
            echo "<tr><th class=\"data\">{$lang['strviewname']}</th></tr>";
580
            echo "<tr>\n<td class=\"data1\">\n";
581
            // View name
582
            echo '<input name="formView" value="', htmlspecialchars($_REQUEST['formView']), "\" size=\"32\" maxlength=\"{$data->_maxNameLen}\" />\n";
583
            echo "</td>\n</tr>\n";
584
            echo "<tr><th class=\"data\">{$lang['strcomment']}</th></tr>";
585
            echo "<tr>\n<td class=\"data1\">\n";
586
            // View comments
587
            echo '<textarea name="formComment" rows="3" cols="32">',
588
            htmlspecialchars($_REQUEST['formComment']), "</textarea>\n";
589
            echo "</td>\n</tr>\n";
590
            echo "</table>\n";
591
592
            // Output selector for fields to be retrieved from view
593
            echo "<table>\n";
594
            echo "<tr><th class=\"data\">{$lang['strcolumns']}</th></tr>";
595
            echo "<tr>\n<td class=\"data1\">\n";
596
            echo \PHPPgAdmin\XHtml\HTMLController::printCombo($arrFields, 'formFields[]', false, '', true);
597
            echo "</td>\n</tr>";
598
            echo "<tr><td><input type=\"radio\" name=\"dblFldMeth\" id=\"dblFldMeth1\" value=\"rename\" /><label for=\"dblFldMeth1\">{$lang['strrenamedupfields']}</label>";
599
            echo "<br /><input type=\"radio\" name=\"dblFldMeth\" id=\"dblFldMeth2\" value=\"drop\" /><label for=\"dblFldMeth2\">{$lang['strdropdupfields']}</label>";
600
            echo "<br /><input type=\"radio\" name=\"dblFldMeth\" id=\"dblFldMeth3\" value=\"\" checked=\"checked\" /><label for=\"dblFldMeth3\">{$lang['strerrordupfields']}</label></td></tr></table><br />";
601
602
            // Output the Linking keys combo boxes
603
            echo "<table>\n";
604
            echo "<tr><th class=\"data\">{$lang['strviewlink']}</th></tr>";
605
            $rowClass = 'data1';
606
            for ($i = 0; $i < $linkCount; $i++) {
607
                // Initialise variables
608
                if (!isset($formLink[$i]['operator'])) {
609
                    $formLink[$i]['operator'] = 'INNER JOIN';
610
                }
611
612
                echo "<tr>\n<td class=\"${rowClass}\">\n";
613
614
                if (!$rsLinkKeys->EOF) {
615
                    $curLeftLink  = htmlspecialchars(serialize(['schemaname' => $rsLinkKeys->fields['p_schema'], 'tablename' => $rsLinkKeys->fields['p_table'], 'fieldname' => $rsLinkKeys->fields['p_field']]));
616
                    $curRightLink = htmlspecialchars(serialize(['schemaname' => $rsLinkKeys->fields['f_schema'], 'tablename' => $rsLinkKeys->fields['f_table'], 'fieldname' => $rsLinkKeys->fields['f_field']]));
617
                    $rsLinkKeys->moveNext();
618
                } else {
619
                    $curLeftLink  = '';
620
                    $curRightLink = '';
621
                }
622
623
                echo \PHPPgAdmin\XHtml\HTMLController::printCombo($arrFields, "formLink[${i}][leftlink]", true, $curLeftLink, false);
624
                echo \PHPPgAdmin\XHtml\HTMLController::printCombo($data->joinOps, "formLink[${i}][operator]", true, $formLink[$i]['operator']);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $formLink does not seem to be defined for all execution paths leading up to this point.
Loading history...
625
                echo \PHPPgAdmin\XHtml\HTMLController::printCombo($arrFields, "formLink[${i}][rightlink]", true, $curRightLink, false);
626
                echo "</td>\n</tr>\n";
627
                $rowClass = 'data1' == $rowClass ? 'data2' : 'data1';
628
            }
629
            echo "</table>\n<br />\n";
630
631
            // Build list of available operators (infix only)
632
            $arrOperators = [];
633
            foreach ($data->selectOps as $k => $v) {
634
                if ('i' == $v) {
635
                    $arrOperators[$k] = $k;
636
                }
637
            }
638
639
            // Output additional conditions, note that this portion of the wizard treats the right hand side as literal values
640
            //(not as database objects) so field names will be treated as strings, use the above linking keys section to perform joins
641
            echo "<table>\n";
642
            echo "<tr><th class=\"data\">{$lang['strviewconditions']}</th></tr>";
643
            $rowClass = 'data1';
644
            for ($i = 0; $i < $linkCount; $i++) {
645
                echo "<tr>\n<td class=\"${rowClass}\">\n";
646
                echo \PHPPgAdmin\XHtml\HTMLController::printCombo($arrFields, "formCondition[${i}][field]");
647
                echo \PHPPgAdmin\XHtml\HTMLController::printCombo($arrOperators, "formCondition[${i}][operator]", false, false);
0 ignored issues
show
Bug introduced by
false of type false is incompatible with the type string expected by parameter $szDefault of PHPPgAdmin\XHtml\HTMLController::printCombo(). ( Ignorable by Annotation )

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

647
                echo \PHPPgAdmin\XHtml\HTMLController::printCombo($arrOperators, "formCondition[${i}][operator]", false, /** @scrutinizer ignore-type */ false);
Loading history...
648
                echo "<input type=\"text\" name=\"formCondition[${i}][txt]\" />\n";
649
                echo "</td>\n</tr>\n";
650
                $rowClass = 'data1' == $rowClass ? 'data2' : 'data1';
651
            }
652
            echo "</table>\n";
653
            echo "<p><input type=\"hidden\" name=\"action\" value=\"save_create_wiz\" />\n";
654
655
            foreach ($arrSelTables as $curTable) {
656
                echo '<input type="hidden" name="formTables[]" value="' . htmlspecialchars(serialize($curTable)) . "\" />\n";
657
            }
658
659
            echo $this->misc->form;
660
            echo "<input type=\"submit\" value=\"{$lang['strcreate']}\" />\n";
661
            echo "<input type=\"submit\" name=\"cancel\" value=\"{$lang['strcancel']}\" /></p>\n";
662
            echo "</form>\n";
663
        }
664
    }
665
666
    /**
667
     * Display a wizard where they can enter a new view
668
     * @param mixed $msg
1 ignored issue
show
Coding Style introduced by
Missing parameter comment
Loading history...
669
     */
670
    public function doWizardCreate($msg = '')
671
    {
672
        $conf = $this->conf;
0 ignored issues
show
Unused Code introduced by
The assignment to $conf is dead and can be removed.
Loading history...
673
674
        $lang = $this->lang;
675
        $data = $this->misc->getDatabaseAccessor();
676
677
        $tables = $data->getTables(true);
678
679
        $this->printTrail('schema');
680
        $this->printTitle($lang['strcreateviewwiz'], 'pg.view.create');
681
        $this->printMsg($msg);
682
683
        echo '<form action="' . SUBFOLDER . "/src/views/views.php\" method=\"post\">\n";
684
        echo "<table>\n";
685
        echo "<tr><th class=\"data\">{$lang['strtables']}</th></tr>";
686
        echo "<tr>\n<td class=\"data1\">\n";
687
688
        $arrTables = [];
689
        while (!$tables->EOF) {
690
            $arrTmp                                                                   = [];
691
            $arrTmp['schemaname']                                                     = $tables->fields['nspname'];
692
            $arrTmp['tablename']                                                      = $tables->fields['relname'];
693
            $arrTables[$tables->fields['nspname'] . '.' . $tables->fields['relname']] = serialize($arrTmp);
694
            $tables->moveNext();
695
        }
696
        echo \PHPPgAdmin\XHtml\HTMLController::printCombo($arrTables, 'formTables[]', false, '', true);
697
698
        echo "</td>\n</tr>\n";
699
        echo "</table>\n";
700
        echo "<p><input type=\"hidden\" name=\"action\" value=\"set_params_create\" />\n";
701
        echo $this->misc->form;
702
        echo "<input type=\"submit\" value=\"{$lang['strnext']}\" />\n";
703
        echo "<input type=\"submit\" name=\"cancel\" value=\"{$lang['strcancel']}\" /></p>\n";
704
        echo "</form>\n";
705
    }
706
707
    /**
708
     * Displays a screen where they can enter a new view
709
     * @param mixed $msg
1 ignored issue
show
Coding Style introduced by
Missing parameter comment
Loading history...
710
     */
711
    public function doCreate($msg = '')
712
    {
713
        $conf = $this->conf;
0 ignored issues
show
Unused Code introduced by
The assignment to $conf is dead and can be removed.
Loading history...
714
715
        $lang = $this->lang;
716
        $data = $this->misc->getDatabaseAccessor();
717
718
        if (!isset($_REQUEST['formView'])) {
719
            $_REQUEST['formView'] = '';
720
        }
721
722
        if (!isset($_REQUEST['formDefinition'])) {
723
            if (isset($_SESSION['sqlquery'])) {
724
                $_REQUEST['formDefinition'] = $_SESSION['sqlquery'];
725
            } else {
726
                $_REQUEST['formDefinition'] = 'SELECT ';
727
            }
728
        }
729
        if (!isset($_REQUEST['formComment'])) {
730
            $_REQUEST['formComment'] = '';
731
        }
732
733
        $this->printTrail('schema');
734
        $this->printTitle($lang['strcreateview'], 'pg.view.create');
735
        $this->printMsg($msg);
736
737
        echo '<form action="' . SUBFOLDER . "/src/views/views.php\" method=\"post\">\n";
738
        echo "<table style=\"width: 100%\">\n";
739
        echo "\t<tr>\n\t\t<th class=\"data left required\">{$lang['strname']}</th>\n";
740
        echo "\t<td class=\"data1\"><input name=\"formView\" size=\"32\" maxlength=\"{$data->_maxNameLen}\" value=\"",
741
        htmlspecialchars($_REQUEST['formView']), "\" /></td>\n\t</tr>\n";
742
        echo "\t<tr>\n\t\t<th class=\"data left required\">{$lang['strdefinition']}</th>\n";
743
        echo "\t<td class=\"data1\"><textarea style=\"width:100%;\" rows=\"10\" cols=\"50\" name=\"formDefinition\">",
744
        htmlspecialchars($_REQUEST['formDefinition']), "</textarea></td>\n\t</tr>\n";
745
        echo "\t<tr>\n\t\t<th class=\"data left\">{$lang['strcomment']}</th>\n";
746
        echo "\t\t<td class=\"data1\"><textarea name=\"formComment\" rows=\"3\" cols=\"32\">",
747
        htmlspecialchars($_REQUEST['formComment']), "</textarea></td>\n\t</tr>\n";
748
        echo "</table>\n";
749
        echo "<p><input type=\"hidden\" name=\"action\" value=\"save_create\" />\n";
750
        echo $this->misc->form;
751
        echo "<input type=\"submit\" value=\"{$lang['strcreate']}\" />\n";
752
        echo "<input type=\"submit\" name=\"cancel\" value=\"{$lang['strcancel']}\" /></p>\n";
753
        echo "</form>\n";
754
    }
755
756
    /**
757
     * Actually creates the new view in the database
758
     */
759
    public function doSaveCreate()
760
    {
761
        $conf = $this->conf;
0 ignored issues
show
Unused Code introduced by
The assignment to $conf is dead and can be removed.
Loading history...
762
763
        $lang = $this->lang;
764
        $data = $this->misc->getDatabaseAccessor();
765
766
        // Check that they've given a name and a definition
767
        if ('' == $_POST['formView']) {
768
            $this->doCreate($lang['strviewneedsname']);
769
        } elseif ('' == $_POST['formDefinition']) {
770
            $this->doCreate($lang['strviewneedsdef']);
771
        } else {
772
            $status = $data->createView($_POST['formView'], $_POST['formDefinition'], false, $_POST['formComment']);
773
            if (0 == $status) {
774
                $this->misc->setReloadBrowser(true);
775
                $this->doDefault($lang['strviewcreated']);
776
            } else {
777
                $this->doCreate($lang['strviewcreatedbad']);
778
            }
779
        }
780
    }
781
782
    /**
783
     * Actually creates the new wizard view in the database
784
     */
785
    public function doSaveCreateWiz()
786
    {
787
        $conf = $this->conf;
0 ignored issues
show
Unused Code introduced by
The assignment to $conf is dead and can be removed.
Loading history...
788
789
        $lang = $this->lang;
790
        $data = $this->misc->getDatabaseAccessor();
791
792
        // Check that they've given a name and fields they want to select
793
794
        if (!strlen($_POST['formView'])) {
795
            $this->doSetParamsCreate($lang['strviewneedsname']);
796
        } elseif (!isset($_POST['formFields']) || !count($_POST['formFields'])) {
797
            $this->doSetParamsCreate($lang['strviewneedsfields']);
798
        } else {
799
            $selFields = '';
800
801
            if (!empty($_POST['dblFldMeth'])) {
802
                $tmpHsh = [];
803
            }
804
805
            foreach ($_POST['formFields'] as $curField) {
806
                $arrTmp = unserialize($curField);
807
                $data->fieldArrayClean($arrTmp);
808
                if (!empty($_POST['dblFldMeth'])) {
809
                    // doublon control
810
                    if (empty($tmpHsh[$arrTmp['fieldname']])) {
811
                        // field does not exist
812
                        $selFields .= "\"{$arrTmp['schemaname']}\".\"{$arrTmp['tablename']}\".\"{$arrTmp['fieldname']}\", ";
813
                        $tmpHsh[$arrTmp['fieldname']] = 1;
814
                    } elseif ('rename' == $_POST['dblFldMeth']) {
815
                        // field exist and must be renamed
816
                        $tmpHsh[$arrTmp['fieldname']]++;
817
                        $selFields .= "\"{$arrTmp['schemaname']}\".\"{$arrTmp['tablename']}\".\"{$arrTmp['fieldname']}\" AS \"{$arrTmp['schemaname']}_{$arrTmp['tablename']}_{$arrTmp['fieldname']}{$tmpHsh[$arrTmp['fieldname']]}\", ";
818
                    }
819
                    // field already exist, just ignore this one
820
                } else {
821
                    // no doublon control
822
                    $selFields .= "\"{$arrTmp['schemaname']}\".\"{$arrTmp['tablename']}\".\"{$arrTmp['fieldname']}\", ";
823
                }
824
            }
825
826
            $selFields = substr($selFields, 0, -2);
827
            unset($arrTmp, $tmpHsh);
828
            $linkFields = '';
829
830
            // If we have links, out put the JOIN ... ON statements
831
            if (is_array($_POST['formLink'])) {
832
                // Filter out invalid/blank entries for our links
833
                $arrLinks = [];
834
                foreach ($_POST['formLink'] as $curLink) {
835
                    if (strlen($curLink['leftlink']) && strlen($curLink['rightlink']) && strlen($curLink['operator'])) {
836
                        $arrLinks[] = $curLink;
837
                    }
838
                }
839
                // We must perform some magic to make sure that we have a valid join order
840
                $count       = sizeof($arrLinks);
841
                $arrJoined   = [];
842
                $arrUsedTbls = [];
843
844
                // If we have at least one join condition, output it
845
                if ($count > 0) {
846
                    $j = 0;
847
                    while ($j < $count) {
848
                        foreach ($arrLinks as $curLink) {
849
                            $arrLeftLink  = unserialize($curLink['leftlink']);
850
                            $arrRightLink = unserialize($curLink['rightlink']);
851
                            $data->fieldArrayClean($arrLeftLink);
852
                            $data->fieldArrayClean($arrRightLink);
853
854
                            $tbl1 = "\"{$arrLeftLink['schemaname']}\".\"{$arrLeftLink['tablename']}\"";
855
                            $tbl2 = "\"{$arrRightLink['schemaname']}\".\"{$arrRightLink['tablename']}\"";
856
857
                            if ((!in_array($curLink, $arrJoined, true) && in_array($tbl1, $arrUsedTbls, true)) || !count($arrJoined)) {
858
                                // Make sure for multi-column foreign keys that we use a table alias tables joined to more than once
859
                                // This can (and should be) more optimized for multi-column foreign keys
860
                                $adj_tbl2 = in_array($tbl2, $arrUsedTbls, true) ? "${tbl2} AS alias_ppa_" . mktime() : $tbl2;
861
862
                                $linkFields .= strlen($linkFields) ? "{$curLink['operator']} ${adj_tbl2} ON (\"{$arrLeftLink['schemaname']}\".\"{$arrLeftLink['tablename']}\".\"{$arrLeftLink['fieldname']}\" = \"{$arrRightLink['schemaname']}\".\"{$arrRightLink['tablename']}\".\"{$arrRightLink['fieldname']}\") "
863
                                : "${tbl1} {$curLink['operator']} ${adj_tbl2} ON (\"{$arrLeftLink['schemaname']}\".\"{$arrLeftLink['tablename']}\".\"{$arrLeftLink['fieldname']}\" = \"{$arrRightLink['schemaname']}\".\"{$arrRightLink['tablename']}\".\"{$arrRightLink['fieldname']}\") ";
864
865
                                $arrJoined[] = $curLink;
866
                                if (!in_array($tbl1, $arrUsedTbls, true)) {
867
                                    $arrUsedTbls[] = $tbl1;
868
                                }
869
870
                                if (!in_array($tbl2, $arrUsedTbls, true)) {
871
                                    $arrUsedTbls[] = $tbl2;
872
                                }
873
                            }
874
                        }
875
                        $j++;
876
                    }
877
                }
878
            }
879
880
            //if linkfields has no length then either _POST['formLink'] was not set, or there were no join conditions
881
            //just select from all seleted tables - a cartesian join do a
882
            if (!strlen($linkFields)) {
883
                foreach ($_POST['formTables'] as $curTable) {
884
                    $arrTmp = unserialize($curTable);
885
                    $data->fieldArrayClean($arrTmp);
886
                    $linkFields .= strlen($linkFields) ? ", \"{$arrTmp['schemaname']}\".\"{$arrTmp['tablename']}\"" : "\"{$arrTmp['schemaname']}\".\"{$arrTmp['tablename']}\"";
887
                }
888
            }
889
890
            $addConditions = '';
891
            if (is_array($_POST['formCondition'])) {
892
                foreach ($_POST['formCondition'] as $curCondition) {
893
                    if (strlen($curCondition['field']) && strlen($curCondition['txt'])) {
894
                        $arrTmp = unserialize($curCondition['field']);
895
                        $data->fieldArrayClean($arrTmp);
896
                        $addConditions .= strlen($addConditions) ? " AND \"{$arrTmp['schemaname']}\".\"{$arrTmp['tablename']}\".\"{$arrTmp['fieldname']}\" {$curCondition['operator']} '{$curCondition['txt']}' "
897
                        : " \"{$arrTmp['schemaname']}\".\"{$arrTmp['tablename']}\".\"{$arrTmp['fieldname']}\" {$curCondition['operator']} '{$curCondition['txt']}' ";
898
                    }
899
                }
900
            }
901
902
            $viewQuery = "SELECT ${selFields} FROM ${linkFields} ";
903
904
            //add where from additional conditions
905
            if (strlen($addConditions)) {
906
                $viewQuery .= ' WHERE ' . $addConditions;
907
            }
908
909
            $status = $data->createView($_POST['formView'], $viewQuery, false, $_POST['formComment']);
910
            if (0 == $status) {
911
                $this->misc->setReloadBrowser(true);
912
                $this->doDefault($lang['strviewcreated']);
913
            } else {
914
                $this->doSetParamsCreate($lang['strviewcreatedbad']);
915
            }
916
        }
917
    }
918
}
919